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