1 /* $NetBSD: traceroute6.c,v 1.32 2003/01/21 09:15:54 itojun Exp $ */ 2 /* $KAME: traceroute6.c,v 1.63 2002/10/24 12:53:25 itojun Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 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. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /*- 34 * Copyright (c) 1990, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * This code is derived from software contributed to Berkeley by 38 * Van Jacobson. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. All advertising materials mentioning features or use of this software 49 * must display the following acknowledgement: 50 * This product includes software developed by the University of 51 * California, Berkeley and its contributors. 52 * 4. Neither the name of the University nor the names of its contributors 53 * may be used to endorse or promote products derived from this software 54 * without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 66 * SUCH DAMAGE. 67 */ 68 69 #if 0 70 #ifndef lint 71 static char copyright[] = 72 "@(#) Copyright (c) 1990, 1993\n\ 73 The Regents of the University of California. All rights reserved.\n"; 74 #endif /* not lint */ 75 76 #ifndef lint 77 static char sccsid[] = "@(#)traceroute.c 8.1 (Berkeley) 6/6/93"; 78 #endif /* not lint */ 79 #else 80 #include <sys/cdefs.h> 81 #ifndef lint 82 __RCSID("$NetBSD: traceroute6.c,v 1.32 2003/01/21 09:15:54 itojun Exp $"); 83 #endif 84 #endif 85 86 /* 87 * traceroute host - trace the route ip packets follow going to "host". 88 * 89 * Attempt to trace the route an ip packet would follow to some 90 * internet host. We find out intermediate hops by launching probe 91 * packets with a small ttl (time to live) then listening for an 92 * icmp "time exceeded" reply from a gateway. We start our probes 93 * with a ttl of one and increase by one until we get an icmp "port 94 * unreachable" (which means we got to "host") or hit a max (which 95 * defaults to 30 hops & can be changed with the -m flag). Three 96 * probes (change with -q flag) are sent at each ttl setting and a 97 * line is printed showing the ttl, address of the gateway and 98 * round trip time of each probe. If the probe answers come from 99 * different gateways, the address of each responding system will 100 * be printed. If there is no response within a 5 sec. timeout 101 * interval (changed with the -w flag), a "*" is printed for that 102 * probe. 103 * 104 * Probe packets are UDP format. We don't want the destination 105 * host to process them so the destination port is set to an 106 * unlikely value (if some clod on the destination is using that 107 * value, it can be changed with the -p flag). 108 * 109 * A sample use might be: 110 * 111 * [yak 71]% traceroute nis.nsf.net. 112 * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet 113 * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms 114 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 115 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 116 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms 117 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms 118 * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms 119 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms 120 * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms 121 * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms 122 * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms 123 * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms 124 * 125 * Note that lines 2 & 3 are the same. This is due to a buggy 126 * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards 127 * packets with a zero ttl. 128 * 129 * A more interesting example is: 130 * 131 * [yak 72]% traceroute allspice.lcs.mit.edu. 132 * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max 133 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 134 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms 135 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms 136 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms 137 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms 138 * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms 139 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms 140 * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms 141 * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms 142 * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms 143 * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms 144 * 12 * * * 145 * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms 146 * 14 * * * 147 * 15 * * * 148 * 16 * * * 149 * 17 * * * 150 * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms 151 * 152 * (I start to see why I'm having so much trouble with mail to 153 * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away 154 * either don't send ICMP "time exceeded" messages or send them 155 * with a ttl too small to reach us. 14 - 17 are running the 156 * MIT C Gateway code that doesn't send "time exceeded"s. God 157 * only knows what's going on with 12. 158 * 159 * The silent gateway 12 in the above may be the result of a bug in 160 * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) 161 * sends an unreachable message using whatever ttl remains in the 162 * original datagram. Since, for gateways, the remaining ttl is 163 * zero, the icmp "time exceeded" is guaranteed to not make it back 164 * to us. The behavior of this bug is slightly more interesting 165 * when it appears on the destination system: 166 * 167 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 168 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms 169 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms 170 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms 171 * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms 172 * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms 173 * 7 * * * 174 * 8 * * * 175 * 9 * * * 176 * 10 * * * 177 * 11 * * * 178 * 12 * * * 179 * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! 180 * 181 * Notice that there are 12 "gateways" (13 is the final 182 * destination) and exactly the last half of them are "missing". 183 * What's really happening is that rip (a Sun-3 running Sun OS3.5) 184 * is using the ttl from our arriving datagram as the ttl in its 185 * icmp reply. So, the reply will time out on the return path 186 * (with no notice sent to anyone since icmp's aren't sent for 187 * icmp's) until we probe with a ttl that's at least twice the path 188 * length. I.e., rip is really only 7 hops away. A reply that 189 * returns with a ttl of 1 is a clue this problem exists. 190 * Traceroute prints a "!" after the time if the ttl is <= 1. 191 * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or 192 * non-standard (HPUX) software, expect to see this problem 193 * frequently and/or take care picking the target host of your 194 * probes. 195 * 196 * Other possible annotations after the time are !H, !N, !P (got a host, 197 * network or protocol unreachable, respectively), !S or !F (source 198 * route failed or fragmentation needed -- neither of these should 199 * ever occur and the associated gateway is busted if you see one). If 200 * almost all the probes result in some kind of unreachable, traceroute 201 * will give up and exit. 202 * 203 * Notes 204 * ----- 205 * This program must be run by root or be setuid. (I suggest that 206 * you *don't* make it setuid -- casual use could result in a lot 207 * of unnecessary traffic on our poor, congested nets.) 208 * 209 * This program requires a kernel mod that does not appear in any 210 * system available from Berkeley: A raw ip socket using proto 211 * IPPROTO_RAW must interpret the data sent as an ip datagram (as 212 * opposed to data to be wrapped in a ip datagram). See the README 213 * file that came with the source to this program for a description 214 * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may 215 * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE 216 * MODIFIED TO RUN THIS PROGRAM. 217 * 218 * The udp port usage may appear bizarre (well, ok, it is bizarre). 219 * The problem is that an icmp message only contains 8 bytes of 220 * data from the original datagram. 8 bytes is the size of a udp 221 * header so, if we want to associate replies with the original 222 * datagram, the necessary information must be encoded into the 223 * udp header (the ip id could be used but there's no way to 224 * interlock with the kernel's assignment of ip id's and, anyway, 225 * it would have taken a lot more kernel hacking to allow this 226 * code to set the ip id). So, to allow two or more users to 227 * use traceroute simultaneously, we use this task's pid as the 228 * source port (the high bit is set to move the port number out 229 * of the "likely" range). To keep track of which probe is being 230 * replied to (so times and/or hop counts don't get confused by a 231 * reply that was delayed in transit), we increment the destination 232 * port number before each probe. 233 * 234 * Don't use this as a coding example. I was trying to find a 235 * routing problem and this code sort-of popped out after 48 hours 236 * without sleep. I was amazed it ever compiled, much less ran. 237 * 238 * I stole the idea for this program from Steve Deering. Since 239 * the first release, I've learned that had I attended the right 240 * IETF working group meetings, I also could have stolen it from Guy 241 * Almes or Matt Mathis. I don't know (or care) who came up with 242 * the idea first. I envy the originators' perspicacity and I'm 243 * glad they didn't keep the idea a secret. 244 * 245 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or 246 * enhancements to the original distribution. 247 * 248 * I've hacked up a round-trip-route version of this that works by 249 * sending a loose-source-routed udp datagram through the destination 250 * back to yourself. Unfortunately, SO many gateways botch source 251 * routing, the thing is almost worthless. Maybe one day... 252 * 253 * -- Van Jacobson (van@helios.ee.lbl.gov) 254 * Tue Dec 20 03:50:13 PST 1988 255 */ 256 257 #include <sys/param.h> 258 #include <sys/time.h> 259 #include <sys/socket.h> 260 #include <sys/uio.h> 261 #include <sys/file.h> 262 #include <sys/ioctl.h> 263 #include <sys/sysctl.h> 264 265 #include <netinet/in.h> 266 267 #include <arpa/inet.h> 268 269 #include <netdb.h> 270 #include <stdio.h> 271 #include <err.h> 272 #ifdef HAVE_POLL 273 #include <poll.h> 274 #endif 275 #include <errno.h> 276 #include <stdlib.h> 277 #include <string.h> 278 #include <unistd.h> 279 280 #include <netinet/ip6.h> 281 #include <netinet/icmp6.h> 282 #include <netinet/udp.h> 283 284 #ifdef IPSEC 285 #include <net/route.h> 286 #include <netinet6/ipsec.h> 287 #endif 288 289 #define DUMMY_PORT 10010 290 291 #define MAXPACKET 65535 /* max ip packet size */ 292 293 #ifndef HAVE_GETIPNODEBYNAME 294 #define getipnodebyname(x, y, z, u) gethostbyname2((x), (y)) 295 #define freehostent(x) 296 #endif 297 298 /* 299 * format of a (udp) probe packet. 300 */ 301 struct opacket { 302 u_char seq; /* sequence number of this packet */ 303 u_char hops; /* hop limit of the packet */ 304 struct timeval tv; /* time packet left */ 305 }; 306 struct tv32 { 307 u_int32_t tv32_sec; 308 u_int32_t tv32_usec; 309 }; 310 311 u_char packet[512]; /* last inbound (icmp) packet */ 312 struct opacket *outpacket; /* last output (udp) packet */ 313 314 int main __P((int, char *[])); 315 int wait_for_reply __P((int, struct msghdr *)); 316 #ifdef IPSEC 317 #ifdef IPSEC_POLICY_IPSEC 318 int setpolicy __P((int so, char *policy)); 319 #endif 320 #endif 321 void send_probe __P((int, u_long)); 322 struct udphdr *get_udphdr __P((struct ip6_hdr *, u_char *)); 323 int get_hoplim __P((struct msghdr *)); 324 double deltaT __P((struct timeval *, struct timeval *)); 325 char *pr_type __P((int)); 326 int packet_ok __P((struct msghdr *, int, int)); 327 void print __P((struct msghdr *, int)); 328 void tvsub __P((struct timeval *, struct timeval *)); 329 const char *inetname __P((struct sockaddr *)); 330 void usage __P((void)); 331 332 int rcvsock; /* receive (icmp) socket file descriptor */ 333 int sndsock; /* send (udp) socket file descriptor */ 334 335 struct msghdr rcvmhdr; 336 struct iovec rcviov[2]; 337 int rcvhlim; 338 struct in6_pktinfo *rcvpktinfo; 339 340 struct sockaddr_in6 Src, Dst, Rcv; 341 u_long datalen; /* How much data */ 342 #define ICMP6ECHOLEN 8 343 /* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */ 344 char rtbuf[2064]; 345 #ifdef USE_RFC2292BIS 346 struct ip6_rthdr *rth; 347 #endif 348 struct cmsghdr *cmsg; 349 350 char *source = 0; 351 char *hostname; 352 353 u_long nprobes = 3; 354 u_long first_hop = 1; 355 u_long max_hops = 30; 356 u_int16_t srcport; 357 u_int16_t port = 32768+666; /* start udp dest port # for probe packets */ 358 u_int16_t ident; 359 int options; /* socket options */ 360 int verbose; 361 int waittime = 5; /* time to wait for response (in seconds) */ 362 int nflag; /* print addresses numerically */ 363 int useicmp; 364 int lflag; /* print both numerical address & hostname */ 365 366 int 367 main(argc, argv) 368 int argc; 369 char *argv[]; 370 { 371 struct hostent *hp; 372 int error; 373 struct addrinfo hints, *res; 374 int ch, i, on, seq, rcvcmsglen; 375 u_long probe, hops; 376 static u_char *rcvcmsgbuf; 377 char hbuf[NI_MAXHOST], src0[NI_MAXHOST]; 378 char *ep; 379 int mib[4] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM }; 380 size_t size; 381 u_long lport; 382 int minlen; 383 384 /* 385 * Receive ICMP 386 */ 387 if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 388 perror("socket(ICMPv6)"); 389 exit(5); 390 } 391 392 /* revoke privs */ 393 seteuid(getuid()); 394 setuid(getuid()); 395 396 size = sizeof(i); 397 (void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &i, &size, NULL, 0); 398 max_hops = i; 399 400 /* set a minimum set of socket options */ 401 on = 1; 402 /* specify to tell receiving interface */ 403 #ifdef IPV6_RECVPKTINFO 404 if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 405 sizeof(on)) < 0) 406 err(1, "setsockopt(IPV6_RECVPKTINFO)"); 407 #else /* old adv. API */ 408 if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_PKTINFO, &on, 409 sizeof(on)) < 0) 410 err(1, "setsockopt(IPV6_PKTINFO)"); 411 #endif 412 413 /* specify to tell value of hoplimit field of received IP6 hdr */ 414 #ifdef IPV6_RECVHOPLIMIT 415 if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, 416 sizeof(on)) < 0) 417 err(1, "setsockopt(IPV6_RECVHOPLIMIT)"); 418 #else /* old adv. API */ 419 if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, 420 sizeof(on)) < 0) 421 err(1, "setsockopt(IPV6_HOPLIMIT)"); 422 #endif 423 424 seq = 0; 425 426 while ((ch = getopt(argc, argv, "df:g:Ilm:np:q:rs:w:v")) != -1) 427 switch (ch) { 428 case 'd': 429 options |= SO_DEBUG; 430 break; 431 case 'f': 432 ep = NULL; 433 errno = 0; 434 first_hop = strtoul(optarg, &ep, 0); 435 if (errno || !*optarg || *ep|| first_hop > 255) { 436 fprintf(stderr, 437 "traceroute6: invalid min hoplimit.\n"); 438 exit(1); 439 } 440 break; 441 case 'g': 442 hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno); 443 if (hp == NULL) { 444 fprintf(stderr, 445 "traceroute6: unknown host %s\n", optarg); 446 exit(1); 447 } 448 #ifdef USE_RFC2292BIS 449 if (rth == NULL) { 450 /* 451 * XXX: We can't detect the number of 452 * intermediate nodes yet. 453 */ 454 if ((rth = inet6_rth_init((void *)rtbuf, 455 sizeof(rtbuf), IPV6_RTHDR_TYPE_0, 456 0)) == NULL) { 457 fprintf(stderr, 458 "inet6_rth_init failed.\n"); 459 exit(1); 460 } 461 } 462 if (inet6_rth_add((void *)rth, 463 (struct in6_addr *)hp->h_addr)) { 464 fprintf(stderr, 465 "inet6_rth_add failed for %s\n", 466 optarg); 467 exit(1); 468 } 469 #else /* old advanced API */ 470 if (cmsg == NULL) 471 cmsg = inet6_rthdr_init(rtbuf, IPV6_RTHDR_TYPE_0); 472 inet6_rthdr_add(cmsg, (struct in6_addr *)hp->h_addr, 473 IPV6_RTHDR_LOOSE); 474 #endif 475 freehostent(hp); 476 break; 477 case 'I': 478 useicmp++; 479 ident = htons(getpid() & 0xffff); /* same as ping6 */ 480 break; 481 case 'l': 482 lflag++; 483 break; 484 case 'm': 485 ep = NULL; 486 errno = 0; 487 max_hops = strtoul(optarg, &ep, 0); 488 if (errno || !*optarg || *ep || max_hops > 255) { 489 fprintf(stderr, 490 "traceroute6: invalid max hoplimit.\n"); 491 exit(1); 492 } 493 break; 494 case 'n': 495 nflag++; 496 break; 497 case 'p': 498 ep = NULL; 499 errno = 0; 500 lport = strtoul(optarg, &ep, 0); 501 if (errno || !*optarg || *ep) { 502 fprintf(stderr, "traceroute6: invalid port.\n"); 503 exit(1); 504 } 505 if (lport == 0 || lport != (lport & 0xffff)) { 506 fprintf(stderr, 507 "traceroute6: port out of range.\n"); 508 exit(1); 509 } 510 port = lport & 0xffff; 511 break; 512 case 'q': 513 ep = NULL; 514 errno = 0; 515 nprobes = strtoul(optarg, &ep, 0); 516 if (errno || !*optarg || *ep) { 517 fprintf(stderr, 518 "traceroute6: invalid nprobes.\n"); 519 exit(1); 520 } 521 if (nprobes < 1) { 522 fprintf(stderr, 523 "traceroute6: nprobes must be >0.\n"); 524 exit(1); 525 } 526 break; 527 case 'r': 528 options |= SO_DONTROUTE; 529 break; 530 case 's': 531 /* 532 * set the ip source address of the outbound 533 * probe (e.g., on a multi-homed host). 534 */ 535 source = optarg; 536 break; 537 case 'v': 538 verbose++; 539 break; 540 case 'w': 541 ep = NULL; 542 errno = 0; 543 waittime = strtoul(optarg, &ep, 0); 544 if (errno || !*optarg || *ep) { 545 fprintf(stderr, 546 "traceroute6: invalid wait time.\n"); 547 exit(1); 548 } 549 if (waittime <= 1) { 550 fprintf(stderr, 551 "traceroute6: wait must be >1 sec.\n"); 552 exit(1); 553 } 554 break; 555 default: 556 usage(); 557 } 558 argc -= optind; 559 argv += optind; 560 561 if (max_hops < first_hop) { 562 fprintf(stderr, 563 "traceroute6: max hoplimit must be larger than first hoplimit.\n"); 564 exit(1); 565 } 566 567 if (argc < 1 || argc > 2) 568 usage(); 569 570 #if 1 571 setvbuf(stdout, NULL, _IOLBF, BUFSIZ); 572 #else 573 setlinebuf (stdout); 574 #endif 575 576 memset(&hints, 0, sizeof(hints)); 577 hints.ai_family = PF_INET6; 578 hints.ai_socktype = SOCK_RAW; 579 hints.ai_protocol = IPPROTO_ICMPV6; 580 hints.ai_flags = AI_CANONNAME; 581 error = getaddrinfo(*argv, NULL, &hints, &res); 582 if (error) { 583 fprintf(stderr, 584 "traceroute6: %s\n", gai_strerror(error)); 585 exit(1); 586 } 587 if (res->ai_addrlen != sizeof(Dst)) { 588 fprintf(stderr, 589 "traceroute6: size of sockaddr mismatch\n"); 590 exit(1); 591 } 592 memcpy(&Dst, res->ai_addr, res->ai_addrlen); 593 hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv; 594 if (!hostname) { 595 fprintf(stderr, "traceroute6: not enough core\n"); 596 exit(1); 597 } 598 if (res->ai_next) { 599 if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, 600 sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 601 strlcpy(hbuf, "?", sizeof(hbuf)); 602 fprintf(stderr, "traceroute6: Warning: %s has multiple " 603 "addresses; using %s\n", hostname, hbuf); 604 } 605 606 if (*++argv) { 607 ep = NULL; 608 errno = 0; 609 datalen = strtoul(*argv, &ep, 0); 610 if (errno || !*argv || *ep) { 611 fprintf(stderr, 612 "traceroute6: invalid packet length.\n"); 613 exit(1); 614 } 615 } 616 if (useicmp) 617 minlen = ICMP6ECHOLEN + sizeof(struct tv32); 618 else 619 minlen = sizeof(struct opacket); 620 if (datalen < minlen) 621 datalen = minlen; 622 else if (datalen >= MAXPACKET) { 623 fprintf(stderr, 624 "traceroute6: packet size must be %d <= s < %ld.\n", 625 minlen, (long)MAXPACKET); 626 exit(1); 627 } 628 outpacket = (struct opacket *)malloc((unsigned)datalen); 629 if (! outpacket) { 630 perror("malloc"); 631 exit(1); 632 } 633 (void) bzero((char *)outpacket, datalen); 634 635 /* initialize msghdr for receiving packets */ 636 rcviov[0].iov_base = (caddr_t)packet; 637 rcviov[0].iov_len = sizeof(packet); 638 rcvmhdr.msg_name = (caddr_t)&Rcv; 639 rcvmhdr.msg_namelen = sizeof(Rcv); 640 rcvmhdr.msg_iov = rcviov; 641 rcvmhdr.msg_iovlen = 1; 642 rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) 643 + CMSG_SPACE(sizeof(int)); 644 if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) { 645 fprintf(stderr, "traceroute6: malloc failed\n"); 646 exit(1); 647 } 648 rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; 649 rcvmhdr.msg_controllen = rcvcmsglen; 650 651 if (options & SO_DEBUG) 652 (void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, 653 (char *)&on, sizeof(on)); 654 if (options & SO_DONTROUTE) 655 (void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, 656 (char *)&on, sizeof(on)); 657 #ifdef IPSEC 658 #ifdef IPSEC_POLICY_IPSEC 659 /* 660 * do not raise error even if setsockopt fails, kernel may have ipsec 661 * turned off. 662 */ 663 if (setpolicy(rcvsock, "in bypass") < 0) 664 errx(1, "%s", ipsec_strerror()); 665 if (setpolicy(rcvsock, "out bypass") < 0) 666 errx(1, "%s", ipsec_strerror()); 667 #else 668 { 669 int level = IPSEC_LEVEL_NONE; 670 671 (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, 672 sizeof(level)); 673 (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, 674 sizeof(level)); 675 #ifdef IP_AUTH_TRANS_LEVEL 676 (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, 677 sizeof(level)); 678 #else 679 (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, 680 sizeof(level)); 681 #endif 682 #ifdef IP_AUTH_NETWORK_LEVEL 683 (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, 684 sizeof(level)); 685 #endif 686 } 687 #endif /*IPSEC_POLICY_IPSEC*/ 688 #endif /*IPSEC*/ 689 690 /* 691 * Send UDP or ICMP 692 */ 693 if (useicmp) { 694 sndsock = rcvsock; 695 } else { 696 if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 697 perror("socket(SOCK_DGRAM)"); 698 exit(5); 699 } 700 } 701 #ifdef SO_SNDBUF 702 i = datalen; 703 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&i, 704 sizeof(i)) < 0) { 705 perror("setsockopt(SO_SNDBUF)"); 706 exit(6); 707 } 708 #endif /* SO_SNDBUF */ 709 if (options & SO_DEBUG) 710 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 711 (char *)&on, sizeof(on)); 712 if (options & SO_DONTROUTE) 713 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, 714 (char *)&on, sizeof(on)); 715 #ifdef USE_RFC2292BIS 716 if (rth) {/* XXX: there is no library to finalize the header... */ 717 rth->ip6r_len = rth->ip6r_segleft * 2; 718 if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR, 719 (void *)rth, (rth->ip6r_len + 1) << 3)) { 720 fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n", 721 strerror(errno)); 722 exit(1); 723 } 724 } 725 #else /* old advanced API */ 726 if (cmsg != NULL) { 727 inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE); 728 if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_PKTOPTIONS, 729 rtbuf, cmsg->cmsg_len) < 0) { 730 fprintf(stderr, "setsockopt(IPV6_PKTOPTIONS): %s\n", 731 strerror(errno)); 732 exit(1); 733 } 734 } 735 #endif /* USE_RFC2292BIS */ 736 #ifdef IPSEC 737 #ifdef IPSEC_POLICY_IPSEC 738 /* 739 * do not raise error even if setsockopt fails, kernel may have ipsec 740 * turned off. 741 */ 742 if (setpolicy(sndsock, "in bypass") < 0) 743 errx(1, "%s", ipsec_strerror()); 744 if (setpolicy(sndsock, "out bypass") < 0) 745 errx(1, "%s", ipsec_strerror()); 746 #else 747 { 748 int level = IPSEC_LEVEL_BYPASS; 749 750 (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, 751 sizeof(level)); 752 (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, 753 sizeof(level)); 754 #ifdef IP_AUTH_TRANS_LEVEL 755 (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, 756 sizeof(level)); 757 #else 758 (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, 759 sizeof(level)); 760 #endif 761 #ifdef IP_AUTH_NETWORK_LEVEL 762 (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, 763 sizeof(level)); 764 #endif 765 } 766 #endif /*IPSEC_POLICY_IPSEC*/ 767 #endif /*IPSEC*/ 768 769 /* 770 * Source selection 771 */ 772 bzero(&Src, sizeof(Src)); 773 if (source) { 774 struct addrinfo hints, *res; 775 int error; 776 777 memset(&hints, 0, sizeof(hints)); 778 hints.ai_family = AF_INET6; 779 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 780 hints.ai_flags = AI_NUMERICHOST; 781 error = getaddrinfo(source, "0", &hints, &res); 782 if (error) { 783 printf("traceroute6: %s: %s\n", source, 784 gai_strerror(error)); 785 exit(1); 786 } 787 if (res->ai_addrlen > sizeof(Src)) { 788 printf("traceroute6: %s: %s\n", source, 789 gai_strerror(error)); 790 exit(1); 791 } 792 memcpy(&Src, res->ai_addr, res->ai_addrlen); 793 freeaddrinfo(res); 794 } else { 795 struct sockaddr_in6 Nxt; 796 int dummy; 797 socklen_t len; 798 799 Nxt = Dst; 800 Nxt.sin6_port = htons(DUMMY_PORT); 801 if (cmsg != NULL) 802 bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr, 803 sizeof(Nxt.sin6_addr)); 804 if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 805 perror("socket"); 806 exit(1); 807 } 808 if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) { 809 perror("connect"); 810 exit(1); 811 } 812 len = sizeof(Src); 813 if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) { 814 perror("getsockname"); 815 exit(1); 816 } 817 if (getnameinfo((struct sockaddr *)&Src, Src.sin6_len, 818 src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) { 819 fprintf(stderr, "getnameinfo failed for source\n"); 820 exit(1); 821 } 822 source = src0; 823 close(dummy); 824 } 825 826 Src.sin6_port = htons(0); 827 if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) { 828 perror("bind"); 829 exit(1); 830 } 831 832 { 833 socklen_t len; 834 835 len = sizeof(Src); 836 if (getsockname(sndsock, (struct sockaddr *)&Src, &len) < 0) { 837 perror("getsockname"); 838 exit(1); 839 } 840 srcport = ntohs(Src.sin6_port); 841 } 842 843 /* 844 * Message to users 845 */ 846 if (getnameinfo((struct sockaddr *)&Dst, Dst.sin6_len, hbuf, 847 sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) 848 strlcpy(hbuf, "(invalid)", sizeof(hbuf)); 849 fprintf(stderr, "traceroute6"); 850 fprintf(stderr, " to %s (%s)", hostname, hbuf); 851 if (source) 852 fprintf(stderr, " from %s", source); 853 fprintf(stderr, ", %lu hops max, %lu byte packets\n", 854 max_hops, datalen); 855 (void) fflush(stderr); 856 857 if (first_hop > 1) 858 printf("Skipping %lu intermediate hops\n", first_hop - 1); 859 860 /* 861 * Main loop 862 */ 863 for (hops = first_hop; hops <= max_hops; ++hops) { 864 struct in6_addr lastaddr; 865 int got_there = 0; 866 int unreachable = 0; 867 868 printf("%2lu ", hops); 869 bzero(&lastaddr, sizeof(lastaddr)); 870 for (probe = 0; probe < nprobes; ++probe) { 871 int cc; 872 struct timeval t1, t2; 873 874 (void) gettimeofday(&t1, NULL); 875 send_probe(++seq, hops); 876 while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) { 877 (void) gettimeofday(&t2, NULL); 878 if ((i = packet_ok(&rcvmhdr, cc, seq))) { 879 if (! IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr, 880 &lastaddr)) { 881 print(&rcvmhdr, cc); 882 lastaddr = Rcv.sin6_addr; 883 } 884 printf(" %g ms", deltaT(&t1, &t2)); 885 switch (i - 1) { 886 case ICMP6_DST_UNREACH_NOROUTE: 887 ++unreachable; 888 printf(" !N"); 889 break; 890 case ICMP6_DST_UNREACH_ADMIN: 891 ++unreachable; 892 printf(" !P"); 893 break; 894 case ICMP6_DST_UNREACH_NOTNEIGHBOR: 895 ++unreachable; 896 printf(" !S"); 897 break; 898 case ICMP6_DST_UNREACH_ADDR: 899 ++unreachable; 900 printf(" !A"); 901 break; 902 case ICMP6_DST_UNREACH_NOPORT: 903 if (rcvhlim >= 0 && 904 rcvhlim <= 1) 905 printf(" !"); 906 ++got_there; 907 break; 908 } 909 break; 910 } 911 } 912 if (cc == 0) 913 printf(" *"); 914 (void) fflush(stdout); 915 } 916 putchar('\n'); 917 if (got_there || 918 (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) { 919 exit(0); 920 } 921 } 922 923 exit(0); 924 } 925 926 int 927 wait_for_reply(sock, mhdr) 928 int sock; 929 struct msghdr *mhdr; 930 { 931 #ifdef HAVE_POLL 932 struct pollfd pfd[1]; 933 int cc = 0; 934 935 pfd[0].fd = sock; 936 pfd[0].events = POLLIN; 937 pfd[0].revents = 0; 938 939 if (poll(pfd, 1, waittime * 1000) > 0) 940 cc = recvmsg(rcvsock, mhdr, 0); 941 942 return(cc); 943 #else 944 fd_set *fdsp; 945 struct timeval wait; 946 int cc = 0, fdsn; 947 948 fdsn = howmany(sock + 1, NFDBITS) * sizeof(fd_mask); 949 if ((fdsp = (fd_set *)malloc(fdsn)) == NULL) 950 err(1, "malloc"); 951 memset(fdsp, 0, fdsn); 952 FD_SET(sock, fdsp); 953 wait.tv_sec = waittime; wait.tv_usec = 0; 954 955 if (select(sock+1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0) 956 cc = recvmsg(rcvsock, mhdr, 0); 957 958 free(fdsp); 959 return(cc); 960 #endif 961 } 962 963 #ifdef IPSEC 964 #ifdef IPSEC_POLICY_IPSEC 965 int 966 setpolicy(so, policy) 967 int so; 968 char *policy; 969 { 970 char *buf; 971 972 buf = ipsec_set_policy(policy, strlen(policy)); 973 if (buf == NULL) { 974 warnx("%s", ipsec_strerror()); 975 return -1; 976 } 977 (void)setsockopt(so, IPPROTO_IPV6, IPV6_IPSEC_POLICY, 978 buf, ipsec_get_policylen(buf)); 979 980 free(buf); 981 982 return 0; 983 } 984 #endif 985 #endif 986 987 void 988 send_probe(seq, hops) 989 int seq; 990 u_long hops; 991 { 992 int i; 993 994 i = hops; 995 if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 996 (char *)&i, sizeof(i)) < 0) { 997 perror("setsockopt IPV6_UNICAST_HOPS"); 998 } 999 1000 Dst.sin6_port = htons(port + seq); 1001 1002 if (useicmp) { 1003 struct icmp6_hdr *icp = (struct icmp6_hdr *)outpacket; 1004 struct timeval tv; 1005 struct tv32 *tv32; 1006 1007 icp->icmp6_type = ICMP6_ECHO_REQUEST; 1008 icp->icmp6_code = 0; 1009 icp->icmp6_cksum = 0; 1010 icp->icmp6_id = ident; 1011 icp->icmp6_seq = htons(seq); 1012 (void) gettimeofday(&tv, NULL); 1013 tv32 = (struct tv32 *)((u_int8_t *)outpacket + ICMP6ECHOLEN); 1014 tv32->tv32_sec = htonl(tv.tv_sec); 1015 tv32->tv32_usec = htonl(tv.tv_usec); 1016 } else { 1017 struct opacket *op = outpacket; 1018 op->seq = seq; 1019 op->hops = hops; 1020 (void) gettimeofday(&op->tv, NULL); 1021 } 1022 1023 i = sendto(sndsock, (char *)outpacket, datalen , 0, 1024 (struct sockaddr *)&Dst, Dst.sin6_len); 1025 if (i < 0 || i != datalen) { 1026 if (i<0) 1027 perror("sendto"); 1028 printf("traceroute6: wrote %s %lu chars, ret=%d\n", 1029 hostname, datalen, i); 1030 (void) fflush(stdout); 1031 } 1032 } 1033 1034 int 1035 get_hoplim(mhdr) 1036 struct msghdr *mhdr; 1037 { 1038 struct cmsghdr *cm; 1039 1040 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 1041 cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 1042 if (cm->cmsg_level == IPPROTO_IPV6 && 1043 cm->cmsg_type == IPV6_HOPLIMIT && 1044 cm->cmsg_len == CMSG_LEN(sizeof(int))) 1045 return(*(int *)CMSG_DATA(cm)); 1046 } 1047 1048 return(-1); 1049 } 1050 1051 double 1052 deltaT(t1p, t2p) 1053 struct timeval *t1p, *t2p; 1054 { 1055 register double dt; 1056 1057 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + 1058 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; 1059 return (dt); 1060 } 1061 1062 /* 1063 * Convert an ICMP "type" field to a printable string. 1064 */ 1065 char * 1066 pr_type(t0) 1067 int t0; 1068 { 1069 u_char t = t0 & 0xff; 1070 char *cp; 1071 1072 switch (t) { 1073 case ICMP6_DST_UNREACH: 1074 cp = "Destination Unreachable"; 1075 break; 1076 case ICMP6_PACKET_TOO_BIG: 1077 cp = "Packet Too Big"; 1078 break; 1079 case ICMP6_TIME_EXCEEDED: 1080 cp = "Time Exceeded"; 1081 break; 1082 case ICMP6_PARAM_PROB: 1083 cp = "Parameter Problem"; 1084 break; 1085 case ICMP6_ECHO_REQUEST: 1086 cp = "Echo Request"; 1087 break; 1088 case ICMP6_ECHO_REPLY: 1089 cp = "Echo Reply"; 1090 break; 1091 case ICMP6_MEMBERSHIP_QUERY: 1092 cp = "Group Membership Query"; 1093 break; 1094 case ICMP6_MEMBERSHIP_REPORT: 1095 cp = "Group Membership Report"; 1096 break; 1097 case ICMP6_MEMBERSHIP_REDUCTION: 1098 cp = "Group Membership Reduction"; 1099 break; 1100 case ND_ROUTER_SOLICIT: 1101 cp = "Router Solicitation"; 1102 break; 1103 case ND_ROUTER_ADVERT: 1104 cp = "Router Advertisement"; 1105 break; 1106 case ND_NEIGHBOR_SOLICIT: 1107 cp = "Neighbor Solicitation"; 1108 break; 1109 case ND_NEIGHBOR_ADVERT: 1110 cp = "Neighbor Advertisement"; 1111 break; 1112 case ND_REDIRECT: 1113 cp = "Redirect"; 1114 break; 1115 default: 1116 cp = "Unknown"; 1117 break; 1118 } 1119 return cp; 1120 } 1121 1122 int 1123 packet_ok(mhdr, cc, seq) 1124 struct msghdr *mhdr; 1125 int cc; 1126 int seq; 1127 { 1128 register struct icmp6_hdr *icp; 1129 struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; 1130 u_char type, code; 1131 char *buf = (char *)mhdr->msg_iov[0].iov_base; 1132 struct cmsghdr *cm; 1133 int *hlimp; 1134 char hbuf[NI_MAXHOST]; 1135 1136 #ifdef OLDRAWSOCKET 1137 int hlen; 1138 struct ip6_hdr *ip; 1139 #endif 1140 1141 #ifdef OLDRAWSOCKET 1142 ip = (struct ip6_hdr *) buf; 1143 hlen = sizeof(struct ip6_hdr); 1144 if (cc < hlen + sizeof(struct icmp6_hdr)) { 1145 if (verbose) { 1146 if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1147 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 1148 strlcpy(hbuf, "invalid", sizeof(hbuf)); 1149 printf("packet too short (%d bytes) from %s\n", cc, 1150 hbuf); 1151 } 1152 return (0); 1153 } 1154 cc -= hlen; 1155 icp = (struct icmp6_hdr *)(buf + hlen); 1156 #else 1157 if (cc < sizeof(struct icmp6_hdr)) { 1158 if (verbose) { 1159 if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1160 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 1161 strlcpy(hbuf, "invalid", sizeof(hbuf)); 1162 printf("data too short (%d bytes) from %s\n", cc, hbuf); 1163 } 1164 return(0); 1165 } 1166 icp = (struct icmp6_hdr *)buf; 1167 #endif 1168 /* get optional information via advanced API */ 1169 rcvpktinfo = NULL; 1170 hlimp = NULL; 1171 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 1172 cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 1173 if (cm->cmsg_level == IPPROTO_IPV6 && 1174 cm->cmsg_type == IPV6_PKTINFO && 1175 cm->cmsg_len == 1176 CMSG_LEN(sizeof(struct in6_pktinfo))) 1177 rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm)); 1178 1179 if (cm->cmsg_level == IPPROTO_IPV6 && 1180 cm->cmsg_type == IPV6_HOPLIMIT && 1181 cm->cmsg_len == CMSG_LEN(sizeof(int))) 1182 hlimp = (int *)CMSG_DATA(cm); 1183 } 1184 if (rcvpktinfo == NULL || hlimp == NULL) { 1185 warnx("failed to get received hop limit or packet info"); 1186 #if 0 1187 return(0); 1188 #else 1189 rcvhlim = 0; /*XXX*/ 1190 #endif 1191 } 1192 else 1193 rcvhlim = *hlimp; 1194 1195 type = icp->icmp6_type; 1196 code = icp->icmp6_code; 1197 if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) 1198 || type == ICMP6_DST_UNREACH) { 1199 struct ip6_hdr *hip; 1200 struct udphdr *up; 1201 1202 hip = (struct ip6_hdr *)(icp + 1); 1203 if ((up = get_udphdr(hip, (u_char *)(buf + cc))) == NULL) { 1204 if (verbose) 1205 warnx("failed to get upper layer header"); 1206 return(0); 1207 } 1208 if (useicmp && 1209 ((struct icmp6_hdr *)up)->icmp6_id == ident && 1210 ((struct icmp6_hdr *)up)->icmp6_seq == htons(seq)) 1211 return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1); 1212 else if (!useicmp && 1213 up->uh_sport == htons(srcport) && 1214 up->uh_dport == htons(port + seq)) 1215 return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1); 1216 } else if (useicmp && type == ICMP6_ECHO_REPLY) { 1217 if (icp->icmp6_id == ident && 1218 icp->icmp6_seq == htons(seq)) 1219 return (ICMP6_DST_UNREACH_NOPORT + 1); 1220 } 1221 if (verbose) { 1222 int i; 1223 u_int8_t *p; 1224 char sbuf[NI_MAXHOST+1], dbuf[INET6_ADDRSTRLEN]; 1225 1226 if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1227 sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0) 1228 strlcpy(sbuf, "invalid", sizeof(sbuf)); 1229 printf("\n%d bytes from %s to %s", cc, sbuf, 1230 rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1231 dbuf, sizeof(dbuf)) : "?"); 1232 printf(": icmp type %d (%s) code %d\n", type, pr_type(type), 1233 icp->icmp6_code); 1234 p = (u_int8_t *)(icp + 1); 1235 #define WIDTH 16 1236 for (i = 0; i < cc; i++) { 1237 if (i % WIDTH == 0) 1238 printf("%04x:", i); 1239 if (i % 4 == 0) 1240 printf(" "); 1241 printf("%02x", p[i]); 1242 if (i % WIDTH == WIDTH - 1) 1243 printf("\n"); 1244 } 1245 if (cc % WIDTH != 0) 1246 printf("\n"); 1247 } 1248 return(0); 1249 } 1250 1251 /* 1252 * Increment pointer until find the UDP or ICMP header. 1253 */ 1254 struct udphdr * 1255 get_udphdr(ip6, lim) 1256 struct ip6_hdr *ip6; 1257 u_char *lim; 1258 { 1259 u_char *cp = (u_char *)ip6, nh; 1260 int hlen; 1261 1262 if (cp + sizeof(*ip6) >= lim) 1263 return(NULL); 1264 1265 nh = ip6->ip6_nxt; 1266 cp += sizeof(struct ip6_hdr); 1267 1268 while (lim - cp >= 8) { 1269 switch (nh) { 1270 case IPPROTO_ESP: 1271 case IPPROTO_TCP: 1272 return(NULL); 1273 case IPPROTO_ICMPV6: 1274 return(useicmp ? (struct udphdr *)cp : NULL); 1275 case IPPROTO_UDP: 1276 return(useicmp ? NULL : (struct udphdr *)cp); 1277 case IPPROTO_FRAGMENT: 1278 hlen = sizeof(struct ip6_frag); 1279 nh = ((struct ip6_frag *)cp)->ip6f_nxt; 1280 break; 1281 case IPPROTO_AH: 1282 hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2; 1283 nh = ((struct ip6_ext *)cp)->ip6e_nxt; 1284 break; 1285 default: 1286 hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3; 1287 nh = ((struct ip6_ext *)cp)->ip6e_nxt; 1288 break; 1289 } 1290 1291 cp += hlen; 1292 } 1293 1294 return(NULL); 1295 } 1296 1297 void 1298 print(mhdr, cc) 1299 struct msghdr *mhdr; 1300 int cc; 1301 { 1302 struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; 1303 char hbuf[NI_MAXHOST]; 1304 1305 if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1306 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 1307 strlcpy(hbuf, "invalid", sizeof(hbuf)); 1308 if (nflag) 1309 printf(" %s", hbuf); 1310 else if (lflag) 1311 printf(" %s (%s)", inetname((struct sockaddr *)from), hbuf); 1312 else 1313 printf(" %s", inetname((struct sockaddr *)from)); 1314 1315 if (verbose) { 1316 #ifdef OLDRAWSOCKET 1317 printf(" %d bytes to %s", cc, 1318 rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1319 hbuf, sizeof(hbuf)) : "?"); 1320 #else 1321 printf(" %d bytes of data to %s", cc, 1322 rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1323 hbuf, sizeof(hbuf)) : "?"); 1324 #endif 1325 } 1326 } 1327 1328 /* 1329 * Subtract 2 timeval structs: out = out - in. 1330 * Out is assumed to be >= in. 1331 */ 1332 void 1333 tvsub(out, in) 1334 register struct timeval *out, *in; 1335 { 1336 1337 if ((out->tv_usec -= in->tv_usec) < 0) { 1338 out->tv_sec--; 1339 out->tv_usec += 1000000; 1340 } 1341 out->tv_sec -= in->tv_sec; 1342 } 1343 1344 /* 1345 * Construct an Internet address representation. 1346 * If the nflag has been supplied, give 1347 * numeric value, otherwise try for symbolic name. 1348 */ 1349 const char * 1350 inetname(sa) 1351 struct sockaddr *sa; 1352 { 1353 register char *cp; 1354 static char line[NI_MAXHOST]; 1355 static char domain[MAXHOSTNAMELEN + 1]; 1356 static int first = 1; 1357 1358 if (first && !nflag) { 1359 first = 0; 1360 if (gethostname(domain, sizeof(domain)) == 0 && 1361 (cp = strchr(domain, '.'))) 1362 (void) strlcpy(domain, cp + 1, sizeof(domain)); 1363 else 1364 domain[0] = 0; 1365 } 1366 cp = NULL; 1367 if (!nflag) { 1368 if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, 1369 NI_NAMEREQD) == 0) { 1370 if ((cp = strchr(line, '.')) && 1371 !strcmp(cp + 1, domain)) 1372 *cp = 0; 1373 cp = line; 1374 } 1375 } 1376 if (cp) 1377 return cp; 1378 1379 if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, 1380 NI_NUMERICHOST) != 0) 1381 strlcpy(line, "invalid", sizeof(line)); 1382 return line; 1383 } 1384 1385 void 1386 usage() 1387 { 1388 1389 fprintf(stderr, 1390 "usage: traceroute6 [-dIlnrv] [-f firsthop] [-g gateway] [-m hoplimit]\n" 1391 " [-p port] [-q probes] [-s src] [-w waittime] target [datalen]\n"); 1392 exit(1); 1393 } 1394