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