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