• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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@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 
main(int argc,char * argv[])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
wait_for_reply(sock,from,to,reset_timer)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 
send_probe(int seq,int ttl)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 
deltaT(struct timeval * t1p,struct timeval * t2p)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  */
pr_type(unsigned char t)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 
packet_ok(u_char * buf,int cc,struct sockaddr_in6 * from,struct in6_addr * to,int seq,struct timeval * tv)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 
print(unsigned char * buf,int cc,struct sockaddr_in6 * from)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
tvsub(out,in)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 
usage(void)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