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