141127Sbostic /*- 241127Sbostic * Copyright (c) 1990 The Regents of the University of California. 341127Sbostic * 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 1241127Sbostic char copyright[] = 1341127Sbostic "@(#) Copyright (c) 1990 The Regents of the University of California.\n\ 1441127Sbostic All rights reserved.\n"; 1541127Sbostic #endif /* not lint */ 1641125Sbostic 1741127Sbostic #ifndef lint 18*41128Sbostic static char sccsid[] = "@(#)traceroute.c 5.3 (Berkeley) 04/28/90"; 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 19241125Sbostic #include <stdio.h> 19341125Sbostic #include <errno.h> 19441125Sbostic #include <strings.h> 19541125Sbostic #include <sys/time.h> 19641125Sbostic 19741125Sbostic #include <sys/param.h> 19841125Sbostic #include <sys/socket.h> 19941125Sbostic #include <sys/file.h> 20041125Sbostic #include <sys/ioctl.h> 20141125Sbostic 20241125Sbostic #include <netinet/in_systm.h> 20341125Sbostic #include <netinet/in.h> 20441125Sbostic #include <netinet/ip.h> 20541125Sbostic #include <netinet/ip_icmp.h> 20641125Sbostic #include <netinet/udp.h> 20741125Sbostic #include <netdb.h> 20841125Sbostic 20941125Sbostic #define MAXPACKET 65535 /* max ip packet size */ 21041125Sbostic #ifndef MAXHOSTNAMELEN 21141125Sbostic #define MAXHOSTNAMELEN 64 21241125Sbostic #endif 21341125Sbostic 21441125Sbostic #ifndef FD_SET 21541125Sbostic #define NFDBITS (8*sizeof(fd_set)) 21641125Sbostic #define FD_SETSIZE NFDBITS 21741125Sbostic #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 21841125Sbostic #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 21941125Sbostic #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 22041125Sbostic #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 22141125Sbostic #endif 22241125Sbostic 22341125Sbostic #define Fprintf (void)fprintf 22441125Sbostic #define Sprintf (void)sprintf 22541125Sbostic #define Printf (void)printf 22641125Sbostic extern int errno; 22741125Sbostic extern char *malloc(); 22841125Sbostic extern char *inet_ntoa(); 22941125Sbostic extern u_long inet_addr(); 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 char *inetname(); 24541125Sbostic 24641125Sbostic int s; /* receive (icmp) socket file descriptor */ 24741125Sbostic int sndsock; /* send (udp) socket file descriptor */ 24841125Sbostic struct timezone tz; /* leftover */ 24941125Sbostic 25041125Sbostic struct sockaddr whereto; /* Who to try to reach */ 25141125Sbostic int datalen; /* How much data */ 25241125Sbostic 25341125Sbostic char *source = 0; 25441125Sbostic char *hostname; 25541125Sbostic 25641125Sbostic int nprobes = 3; 25741125Sbostic int max_ttl = 30; 25841125Sbostic u_short ident; 25941125Sbostic u_short port = 32768+666; /* start udp dest port # for probe packets */ 26041125Sbostic int options; /* socket options */ 26141125Sbostic int verbose; 26241125Sbostic int waittime = 5; /* time to wait for response (in seconds) */ 26341125Sbostic int nflag; /* print addresses numerically */ 26441125Sbostic 26541125Sbostic main(argc, argv) 26641125Sbostic char *argv[]; 26741125Sbostic { 268*41128Sbostic extern char *optarg; 269*41128Sbostic extern int optind; 270*41128Sbostic struct hostent *hp; 27141125Sbostic struct protoent *pe; 272*41128Sbostic struct sockaddr_in from, *to; 273*41128Sbostic int ch, i, on, probe, seq, tos, ttl; 27441125Sbostic 275*41128Sbostic on = 1; 276*41128Sbostic seq = tos = 0; 277*41128Sbostic to = (struct sockaddr_in *)&whereto; 278*41128Sbostic while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF) 279*41128Sbostic switch(ch) { 280*41128Sbostic case 'd': 281*41128Sbostic options |= SO_DEBUG; 282*41128Sbostic break; 283*41128Sbostic case 'm': 284*41128Sbostic max_ttl = atoi(optarg); 285*41128Sbostic if (max_ttl <= 1) { 286*41128Sbostic Fprintf(stderr, 287*41128Sbostic "traceroute: max ttl must be >1.\n"); 288*41128Sbostic exit(1); 28941125Sbostic } 290*41128Sbostic break; 291*41128Sbostic case 'n': 292*41128Sbostic nflag++; 293*41128Sbostic break; 294*41128Sbostic case 'p': 295*41128Sbostic port = atoi(optarg); 296*41128Sbostic if (port < 1) { 297*41128Sbostic Fprintf(stderr, 298*41128Sbostic "traceroute: port must be >0.\n"); 299*41128Sbostic exit(1); 300*41128Sbostic } 301*41128Sbostic break; 302*41128Sbostic case 'q': 303*41128Sbostic nprobes = atoi(optarg); 304*41128Sbostic if (nprobes < 1) { 305*41128Sbostic Fprintf(stderr, 306*41128Sbostic "traceroute: nprobes must be >0.\n"); 307*41128Sbostic exit(1); 308*41128Sbostic } 309*41128Sbostic break; 310*41128Sbostic case 'r': 311*41128Sbostic options |= SO_DONTROUTE; 312*41128Sbostic break; 313*41128Sbostic case 's': 314*41128Sbostic /* 315*41128Sbostic * set the ip source address of the outbound 316*41128Sbostic * probe (e.g., on a multi-homed host). 317*41128Sbostic */ 318*41128Sbostic source = optarg; 319*41128Sbostic break; 320*41128Sbostic case 't': 321*41128Sbostic tos = atoi(optarg); 322*41128Sbostic if (tos < 0 || tos > 255) { 323*41128Sbostic Fprintf(stderr, 324*41128Sbostic "traceroute: tos must be 0 to 255.\n"); 325*41128Sbostic exit(1); 326*41128Sbostic } 327*41128Sbostic break; 328*41128Sbostic case 'v': 329*41128Sbostic verbose++; 330*41128Sbostic break; 331*41128Sbostic case 'w': 332*41128Sbostic waittime = atoi(optarg); 333*41128Sbostic if (waittime <= 1) { 334*41128Sbostic Fprintf(stderr, 335*41128Sbostic "traceroute: wait must be >1 sec.\n"); 336*41128Sbostic exit(1); 337*41128Sbostic } 338*41128Sbostic break; 339*41128Sbostic default: 340*41128Sbostic usage(); 341*41128Sbostic } 342*41128Sbostic argc -= optind; 343*41128Sbostic argv += optind; 344*41128Sbostic 345*41128Sbostic if (argc < 1) 346*41128Sbostic usage(); 347*41128Sbostic 34841125Sbostic setlinebuf (stdout); 34941125Sbostic 35041125Sbostic (void) bzero((char *)&whereto, sizeof(struct sockaddr)); 35141125Sbostic to->sin_family = AF_INET; 352*41128Sbostic to->sin_addr.s_addr = inet_addr(*argv); 353*41128Sbostic if (to->sin_addr.s_addr != -1) 354*41128Sbostic hostname = *argv; 355*41128Sbostic else { 356*41128Sbostic hp = gethostbyname(*argv); 35741125Sbostic if (hp) { 35841125Sbostic to->sin_family = hp->h_addrtype; 35941125Sbostic bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length); 36041125Sbostic hostname = hp->h_name; 36141125Sbostic } else { 362*41128Sbostic (void)fprintf(stderr, 363*41128Sbostic "traceroute: unknown host %s\n", *argv); 36441125Sbostic exit(1); 36541125Sbostic } 36641125Sbostic } 367*41128Sbostic if (*++argv) 368*41128Sbostic datalen = atoi(*argv); 36941125Sbostic if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) { 370*41128Sbostic Fprintf(stderr, 371*41128Sbostic "traceroute: packet size must be 0 <= s < %ld.\n", 372*41128Sbostic MAXPACKET - sizeof(struct opacket)); 37341125Sbostic exit(1); 37441125Sbostic } 37541125Sbostic datalen += sizeof(struct opacket); 37641125Sbostic outpacket = (struct opacket *)malloc((unsigned)datalen); 37741125Sbostic if (! outpacket) { 37841125Sbostic perror("traceroute: malloc"); 37941125Sbostic exit(1); 38041125Sbostic } 38141125Sbostic (void) bzero((char *)outpacket, datalen); 38241125Sbostic outpacket->ip.ip_dst = to->sin_addr; 38341125Sbostic outpacket->ip.ip_tos = tos; 38441125Sbostic 38541125Sbostic ident = (getpid() & 0xffff) | 0x8000; 38641125Sbostic 38741125Sbostic if ((pe = getprotobyname("icmp")) == NULL) { 38841125Sbostic Fprintf(stderr, "icmp: unknown protocol\n"); 38941125Sbostic exit(10); 39041125Sbostic } 39141125Sbostic if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) { 39241125Sbostic perror("traceroute: icmp socket"); 39341125Sbostic exit(5); 39441125Sbostic } 39541125Sbostic if (options & SO_DEBUG) 39641125Sbostic (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 39741125Sbostic (char *)&on, sizeof(on)); 39841125Sbostic if (options & SO_DONTROUTE) 39941125Sbostic (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, 40041125Sbostic (char *)&on, sizeof(on)); 40141125Sbostic 40241125Sbostic if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { 40341125Sbostic perror("traceroute: raw socket"); 40441125Sbostic exit(5); 40541125Sbostic } 40641125Sbostic #ifdef SO_SNDBUF 40741125Sbostic if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, 40841125Sbostic sizeof(datalen)) < 0) { 40941125Sbostic perror("traceroute: SO_SNDBUF"); 41041125Sbostic exit(6); 41141125Sbostic } 41241125Sbostic #endif SO_SNDBUF 41341125Sbostic #ifdef IP_HDRINCL 41441125Sbostic if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, 41541125Sbostic sizeof(on)) < 0) { 41641125Sbostic perror("traceroute: IP_HDRINCL"); 41741125Sbostic exit(6); 41841125Sbostic } 41941125Sbostic #endif IP_HDRINCL 42041125Sbostic if (options & SO_DEBUG) 42141125Sbostic (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 42241125Sbostic (char *)&on, sizeof(on)); 42341125Sbostic if (options & SO_DONTROUTE) 42441125Sbostic (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, 42541125Sbostic (char *)&on, sizeof(on)); 42641125Sbostic 42741125Sbostic if (source) { 42841125Sbostic (void) bzero((char *)&from, sizeof(struct sockaddr)); 42941125Sbostic from.sin_family = AF_INET; 43041125Sbostic from.sin_addr.s_addr = inet_addr(source); 43141125Sbostic if (from.sin_addr.s_addr == -1) { 43241125Sbostic Printf("traceroute: unknown host %s\n", source); 43341125Sbostic exit(1); 43441125Sbostic } 43541125Sbostic outpacket->ip.ip_src = from.sin_addr; 43641125Sbostic #ifndef IP_HDRINCL 43741125Sbostic if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) { 43841125Sbostic perror ("traceroute: bind:"); 43941125Sbostic exit (1); 44041125Sbostic } 44141125Sbostic #endif IP_HDRINCL 44241125Sbostic } 44341125Sbostic 44441125Sbostic Fprintf(stderr, "traceroute to %s (%s)", hostname, 44541125Sbostic inet_ntoa(to->sin_addr)); 44641125Sbostic if (source) 44741125Sbostic Fprintf(stderr, " from %s", source); 44841125Sbostic Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen); 44941125Sbostic (void) fflush(stderr); 45041125Sbostic 45141125Sbostic for (ttl = 1; ttl <= max_ttl; ++ttl) { 45241125Sbostic u_long lastaddr = 0; 45341125Sbostic int got_there = 0; 45441125Sbostic int unreachable = 0; 45541125Sbostic 45641125Sbostic Printf("%2d ", ttl); 45741125Sbostic for (probe = 0; probe < nprobes; ++probe) { 45841125Sbostic int cc; 45941125Sbostic struct timeval tv; 46041125Sbostic struct ip *ip; 46141125Sbostic 46241125Sbostic (void) gettimeofday(&tv, &tz); 46341125Sbostic send_probe(++seq, ttl); 46441125Sbostic while (cc = wait_for_reply(s, &from)) { 46541125Sbostic if ((i = packet_ok(packet, cc, &from, seq))) { 46641125Sbostic int dt = deltaT(&tv); 46741125Sbostic if (from.sin_addr.s_addr != lastaddr) { 46841125Sbostic print(packet, cc, &from); 46941125Sbostic lastaddr = from.sin_addr.s_addr; 47041125Sbostic } 47141125Sbostic Printf(" %d ms", dt); 47241125Sbostic switch(i - 1) { 47341125Sbostic case ICMP_UNREACH_PORT: 47441125Sbostic #ifndef ARCHAIC 47541125Sbostic ip = (struct ip *)packet; 47641125Sbostic if (ip->ip_ttl <= 1) 47741125Sbostic Printf(" !"); 47841125Sbostic #endif ARCHAIC 47941125Sbostic ++got_there; 48041125Sbostic break; 48141125Sbostic case ICMP_UNREACH_NET: 48241125Sbostic ++unreachable; 48341125Sbostic Printf(" !N"); 48441125Sbostic break; 48541125Sbostic case ICMP_UNREACH_HOST: 48641125Sbostic ++unreachable; 48741125Sbostic Printf(" !H"); 48841125Sbostic break; 48941125Sbostic case ICMP_UNREACH_PROTOCOL: 49041125Sbostic ++got_there; 49141125Sbostic Printf(" !P"); 49241125Sbostic break; 49341125Sbostic case ICMP_UNREACH_NEEDFRAG: 49441125Sbostic ++unreachable; 49541125Sbostic Printf(" !F"); 49641125Sbostic break; 49741125Sbostic case ICMP_UNREACH_SRCFAIL: 49841125Sbostic ++unreachable; 49941125Sbostic Printf(" !S"); 50041125Sbostic break; 50141125Sbostic } 50241125Sbostic break; 50341125Sbostic } 50441125Sbostic } 50541125Sbostic if (cc == 0) 50641125Sbostic Printf(" *"); 50741125Sbostic (void) fflush(stdout); 50841125Sbostic } 50941125Sbostic putchar('\n'); 51041125Sbostic if (got_there || unreachable >= nprobes-1) 51141125Sbostic exit(0); 51241125Sbostic } 51341125Sbostic } 51441125Sbostic 51541125Sbostic wait_for_reply(sock, from) 51641125Sbostic int sock; 51741125Sbostic struct sockaddr_in *from; 51841125Sbostic { 51941125Sbostic fd_set fds; 52041125Sbostic struct timeval wait; 52141125Sbostic int cc = 0; 52241125Sbostic int fromlen = sizeof (*from); 52341125Sbostic 52441125Sbostic FD_ZERO(&fds); 52541125Sbostic FD_SET(sock, &fds); 52641125Sbostic wait.tv_sec = waittime; wait.tv_usec = 0; 52741125Sbostic 52841125Sbostic if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0) 52941125Sbostic cc=recvfrom(s, (char *)packet, sizeof(packet), 0, 53041125Sbostic (struct sockaddr *)from, &fromlen); 53141125Sbostic 53241125Sbostic return(cc); 53341125Sbostic } 53441125Sbostic 53541125Sbostic 53641125Sbostic send_probe(seq, ttl) 53741125Sbostic { 53841125Sbostic struct opacket *op = outpacket; 53941125Sbostic struct ip *ip = &op->ip; 54041125Sbostic struct udphdr *up = &op->udp; 54141125Sbostic int i; 54241125Sbostic 54341125Sbostic ip->ip_off = 0; 54441125Sbostic ip->ip_p = IPPROTO_UDP; 54541125Sbostic ip->ip_len = datalen; 54641125Sbostic ip->ip_ttl = ttl; 54741125Sbostic 54841125Sbostic up->uh_sport = htons(ident); 54941125Sbostic up->uh_dport = htons(port+seq); 55041125Sbostic up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip))); 55141125Sbostic up->uh_sum = 0; 55241125Sbostic 55341125Sbostic op->seq = seq; 55441125Sbostic op->ttl = ttl; 55541125Sbostic (void) gettimeofday(&op->tv, &tz); 55641125Sbostic 55741125Sbostic i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto, 55841125Sbostic sizeof(struct sockaddr)); 55941125Sbostic if (i < 0 || i != datalen) { 56041125Sbostic if (i<0) 56141125Sbostic perror("sendto"); 56241125Sbostic Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname, 56341125Sbostic datalen, i); 56441125Sbostic (void) fflush(stdout); 56541125Sbostic } 56641125Sbostic } 56741125Sbostic 56841125Sbostic 56941125Sbostic deltaT(tp) 57041125Sbostic struct timeval *tp; 57141125Sbostic { 57241125Sbostic struct timeval tv; 57341125Sbostic 57441125Sbostic (void) gettimeofday(&tv, &tz); 57541125Sbostic tvsub(&tv, tp); 57641125Sbostic return (tv.tv_sec*1000 + (tv.tv_usec + 500)/1000); 57741125Sbostic } 57841125Sbostic 57941125Sbostic 58041125Sbostic /* 58141125Sbostic * Convert an ICMP "type" field to a printable string. 58241125Sbostic */ 58341125Sbostic char * 58441125Sbostic pr_type(t) 58541125Sbostic u_char t; 58641125Sbostic { 58741125Sbostic static char *ttab[] = { 58841125Sbostic "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", 58941125Sbostic "Source Quench", "Redirect", "ICMP 6", "ICMP 7", 59041125Sbostic "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", 59141125Sbostic "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", 59241125Sbostic "Info Reply" 59341125Sbostic }; 59441125Sbostic 59541125Sbostic if(t > 16) 59641125Sbostic return("OUT-OF-RANGE"); 59741125Sbostic 59841125Sbostic return(ttab[t]); 59941125Sbostic } 60041125Sbostic 60141125Sbostic 60241125Sbostic packet_ok(buf, cc, from, seq) 60341125Sbostic u_char *buf; 60441125Sbostic int cc; 60541125Sbostic struct sockaddr_in *from; 60641125Sbostic int seq; 60741125Sbostic { 60841125Sbostic register struct icmp *icp; 60941125Sbostic u_char type, code; 61041125Sbostic int hlen; 61141125Sbostic #ifndef ARCHAIC 61241125Sbostic struct ip *ip; 61341125Sbostic 61441125Sbostic ip = (struct ip *) buf; 61541125Sbostic hlen = ip->ip_hl << 2; 61641125Sbostic if (cc < hlen + ICMP_MINLEN) { 61741125Sbostic if (verbose) 61841125Sbostic Printf("packet too short (%d bytes) from %s\n", cc, 61941125Sbostic inet_ntoa(from->sin_addr)); 62041125Sbostic return (0); 62141125Sbostic } 62241125Sbostic cc -= hlen; 62341125Sbostic icp = (struct icmp *)(buf + hlen); 62441125Sbostic #else 62541125Sbostic icp = (struct icmp *)buf; 62641125Sbostic #endif ARCHAIC 62741125Sbostic type = icp->icmp_type; code = icp->icmp_code; 62841125Sbostic if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || 62941125Sbostic type == ICMP_UNREACH) { 63041125Sbostic struct ip *hip; 63141125Sbostic struct udphdr *up; 63241125Sbostic 63341125Sbostic hip = &icp->icmp_ip; 63441125Sbostic hlen = hip->ip_hl << 2; 63541125Sbostic up = (struct udphdr *)((u_char *)hip + hlen); 63641125Sbostic if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP && 63741125Sbostic up->uh_sport == htons(ident) && 63841125Sbostic up->uh_dport == htons(port+seq)) 63941125Sbostic return (type == ICMP_TIMXCEED? -1 : code+1); 64041125Sbostic } 64141125Sbostic #ifndef ARCHAIC 64241125Sbostic if (verbose) { 64341125Sbostic int i; 64441125Sbostic u_long *lp = (u_long *)&icp->icmp_ip; 64541125Sbostic 64641125Sbostic Printf("\n%d bytes from %s to %s", cc, 64741125Sbostic inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst)); 64841125Sbostic Printf(": icmp type %d (%s) code %d\n", type, pr_type(type), 64941125Sbostic icp->icmp_code); 65041125Sbostic for (i = 4; i < cc ; i += sizeof(long)) 65141125Sbostic Printf("%2d: x%8.8lx\n", i, *lp++); 65241125Sbostic } 65341125Sbostic #endif ARCHAIC 65441125Sbostic return(0); 65541125Sbostic } 65641125Sbostic 65741125Sbostic 65841125Sbostic print(buf, cc, from) 65941125Sbostic u_char *buf; 66041125Sbostic int cc; 66141125Sbostic struct sockaddr_in *from; 66241125Sbostic { 66341125Sbostic struct ip *ip; 66441125Sbostic int hlen; 66541125Sbostic 66641125Sbostic ip = (struct ip *) buf; 66741125Sbostic hlen = ip->ip_hl << 2; 66841125Sbostic cc -= hlen; 66941125Sbostic 67041125Sbostic if (nflag) 67141125Sbostic Printf(" %s", inet_ntoa(from->sin_addr)); 67241125Sbostic else 67341125Sbostic Printf(" %s (%s)", inetname(from->sin_addr), 67441125Sbostic inet_ntoa(from->sin_addr)); 67541125Sbostic 67641125Sbostic if (verbose) 67741125Sbostic Printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); 67841125Sbostic } 67941125Sbostic 68041125Sbostic 68141125Sbostic #ifdef notyet 68241125Sbostic /* 68341125Sbostic * Checksum routine for Internet Protocol family headers (C Version) 68441125Sbostic */ 68541125Sbostic in_cksum(addr, len) 68641125Sbostic u_short *addr; 68741125Sbostic int len; 68841125Sbostic { 68941125Sbostic register int nleft = len; 69041125Sbostic register u_short *w = addr; 69141125Sbostic register u_short answer; 69241125Sbostic register int sum = 0; 69341125Sbostic 69441125Sbostic /* 69541125Sbostic * Our algorithm is simple, using a 32 bit accumulator (sum), 69641125Sbostic * we add sequential 16 bit words to it, and at the end, fold 69741125Sbostic * back all the carry bits from the top 16 bits into the lower 69841125Sbostic * 16 bits. 69941125Sbostic */ 70041125Sbostic while (nleft > 1) { 70141125Sbostic sum += *w++; 70241125Sbostic nleft -= 2; 70341125Sbostic } 70441125Sbostic 70541125Sbostic /* mop up an odd byte, if necessary */ 70641125Sbostic if (nleft == 1) 70741125Sbostic sum += *(u_char *)w; 70841125Sbostic 70941125Sbostic /* 71041125Sbostic * add back carry outs from top 16 bits to low 16 bits 71141125Sbostic */ 71241125Sbostic sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 71341125Sbostic sum += (sum >> 16); /* add carry */ 71441125Sbostic answer = ~sum; /* truncate to 16 bits */ 71541125Sbostic return (answer); 71641125Sbostic } 71741125Sbostic #endif notyet 71841125Sbostic 71941125Sbostic /* 72041125Sbostic * Subtract 2 timeval structs: out = out - in. 72141125Sbostic * Out is assumed to be >= in. 72241125Sbostic */ 72341125Sbostic tvsub(out, in) 72441125Sbostic register struct timeval *out, *in; 72541125Sbostic { 72641125Sbostic if ((out->tv_usec -= in->tv_usec) < 0) { 72741125Sbostic out->tv_sec--; 72841125Sbostic out->tv_usec += 1000000; 72941125Sbostic } 73041125Sbostic out->tv_sec -= in->tv_sec; 73141125Sbostic } 73241125Sbostic 73341125Sbostic 73441125Sbostic /* 73541125Sbostic * Construct an Internet address representation. 73641125Sbostic * If the nflag has been supplied, give 73741125Sbostic * numeric value, otherwise try for symbolic name. 73841125Sbostic */ 73941125Sbostic char * 74041125Sbostic inetname(in) 74141125Sbostic struct in_addr in; 74241125Sbostic { 74341125Sbostic register char *cp; 74441125Sbostic static char line[50]; 74541125Sbostic struct hostent *hp; 74641125Sbostic static char domain[MAXHOSTNAMELEN + 1]; 74741125Sbostic static int first = 1; 74841125Sbostic 74941125Sbostic if (first && !nflag) { 75041125Sbostic first = 0; 75141125Sbostic if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 75241125Sbostic (cp = index(domain, '.'))) 75341125Sbostic (void) strcpy(domain, cp + 1); 75441125Sbostic else 75541125Sbostic domain[0] = 0; 75641125Sbostic } 75741125Sbostic cp = 0; 75841125Sbostic if (!nflag && in.s_addr != INADDR_ANY) { 75941125Sbostic hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET); 76041125Sbostic if (hp) { 76141125Sbostic if ((cp = index(hp->h_name, '.')) && 76241125Sbostic !strcmp(cp + 1, domain)) 76341125Sbostic *cp = 0; 76441125Sbostic cp = hp->h_name; 76541125Sbostic } 76641125Sbostic } 76741125Sbostic if (cp) 76841125Sbostic (void) strcpy(line, cp); 76941125Sbostic else { 77041125Sbostic in.s_addr = ntohl(in.s_addr); 77141125Sbostic #define C(x) ((x) & 0xff) 77241125Sbostic Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >> 24), 77341125Sbostic C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); 77441125Sbostic } 77541125Sbostic return (line); 77641125Sbostic } 777*41128Sbostic 778*41128Sbostic usage() 779*41128Sbostic { 780*41128Sbostic (void)fprintf(stderr, 781*41128Sbostic "usage: traceroute [-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\t\ 782*41128Sbostic [-s src_addr] [-t tos] [-w wait] host [data size]\n"); 783*41128Sbostic exit(1); 784*41128Sbostic } 785