1*41125Sbostic #ifndef lint 2*41125Sbostic static char *rcsid = 3*41125Sbostic "@(#)$Header: traceroute.c,v 1.17 89/02/28 21:01:13 van Exp $ (LBL)"; 4*41125Sbostic #endif 5*41125Sbostic 6*41125Sbostic /* 7*41125Sbostic * traceroute host - trace the route ip packets follow going to "host". 8*41125Sbostic * 9*41125Sbostic * Attempt to trace the route an ip packet would follow to some 10*41125Sbostic * internet host. We find out intermediate hops by launching probe 11*41125Sbostic * packets with a small ttl (time to live) then listening for an 12*41125Sbostic * icmp "time exceeded" reply from a gateway. We start our probes 13*41125Sbostic * with a ttl of one and increase by one until we get an icmp "port 14*41125Sbostic * unreachable" (which means we got to "host") or hit a max (which 15*41125Sbostic * defaults to 30 hops & can be changed with the -m flag). Three 16*41125Sbostic * probes (change with -q flag) are sent at each ttl setting and a 17*41125Sbostic * line is printed showing the ttl, address of the gateway and 18*41125Sbostic * round trip time of each probe. If the probe answers come from 19*41125Sbostic * different gateways, the address of each responding system will 20*41125Sbostic * be printed. If there is no response within a 5 sec. timeout 21*41125Sbostic * interval (changed with the -w flag), a "*" is printed for that 22*41125Sbostic * probe. 23*41125Sbostic * 24*41125Sbostic * Probe packets are UDP format. We don't want the destination 25*41125Sbostic * host to process them so the destination port is set to an 26*41125Sbostic * unlikely value (if some clod on the destination is using that 27*41125Sbostic * value, it can be changed with the -p flag). 28*41125Sbostic * 29*41125Sbostic * A sample use might be: 30*41125Sbostic * 31*41125Sbostic * [yak 71]% traceroute nis.nsf.net. 32*41125Sbostic * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet 33*41125Sbostic * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms 34*41125Sbostic * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 35*41125Sbostic * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 36*41125Sbostic * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms 37*41125Sbostic * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms 38*41125Sbostic * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms 39*41125Sbostic * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms 40*41125Sbostic * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms 41*41125Sbostic * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms 42*41125Sbostic * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms 43*41125Sbostic * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms 44*41125Sbostic * 45*41125Sbostic * Note that lines 2 & 3 are the same. This is due to a buggy 46*41125Sbostic * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards 47*41125Sbostic * packets with a zero ttl. 48*41125Sbostic * 49*41125Sbostic * A more interesting example is: 50*41125Sbostic * 51*41125Sbostic * [yak 72]% traceroute allspice.lcs.mit.edu. 52*41125Sbostic * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max 53*41125Sbostic * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 54*41125Sbostic * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms 55*41125Sbostic * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms 56*41125Sbostic * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms 57*41125Sbostic * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms 58*41125Sbostic * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms 59*41125Sbostic * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms 60*41125Sbostic * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms 61*41125Sbostic * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms 62*41125Sbostic * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms 63*41125Sbostic * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms 64*41125Sbostic * 12 * * * 65*41125Sbostic * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms 66*41125Sbostic * 14 * * * 67*41125Sbostic * 15 * * * 68*41125Sbostic * 16 * * * 69*41125Sbostic * 17 * * * 70*41125Sbostic * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms 71*41125Sbostic * 72*41125Sbostic * (I start to see why I'm having so much trouble with mail to 73*41125Sbostic * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away 74*41125Sbostic * either don't send ICMP "time exceeded" messages or send them 75*41125Sbostic * with a ttl too small to reach us. 14 - 17 are running the 76*41125Sbostic * MIT C Gateway code that doesn't send "time exceeded"s. God 77*41125Sbostic * only knows what's going on with 12. 78*41125Sbostic * 79*41125Sbostic * The silent gateway 12 in the above may be the result of a bug in 80*41125Sbostic * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) 81*41125Sbostic * sends an unreachable message using whatever ttl remains in the 82*41125Sbostic * original datagram. Since, for gateways, the remaining ttl is 83*41125Sbostic * zero, the icmp "time exceeded" is guaranteed to not make it back 84*41125Sbostic * to us. The behavior of this bug is slightly more interesting 85*41125Sbostic * when it appears on the destination system: 86*41125Sbostic * 87*41125Sbostic * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 88*41125Sbostic * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms 89*41125Sbostic * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms 90*41125Sbostic * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms 91*41125Sbostic * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms 92*41125Sbostic * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms 93*41125Sbostic * 7 * * * 94*41125Sbostic * 8 * * * 95*41125Sbostic * 9 * * * 96*41125Sbostic * 10 * * * 97*41125Sbostic * 11 * * * 98*41125Sbostic * 12 * * * 99*41125Sbostic * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! 100*41125Sbostic * 101*41125Sbostic * Notice that there are 12 "gateways" (13 is the final 102*41125Sbostic * destination) and exactly the last half of them are "missing". 103*41125Sbostic * What's really happening is that rip (a Sun-3 running Sun OS3.5) 104*41125Sbostic * is using the ttl from our arriving datagram as the ttl in its 105*41125Sbostic * icmp reply. So, the reply will time out on the return path 106*41125Sbostic * (with no notice sent to anyone since icmp's aren't sent for 107*41125Sbostic * icmp's) until we probe with a ttl that's at least twice the path 108*41125Sbostic * length. I.e., rip is really only 7 hops away. A reply that 109*41125Sbostic * returns with a ttl of 1 is a clue this problem exists. 110*41125Sbostic * Traceroute prints a "!" after the time if the ttl is <= 1. 111*41125Sbostic * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or 112*41125Sbostic * non-standard (HPUX) software, expect to see this problem 113*41125Sbostic * frequently and/or take care picking the target host of your 114*41125Sbostic * probes. 115*41125Sbostic * 116*41125Sbostic * Other possible annotations after the time are !H, !N, !P (got a host, 117*41125Sbostic * network or protocol unreachable, respectively), !S or !F (source 118*41125Sbostic * route failed or fragmentation needed -- neither of these should 119*41125Sbostic * ever occur and the associated gateway is busted if you see one). If 120*41125Sbostic * almost all the probes result in some kind of unreachable, traceroute 121*41125Sbostic * will give up and exit. 122*41125Sbostic * 123*41125Sbostic * Notes 124*41125Sbostic * ----- 125*41125Sbostic * This program must be run by root or be setuid. (I suggest that 126*41125Sbostic * you *don't* make it setuid -- casual use could result in a lot 127*41125Sbostic * of unnecessary traffic on our poor, congested nets.) 128*41125Sbostic * 129*41125Sbostic * This program requires a kernel mod that does not appear in any 130*41125Sbostic * system available from Berkeley: A raw ip socket using proto 131*41125Sbostic * IPPROTO_RAW must interpret the data sent as an ip datagram (as 132*41125Sbostic * opposed to data to be wrapped in a ip datagram). See the README 133*41125Sbostic * file that came with the source to this program for a description 134*41125Sbostic * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may 135*41125Sbostic * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE 136*41125Sbostic * MODIFIED TO RUN THIS PROGRAM. 137*41125Sbostic * 138*41125Sbostic * The udp port usage may appear bizarre (well, ok, it is bizarre). 139*41125Sbostic * The problem is that an icmp message only contains 8 bytes of 140*41125Sbostic * data from the original datagram. 8 bytes is the size of a udp 141*41125Sbostic * header so, if we want to associate replies with the original 142*41125Sbostic * datagram, the necessary information must be encoded into the 143*41125Sbostic * udp header (the ip id could be used but there's no way to 144*41125Sbostic * interlock with the kernel's assignment of ip id's and, anyway, 145*41125Sbostic * it would have taken a lot more kernel hacking to allow this 146*41125Sbostic * code to set the ip id). So, to allow two or more users to 147*41125Sbostic * use traceroute simultaneously, we use this task's pid as the 148*41125Sbostic * source port (the high bit is set to move the port number out 149*41125Sbostic * of the "likely" range). To keep track of which probe is being 150*41125Sbostic * replied to (so times and/or hop counts don't get confused by a 151*41125Sbostic * reply that was delayed in transit), we increment the destination 152*41125Sbostic * port number before each probe. 153*41125Sbostic * 154*41125Sbostic * Don't use this as a coding example. I was trying to find a 155*41125Sbostic * routing problem and this code sort-of popped out after 48 hours 156*41125Sbostic * without sleep. I was amazed it ever compiled, much less ran. 157*41125Sbostic * 158*41125Sbostic * I stole the idea for this program from Steve Deering. Since 159*41125Sbostic * the first release, I've learned that had I attended the right 160*41125Sbostic * IETF working group meetings, I also could have stolen it from Guy 161*41125Sbostic * Almes or Matt Mathis. I don't know (or care) who came up with 162*41125Sbostic * the idea first. I envy the originators' perspicacity and I'm 163*41125Sbostic * glad they didn't keep the idea a secret. 164*41125Sbostic * 165*41125Sbostic * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or 166*41125Sbostic * enhancements to the original distribution. 167*41125Sbostic * 168*41125Sbostic * I've hacked up a round-trip-route version of this that works by 169*41125Sbostic * sending a loose-source-routed udp datagram through the destination 170*41125Sbostic * back to yourself. Unfortunately, SO many gateways botch source 171*41125Sbostic * routing, the thing is almost worthless. Maybe one day... 172*41125Sbostic * 173*41125Sbostic * -- Van Jacobson (van@helios.ee.lbl.gov) 174*41125Sbostic * Tue Dec 20 03:50:13 PST 1988 175*41125Sbostic * 176*41125Sbostic * Copyright (c) 1988 Regents of the University of California. 177*41125Sbostic * All rights reserved. 178*41125Sbostic * 179*41125Sbostic * Redistribution and use in source and binary forms are permitted 180*41125Sbostic * provided that the above copyright notice and this paragraph are 181*41125Sbostic * duplicated in all such forms and that any documentation, 182*41125Sbostic * advertising materials, and other materials related to such 183*41125Sbostic * distribution and use acknowledge that the software was developed 184*41125Sbostic * by the University of California, Berkeley. The name of the 185*41125Sbostic * University may not be used to endorse or promote products derived 186*41125Sbostic * from this software without specific prior written permission. 187*41125Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 188*41125Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 189*41125Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 190*41125Sbostic */ 191*41125Sbostic 192*41125Sbostic #include <stdio.h> 193*41125Sbostic #include <errno.h> 194*41125Sbostic #include <strings.h> 195*41125Sbostic #include <sys/time.h> 196*41125Sbostic 197*41125Sbostic #include <sys/param.h> 198*41125Sbostic #include <sys/socket.h> 199*41125Sbostic #include <sys/file.h> 200*41125Sbostic #include <sys/ioctl.h> 201*41125Sbostic 202*41125Sbostic #include <netinet/in_systm.h> 203*41125Sbostic #include <netinet/in.h> 204*41125Sbostic #include <netinet/ip.h> 205*41125Sbostic #include <netinet/ip_icmp.h> 206*41125Sbostic #include <netinet/udp.h> 207*41125Sbostic #include <netdb.h> 208*41125Sbostic 209*41125Sbostic #define MAXPACKET 65535 /* max ip packet size */ 210*41125Sbostic #ifndef MAXHOSTNAMELEN 211*41125Sbostic #define MAXHOSTNAMELEN 64 212*41125Sbostic #endif 213*41125Sbostic 214*41125Sbostic #ifndef FD_SET 215*41125Sbostic #define NFDBITS (8*sizeof(fd_set)) 216*41125Sbostic #define FD_SETSIZE NFDBITS 217*41125Sbostic #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 218*41125Sbostic #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 219*41125Sbostic #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 220*41125Sbostic #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 221*41125Sbostic #endif 222*41125Sbostic 223*41125Sbostic #define Fprintf (void)fprintf 224*41125Sbostic #define Sprintf (void)sprintf 225*41125Sbostic #define Printf (void)printf 226*41125Sbostic extern int errno; 227*41125Sbostic extern char *malloc(); 228*41125Sbostic extern char *inet_ntoa(); 229*41125Sbostic extern u_long inet_addr(); 230*41125Sbostic 231*41125Sbostic /* 232*41125Sbostic * format of a (udp) probe packet. 233*41125Sbostic */ 234*41125Sbostic struct opacket { 235*41125Sbostic struct ip ip; 236*41125Sbostic struct udphdr udp; 237*41125Sbostic u_char seq; /* sequence number of this packet */ 238*41125Sbostic u_char ttl; /* ttl packet left with */ 239*41125Sbostic struct timeval tv; /* time packet left */ 240*41125Sbostic }; 241*41125Sbostic 242*41125Sbostic u_char packet[512]; /* last inbound (icmp) packet */ 243*41125Sbostic struct opacket *outpacket; /* last output (udp) packet */ 244*41125Sbostic char *inetname(); 245*41125Sbostic 246*41125Sbostic int s; /* receive (icmp) socket file descriptor */ 247*41125Sbostic int sndsock; /* send (udp) socket file descriptor */ 248*41125Sbostic struct timezone tz; /* leftover */ 249*41125Sbostic 250*41125Sbostic struct sockaddr whereto; /* Who to try to reach */ 251*41125Sbostic int datalen; /* How much data */ 252*41125Sbostic 253*41125Sbostic char *source = 0; 254*41125Sbostic char *hostname; 255*41125Sbostic char hnamebuf[MAXHOSTNAMELEN]; 256*41125Sbostic 257*41125Sbostic int nprobes = 3; 258*41125Sbostic int max_ttl = 30; 259*41125Sbostic u_short ident; 260*41125Sbostic u_short port = 32768+666; /* start udp dest port # for probe packets */ 261*41125Sbostic 262*41125Sbostic int options; /* socket options */ 263*41125Sbostic int verbose; 264*41125Sbostic int waittime = 5; /* time to wait for response (in seconds) */ 265*41125Sbostic int nflag; /* print addresses numerically */ 266*41125Sbostic 267*41125Sbostic char usage[] = 268*41125Sbostic "Usage: traceroute [-dnrv] [-w wait] [-m max_ttl] [-p port#] [-q nqueries] [-t tos] [-s src_addr] host [data size]\n"; 269*41125Sbostic 270*41125Sbostic 271*41125Sbostic main(argc, argv) 272*41125Sbostic char *argv[]; 273*41125Sbostic { 274*41125Sbostic struct sockaddr_in from; 275*41125Sbostic char **av = argv; 276*41125Sbostic struct sockaddr_in *to = (struct sockaddr_in *) &whereto; 277*41125Sbostic int on = 1; 278*41125Sbostic struct protoent *pe; 279*41125Sbostic int ttl, probe, i; 280*41125Sbostic int seq = 0; 281*41125Sbostic int tos = 0; 282*41125Sbostic struct hostent *hp; 283*41125Sbostic 284*41125Sbostic argc--, av++; 285*41125Sbostic while (argc && *av[0] == '-') { 286*41125Sbostic while (*++av[0]) 287*41125Sbostic switch (*av[0]) { 288*41125Sbostic case 'd': 289*41125Sbostic options |= SO_DEBUG; 290*41125Sbostic break; 291*41125Sbostic case 'm': 292*41125Sbostic argc--, av++; 293*41125Sbostic max_ttl = atoi(av[0]); 294*41125Sbostic if (max_ttl <= 1) { 295*41125Sbostic Fprintf(stderr, "max ttl must be >1\n"); 296*41125Sbostic exit(1); 297*41125Sbostic } 298*41125Sbostic goto nextarg; 299*41125Sbostic case 'n': 300*41125Sbostic nflag++; 301*41125Sbostic break; 302*41125Sbostic case 'p': 303*41125Sbostic argc--, av++; 304*41125Sbostic port = atoi(av[0]); 305*41125Sbostic if (port < 1) { 306*41125Sbostic Fprintf(stderr, "port must be >0\n"); 307*41125Sbostic exit(1); 308*41125Sbostic } 309*41125Sbostic goto nextarg; 310*41125Sbostic case 'q': 311*41125Sbostic argc--, av++; 312*41125Sbostic nprobes = atoi(av[0]); 313*41125Sbostic if (nprobes < 1) { 314*41125Sbostic Fprintf(stderr, "nprobes must be >0\n"); 315*41125Sbostic exit(1); 316*41125Sbostic } 317*41125Sbostic goto nextarg; 318*41125Sbostic case 'r': 319*41125Sbostic options |= SO_DONTROUTE; 320*41125Sbostic break; 321*41125Sbostic case 's': 322*41125Sbostic /* 323*41125Sbostic * set the ip source address of the outbound 324*41125Sbostic * probe (e.g., on a multi-homed host). 325*41125Sbostic */ 326*41125Sbostic argc--, av++; 327*41125Sbostic source = av[0]; 328*41125Sbostic goto nextarg; 329*41125Sbostic case 't': 330*41125Sbostic argc--, av++; 331*41125Sbostic tos = atoi(av[0]); 332*41125Sbostic if (tos < 0 || tos > 255) { 333*41125Sbostic Fprintf(stderr, "tos must be 0 to 255\n"); 334*41125Sbostic exit(1); 335*41125Sbostic } 336*41125Sbostic goto nextarg; 337*41125Sbostic case 'v': 338*41125Sbostic verbose++; 339*41125Sbostic break; 340*41125Sbostic case 'w': 341*41125Sbostic argc--, av++; 342*41125Sbostic waittime = atoi(av[0]); 343*41125Sbostic if (waittime <= 1) { 344*41125Sbostic Fprintf(stderr, "wait must be >1 sec\n"); 345*41125Sbostic exit(1); 346*41125Sbostic } 347*41125Sbostic goto nextarg; 348*41125Sbostic } 349*41125Sbostic nextarg: 350*41125Sbostic argc--, av++; 351*41125Sbostic } 352*41125Sbostic if (argc < 1) { 353*41125Sbostic Printf(usage); 354*41125Sbostic exit(1); 355*41125Sbostic } 356*41125Sbostic setlinebuf (stdout); 357*41125Sbostic 358*41125Sbostic (void) bzero((char *)&whereto, sizeof(struct sockaddr)); 359*41125Sbostic to->sin_family = AF_INET; 360*41125Sbostic to->sin_addr.s_addr = inet_addr(av[0]); 361*41125Sbostic if (to->sin_addr.s_addr != -1) { 362*41125Sbostic (void) strcpy(hnamebuf, av[0]); 363*41125Sbostic hostname = hnamebuf; 364*41125Sbostic } else { 365*41125Sbostic hp = gethostbyname(av[0]); 366*41125Sbostic if (hp) { 367*41125Sbostic to->sin_family = hp->h_addrtype; 368*41125Sbostic bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length); 369*41125Sbostic hostname = hp->h_name; 370*41125Sbostic } else { 371*41125Sbostic Printf("%s: unknown host %s\n", argv[0], av[0]); 372*41125Sbostic exit(1); 373*41125Sbostic } 374*41125Sbostic } 375*41125Sbostic 376*41125Sbostic if (argc >= 2) 377*41125Sbostic datalen = atoi(av[1]); 378*41125Sbostic if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) { 379*41125Sbostic Fprintf(stderr, "traceroute: packet size must be 0 <= s < %ld\n", 380*41125Sbostic MAXPACKET - sizeof(struct opacket)); 381*41125Sbostic exit(1); 382*41125Sbostic } 383*41125Sbostic datalen += sizeof(struct opacket); 384*41125Sbostic outpacket = (struct opacket *)malloc((unsigned)datalen); 385*41125Sbostic if (! outpacket) { 386*41125Sbostic perror("traceroute: malloc"); 387*41125Sbostic exit(1); 388*41125Sbostic } 389*41125Sbostic (void) bzero((char *)outpacket, datalen); 390*41125Sbostic outpacket->ip.ip_dst = to->sin_addr; 391*41125Sbostic outpacket->ip.ip_tos = tos; 392*41125Sbostic 393*41125Sbostic ident = (getpid() & 0xffff) | 0x8000; 394*41125Sbostic 395*41125Sbostic if ((pe = getprotobyname("icmp")) == NULL) { 396*41125Sbostic Fprintf(stderr, "icmp: unknown protocol\n"); 397*41125Sbostic exit(10); 398*41125Sbostic } 399*41125Sbostic if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) { 400*41125Sbostic perror("traceroute: icmp socket"); 401*41125Sbostic exit(5); 402*41125Sbostic } 403*41125Sbostic if (options & SO_DEBUG) 404*41125Sbostic (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 405*41125Sbostic (char *)&on, sizeof(on)); 406*41125Sbostic if (options & SO_DONTROUTE) 407*41125Sbostic (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, 408*41125Sbostic (char *)&on, sizeof(on)); 409*41125Sbostic 410*41125Sbostic if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { 411*41125Sbostic perror("traceroute: raw socket"); 412*41125Sbostic exit(5); 413*41125Sbostic } 414*41125Sbostic #ifdef SO_SNDBUF 415*41125Sbostic if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, 416*41125Sbostic sizeof(datalen)) < 0) { 417*41125Sbostic perror("traceroute: SO_SNDBUF"); 418*41125Sbostic exit(6); 419*41125Sbostic } 420*41125Sbostic #endif SO_SNDBUF 421*41125Sbostic #ifdef IP_HDRINCL 422*41125Sbostic if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, 423*41125Sbostic sizeof(on)) < 0) { 424*41125Sbostic perror("traceroute: IP_HDRINCL"); 425*41125Sbostic exit(6); 426*41125Sbostic } 427*41125Sbostic #endif IP_HDRINCL 428*41125Sbostic if (options & SO_DEBUG) 429*41125Sbostic (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 430*41125Sbostic (char *)&on, sizeof(on)); 431*41125Sbostic if (options & SO_DONTROUTE) 432*41125Sbostic (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, 433*41125Sbostic (char *)&on, sizeof(on)); 434*41125Sbostic 435*41125Sbostic if (source) { 436*41125Sbostic (void) bzero((char *)&from, sizeof(struct sockaddr)); 437*41125Sbostic from.sin_family = AF_INET; 438*41125Sbostic from.sin_addr.s_addr = inet_addr(source); 439*41125Sbostic if (from.sin_addr.s_addr == -1) { 440*41125Sbostic Printf("traceroute: unknown host %s\n", source); 441*41125Sbostic exit(1); 442*41125Sbostic } 443*41125Sbostic outpacket->ip.ip_src = from.sin_addr; 444*41125Sbostic #ifndef IP_HDRINCL 445*41125Sbostic if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) { 446*41125Sbostic perror ("traceroute: bind:"); 447*41125Sbostic exit (1); 448*41125Sbostic } 449*41125Sbostic #endif IP_HDRINCL 450*41125Sbostic } 451*41125Sbostic 452*41125Sbostic Fprintf(stderr, "traceroute to %s (%s)", hostname, 453*41125Sbostic inet_ntoa(to->sin_addr)); 454*41125Sbostic if (source) 455*41125Sbostic Fprintf(stderr, " from %s", source); 456*41125Sbostic Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen); 457*41125Sbostic (void) fflush(stderr); 458*41125Sbostic 459*41125Sbostic for (ttl = 1; ttl <= max_ttl; ++ttl) { 460*41125Sbostic u_long lastaddr = 0; 461*41125Sbostic int got_there = 0; 462*41125Sbostic int unreachable = 0; 463*41125Sbostic 464*41125Sbostic Printf("%2d ", ttl); 465*41125Sbostic for (probe = 0; probe < nprobes; ++probe) { 466*41125Sbostic int cc; 467*41125Sbostic struct timeval tv; 468*41125Sbostic struct ip *ip; 469*41125Sbostic 470*41125Sbostic (void) gettimeofday(&tv, &tz); 471*41125Sbostic send_probe(++seq, ttl); 472*41125Sbostic while (cc = wait_for_reply(s, &from)) { 473*41125Sbostic if ((i = packet_ok(packet, cc, &from, seq))) { 474*41125Sbostic int dt = deltaT(&tv); 475*41125Sbostic if (from.sin_addr.s_addr != lastaddr) { 476*41125Sbostic print(packet, cc, &from); 477*41125Sbostic lastaddr = from.sin_addr.s_addr; 478*41125Sbostic } 479*41125Sbostic Printf(" %d ms", dt); 480*41125Sbostic switch(i - 1) { 481*41125Sbostic case ICMP_UNREACH_PORT: 482*41125Sbostic #ifndef ARCHAIC 483*41125Sbostic ip = (struct ip *)packet; 484*41125Sbostic if (ip->ip_ttl <= 1) 485*41125Sbostic Printf(" !"); 486*41125Sbostic #endif ARCHAIC 487*41125Sbostic ++got_there; 488*41125Sbostic break; 489*41125Sbostic case ICMP_UNREACH_NET: 490*41125Sbostic ++unreachable; 491*41125Sbostic Printf(" !N"); 492*41125Sbostic break; 493*41125Sbostic case ICMP_UNREACH_HOST: 494*41125Sbostic ++unreachable; 495*41125Sbostic Printf(" !H"); 496*41125Sbostic break; 497*41125Sbostic case ICMP_UNREACH_PROTOCOL: 498*41125Sbostic ++got_there; 499*41125Sbostic Printf(" !P"); 500*41125Sbostic break; 501*41125Sbostic case ICMP_UNREACH_NEEDFRAG: 502*41125Sbostic ++unreachable; 503*41125Sbostic Printf(" !F"); 504*41125Sbostic break; 505*41125Sbostic case ICMP_UNREACH_SRCFAIL: 506*41125Sbostic ++unreachable; 507*41125Sbostic Printf(" !S"); 508*41125Sbostic break; 509*41125Sbostic } 510*41125Sbostic break; 511*41125Sbostic } 512*41125Sbostic } 513*41125Sbostic if (cc == 0) 514*41125Sbostic Printf(" *"); 515*41125Sbostic (void) fflush(stdout); 516*41125Sbostic } 517*41125Sbostic putchar('\n'); 518*41125Sbostic if (got_there || unreachable >= nprobes-1) 519*41125Sbostic exit(0); 520*41125Sbostic } 521*41125Sbostic } 522*41125Sbostic 523*41125Sbostic wait_for_reply(sock, from) 524*41125Sbostic int sock; 525*41125Sbostic struct sockaddr_in *from; 526*41125Sbostic { 527*41125Sbostic fd_set fds; 528*41125Sbostic struct timeval wait; 529*41125Sbostic int cc = 0; 530*41125Sbostic int fromlen = sizeof (*from); 531*41125Sbostic 532*41125Sbostic FD_ZERO(&fds); 533*41125Sbostic FD_SET(sock, &fds); 534*41125Sbostic wait.tv_sec = waittime; wait.tv_usec = 0; 535*41125Sbostic 536*41125Sbostic if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0) 537*41125Sbostic cc=recvfrom(s, (char *)packet, sizeof(packet), 0, 538*41125Sbostic (struct sockaddr *)from, &fromlen); 539*41125Sbostic 540*41125Sbostic return(cc); 541*41125Sbostic } 542*41125Sbostic 543*41125Sbostic 544*41125Sbostic send_probe(seq, ttl) 545*41125Sbostic { 546*41125Sbostic struct opacket *op = outpacket; 547*41125Sbostic struct ip *ip = &op->ip; 548*41125Sbostic struct udphdr *up = &op->udp; 549*41125Sbostic int i; 550*41125Sbostic 551*41125Sbostic ip->ip_off = 0; 552*41125Sbostic ip->ip_p = IPPROTO_UDP; 553*41125Sbostic ip->ip_len = datalen; 554*41125Sbostic ip->ip_ttl = ttl; 555*41125Sbostic 556*41125Sbostic up->uh_sport = htons(ident); 557*41125Sbostic up->uh_dport = htons(port+seq); 558*41125Sbostic up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip))); 559*41125Sbostic up->uh_sum = 0; 560*41125Sbostic 561*41125Sbostic op->seq = seq; 562*41125Sbostic op->ttl = ttl; 563*41125Sbostic (void) gettimeofday(&op->tv, &tz); 564*41125Sbostic 565*41125Sbostic i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto, 566*41125Sbostic sizeof(struct sockaddr)); 567*41125Sbostic if (i < 0 || i != datalen) { 568*41125Sbostic if (i<0) 569*41125Sbostic perror("sendto"); 570*41125Sbostic Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname, 571*41125Sbostic datalen, i); 572*41125Sbostic (void) fflush(stdout); 573*41125Sbostic } 574*41125Sbostic } 575*41125Sbostic 576*41125Sbostic 577*41125Sbostic deltaT(tp) 578*41125Sbostic struct timeval *tp; 579*41125Sbostic { 580*41125Sbostic struct timeval tv; 581*41125Sbostic 582*41125Sbostic (void) gettimeofday(&tv, &tz); 583*41125Sbostic tvsub(&tv, tp); 584*41125Sbostic return (tv.tv_sec*1000 + (tv.tv_usec + 500)/1000); 585*41125Sbostic } 586*41125Sbostic 587*41125Sbostic 588*41125Sbostic /* 589*41125Sbostic * Convert an ICMP "type" field to a printable string. 590*41125Sbostic */ 591*41125Sbostic char * 592*41125Sbostic pr_type(t) 593*41125Sbostic u_char t; 594*41125Sbostic { 595*41125Sbostic static char *ttab[] = { 596*41125Sbostic "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", 597*41125Sbostic "Source Quench", "Redirect", "ICMP 6", "ICMP 7", 598*41125Sbostic "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", 599*41125Sbostic "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", 600*41125Sbostic "Info Reply" 601*41125Sbostic }; 602*41125Sbostic 603*41125Sbostic if(t > 16) 604*41125Sbostic return("OUT-OF-RANGE"); 605*41125Sbostic 606*41125Sbostic return(ttab[t]); 607*41125Sbostic } 608*41125Sbostic 609*41125Sbostic 610*41125Sbostic packet_ok(buf, cc, from, seq) 611*41125Sbostic u_char *buf; 612*41125Sbostic int cc; 613*41125Sbostic struct sockaddr_in *from; 614*41125Sbostic int seq; 615*41125Sbostic { 616*41125Sbostic register struct icmp *icp; 617*41125Sbostic u_char type, code; 618*41125Sbostic int hlen; 619*41125Sbostic #ifndef ARCHAIC 620*41125Sbostic struct ip *ip; 621*41125Sbostic 622*41125Sbostic ip = (struct ip *) buf; 623*41125Sbostic hlen = ip->ip_hl << 2; 624*41125Sbostic if (cc < hlen + ICMP_MINLEN) { 625*41125Sbostic if (verbose) 626*41125Sbostic Printf("packet too short (%d bytes) from %s\n", cc, 627*41125Sbostic inet_ntoa(from->sin_addr)); 628*41125Sbostic return (0); 629*41125Sbostic } 630*41125Sbostic cc -= hlen; 631*41125Sbostic icp = (struct icmp *)(buf + hlen); 632*41125Sbostic #else 633*41125Sbostic icp = (struct icmp *)buf; 634*41125Sbostic #endif ARCHAIC 635*41125Sbostic type = icp->icmp_type; code = icp->icmp_code; 636*41125Sbostic if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || 637*41125Sbostic type == ICMP_UNREACH) { 638*41125Sbostic struct ip *hip; 639*41125Sbostic struct udphdr *up; 640*41125Sbostic 641*41125Sbostic hip = &icp->icmp_ip; 642*41125Sbostic hlen = hip->ip_hl << 2; 643*41125Sbostic up = (struct udphdr *)((u_char *)hip + hlen); 644*41125Sbostic if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP && 645*41125Sbostic up->uh_sport == htons(ident) && 646*41125Sbostic up->uh_dport == htons(port+seq)) 647*41125Sbostic return (type == ICMP_TIMXCEED? -1 : code+1); 648*41125Sbostic } 649*41125Sbostic #ifndef ARCHAIC 650*41125Sbostic if (verbose) { 651*41125Sbostic int i; 652*41125Sbostic u_long *lp = (u_long *)&icp->icmp_ip; 653*41125Sbostic 654*41125Sbostic Printf("\n%d bytes from %s to %s", cc, 655*41125Sbostic inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst)); 656*41125Sbostic Printf(": icmp type %d (%s) code %d\n", type, pr_type(type), 657*41125Sbostic icp->icmp_code); 658*41125Sbostic for (i = 4; i < cc ; i += sizeof(long)) 659*41125Sbostic Printf("%2d: x%8.8lx\n", i, *lp++); 660*41125Sbostic } 661*41125Sbostic #endif ARCHAIC 662*41125Sbostic return(0); 663*41125Sbostic } 664*41125Sbostic 665*41125Sbostic 666*41125Sbostic print(buf, cc, from) 667*41125Sbostic u_char *buf; 668*41125Sbostic int cc; 669*41125Sbostic struct sockaddr_in *from; 670*41125Sbostic { 671*41125Sbostic struct ip *ip; 672*41125Sbostic int hlen; 673*41125Sbostic 674*41125Sbostic ip = (struct ip *) buf; 675*41125Sbostic hlen = ip->ip_hl << 2; 676*41125Sbostic cc -= hlen; 677*41125Sbostic 678*41125Sbostic if (nflag) 679*41125Sbostic Printf(" %s", inet_ntoa(from->sin_addr)); 680*41125Sbostic else 681*41125Sbostic Printf(" %s (%s)", inetname(from->sin_addr), 682*41125Sbostic inet_ntoa(from->sin_addr)); 683*41125Sbostic 684*41125Sbostic if (verbose) 685*41125Sbostic Printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); 686*41125Sbostic } 687*41125Sbostic 688*41125Sbostic 689*41125Sbostic #ifdef notyet 690*41125Sbostic /* 691*41125Sbostic * Checksum routine for Internet Protocol family headers (C Version) 692*41125Sbostic */ 693*41125Sbostic in_cksum(addr, len) 694*41125Sbostic u_short *addr; 695*41125Sbostic int len; 696*41125Sbostic { 697*41125Sbostic register int nleft = len; 698*41125Sbostic register u_short *w = addr; 699*41125Sbostic register u_short answer; 700*41125Sbostic register int sum = 0; 701*41125Sbostic 702*41125Sbostic /* 703*41125Sbostic * Our algorithm is simple, using a 32 bit accumulator (sum), 704*41125Sbostic * we add sequential 16 bit words to it, and at the end, fold 705*41125Sbostic * back all the carry bits from the top 16 bits into the lower 706*41125Sbostic * 16 bits. 707*41125Sbostic */ 708*41125Sbostic while (nleft > 1) { 709*41125Sbostic sum += *w++; 710*41125Sbostic nleft -= 2; 711*41125Sbostic } 712*41125Sbostic 713*41125Sbostic /* mop up an odd byte, if necessary */ 714*41125Sbostic if (nleft == 1) 715*41125Sbostic sum += *(u_char *)w; 716*41125Sbostic 717*41125Sbostic /* 718*41125Sbostic * add back carry outs from top 16 bits to low 16 bits 719*41125Sbostic */ 720*41125Sbostic sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 721*41125Sbostic sum += (sum >> 16); /* add carry */ 722*41125Sbostic answer = ~sum; /* truncate to 16 bits */ 723*41125Sbostic return (answer); 724*41125Sbostic } 725*41125Sbostic #endif notyet 726*41125Sbostic 727*41125Sbostic /* 728*41125Sbostic * Subtract 2 timeval structs: out = out - in. 729*41125Sbostic * Out is assumed to be >= in. 730*41125Sbostic */ 731*41125Sbostic tvsub(out, in) 732*41125Sbostic register struct timeval *out, *in; 733*41125Sbostic { 734*41125Sbostic if ((out->tv_usec -= in->tv_usec) < 0) { 735*41125Sbostic out->tv_sec--; 736*41125Sbostic out->tv_usec += 1000000; 737*41125Sbostic } 738*41125Sbostic out->tv_sec -= in->tv_sec; 739*41125Sbostic } 740*41125Sbostic 741*41125Sbostic 742*41125Sbostic /* 743*41125Sbostic * Construct an Internet address representation. 744*41125Sbostic * If the nflag has been supplied, give 745*41125Sbostic * numeric value, otherwise try for symbolic name. 746*41125Sbostic */ 747*41125Sbostic char * 748*41125Sbostic inetname(in) 749*41125Sbostic struct in_addr in; 750*41125Sbostic { 751*41125Sbostic register char *cp; 752*41125Sbostic static char line[50]; 753*41125Sbostic struct hostent *hp; 754*41125Sbostic static char domain[MAXHOSTNAMELEN + 1]; 755*41125Sbostic static int first = 1; 756*41125Sbostic 757*41125Sbostic if (first && !nflag) { 758*41125Sbostic first = 0; 759*41125Sbostic if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 760*41125Sbostic (cp = index(domain, '.'))) 761*41125Sbostic (void) strcpy(domain, cp + 1); 762*41125Sbostic else 763*41125Sbostic domain[0] = 0; 764*41125Sbostic } 765*41125Sbostic cp = 0; 766*41125Sbostic if (!nflag && in.s_addr != INADDR_ANY) { 767*41125Sbostic hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET); 768*41125Sbostic if (hp) { 769*41125Sbostic if ((cp = index(hp->h_name, '.')) && 770*41125Sbostic !strcmp(cp + 1, domain)) 771*41125Sbostic *cp = 0; 772*41125Sbostic cp = hp->h_name; 773*41125Sbostic } 774*41125Sbostic } 775*41125Sbostic if (cp) 776*41125Sbostic (void) strcpy(line, cp); 777*41125Sbostic else { 778*41125Sbostic in.s_addr = ntohl(in.s_addr); 779*41125Sbostic #define C(x) ((x) & 0xff) 780*41125Sbostic Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >> 24), 781*41125Sbostic C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); 782*41125Sbostic } 783*41125Sbostic return (line); 784*41125Sbostic } 785