xref: /freebsd/usr.sbin/traceroute6/traceroute6.c (revision 51eff8efd9844ba91b859cb7c25f5f6aa85382f4)
1e961704aSDavid Malone /*	$KAME: traceroute6.c,v 1.68 2004/01/25 11:16:12 suz Exp $	*/
2de68a0daSKris Kennaway 
38a16b7a1SPedro F. Giffuni /*-
48a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
58a16b7a1SPedro F. Giffuni  *
67d56d374SYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
77d56d374SYoshinobu Inoue  * All rights reserved.
87d56d374SYoshinobu Inoue  *
97d56d374SYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
107d56d374SYoshinobu Inoue  * modification, are permitted provided that the following conditions
117d56d374SYoshinobu Inoue  * are met:
127d56d374SYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
137d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
147d56d374SYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
157d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
167d56d374SYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
177d56d374SYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
187d56d374SYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
197d56d374SYoshinobu Inoue  *    without specific prior written permission.
207d56d374SYoshinobu Inoue  *
217d56d374SYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
227d56d374SYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
237d56d374SYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
247d56d374SYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
257d56d374SYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
267d56d374SYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
277d56d374SYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
287d56d374SYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
297d56d374SYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
307d56d374SYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
317d56d374SYoshinobu Inoue  * SUCH DAMAGE.
327d56d374SYoshinobu Inoue  */
337d56d374SYoshinobu Inoue 
347d56d374SYoshinobu Inoue /*-
357d56d374SYoshinobu Inoue  * Copyright (c) 1990, 1993
367d56d374SYoshinobu Inoue  *	The Regents of the University of California.  All rights reserved.
377d56d374SYoshinobu Inoue  *
387d56d374SYoshinobu Inoue  * This code is derived from software contributed to Berkeley by
397d56d374SYoshinobu Inoue  * Van Jacobson.
407d56d374SYoshinobu Inoue  *
417d56d374SYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
427d56d374SYoshinobu Inoue  * modification, are permitted provided that the following conditions
437d56d374SYoshinobu Inoue  * are met:
447d56d374SYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
457d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
467d56d374SYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
477d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
487d56d374SYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
49fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
507d56d374SYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
517d56d374SYoshinobu Inoue  *    without specific prior written permission.
527d56d374SYoshinobu Inoue  *
537d56d374SYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
547d56d374SYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
557d56d374SYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
567d56d374SYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
577d56d374SYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
587d56d374SYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
597d56d374SYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
607d56d374SYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
617d56d374SYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
627d56d374SYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
637d56d374SYoshinobu Inoue  * SUCH DAMAGE.
647d56d374SYoshinobu Inoue  */
657d56d374SYoshinobu Inoue 
667d56d374SYoshinobu Inoue #ifndef lint
67f42640a3SUlrich Spörlein static const char copyright[] =
687d56d374SYoshinobu Inoue "@(#) Copyright (c) 1990, 1993\n\
697d56d374SYoshinobu Inoue 	The Regents of the University of California.  All rights reserved.\n";
707d56d374SYoshinobu Inoue #endif /* not lint */
717d56d374SYoshinobu Inoue 
727d56d374SYoshinobu Inoue #ifndef lint
73de68a0daSKris Kennaway #if 0
747d56d374SYoshinobu Inoue static char sccsid[] = "@(#)traceroute.c	8.1 (Berkeley) 6/6/93";
75de68a0daSKris Kennaway #endif
76de68a0daSKris Kennaway static const char rcsid[] =
77de68a0daSKris Kennaway   "$FreeBSD$";
787d56d374SYoshinobu Inoue #endif /* not lint */
797d56d374SYoshinobu Inoue 
807d56d374SYoshinobu Inoue /*
817d56d374SYoshinobu Inoue  * traceroute host  - trace the route ip packets follow going to "host".
827d56d374SYoshinobu Inoue  *
837d56d374SYoshinobu Inoue  * Attempt to trace the route an ip packet would follow to some
847d56d374SYoshinobu Inoue  * internet host.  We find out intermediate hops by launching probe
857d56d374SYoshinobu Inoue  * packets with a small ttl (time to live) then listening for an
867d56d374SYoshinobu Inoue  * icmp "time exceeded" reply from a gateway.  We start our probes
877d56d374SYoshinobu Inoue  * with a ttl of one and increase by one until we get an icmp "port
887d56d374SYoshinobu Inoue  * unreachable" (which means we got to "host") or hit a max (which
897d56d374SYoshinobu Inoue  * defaults to 30 hops & can be changed with the -m flag).  Three
907d56d374SYoshinobu Inoue  * probes (change with -q flag) are sent at each ttl setting and a
917d56d374SYoshinobu Inoue  * line is printed showing the ttl, address of the gateway and
927d56d374SYoshinobu Inoue  * round trip time of each probe.  If the probe answers come from
937d56d374SYoshinobu Inoue  * different gateways, the address of each responding system will
947d56d374SYoshinobu Inoue  * be printed.  If there is no response within a 5 sec. timeout
957d56d374SYoshinobu Inoue  * interval (changed with the -w flag), a "*" is printed for that
967d56d374SYoshinobu Inoue  * probe.
977d56d374SYoshinobu Inoue  *
987d56d374SYoshinobu Inoue  * Probe packets are UDP format.  We don't want the destination
997d56d374SYoshinobu Inoue  * host to process them so the destination port is set to an
1007d56d374SYoshinobu Inoue  * unlikely value (if some clod on the destination is using that
1017d56d374SYoshinobu Inoue  * value, it can be changed with the -p flag).
1027d56d374SYoshinobu Inoue  *
1037d56d374SYoshinobu Inoue  * A sample use might be:
1047d56d374SYoshinobu Inoue  *
1057d56d374SYoshinobu Inoue  *     [yak 71]% traceroute nis.nsf.net.
1067d56d374SYoshinobu Inoue  *     traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
1077d56d374SYoshinobu Inoue  *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
1087d56d374SYoshinobu Inoue  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
1097d56d374SYoshinobu Inoue  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
1107d56d374SYoshinobu Inoue  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
1117d56d374SYoshinobu Inoue  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
1127d56d374SYoshinobu Inoue  *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
1137d56d374SYoshinobu Inoue  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
1147d56d374SYoshinobu Inoue  *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
1157d56d374SYoshinobu Inoue  *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
1167d56d374SYoshinobu Inoue  *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
1177d56d374SYoshinobu Inoue  *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
1187d56d374SYoshinobu Inoue  *
1197d56d374SYoshinobu Inoue  * Note that lines 2 & 3 are the same.  This is due to a buggy
1207d56d374SYoshinobu Inoue  * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
1217d56d374SYoshinobu Inoue  * packets with a zero ttl.
1227d56d374SYoshinobu Inoue  *
1237d56d374SYoshinobu Inoue  * A more interesting example is:
1247d56d374SYoshinobu Inoue  *
1257d56d374SYoshinobu Inoue  *     [yak 72]% traceroute allspice.lcs.mit.edu.
1267d56d374SYoshinobu Inoue  *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
1277d56d374SYoshinobu Inoue  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
1287d56d374SYoshinobu Inoue  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
1297d56d374SYoshinobu Inoue  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
1307d56d374SYoshinobu Inoue  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
1317d56d374SYoshinobu Inoue  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
1327d56d374SYoshinobu Inoue  *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
1337d56d374SYoshinobu Inoue  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
1347d56d374SYoshinobu Inoue  *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
1357d56d374SYoshinobu Inoue  *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
1367d56d374SYoshinobu Inoue  *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
1377d56d374SYoshinobu Inoue  *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
1387d56d374SYoshinobu Inoue  *     12  * * *
1397d56d374SYoshinobu Inoue  *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
1407d56d374SYoshinobu Inoue  *     14  * * *
1417d56d374SYoshinobu Inoue  *     15  * * *
1427d56d374SYoshinobu Inoue  *     16  * * *
1437d56d374SYoshinobu Inoue  *     17  * * *
1447d56d374SYoshinobu Inoue  *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
1457d56d374SYoshinobu Inoue  *
1467d56d374SYoshinobu Inoue  * (I start to see why I'm having so much trouble with mail to
1477d56d374SYoshinobu Inoue  * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
1487d56d374SYoshinobu Inoue  * either don't send ICMP "time exceeded" messages or send them
1497d56d374SYoshinobu Inoue  * with a ttl too small to reach us.  14 - 17 are running the
1507d56d374SYoshinobu Inoue  * MIT C Gateway code that doesn't send "time exceeded"s.  God
1517d56d374SYoshinobu Inoue  * only knows what's going on with 12.
1527d56d374SYoshinobu Inoue  *
1537d56d374SYoshinobu Inoue  * The silent gateway 12 in the above may be the result of a bug in
1547d56d374SYoshinobu Inoue  * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
1557d56d374SYoshinobu Inoue  * sends an unreachable message using whatever ttl remains in the
1567d56d374SYoshinobu Inoue  * original datagram.  Since, for gateways, the remaining ttl is
1577d56d374SYoshinobu Inoue  * zero, the icmp "time exceeded" is guaranteed to not make it back
1587d56d374SYoshinobu Inoue  * to us.  The behavior of this bug is slightly more interesting
1597d56d374SYoshinobu Inoue  * when it appears on the destination system:
1607d56d374SYoshinobu Inoue  *
1617d56d374SYoshinobu Inoue  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
1627d56d374SYoshinobu Inoue  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
1637d56d374SYoshinobu Inoue  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
1647d56d374SYoshinobu Inoue  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
1657d56d374SYoshinobu Inoue  *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
1667d56d374SYoshinobu Inoue  *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
1677d56d374SYoshinobu Inoue  *      7  * * *
1687d56d374SYoshinobu Inoue  *      8  * * *
1697d56d374SYoshinobu Inoue  *      9  * * *
1707d56d374SYoshinobu Inoue  *     10  * * *
1717d56d374SYoshinobu Inoue  *     11  * * *
1727d56d374SYoshinobu Inoue  *     12  * * *
1737d56d374SYoshinobu Inoue  *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
1747d56d374SYoshinobu Inoue  *
1757d56d374SYoshinobu Inoue  * Notice that there are 12 "gateways" (13 is the final
1767d56d374SYoshinobu Inoue  * destination) and exactly the last half of them are "missing".
1777d56d374SYoshinobu Inoue  * What's really happening is that rip (a Sun-3 running Sun OS3.5)
1787d56d374SYoshinobu Inoue  * is using the ttl from our arriving datagram as the ttl in its
1797d56d374SYoshinobu Inoue  * icmp reply.  So, the reply will time out on the return path
1807d56d374SYoshinobu Inoue  * (with no notice sent to anyone since icmp's aren't sent for
1817d56d374SYoshinobu Inoue  * icmp's) until we probe with a ttl that's at least twice the path
1827d56d374SYoshinobu Inoue  * length.  I.e., rip is really only 7 hops away.  A reply that
1837d56d374SYoshinobu Inoue  * returns with a ttl of 1 is a clue this problem exists.
1847d56d374SYoshinobu Inoue  * Traceroute prints a "!" after the time if the ttl is <= 1.
1857d56d374SYoshinobu Inoue  * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
1867d56d374SYoshinobu Inoue  * non-standard (HPUX) software, expect to see this problem
1877d56d374SYoshinobu Inoue  * frequently and/or take care picking the target host of your
1887d56d374SYoshinobu Inoue  * probes.
1897d56d374SYoshinobu Inoue  *
1907d56d374SYoshinobu Inoue  * Other possible annotations after the time are !H, !N, !P (got a host,
1917d56d374SYoshinobu Inoue  * network or protocol unreachable, respectively), !S or !F (source
1927d56d374SYoshinobu Inoue  * route failed or fragmentation needed -- neither of these should
1937d56d374SYoshinobu Inoue  * ever occur and the associated gateway is busted if you see one).  If
1947d56d374SYoshinobu Inoue  * almost all the probes result in some kind of unreachable, traceroute
1957d56d374SYoshinobu Inoue  * will give up and exit.
1967d56d374SYoshinobu Inoue  *
1977d56d374SYoshinobu Inoue  * Notes
1987d56d374SYoshinobu Inoue  * -----
1997d56d374SYoshinobu Inoue  * This program must be run by root or be setuid.  (I suggest that
2007d56d374SYoshinobu Inoue  * you *don't* make it setuid -- casual use could result in a lot
2017d56d374SYoshinobu Inoue  * of unnecessary traffic on our poor, congested nets.)
2027d56d374SYoshinobu Inoue  *
2037d56d374SYoshinobu Inoue  * This program requires a kernel mod that does not appear in any
2047d56d374SYoshinobu Inoue  * system available from Berkeley:  A raw ip socket using proto
2057d56d374SYoshinobu Inoue  * IPPROTO_RAW must interpret the data sent as an ip datagram (as
2069d5abbddSJens Schweikhardt  * opposed to data to be wrapped in an ip datagram).  See the README
2077d56d374SYoshinobu Inoue  * file that came with the source to this program for a description
2087d56d374SYoshinobu Inoue  * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
2097d56d374SYoshinobu Inoue  * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
2107d56d374SYoshinobu Inoue  * MODIFIED TO RUN THIS PROGRAM.
2117d56d374SYoshinobu Inoue  *
2127d56d374SYoshinobu Inoue  * The udp port usage may appear bizarre (well, ok, it is bizarre).
2137d56d374SYoshinobu Inoue  * The problem is that an icmp message only contains 8 bytes of
2147d56d374SYoshinobu Inoue  * data from the original datagram.  8 bytes is the size of a udp
2157d56d374SYoshinobu Inoue  * header so, if we want to associate replies with the original
2167d56d374SYoshinobu Inoue  * datagram, the necessary information must be encoded into the
2177d56d374SYoshinobu Inoue  * udp header (the ip id could be used but there's no way to
2187d56d374SYoshinobu Inoue  * interlock with the kernel's assignment of ip id's and, anyway,
2197d56d374SYoshinobu Inoue  * it would have taken a lot more kernel hacking to allow this
2207d56d374SYoshinobu Inoue  * code to set the ip id).  So, to allow two or more users to
2217d56d374SYoshinobu Inoue  * use traceroute simultaneously, we use this task's pid as the
2227d56d374SYoshinobu Inoue  * source port (the high bit is set to move the port number out
2237d56d374SYoshinobu Inoue  * of the "likely" range).  To keep track of which probe is being
2247d56d374SYoshinobu Inoue  * replied to (so times and/or hop counts don't get confused by a
2257d56d374SYoshinobu Inoue  * reply that was delayed in transit), we increment the destination
2267d56d374SYoshinobu Inoue  * port number before each probe.
2277d56d374SYoshinobu Inoue  *
2287d56d374SYoshinobu Inoue  * Don't use this as a coding example.  I was trying to find a
2297d56d374SYoshinobu Inoue  * routing problem and this code sort-of popped out after 48 hours
2307d56d374SYoshinobu Inoue  * without sleep.  I was amazed it ever compiled, much less ran.
2317d56d374SYoshinobu Inoue  *
2327d56d374SYoshinobu Inoue  * I stole the idea for this program from Steve Deering.  Since
2337d56d374SYoshinobu Inoue  * the first release, I've learned that had I attended the right
2347d56d374SYoshinobu Inoue  * IETF working group meetings, I also could have stolen it from Guy
2357d56d374SYoshinobu Inoue  * Almes or Matt Mathis.  I don't know (or care) who came up with
2367d56d374SYoshinobu Inoue  * the idea first.  I envy the originators' perspicacity and I'm
2377d56d374SYoshinobu Inoue  * glad they didn't keep the idea a secret.
2387d56d374SYoshinobu Inoue  *
2397d56d374SYoshinobu Inoue  * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
2407d56d374SYoshinobu Inoue  * enhancements to the original distribution.
2417d56d374SYoshinobu Inoue  *
2427d56d374SYoshinobu Inoue  * I've hacked up a round-trip-route version of this that works by
2437d56d374SYoshinobu Inoue  * sending a loose-source-routed udp datagram through the destination
2447d56d374SYoshinobu Inoue  * back to yourself.  Unfortunately, SO many gateways botch source
2457d56d374SYoshinobu Inoue  * routing, the thing is almost worthless.  Maybe one day...
2467d56d374SYoshinobu Inoue  *
2477d56d374SYoshinobu Inoue  *  -- Van Jacobson (van@helios.ee.lbl.gov)
2487d56d374SYoshinobu Inoue  *     Tue Dec 20 03:50:13 PST 1988
2497d56d374SYoshinobu Inoue  */
2507d56d374SYoshinobu Inoue 
2517d56d374SYoshinobu Inoue #include <sys/param.h>
2527d56d374SYoshinobu Inoue #include <sys/time.h>
2537d56d374SYoshinobu Inoue #include <sys/socket.h>
2547d56d374SYoshinobu Inoue #include <sys/uio.h>
2557d56d374SYoshinobu Inoue #include <sys/file.h>
2567d56d374SYoshinobu Inoue #include <sys/ioctl.h>
25784a1a4cfSHajimu UMEMOTO #include <sys/sysctl.h>
2587d56d374SYoshinobu Inoue 
2597d56d374SYoshinobu Inoue #include <netinet/in.h>
2607d56d374SYoshinobu Inoue 
2617d56d374SYoshinobu Inoue #include <arpa/inet.h>
2627d56d374SYoshinobu Inoue 
2637d56d374SYoshinobu Inoue #include <netdb.h>
2647d56d374SYoshinobu Inoue #include <stdio.h>
2657d56d374SYoshinobu Inoue #include <err.h>
2662a1c5efaSKris Kennaway #ifdef HAVE_POLL
2672a1c5efaSKris Kennaway #include <poll.h>
2682a1c5efaSKris Kennaway #endif
2697d56d374SYoshinobu Inoue #include <errno.h>
2707d56d374SYoshinobu Inoue #include <stdlib.h>
2717d56d374SYoshinobu Inoue #include <string.h>
2727d56d374SYoshinobu Inoue #include <unistd.h>
2737d56d374SYoshinobu Inoue 
2747d56d374SYoshinobu Inoue #include <netinet/ip6.h>
2757d56d374SYoshinobu Inoue #include <netinet/icmp6.h>
2769d8b46c8SMichael Tuexen #include <netinet/sctp.h>
277*51eff8efSMichael Tuexen #include <netinet/sctp_header.h>
2789d8b46c8SMichael Tuexen #include <netinet/tcp.h>
2797d56d374SYoshinobu Inoue #include <netinet/udp.h>
2807d56d374SYoshinobu Inoue 
2817d56d374SYoshinobu Inoue #ifdef IPSEC
2827d56d374SYoshinobu Inoue #include <net/route.h>
2838409aedfSGeorge V. Neville-Neil #include <netipsec/ipsec.h>
2847d56d374SYoshinobu Inoue #endif
2857d56d374SYoshinobu Inoue 
286d429d720SHajimu UMEMOTO #include "as.h"
287d429d720SHajimu UMEMOTO 
2887d56d374SYoshinobu Inoue #define DUMMY_PORT 10010
2897d56d374SYoshinobu Inoue 
2907d56d374SYoshinobu Inoue #define	MAXPACKET	65535	/* max ip packet size */
2917d56d374SYoshinobu Inoue 
292de68a0daSKris Kennaway #ifndef HAVE_GETIPNODEBYNAME
293de68a0daSKris Kennaway #define getipnodebyname(x, y, z, u)	gethostbyname2((x), (y))
294de68a0daSKris Kennaway #define freehostent(x)
295de68a0daSKris Kennaway #endif
296de68a0daSKris Kennaway 
2977d56d374SYoshinobu Inoue u_char	packet[512];		/* last inbound (icmp) packet */
298aa96470cSMichael Tuexen char 	*outpacket;		/* last output packet */
2997d56d374SYoshinobu Inoue 
300784bddbcSKevin Lo int	main(int, char *[]);
301784bddbcSKevin Lo int	wait_for_reply(int, struct msghdr *);
302de68a0daSKris Kennaway #ifdef IPSEC
303de68a0daSKris Kennaway #ifdef IPSEC_POLICY_IPSEC
304784bddbcSKevin Lo int	setpolicy(int so, char *policy);
305de68a0daSKris Kennaway #endif
306de68a0daSKris Kennaway #endif
307784bddbcSKevin Lo void	send_probe(int, u_long);
308d7b63fafSDavid Malone void	*get_uphdr(struct ip6_hdr *, u_char *);
309784bddbcSKevin Lo int	get_hoplim(struct msghdr *);
310784bddbcSKevin Lo double	deltaT(struct timeval *, struct timeval *);
311f42640a3SUlrich Spörlein const char *pr_type(int);
312784bddbcSKevin Lo int	packet_ok(struct msghdr *, int, int);
313784bddbcSKevin Lo void	print(struct msghdr *, int);
314784bddbcSKevin Lo const char *inetname(struct sockaddr *);
3159d8b46c8SMichael Tuexen u_int32_t sctp_crc32c(void *, u_int32_t);
3169d8b46c8SMichael Tuexen u_int16_t in_cksum(u_int16_t *addr, int);
3179d8b46c8SMichael Tuexen u_int16_t tcp_chksum(struct sockaddr_in6 *, struct sockaddr_in6 *,
3189d8b46c8SMichael Tuexen     void *, u_int32_t);
319784bddbcSKevin Lo void	usage(void);
3207d56d374SYoshinobu Inoue 
3217d56d374SYoshinobu Inoue int rcvsock;			/* receive (icmp) socket file descriptor */
3229d8b46c8SMichael Tuexen int sndsock;			/* send (raw/udp) socket file descriptor */
3237d56d374SYoshinobu Inoue 
3247d56d374SYoshinobu Inoue struct msghdr rcvmhdr;
3257d56d374SYoshinobu Inoue struct iovec rcviov[2];
3267d56d374SYoshinobu Inoue int rcvhlim;
3277d56d374SYoshinobu Inoue struct in6_pktinfo *rcvpktinfo;
3287d56d374SYoshinobu Inoue 
3297d56d374SYoshinobu Inoue struct sockaddr_in6 Src, Dst, Rcv;
330aa96470cSMichael Tuexen u_long datalen = 20;			/* How much data */
33184a1a4cfSHajimu UMEMOTO #define	ICMP6ECHOLEN	8
332de68a0daSKris Kennaway /* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */
333de68a0daSKris Kennaway char rtbuf[2064];
334de68a0daSKris Kennaway #ifdef USE_RFC2292BIS
335de68a0daSKris Kennaway struct ip6_rthdr *rth;
336de68a0daSKris Kennaway #endif
3377d56d374SYoshinobu Inoue struct cmsghdr *cmsg;
3387d56d374SYoshinobu Inoue 
339ac97203fSPedro F. Giffuni char *source = NULL;
3407d56d374SYoshinobu Inoue char *hostname;
3417d56d374SYoshinobu Inoue 
34284a1a4cfSHajimu UMEMOTO u_long nprobes = 3;
34384a1a4cfSHajimu UMEMOTO u_long first_hop = 1;
34484a1a4cfSHajimu UMEMOTO u_long max_hops = 30;
34584a1a4cfSHajimu UMEMOTO u_int16_t srcport;
34684a1a4cfSHajimu UMEMOTO u_int16_t port = 32768+666;	/* start udp dest port # for probe packets */
34784a1a4cfSHajimu UMEMOTO u_int16_t ident;
3487d56d374SYoshinobu Inoue int options;			/* socket options */
3497d56d374SYoshinobu Inoue int verbose;
3507d56d374SYoshinobu Inoue int waittime = 5;		/* time to wait for response (in seconds) */
3517d56d374SYoshinobu Inoue int nflag;			/* print addresses numerically */
352d7b63fafSDavid Malone int useproto = IPPROTO_UDP;	/* protocol to use to send packet */
3537d56d374SYoshinobu Inoue int lflag;			/* print both numerical address & hostname */
354d429d720SHajimu UMEMOTO int as_path;			/* print as numbers for each hop */
355d429d720SHajimu UMEMOTO char *as_server = NULL;
356d429d720SHajimu UMEMOTO void *asn;
3577d56d374SYoshinobu Inoue 
3587d56d374SYoshinobu Inoue int
359aa96470cSMichael Tuexen main(int argc, char *argv[])
3607d56d374SYoshinobu Inoue {
36184a1a4cfSHajimu UMEMOTO 	int mib[4] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM };
362e961704aSDavid Malone 	char hbuf[NI_MAXHOST], src0[NI_MAXHOST], *ep;
363f42640a3SUlrich Spörlein 	int ch, i, on = 1, seq, rcvcmsglen, error;
364e961704aSDavid Malone 	struct addrinfo hints, *res;
365e961704aSDavid Malone 	static u_char *rcvcmsgbuf;
366e961704aSDavid Malone 	u_long probe, hops, lport;
367e961704aSDavid Malone 	struct hostent *hp;
368f42640a3SUlrich Spörlein 	size_t size, minlen;
36919c7ed84SKevin Lo 	uid_t uid;
3707d56d374SYoshinobu Inoue 
37153c9088fSYoshinobu Inoue 	/*
37253c9088fSYoshinobu Inoue 	 * Receive ICMP
37353c9088fSYoshinobu Inoue 	 */
37453c9088fSYoshinobu Inoue 	if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
375de68a0daSKris Kennaway 		perror("socket(ICMPv6)");
37653c9088fSYoshinobu Inoue 		exit(5);
37753c9088fSYoshinobu Inoue 	}
378de68a0daSKris Kennaway 
37984a1a4cfSHajimu UMEMOTO 	size = sizeof(i);
38084a1a4cfSHajimu UMEMOTO 	(void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &i, &size, NULL, 0);
38184a1a4cfSHajimu UMEMOTO 	max_hops = i;
38284a1a4cfSHajimu UMEMOTO 
383de68a0daSKris Kennaway 	/* specify to tell receiving interface */
384de68a0daSKris Kennaway #ifdef IPV6_RECVPKTINFO
385de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
386de68a0daSKris Kennaway 	    sizeof(on)) < 0)
387de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_RECVPKTINFO)");
388de68a0daSKris Kennaway #else  /* old adv. API */
389de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
390de68a0daSKris Kennaway 	    sizeof(on)) < 0)
391de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_PKTINFO)");
392de68a0daSKris Kennaway #endif
393de68a0daSKris Kennaway 
394de68a0daSKris Kennaway 	/* specify to tell value of hoplimit field of received IP6 hdr */
395de68a0daSKris Kennaway #ifdef IPV6_RECVHOPLIMIT
396de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
397de68a0daSKris Kennaway 	    sizeof(on)) < 0)
398de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_RECVHOPLIMIT)");
399de68a0daSKris Kennaway #else  /* old adv. API */
400de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
401de68a0daSKris Kennaway 	    sizeof(on)) < 0)
402de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_HOPLIMIT)");
403de68a0daSKris Kennaway #endif
404de68a0daSKris Kennaway 
4057d56d374SYoshinobu Inoue 	seq = 0;
4069d8b46c8SMichael Tuexen 	ident = htons(getpid() & 0xffff); /* same as ping6 */
4077d56d374SYoshinobu Inoue 
4089d8b46c8SMichael Tuexen 	while ((ch = getopt(argc, argv, "aA:df:g:Ilm:nNp:q:rs:STUvw:")) != -1)
4097d56d374SYoshinobu Inoue 		switch (ch) {
410d429d720SHajimu UMEMOTO 		case 'a':
411d429d720SHajimu UMEMOTO 			as_path = 1;
412d429d720SHajimu UMEMOTO 			break;
413d429d720SHajimu UMEMOTO 		case 'A':
414d429d720SHajimu UMEMOTO 			as_path = 1;
415d429d720SHajimu UMEMOTO 			as_server = optarg;
416d429d720SHajimu UMEMOTO 			break;
4177d56d374SYoshinobu Inoue 		case 'd':
4187d56d374SYoshinobu Inoue 			options |= SO_DEBUG;
4197d56d374SYoshinobu Inoue 			break;
420de68a0daSKris Kennaway 		case 'f':
42133841545SHajimu UMEMOTO 			ep = NULL;
42284a1a4cfSHajimu UMEMOTO 			errno = 0;
42333841545SHajimu UMEMOTO 			first_hop = strtoul(optarg, &ep, 0);
42484a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep || first_hop > 255) {
425c449e284SHajimu UMEMOTO 				fprintf(stderr,
42633841545SHajimu UMEMOTO 				    "traceroute6: invalid min hoplimit.\n");
42733841545SHajimu UMEMOTO 				exit(1);
42833841545SHajimu UMEMOTO 			}
4297d56d374SYoshinobu Inoue 			break;
4307d56d374SYoshinobu Inoue 		case 'g':
4317d56d374SYoshinobu Inoue 			hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno);
4327d56d374SYoshinobu Inoue 			if (hp == NULL) {
433c449e284SHajimu UMEMOTO 				fprintf(stderr,
4347d56d374SYoshinobu Inoue 				    "traceroute6: unknown host %s\n", optarg);
4357d56d374SYoshinobu Inoue 				exit(1);
4367d56d374SYoshinobu Inoue 			}
437de68a0daSKris Kennaway #ifdef USE_RFC2292BIS
438de68a0daSKris Kennaway 			if (rth == NULL) {
439de68a0daSKris Kennaway 				/*
440de68a0daSKris Kennaway 				 * XXX: We can't detect the number of
441de68a0daSKris Kennaway 				 * intermediate nodes yet.
442de68a0daSKris Kennaway 				 */
443de68a0daSKris Kennaway 				if ((rth = inet6_rth_init((void *)rtbuf,
444c449e284SHajimu UMEMOTO 				    sizeof(rtbuf), IPV6_RTHDR_TYPE_0,
445de68a0daSKris Kennaway 				    0)) == NULL) {
446c449e284SHajimu UMEMOTO 					fprintf(stderr,
447de68a0daSKris Kennaway 					    "inet6_rth_init failed.\n");
448de68a0daSKris Kennaway 					exit(1);
449de68a0daSKris Kennaway 				}
450de68a0daSKris Kennaway 			}
451de68a0daSKris Kennaway 			if (inet6_rth_add((void *)rth,
452de68a0daSKris Kennaway 			    (struct in6_addr *)hp->h_addr)) {
453c449e284SHajimu UMEMOTO 				fprintf(stderr,
454de68a0daSKris Kennaway 				    "inet6_rth_add failed for %s\n",
455de68a0daSKris Kennaway 				    optarg);
456de68a0daSKris Kennaway 				exit(1);
457de68a0daSKris Kennaway 			}
458de68a0daSKris Kennaway #else  /* old advanced API */
4597d56d374SYoshinobu Inoue 			if (cmsg == NULL)
4607d56d374SYoshinobu Inoue 				cmsg = inet6_rthdr_init(rtbuf, IPV6_RTHDR_TYPE_0);
461c449e284SHajimu UMEMOTO 			inet6_rthdr_add(cmsg, (struct in6_addr *)hp->h_addr,
462c449e284SHajimu UMEMOTO 			    IPV6_RTHDR_LOOSE);
463de68a0daSKris Kennaway #endif
464de68a0daSKris Kennaway 			freehostent(hp);
465de68a0daSKris Kennaway 			break;
46684a1a4cfSHajimu UMEMOTO 		case 'I':
467d7b63fafSDavid Malone 			useproto = IPPROTO_ICMPV6;
46884a1a4cfSHajimu UMEMOTO 			break;
469de68a0daSKris Kennaway 		case 'l':
470de68a0daSKris Kennaway 			lflag++;
4717d56d374SYoshinobu Inoue 			break;
4727d56d374SYoshinobu Inoue 		case 'm':
47333841545SHajimu UMEMOTO 			ep = NULL;
47484a1a4cfSHajimu UMEMOTO 			errno = 0;
47533841545SHajimu UMEMOTO 			max_hops = strtoul(optarg, &ep, 0);
47684a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep || max_hops > 255) {
477c449e284SHajimu UMEMOTO 				fprintf(stderr,
47833841545SHajimu UMEMOTO 				    "traceroute6: invalid max hoplimit.\n");
47933841545SHajimu UMEMOTO 				exit(1);
48033841545SHajimu UMEMOTO 			}
4817d56d374SYoshinobu Inoue 			break;
4827d56d374SYoshinobu Inoue 		case 'n':
4837d56d374SYoshinobu Inoue 			nflag++;
4847d56d374SYoshinobu Inoue 			break;
485d7b63fafSDavid Malone 		case 'N':
486d7b63fafSDavid Malone 			useproto = IPPROTO_NONE;
487d7b63fafSDavid Malone 			break;
4887d56d374SYoshinobu Inoue 		case 'p':
48933841545SHajimu UMEMOTO 			ep = NULL;
49084a1a4cfSHajimu UMEMOTO 			errno = 0;
49184a1a4cfSHajimu UMEMOTO 			lport = strtoul(optarg, &ep, 0);
49284a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep) {
49384a1a4cfSHajimu UMEMOTO 				fprintf(stderr, "traceroute6: invalid port.\n");
49433841545SHajimu UMEMOTO 				exit(1);
49533841545SHajimu UMEMOTO 			}
49684a1a4cfSHajimu UMEMOTO 			if (lport == 0 || lport != (lport & 0xffff)) {
497c449e284SHajimu UMEMOTO 				fprintf(stderr,
49884a1a4cfSHajimu UMEMOTO 				    "traceroute6: port out of range.\n");
4997d56d374SYoshinobu Inoue 				exit(1);
5007d56d374SYoshinobu Inoue 			}
50184a1a4cfSHajimu UMEMOTO 			port = lport & 0xffff;
5027d56d374SYoshinobu Inoue 			break;
5037d56d374SYoshinobu Inoue 		case 'q':
50433841545SHajimu UMEMOTO 			ep = NULL;
50584a1a4cfSHajimu UMEMOTO 			errno = 0;
50633841545SHajimu UMEMOTO 			nprobes = strtoul(optarg, &ep, 0);
50784a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep) {
508c449e284SHajimu UMEMOTO 				fprintf(stderr,
50933841545SHajimu UMEMOTO 				    "traceroute6: invalid nprobes.\n");
51033841545SHajimu UMEMOTO 				exit(1);
51133841545SHajimu UMEMOTO 			}
5127d56d374SYoshinobu Inoue 			if (nprobes < 1) {
513c449e284SHajimu UMEMOTO 				fprintf(stderr,
5147d56d374SYoshinobu Inoue 				    "traceroute6: nprobes must be >0.\n");
5157d56d374SYoshinobu Inoue 				exit(1);
5167d56d374SYoshinobu Inoue 			}
5177d56d374SYoshinobu Inoue 			break;
5187d56d374SYoshinobu Inoue 		case 'r':
5197d56d374SYoshinobu Inoue 			options |= SO_DONTROUTE;
5207d56d374SYoshinobu Inoue 			break;
5217d56d374SYoshinobu Inoue 		case 's':
5227d56d374SYoshinobu Inoue 			/*
5237d56d374SYoshinobu Inoue 			 * set the ip source address of the outbound
5247d56d374SYoshinobu Inoue 			 * probe (e.g., on a multi-homed host).
5257d56d374SYoshinobu Inoue 			 */
5267d56d374SYoshinobu Inoue 			source = optarg;
5277d56d374SYoshinobu Inoue 			break;
5289d8b46c8SMichael Tuexen 		case 'S':
5299d8b46c8SMichael Tuexen 			useproto = IPPROTO_SCTP;
5309d8b46c8SMichael Tuexen 			break;
5319d8b46c8SMichael Tuexen 		case 'T':
5329d8b46c8SMichael Tuexen 			useproto = IPPROTO_TCP;
5339d8b46c8SMichael Tuexen 			break;
534d7b63fafSDavid Malone 		case 'U':
535d7b63fafSDavid Malone 			useproto = IPPROTO_UDP;
536d7b63fafSDavid Malone 			break;
537aa96470cSMichael Tuexen 		case 'v':
538aa96470cSMichael Tuexen 			verbose++;
539aa96470cSMichael Tuexen 			break;
5407d56d374SYoshinobu Inoue 		case 'w':
54133841545SHajimu UMEMOTO 			ep = NULL;
54284a1a4cfSHajimu UMEMOTO 			errno = 0;
54333841545SHajimu UMEMOTO 			waittime = strtoul(optarg, &ep, 0);
54484a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep) {
545c449e284SHajimu UMEMOTO 				fprintf(stderr,
54633841545SHajimu UMEMOTO 				    "traceroute6: invalid wait time.\n");
54733841545SHajimu UMEMOTO 				exit(1);
54833841545SHajimu UMEMOTO 			}
549eea319c4SMaxim Konovalov 			if (waittime < 1) {
550c449e284SHajimu UMEMOTO 				fprintf(stderr,
551eea319c4SMaxim Konovalov 				    "traceroute6: wait must be >= 1 sec.\n");
5527d56d374SYoshinobu Inoue 				exit(1);
5537d56d374SYoshinobu Inoue 			}
5547d56d374SYoshinobu Inoue 			break;
5557d56d374SYoshinobu Inoue 		default:
5567d56d374SYoshinobu Inoue 			usage();
5577d56d374SYoshinobu Inoue 		}
5587d56d374SYoshinobu Inoue 	argc -= optind;
5597d56d374SYoshinobu Inoue 	argv += optind;
5607d56d374SYoshinobu Inoue 
561d7b63fafSDavid Malone 	/*
562d7b63fafSDavid Malone 	 * Open socket to send probe packets.
563d7b63fafSDavid Malone 	 */
564d7b63fafSDavid Malone 	switch (useproto) {
565d7b63fafSDavid Malone 	case IPPROTO_ICMPV6:
566d7b63fafSDavid Malone 		sndsock = rcvsock;
567d7b63fafSDavid Malone 		break;
568d7b63fafSDavid Malone 	case IPPROTO_UDP:
569d7b63fafSDavid Malone 		if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
570d7b63fafSDavid Malone 			perror("socket(SOCK_DGRAM)");
571d7b63fafSDavid Malone 			exit(5);
572d7b63fafSDavid Malone 		}
573d7b63fafSDavid Malone 		break;
574d7b63fafSDavid Malone 	case IPPROTO_NONE:
5759d8b46c8SMichael Tuexen 	case IPPROTO_SCTP:
5769d8b46c8SMichael Tuexen 	case IPPROTO_TCP:
5779d8b46c8SMichael Tuexen 		if ((sndsock = socket(AF_INET6, SOCK_RAW, useproto)) < 0) {
578d7b63fafSDavid Malone 			perror("socket(SOCK_RAW)");
579d7b63fafSDavid Malone 			exit(5);
580d7b63fafSDavid Malone 		}
581d7b63fafSDavid Malone 		break;
582d7b63fafSDavid Malone 	default:
583aa96470cSMichael Tuexen 		fprintf(stderr, "traceroute6: unknown probe protocol %d\n",
584d7b63fafSDavid Malone 		    useproto);
585d7b63fafSDavid Malone 		exit(5);
586d7b63fafSDavid Malone 	}
58784a1a4cfSHajimu UMEMOTO 	if (max_hops < first_hop) {
58884a1a4cfSHajimu UMEMOTO 		fprintf(stderr,
58984a1a4cfSHajimu UMEMOTO 		    "traceroute6: max hoplimit must be larger than first hoplimit.\n");
59084a1a4cfSHajimu UMEMOTO 		exit(1);
59184a1a4cfSHajimu UMEMOTO 	}
59284a1a4cfSHajimu UMEMOTO 
593d7b63fafSDavid Malone 	/* revoke privs */
594d7b63fafSDavid Malone 	uid = getuid();
595d7b63fafSDavid Malone 	if (setresuid(uid, uid, uid) == -1) {
596d7b63fafSDavid Malone 		perror("setresuid");
597d7b63fafSDavid Malone 		exit(1);
598d7b63fafSDavid Malone 	}
599d7b63fafSDavid Malone 
600d7b63fafSDavid Malone 
60133841545SHajimu UMEMOTO 	if (argc < 1 || argc > 2)
6027d56d374SYoshinobu Inoue 		usage();
6037d56d374SYoshinobu Inoue 
604de68a0daSKris Kennaway #if 1
6057d56d374SYoshinobu Inoue 	setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
606de68a0daSKris Kennaway #else
607de68a0daSKris Kennaway 	setlinebuf(stdout);
608de68a0daSKris Kennaway #endif
6097d56d374SYoshinobu Inoue 
61039865d64SYoshinobu Inoue 	memset(&hints, 0, sizeof(hints));
61139865d64SYoshinobu Inoue 	hints.ai_family = PF_INET6;
61239865d64SYoshinobu Inoue 	hints.ai_socktype = SOCK_RAW;
61339865d64SYoshinobu Inoue 	hints.ai_protocol = IPPROTO_ICMPV6;
61439865d64SYoshinobu Inoue 	hints.ai_flags = AI_CANONNAME;
61539865d64SYoshinobu Inoue 	error = getaddrinfo(*argv, NULL, &hints, &res);
61639865d64SYoshinobu Inoue 	if (error) {
617c449e284SHajimu UMEMOTO 		fprintf(stderr,
61839865d64SYoshinobu Inoue 		    "traceroute6: %s\n", gai_strerror(error));
6197d56d374SYoshinobu Inoue 		exit(1);
6207d56d374SYoshinobu Inoue 	}
621de68a0daSKris Kennaway 	if (res->ai_addrlen != sizeof(Dst)) {
622c449e284SHajimu UMEMOTO 		fprintf(stderr,
623de68a0daSKris Kennaway 		    "traceroute6: size of sockaddr mismatch\n");
624de68a0daSKris Kennaway 		exit(1);
625de68a0daSKris Kennaway 	}
62639865d64SYoshinobu Inoue 	memcpy(&Dst, res->ai_addr, res->ai_addrlen);
62739865d64SYoshinobu Inoue 	hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv;
62833841545SHajimu UMEMOTO 	if (!hostname) {
629c449e284SHajimu UMEMOTO 		fprintf(stderr, "traceroute6: not enough core\n");
63033841545SHajimu UMEMOTO 		exit(1);
63133841545SHajimu UMEMOTO 	}
63284a1a4cfSHajimu UMEMOTO 	if (res->ai_next) {
63384a1a4cfSHajimu UMEMOTO 		if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf,
63484a1a4cfSHajimu UMEMOTO 		    sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
63584a1a4cfSHajimu UMEMOTO 			strlcpy(hbuf, "?", sizeof(hbuf));
63684a1a4cfSHajimu UMEMOTO 		fprintf(stderr, "traceroute6: Warning: %s has multiple "
63784a1a4cfSHajimu UMEMOTO 		    "addresses; using %s\n", hostname, hbuf);
63884a1a4cfSHajimu UMEMOTO 	}
6397d56d374SYoshinobu Inoue 
64033841545SHajimu UMEMOTO 	if (*++argv) {
64133841545SHajimu UMEMOTO 		ep = NULL;
64284a1a4cfSHajimu UMEMOTO 		errno = 0;
64333841545SHajimu UMEMOTO 		datalen = strtoul(*argv, &ep, 0);
644aa96470cSMichael Tuexen 		if (errno || *ep) {
645c449e284SHajimu UMEMOTO 			fprintf(stderr,
64633841545SHajimu UMEMOTO 			    "traceroute6: invalid packet length.\n");
64733841545SHajimu UMEMOTO 			exit(1);
64833841545SHajimu UMEMOTO 		}
64933841545SHajimu UMEMOTO 	}
650d7b63fafSDavid Malone 	switch (useproto) {
651d7b63fafSDavid Malone 	case IPPROTO_ICMPV6:
652aa96470cSMichael Tuexen 		minlen = ICMP6ECHOLEN;
653d7b63fafSDavid Malone 		break;
654d7b63fafSDavid Malone 	case IPPROTO_UDP:
655aa96470cSMichael Tuexen 		minlen = sizeof(struct udphdr);
656d7b63fafSDavid Malone 		break;
657d7b63fafSDavid Malone 	case IPPROTO_NONE:
658d7b63fafSDavid Malone 		minlen = 0;
659d7b63fafSDavid Malone 		datalen = 0;
660d7b63fafSDavid Malone 		break;
6619d8b46c8SMichael Tuexen 	case IPPROTO_SCTP:
6629d8b46c8SMichael Tuexen 		minlen = sizeof(struct sctphdr);
6639d8b46c8SMichael Tuexen 		break;
6649d8b46c8SMichael Tuexen 	case IPPROTO_TCP:
6659d8b46c8SMichael Tuexen 		minlen = sizeof(struct tcphdr);
6669d8b46c8SMichael Tuexen 		break;
667d7b63fafSDavid Malone 	default:
668d7b63fafSDavid Malone 		fprintf(stderr, "traceroute6: unknown probe protocol %d.\n",
669d7b63fafSDavid Malone 		    useproto);
670d7b63fafSDavid Malone 		exit(1);
671d7b63fafSDavid Malone 	}
67284a1a4cfSHajimu UMEMOTO 	if (datalen < minlen)
67384a1a4cfSHajimu UMEMOTO 		datalen = minlen;
67484a1a4cfSHajimu UMEMOTO 	else if (datalen >= MAXPACKET) {
675c449e284SHajimu UMEMOTO 		fprintf(stderr,
676f42640a3SUlrich Spörlein 		    "traceroute6: packet size must be %zu <= s < %d.\n",
677f42640a3SUlrich Spörlein 		    minlen, MAXPACKET);
6787d56d374SYoshinobu Inoue 		exit(1);
6797d56d374SYoshinobu Inoue 	}
680aa96470cSMichael Tuexen 	if (useproto == IPPROTO_UDP)
681aa96470cSMichael Tuexen 		datalen -= sizeof(struct udphdr);
682*51eff8efSMichael Tuexen 	if ((useproto == IPPROTO_SCTP) && (datalen & 3)) {
683*51eff8efSMichael Tuexen 		fprintf(stderr,
684*51eff8efSMichael Tuexen 		    "traceroute6: packet size must be a multiple of 4.\n");
685*51eff8efSMichael Tuexen 		exit(1);
686*51eff8efSMichael Tuexen 	}
687f42640a3SUlrich Spörlein 	outpacket = malloc(datalen);
6887d56d374SYoshinobu Inoue 	if (!outpacket) {
689de68a0daSKris Kennaway 		perror("malloc");
6907d56d374SYoshinobu Inoue 		exit(1);
6917d56d374SYoshinobu Inoue 	}
6927d56d374SYoshinobu Inoue 	(void) bzero((char *)outpacket, datalen);
6937d56d374SYoshinobu Inoue 
6947d56d374SYoshinobu Inoue 	/* initialize msghdr for receiving packets */
6957d56d374SYoshinobu Inoue 	rcviov[0].iov_base = (caddr_t)packet;
6967d56d374SYoshinobu Inoue 	rcviov[0].iov_len = sizeof(packet);
697de68a0daSKris Kennaway 	rcvmhdr.msg_name = (caddr_t)&Rcv;
698de68a0daSKris Kennaway 	rcvmhdr.msg_namelen = sizeof(Rcv);
6997d56d374SYoshinobu Inoue 	rcvmhdr.msg_iov = rcviov;
7007d56d374SYoshinobu Inoue 	rcvmhdr.msg_iovlen = 1;
701e961704aSDavid Malone 	rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
702e961704aSDavid Malone 	    CMSG_SPACE(sizeof(int));
703de68a0daSKris Kennaway 	if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) {
704c449e284SHajimu UMEMOTO 		fprintf(stderr, "traceroute6: malloc failed\n");
705de68a0daSKris Kennaway 		exit(1);
706de68a0daSKris Kennaway 	}
7077d56d374SYoshinobu Inoue 	rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
708de68a0daSKris Kennaway 	rcvmhdr.msg_controllen = rcvcmsglen;
7097d56d374SYoshinobu Inoue 
7107d56d374SYoshinobu Inoue 	if (options & SO_DEBUG)
7117d56d374SYoshinobu Inoue 		(void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
7127d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
7137d56d374SYoshinobu Inoue 	if (options & SO_DONTROUTE)
7147d56d374SYoshinobu Inoue 		(void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
7157d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
7167d56d374SYoshinobu Inoue #ifdef IPSEC
7177d56d374SYoshinobu Inoue #ifdef IPSEC_POLICY_IPSEC
7187d56d374SYoshinobu Inoue 	/*
7197d56d374SYoshinobu Inoue 	 * do not raise error even if setsockopt fails, kernel may have ipsec
7207d56d374SYoshinobu Inoue 	 * turned off.
7217d56d374SYoshinobu Inoue 	 */
7227d56d374SYoshinobu Inoue 	if (setpolicy(rcvsock, "in bypass") < 0)
723d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
7247d56d374SYoshinobu Inoue 	if (setpolicy(rcvsock, "out bypass") < 0)
725d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
726de68a0daSKris Kennaway #else
727de68a0daSKris Kennaway     {
728de68a0daSKris Kennaway 	int level = IPSEC_LEVEL_NONE;
729de68a0daSKris Kennaway 
730de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
731de68a0daSKris Kennaway 	    sizeof(level));
732de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
733de68a0daSKris Kennaway 	    sizeof(level));
734de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL
735de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
736de68a0daSKris Kennaway 	    sizeof(level));
737de68a0daSKris Kennaway #else
738de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
739de68a0daSKris Kennaway 	    sizeof(level));
740de68a0daSKris Kennaway #endif
741de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL
742de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
743de68a0daSKris Kennaway 	    sizeof(level));
744de68a0daSKris Kennaway #endif
745de68a0daSKris Kennaway     }
7467d56d374SYoshinobu Inoue #endif /*IPSEC_POLICY_IPSEC*/
7477d56d374SYoshinobu Inoue #endif /*IPSEC*/
7487d56d374SYoshinobu Inoue 
749de68a0daSKris Kennaway #ifdef SO_SNDBUF
75084a1a4cfSHajimu UMEMOTO 	i = datalen;
751aa96470cSMichael Tuexen 	if (i == 0)
752aa96470cSMichael Tuexen 		i = 1;
75384a1a4cfSHajimu UMEMOTO 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&i,
754aa96470cSMichael Tuexen 	    sizeof(i)) < 0) {
755de68a0daSKris Kennaway 		perror("setsockopt(SO_SNDBUF)");
7567d56d374SYoshinobu Inoue 		exit(6);
7577d56d374SYoshinobu Inoue 	}
758de68a0daSKris Kennaway #endif /* SO_SNDBUF */
7597d56d374SYoshinobu Inoue 	if (options & SO_DEBUG)
7607d56d374SYoshinobu Inoue 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
7617d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
7627d56d374SYoshinobu Inoue 	if (options & SO_DONTROUTE)
7637d56d374SYoshinobu Inoue 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
7647d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
765de68a0daSKris Kennaway #ifdef USE_RFC2292BIS
766de68a0daSKris Kennaway 	if (rth) {/* XXX: there is no library to finalize the header... */
767de68a0daSKris Kennaway 		rth->ip6r_len = rth->ip6r_segleft * 2;
768de68a0daSKris Kennaway 		if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR,
769de68a0daSKris Kennaway 		    (void *)rth, (rth->ip6r_len + 1) << 3)) {
770c449e284SHajimu UMEMOTO 			fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n",
771de68a0daSKris Kennaway 			    strerror(errno));
772de68a0daSKris Kennaway 			exit(1);
773de68a0daSKris Kennaway 		}
774de68a0daSKris Kennaway 	}
775de68a0daSKris Kennaway #else  /* old advanced API */
7767d56d374SYoshinobu Inoue 	if (cmsg != NULL) {
7777d56d374SYoshinobu Inoue 		inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
778de68a0daSKris Kennaway 		if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_PKTOPTIONS,
779de68a0daSKris Kennaway 		    rtbuf, cmsg->cmsg_len) < 0) {
780c449e284SHajimu UMEMOTO 			fprintf(stderr, "setsockopt(IPV6_PKTOPTIONS): %s\n",
781de68a0daSKris Kennaway 			    strerror(errno));
782de68a0daSKris Kennaway 			exit(1);
7837d56d374SYoshinobu Inoue 		}
784de68a0daSKris Kennaway 	}
785de68a0daSKris Kennaway #endif /* USE_RFC2292BIS */
7867d56d374SYoshinobu Inoue #ifdef IPSEC
7877d56d374SYoshinobu Inoue #ifdef IPSEC_POLICY_IPSEC
7887d56d374SYoshinobu Inoue 	/*
7897d56d374SYoshinobu Inoue 	 * do not raise error even if setsockopt fails, kernel may have ipsec
7907d56d374SYoshinobu Inoue 	 * turned off.
7917d56d374SYoshinobu Inoue 	 */
7927d56d374SYoshinobu Inoue 	if (setpolicy(sndsock, "in bypass") < 0)
793d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
7947d56d374SYoshinobu Inoue 	if (setpolicy(sndsock, "out bypass") < 0)
795d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
796de68a0daSKris Kennaway #else
797de68a0daSKris Kennaway     {
798de68a0daSKris Kennaway 	int level = IPSEC_LEVEL_BYPASS;
799de68a0daSKris Kennaway 
800de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
801de68a0daSKris Kennaway 	    sizeof(level));
802de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
803de68a0daSKris Kennaway 	    sizeof(level));
804de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL
805de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
806de68a0daSKris Kennaway 	    sizeof(level));
807de68a0daSKris Kennaway #else
808de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
809de68a0daSKris Kennaway 	    sizeof(level));
810de68a0daSKris Kennaway #endif
811de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL
812de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
813de68a0daSKris Kennaway 	    sizeof(level));
814de68a0daSKris Kennaway #endif
815de68a0daSKris Kennaway     }
8167d56d374SYoshinobu Inoue #endif /*IPSEC_POLICY_IPSEC*/
8177d56d374SYoshinobu Inoue #endif /*IPSEC*/
8187d56d374SYoshinobu Inoue 
8197d56d374SYoshinobu Inoue 	/*
8207d56d374SYoshinobu Inoue 	 * Source selection
8217d56d374SYoshinobu Inoue 	 */
822de68a0daSKris Kennaway 	bzero(&Src, sizeof(Src));
8237d56d374SYoshinobu Inoue 	if (source) {
824de68a0daSKris Kennaway 		struct addrinfo hints, *res;
825de68a0daSKris Kennaway 		int error;
826de68a0daSKris Kennaway 
827de68a0daSKris Kennaway 		memset(&hints, 0, sizeof(hints));
828de68a0daSKris Kennaway 		hints.ai_family = AF_INET6;
829de68a0daSKris Kennaway 		hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
830de68a0daSKris Kennaway 		hints.ai_flags = AI_NUMERICHOST;
831de68a0daSKris Kennaway 		error = getaddrinfo(source, "0", &hints, &res);
832de68a0daSKris Kennaway 		if (error) {
833c449e284SHajimu UMEMOTO 			printf("traceroute6: %s: %s\n", source,
834de68a0daSKris Kennaway 			    gai_strerror(error));
8357d56d374SYoshinobu Inoue 			exit(1);
8367d56d374SYoshinobu Inoue 		}
837de68a0daSKris Kennaway 		if (res->ai_addrlen > sizeof(Src)) {
838c449e284SHajimu UMEMOTO 			printf("traceroute6: %s: %s\n", source,
839de68a0daSKris Kennaway 			    gai_strerror(error));
840de68a0daSKris Kennaway 			exit(1);
841de68a0daSKris Kennaway 		}
842de68a0daSKris Kennaway 		memcpy(&Src, res->ai_addr, res->ai_addrlen);
843de68a0daSKris Kennaway 		freeaddrinfo(res);
8447d56d374SYoshinobu Inoue 	} else {
8457d56d374SYoshinobu Inoue 		struct sockaddr_in6 Nxt;
84684a1a4cfSHajimu UMEMOTO 		int dummy;
84784a1a4cfSHajimu UMEMOTO 		socklen_t len;
8487d56d374SYoshinobu Inoue 
8497d56d374SYoshinobu Inoue 		Nxt = Dst;
8507d56d374SYoshinobu Inoue 		Nxt.sin6_port = htons(DUMMY_PORT);
8517d56d374SYoshinobu Inoue 		if (cmsg != NULL)
8527d56d374SYoshinobu Inoue 			bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr,
8537d56d374SYoshinobu Inoue 			    sizeof(Nxt.sin6_addr));
8547d56d374SYoshinobu Inoue 		if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
8557d56d374SYoshinobu Inoue 			perror("socket");
856de68a0daSKris Kennaway 			exit(1);
8577d56d374SYoshinobu Inoue 		}
858de68a0daSKris Kennaway 		if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) {
8597d56d374SYoshinobu Inoue 			perror("connect");
860de68a0daSKris Kennaway 			exit(1);
8617d56d374SYoshinobu Inoue 		}
862de68a0daSKris Kennaway 		len = sizeof(Src);
863de68a0daSKris Kennaway 		if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) {
864de68a0daSKris Kennaway 			perror("getsockname");
865de68a0daSKris Kennaway 			exit(1);
866de68a0daSKris Kennaway 		}
867de68a0daSKris Kennaway 		if (getnameinfo((struct sockaddr *)&Src, Src.sin6_len,
868d24cb249SHajimu UMEMOTO 		    src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) {
869c449e284SHajimu UMEMOTO 			fprintf(stderr, "getnameinfo failed for source\n");
870de68a0daSKris Kennaway 			exit(1);
871de68a0daSKris Kennaway 		}
872de68a0daSKris Kennaway 		source = src0;
8737d56d374SYoshinobu Inoue 		close(dummy);
8747d56d374SYoshinobu Inoue 	}
875de68a0daSKris Kennaway 
87684a1a4cfSHajimu UMEMOTO 	Src.sin6_port = htons(0);
877de68a0daSKris Kennaway 	if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) {
878de68a0daSKris Kennaway 		perror("bind");
8797d56d374SYoshinobu Inoue 		exit(1);
8807d56d374SYoshinobu Inoue 	}
8817d56d374SYoshinobu Inoue 
88284a1a4cfSHajimu UMEMOTO 	{
883c449e284SHajimu UMEMOTO 		socklen_t len;
884de68a0daSKris Kennaway 
885de68a0daSKris Kennaway 		len = sizeof(Src);
88684a1a4cfSHajimu UMEMOTO 		if (getsockname(sndsock, (struct sockaddr *)&Src, &len) < 0) {
887de68a0daSKris Kennaway 			perror("getsockname");
888de68a0daSKris Kennaway 			exit(1);
889de68a0daSKris Kennaway 		}
89084a1a4cfSHajimu UMEMOTO 		srcport = ntohs(Src.sin6_port);
891de68a0daSKris Kennaway 	}
892de68a0daSKris Kennaway 
893d429d720SHajimu UMEMOTO 	if (as_path) {
894d429d720SHajimu UMEMOTO 		asn = as_setup(as_server);
895d429d720SHajimu UMEMOTO 		if (asn == NULL) {
896d429d720SHajimu UMEMOTO 			fprintf(stderr,
897d429d720SHajimu UMEMOTO 			    "traceroute6: as_setup failed, AS# lookups"
898d429d720SHajimu UMEMOTO 			    " disabled\n");
899d429d720SHajimu UMEMOTO 			(void)fflush(stderr);
900d429d720SHajimu UMEMOTO 			as_path = 0;
901d429d720SHajimu UMEMOTO 		}
902d429d720SHajimu UMEMOTO 	}
903d429d720SHajimu UMEMOTO 
9047d56d374SYoshinobu Inoue 	/*
9057d56d374SYoshinobu Inoue 	 * Message to users
9067d56d374SYoshinobu Inoue 	 */
907de68a0daSKris Kennaway 	if (getnameinfo((struct sockaddr *)&Dst, Dst.sin6_len, hbuf,
908d24cb249SHajimu UMEMOTO 	    sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
90933841545SHajimu UMEMOTO 		strlcpy(hbuf, "(invalid)", sizeof(hbuf));
910c449e284SHajimu UMEMOTO 	fprintf(stderr, "traceroute6");
911c449e284SHajimu UMEMOTO 	fprintf(stderr, " to %s (%s)", hostname, hbuf);
9127d56d374SYoshinobu Inoue 	if (source)
913c449e284SHajimu UMEMOTO 		fprintf(stderr, " from %s", source);
91484a1a4cfSHajimu UMEMOTO 	fprintf(stderr, ", %lu hops max, %lu byte packets\n",
915d55fae02SMichael Tuexen 	    max_hops,
916d55fae02SMichael Tuexen 	    datalen + ((useproto == IPPROTO_UDP) ? sizeof(struct udphdr) : 0));
9177d56d374SYoshinobu Inoue 	(void) fflush(stderr);
9187d56d374SYoshinobu Inoue 
919de68a0daSKris Kennaway 	if (first_hop > 1)
92084a1a4cfSHajimu UMEMOTO 		printf("Skipping %lu intermediate hops\n", first_hop - 1);
921de68a0daSKris Kennaway 
9227d56d374SYoshinobu Inoue 	/*
9237d56d374SYoshinobu Inoue 	 * Main loop
9247d56d374SYoshinobu Inoue 	 */
925de68a0daSKris Kennaway 	for (hops = first_hop; hops <= max_hops; ++hops) {
9267d56d374SYoshinobu Inoue 		struct in6_addr lastaddr;
9277d56d374SYoshinobu Inoue 		int got_there = 0;
928f42640a3SUlrich Spörlein 		unsigned unreachable = 0;
9297d56d374SYoshinobu Inoue 
93084a1a4cfSHajimu UMEMOTO 		printf("%2lu ", hops);
9317d56d374SYoshinobu Inoue 		bzero(&lastaddr, sizeof(lastaddr));
9327d56d374SYoshinobu Inoue 		for (probe = 0; probe < nprobes; ++probe) {
9337d56d374SYoshinobu Inoue 			int cc;
9347d56d374SYoshinobu Inoue 			struct timeval t1, t2;
9357d56d374SYoshinobu Inoue 
93684a1a4cfSHajimu UMEMOTO 			(void) gettimeofday(&t1, NULL);
9377d56d374SYoshinobu Inoue 			send_probe(++seq, hops);
9387d56d374SYoshinobu Inoue 			while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) {
93984a1a4cfSHajimu UMEMOTO 				(void) gettimeofday(&t2, NULL);
9407d56d374SYoshinobu Inoue 				if ((i = packet_ok(&rcvmhdr, cc, seq))) {
9417d56d374SYoshinobu Inoue 					if (!IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr,
9427d56d374SYoshinobu Inoue 					    &lastaddr)) {
94359876f93SChristian S.J. Peron 						if (probe > 0)
94459876f93SChristian S.J. Peron 							fputs("\n   ", stdout);
9457d56d374SYoshinobu Inoue 						print(&rcvmhdr, cc);
9467d56d374SYoshinobu Inoue 						lastaddr = Rcv.sin6_addr;
9477d56d374SYoshinobu Inoue 					}
948c449e284SHajimu UMEMOTO 					printf("  %.3f ms", deltaT(&t1, &t2));
9497d56d374SYoshinobu Inoue 					switch (i - 1) {
9507d56d374SYoshinobu Inoue 					case ICMP6_DST_UNREACH_NOROUTE:
9517d56d374SYoshinobu Inoue 						++unreachable;
952c449e284SHajimu UMEMOTO 						printf(" !N");
9537d56d374SYoshinobu Inoue 						break;
9547d56d374SYoshinobu Inoue 					case ICMP6_DST_UNREACH_ADMIN:
9557d56d374SYoshinobu Inoue 						++unreachable;
956c449e284SHajimu UMEMOTO 						printf(" !P");
9577d56d374SYoshinobu Inoue 						break;
9587d56d374SYoshinobu Inoue 					case ICMP6_DST_UNREACH_NOTNEIGHBOR:
9597d56d374SYoshinobu Inoue 						++unreachable;
960c449e284SHajimu UMEMOTO 						printf(" !S");
9617d56d374SYoshinobu Inoue 						break;
9627d56d374SYoshinobu Inoue 					case ICMP6_DST_UNREACH_ADDR:
9637d56d374SYoshinobu Inoue 						++unreachable;
964c449e284SHajimu UMEMOTO 						printf(" !A");
9657d56d374SYoshinobu Inoue 						break;
9667d56d374SYoshinobu Inoue 					case ICMP6_DST_UNREACH_NOPORT:
9677d56d374SYoshinobu Inoue 						if (rcvhlim >= 0 &&
9687d56d374SYoshinobu Inoue 						    rcvhlim <= 1)
969c449e284SHajimu UMEMOTO 							printf(" !");
9707d56d374SYoshinobu Inoue 						++got_there;
9717d56d374SYoshinobu Inoue 						break;
9727d56d374SYoshinobu Inoue 					}
9737d56d374SYoshinobu Inoue 					break;
974161ab37dSHiroki Sato 				} else if (deltaT(&t1, &t2) > waittime * 1000) {
975161ab37dSHiroki Sato 					cc = 0;
976161ab37dSHiroki Sato 					break;
9777d56d374SYoshinobu Inoue 				}
9787d56d374SYoshinobu Inoue 			}
9797d56d374SYoshinobu Inoue 			if (cc == 0)
980c449e284SHajimu UMEMOTO 				printf(" *");
9817d56d374SYoshinobu Inoue 			(void) fflush(stdout);
9827d56d374SYoshinobu Inoue 		}
9837d56d374SYoshinobu Inoue 		putchar('\n');
9847d56d374SYoshinobu Inoue 		if (got_there ||
9857d56d374SYoshinobu Inoue 		    (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) {
9867d56d374SYoshinobu Inoue 			exit(0);
9877d56d374SYoshinobu Inoue 		}
9887d56d374SYoshinobu Inoue 	}
989d429d720SHajimu UMEMOTO 	if (as_path)
990d429d720SHajimu UMEMOTO 		as_shutdown(asn);
9917d56d374SYoshinobu Inoue 
9927d56d374SYoshinobu Inoue 	exit(0);
9937d56d374SYoshinobu Inoue }
9947d56d374SYoshinobu Inoue 
9957d56d374SYoshinobu Inoue int
996aa96470cSMichael Tuexen wait_for_reply(int sock, struct msghdr *mhdr)
9977d56d374SYoshinobu Inoue {
9982a1c5efaSKris Kennaway #ifdef HAVE_POLL
9992a1c5efaSKris Kennaway 	struct pollfd pfd[1];
10007d56d374SYoshinobu Inoue 	int cc = 0;
10017d56d374SYoshinobu Inoue 
10022a1c5efaSKris Kennaway 	pfd[0].fd = sock;
10032a1c5efaSKris Kennaway 	pfd[0].events = POLLIN;
10042a1c5efaSKris Kennaway 	pfd[0].revents = 0;
10057d56d374SYoshinobu Inoue 
10062a1c5efaSKris Kennaway 	if (poll(pfd, 1, waittime * 1000) > 0)
10077d56d374SYoshinobu Inoue 		cc = recvmsg(rcvsock, mhdr, 0);
10087d56d374SYoshinobu Inoue 
10097d56d374SYoshinobu Inoue 	return(cc);
10102a1c5efaSKris Kennaway #else
10112a1c5efaSKris Kennaway 	fd_set *fdsp;
10122a1c5efaSKris Kennaway 	struct timeval wait;
10132a1c5efaSKris Kennaway 	int cc = 0, fdsn;
10142a1c5efaSKris Kennaway 
10152a1c5efaSKris Kennaway 	fdsn = howmany(sock + 1, NFDBITS) * sizeof(fd_mask);
10162a1c5efaSKris Kennaway 	if ((fdsp = (fd_set *)malloc(fdsn)) == NULL)
10172a1c5efaSKris Kennaway 		err(1, "malloc");
10182a1c5efaSKris Kennaway 	memset(fdsp, 0, fdsn);
10192a1c5efaSKris Kennaway 	FD_SET(sock, fdsp);
10202a1c5efaSKris Kennaway 	wait.tv_sec = waittime; wait.tv_usec = 0;
10212a1c5efaSKris Kennaway 
10222a1c5efaSKris Kennaway 	if (select(sock+1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0)
10232a1c5efaSKris Kennaway 		cc = recvmsg(rcvsock, mhdr, 0);
10242a1c5efaSKris Kennaway 
10252a1c5efaSKris Kennaway 	free(fdsp);
10262a1c5efaSKris Kennaway 	return(cc);
10272a1c5efaSKris Kennaway #endif
10287d56d374SYoshinobu Inoue }
10297d56d374SYoshinobu Inoue 
10307d56d374SYoshinobu Inoue #ifdef IPSEC
10317d56d374SYoshinobu Inoue #ifdef IPSEC_POLICY_IPSEC
10327d56d374SYoshinobu Inoue int
10337d56d374SYoshinobu Inoue setpolicy(so, policy)
10347d56d374SYoshinobu Inoue 	int so;
10357d56d374SYoshinobu Inoue 	char *policy;
10367d56d374SYoshinobu Inoue {
10377d56d374SYoshinobu Inoue 	char *buf;
10387d56d374SYoshinobu Inoue 
10397d56d374SYoshinobu Inoue 	buf = ipsec_set_policy(policy, strlen(policy));
10407d56d374SYoshinobu Inoue 	if (buf == NULL) {
1041de68a0daSKris Kennaway 		warnx("%s", ipsec_strerror());
10427d56d374SYoshinobu Inoue 		return -1;
10437d56d374SYoshinobu Inoue 	}
10447d56d374SYoshinobu Inoue 	(void)setsockopt(so, IPPROTO_IPV6, IPV6_IPSEC_POLICY,
10457d56d374SYoshinobu Inoue 	    buf, ipsec_get_policylen(buf));
10467d56d374SYoshinobu Inoue 
10477d56d374SYoshinobu Inoue 	free(buf);
10487d56d374SYoshinobu Inoue 
10497d56d374SYoshinobu Inoue 	return 0;
10507d56d374SYoshinobu Inoue }
10517d56d374SYoshinobu Inoue #endif
10527d56d374SYoshinobu Inoue #endif
10537d56d374SYoshinobu Inoue 
10547d56d374SYoshinobu Inoue void
1055aa96470cSMichael Tuexen send_probe(int seq, u_long hops)
10567d56d374SYoshinobu Inoue {
1057d7b63fafSDavid Malone 	struct icmp6_hdr *icp;
10589d8b46c8SMichael Tuexen 	struct sctphdr *sctp;
10599d8b46c8SMichael Tuexen 	struct sctp_chunkhdr *chk;
1060*51eff8efSMichael Tuexen 	struct sctp_init_chunk *init;
1061*51eff8efSMichael Tuexen 	struct sctp_paramhdr *param;
10629d8b46c8SMichael Tuexen 	struct tcphdr *tcp;
10637d56d374SYoshinobu Inoue 	int i;
10647d56d374SYoshinobu Inoue 
106584a1a4cfSHajimu UMEMOTO 	i = hops;
10667d56d374SYoshinobu Inoue 	if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
106784a1a4cfSHajimu UMEMOTO 	    (char *)&i, sizeof(i)) < 0) {
10687d56d374SYoshinobu Inoue 		perror("setsockopt IPV6_UNICAST_HOPS");
10697d56d374SYoshinobu Inoue 	}
10707d56d374SYoshinobu Inoue 
10717d56d374SYoshinobu Inoue 	Dst.sin6_port = htons(port + seq);
10727d56d374SYoshinobu Inoue 
1073d7b63fafSDavid Malone 	switch (useproto) {
1074d7b63fafSDavid Malone 	case IPPROTO_ICMPV6:
1075d7b63fafSDavid Malone 		icp = (struct icmp6_hdr *)outpacket;
107684a1a4cfSHajimu UMEMOTO 
107784a1a4cfSHajimu UMEMOTO 		icp->icmp6_type = ICMP6_ECHO_REQUEST;
107884a1a4cfSHajimu UMEMOTO 		icp->icmp6_code = 0;
107984a1a4cfSHajimu UMEMOTO 		icp->icmp6_cksum = 0;
108084a1a4cfSHajimu UMEMOTO 		icp->icmp6_id = ident;
108184a1a4cfSHajimu UMEMOTO 		icp->icmp6_seq = htons(seq);
1082d7b63fafSDavid Malone 		break;
1083d7b63fafSDavid Malone 	case IPPROTO_UDP:
1084d7b63fafSDavid Malone 		break;
1085d7b63fafSDavid Malone 	case IPPROTO_NONE:
1086d7b63fafSDavid Malone 		/* No space for anything. No harm as seq/tv32 are decorative. */
1087d7b63fafSDavid Malone 		break;
10889d8b46c8SMichael Tuexen 	case IPPROTO_SCTP:
10899d8b46c8SMichael Tuexen 		sctp = (struct sctphdr *)outpacket;
10909d8b46c8SMichael Tuexen 
10919d8b46c8SMichael Tuexen 		sctp->src_port = htons(ident);
10929d8b46c8SMichael Tuexen 		sctp->dest_port = htons(port + seq);
1093*51eff8efSMichael Tuexen 		if (datalen >= (u_long)(sizeof(struct sctphdr) +
1094*51eff8efSMichael Tuexen 		    sizeof(struct sctp_init_chunk))) {
1095*51eff8efSMichael Tuexen 			sctp->v_tag = 0;
1096*51eff8efSMichael Tuexen 		} else {
10979d8b46c8SMichael Tuexen 			sctp->v_tag = (sctp->src_port << 16) | sctp->dest_port;
1098*51eff8efSMichael Tuexen 		}
10999d8b46c8SMichael Tuexen 		sctp->checksum = htonl(0);
11009d8b46c8SMichael Tuexen 		if (datalen >= (u_long)(sizeof(struct sctphdr) +
1101*51eff8efSMichael Tuexen 		    sizeof(struct sctp_init_chunk))) {
1102*51eff8efSMichael Tuexen 			/*
1103*51eff8efSMichael Tuexen 			 * Send a packet containing an INIT chunk. This works
1104*51eff8efSMichael Tuexen 			 * better in case of firewalls on the path, but
1105*51eff8efSMichael Tuexen 			 * results in a probe packet containing at least
1106*51eff8efSMichael Tuexen 			 * 32 bytes of payload. For shorter payloads, use
1107*51eff8efSMichael Tuexen 			 * SHUTDOWN-ACK chunks.
1108*51eff8efSMichael Tuexen 			 */
1109*51eff8efSMichael Tuexen 			init = (struct sctp_init_chunk *)(sctp + 1);
1110*51eff8efSMichael Tuexen 			init->ch.chunk_type = SCTP_INITIATION;
1111*51eff8efSMichael Tuexen 			init->ch.chunk_flags = 0;
1112*51eff8efSMichael Tuexen 			init->ch.chunk_length = htons((u_int16_t)(datalen -
1113*51eff8efSMichael Tuexen 			    sizeof(struct sctphdr)));
1114*51eff8efSMichael Tuexen 			init->init.initiate_tag = (sctp->src_port << 16) |
1115*51eff8efSMichael Tuexen 			    sctp->dest_port;
1116*51eff8efSMichael Tuexen 			init->init.a_rwnd = htonl(1500);
1117*51eff8efSMichael Tuexen 			init->init.num_outbound_streams = htons(1);
1118*51eff8efSMichael Tuexen 			init->init.num_inbound_streams = htons(1);
1119*51eff8efSMichael Tuexen 			init->init.initial_tsn = htonl(0);
1120*51eff8efSMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
1121*51eff8efSMichael Tuexen 			    sizeof(struct sctp_init_chunk) +
1122*51eff8efSMichael Tuexen 			    sizeof(struct sctp_paramhdr))) {
1123*51eff8efSMichael Tuexen 				param = (struct sctp_paramhdr *)(init + 1);
1124*51eff8efSMichael Tuexen 				param->param_type = htons(SCTP_PAD);
1125*51eff8efSMichael Tuexen 				param->param_length =
1126*51eff8efSMichael Tuexen 				    htons((u_int16_t)(datalen -
1127*51eff8efSMichael Tuexen 				    sizeof(struct sctphdr) -
1128*51eff8efSMichael Tuexen 				    sizeof(struct sctp_init_chunk)));
1129*51eff8efSMichael Tuexen 			}
1130*51eff8efSMichael Tuexen 		} else {
1131*51eff8efSMichael Tuexen 			/*
1132*51eff8efSMichael Tuexen 			 * Send a packet containing a SHUTDOWN-ACK chunk,
1133*51eff8efSMichael Tuexen 			 * possibly followed by a PAD chunk.
1134*51eff8efSMichael Tuexen 			 */
1135*51eff8efSMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
11369d8b46c8SMichael Tuexen 			    sizeof(struct sctp_chunkhdr))) {
11379d8b46c8SMichael Tuexen 				chk = (struct sctp_chunkhdr *)(sctp + 1);
11389d8b46c8SMichael Tuexen 				chk->chunk_type = SCTP_SHUTDOWN_ACK;
11399d8b46c8SMichael Tuexen 				chk->chunk_flags = 0;
11409d8b46c8SMichael Tuexen 				chk->chunk_length = htons(4);
11419d8b46c8SMichael Tuexen 			}
11429d8b46c8SMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
11439d8b46c8SMichael Tuexen 			    2 * sizeof(struct sctp_chunkhdr))) {
11449d8b46c8SMichael Tuexen 				chk = chk + 1;
11459d8b46c8SMichael Tuexen 				chk->chunk_type = SCTP_PAD_CHUNK;
11469d8b46c8SMichael Tuexen 				chk->chunk_flags = 0;
11479d8b46c8SMichael Tuexen 				chk->chunk_length = htons((u_int16_t)(datalen -
11489d8b46c8SMichael Tuexen 				    sizeof(struct sctphdr) -
11499d8b46c8SMichael Tuexen 				    sizeof(struct sctp_chunkhdr)));
11509d8b46c8SMichael Tuexen 			}
1151*51eff8efSMichael Tuexen 		}
11529d8b46c8SMichael Tuexen 		sctp->checksum = sctp_crc32c(outpacket, datalen);
11539d8b46c8SMichael Tuexen 		break;
11549d8b46c8SMichael Tuexen 	case IPPROTO_TCP:
11559d8b46c8SMichael Tuexen 		tcp = (struct tcphdr *)outpacket;
11569d8b46c8SMichael Tuexen 
11579d8b46c8SMichael Tuexen 		tcp->th_sport = htons(ident);
11589d8b46c8SMichael Tuexen 		tcp->th_dport = htons(port + seq);
11599d8b46c8SMichael Tuexen 		tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport;
11609d8b46c8SMichael Tuexen 		tcp->th_ack = 0;
11619d8b46c8SMichael Tuexen 		tcp->th_off = 5;
11629d8b46c8SMichael Tuexen 		tcp->th_flags = TH_SYN;
11639d8b46c8SMichael Tuexen 		tcp->th_sum = 0;
11649d8b46c8SMichael Tuexen 		tcp->th_sum = tcp_chksum(&Src, &Dst, outpacket, datalen);
11659d8b46c8SMichael Tuexen 		break;
1166d7b63fafSDavid Malone 	default:
1167d7b63fafSDavid Malone 		fprintf(stderr, "Unknown probe protocol %d.\n", useproto);
1168d7b63fafSDavid Malone 		exit(1);
116984a1a4cfSHajimu UMEMOTO 	}
11707d56d374SYoshinobu Inoue 
11717d56d374SYoshinobu Inoue 	i = sendto(sndsock, (char *)outpacket, datalen, 0,
1172de68a0daSKris Kennaway 	    (struct sockaddr *)&Dst, Dst.sin6_len);
1173f42640a3SUlrich Spörlein 	if (i < 0 || (u_long)i != datalen)  {
11747d56d374SYoshinobu Inoue 		if (i < 0)
11757d56d374SYoshinobu Inoue 			perror("sendto");
117684a1a4cfSHajimu UMEMOTO 		printf("traceroute6: wrote %s %lu chars, ret=%d\n",
1177c449e284SHajimu UMEMOTO 		    hostname, datalen, i);
11787d56d374SYoshinobu Inoue 		(void) fflush(stdout);
11797d56d374SYoshinobu Inoue 	}
11807d56d374SYoshinobu Inoue }
11817d56d374SYoshinobu Inoue 
11827d56d374SYoshinobu Inoue int
1183aa96470cSMichael Tuexen get_hoplim(struct msghdr *mhdr)
11847d56d374SYoshinobu Inoue {
11857d56d374SYoshinobu Inoue 	struct cmsghdr *cm;
11867d56d374SYoshinobu Inoue 
11877d56d374SYoshinobu Inoue 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
11887d56d374SYoshinobu Inoue 	    cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
11897d56d374SYoshinobu Inoue 		if (cm->cmsg_level == IPPROTO_IPV6 &&
11907d56d374SYoshinobu Inoue 		    cm->cmsg_type == IPV6_HOPLIMIT &&
11917d56d374SYoshinobu Inoue 		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
11927d56d374SYoshinobu Inoue 			return(*(int *)CMSG_DATA(cm));
11937d56d374SYoshinobu Inoue 	}
11947d56d374SYoshinobu Inoue 
11957d56d374SYoshinobu Inoue 	return(-1);
11967d56d374SYoshinobu Inoue }
11977d56d374SYoshinobu Inoue 
11987d56d374SYoshinobu Inoue double
1199aa96470cSMichael Tuexen deltaT(struct timeval *t1p, struct timeval *t2p)
12007d56d374SYoshinobu Inoue {
1201e961704aSDavid Malone 	double dt;
12027d56d374SYoshinobu Inoue 
12037d56d374SYoshinobu Inoue 	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
12047d56d374SYoshinobu Inoue 	    (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
12057d56d374SYoshinobu Inoue 	return (dt);
12067d56d374SYoshinobu Inoue }
12077d56d374SYoshinobu Inoue 
12087d56d374SYoshinobu Inoue /*
12097d56d374SYoshinobu Inoue  * Convert an ICMP "type" field to a printable string.
12107d56d374SYoshinobu Inoue  */
1211f42640a3SUlrich Spörlein const char *
1212f42640a3SUlrich Spörlein pr_type(int t0)
12137d56d374SYoshinobu Inoue {
12147d56d374SYoshinobu Inoue 	u_char t = t0 & 0xff;
1215f42640a3SUlrich Spörlein 	const char *cp;
12167d56d374SYoshinobu Inoue 
12177d56d374SYoshinobu Inoue 	switch (t) {
12187d56d374SYoshinobu Inoue 	case ICMP6_DST_UNREACH:
12197d56d374SYoshinobu Inoue 		cp = "Destination Unreachable";
12207d56d374SYoshinobu Inoue 		break;
12217d56d374SYoshinobu Inoue 	case ICMP6_PACKET_TOO_BIG:
1222c449e284SHajimu UMEMOTO 		cp = "Packet Too Big";
12237d56d374SYoshinobu Inoue 		break;
12247d56d374SYoshinobu Inoue 	case ICMP6_TIME_EXCEEDED:
12257d56d374SYoshinobu Inoue 		cp = "Time Exceeded";
12267d56d374SYoshinobu Inoue 		break;
12277d56d374SYoshinobu Inoue 	case ICMP6_PARAM_PROB:
12287d56d374SYoshinobu Inoue 		cp = "Parameter Problem";
12297d56d374SYoshinobu Inoue 		break;
12307d56d374SYoshinobu Inoue 	case ICMP6_ECHO_REQUEST:
12317d56d374SYoshinobu Inoue 		cp = "Echo Request";
12327d56d374SYoshinobu Inoue 		break;
12337d56d374SYoshinobu Inoue 	case ICMP6_ECHO_REPLY:
12347d56d374SYoshinobu Inoue 		cp = "Echo Reply";
12357d56d374SYoshinobu Inoue 		break;
12367d56d374SYoshinobu Inoue 	case ICMP6_MEMBERSHIP_QUERY:
12377d56d374SYoshinobu Inoue 		cp = "Group Membership Query";
12387d56d374SYoshinobu Inoue 		break;
12397d56d374SYoshinobu Inoue 	case ICMP6_MEMBERSHIP_REPORT:
12407d56d374SYoshinobu Inoue 		cp = "Group Membership Report";
12417d56d374SYoshinobu Inoue 		break;
12427d56d374SYoshinobu Inoue 	case ICMP6_MEMBERSHIP_REDUCTION:
12437d56d374SYoshinobu Inoue 		cp = "Group Membership Reduction";
12447d56d374SYoshinobu Inoue 		break;
12457d56d374SYoshinobu Inoue 	case ND_ROUTER_SOLICIT:
12467d56d374SYoshinobu Inoue 		cp = "Router Solicitation";
12477d56d374SYoshinobu Inoue 		break;
12487d56d374SYoshinobu Inoue 	case ND_ROUTER_ADVERT:
12497d56d374SYoshinobu Inoue 		cp = "Router Advertisement";
12507d56d374SYoshinobu Inoue 		break;
12517d56d374SYoshinobu Inoue 	case ND_NEIGHBOR_SOLICIT:
12527d56d374SYoshinobu Inoue 		cp = "Neighbor Solicitation";
12537d56d374SYoshinobu Inoue 		break;
12547d56d374SYoshinobu Inoue 	case ND_NEIGHBOR_ADVERT:
12557d56d374SYoshinobu Inoue 		cp = "Neighbor Advertisement";
12567d56d374SYoshinobu Inoue 		break;
12577d56d374SYoshinobu Inoue 	case ND_REDIRECT:
1258de68a0daSKris Kennaway 		cp = "Redirect";
12597d56d374SYoshinobu Inoue 		break;
12607d56d374SYoshinobu Inoue 	default:
12617d56d374SYoshinobu Inoue 		cp = "Unknown";
12627d56d374SYoshinobu Inoue 		break;
12637d56d374SYoshinobu Inoue 	}
12647d56d374SYoshinobu Inoue 	return cp;
12657d56d374SYoshinobu Inoue }
12667d56d374SYoshinobu Inoue 
12677d56d374SYoshinobu Inoue int
1268aa96470cSMichael Tuexen packet_ok(struct msghdr *mhdr, int cc, int seq)
12697d56d374SYoshinobu Inoue {
1270e961704aSDavid Malone 	struct icmp6_hdr *icp;
12717d56d374SYoshinobu Inoue 	struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
12727d56d374SYoshinobu Inoue 	u_char type, code;
12737d56d374SYoshinobu Inoue 	char *buf = (char *)mhdr->msg_iov[0].iov_base;
12747d56d374SYoshinobu Inoue 	struct cmsghdr *cm;
12757d56d374SYoshinobu Inoue 	int *hlimp;
1276de68a0daSKris Kennaway 	char hbuf[NI_MAXHOST];
12777d56d374SYoshinobu Inoue 
1278de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1279de68a0daSKris Kennaway 	int hlen;
1280de68a0daSKris Kennaway 	struct ip6_hdr *ip;
1281de68a0daSKris Kennaway #endif
1282de68a0daSKris Kennaway 
1283de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1284de68a0daSKris Kennaway 	ip = (struct ip6_hdr *) buf;
1285de68a0daSKris Kennaway 	hlen = sizeof(struct ip6_hdr);
1286de68a0daSKris Kennaway 	if (cc < hlen + sizeof(struct icmp6_hdr)) {
1287de68a0daSKris Kennaway 		if (verbose) {
1288de68a0daSKris Kennaway 			if (getnameinfo((struct sockaddr *)from, from->sin6_len,
1289d24cb249SHajimu UMEMOTO 			    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
129033841545SHajimu UMEMOTO 				strlcpy(hbuf, "invalid", sizeof(hbuf));
1291c449e284SHajimu UMEMOTO 			printf("packet too short (%d bytes) from %s\n", cc,
1292de68a0daSKris Kennaway 			    hbuf);
1293de68a0daSKris Kennaway 		}
1294de68a0daSKris Kennaway 		return (0);
1295de68a0daSKris Kennaway 	}
1296de68a0daSKris Kennaway 	cc -= hlen;
1297de68a0daSKris Kennaway 	icp = (struct icmp6_hdr *)(buf + hlen);
1298de68a0daSKris Kennaway #else
1299f42640a3SUlrich Spörlein 	if (cc < (int)sizeof(struct icmp6_hdr)) {
1300de68a0daSKris Kennaway 		if (verbose) {
1301de68a0daSKris Kennaway 			if (getnameinfo((struct sockaddr *)from, from->sin6_len,
1302d24cb249SHajimu UMEMOTO 			    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
130333841545SHajimu UMEMOTO 				strlcpy(hbuf, "invalid", sizeof(hbuf));
1304c449e284SHajimu UMEMOTO 			printf("data too short (%d bytes) from %s\n", cc, hbuf);
1305de68a0daSKris Kennaway 		}
13067d56d374SYoshinobu Inoue 		return(0);
13077d56d374SYoshinobu Inoue 	}
13087d56d374SYoshinobu Inoue 	icp = (struct icmp6_hdr *)buf;
1309de68a0daSKris Kennaway #endif
13107d56d374SYoshinobu Inoue 	/* get optional information via advanced API */
13117d56d374SYoshinobu Inoue 	rcvpktinfo = NULL;
13127d56d374SYoshinobu Inoue 	hlimp = NULL;
13137d56d374SYoshinobu Inoue 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
13147d56d374SYoshinobu Inoue 	    cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
13157d56d374SYoshinobu Inoue 		if (cm->cmsg_level == IPPROTO_IPV6 &&
13167d56d374SYoshinobu Inoue 		    cm->cmsg_type == IPV6_PKTINFO &&
13177d56d374SYoshinobu Inoue 		    cm->cmsg_len ==
13187d56d374SYoshinobu Inoue 		    CMSG_LEN(sizeof(struct in6_pktinfo)))
13197d56d374SYoshinobu Inoue 			rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm));
13207d56d374SYoshinobu Inoue 
13217d56d374SYoshinobu Inoue 		if (cm->cmsg_level == IPPROTO_IPV6 &&
13227d56d374SYoshinobu Inoue 		    cm->cmsg_type == IPV6_HOPLIMIT &&
13237d56d374SYoshinobu Inoue 		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
13247d56d374SYoshinobu Inoue 			hlimp = (int *)CMSG_DATA(cm);
13257d56d374SYoshinobu Inoue 	}
13267d56d374SYoshinobu Inoue 	if (rcvpktinfo == NULL || hlimp == NULL) {
13277d56d374SYoshinobu Inoue 		warnx("failed to get received hop limit or packet info");
1328de68a0daSKris Kennaway #if 0
13297d56d374SYoshinobu Inoue 		return(0);
1330de68a0daSKris Kennaway #else
1331de68a0daSKris Kennaway 		rcvhlim = 0;	/*XXX*/
1332de68a0daSKris Kennaway #endif
13337d56d374SYoshinobu Inoue 	}
1334de68a0daSKris Kennaway 	else
13357d56d374SYoshinobu Inoue 		rcvhlim = *hlimp;
13367d56d374SYoshinobu Inoue 
13377d56d374SYoshinobu Inoue 	type = icp->icmp6_type;
13387d56d374SYoshinobu Inoue 	code = icp->icmp6_code;
13397d56d374SYoshinobu Inoue 	if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
13407d56d374SYoshinobu Inoue 	    || type == ICMP6_DST_UNREACH) {
13417d56d374SYoshinobu Inoue 		struct ip6_hdr *hip;
1342aa96470cSMichael Tuexen 		struct icmp6_hdr *icmp;
1343*51eff8efSMichael Tuexen 		struct sctp_init_chunk *init;
13449d8b46c8SMichael Tuexen 		struct sctphdr *sctp;
13459d8b46c8SMichael Tuexen 		struct tcphdr *tcp;
1346aa96470cSMichael Tuexen 		struct udphdr *udp;
1347d7b63fafSDavid Malone 		void *up;
13487d56d374SYoshinobu Inoue 
13497d56d374SYoshinobu Inoue 		hip = (struct ip6_hdr *)(icp + 1);
1350d7b63fafSDavid Malone 		if ((up = get_uphdr(hip, (u_char *)(buf + cc))) == NULL) {
13517d56d374SYoshinobu Inoue 			if (verbose)
13527d56d374SYoshinobu Inoue 				warnx("failed to get upper layer header");
13537d56d374SYoshinobu Inoue 			return(0);
13547d56d374SYoshinobu Inoue 		}
1355d7b63fafSDavid Malone 		switch (useproto) {
1356d7b63fafSDavid Malone 		case IPPROTO_ICMPV6:
1357aa96470cSMichael Tuexen 			icmp = (struct icmp6_hdr *)up;
1358aa96470cSMichael Tuexen 			if (icmp->icmp6_id == ident &&
1359aa96470cSMichael Tuexen 			    icmp->icmp6_seq == htons(seq))
1360d7b63fafSDavid Malone 				return (type == ICMP6_TIME_EXCEEDED ?
1361d7b63fafSDavid Malone 				    -1 : code + 1);
1362d7b63fafSDavid Malone 			break;
1363d7b63fafSDavid Malone 		case IPPROTO_UDP:
1364aa96470cSMichael Tuexen 			udp = (struct udphdr *)up;
1365aa96470cSMichael Tuexen 			if (udp->uh_sport == htons(srcport) &&
1366aa96470cSMichael Tuexen 			    udp->uh_dport == htons(port + seq))
1367d7b63fafSDavid Malone 				return (type == ICMP6_TIME_EXCEEDED ?
1368d7b63fafSDavid Malone 				    -1 : code + 1);
1369d7b63fafSDavid Malone 			break;
13709d8b46c8SMichael Tuexen 		case IPPROTO_SCTP:
13719d8b46c8SMichael Tuexen 			sctp = (struct sctphdr *)up;
1372*51eff8efSMichael Tuexen 			if (sctp->src_port != htons(ident) ||
1373*51eff8efSMichael Tuexen 			    sctp->dest_port != htons(port + seq)) {
1374*51eff8efSMichael Tuexen 				break;
1375*51eff8efSMichael Tuexen 			}
1376*51eff8efSMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
1377*51eff8efSMichael Tuexen 			    sizeof(struct sctp_init_chunk))) {
1378*51eff8efSMichael Tuexen 				if (sctp->v_tag != 0) {
1379*51eff8efSMichael Tuexen 					break;
1380*51eff8efSMichael Tuexen 				}
1381*51eff8efSMichael Tuexen 				init = (struct sctp_init_chunk *)(sctp + 1);
1382*51eff8efSMichael Tuexen 				/* Check the initiate tag, if available. */
1383*51eff8efSMichael Tuexen 				if ((char *)&init->init.a_rwnd > buf + cc) {
13849d8b46c8SMichael Tuexen 					return (type == ICMP6_TIME_EXCEEDED ?
13859d8b46c8SMichael Tuexen 					    -1 : code + 1);
1386*51eff8efSMichael Tuexen 				}
1387*51eff8efSMichael Tuexen 				if (init->init.initiate_tag == (u_int32_t)
1388*51eff8efSMichael Tuexen 				    ((sctp->src_port << 16) | sctp->dest_port)) {
1389*51eff8efSMichael Tuexen 					return (type == ICMP6_TIME_EXCEEDED ?
1390*51eff8efSMichael Tuexen 					    -1 : code + 1);
1391*51eff8efSMichael Tuexen 				}
1392*51eff8efSMichael Tuexen 			} else {
1393*51eff8efSMichael Tuexen 				if (sctp->v_tag ==
1394*51eff8efSMichael Tuexen 				    (u_int32_t)((sctp->src_port << 16) |
1395*51eff8efSMichael Tuexen 				    sctp->dest_port)) {
1396*51eff8efSMichael Tuexen 					return (type == ICMP6_TIME_EXCEEDED ?
1397*51eff8efSMichael Tuexen 					    -1 : code + 1);
1398*51eff8efSMichael Tuexen 				}
1399*51eff8efSMichael Tuexen 			}
14009d8b46c8SMichael Tuexen 			break;
14019d8b46c8SMichael Tuexen 		case IPPROTO_TCP:
14029d8b46c8SMichael Tuexen 			tcp = (struct tcphdr *)up;
14039d8b46c8SMichael Tuexen 			if (tcp->th_sport == htons(ident) &&
14049d8b46c8SMichael Tuexen 			    tcp->th_dport == htons(port + seq) &&
14059d8b46c8SMichael Tuexen 			    tcp->th_seq ==
14069d8b46c8SMichael Tuexen 			    (tcp_seq)((tcp->th_sport << 16) | tcp->th_dport))
14079d8b46c8SMichael Tuexen 				return (type == ICMP6_TIME_EXCEEDED ?
14089d8b46c8SMichael Tuexen 				    -1 : code + 1);
14099d8b46c8SMichael Tuexen 			break;
1410d7b63fafSDavid Malone 		case IPPROTO_NONE:
141184a1a4cfSHajimu UMEMOTO 			return (type == ICMP6_TIME_EXCEEDED ?  -1 : code + 1);
1412d7b63fafSDavid Malone 		default:
1413d7b63fafSDavid Malone 			fprintf(stderr, "Unknown probe proto %d.\n", useproto);
1414d7b63fafSDavid Malone 			break;
1415d7b63fafSDavid Malone 		}
1416d7b63fafSDavid Malone 	} else if (useproto == IPPROTO_ICMPV6 && type == ICMP6_ECHO_REPLY) {
141784a1a4cfSHajimu UMEMOTO 		if (icp->icmp6_id == ident &&
141884a1a4cfSHajimu UMEMOTO 		    icp->icmp6_seq == htons(seq))
141984a1a4cfSHajimu UMEMOTO 			return (ICMP6_DST_UNREACH_NOPORT + 1);
14207d56d374SYoshinobu Inoue 	}
14217d56d374SYoshinobu Inoue 	if (verbose) {
1422de68a0daSKris Kennaway 		char sbuf[NI_MAXHOST+1], dbuf[INET6_ADDRSTRLEN];
1423e961704aSDavid Malone 		u_int8_t *p;
1424e961704aSDavid Malone 		int i;
14257d56d374SYoshinobu Inoue 
1426de68a0daSKris Kennaway 		if (getnameinfo((struct sockaddr *)from, from->sin6_len,
1427d24cb249SHajimu UMEMOTO 		    sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0)
1428c449e284SHajimu UMEMOTO 			strlcpy(sbuf, "invalid", sizeof(sbuf));
1429c449e284SHajimu UMEMOTO 		printf("\n%d bytes from %s to %s", cc, sbuf,
1430de68a0daSKris Kennaway 		    rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1431c449e284SHajimu UMEMOTO 		    dbuf, sizeof(dbuf)) : "?");
1432c449e284SHajimu UMEMOTO 		printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
14337d56d374SYoshinobu Inoue 		    icp->icmp6_code);
1434de68a0daSKris Kennaway 		p = (u_int8_t *)(icp + 1);
1435de68a0daSKris Kennaway #define WIDTH	16
1436de68a0daSKris Kennaway 		for (i = 0; i < cc; i++) {
1437de68a0daSKris Kennaway 			if (i % WIDTH == 0)
1438c449e284SHajimu UMEMOTO 				printf("%04x:", i);
1439de68a0daSKris Kennaway 			if (i % 4 == 0)
1440c449e284SHajimu UMEMOTO 				printf(" ");
1441c449e284SHajimu UMEMOTO 			printf("%02x", p[i]);
1442de68a0daSKris Kennaway 			if (i % WIDTH == WIDTH - 1)
1443c449e284SHajimu UMEMOTO 				printf("\n");
1444de68a0daSKris Kennaway 		}
1445de68a0daSKris Kennaway 		if (cc % WIDTH != 0)
1446c449e284SHajimu UMEMOTO 			printf("\n");
14477d56d374SYoshinobu Inoue 	}
14487d56d374SYoshinobu Inoue 	return(0);
14497d56d374SYoshinobu Inoue }
14507d56d374SYoshinobu Inoue 
14517d56d374SYoshinobu Inoue /*
145284a1a4cfSHajimu UMEMOTO  * Increment pointer until find the UDP or ICMP header.
14537d56d374SYoshinobu Inoue  */
1454d7b63fafSDavid Malone void *
1455aa96470cSMichael Tuexen get_uphdr(struct ip6_hdr *ip6, u_char *lim)
14567d56d374SYoshinobu Inoue {
14577d56d374SYoshinobu Inoue 	u_char *cp = (u_char *)ip6, nh;
14587d56d374SYoshinobu Inoue 	int hlen;
1459d7b63fafSDavid Malone 	static u_char none_hdr[1]; /* Fake pointer for IPPROTO_NONE. */
14607d56d374SYoshinobu Inoue 
1461d7b63fafSDavid Malone 	if (cp + sizeof(*ip6) > lim)
14627d56d374SYoshinobu Inoue 		return(NULL);
14637d56d374SYoshinobu Inoue 
14647d56d374SYoshinobu Inoue 	nh = ip6->ip6_nxt;
14657d56d374SYoshinobu Inoue 	cp += sizeof(struct ip6_hdr);
14667d56d374SYoshinobu Inoue 
1467d7b63fafSDavid Malone 	while (lim - cp >= (nh == IPPROTO_NONE ? 0 : 8)) {
14687d56d374SYoshinobu Inoue 		switch (nh) {
14697d56d374SYoshinobu Inoue 		case IPPROTO_ESP:
14707d56d374SYoshinobu Inoue 			return(NULL);
147184a1a4cfSHajimu UMEMOTO 		case IPPROTO_ICMPV6:
1472d7b63fafSDavid Malone 			return(useproto == nh ? cp : NULL);
14739d8b46c8SMichael Tuexen 		case IPPROTO_SCTP:
14749d8b46c8SMichael Tuexen 		case IPPROTO_TCP:
14757d56d374SYoshinobu Inoue 		case IPPROTO_UDP:
1476d7b63fafSDavid Malone 			return(useproto == nh ? cp : NULL);
1477d7b63fafSDavid Malone 		case IPPROTO_NONE:
1478d7b63fafSDavid Malone 			return(useproto == nh ? none_hdr : NULL);
14797d56d374SYoshinobu Inoue 		case IPPROTO_FRAGMENT:
14807d56d374SYoshinobu Inoue 			hlen = sizeof(struct ip6_frag);
14817d56d374SYoshinobu Inoue 			nh = ((struct ip6_frag *)cp)->ip6f_nxt;
14827d56d374SYoshinobu Inoue 			break;
14837d56d374SYoshinobu Inoue 		case IPPROTO_AH:
14847d56d374SYoshinobu Inoue 			hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2;
14857d56d374SYoshinobu Inoue 			nh = ((struct ip6_ext *)cp)->ip6e_nxt;
14867d56d374SYoshinobu Inoue 			break;
14877d56d374SYoshinobu Inoue 		default:
14887d56d374SYoshinobu Inoue 			hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3;
14897d56d374SYoshinobu Inoue 			nh = ((struct ip6_ext *)cp)->ip6e_nxt;
14907d56d374SYoshinobu Inoue 			break;
14917d56d374SYoshinobu Inoue 		}
14927d56d374SYoshinobu Inoue 
14937d56d374SYoshinobu Inoue 		cp += hlen;
14947d56d374SYoshinobu Inoue 	}
14957d56d374SYoshinobu Inoue 
14967d56d374SYoshinobu Inoue 	return(NULL);
14977d56d374SYoshinobu Inoue }
14987d56d374SYoshinobu Inoue 
14997d56d374SYoshinobu Inoue void
1500aa96470cSMichael Tuexen print(struct msghdr *mhdr, int cc)
15017d56d374SYoshinobu Inoue {
15027d56d374SYoshinobu Inoue 	struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
1503de68a0daSKris Kennaway 	char hbuf[NI_MAXHOST];
15047d56d374SYoshinobu Inoue 
1505de68a0daSKris Kennaway 	if (getnameinfo((struct sockaddr *)from, from->sin6_len,
1506d24cb249SHajimu UMEMOTO 	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
150733841545SHajimu UMEMOTO 		strlcpy(hbuf, "invalid", sizeof(hbuf));
1508d429d720SHajimu UMEMOTO 	if (as_path)
1509d429d720SHajimu UMEMOTO 		printf(" [AS%u]", as_lookup(asn, hbuf, AF_INET6));
1510de68a0daSKris Kennaway 	if (nflag)
1511c449e284SHajimu UMEMOTO 		printf(" %s", hbuf);
1512de68a0daSKris Kennaway 	else if (lflag)
1513c449e284SHajimu UMEMOTO 		printf(" %s (%s)", inetname((struct sockaddr *)from), hbuf);
1514de68a0daSKris Kennaway 	else
1515c449e284SHajimu UMEMOTO 		printf(" %s", inetname((struct sockaddr *)from));
15167d56d374SYoshinobu Inoue 
15177d56d374SYoshinobu Inoue 	if (verbose) {
1518de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1519c449e284SHajimu UMEMOTO 		printf(" %d bytes to %s", cc,
1520de68a0daSKris Kennaway 		    rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1521c449e284SHajimu UMEMOTO 		    hbuf, sizeof(hbuf)) : "?");
1522de68a0daSKris Kennaway #else
1523c449e284SHajimu UMEMOTO 		printf(" %d bytes of data to %s", cc,
1524de68a0daSKris Kennaway 		    rcvpktinfo ?  inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1525c449e284SHajimu UMEMOTO 		    hbuf, sizeof(hbuf)) : "?");
1526de68a0daSKris Kennaway #endif
15277d56d374SYoshinobu Inoue 	}
15287d56d374SYoshinobu Inoue }
15297d56d374SYoshinobu Inoue 
15307d56d374SYoshinobu Inoue /*
15317d56d374SYoshinobu Inoue  * Construct an Internet address representation.
15327d56d374SYoshinobu Inoue  * If the nflag has been supplied, give
15337d56d374SYoshinobu Inoue  * numeric value, otherwise try for symbolic name.
15347d56d374SYoshinobu Inoue  */
1535de68a0daSKris Kennaway const char *
1536aa96470cSMichael Tuexen inetname(struct sockaddr *sa)
15377d56d374SYoshinobu Inoue {
1538e961704aSDavid Malone 	static char line[NI_MAXHOST], domain[MAXHOSTNAMELEN + 1];
15397d56d374SYoshinobu Inoue 	static int first = 1;
1540e961704aSDavid Malone 	char *cp;
15417d56d374SYoshinobu Inoue 
15427d56d374SYoshinobu Inoue 	if (first && !nflag) {
15437d56d374SYoshinobu Inoue 		first = 0;
1544c449e284SHajimu UMEMOTO 		if (gethostname(domain, sizeof(domain)) == 0 &&
1545c449e284SHajimu UMEMOTO 		    (cp = strchr(domain, '.')))
154633841545SHajimu UMEMOTO 			(void) strlcpy(domain, cp + 1, sizeof(domain));
15477d56d374SYoshinobu Inoue 		else
15487d56d374SYoshinobu Inoue 			domain[0] = 0;
15497d56d374SYoshinobu Inoue 	}
1550de68a0daSKris Kennaway 	cp = NULL;
15517d56d374SYoshinobu Inoue 	if (!nflag) {
1552de68a0daSKris Kennaway 		if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
1553de68a0daSKris Kennaway 		    NI_NAMEREQD) == 0) {
1554c449e284SHajimu UMEMOTO 			if ((cp = strchr(line, '.')) &&
15557d56d374SYoshinobu Inoue 			    !strcmp(cp + 1, domain))
15567d56d374SYoshinobu Inoue 				*cp = 0;
1557de68a0daSKris Kennaway 			cp = line;
15587d56d374SYoshinobu Inoue 		}
15597d56d374SYoshinobu Inoue 	}
15607d56d374SYoshinobu Inoue 	if (cp)
1561de68a0daSKris Kennaway 		return cp;
1562de68a0daSKris Kennaway 
1563de68a0daSKris Kennaway 	if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
1564d24cb249SHajimu UMEMOTO 	    NI_NUMERICHOST) != 0)
156533841545SHajimu UMEMOTO 		strlcpy(line, "invalid", sizeof(line));
1566de68a0daSKris Kennaway 	return line;
15677d56d374SYoshinobu Inoue }
15687d56d374SYoshinobu Inoue 
15699d8b46c8SMichael Tuexen /*
15709d8b46c8SMichael Tuexen  * CRC32C routine for the Stream Control Transmission Protocol
15719d8b46c8SMichael Tuexen  */
15729d8b46c8SMichael Tuexen 
15739d8b46c8SMichael Tuexen #define CRC32C(c, d) (c = (c>>8) ^ crc_c[(c^(d))&0xFF])
15749d8b46c8SMichael Tuexen 
15759d8b46c8SMichael Tuexen static u_int32_t crc_c[256] = {
15769d8b46c8SMichael Tuexen 	0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
15779d8b46c8SMichael Tuexen 	0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
15789d8b46c8SMichael Tuexen 	0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
15799d8b46c8SMichael Tuexen 	0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
15809d8b46c8SMichael Tuexen 	0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
15819d8b46c8SMichael Tuexen 	0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
15829d8b46c8SMichael Tuexen 	0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
15839d8b46c8SMichael Tuexen 	0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
15849d8b46c8SMichael Tuexen 	0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
15859d8b46c8SMichael Tuexen 	0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
15869d8b46c8SMichael Tuexen 	0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
15879d8b46c8SMichael Tuexen 	0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
15889d8b46c8SMichael Tuexen 	0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
15899d8b46c8SMichael Tuexen 	0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
15909d8b46c8SMichael Tuexen 	0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
15919d8b46c8SMichael Tuexen 	0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
15929d8b46c8SMichael Tuexen 	0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
15939d8b46c8SMichael Tuexen 	0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
15949d8b46c8SMichael Tuexen 	0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
15959d8b46c8SMichael Tuexen 	0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
15969d8b46c8SMichael Tuexen 	0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
15979d8b46c8SMichael Tuexen 	0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
15989d8b46c8SMichael Tuexen 	0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
15999d8b46c8SMichael Tuexen 	0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
16009d8b46c8SMichael Tuexen 	0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
16019d8b46c8SMichael Tuexen 	0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
16029d8b46c8SMichael Tuexen 	0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
16039d8b46c8SMichael Tuexen 	0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
16049d8b46c8SMichael Tuexen 	0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
16059d8b46c8SMichael Tuexen 	0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
16069d8b46c8SMichael Tuexen 	0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
16079d8b46c8SMichael Tuexen 	0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
16089d8b46c8SMichael Tuexen 	0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
16099d8b46c8SMichael Tuexen 	0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
16109d8b46c8SMichael Tuexen 	0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
16119d8b46c8SMichael Tuexen 	0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
16129d8b46c8SMichael Tuexen 	0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
16139d8b46c8SMichael Tuexen 	0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
16149d8b46c8SMichael Tuexen 	0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
16159d8b46c8SMichael Tuexen 	0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
16169d8b46c8SMichael Tuexen 	0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
16179d8b46c8SMichael Tuexen 	0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
16189d8b46c8SMichael Tuexen 	0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
16199d8b46c8SMichael Tuexen 	0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
16209d8b46c8SMichael Tuexen 	0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
16219d8b46c8SMichael Tuexen 	0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
16229d8b46c8SMichael Tuexen 	0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
16239d8b46c8SMichael Tuexen 	0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
16249d8b46c8SMichael Tuexen 	0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
16259d8b46c8SMichael Tuexen 	0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
16269d8b46c8SMichael Tuexen 	0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
16279d8b46c8SMichael Tuexen 	0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
16289d8b46c8SMichael Tuexen 	0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
16299d8b46c8SMichael Tuexen 	0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
16309d8b46c8SMichael Tuexen 	0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
16319d8b46c8SMichael Tuexen 	0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
16329d8b46c8SMichael Tuexen 	0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
16339d8b46c8SMichael Tuexen 	0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
16349d8b46c8SMichael Tuexen 	0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
16359d8b46c8SMichael Tuexen 	0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
16369d8b46c8SMichael Tuexen 	0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
16379d8b46c8SMichael Tuexen 	0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
16389d8b46c8SMichael Tuexen 	0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
16399d8b46c8SMichael Tuexen 	0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
16409d8b46c8SMichael Tuexen };
16419d8b46c8SMichael Tuexen 
16429d8b46c8SMichael Tuexen u_int32_t
16439d8b46c8SMichael Tuexen sctp_crc32c(void *packet, u_int32_t len)
16449d8b46c8SMichael Tuexen {
16459d8b46c8SMichael Tuexen 	u_int32_t i, crc32c;
16469d8b46c8SMichael Tuexen 	u_int8_t byte0, byte1, byte2, byte3;
16479d8b46c8SMichael Tuexen 	u_int8_t *buf = (u_int8_t *)packet;
16489d8b46c8SMichael Tuexen 
16499d8b46c8SMichael Tuexen 	crc32c = ~0;
16509d8b46c8SMichael Tuexen 	for (i = 0; i < len; i++)
16519d8b46c8SMichael Tuexen 		CRC32C(crc32c, buf[i]);
16529d8b46c8SMichael Tuexen 	crc32c = ~crc32c;
16539d8b46c8SMichael Tuexen 	byte0  = crc32c & 0xff;
16549d8b46c8SMichael Tuexen 	byte1  = (crc32c>>8) & 0xff;
16559d8b46c8SMichael Tuexen 	byte2  = (crc32c>>16) & 0xff;
16569d8b46c8SMichael Tuexen 	byte3  = (crc32c>>24) & 0xff;
16579d8b46c8SMichael Tuexen 	crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
16589d8b46c8SMichael Tuexen 	return htonl(crc32c);
16599d8b46c8SMichael Tuexen }
16609d8b46c8SMichael Tuexen 
16619d8b46c8SMichael Tuexen u_int16_t
16629d8b46c8SMichael Tuexen in_cksum(u_int16_t *addr, int len)
16639d8b46c8SMichael Tuexen {
16649d8b46c8SMichael Tuexen 	int nleft = len;
16659d8b46c8SMichael Tuexen 	u_int16_t *w = addr;
16669d8b46c8SMichael Tuexen 	u_int16_t answer;
16679d8b46c8SMichael Tuexen 	int sum = 0;
16689d8b46c8SMichael Tuexen 
16699d8b46c8SMichael Tuexen 	/*
16709d8b46c8SMichael Tuexen 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
16719d8b46c8SMichael Tuexen 	 *  we add sequential 16 bit words to it, and at the end, fold
16729d8b46c8SMichael Tuexen 	 *  back all the carry bits from the top 16 bits into the lower
16739d8b46c8SMichael Tuexen 	 *  16 bits.
16749d8b46c8SMichael Tuexen 	 */
16759d8b46c8SMichael Tuexen 	while (nleft > 1)  {
16769d8b46c8SMichael Tuexen 		sum += *w++;
16779d8b46c8SMichael Tuexen 		nleft -= 2;
16789d8b46c8SMichael Tuexen 	}
16799d8b46c8SMichael Tuexen 
16809d8b46c8SMichael Tuexen 	/* mop up an odd byte, if necessary */
16819d8b46c8SMichael Tuexen 	if (nleft == 1)
16829d8b46c8SMichael Tuexen 		sum += *(u_char *)w;
16839d8b46c8SMichael Tuexen 
16849d8b46c8SMichael Tuexen 	/*
16859d8b46c8SMichael Tuexen 	 * add back carry outs from top 16 bits to low 16 bits
16869d8b46c8SMichael Tuexen 	 */
16879d8b46c8SMichael Tuexen 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
16889d8b46c8SMichael Tuexen 	sum += (sum >> 16);			/* add carry */
16899d8b46c8SMichael Tuexen 	answer = ~sum;				/* truncate to 16 bits */
16909d8b46c8SMichael Tuexen 	return (answer);
16919d8b46c8SMichael Tuexen }
16929d8b46c8SMichael Tuexen 
16939d8b46c8SMichael Tuexen u_int16_t
16949d8b46c8SMichael Tuexen tcp_chksum(struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
16959d8b46c8SMichael Tuexen     void *payload, u_int32_t len)
16969d8b46c8SMichael Tuexen {
16979d8b46c8SMichael Tuexen 	struct {
16989d8b46c8SMichael Tuexen 		struct in6_addr src;
16999d8b46c8SMichael Tuexen 		struct in6_addr dst;
17009d8b46c8SMichael Tuexen 		u_int32_t len;
17019d8b46c8SMichael Tuexen 		u_int8_t zero[3];
17029d8b46c8SMichael Tuexen 		u_int8_t next;
17039d8b46c8SMichael Tuexen 	} pseudo_hdr;
17049d8b46c8SMichael Tuexen 	u_int16_t sum[2];
17059d8b46c8SMichael Tuexen 
17069d8b46c8SMichael Tuexen 	pseudo_hdr.src = src->sin6_addr;
17079d8b46c8SMichael Tuexen 	pseudo_hdr.dst = dst->sin6_addr;
17089d8b46c8SMichael Tuexen 	pseudo_hdr.len = htonl(len);
17099d8b46c8SMichael Tuexen 	pseudo_hdr.zero[0] = 0;
17109d8b46c8SMichael Tuexen 	pseudo_hdr.zero[1] = 0;
17119d8b46c8SMichael Tuexen 	pseudo_hdr.zero[2] = 0;
17129d8b46c8SMichael Tuexen 	pseudo_hdr.next = IPPROTO_TCP;
17139d8b46c8SMichael Tuexen 
17149d8b46c8SMichael Tuexen 	sum[1] = in_cksum((u_int16_t *)&pseudo_hdr, sizeof(pseudo_hdr));
17159d8b46c8SMichael Tuexen 	sum[0] = in_cksum(payload, len);
17169d8b46c8SMichael Tuexen 
17179d8b46c8SMichael Tuexen 	return (~in_cksum(sum, sizeof(sum)));
17189d8b46c8SMichael Tuexen }
17199d8b46c8SMichael Tuexen 
17207d56d374SYoshinobu Inoue void
1721aa96470cSMichael Tuexen usage(void)
17227d56d374SYoshinobu Inoue {
172384a1a4cfSHajimu UMEMOTO 
172484a1a4cfSHajimu UMEMOTO 	fprintf(stderr,
17259d8b46c8SMichael Tuexen "usage: traceroute6 [-adIlnNrSTUv] [-A as_server] [-f firsthop] [-g gateway]\n"
17260d7d117cSHajimu UMEMOTO "       [-m hoplimit] [-p port] [-q probes] [-s src] [-w waittime] target\n"
17270d7d117cSHajimu UMEMOTO "       [datalen]\n");
17287d56d374SYoshinobu Inoue 	exit(1);
17297d56d374SYoshinobu Inoue }
1730