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