1 /* $NetBSD: traceroute6.c,v 1.21 2002/05/26 14:45:44 itojun Exp $ */ 2 /* $KAME: traceroute6.c,v 1.50 2002/05/26 13:12:07 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.21 2002/05/26 14:45:44 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 307 u_char packet[512]; /* last inbound (icmp) packet */ 308 struct opacket *outpacket; /* last output (udp) packet */ 309 310 int main __P((int, char *[])); 311 int wait_for_reply __P((int, struct msghdr *)); 312 #ifdef IPSEC 313 #ifdef IPSEC_POLICY_IPSEC 314 int setpolicy __P((int so, char *policy)); 315 #endif 316 #endif 317 void send_probe __P((int, int)); 318 struct udphdr *get_udphdr __P((struct ip6_hdr *, u_char *)); 319 int get_hoplim __P((struct msghdr *)); 320 double deltaT __P((struct timeval *, struct timeval *)); 321 char *pr_type __P((int)); 322 int packet_ok __P((struct msghdr *, int, int)); 323 void print __P((struct msghdr *, int)); 324 void tvsub __P((struct timeval *, struct timeval *)); 325 const char *inetname __P((struct sockaddr *)); 326 void usage __P((void)); 327 328 int rcvsock; /* receive (icmp) socket file descriptor */ 329 int sndsock; /* send (udp) socket file descriptor */ 330 struct timezone tz; /* leftover */ 331 332 struct msghdr rcvmhdr; 333 struct iovec rcviov[2]; 334 int rcvhlim; 335 struct in6_pktinfo *rcvpktinfo; 336 337 struct sockaddr_in6 Src, Dst, Rcv; 338 int datalen; /* How much data */ 339 /* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */ 340 char rtbuf[2064]; 341 #ifdef USE_RFC2292BIS 342 struct ip6_rthdr *rth; 343 #endif 344 struct cmsghdr *cmsg; 345 346 char *source = 0; 347 char *hostname; 348 349 int nprobes = 3; 350 int first_hop = 1; 351 int max_hops = 30; 352 u_short srcport; 353 u_short port = 32768+666; /* start udp dest port # for probe packets */ 354 int options; /* socket options */ 355 int verbose; 356 int waittime = 5; /* time to wait for response (in seconds) */ 357 int nflag; /* print addresses numerically */ 358 int lflag; /* print both numerical address & hostname */ 359 360 int 361 main(argc, argv) 362 int argc; 363 char *argv[]; 364 { 365 struct hostent *hp; 366 int error; 367 struct addrinfo hints, *res; 368 int ch, i, on, probe, seq, hops, rcvcmsglen; 369 static u_char *rcvcmsgbuf; 370 char hbuf[NI_MAXHOST], src0[NI_MAXHOST]; 371 char *ep; 372 int mib[4] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM }; 373 size_t size = sizeof(max_hops); 374 375 /* 376 * Receive ICMP 377 */ 378 if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 379 perror("socket(ICMPv6)"); 380 exit(5); 381 } 382 383 /* revoke privs */ 384 seteuid(getuid()); 385 setuid(getuid()); 386 387 (void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &max_hops, &size, 388 NULL, 0); 389 390 /* set a minimum set of socket options */ 391 on = 1; 392 /* specify to tell receiving interface */ 393 #ifdef IPV6_RECVPKTINFO 394 if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 395 sizeof(on)) < 0) 396 err(1, "setsockopt(IPV6_RECVPKTINFO)"); 397 #else /* old adv. API */ 398 if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_PKTINFO, &on, 399 sizeof(on)) < 0) 400 err(1, "setsockopt(IPV6_PKTINFO)"); 401 #endif 402 403 /* specify to tell value of hoplimit field of received IP6 hdr */ 404 #ifdef IPV6_RECVHOPLIMIT 405 if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, 406 sizeof(on)) < 0) 407 err(1, "setsockopt(IPV6_RECVHOPLIMIT)"); 408 #else /* old adv. API */ 409 if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, 410 sizeof(on)) < 0) 411 err(1, "setsockopt(IPV6_HOPLIMIT)"); 412 #endif 413 414 seq = 0; 415 416 while ((ch = getopt(argc, argv, "df:g:lm:np:q:rs:w:v")) != -1) 417 switch(ch) { 418 case 'd': 419 options |= SO_DEBUG; 420 break; 421 case 'f': 422 ep = NULL; 423 first_hop = strtoul(optarg, &ep, 0); 424 if (!*argv || *ep) { 425 fprintf(stderr, 426 "traceroute6: invalid min hoplimit.\n"); 427 exit(1); 428 } 429 if (first_hop > max_hops) { 430 fprintf(stderr, 431 "traceroute6: min hoplimit must be <= %d.\n", 432 max_hops); 433 exit(1); 434 } 435 break; 436 case 'g': 437 hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno); 438 if (hp == NULL) { 439 fprintf(stderr, 440 "traceroute6: unknown host %s\n", optarg); 441 exit(1); 442 } 443 #ifdef USE_RFC2292BIS 444 if (rth == NULL) { 445 /* 446 * XXX: We can't detect the number of 447 * intermediate nodes yet. 448 */ 449 if ((rth = inet6_rth_init((void *)rtbuf, 450 sizeof(rtbuf), IPV6_RTHDR_TYPE_0, 451 0)) == NULL) { 452 fprintf(stderr, 453 "inet6_rth_init failed.\n"); 454 exit(1); 455 } 456 } 457 if (inet6_rth_add((void *)rth, 458 (struct in6_addr *)hp->h_addr)) { 459 fprintf(stderr, 460 "inet6_rth_add failed for %s\n", 461 optarg); 462 exit(1); 463 } 464 #else /* old advanced API */ 465 if (cmsg == NULL) 466 cmsg = inet6_rthdr_init(rtbuf, IPV6_RTHDR_TYPE_0); 467 inet6_rthdr_add(cmsg, (struct in6_addr *)hp->h_addr, 468 IPV6_RTHDR_LOOSE); 469 #endif 470 freehostent(hp); 471 break; 472 case 'l': 473 lflag++; 474 break; 475 case 'm': 476 ep = NULL; 477 max_hops = strtoul(optarg, &ep, 0); 478 if (!*argv || *ep) { 479 fprintf(stderr, 480 "traceroute6: invalid max hoplimit.\n"); 481 exit(1); 482 } 483 if (max_hops < first_hop) { 484 fprintf(stderr, 485 "traceroute6: max hoplimit must be >= %d.\n", 486 first_hop); 487 exit(1); 488 } 489 break; 490 case 'n': 491 nflag++; 492 break; 493 case 'p': 494 ep = NULL; 495 port = strtoul(optarg, &ep, 0); 496 if (!*argv || *ep) { 497 fprintf(stderr, "traceroute6: port.\n"); 498 exit(1); 499 } 500 if (port < 1) { 501 fprintf(stderr, 502 "traceroute6: port must be >0.\n"); 503 exit(1); 504 } 505 break; 506 case 'q': 507 ep = NULL; 508 nprobes = strtoul(optarg, &ep, 0); 509 if (!*argv || *ep) { 510 fprintf(stderr, 511 "traceroute6: invalid nprobes.\n"); 512 exit(1); 513 } 514 if (nprobes < 1) { 515 fprintf(stderr, 516 "traceroute6: nprobes must be >0.\n"); 517 exit(1); 518 } 519 break; 520 case 'r': 521 options |= SO_DONTROUTE; 522 break; 523 case 's': 524 /* 525 * set the ip source address of the outbound 526 * probe (e.g., on a multi-homed host). 527 */ 528 source = optarg; 529 break; 530 case 'v': 531 verbose++; 532 break; 533 case 'w': 534 ep = NULL; 535 waittime = strtoul(optarg, &ep, 0); 536 if (!*argv || *ep) { 537 fprintf(stderr, 538 "traceroute6: invalid wait time.\n"); 539 exit(1); 540 } 541 if (waittime <= 1) { 542 fprintf(stderr, 543 "traceroute6: wait must be >1 sec.\n"); 544 exit(1); 545 } 546 break; 547 default: 548 usage(); 549 } 550 argc -= optind; 551 argv += optind; 552 553 if (argc < 1 || argc > 2) 554 usage(); 555 556 #if 1 557 setvbuf(stdout, NULL, _IOLBF, BUFSIZ); 558 #else 559 setlinebuf (stdout); 560 #endif 561 562 memset(&hints, 0, sizeof(hints)); 563 hints.ai_family = PF_INET6; 564 hints.ai_socktype = SOCK_RAW; 565 hints.ai_protocol = IPPROTO_ICMPV6; 566 hints.ai_flags = AI_CANONNAME; 567 error = getaddrinfo(*argv, NULL, &hints, &res); 568 if (error) { 569 fprintf(stderr, 570 "traceroute6: %s\n", gai_strerror(error)); 571 exit(1); 572 } 573 if (res->ai_addrlen != sizeof(Dst)) { 574 fprintf(stderr, 575 "traceroute6: size of sockaddr mismatch\n"); 576 exit(1); 577 } 578 memcpy(&Dst, res->ai_addr, res->ai_addrlen); 579 hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv; 580 if (!hostname) { 581 fprintf(stderr, "traceroute6: not enough core\n"); 582 exit(1); 583 } 584 585 if (*++argv) { 586 ep = NULL; 587 datalen = strtoul(*argv, &ep, 0); 588 if (!*argv || *ep) { 589 fprintf(stderr, 590 "traceroute6: invalid packet length.\n"); 591 exit(1); 592 } 593 } 594 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) { 595 fprintf(stderr, 596 "traceroute6: packet size must be 0 <= s < %ld.\n", 597 (long)(MAXPACKET - sizeof(struct opacket))); 598 exit(1); 599 } 600 datalen += sizeof(struct opacket); 601 outpacket = (struct opacket *)malloc((unsigned)datalen); 602 if (! outpacket) { 603 perror("malloc"); 604 exit(1); 605 } 606 (void) bzero((char *)outpacket, datalen); 607 608 /* initialize msghdr for receiving packets */ 609 rcviov[0].iov_base = (caddr_t)packet; 610 rcviov[0].iov_len = sizeof(packet); 611 rcvmhdr.msg_name = (caddr_t)&Rcv; 612 rcvmhdr.msg_namelen = sizeof(Rcv); 613 rcvmhdr.msg_iov = rcviov; 614 rcvmhdr.msg_iovlen = 1; 615 rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) 616 + CMSG_SPACE(sizeof(int)); 617 if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) { 618 fprintf(stderr, "traceroute6: malloc failed\n"); 619 exit(1); 620 } 621 rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; 622 rcvmhdr.msg_controllen = rcvcmsglen; 623 624 if (options & SO_DEBUG) 625 (void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, 626 (char *)&on, sizeof(on)); 627 if (options & SO_DONTROUTE) 628 (void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, 629 (char *)&on, sizeof(on)); 630 #ifdef IPSEC 631 #ifdef IPSEC_POLICY_IPSEC 632 /* 633 * do not raise error even if setsockopt fails, kernel may have ipsec 634 * turned off. 635 */ 636 if (setpolicy(rcvsock, "in bypass") < 0) 637 errx(1, "%s", ipsec_strerror()); 638 if (setpolicy(rcvsock, "out bypass") < 0) 639 errx(1, "%s", ipsec_strerror()); 640 #else 641 { 642 int level = IPSEC_LEVEL_NONE; 643 644 (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, 645 sizeof(level)); 646 (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, 647 sizeof(level)); 648 #ifdef IP_AUTH_TRANS_LEVEL 649 (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, 650 sizeof(level)); 651 #else 652 (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, 653 sizeof(level)); 654 #endif 655 #ifdef IP_AUTH_NETWORK_LEVEL 656 (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, 657 sizeof(level)); 658 #endif 659 } 660 #endif /*IPSEC_POLICY_IPSEC*/ 661 #endif /*IPSEC*/ 662 663 /* 664 * Send UDP 665 */ 666 if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 667 perror("socket(SOCK_DGRAM)"); 668 exit(5); 669 } 670 #ifdef SO_SNDBUF 671 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, 672 sizeof(datalen)) < 0) { 673 perror("setsockopt(SO_SNDBUF)"); 674 exit(6); 675 } 676 #endif /* SO_SNDBUF */ 677 if (options & SO_DEBUG) 678 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 679 (char *)&on, sizeof(on)); 680 if (options & SO_DONTROUTE) 681 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, 682 (char *)&on, sizeof(on)); 683 #ifdef USE_RFC2292BIS 684 if (rth) {/* XXX: there is no library to finalize the header... */ 685 rth->ip6r_len = rth->ip6r_segleft * 2; 686 if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR, 687 (void *)rth, (rth->ip6r_len + 1) << 3)) { 688 fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n", 689 strerror(errno)); 690 exit(1); 691 } 692 } 693 #else /* old advanced API */ 694 if (cmsg != NULL) { 695 inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE); 696 if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_PKTOPTIONS, 697 rtbuf, cmsg->cmsg_len) < 0) { 698 fprintf(stderr, "setsockopt(IPV6_PKTOPTIONS): %s\n", 699 strerror(errno)); 700 exit(1); 701 } 702 } 703 #endif /* USE_RFC2292BIS */ 704 #ifdef IPSEC 705 #ifdef IPSEC_POLICY_IPSEC 706 /* 707 * do not raise error even if setsockopt fails, kernel may have ipsec 708 * turned off. 709 */ 710 if (setpolicy(sndsock, "in bypass") < 0) 711 errx(1, "%s", ipsec_strerror()); 712 if (setpolicy(sndsock, "out bypass") < 0) 713 errx(1, "%s", ipsec_strerror()); 714 #else 715 { 716 int level = IPSEC_LEVEL_BYPASS; 717 718 (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, 719 sizeof(level)); 720 (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, 721 sizeof(level)); 722 #ifdef IP_AUTH_TRANS_LEVEL 723 (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, 724 sizeof(level)); 725 #else 726 (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, 727 sizeof(level)); 728 #endif 729 #ifdef IP_AUTH_NETWORK_LEVEL 730 (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, 731 sizeof(level)); 732 #endif 733 } 734 #endif /*IPSEC_POLICY_IPSEC*/ 735 #endif /*IPSEC*/ 736 737 /* 738 * Source selection 739 */ 740 bzero(&Src, sizeof(Src)); 741 if (source) { 742 struct addrinfo hints, *res; 743 int error; 744 745 memset(&hints, 0, sizeof(hints)); 746 hints.ai_family = AF_INET6; 747 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 748 hints.ai_flags = AI_NUMERICHOST; 749 error = getaddrinfo(source, "0", &hints, &res); 750 if (error) { 751 printf("traceroute6: %s: %s\n", source, 752 gai_strerror(error)); 753 exit(1); 754 } 755 if (res->ai_addrlen > sizeof(Src)) { 756 printf("traceroute6: %s: %s\n", source, 757 gai_strerror(error)); 758 exit(1); 759 } 760 memcpy(&Src, res->ai_addr, res->ai_addrlen); 761 freeaddrinfo(res); 762 } else { 763 struct sockaddr_in6 Nxt; 764 int dummy, len; 765 766 Nxt = Dst; 767 Nxt.sin6_port = htons(DUMMY_PORT); 768 if (cmsg != NULL) 769 bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr, 770 sizeof(Nxt.sin6_addr)); 771 if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 772 perror("socket"); 773 exit(1); 774 } 775 if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) { 776 perror("connect"); 777 exit(1); 778 } 779 len = sizeof(Src); 780 if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) { 781 perror("getsockname"); 782 exit(1); 783 } 784 if (getnameinfo((struct sockaddr *)&Src, Src.sin6_len, 785 src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) { 786 fprintf(stderr, "getnameinfo failed for source\n"); 787 exit(1); 788 } 789 source = src0; 790 close(dummy); 791 } 792 793 Src.sin6_port = htons(0); 794 if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) { 795 perror("bind"); 796 exit(1); 797 } 798 799 { 800 int len; 801 802 len = sizeof(Src); 803 if (getsockname(sndsock, (struct sockaddr *)&Src, &len) < 0) { 804 perror("getsockname"); 805 exit(1); 806 } 807 srcport = ntohs(Src.sin6_port); 808 } 809 810 /* 811 * Message to users 812 */ 813 if (getnameinfo((struct sockaddr *)&Dst, Dst.sin6_len, hbuf, 814 sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) 815 strlcpy(hbuf, "(invalid)", sizeof(hbuf)); 816 fprintf(stderr, "traceroute6"); 817 fprintf(stderr, " to %s (%s)", hostname, hbuf); 818 if (source) 819 fprintf(stderr, " from %s", source); 820 fprintf(stderr, ", %d hops max, %d byte packets\n", 821 max_hops, datalen); 822 (void) fflush(stderr); 823 824 if (first_hop > 1) 825 printf("Skipping %d intermediate hops\n", first_hop - 1); 826 827 /* 828 * Main loop 829 */ 830 for (hops = first_hop; hops <= max_hops; ++hops) { 831 struct in6_addr lastaddr; 832 int got_there = 0; 833 int unreachable = 0; 834 835 printf("%2d ", hops); 836 bzero(&lastaddr, sizeof(lastaddr)); 837 for (probe = 0; probe < nprobes; ++probe) { 838 int cc; 839 struct timeval t1, t2; 840 struct timezone tz; 841 842 (void) gettimeofday(&t1, &tz); 843 send_probe(++seq, hops); 844 while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) { 845 (void) gettimeofday(&t2, &tz); 846 if ((i = packet_ok(&rcvmhdr, cc, seq))) { 847 if (! IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr, 848 &lastaddr)) { 849 print(&rcvmhdr, cc); 850 lastaddr = Rcv.sin6_addr; 851 } 852 printf(" %g ms", deltaT(&t1, &t2)); 853 switch(i - 1) { 854 case ICMP6_DST_UNREACH_NOROUTE: 855 ++unreachable; 856 printf(" !N"); 857 break; 858 case ICMP6_DST_UNREACH_ADMIN: 859 ++unreachable; 860 printf(" !P"); 861 break; 862 case ICMP6_DST_UNREACH_NOTNEIGHBOR: 863 ++unreachable; 864 printf(" !S"); 865 break; 866 case ICMP6_DST_UNREACH_ADDR: 867 ++unreachable; 868 printf(" !A"); 869 break; 870 case ICMP6_DST_UNREACH_NOPORT: 871 if (rcvhlim >= 0 && 872 rcvhlim <= 1) 873 printf(" !"); 874 ++got_there; 875 break; 876 } 877 break; 878 } 879 } 880 if (cc == 0) 881 printf(" *"); 882 (void) fflush(stdout); 883 } 884 putchar('\n'); 885 if (got_there || 886 (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) { 887 exit(0); 888 } 889 } 890 891 exit(0); 892 } 893 894 int 895 wait_for_reply(sock, mhdr) 896 int sock; 897 struct msghdr *mhdr; 898 { 899 #ifdef HAVE_POLL 900 struct pollfd pfd[1]; 901 int cc = 0; 902 903 pfd[0].fd = sock; 904 pfd[0].events = POLLIN; 905 pfd[0].revents = 0; 906 907 if (poll(pfd, 1, waittime * 1000) > 0) 908 cc = recvmsg(rcvsock, mhdr, 0); 909 910 return(cc); 911 #else 912 fd_set *fdsp; 913 struct timeval wait; 914 int cc = 0, fdsn; 915 916 fdsn = howmany(sock + 1, NFDBITS) * sizeof(fd_mask); 917 if ((fdsp = (fd_set *)malloc(fdsn)) == NULL) 918 err(1, "malloc"); 919 memset(fdsp, 0, fdsn); 920 FD_SET(sock, fdsp); 921 wait.tv_sec = waittime; wait.tv_usec = 0; 922 923 if (select(sock+1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0) 924 cc = recvmsg(rcvsock, mhdr, 0); 925 926 free(fdsp); 927 return(cc); 928 #endif 929 } 930 931 #ifdef IPSEC 932 #ifdef IPSEC_POLICY_IPSEC 933 int 934 setpolicy(so, policy) 935 int so; 936 char *policy; 937 { 938 char *buf; 939 940 buf = ipsec_set_policy(policy, strlen(policy)); 941 if (buf == NULL) { 942 warnx("%s", ipsec_strerror()); 943 return -1; 944 } 945 (void)setsockopt(so, IPPROTO_IPV6, IPV6_IPSEC_POLICY, 946 buf, ipsec_get_policylen(buf)); 947 948 free(buf); 949 950 return 0; 951 } 952 #endif 953 #endif 954 955 void 956 send_probe(seq, hops) 957 int seq, hops; 958 { 959 struct opacket *op = outpacket; 960 int i; 961 962 if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 963 (char *)&hops, sizeof(hops)) < 0) { 964 perror("setsockopt IPV6_UNICAST_HOPS"); 965 } 966 967 Dst.sin6_port = htons(port + seq); 968 969 op->seq = seq; 970 op->hops = hops; 971 (void) gettimeofday(&op->tv, &tz); 972 973 i = sendto(sndsock, (char *)outpacket, datalen , 0, 974 (struct sockaddr *)&Dst, Dst.sin6_len); 975 if (i < 0 || i != datalen) { 976 if (i<0) 977 perror("sendto"); 978 printf("traceroute6: wrote %s %d chars, ret=%d\n", 979 hostname, datalen, i); 980 (void) fflush(stdout); 981 } 982 } 983 984 int 985 get_hoplim(mhdr) 986 struct msghdr *mhdr; 987 { 988 struct cmsghdr *cm; 989 990 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 991 cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 992 if (cm->cmsg_level == IPPROTO_IPV6 && 993 cm->cmsg_type == IPV6_HOPLIMIT && 994 cm->cmsg_len == CMSG_LEN(sizeof(int))) 995 return(*(int *)CMSG_DATA(cm)); 996 } 997 998 return(-1); 999 } 1000 1001 double 1002 deltaT(t1p, t2p) 1003 struct timeval *t1p, *t2p; 1004 { 1005 register double dt; 1006 1007 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + 1008 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; 1009 return (dt); 1010 } 1011 1012 /* 1013 * Convert an ICMP "type" field to a printable string. 1014 */ 1015 char * 1016 pr_type(t0) 1017 int t0; 1018 { 1019 u_char t = t0 & 0xff; 1020 char *cp; 1021 1022 switch (t) { 1023 case ICMP6_DST_UNREACH: 1024 cp = "Destination Unreachable"; 1025 break; 1026 case ICMP6_PACKET_TOO_BIG: 1027 cp = "Packet Too Big"; 1028 break; 1029 case ICMP6_TIME_EXCEEDED: 1030 cp = "Time Exceeded"; 1031 break; 1032 case ICMP6_PARAM_PROB: 1033 cp = "Parameter Problem"; 1034 break; 1035 case ICMP6_ECHO_REQUEST: 1036 cp = "Echo Request"; 1037 break; 1038 case ICMP6_ECHO_REPLY: 1039 cp = "Echo Reply"; 1040 break; 1041 case ICMP6_MEMBERSHIP_QUERY: 1042 cp = "Group Membership Query"; 1043 break; 1044 case ICMP6_MEMBERSHIP_REPORT: 1045 cp = "Group Membership Report"; 1046 break; 1047 case ICMP6_MEMBERSHIP_REDUCTION: 1048 cp = "Group Membership Reduction"; 1049 break; 1050 case ND_ROUTER_SOLICIT: 1051 cp = "Router Solicitation"; 1052 break; 1053 case ND_ROUTER_ADVERT: 1054 cp = "Router Advertisement"; 1055 break; 1056 case ND_NEIGHBOR_SOLICIT: 1057 cp = "Neighbor Solicitation"; 1058 break; 1059 case ND_NEIGHBOR_ADVERT: 1060 cp = "Neighbor Advertisement"; 1061 break; 1062 case ND_REDIRECT: 1063 cp = "Redirect"; 1064 break; 1065 default: 1066 cp = "Unknown"; 1067 break; 1068 } 1069 return cp; 1070 } 1071 1072 int 1073 packet_ok(mhdr, cc, seq) 1074 struct msghdr *mhdr; 1075 int cc; 1076 int seq; 1077 { 1078 register struct icmp6_hdr *icp; 1079 struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; 1080 u_char type, code; 1081 char *buf = (char *)mhdr->msg_iov[0].iov_base; 1082 struct cmsghdr *cm; 1083 int *hlimp; 1084 char hbuf[NI_MAXHOST]; 1085 1086 #ifdef OLDRAWSOCKET 1087 int hlen; 1088 struct ip6_hdr *ip; 1089 #endif 1090 1091 #ifdef OLDRAWSOCKET 1092 ip = (struct ip6_hdr *) buf; 1093 hlen = sizeof(struct ip6_hdr); 1094 if (cc < hlen + sizeof(struct icmp6_hdr)) { 1095 if (verbose) { 1096 if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1097 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 1098 strlcpy(hbuf, "invalid", sizeof(hbuf)); 1099 printf("packet too short (%d bytes) from %s\n", cc, 1100 hbuf); 1101 } 1102 return (0); 1103 } 1104 cc -= hlen; 1105 icp = (struct icmp6_hdr *)(buf + hlen); 1106 #else 1107 if (cc < sizeof(struct icmp6_hdr)) { 1108 if (verbose) { 1109 if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1110 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 1111 strlcpy(hbuf, "invalid", sizeof(hbuf)); 1112 printf("data too short (%d bytes) from %s\n", cc, hbuf); 1113 } 1114 return(0); 1115 } 1116 icp = (struct icmp6_hdr *)buf; 1117 #endif 1118 /* get optional information via advanced API */ 1119 rcvpktinfo = NULL; 1120 hlimp = NULL; 1121 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 1122 cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 1123 if (cm->cmsg_level == IPPROTO_IPV6 && 1124 cm->cmsg_type == IPV6_PKTINFO && 1125 cm->cmsg_len == 1126 CMSG_LEN(sizeof(struct in6_pktinfo))) 1127 rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm)); 1128 1129 if (cm->cmsg_level == IPPROTO_IPV6 && 1130 cm->cmsg_type == IPV6_HOPLIMIT && 1131 cm->cmsg_len == CMSG_LEN(sizeof(int))) 1132 hlimp = (int *)CMSG_DATA(cm); 1133 } 1134 if (rcvpktinfo == NULL || hlimp == NULL) { 1135 warnx("failed to get received hop limit or packet info"); 1136 #if 0 1137 return(0); 1138 #else 1139 rcvhlim = 0; /*XXX*/ 1140 #endif 1141 } 1142 else 1143 rcvhlim = *hlimp; 1144 1145 type = icp->icmp6_type; 1146 code = icp->icmp6_code; 1147 if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) 1148 || type == ICMP6_DST_UNREACH) { 1149 struct ip6_hdr *hip; 1150 struct udphdr *up; 1151 1152 hip = (struct ip6_hdr *)(icp + 1); 1153 if ((up = get_udphdr(hip, (u_char *)(buf + cc))) == NULL) { 1154 if (verbose) 1155 warnx("failed to get upper layer header"); 1156 return(0); 1157 } 1158 if (up->uh_sport == htons(srcport) && 1159 up->uh_dport == htons(port + seq)) 1160 return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1); 1161 } 1162 if (verbose) { 1163 int i; 1164 u_int8_t *p; 1165 char sbuf[NI_MAXHOST+1], dbuf[INET6_ADDRSTRLEN]; 1166 1167 if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1168 sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0) 1169 strlcpy(sbuf, "invalid", sizeof(hbuf)); 1170 printf("\n%d bytes from %s to %s", cc, sbuf, 1171 rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1172 dbuf, sizeof(dbuf)) : "?"); 1173 printf(": icmp type %d (%s) code %d\n", type, pr_type(type), 1174 icp->icmp6_code); 1175 p = (u_int8_t *)(icp + 1); 1176 #define WIDTH 16 1177 for (i = 0; i < cc; i++) { 1178 if (i % WIDTH == 0) 1179 printf("%04x:", i); 1180 if (i % 4 == 0) 1181 printf(" "); 1182 printf("%02x", p[i]); 1183 if (i % WIDTH == WIDTH - 1) 1184 printf("\n"); 1185 } 1186 if (cc % WIDTH != 0) 1187 printf("\n"); 1188 } 1189 return(0); 1190 } 1191 1192 /* 1193 * Increment pointer until find the UDP header. 1194 */ 1195 struct udphdr * 1196 get_udphdr(ip6, lim) 1197 struct ip6_hdr *ip6; 1198 u_char *lim; 1199 { 1200 u_char *cp = (u_char *)ip6, nh; 1201 int hlen; 1202 1203 if (cp + sizeof(*ip6) >= lim) 1204 return(NULL); 1205 1206 nh = ip6->ip6_nxt; 1207 cp += sizeof(struct ip6_hdr); 1208 1209 while (lim - cp >= 8) { 1210 switch(nh) { 1211 case IPPROTO_ESP: 1212 case IPPROTO_TCP: 1213 case IPPROTO_ICMPV6: 1214 return(NULL); 1215 case IPPROTO_UDP: 1216 return((struct udphdr *)cp); 1217 case IPPROTO_FRAGMENT: 1218 hlen = sizeof(struct ip6_frag); 1219 nh = ((struct ip6_frag *)cp)->ip6f_nxt; 1220 break; 1221 case IPPROTO_AH: 1222 hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2; 1223 nh = ((struct ip6_ext *)cp)->ip6e_nxt; 1224 break; 1225 default: 1226 hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3; 1227 nh = ((struct ip6_ext *)cp)->ip6e_nxt; 1228 break; 1229 } 1230 1231 cp += hlen; 1232 } 1233 1234 return(NULL); 1235 } 1236 1237 void 1238 print(mhdr, cc) 1239 struct msghdr *mhdr; 1240 int cc; 1241 { 1242 struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; 1243 char hbuf[NI_MAXHOST]; 1244 1245 if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1246 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 1247 strlcpy(hbuf, "invalid", sizeof(hbuf)); 1248 if (nflag) 1249 printf(" %s", hbuf); 1250 else if (lflag) 1251 printf(" %s (%s)", inetname((struct sockaddr *)from), hbuf); 1252 else 1253 printf(" %s", inetname((struct sockaddr *)from)); 1254 1255 if (verbose) { 1256 #ifdef OLDRAWSOCKET 1257 printf(" %d bytes to %s", cc, 1258 rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1259 hbuf, sizeof(hbuf)) : "?"); 1260 #else 1261 printf(" %d bytes of data to %s", cc, 1262 rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1263 hbuf, sizeof(hbuf)) : "?"); 1264 #endif 1265 } 1266 } 1267 1268 /* 1269 * Subtract 2 timeval structs: out = out - in. 1270 * Out is assumed to be >= in. 1271 */ 1272 void 1273 tvsub(out, in) 1274 register struct timeval *out, *in; 1275 { 1276 1277 if ((out->tv_usec -= in->tv_usec) < 0) { 1278 out->tv_sec--; 1279 out->tv_usec += 1000000; 1280 } 1281 out->tv_sec -= in->tv_sec; 1282 } 1283 1284 /* 1285 * Construct an Internet address representation. 1286 * If the nflag has been supplied, give 1287 * numeric value, otherwise try for symbolic name. 1288 */ 1289 const char * 1290 inetname(sa) 1291 struct sockaddr *sa; 1292 { 1293 register char *cp; 1294 static char line[NI_MAXHOST]; 1295 static char domain[MAXHOSTNAMELEN + 1]; 1296 static int first = 1; 1297 1298 if (first && !nflag) { 1299 first = 0; 1300 if (gethostname(domain, sizeof(domain)) == 0 && 1301 (cp = index(domain, '.'))) 1302 (void) strlcpy(domain, cp + 1, sizeof(domain)); 1303 else 1304 domain[0] = 0; 1305 } 1306 cp = NULL; 1307 if (!nflag) { 1308 if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, 1309 NI_NAMEREQD) == 0) { 1310 if ((cp = index(line, '.')) && 1311 !strcmp(cp + 1, domain)) 1312 *cp = 0; 1313 cp = line; 1314 } 1315 } 1316 if (cp) 1317 return cp; 1318 1319 if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, 1320 NI_NUMERICHOST) != 0) 1321 strlcpy(line, "invalid", sizeof(line)); 1322 return line; 1323 } 1324 1325 void 1326 usage() 1327 { 1328 1329 fprintf(stderr, 1330 "usage: traceroute6 [-dlnrv] [-f firsthop] [-g gateway] [-m hoplimit] [-p port]\n" 1331 " [-q probes] [-s src] [-w waittime] target [datalen]\n"); 1332 exit(1); 1333 } 1334