1 /* 2 * Modified for NRL 4.4BSD IPv6 release. 3 * 07/31/96 bgp 4 * 5 * Search for "#ifdef NRL" to find the changes. 6 */ 7 8 /* 9 * Modified for Linux IPv6 by Pedro Roque <roque (at) di.fc.ul.pt> 10 * 31/07/1996 11 * 12 * As ICMP error messages for IPv6 now include more than 8 bytes 13 * UDP datagrams are now sent via an UDP socket instead of magic 14 * RAW socket tricks. 15 * 16 * Original copyright and comments left intact. They might not 17 * match the code anymore. 18 */ 19 20 /*- 21 * Copyright (c) 1990, 1993 22 * The Regents of the University of California. All rights reserved. 23 * 24 * This code is derived from software contributed to Berkeley by 25 * Van Jacobson. 26 * 27 * Redistribution and use in source and binary forms, with or without 28 * modification, are permitted provided that the following conditions 29 * are met: 30 * 1. Redistributions of source code must retain the above copyright 31 * notice, this list of conditions and the following disclaimer. 32 * 2. Redistributions in binary form must reproduce the above copyright 33 * notice, this list of conditions and the following disclaimer in the 34 * documentation and/or other materials provided with the distribution. 35 * 3. All advertising materials mentioning features or use of this software 36 * must display the following acknowledgement: 37 * This product includes software developed by the University of 38 * California, Berkeley and its contributors. 39 * 4. Neither the name of the University nor the names of its contributors 40 * may be used to endorse or promote products derived from this software 41 * without specific prior written permission. 42 * 43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 53 * SUCH DAMAGE. 54 */ 55 56 #ifndef lint 57 char copyright[] = 58 "@(#) Copyright (c) 1990, 1993\n\ 59 The Regents of the University of California. All rights reserved.\n"; 60 #endif /* not lint */ 61 62 /* 63 * traceroute host - trace the route ip packets follow going to "host". 64 * 65 * Attempt to trace the route an ip packet would follow to some 66 * internet host. We find out intermediate hops by launching probe 67 * packets with a small ttl (time to live) then listening for an 68 * icmp "time exceeded" reply from a gateway. We start our probes 69 * with a ttl of one and increase by one until we get an icmp "port 70 * unreachable" (which means we got to "host") or hit a max (which 71 * defaults to 30 hops & can be changed with the -m flag). Three 72 * probes (change with -q flag) are sent at each ttl setting and a 73 * line is printed showing the ttl, address of the gateway and 74 * round trip time of each probe. If the probe answers come from 75 * different gateways, the address of each responding system will 76 * be printed. If there is no response within a 5 sec. timeout 77 * interval (changed with the -w flag), a "*" is printed for that 78 * probe. 79 * 80 * Probe packets are UDP format. We don't want the destination 81 * host to process them so the destination port is set to an 82 * unlikely value (if some clod on the destination is using that 83 * value, it can be changed with the -p flag). 84 * 85 * A sample use might be: 86 * 87 * [yak 71]% traceroute nis.nsf.net. 88 * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet 89 * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms 90 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 91 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 92 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms 93 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms 94 * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms 95 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms 96 * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms 97 * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms 98 * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms 99 * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms 100 * 101 * Note that lines 2 & 3 are the same. This is due to a buggy 102 * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards 103 * packets with a zero ttl. 104 * 105 * A more interesting example is: 106 * 107 * [yak 72]% traceroute allspice.lcs.mit.edu. 108 * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max 109 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 110 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms 111 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms 112 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms 113 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms 114 * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms 115 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms 116 * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms 117 * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms 118 * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms 119 * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms 120 * 12 * * * 121 * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms 122 * 14 * * * 123 * 15 * * * 124 * 16 * * * 125 * 17 * * * 126 * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms 127 * 128 * (I start to see why I'm having so much trouble with mail to 129 * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away 130 * either don't send ICMP "time exceeded" messages or send them 131 * with a ttl too small to reach us. 14 - 17 are running the 132 * MIT C Gateway code that doesn't send "time exceeded"s. God 133 * only knows what's going on with 12. 134 * 135 * The silent gateway 12 in the above may be the result of a bug in 136 * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) 137 * sends an unreachable message using whatever ttl remains in the 138 * original datagram. Since, for gateways, the remaining ttl is 139 * zero, the icmp "time exceeded" is guaranteed to not make it back 140 * to us. The behavior of this bug is slightly more interesting 141 * when it appears on the destination system: 142 * 143 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 144 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms 145 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms 146 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms 147 * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms 148 * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms 149 * 7 * * * 150 * 8 * * * 151 * 9 * * * 152 * 10 * * * 153 * 11 * * * 154 * 12 * * * 155 * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! 156 * 157 * Notice that there are 12 "gateways" (13 is the final 158 * destination) and exactly the last half of them are "missing". 159 * What's really happening is that rip (a Sun-3 running Sun OS3.5) 160 * is using the ttl from our arriving datagram as the ttl in its 161 * icmp reply. So, the reply will time out on the return path 162 * (with no notice sent to anyone since icmp's aren't sent for 163 * icmp's) until we probe with a ttl that's at least twice the path 164 * length. I.e., rip is really only 7 hops away. A reply that 165 * returns with a ttl of 1 is a clue this problem exists. 166 * Traceroute prints a "!" after the time if the ttl is <= 1. 167 * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or 168 * non-standard (HPUX) software, expect to see this problem 169 * frequently and/or take care picking the target host of your 170 * probes. 171 * 172 * Other possible annotations after the time are !H, !N, !P (got a host, 173 * network or protocol unreachable, respectively), !S or !F (source 174 * route failed or fragmentation needed -- neither of these should 175 * ever occur and the associated gateway is busted if you see one). If 176 * almost all the probes result in some kind of unreachable, traceroute 177 * will give up and exit. 178 * 179 * Notes 180 * ----- 181 * This program must be run by root or be setuid. (I suggest that 182 * you *don't* make it setuid -- casual use could result in a lot 183 * of unnecessary traffic on our poor, congested nets.) 184 * 185 * This program requires a kernel mod that does not appear in any 186 * system available from Berkeley: A raw ip socket using proto 187 * IPPROTO_RAW must interpret the data sent as an ip datagram (as 188 * opposed to data to be wrapped in a ip datagram). See the README 189 * file that came with the source to this program for a description 190 * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may 191 * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE 192 * MODIFIED TO RUN THIS PROGRAM. 193 * 194 * The udp port usage may appear bizarre (well, ok, it is bizarre). 195 * The problem is that an icmp message only contains 8 bytes of 196 * data from the original datagram. 8 bytes is the size of a udp 197 * header so, if we want to associate replies with the original 198 * datagram, the necessary information must be encoded into the 199 * udp header (the ip id could be used but there's no way to 200 * interlock with the kernel's assignment of ip id's and, anyway, 201 * it would have taken a lot more kernel hacking to allow this 202 * code to set the ip id). So, to allow two or more users to 203 * use traceroute simultaneously, we use this task's pid as the 204 * source port (the high bit is set to move the port number out 205 * of the "likely" range). To keep track of which probe is being 206 * replied to (so times and/or hop counts don't get confused by a 207 * reply that was delayed in transit), we increment the destination 208 * port number before each probe. 209 * 210 * Don't use this as a coding example. I was trying to find a 211 * routing problem and this code sort-of popped out after 48 hours 212 * without sleep. I was amazed it ever compiled, much less ran. 213 * 214 * I stole the idea for this program from Steve Deering. Since 215 * the first release, I've learned that had I attended the right 216 * IETF working group meetings, I also could have stolen it from Guy 217 * Almes or Matt Mathis. I don't know (or care) who came up with 218 * the idea first. I envy the originators' perspicacity and I'm 219 * glad they didn't keep the idea a secret. 220 * 221 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or 222 * enhancements to the original distribution. 223 * 224 * I've hacked up a round-trip-route version of this that works by 225 * sending a loose-source-routed udp datagram through the destination 226 * back to yourself. Unfortunately, SO many gateways botch source 227 * routing, the thing is almost worthless. Maybe one day... 228 * 229 * -- Van Jacobson (van (at) helios.ee.lbl.gov) 230 * Tue Dec 20 03:50:13 PST 1988 231 */ 232 233 #include <sys/param.h> 234 #include <sys/time.h> 235 #include <sys/socket.h> 236 #include <sys/file.h> 237 #include <sys/ioctl.h> 238 #include <net/if.h> 239 240 #if __linux__ 241 #include <endian.h> 242 #endif 243 #include <netinet/in_systm.h> 244 #include <netinet/in.h> 245 #include <netinet/ip.h> 246 #include <netinet/ip_icmp.h> 247 #include <netinet/udp.h> 248 249 #include <netinet/ip6.h> 250 #include <netinet/icmp6.h> 251 #include <linux/types.h> 252 #ifdef CAPABILITIES 253 #include <sys/capability.h> 254 #endif 255 256 #ifdef USE_IDN 257 #include <idna.h> 258 #include <locale.h> 259 #endif 260 261 #include <arpa/inet.h> 262 263 #include <netdb.h> 264 #include <stdio.h> 265 #include <errno.h> 266 #include <stdlib.h> 267 #include <string.h> 268 #include <unistd.h> 269 270 #include "SNAPSHOT.h" 271 272 #ifndef SOL_IPV6 273 #define SOL_IPV6 IPPROTO_IPV6 274 #endif 275 276 #define MAXPACKET 65535 277 #define MAX_HOSTNAMELEN NI_MAXHOST 278 279 #ifndef FD_SET 280 #define NFDBITS (8*sizeof(fd_set)) 281 #define FD_SETSIZE NFDBITS 282 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 283 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 284 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 285 #define FD_ZERO(p) memset((char *)(p), 0, sizeof(*(p))) 286 #endif 287 288 #define Fprintf (void)fprintf 289 #define Printf (void)printf 290 291 u_char packet[512]; /* last inbound (icmp) packet */ 292 293 int wait_for_reply(int, struct sockaddr_in6 *, struct in6_addr *, int); 294 int packet_ok(u_char *buf, int cc, struct sockaddr_in6 *from, 295 struct in6_addr *to, int seq, struct timeval *); 296 void send_probe(int seq, int ttl); 297 double deltaT (struct timeval *, struct timeval *); 298 void print(unsigned char *buf, int cc, struct sockaddr_in6 *from); 299 void tvsub (struct timeval *, struct timeval *); 300 void usage(void); 301 302 int icmp_sock; /* receive (icmp) socket file descriptor */ 303 int sndsock; /* send (udp) socket file descriptor */ 304 struct timezone tz; /* leftover */ 305 306 struct sockaddr_in6 whereto; /* Who to try to reach */ 307 308 struct sockaddr_in6 saddr; 309 struct sockaddr_in6 firsthop; 310 char *source = NULL; 311 char *device = NULL; 312 char *hostname; 313 314 int nprobes = 3; 315 int max_ttl = 30; 316 pid_t ident; 317 u_short port = 32768+666; /* start udp dest port # for probe packets */ 318 int options; /* socket options */ 319 int verbose; 320 int waittime = 5; /* time to wait for response (in seconds) */ 321 int nflag; /* print addresses numerically */ 322 323 324 struct pkt_format 325 { 326 __u32 ident; 327 __u32 seq; 328 struct timeval tv; 329 }; 330 331 char *sendbuff; 332 int datalen = sizeof(struct pkt_format); 333 334 335 336 int main(int argc, char *argv[]) 337 { 338 char pa[MAX_HOSTNAMELEN]; 339 extern char *optarg; 340 extern int optind; 341 struct hostent *hp; 342 struct sockaddr_in6 from, *to; 343 int ch, i, on, probe, seq, tos, ttl; 344 int socket_errno; 345 346 icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 347 socket_errno = errno; 348 349 if (setuid(getuid())) { 350 perror("traceroute6: setuid"); 351 exit(-1); 352 } 353 #ifdef CAPABILITIES 354 { 355 cap_t caps = cap_init(); 356 if (cap_set_proc(caps)) { 357 perror("traceroute6: cap_set_proc"); 358 exit(-1); 359 } 360 cap_free(caps); 361 } 362 #endif 363 364 #ifdef USE_IDN 365 setlocale(LC_ALL, ""); 366 #endif 367 368 on = 1; 369 seq = tos = 0; 370 to = (struct sockaddr_in6 *)&whereto; 371 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:vi:g:V")) != EOF) { 372 switch(ch) { 373 case 'd': 374 options |= SO_DEBUG; 375 break; 376 case 'm': 377 max_ttl = atoi(optarg); 378 if (max_ttl <= 1) { 379 Fprintf(stderr, 380 "traceroute: max ttl must be >1.\n"); 381 exit(1); 382 } 383 break; 384 case 'n': 385 nflag++; 386 break; 387 case 'p': 388 port = atoi(optarg); 389 if (port < 1) { 390 Fprintf(stderr, 391 "traceroute: port must be >0.\n"); 392 exit(1); 393 } 394 break; 395 case 'q': 396 nprobes = atoi(optarg); 397 if (nprobes < 1) { 398 Fprintf(stderr, 399 "traceroute: nprobes must be >0.\n"); 400 exit(1); 401 } 402 break; 403 case 'r': 404 options |= SO_DONTROUTE; 405 break; 406 case 's': 407 /* 408 * set the ip source address of the outbound 409 * probe (e.g., on a multi-homed host). 410 */ 411 source = optarg; 412 break; 413 case 'i': 414 device = optarg; 415 break; 416 case 'g': 417 Fprintf(stderr, "Sorry, rthdr is not yet supported\n"); 418 break; 419 case 'v': 420 verbose++; 421 break; 422 case 'w': 423 waittime = atoi(optarg); 424 if (waittime <= 1) { 425 Fprintf(stderr, 426 "traceroute: wait must be >1 sec.\n"); 427 exit(1); 428 } 429 break; 430 case 'V': 431 printf("traceroute6 utility, iputils-%s\n", SNAPSHOT); 432 exit(0); 433 default: 434 usage(); 435 } 436 } 437 argc -= optind; 438 argv += optind; 439 440 if (argc < 1) 441 usage(); 442 443 setlinebuf (stdout); 444 445 (void) memset((char *)&whereto, 0, sizeof(whereto)); 446 447 to->sin6_family = AF_INET6; 448 to->sin6_port = htons(port); 449 450 if (inet_pton(AF_INET6, *argv, &to->sin6_addr) > 0) { 451 hostname = *argv; 452 } else { 453 char *idn = NULL; 454 #ifdef USE_IDN 455 if (idna_to_ascii_lz(*argv, &idn, 0) != IDNA_SUCCESS) 456 idn = NULL; 457 #endif 458 hp = gethostbyname2(idn ? idn : *argv, AF_INET6); 459 if (hp) { 460 memmove((caddr_t)&to->sin6_addr, hp->h_addr, sizeof(to->sin6_addr)); 461 hostname = (char *)hp->h_name; 462 } else { 463 (void)fprintf(stderr, 464 "traceroute: unknown host %s\n", *argv); 465 exit(1); 466 } 467 } 468 firsthop = *to; 469 if (*++argv) { 470 datalen = atoi(*argv); 471 /* Message for rpm maintainers: have _shame_. If you want 472 * to fix something send the patch to me for sanity checking. 473 * "datalen" patch is a shit. */ 474 if (datalen == 0) 475 datalen = sizeof(struct pkt_format); 476 else if (datalen < (int)sizeof(struct pkt_format) || 477 datalen >= MAXPACKET) { 478 Fprintf(stderr, 479 "traceroute: packet size must be %d <= s < %d.\n", 480 (int)sizeof(struct pkt_format), MAXPACKET); 481 exit(1); 482 } 483 } 484 485 ident = getpid(); 486 487 sendbuff = malloc(datalen); 488 if (sendbuff == NULL) { 489 fprintf(stderr, "malloc failed\n"); 490 exit(1); 491 } 492 493 if (icmp_sock < 0) { 494 errno = socket_errno; 495 perror("traceroute6: icmp socket"); 496 exit(1); 497 } 498 499 #ifdef IPV6_RECVPKTINFO 500 setsockopt(icmp_sock, SOL_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); 501 setsockopt(icmp_sock, SOL_IPV6, IPV6_2292PKTINFO, &on, sizeof(on)); 502 #else 503 setsockopt(icmp_sock, SOL_IPV6, IPV6_PKTINFO, &on, sizeof(on)); 504 #endif 505 506 if (options & SO_DEBUG) 507 setsockopt(icmp_sock, SOL_SOCKET, SO_DEBUG, 508 (char *)&on, sizeof(on)); 509 if (options & SO_DONTROUTE) 510 setsockopt(icmp_sock, SOL_SOCKET, SO_DONTROUTE, 511 (char *)&on, sizeof(on)); 512 513 #ifdef __linux__ 514 on = 2; 515 if (setsockopt(icmp_sock, SOL_RAW, IPV6_CHECKSUM, &on, sizeof(on)) < 0) { 516 /* checksum should be enabled by default and setting this 517 * option might fail anyway. 518 */ 519 fprintf(stderr, "setsockopt(RAW_CHECKSUM) failed - try to continue."); 520 } 521 #endif 522 523 if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 524 perror("traceroute: UDP socket"); 525 exit(5); 526 } 527 #ifdef SO_SNDBUF 528 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, 529 sizeof(datalen)) < 0) { 530 perror("traceroute: SO_SNDBUF"); 531 exit(6); 532 } 533 #endif /* SO_SNDBUF */ 534 535 if (options & SO_DEBUG) 536 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 537 (char *)&on, sizeof(on)); 538 if (options & SO_DONTROUTE) 539 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, 540 (char *)&on, sizeof(on)); 541 542 if (source == NULL) { 543 socklen_t alen; 544 int probe_fd = socket(AF_INET6, SOCK_DGRAM, 0); 545 546 if (probe_fd < 0) { 547 perror("socket"); 548 exit(1); 549 } 550 if (device) { 551 if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1) 552 perror("WARNING: interface is ignored"); 553 } 554 firsthop.sin6_port = htons(1025); 555 if (connect(probe_fd, (struct sockaddr*)&firsthop, sizeof(firsthop)) == -1) { 556 perror("connect"); 557 exit(1); 558 } 559 alen = sizeof(saddr); 560 if (getsockname(probe_fd, (struct sockaddr*)&saddr, &alen) == -1) { 561 perror("getsockname"); 562 exit(1); 563 } 564 saddr.sin6_port = 0; 565 close(probe_fd); 566 } else { 567 (void) memset((char *)&saddr, 0, sizeof(saddr)); 568 saddr.sin6_family = AF_INET6; 569 if (inet_pton(AF_INET6, source, &saddr.sin6_addr) <= 0) 570 { 571 Printf("traceroute: unknown addr %s\n", source); 572 exit(1); 573 } 574 } 575 576 if (bind(sndsock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { 577 perror ("traceroute: bind sending socket"); 578 exit (1); 579 } 580 if (bind(icmp_sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { 581 perror ("traceroute: bind icmp6 socket"); 582 exit (1); 583 } 584 585 Fprintf(stderr, "traceroute to %s (%s)", hostname, 586 inet_ntop(AF_INET6, &to->sin6_addr, pa, sizeof(pa))); 587 588 Fprintf(stderr, " from %s", 589 inet_ntop(AF_INET6, &saddr.sin6_addr, pa, sizeof(pa))); 590 Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen); 591 (void) fflush(stderr); 592 593 for (ttl = 1; ttl <= max_ttl; ++ttl) { 594 struct in6_addr lastaddr = {{{0,}}}; 595 int got_there = 0; 596 int unreachable = 0; 597 598 Printf("%2d ", ttl); 599 for (probe = 0; probe < nprobes; ++probe) { 600 int cc, reset_timer; 601 struct timeval t1, t2; 602 struct timezone tz; 603 struct in6_addr to; 604 605 gettimeofday(&t1, &tz); 606 send_probe(++seq, ttl); 607 reset_timer = 1; 608 609 while ((cc = wait_for_reply(icmp_sock, &from, &to, reset_timer)) != 0) { 610 gettimeofday(&t2, &tz); 611 if ((i = packet_ok(packet, cc, &from, &to, seq, &t1))) { 612 reset_timer = 1; 613 if (memcmp(&from.sin6_addr, &lastaddr, sizeof(from.sin6_addr))) { 614 print(packet, cc, &from); 615 memcpy(&lastaddr, 616 &from.sin6_addr, 617 sizeof(lastaddr)); 618 } 619 Printf(" %g ms", deltaT(&t1, &t2)); 620 switch(i - 1) { 621 case ICMP6_DST_UNREACH_NOPORT: 622 ++got_there; 623 break; 624 625 case ICMP6_DST_UNREACH_NOROUTE: 626 ++unreachable; 627 Printf(" !N"); 628 break; 629 case ICMP6_DST_UNREACH_ADDR: 630 ++unreachable; 631 Printf(" !H"); 632 break; 633 634 case ICMP6_DST_UNREACH_ADMIN: 635 ++unreachable; 636 Printf(" !S"); 637 break; 638 } 639 break; 640 } else 641 reset_timer = 0; 642 } 643 if (cc <= 0) 644 Printf(" *"); 645 (void) fflush(stdout); 646 } 647 putchar('\n'); 648 if (got_there || 649 (unreachable > 0 && unreachable >= nprobes-1)) 650 exit(0); 651 } 652 653 return 0; 654 } 655 656 int 657 wait_for_reply(sock, from, to, reset_timer) 658 int sock; 659 struct sockaddr_in6 *from; 660 struct in6_addr *to; 661 int reset_timer; 662 { 663 fd_set fds; 664 static struct timeval wait; 665 int cc = 0; 666 char cbuf[512]; 667 668 FD_ZERO(&fds); 669 FD_SET(sock, &fds); 670 if (reset_timer) { 671 /* 672 * traceroute could hang if someone else has a ping 673 * running and our ICMP reply gets dropped but we don't 674 * realize it because we keep waking up to handle those 675 * other ICMP packets that keep coming in. To fix this, 676 * "reset_timer" will only be true if the last packet that 677 * came in was for us or if this is the first time we're 678 * waiting for a reply since sending out a probe. Note 679 * that this takes advantage of the select() feature on 680 * Linux where the remaining timeout is written to the 681 * struct timeval area. 682 */ 683 wait.tv_sec = waittime; 684 wait.tv_usec = 0; 685 } 686 687 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0) { 688 struct iovec iov; 689 struct msghdr msg; 690 iov.iov_base = packet; 691 iov.iov_len = sizeof(packet); 692 msg.msg_name = (void *)from; 693 msg.msg_namelen = sizeof(*from); 694 msg.msg_iov = &iov; 695 msg.msg_iovlen = 1; 696 msg.msg_flags = 0; 697 msg.msg_control = cbuf; 698 msg.msg_controllen = sizeof(cbuf); 699 700 cc = recvmsg(icmp_sock, &msg, 0); 701 if (cc >= 0) { 702 struct cmsghdr *cmsg; 703 struct in6_pktinfo *ipi; 704 705 for (cmsg = CMSG_FIRSTHDR(&msg); 706 cmsg; 707 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 708 if (cmsg->cmsg_level != SOL_IPV6) 709 continue; 710 switch (cmsg->cmsg_type) { 711 case IPV6_PKTINFO: 712 #ifdef IPV6_2292PKTINFO 713 case IPV6_2292PKTINFO: 714 #endif 715 ipi = (struct in6_pktinfo *)CMSG_DATA(cmsg); 716 memcpy(to, ipi, sizeof(*to)); 717 } 718 } 719 } 720 } 721 722 return(cc); 723 } 724 725 726 void send_probe(int seq, int ttl) 727 { 728 struct pkt_format *pkt = (struct pkt_format *) sendbuff; 729 int i; 730 731 pkt->ident = htonl(ident); 732 pkt->seq = htonl(seq); 733 gettimeofday(&pkt->tv, &tz); 734 735 i = setsockopt(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); 736 if (i < 0) 737 { 738 perror("setsockopt"); 739 exit(1); 740 } 741 742 do { 743 i = sendto(sndsock, sendbuff, datalen, 0, 744 (struct sockaddr *)&whereto, sizeof(whereto)); 745 } while (i<0 && errno == ECONNREFUSED); 746 747 if (i < 0 || i != datalen) { 748 if (i<0) 749 perror("sendto"); 750 Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname, 751 datalen, i); 752 (void) fflush(stdout); 753 } 754 } 755 756 757 double deltaT(struct timeval *t1p, struct timeval *t2p) 758 { 759 register double dt; 760 761 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + 762 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; 763 return (dt); 764 } 765 766 767 /* 768 * Convert an ICMP "type" field to a printable string. 769 */ 770 char * pr_type(unsigned char t) 771 { 772 switch(t) { 773 /* Unknown */ 774 case 0: 775 return "Error"; 776 case 1: 777 /* ICMP6_DST_UNREACH: */ 778 return "Destination Unreachable"; 779 case 2: 780 /* ICMP6_PACKET_TOO_BIG: */ 781 return "Packet Too Big"; 782 case 3: 783 /* ICMP6_TIME_EXCEEDED */ 784 return "Time Exceeded in Transit"; 785 case 4: 786 /* ICMP6_PARAM_PROB */ 787 return "Parameter Problem"; 788 case 128: 789 /* ICMP6_ECHO_REQUEST */ 790 return "Echo Request"; 791 case 129: 792 /* ICMP6_ECHO_REPLY */ 793 return "Echo Reply"; 794 case 130: 795 /* ICMP6_MEMBERSHIP_QUERY */ 796 return "Membership Query"; 797 case 131: 798 /* ICMP6_MEMBERSHIP_REPORT */ 799 return "Membership Report"; 800 case 132: 801 /* ICMP6_MEMBERSHIP_REDUCTION */ 802 return "Membership Reduction"; 803 case 133: 804 /* ND_ROUTER_SOLICIT */ 805 return "Router Solicitation"; 806 case 134: 807 /* ND_ROUTER_ADVERT */ 808 return "Router Advertisement"; 809 case 135: 810 /* ND_NEIGHBOR_SOLICIT */ 811 return "Neighbor Solicitation"; 812 case 136: 813 /* ND_NEIGHBOR_ADVERT */ 814 return "Neighbor Advertisement"; 815 case 137: 816 /* ND_REDIRECT */ 817 return "Redirect"; 818 } 819 820 return("OUT-OF-RANGE"); 821 } 822 823 824 int packet_ok(u_char *buf, int cc, struct sockaddr_in6 *from, 825 struct in6_addr *to, int seq, 826 struct timeval *tv) 827 { 828 struct icmp6_hdr *icp; 829 u_char type, code; 830 831 icp = (struct icmp6_hdr *) buf; 832 833 type = icp->icmp6_type; 834 code = icp->icmp6_code; 835 836 if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) || 837 type == ICMP6_DST_UNREACH) 838 { 839 struct ip6_hdr *hip; 840 struct udphdr *up; 841 int nexthdr; 842 843 hip = (struct ip6_hdr *) (icp + 1); 844 up = (struct udphdr *)(hip+1); 845 nexthdr = hip->ip6_nxt; 846 847 if (nexthdr == 44) { 848 nexthdr = *(unsigned char*)up; 849 up++; 850 } 851 if (nexthdr == IPPROTO_UDP) 852 { 853 struct pkt_format *pkt; 854 855 pkt = (struct pkt_format *) (up + 1); 856 857 if (ntohl(pkt->ident) == ident && 858 ntohl(pkt->seq) == seq) 859 { 860 *tv = pkt->tv; 861 return (type == ICMP6_TIME_EXCEEDED ? -1 : code+1); 862 } 863 } 864 865 } 866 867 if (verbose) { 868 unsigned char *p; 869 char pa1[MAX_HOSTNAMELEN]; 870 char pa2[MAX_HOSTNAMELEN]; 871 int i; 872 873 p = (unsigned char *) (icp + 1); 874 875 Printf("\n%d bytes from %s to %s", cc, 876 inet_ntop(AF_INET6, &from->sin6_addr, pa1, sizeof(pa1)), 877 inet_ntop(AF_INET6, to, pa2, sizeof(pa2))); 878 879 Printf(": icmp type %d (%s) code %d\n", type, pr_type(type), 880 icp->icmp6_code); 881 882 cc -= sizeof(struct icmp6_hdr); 883 for (i = 0; i < cc ; i++) { 884 if (i % 16 == 0) 885 Printf("%04x:", i); 886 if (i % 4 == 0) 887 Printf(" "); 888 Printf("%02x", 0xff & (unsigned)p[i]); 889 if (i % 16 == 15 && i + 1 < cc) 890 Printf("\n"); 891 } 892 Printf("\n"); 893 } 894 895 return(0); 896 } 897 898 899 void print(unsigned char *buf, int cc, struct sockaddr_in6 *from) 900 { 901 char pa[MAX_HOSTNAMELEN]; 902 903 if (nflag) 904 Printf(" %s", inet_ntop(AF_INET6, &from->sin6_addr, 905 pa, sizeof(pa))); 906 else 907 { 908 const char *hostname; 909 struct hostent *hp; 910 char *s = NULL; 911 912 hostname = inet_ntop(AF_INET6, &from->sin6_addr, pa, sizeof(pa)); 913 914 if ((hp = gethostbyaddr((char *)&from->sin6_addr, 915 sizeof(from->sin6_addr), AF_INET6))) { 916 #ifdef USE_IDN 917 if (idna_to_unicode_lzlz(hp->h_name, &s, 0) != IDNA_SUCCESS) 918 s = NULL; 919 #endif 920 } 921 922 Printf(" %s (%s)", hp ? (s ? s : hp->h_name) : hostname, pa); 923 924 free(s); 925 } 926 } 927 928 929 /* 930 * Subtract 2 timeval structs: out = out - in. 931 * Out is assumed to be >= in. 932 */ 933 void 934 tvsub(out, in) 935 register struct timeval *out, *in; 936 { 937 if ((out->tv_usec -= in->tv_usec) < 0) { 938 out->tv_sec--; 939 out->tv_usec += 1000000; 940 } 941 out->tv_sec -= in->tv_sec; 942 } 943 944 void usage(void) 945 { 946 fprintf(stderr, 947 "Usage: traceroute6 [-dnrvV] [-m max_ttl] [-p port#] [-q nqueries]\n\t\ 948 [-s src_addr] [-t tos] [-w wait] host [data size]\n"); 949 exit(1); 950 } 951