141127Sbostic /*-
2*61891Sbostic * Copyright (c) 1990, 1993
3*61891Sbostic * The Regents of the University of California. All rights reserved.
441127Sbostic *
541127Sbostic * This code is derived from software contributed to Berkeley by
641127Sbostic * Van Jacobson.
741127Sbostic *
841127Sbostic * %sccs.include.redist.c%
941127Sbostic */
1041127Sbostic
1141125Sbostic #ifndef lint
12*61891Sbostic static char copyright[] =
13*61891Sbostic "@(#) Copyright (c) 1990, 1993\n\
14*61891Sbostic The Regents of the University of California. All rights reserved.\n";
1541127Sbostic #endif /* not lint */
1641125Sbostic
1741127Sbostic #ifndef lint
18*61891Sbostic static char sccsid[] = "@(#)traceroute.c 8.1 (Berkeley) 06/06/93";
1941127Sbostic #endif /* not lint */
2041127Sbostic
2141125Sbostic /*
2241125Sbostic * traceroute host - trace the route ip packets follow going to "host".
2341125Sbostic *
2441125Sbostic * Attempt to trace the route an ip packet would follow to some
2541125Sbostic * internet host. We find out intermediate hops by launching probe
2641125Sbostic * packets with a small ttl (time to live) then listening for an
2741125Sbostic * icmp "time exceeded" reply from a gateway. We start our probes
2841125Sbostic * with a ttl of one and increase by one until we get an icmp "port
2941125Sbostic * unreachable" (which means we got to "host") or hit a max (which
3041125Sbostic * defaults to 30 hops & can be changed with the -m flag). Three
3141125Sbostic * probes (change with -q flag) are sent at each ttl setting and a
3241125Sbostic * line is printed showing the ttl, address of the gateway and
3341125Sbostic * round trip time of each probe. If the probe answers come from
3441125Sbostic * different gateways, the address of each responding system will
3541125Sbostic * be printed. If there is no response within a 5 sec. timeout
3641125Sbostic * interval (changed with the -w flag), a "*" is printed for that
3741125Sbostic * probe.
3841125Sbostic *
3941125Sbostic * Probe packets are UDP format. We don't want the destination
4041125Sbostic * host to process them so the destination port is set to an
4141125Sbostic * unlikely value (if some clod on the destination is using that
4241125Sbostic * value, it can be changed with the -p flag).
4341125Sbostic *
4441125Sbostic * A sample use might be:
4541125Sbostic *
4641125Sbostic * [yak 71]% traceroute nis.nsf.net.
4741125Sbostic * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
4841125Sbostic * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
4941125Sbostic * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
5041125Sbostic * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
5141125Sbostic * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
5241125Sbostic * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
5341125Sbostic * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
5441125Sbostic * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
5541125Sbostic * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
5641125Sbostic * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
5741125Sbostic * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
5841125Sbostic * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
5941125Sbostic *
6041125Sbostic * Note that lines 2 & 3 are the same. This is due to a buggy
6141125Sbostic * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
6241125Sbostic * packets with a zero ttl.
6341125Sbostic *
6441125Sbostic * A more interesting example is:
6541125Sbostic *
6641125Sbostic * [yak 72]% traceroute allspice.lcs.mit.edu.
6741125Sbostic * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
6841125Sbostic * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
6941125Sbostic * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
7041125Sbostic * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
7141125Sbostic * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
7241125Sbostic * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
7341125Sbostic * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
7441125Sbostic * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
7541125Sbostic * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
7641125Sbostic * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
7741125Sbostic * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
7841125Sbostic * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
7941125Sbostic * 12 * * *
8041125Sbostic * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
8141125Sbostic * 14 * * *
8241125Sbostic * 15 * * *
8341125Sbostic * 16 * * *
8441125Sbostic * 17 * * *
8541125Sbostic * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
8641125Sbostic *
8741125Sbostic * (I start to see why I'm having so much trouble with mail to
8841125Sbostic * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away
8941125Sbostic * either don't send ICMP "time exceeded" messages or send them
9041125Sbostic * with a ttl too small to reach us. 14 - 17 are running the
9141125Sbostic * MIT C Gateway code that doesn't send "time exceeded"s. God
9241125Sbostic * only knows what's going on with 12.
9341125Sbostic *
9441125Sbostic * The silent gateway 12 in the above may be the result of a bug in
9541125Sbostic * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3)
9641125Sbostic * sends an unreachable message using whatever ttl remains in the
9741125Sbostic * original datagram. Since, for gateways, the remaining ttl is
9841125Sbostic * zero, the icmp "time exceeded" is guaranteed to not make it back
9941125Sbostic * to us. The behavior of this bug is slightly more interesting
10041125Sbostic * when it appears on the destination system:
10141125Sbostic *
10241125Sbostic * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
10341125Sbostic * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
10441125Sbostic * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
10541125Sbostic * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
10641125Sbostic * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
10741125Sbostic * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
10841125Sbostic * 7 * * *
10941125Sbostic * 8 * * *
11041125Sbostic * 9 * * *
11141125Sbostic * 10 * * *
11241125Sbostic * 11 * * *
11341125Sbostic * 12 * * *
11441125Sbostic * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
11541125Sbostic *
11641125Sbostic * Notice that there are 12 "gateways" (13 is the final
11741125Sbostic * destination) and exactly the last half of them are "missing".
11841125Sbostic * What's really happening is that rip (a Sun-3 running Sun OS3.5)
11941125Sbostic * is using the ttl from our arriving datagram as the ttl in its
12041125Sbostic * icmp reply. So, the reply will time out on the return path
12141125Sbostic * (with no notice sent to anyone since icmp's aren't sent for
12241125Sbostic * icmp's) until we probe with a ttl that's at least twice the path
12341125Sbostic * length. I.e., rip is really only 7 hops away. A reply that
12441125Sbostic * returns with a ttl of 1 is a clue this problem exists.
12541125Sbostic * Traceroute prints a "!" after the time if the ttl is <= 1.
12641125Sbostic * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
12741125Sbostic * non-standard (HPUX) software, expect to see this problem
12841125Sbostic * frequently and/or take care picking the target host of your
12941125Sbostic * probes.
13041125Sbostic *
13141125Sbostic * Other possible annotations after the time are !H, !N, !P (got a host,
13241125Sbostic * network or protocol unreachable, respectively), !S or !F (source
13341125Sbostic * route failed or fragmentation needed -- neither of these should
13441125Sbostic * ever occur and the associated gateway is busted if you see one). If
13541125Sbostic * almost all the probes result in some kind of unreachable, traceroute
13641125Sbostic * will give up and exit.
13741125Sbostic *
13841125Sbostic * Notes
13941125Sbostic * -----
14041125Sbostic * This program must be run by root or be setuid. (I suggest that
14141125Sbostic * you *don't* make it setuid -- casual use could result in a lot
14241125Sbostic * of unnecessary traffic on our poor, congested nets.)
14341125Sbostic *
14441125Sbostic * This program requires a kernel mod that does not appear in any
14541125Sbostic * system available from Berkeley: A raw ip socket using proto
14641125Sbostic * IPPROTO_RAW must interpret the data sent as an ip datagram (as
14741125Sbostic * opposed to data to be wrapped in a ip datagram). See the README
14841125Sbostic * file that came with the source to this program for a description
14941125Sbostic * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may
15041125Sbostic * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
15141125Sbostic * MODIFIED TO RUN THIS PROGRAM.
15241125Sbostic *
15341125Sbostic * The udp port usage may appear bizarre (well, ok, it is bizarre).
15441125Sbostic * The problem is that an icmp message only contains 8 bytes of
15541125Sbostic * data from the original datagram. 8 bytes is the size of a udp
15641125Sbostic * header so, if we want to associate replies with the original
15741125Sbostic * datagram, the necessary information must be encoded into the
15841125Sbostic * udp header (the ip id could be used but there's no way to
15941125Sbostic * interlock with the kernel's assignment of ip id's and, anyway,
16041125Sbostic * it would have taken a lot more kernel hacking to allow this
16141125Sbostic * code to set the ip id). So, to allow two or more users to
16241125Sbostic * use traceroute simultaneously, we use this task's pid as the
16341125Sbostic * source port (the high bit is set to move the port number out
16441125Sbostic * of the "likely" range). To keep track of which probe is being
16541125Sbostic * replied to (so times and/or hop counts don't get confused by a
16641125Sbostic * reply that was delayed in transit), we increment the destination
16741125Sbostic * port number before each probe.
16841125Sbostic *
16941125Sbostic * Don't use this as a coding example. I was trying to find a
17041125Sbostic * routing problem and this code sort-of popped out after 48 hours
17141125Sbostic * without sleep. I was amazed it ever compiled, much less ran.
17241125Sbostic *
17341125Sbostic * I stole the idea for this program from Steve Deering. Since
17441125Sbostic * the first release, I've learned that had I attended the right
17541125Sbostic * IETF working group meetings, I also could have stolen it from Guy
17641125Sbostic * Almes or Matt Mathis. I don't know (or care) who came up with
17741125Sbostic * the idea first. I envy the originators' perspicacity and I'm
17841125Sbostic * glad they didn't keep the idea a secret.
17941125Sbostic *
18041125Sbostic * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
18141125Sbostic * enhancements to the original distribution.
18241125Sbostic *
18341125Sbostic * I've hacked up a round-trip-route version of this that works by
18441125Sbostic * sending a loose-source-routed udp datagram through the destination
18541125Sbostic * back to yourself. Unfortunately, SO many gateways botch source
18641125Sbostic * routing, the thing is almost worthless. Maybe one day...
18741125Sbostic *
18841125Sbostic * -- Van Jacobson (van@helios.ee.lbl.gov)
18941125Sbostic * Tue Dec 20 03:50:13 PST 1988
19041125Sbostic */
19141125Sbostic
19242065Sbostic #include <sys/param.h>
19341125Sbostic #include <sys/time.h>
19441125Sbostic #include <sys/socket.h>
19541125Sbostic #include <sys/file.h>
19641125Sbostic #include <sys/ioctl.h>
19741125Sbostic
19841125Sbostic #include <netinet/in_systm.h>
19941125Sbostic #include <netinet/in.h>
20041125Sbostic #include <netinet/ip.h>
20141125Sbostic #include <netinet/ip_icmp.h>
20241125Sbostic #include <netinet/udp.h>
20353667Sbostic
20453667Sbostic #include <arpa/inet.h>
20553667Sbostic
20641125Sbostic #include <netdb.h>
20742065Sbostic #include <stdio.h>
20842065Sbostic #include <errno.h>
20953667Sbostic #include <stdlib.h>
21042065Sbostic #include <string.h>
21153667Sbostic #include <unistd.h>
21242065Sbostic
21341125Sbostic #define MAXPACKET 65535 /* max ip packet size */
21441125Sbostic #ifndef MAXHOSTNAMELEN
21541125Sbostic #define MAXHOSTNAMELEN 64
21641125Sbostic #endif
21741125Sbostic
21841125Sbostic #ifndef FD_SET
21941125Sbostic #define NFDBITS (8*sizeof(fd_set))
22041125Sbostic #define FD_SETSIZE NFDBITS
22141125Sbostic #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
22241125Sbostic #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
22341125Sbostic #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
22441125Sbostic #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
22541125Sbostic #endif
22641125Sbostic
22741125Sbostic #define Fprintf (void)fprintf
22841125Sbostic #define Sprintf (void)sprintf
22941125Sbostic #define Printf (void)printf
23041125Sbostic
23141125Sbostic /*
23241125Sbostic * format of a (udp) probe packet.
23341125Sbostic */
23441125Sbostic struct opacket {
23541125Sbostic struct ip ip;
23641125Sbostic struct udphdr udp;
23741125Sbostic u_char seq; /* sequence number of this packet */
23841125Sbostic u_char ttl; /* ttl packet left with */
23941125Sbostic struct timeval tv; /* time packet left */
24041125Sbostic };
24141125Sbostic
24241125Sbostic u_char packet[512]; /* last inbound (icmp) packet */
24341125Sbostic struct opacket *outpacket; /* last output (udp) packet */
24441125Sbostic
24553667Sbostic int wait_for_reply __P((int, struct sockaddr_in *));
24653667Sbostic void send_probe __P((int, int));
24753667Sbostic double deltaT __P((struct timeval *, struct timeval *));
24853667Sbostic int packet_ok __P((u_char *, int, struct sockaddr_in *, int));
24953667Sbostic void print __P((u_char *, int, struct sockaddr_in *));
25053667Sbostic void tvsub __P((struct timeval *, struct timeval *));
25153667Sbostic char *inetname __P((struct in_addr));
25253667Sbostic void usage __P(());
25353667Sbostic
25441125Sbostic int s; /* receive (icmp) socket file descriptor */
25541125Sbostic int sndsock; /* send (udp) socket file descriptor */
25641125Sbostic struct timezone tz; /* leftover */
25741125Sbostic
25841125Sbostic struct sockaddr whereto; /* Who to try to reach */
25941125Sbostic int datalen; /* How much data */
26041125Sbostic
26141125Sbostic char *source = 0;
26241125Sbostic char *hostname;
26341125Sbostic
26441125Sbostic int nprobes = 3;
26541125Sbostic int max_ttl = 30;
26641125Sbostic u_short ident;
26741125Sbostic u_short port = 32768+666; /* start udp dest port # for probe packets */
26841125Sbostic int options; /* socket options */
26941125Sbostic int verbose;
27041125Sbostic int waittime = 5; /* time to wait for response (in seconds) */
27141125Sbostic int nflag; /* print addresses numerically */
27241125Sbostic
27353667Sbostic int
main(argc,argv)27441125Sbostic main(argc, argv)
27553667Sbostic int argc;
27641125Sbostic char *argv[];
27741125Sbostic {
27841128Sbostic extern char *optarg;
27941128Sbostic extern int optind;
28041128Sbostic struct hostent *hp;
28141125Sbostic struct protoent *pe;
28241128Sbostic struct sockaddr_in from, *to;
28341128Sbostic int ch, i, on, probe, seq, tos, ttl;
28441125Sbostic
28541128Sbostic on = 1;
28641128Sbostic seq = tos = 0;
28741128Sbostic to = (struct sockaddr_in *)&whereto;
28841128Sbostic while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
28941128Sbostic switch(ch) {
29041128Sbostic case 'd':
29141128Sbostic options |= SO_DEBUG;
29241128Sbostic break;
29341128Sbostic case 'm':
29441128Sbostic max_ttl = atoi(optarg);
29541128Sbostic if (max_ttl <= 1) {
29641128Sbostic Fprintf(stderr,
29741128Sbostic "traceroute: max ttl must be >1.\n");
29841128Sbostic exit(1);
29941125Sbostic }
30041128Sbostic break;
30141128Sbostic case 'n':
30241128Sbostic nflag++;
30341128Sbostic break;
30441128Sbostic case 'p':
30541128Sbostic port = atoi(optarg);
30641128Sbostic if (port < 1) {
30741128Sbostic Fprintf(stderr,
30841128Sbostic "traceroute: port must be >0.\n");
30941128Sbostic exit(1);
31041128Sbostic }
31141128Sbostic break;
31241128Sbostic case 'q':
31341128Sbostic nprobes = atoi(optarg);
31441128Sbostic if (nprobes < 1) {
31541128Sbostic Fprintf(stderr,
31641128Sbostic "traceroute: nprobes must be >0.\n");
31741128Sbostic exit(1);
31841128Sbostic }
31941128Sbostic break;
32041128Sbostic case 'r':
32141128Sbostic options |= SO_DONTROUTE;
32241128Sbostic break;
32341128Sbostic case 's':
32441128Sbostic /*
32541128Sbostic * set the ip source address of the outbound
32641128Sbostic * probe (e.g., on a multi-homed host).
32741128Sbostic */
32841128Sbostic source = optarg;
32941128Sbostic break;
33041128Sbostic case 't':
33141128Sbostic tos = atoi(optarg);
33241128Sbostic if (tos < 0 || tos > 255) {
33341128Sbostic Fprintf(stderr,
33441128Sbostic "traceroute: tos must be 0 to 255.\n");
33541128Sbostic exit(1);
33641128Sbostic }
33741128Sbostic break;
33841128Sbostic case 'v':
33941128Sbostic verbose++;
34041128Sbostic break;
34141128Sbostic case 'w':
34241128Sbostic waittime = atoi(optarg);
34341128Sbostic if (waittime <= 1) {
34441128Sbostic Fprintf(stderr,
34541128Sbostic "traceroute: wait must be >1 sec.\n");
34641128Sbostic exit(1);
34741128Sbostic }
34841128Sbostic break;
34941128Sbostic default:
35041128Sbostic usage();
35141128Sbostic }
35241128Sbostic argc -= optind;
35341128Sbostic argv += optind;
35441128Sbostic
35553667Sbostic if (argc < 1)
35641128Sbostic usage();
35741128Sbostic
35841125Sbostic setlinebuf (stdout);
35941125Sbostic
36041125Sbostic (void) bzero((char *)&whereto, sizeof(struct sockaddr));
36141125Sbostic to->sin_family = AF_INET;
36241128Sbostic to->sin_addr.s_addr = inet_addr(*argv);
36353667Sbostic if (to->sin_addr.s_addr != -1)
36441128Sbostic hostname = *argv;
36541128Sbostic else {
36641128Sbostic hp = gethostbyname(*argv);
36741125Sbostic if (hp) {
36841125Sbostic to->sin_family = hp->h_addrtype;
36941125Sbostic bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
37041125Sbostic hostname = hp->h_name;
37141125Sbostic } else {
37241128Sbostic (void)fprintf(stderr,
37341128Sbostic "traceroute: unknown host %s\n", *argv);
37441125Sbostic exit(1);
37541125Sbostic }
37641125Sbostic }
37753667Sbostic if (*++argv)
37841128Sbostic datalen = atoi(*argv);
37941125Sbostic if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) {
38041128Sbostic Fprintf(stderr,
38141128Sbostic "traceroute: packet size must be 0 <= s < %ld.\n",
38241128Sbostic MAXPACKET - sizeof(struct opacket));
38341125Sbostic exit(1);
38441125Sbostic }
38541125Sbostic datalen += sizeof(struct opacket);
38641125Sbostic outpacket = (struct opacket *)malloc((unsigned)datalen);
38741125Sbostic if (! outpacket) {
38841125Sbostic perror("traceroute: malloc");
38941125Sbostic exit(1);
39041125Sbostic }
39141125Sbostic (void) bzero((char *)outpacket, datalen);
39241125Sbostic outpacket->ip.ip_dst = to->sin_addr;
39341125Sbostic outpacket->ip.ip_tos = tos;
39459018Sandrew outpacket->ip.ip_v = IPVERSION;
39559018Sandrew outpacket->ip.ip_id = 0;
39641125Sbostic
39741125Sbostic ident = (getpid() & 0xffff) | 0x8000;
39841125Sbostic
39941125Sbostic if ((pe = getprotobyname("icmp")) == NULL) {
40041125Sbostic Fprintf(stderr, "icmp: unknown protocol\n");
40141125Sbostic exit(10);
40241125Sbostic }
40341125Sbostic if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) {
40441125Sbostic perror("traceroute: icmp socket");
40541125Sbostic exit(5);
40641125Sbostic }
40741125Sbostic if (options & SO_DEBUG)
40841125Sbostic (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
40941125Sbostic (char *)&on, sizeof(on));
41041125Sbostic if (options & SO_DONTROUTE)
41141125Sbostic (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
41241125Sbostic (char *)&on, sizeof(on));
41341125Sbostic
41441125Sbostic if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
41541125Sbostic perror("traceroute: raw socket");
41641125Sbostic exit(5);
41741125Sbostic }
41841125Sbostic #ifdef SO_SNDBUF
41941125Sbostic if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
42041125Sbostic sizeof(datalen)) < 0) {
42141125Sbostic perror("traceroute: SO_SNDBUF");
42241125Sbostic exit(6);
42341125Sbostic }
42441125Sbostic #endif SO_SNDBUF
42541125Sbostic #ifdef IP_HDRINCL
42641125Sbostic if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
42741125Sbostic sizeof(on)) < 0) {
42841125Sbostic perror("traceroute: IP_HDRINCL");
42941125Sbostic exit(6);
43041125Sbostic }
43141125Sbostic #endif IP_HDRINCL
43241125Sbostic if (options & SO_DEBUG)
43341125Sbostic (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
43441125Sbostic (char *)&on, sizeof(on));
43541125Sbostic if (options & SO_DONTROUTE)
43641125Sbostic (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
43741125Sbostic (char *)&on, sizeof(on));
43841125Sbostic
43941125Sbostic if (source) {
44041125Sbostic (void) bzero((char *)&from, sizeof(struct sockaddr));
44141125Sbostic from.sin_family = AF_INET;
44241125Sbostic from.sin_addr.s_addr = inet_addr(source);
44341125Sbostic if (from.sin_addr.s_addr == -1) {
44441125Sbostic Printf("traceroute: unknown host %s\n", source);
44541125Sbostic exit(1);
44641125Sbostic }
44741125Sbostic outpacket->ip.ip_src = from.sin_addr;
44841125Sbostic #ifndef IP_HDRINCL
44941125Sbostic if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) {
45041125Sbostic perror ("traceroute: bind:");
45141125Sbostic exit (1);
45241125Sbostic }
45341125Sbostic #endif IP_HDRINCL
45441125Sbostic }
45541125Sbostic
45641125Sbostic Fprintf(stderr, "traceroute to %s (%s)", hostname,
45741125Sbostic inet_ntoa(to->sin_addr));
45841125Sbostic if (source)
45941125Sbostic Fprintf(stderr, " from %s", source);
46041125Sbostic Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
46141125Sbostic (void) fflush(stderr);
46241125Sbostic
46341125Sbostic for (ttl = 1; ttl <= max_ttl; ++ttl) {
46441125Sbostic u_long lastaddr = 0;
46541125Sbostic int got_there = 0;
46641125Sbostic int unreachable = 0;
46741125Sbostic
46841125Sbostic Printf("%2d ", ttl);
46941125Sbostic for (probe = 0; probe < nprobes; ++probe) {
47041125Sbostic int cc;
47153667Sbostic struct timeval t1, t2;
47253667Sbostic struct timezone tz;
47341125Sbostic struct ip *ip;
47441125Sbostic
47553667Sbostic (void) gettimeofday(&t1, &tz);
47641125Sbostic send_probe(++seq, ttl);
47741125Sbostic while (cc = wait_for_reply(s, &from)) {
47853667Sbostic (void) gettimeofday(&t2, &tz);
47941125Sbostic if ((i = packet_ok(packet, cc, &from, seq))) {
48041125Sbostic if (from.sin_addr.s_addr != lastaddr) {
48141125Sbostic print(packet, cc, &from);
48241125Sbostic lastaddr = from.sin_addr.s_addr;
48341125Sbostic }
48453667Sbostic Printf(" %g ms", deltaT(&t1, &t2));
48541125Sbostic switch(i - 1) {
48641125Sbostic case ICMP_UNREACH_PORT:
48741125Sbostic #ifndef ARCHAIC
48841125Sbostic ip = (struct ip *)packet;
48941125Sbostic if (ip->ip_ttl <= 1)
49041125Sbostic Printf(" !");
49141125Sbostic #endif ARCHAIC
49241125Sbostic ++got_there;
49341125Sbostic break;
49441125Sbostic case ICMP_UNREACH_NET:
49541125Sbostic ++unreachable;
49641125Sbostic Printf(" !N");
49741125Sbostic break;
49841125Sbostic case ICMP_UNREACH_HOST:
49941125Sbostic ++unreachable;
50041125Sbostic Printf(" !H");
50141125Sbostic break;
50241125Sbostic case ICMP_UNREACH_PROTOCOL:
50341125Sbostic ++got_there;
50441125Sbostic Printf(" !P");
50541125Sbostic break;
50641125Sbostic case ICMP_UNREACH_NEEDFRAG:
50741125Sbostic ++unreachable;
50841125Sbostic Printf(" !F");
50941125Sbostic break;
51041125Sbostic case ICMP_UNREACH_SRCFAIL:
51141125Sbostic ++unreachable;
51241125Sbostic Printf(" !S");
51341125Sbostic break;
51441125Sbostic }
51541125Sbostic break;
51641125Sbostic }
51741125Sbostic }
51841125Sbostic if (cc == 0)
51941125Sbostic Printf(" *");
52041125Sbostic (void) fflush(stdout);
52141125Sbostic }
52241125Sbostic putchar('\n');
52341125Sbostic if (got_there || unreachable >= nprobes-1)
52441125Sbostic exit(0);
52541125Sbostic }
52641125Sbostic }
52741125Sbostic
52853667Sbostic int
wait_for_reply(sock,from)52941125Sbostic wait_for_reply(sock, from)
53041125Sbostic int sock;
53141125Sbostic struct sockaddr_in *from;
53241125Sbostic {
53341125Sbostic fd_set fds;
53441125Sbostic struct timeval wait;
53541125Sbostic int cc = 0;
53641125Sbostic int fromlen = sizeof (*from);
53741125Sbostic
53841125Sbostic FD_ZERO(&fds);
53941125Sbostic FD_SET(sock, &fds);
54041125Sbostic wait.tv_sec = waittime; wait.tv_usec = 0;
54141125Sbostic
54241125Sbostic if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
54341125Sbostic cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
54441125Sbostic (struct sockaddr *)from, &fromlen);
54541125Sbostic
54641125Sbostic return(cc);
54741125Sbostic }
54841125Sbostic
54941125Sbostic
55053667Sbostic void
send_probe(seq,ttl)55141125Sbostic send_probe(seq, ttl)
55253667Sbostic int seq, ttl;
55341125Sbostic {
55441125Sbostic struct opacket *op = outpacket;
55541125Sbostic struct ip *ip = &op->ip;
55641125Sbostic struct udphdr *up = &op->udp;
55741125Sbostic int i;
55841125Sbostic
55941125Sbostic ip->ip_off = 0;
56059018Sandrew ip->ip_hl = sizeof(*ip) >> 2;
56141125Sbostic ip->ip_p = IPPROTO_UDP;
56241125Sbostic ip->ip_len = datalen;
56341125Sbostic ip->ip_ttl = ttl;
56459258Ssklower ip->ip_v = IPVERSION;
56559258Ssklower ip->ip_id = htons(ident+seq);
56641125Sbostic
56741125Sbostic up->uh_sport = htons(ident);
56841125Sbostic up->uh_dport = htons(port+seq);
56941125Sbostic up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip)));
57041125Sbostic up->uh_sum = 0;
57141125Sbostic
57241125Sbostic op->seq = seq;
57341125Sbostic op->ttl = ttl;
57441125Sbostic (void) gettimeofday(&op->tv, &tz);
57541125Sbostic
57641125Sbostic i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
57741125Sbostic sizeof(struct sockaddr));
57841125Sbostic if (i < 0 || i != datalen) {
57941125Sbostic if (i<0)
58041125Sbostic perror("sendto");
58141125Sbostic Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
58241125Sbostic datalen, i);
58341125Sbostic (void) fflush(stdout);
58441125Sbostic }
58541125Sbostic }
58641125Sbostic
58741125Sbostic
58853667Sbostic double
deltaT(t1p,t2p)58953667Sbostic deltaT(t1p, t2p)
59053667Sbostic struct timeval *t1p, *t2p;
59141125Sbostic {
59253667Sbostic register double dt;
59341125Sbostic
59453667Sbostic dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
59553667Sbostic (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
59653667Sbostic return (dt);
59741125Sbostic }
59841125Sbostic
59941125Sbostic
60041125Sbostic /*
60141125Sbostic * Convert an ICMP "type" field to a printable string.
60241125Sbostic */
60341125Sbostic char *
pr_type(t)60441125Sbostic pr_type(t)
60541125Sbostic u_char t;
60641125Sbostic {
60741125Sbostic static char *ttab[] = {
60841125Sbostic "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
60941125Sbostic "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
61041125Sbostic "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
61141125Sbostic "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
61241125Sbostic "Info Reply"
61341125Sbostic };
61441125Sbostic
61541125Sbostic if(t > 16)
61641125Sbostic return("OUT-OF-RANGE");
61741125Sbostic
61841125Sbostic return(ttab[t]);
61941125Sbostic }
62041125Sbostic
62141125Sbostic
62253667Sbostic int
packet_ok(buf,cc,from,seq)62341125Sbostic packet_ok(buf, cc, from, seq)
62441125Sbostic u_char *buf;
62541125Sbostic int cc;
62641125Sbostic struct sockaddr_in *from;
62741125Sbostic int seq;
62841125Sbostic {
62941125Sbostic register struct icmp *icp;
63041125Sbostic u_char type, code;
63141125Sbostic int hlen;
63241125Sbostic #ifndef ARCHAIC
63341125Sbostic struct ip *ip;
63441125Sbostic
63541125Sbostic ip = (struct ip *) buf;
63641125Sbostic hlen = ip->ip_hl << 2;
63741125Sbostic if (cc < hlen + ICMP_MINLEN) {
63841125Sbostic if (verbose)
63941125Sbostic Printf("packet too short (%d bytes) from %s\n", cc,
64041125Sbostic inet_ntoa(from->sin_addr));
64141125Sbostic return (0);
64241125Sbostic }
64341125Sbostic cc -= hlen;
64441125Sbostic icp = (struct icmp *)(buf + hlen);
64541125Sbostic #else
64641125Sbostic icp = (struct icmp *)buf;
64741125Sbostic #endif ARCHAIC
64841125Sbostic type = icp->icmp_type; code = icp->icmp_code;
64941125Sbostic if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
65041125Sbostic type == ICMP_UNREACH) {
65141125Sbostic struct ip *hip;
65241125Sbostic struct udphdr *up;
65341125Sbostic
65441125Sbostic hip = &icp->icmp_ip;
65541125Sbostic hlen = hip->ip_hl << 2;
65641125Sbostic up = (struct udphdr *)((u_char *)hip + hlen);
65741125Sbostic if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
65841125Sbostic up->uh_sport == htons(ident) &&
65941125Sbostic up->uh_dport == htons(port+seq))
66041125Sbostic return (type == ICMP_TIMXCEED? -1 : code+1);
66141125Sbostic }
66241125Sbostic #ifndef ARCHAIC
66341125Sbostic if (verbose) {
66441125Sbostic int i;
66541125Sbostic u_long *lp = (u_long *)&icp->icmp_ip;
66641125Sbostic
66741125Sbostic Printf("\n%d bytes from %s to %s", cc,
66841125Sbostic inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst));
66941125Sbostic Printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
67041125Sbostic icp->icmp_code);
67141125Sbostic for (i = 4; i < cc ; i += sizeof(long))
67241125Sbostic Printf("%2d: x%8.8lx\n", i, *lp++);
67341125Sbostic }
67441125Sbostic #endif ARCHAIC
67541125Sbostic return(0);
67641125Sbostic }
67741125Sbostic
67841125Sbostic
67953667Sbostic void
print(buf,cc,from)68041125Sbostic print(buf, cc, from)
68141125Sbostic u_char *buf;
68241125Sbostic int cc;
68341125Sbostic struct sockaddr_in *from;
68441125Sbostic {
68541125Sbostic struct ip *ip;
68641125Sbostic int hlen;
68741125Sbostic
68841125Sbostic ip = (struct ip *) buf;
68941125Sbostic hlen = ip->ip_hl << 2;
69041125Sbostic cc -= hlen;
69141125Sbostic
69241125Sbostic if (nflag)
69341125Sbostic Printf(" %s", inet_ntoa(from->sin_addr));
69441125Sbostic else
69541125Sbostic Printf(" %s (%s)", inetname(from->sin_addr),
69641125Sbostic inet_ntoa(from->sin_addr));
69741125Sbostic
69841125Sbostic if (verbose)
69941125Sbostic Printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
70041125Sbostic }
70141125Sbostic
70241125Sbostic
70341125Sbostic #ifdef notyet
70441125Sbostic /*
70541125Sbostic * Checksum routine for Internet Protocol family headers (C Version)
70641125Sbostic */
70753667Sbostic u_short
in_cksum(addr,len)70841125Sbostic in_cksum(addr, len)
70953667Sbostic u_short *addr;
71053667Sbostic int len;
71141125Sbostic {
71241125Sbostic register int nleft = len;
71341125Sbostic register u_short *w = addr;
71441125Sbostic register u_short answer;
71541125Sbostic register int sum = 0;
71641125Sbostic
71741125Sbostic /*
71841125Sbostic * Our algorithm is simple, using a 32 bit accumulator (sum),
71941125Sbostic * we add sequential 16 bit words to it, and at the end, fold
72041125Sbostic * back all the carry bits from the top 16 bits into the lower
72141125Sbostic * 16 bits.
72241125Sbostic */
72341125Sbostic while (nleft > 1) {
72441125Sbostic sum += *w++;
72541125Sbostic nleft -= 2;
72641125Sbostic }
72741125Sbostic
72841125Sbostic /* mop up an odd byte, if necessary */
72941125Sbostic if (nleft == 1)
73041125Sbostic sum += *(u_char *)w;
73141125Sbostic
73241125Sbostic /*
73341125Sbostic * add back carry outs from top 16 bits to low 16 bits
73441125Sbostic */
73541125Sbostic sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
73641125Sbostic sum += (sum >> 16); /* add carry */
73741125Sbostic answer = ~sum; /* truncate to 16 bits */
73841125Sbostic return (answer);
73941125Sbostic }
74041125Sbostic #endif notyet
74141125Sbostic
74241125Sbostic /*
74341125Sbostic * Subtract 2 timeval structs: out = out - in.
74441125Sbostic * Out is assumed to be >= in.
74541125Sbostic */
74653667Sbostic void
tvsub(out,in)74741125Sbostic tvsub(out, in)
74853667Sbostic register struct timeval *out, *in;
74941125Sbostic {
75041125Sbostic if ((out->tv_usec -= in->tv_usec) < 0) {
75141125Sbostic out->tv_sec--;
75241125Sbostic out->tv_usec += 1000000;
75341125Sbostic }
75441125Sbostic out->tv_sec -= in->tv_sec;
75541125Sbostic }
75641125Sbostic
75741125Sbostic
75841125Sbostic /*
75941125Sbostic * Construct an Internet address representation.
76053667Sbostic * If the nflag has been supplied, give
76141125Sbostic * numeric value, otherwise try for symbolic name.
76241125Sbostic */
76341125Sbostic char *
inetname(in)76441125Sbostic inetname(in)
76541125Sbostic struct in_addr in;
76641125Sbostic {
76741125Sbostic register char *cp;
76841125Sbostic static char line[50];
76941125Sbostic struct hostent *hp;
77041125Sbostic static char domain[MAXHOSTNAMELEN + 1];
77141125Sbostic static int first = 1;
77241125Sbostic
77341125Sbostic if (first && !nflag) {
77441125Sbostic first = 0;
77541125Sbostic if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
77641125Sbostic (cp = index(domain, '.')))
77741125Sbostic (void) strcpy(domain, cp + 1);
77841125Sbostic else
77941125Sbostic domain[0] = 0;
78041125Sbostic }
78141125Sbostic cp = 0;
78241125Sbostic if (!nflag && in.s_addr != INADDR_ANY) {
78341125Sbostic hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
78441125Sbostic if (hp) {
78541125Sbostic if ((cp = index(hp->h_name, '.')) &&
78641125Sbostic !strcmp(cp + 1, domain))
78741125Sbostic *cp = 0;
78841125Sbostic cp = hp->h_name;
78941125Sbostic }
79041125Sbostic }
79141125Sbostic if (cp)
79241125Sbostic (void) strcpy(line, cp);
79341125Sbostic else {
79441125Sbostic in.s_addr = ntohl(in.s_addr);
79541125Sbostic #define C(x) ((x) & 0xff)
79641125Sbostic Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >> 24),
79741125Sbostic C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
79841125Sbostic }
79941125Sbostic return (line);
80041125Sbostic }
80141128Sbostic
80253667Sbostic void
usage()80341128Sbostic usage()
80441128Sbostic {
80553667Sbostic (void)fprintf(stderr,
80641128Sbostic "usage: traceroute [-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\t\
80741128Sbostic [-s src_addr] [-t tos] [-w wait] host [data size]\n");
80841128Sbostic exit(1);
80941128Sbostic }
810