xref: /freebsd/usr.sbin/traceroute6/traceroute6.c (revision 8a16b7a18f5d0b031f09832fd7752fba717e2a97)
1e961704aSDavid Malone /*	$KAME: traceroute6.c,v 1.68 2004/01/25 11:16:12 suz Exp $	*/
2de68a0daSKris Kennaway 
3*8a16b7a1SPedro F. Giffuni /*-
4*8a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
5*8a16b7a1SPedro 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>
2779d8b46c8SMichael Tuexen #include <netinet/tcp.h>
2787d56d374SYoshinobu Inoue #include <netinet/udp.h>
2797d56d374SYoshinobu Inoue 
2807d56d374SYoshinobu Inoue #ifdef IPSEC
2817d56d374SYoshinobu Inoue #include <net/route.h>
2828409aedfSGeorge V. Neville-Neil #include <netipsec/ipsec.h>
2837d56d374SYoshinobu Inoue #endif
2847d56d374SYoshinobu Inoue 
285d429d720SHajimu UMEMOTO #include "as.h"
286d429d720SHajimu UMEMOTO 
2877d56d374SYoshinobu Inoue #define DUMMY_PORT 10010
2887d56d374SYoshinobu Inoue 
2897d56d374SYoshinobu Inoue #define	MAXPACKET	65535	/* max ip packet size */
2907d56d374SYoshinobu Inoue 
291de68a0daSKris Kennaway #ifndef HAVE_GETIPNODEBYNAME
292de68a0daSKris Kennaway #define getipnodebyname(x, y, z, u)	gethostbyname2((x), (y))
293de68a0daSKris Kennaway #define freehostent(x)
294de68a0daSKris Kennaway #endif
295de68a0daSKris Kennaway 
2967d56d374SYoshinobu Inoue u_char	packet[512];		/* last inbound (icmp) packet */
297aa96470cSMichael Tuexen char 	*outpacket;		/* last output packet */
2987d56d374SYoshinobu Inoue 
299784bddbcSKevin Lo int	main(int, char *[]);
300784bddbcSKevin Lo int	wait_for_reply(int, struct msghdr *);
301de68a0daSKris Kennaway #ifdef IPSEC
302de68a0daSKris Kennaway #ifdef IPSEC_POLICY_IPSEC
303784bddbcSKevin Lo int	setpolicy(int so, char *policy);
304de68a0daSKris Kennaway #endif
305de68a0daSKris Kennaway #endif
306784bddbcSKevin Lo void	send_probe(int, u_long);
307d7b63fafSDavid Malone void	*get_uphdr(struct ip6_hdr *, u_char *);
308784bddbcSKevin Lo int	get_hoplim(struct msghdr *);
309784bddbcSKevin Lo double	deltaT(struct timeval *, struct timeval *);
310f42640a3SUlrich Spörlein const char *pr_type(int);
311784bddbcSKevin Lo int	packet_ok(struct msghdr *, int, int);
312784bddbcSKevin Lo void	print(struct msghdr *, int);
313784bddbcSKevin Lo const char *inetname(struct sockaddr *);
3149d8b46c8SMichael Tuexen u_int32_t sctp_crc32c(void *, u_int32_t);
3159d8b46c8SMichael Tuexen u_int16_t in_cksum(u_int16_t *addr, int);
3169d8b46c8SMichael Tuexen u_int16_t tcp_chksum(struct sockaddr_in6 *, struct sockaddr_in6 *,
3179d8b46c8SMichael Tuexen     void *, u_int32_t);
318784bddbcSKevin Lo void	usage(void);
3197d56d374SYoshinobu Inoue 
3207d56d374SYoshinobu Inoue int rcvsock;			/* receive (icmp) socket file descriptor */
3219d8b46c8SMichael Tuexen int sndsock;			/* send (raw/udp) socket file descriptor */
3227d56d374SYoshinobu Inoue 
3237d56d374SYoshinobu Inoue struct msghdr rcvmhdr;
3247d56d374SYoshinobu Inoue struct iovec rcviov[2];
3257d56d374SYoshinobu Inoue int rcvhlim;
3267d56d374SYoshinobu Inoue struct in6_pktinfo *rcvpktinfo;
3277d56d374SYoshinobu Inoue 
3287d56d374SYoshinobu Inoue struct sockaddr_in6 Src, Dst, Rcv;
329aa96470cSMichael Tuexen u_long datalen = 20;			/* How much data */
33084a1a4cfSHajimu UMEMOTO #define	ICMP6ECHOLEN	8
331de68a0daSKris Kennaway /* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */
332de68a0daSKris Kennaway char rtbuf[2064];
333de68a0daSKris Kennaway #ifdef USE_RFC2292BIS
334de68a0daSKris Kennaway struct ip6_rthdr *rth;
335de68a0daSKris Kennaway #endif
3367d56d374SYoshinobu Inoue struct cmsghdr *cmsg;
3377d56d374SYoshinobu Inoue 
338ac97203fSPedro F. Giffuni char *source = NULL;
3397d56d374SYoshinobu Inoue char *hostname;
3407d56d374SYoshinobu Inoue 
34184a1a4cfSHajimu UMEMOTO u_long nprobes = 3;
34284a1a4cfSHajimu UMEMOTO u_long first_hop = 1;
34384a1a4cfSHajimu UMEMOTO u_long max_hops = 30;
34484a1a4cfSHajimu UMEMOTO u_int16_t srcport;
34584a1a4cfSHajimu UMEMOTO u_int16_t port = 32768+666;	/* start udp dest port # for probe packets */
34684a1a4cfSHajimu UMEMOTO u_int16_t ident;
3477d56d374SYoshinobu Inoue int options;			/* socket options */
3487d56d374SYoshinobu Inoue int verbose;
3497d56d374SYoshinobu Inoue int waittime = 5;		/* time to wait for response (in seconds) */
3507d56d374SYoshinobu Inoue int nflag;			/* print addresses numerically */
351d7b63fafSDavid Malone int useproto = IPPROTO_UDP;	/* protocol to use to send packet */
3527d56d374SYoshinobu Inoue int lflag;			/* print both numerical address & hostname */
353d429d720SHajimu UMEMOTO int as_path;			/* print as numbers for each hop */
354d429d720SHajimu UMEMOTO char *as_server = NULL;
355d429d720SHajimu UMEMOTO void *asn;
3567d56d374SYoshinobu Inoue 
3577d56d374SYoshinobu Inoue int
358aa96470cSMichael Tuexen main(int argc, char *argv[])
3597d56d374SYoshinobu Inoue {
36084a1a4cfSHajimu UMEMOTO 	int mib[4] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM };
361e961704aSDavid Malone 	char hbuf[NI_MAXHOST], src0[NI_MAXHOST], *ep;
362f42640a3SUlrich Spörlein 	int ch, i, on = 1, seq, rcvcmsglen, error;
363e961704aSDavid Malone 	struct addrinfo hints, *res;
364e961704aSDavid Malone 	static u_char *rcvcmsgbuf;
365e961704aSDavid Malone 	u_long probe, hops, lport;
366e961704aSDavid Malone 	struct hostent *hp;
367f42640a3SUlrich Spörlein 	size_t size, minlen;
36819c7ed84SKevin Lo 	uid_t uid;
3697d56d374SYoshinobu Inoue 
37053c9088fSYoshinobu Inoue 	/*
37153c9088fSYoshinobu Inoue 	 * Receive ICMP
37253c9088fSYoshinobu Inoue 	 */
37353c9088fSYoshinobu Inoue 	if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
374de68a0daSKris Kennaway 		perror("socket(ICMPv6)");
37553c9088fSYoshinobu Inoue 		exit(5);
37653c9088fSYoshinobu Inoue 	}
377de68a0daSKris Kennaway 
37884a1a4cfSHajimu UMEMOTO 	size = sizeof(i);
37984a1a4cfSHajimu UMEMOTO 	(void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &i, &size, NULL, 0);
38084a1a4cfSHajimu UMEMOTO 	max_hops = i;
38184a1a4cfSHajimu UMEMOTO 
382de68a0daSKris Kennaway 	/* specify to tell receiving interface */
383de68a0daSKris Kennaway #ifdef IPV6_RECVPKTINFO
384de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
385de68a0daSKris Kennaway 	    sizeof(on)) < 0)
386de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_RECVPKTINFO)");
387de68a0daSKris Kennaway #else  /* old adv. API */
388de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
389de68a0daSKris Kennaway 	    sizeof(on)) < 0)
390de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_PKTINFO)");
391de68a0daSKris Kennaway #endif
392de68a0daSKris Kennaway 
393de68a0daSKris Kennaway 	/* specify to tell value of hoplimit field of received IP6 hdr */
394de68a0daSKris Kennaway #ifdef IPV6_RECVHOPLIMIT
395de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
396de68a0daSKris Kennaway 	    sizeof(on)) < 0)
397de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_RECVHOPLIMIT)");
398de68a0daSKris Kennaway #else  /* old adv. API */
399de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
400de68a0daSKris Kennaway 	    sizeof(on)) < 0)
401de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_HOPLIMIT)");
402de68a0daSKris Kennaway #endif
403de68a0daSKris Kennaway 
4047d56d374SYoshinobu Inoue 	seq = 0;
4059d8b46c8SMichael Tuexen 	ident = htons(getpid() & 0xffff); /* same as ping6 */
4067d56d374SYoshinobu Inoue 
4079d8b46c8SMichael Tuexen 	while ((ch = getopt(argc, argv, "aA:df:g:Ilm:nNp:q:rs:STUvw:")) != -1)
4087d56d374SYoshinobu Inoue 		switch (ch) {
409d429d720SHajimu UMEMOTO 		case 'a':
410d429d720SHajimu UMEMOTO 			as_path = 1;
411d429d720SHajimu UMEMOTO 			break;
412d429d720SHajimu UMEMOTO 		case 'A':
413d429d720SHajimu UMEMOTO 			as_path = 1;
414d429d720SHajimu UMEMOTO 			as_server = optarg;
415d429d720SHajimu UMEMOTO 			break;
4167d56d374SYoshinobu Inoue 		case 'd':
4177d56d374SYoshinobu Inoue 			options |= SO_DEBUG;
4187d56d374SYoshinobu Inoue 			break;
419de68a0daSKris Kennaway 		case 'f':
42033841545SHajimu UMEMOTO 			ep = NULL;
42184a1a4cfSHajimu UMEMOTO 			errno = 0;
42233841545SHajimu UMEMOTO 			first_hop = strtoul(optarg, &ep, 0);
42384a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep || first_hop > 255) {
424c449e284SHajimu UMEMOTO 				fprintf(stderr,
42533841545SHajimu UMEMOTO 				    "traceroute6: invalid min hoplimit.\n");
42633841545SHajimu UMEMOTO 				exit(1);
42733841545SHajimu UMEMOTO 			}
4287d56d374SYoshinobu Inoue 			break;
4297d56d374SYoshinobu Inoue 		case 'g':
4307d56d374SYoshinobu Inoue 			hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno);
4317d56d374SYoshinobu Inoue 			if (hp == NULL) {
432c449e284SHajimu UMEMOTO 				fprintf(stderr,
4337d56d374SYoshinobu Inoue 				    "traceroute6: unknown host %s\n", optarg);
4347d56d374SYoshinobu Inoue 				exit(1);
4357d56d374SYoshinobu Inoue 			}
436de68a0daSKris Kennaway #ifdef USE_RFC2292BIS
437de68a0daSKris Kennaway 			if (rth == NULL) {
438de68a0daSKris Kennaway 				/*
439de68a0daSKris Kennaway 				 * XXX: We can't detect the number of
440de68a0daSKris Kennaway 				 * intermediate nodes yet.
441de68a0daSKris Kennaway 				 */
442de68a0daSKris Kennaway 				if ((rth = inet6_rth_init((void *)rtbuf,
443c449e284SHajimu UMEMOTO 				    sizeof(rtbuf), IPV6_RTHDR_TYPE_0,
444de68a0daSKris Kennaway 				    0)) == NULL) {
445c449e284SHajimu UMEMOTO 					fprintf(stderr,
446de68a0daSKris Kennaway 					    "inet6_rth_init failed.\n");
447de68a0daSKris Kennaway 					exit(1);
448de68a0daSKris Kennaway 				}
449de68a0daSKris Kennaway 			}
450de68a0daSKris Kennaway 			if (inet6_rth_add((void *)rth,
451de68a0daSKris Kennaway 			    (struct in6_addr *)hp->h_addr)) {
452c449e284SHajimu UMEMOTO 				fprintf(stderr,
453de68a0daSKris Kennaway 				    "inet6_rth_add failed for %s\n",
454de68a0daSKris Kennaway 				    optarg);
455de68a0daSKris Kennaway 				exit(1);
456de68a0daSKris Kennaway 			}
457de68a0daSKris Kennaway #else  /* old advanced API */
4587d56d374SYoshinobu Inoue 			if (cmsg == NULL)
4597d56d374SYoshinobu Inoue 				cmsg = inet6_rthdr_init(rtbuf, IPV6_RTHDR_TYPE_0);
460c449e284SHajimu UMEMOTO 			inet6_rthdr_add(cmsg, (struct in6_addr *)hp->h_addr,
461c449e284SHajimu UMEMOTO 			    IPV6_RTHDR_LOOSE);
462de68a0daSKris Kennaway #endif
463de68a0daSKris Kennaway 			freehostent(hp);
464de68a0daSKris Kennaway 			break;
46584a1a4cfSHajimu UMEMOTO 		case 'I':
466d7b63fafSDavid Malone 			useproto = IPPROTO_ICMPV6;
46784a1a4cfSHajimu UMEMOTO 			break;
468de68a0daSKris Kennaway 		case 'l':
469de68a0daSKris Kennaway 			lflag++;
4707d56d374SYoshinobu Inoue 			break;
4717d56d374SYoshinobu Inoue 		case 'm':
47233841545SHajimu UMEMOTO 			ep = NULL;
47384a1a4cfSHajimu UMEMOTO 			errno = 0;
47433841545SHajimu UMEMOTO 			max_hops = strtoul(optarg, &ep, 0);
47584a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep || max_hops > 255) {
476c449e284SHajimu UMEMOTO 				fprintf(stderr,
47733841545SHajimu UMEMOTO 				    "traceroute6: invalid max hoplimit.\n");
47833841545SHajimu UMEMOTO 				exit(1);
47933841545SHajimu UMEMOTO 			}
4807d56d374SYoshinobu Inoue 			break;
4817d56d374SYoshinobu Inoue 		case 'n':
4827d56d374SYoshinobu Inoue 			nflag++;
4837d56d374SYoshinobu Inoue 			break;
484d7b63fafSDavid Malone 		case 'N':
485d7b63fafSDavid Malone 			useproto = IPPROTO_NONE;
486d7b63fafSDavid Malone 			break;
4877d56d374SYoshinobu Inoue 		case 'p':
48833841545SHajimu UMEMOTO 			ep = NULL;
48984a1a4cfSHajimu UMEMOTO 			errno = 0;
49084a1a4cfSHajimu UMEMOTO 			lport = strtoul(optarg, &ep, 0);
49184a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep) {
49284a1a4cfSHajimu UMEMOTO 				fprintf(stderr, "traceroute6: invalid port.\n");
49333841545SHajimu UMEMOTO 				exit(1);
49433841545SHajimu UMEMOTO 			}
49584a1a4cfSHajimu UMEMOTO 			if (lport == 0 || lport != (lport & 0xffff)) {
496c449e284SHajimu UMEMOTO 				fprintf(stderr,
49784a1a4cfSHajimu UMEMOTO 				    "traceroute6: port out of range.\n");
4987d56d374SYoshinobu Inoue 				exit(1);
4997d56d374SYoshinobu Inoue 			}
50084a1a4cfSHajimu UMEMOTO 			port = lport & 0xffff;
5017d56d374SYoshinobu Inoue 			break;
5027d56d374SYoshinobu Inoue 		case 'q':
50333841545SHajimu UMEMOTO 			ep = NULL;
50484a1a4cfSHajimu UMEMOTO 			errno = 0;
50533841545SHajimu UMEMOTO 			nprobes = strtoul(optarg, &ep, 0);
50684a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep) {
507c449e284SHajimu UMEMOTO 				fprintf(stderr,
50833841545SHajimu UMEMOTO 				    "traceroute6: invalid nprobes.\n");
50933841545SHajimu UMEMOTO 				exit(1);
51033841545SHajimu UMEMOTO 			}
5117d56d374SYoshinobu Inoue 			if (nprobes < 1) {
512c449e284SHajimu UMEMOTO 				fprintf(stderr,
5137d56d374SYoshinobu Inoue 				    "traceroute6: nprobes must be >0.\n");
5147d56d374SYoshinobu Inoue 				exit(1);
5157d56d374SYoshinobu Inoue 			}
5167d56d374SYoshinobu Inoue 			break;
5177d56d374SYoshinobu Inoue 		case 'r':
5187d56d374SYoshinobu Inoue 			options |= SO_DONTROUTE;
5197d56d374SYoshinobu Inoue 			break;
5207d56d374SYoshinobu Inoue 		case 's':
5217d56d374SYoshinobu Inoue 			/*
5227d56d374SYoshinobu Inoue 			 * set the ip source address of the outbound
5237d56d374SYoshinobu Inoue 			 * probe (e.g., on a multi-homed host).
5247d56d374SYoshinobu Inoue 			 */
5257d56d374SYoshinobu Inoue 			source = optarg;
5267d56d374SYoshinobu Inoue 			break;
5279d8b46c8SMichael Tuexen 		case 'S':
5289d8b46c8SMichael Tuexen 			useproto = IPPROTO_SCTP;
5299d8b46c8SMichael Tuexen 			break;
5309d8b46c8SMichael Tuexen 		case 'T':
5319d8b46c8SMichael Tuexen 			useproto = IPPROTO_TCP;
5329d8b46c8SMichael Tuexen 			break;
533d7b63fafSDavid Malone 		case 'U':
534d7b63fafSDavid Malone 			useproto = IPPROTO_UDP;
535d7b63fafSDavid Malone 			break;
536aa96470cSMichael Tuexen 		case 'v':
537aa96470cSMichael Tuexen 			verbose++;
538aa96470cSMichael Tuexen 			break;
5397d56d374SYoshinobu Inoue 		case 'w':
54033841545SHajimu UMEMOTO 			ep = NULL;
54184a1a4cfSHajimu UMEMOTO 			errno = 0;
54233841545SHajimu UMEMOTO 			waittime = strtoul(optarg, &ep, 0);
54384a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep) {
544c449e284SHajimu UMEMOTO 				fprintf(stderr,
54533841545SHajimu UMEMOTO 				    "traceroute6: invalid wait time.\n");
54633841545SHajimu UMEMOTO 				exit(1);
54733841545SHajimu UMEMOTO 			}
548eea319c4SMaxim Konovalov 			if (waittime < 1) {
549c449e284SHajimu UMEMOTO 				fprintf(stderr,
550eea319c4SMaxim Konovalov 				    "traceroute6: wait must be >= 1 sec.\n");
5517d56d374SYoshinobu Inoue 				exit(1);
5527d56d374SYoshinobu Inoue 			}
5537d56d374SYoshinobu Inoue 			break;
5547d56d374SYoshinobu Inoue 		default:
5557d56d374SYoshinobu Inoue 			usage();
5567d56d374SYoshinobu Inoue 		}
5577d56d374SYoshinobu Inoue 	argc -= optind;
5587d56d374SYoshinobu Inoue 	argv += optind;
5597d56d374SYoshinobu Inoue 
560d7b63fafSDavid Malone 	/*
561d7b63fafSDavid Malone 	 * Open socket to send probe packets.
562d7b63fafSDavid Malone 	 */
563d7b63fafSDavid Malone 	switch (useproto) {
564d7b63fafSDavid Malone 	case IPPROTO_ICMPV6:
565d7b63fafSDavid Malone 		sndsock = rcvsock;
566d7b63fafSDavid Malone 		break;
567d7b63fafSDavid Malone 	case IPPROTO_UDP:
568d7b63fafSDavid Malone 		if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
569d7b63fafSDavid Malone 			perror("socket(SOCK_DGRAM)");
570d7b63fafSDavid Malone 			exit(5);
571d7b63fafSDavid Malone 		}
572d7b63fafSDavid Malone 		break;
573d7b63fafSDavid Malone 	case IPPROTO_NONE:
5749d8b46c8SMichael Tuexen 	case IPPROTO_SCTP:
5759d8b46c8SMichael Tuexen 	case IPPROTO_TCP:
5769d8b46c8SMichael Tuexen 		if ((sndsock = socket(AF_INET6, SOCK_RAW, useproto)) < 0) {
577d7b63fafSDavid Malone 			perror("socket(SOCK_RAW)");
578d7b63fafSDavid Malone 			exit(5);
579d7b63fafSDavid Malone 		}
580d7b63fafSDavid Malone 		break;
581d7b63fafSDavid Malone 	default:
582aa96470cSMichael Tuexen 		fprintf(stderr, "traceroute6: unknown probe protocol %d\n",
583d7b63fafSDavid Malone 		    useproto);
584d7b63fafSDavid Malone 		exit(5);
585d7b63fafSDavid Malone 	}
58684a1a4cfSHajimu UMEMOTO 	if (max_hops < first_hop) {
58784a1a4cfSHajimu UMEMOTO 		fprintf(stderr,
58884a1a4cfSHajimu UMEMOTO 		    "traceroute6: max hoplimit must be larger than first hoplimit.\n");
58984a1a4cfSHajimu UMEMOTO 		exit(1);
59084a1a4cfSHajimu UMEMOTO 	}
59184a1a4cfSHajimu UMEMOTO 
592d7b63fafSDavid Malone 	/* revoke privs */
593d7b63fafSDavid Malone 	uid = getuid();
594d7b63fafSDavid Malone 	if (setresuid(uid, uid, uid) == -1) {
595d7b63fafSDavid Malone 		perror("setresuid");
596d7b63fafSDavid Malone 		exit(1);
597d7b63fafSDavid Malone 	}
598d7b63fafSDavid Malone 
599d7b63fafSDavid Malone 
60033841545SHajimu UMEMOTO 	if (argc < 1 || argc > 2)
6017d56d374SYoshinobu Inoue 		usage();
6027d56d374SYoshinobu Inoue 
603de68a0daSKris Kennaway #if 1
6047d56d374SYoshinobu Inoue 	setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
605de68a0daSKris Kennaway #else
606de68a0daSKris Kennaway 	setlinebuf(stdout);
607de68a0daSKris Kennaway #endif
6087d56d374SYoshinobu Inoue 
60939865d64SYoshinobu Inoue 	memset(&hints, 0, sizeof(hints));
61039865d64SYoshinobu Inoue 	hints.ai_family = PF_INET6;
61139865d64SYoshinobu Inoue 	hints.ai_socktype = SOCK_RAW;
61239865d64SYoshinobu Inoue 	hints.ai_protocol = IPPROTO_ICMPV6;
61339865d64SYoshinobu Inoue 	hints.ai_flags = AI_CANONNAME;
61439865d64SYoshinobu Inoue 	error = getaddrinfo(*argv, NULL, &hints, &res);
61539865d64SYoshinobu Inoue 	if (error) {
616c449e284SHajimu UMEMOTO 		fprintf(stderr,
61739865d64SYoshinobu Inoue 		    "traceroute6: %s\n", gai_strerror(error));
6187d56d374SYoshinobu Inoue 		exit(1);
6197d56d374SYoshinobu Inoue 	}
620de68a0daSKris Kennaway 	if (res->ai_addrlen != sizeof(Dst)) {
621c449e284SHajimu UMEMOTO 		fprintf(stderr,
622de68a0daSKris Kennaway 		    "traceroute6: size of sockaddr mismatch\n");
623de68a0daSKris Kennaway 		exit(1);
624de68a0daSKris Kennaway 	}
62539865d64SYoshinobu Inoue 	memcpy(&Dst, res->ai_addr, res->ai_addrlen);
62639865d64SYoshinobu Inoue 	hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv;
62733841545SHajimu UMEMOTO 	if (!hostname) {
628c449e284SHajimu UMEMOTO 		fprintf(stderr, "traceroute6: not enough core\n");
62933841545SHajimu UMEMOTO 		exit(1);
63033841545SHajimu UMEMOTO 	}
63184a1a4cfSHajimu UMEMOTO 	if (res->ai_next) {
63284a1a4cfSHajimu UMEMOTO 		if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf,
63384a1a4cfSHajimu UMEMOTO 		    sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
63484a1a4cfSHajimu UMEMOTO 			strlcpy(hbuf, "?", sizeof(hbuf));
63584a1a4cfSHajimu UMEMOTO 		fprintf(stderr, "traceroute6: Warning: %s has multiple "
63684a1a4cfSHajimu UMEMOTO 		    "addresses; using %s\n", hostname, hbuf);
63784a1a4cfSHajimu UMEMOTO 	}
6387d56d374SYoshinobu Inoue 
63933841545SHajimu UMEMOTO 	if (*++argv) {
64033841545SHajimu UMEMOTO 		ep = NULL;
64184a1a4cfSHajimu UMEMOTO 		errno = 0;
64233841545SHajimu UMEMOTO 		datalen = strtoul(*argv, &ep, 0);
643aa96470cSMichael Tuexen 		if (errno || *ep) {
644c449e284SHajimu UMEMOTO 			fprintf(stderr,
64533841545SHajimu UMEMOTO 			    "traceroute6: invalid packet length.\n");
64633841545SHajimu UMEMOTO 			exit(1);
64733841545SHajimu UMEMOTO 		}
64833841545SHajimu UMEMOTO 	}
649d7b63fafSDavid Malone 	switch (useproto) {
650d7b63fafSDavid Malone 	case IPPROTO_ICMPV6:
651aa96470cSMichael Tuexen 		minlen = ICMP6ECHOLEN;
652d7b63fafSDavid Malone 		break;
653d7b63fafSDavid Malone 	case IPPROTO_UDP:
654aa96470cSMichael Tuexen 		minlen = sizeof(struct udphdr);
655d7b63fafSDavid Malone 		break;
656d7b63fafSDavid Malone 	case IPPROTO_NONE:
657d7b63fafSDavid Malone 		minlen = 0;
658d7b63fafSDavid Malone 		datalen = 0;
659d7b63fafSDavid Malone 		break;
6609d8b46c8SMichael Tuexen 	case IPPROTO_SCTP:
6619d8b46c8SMichael Tuexen 		minlen = sizeof(struct sctphdr);
6629d8b46c8SMichael Tuexen 		break;
6639d8b46c8SMichael Tuexen 	case IPPROTO_TCP:
6649d8b46c8SMichael Tuexen 		minlen = sizeof(struct tcphdr);
6659d8b46c8SMichael Tuexen 		break;
666d7b63fafSDavid Malone 	default:
667d7b63fafSDavid Malone 		fprintf(stderr, "traceroute6: unknown probe protocol %d.\n",
668d7b63fafSDavid Malone 		    useproto);
669d7b63fafSDavid Malone 		exit(1);
670d7b63fafSDavid Malone 	}
67184a1a4cfSHajimu UMEMOTO 	if (datalen < minlen)
67284a1a4cfSHajimu UMEMOTO 		datalen = minlen;
67384a1a4cfSHajimu UMEMOTO 	else if (datalen >= MAXPACKET) {
674c449e284SHajimu UMEMOTO 		fprintf(stderr,
675f42640a3SUlrich Spörlein 		    "traceroute6: packet size must be %zu <= s < %d.\n",
676f42640a3SUlrich Spörlein 		    minlen, MAXPACKET);
6777d56d374SYoshinobu Inoue 		exit(1);
6787d56d374SYoshinobu Inoue 	}
679aa96470cSMichael Tuexen 	if (useproto == IPPROTO_UDP)
680aa96470cSMichael Tuexen 		datalen -= sizeof(struct udphdr);
681f42640a3SUlrich Spörlein 	outpacket = malloc(datalen);
6827d56d374SYoshinobu Inoue 	if (!outpacket) {
683de68a0daSKris Kennaway 		perror("malloc");
6847d56d374SYoshinobu Inoue 		exit(1);
6857d56d374SYoshinobu Inoue 	}
6867d56d374SYoshinobu Inoue 	(void) bzero((char *)outpacket, datalen);
6877d56d374SYoshinobu Inoue 
6887d56d374SYoshinobu Inoue 	/* initialize msghdr for receiving packets */
6897d56d374SYoshinobu Inoue 	rcviov[0].iov_base = (caddr_t)packet;
6907d56d374SYoshinobu Inoue 	rcviov[0].iov_len = sizeof(packet);
691de68a0daSKris Kennaway 	rcvmhdr.msg_name = (caddr_t)&Rcv;
692de68a0daSKris Kennaway 	rcvmhdr.msg_namelen = sizeof(Rcv);
6937d56d374SYoshinobu Inoue 	rcvmhdr.msg_iov = rcviov;
6947d56d374SYoshinobu Inoue 	rcvmhdr.msg_iovlen = 1;
695e961704aSDavid Malone 	rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
696e961704aSDavid Malone 	    CMSG_SPACE(sizeof(int));
697de68a0daSKris Kennaway 	if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) {
698c449e284SHajimu UMEMOTO 		fprintf(stderr, "traceroute6: malloc failed\n");
699de68a0daSKris Kennaway 		exit(1);
700de68a0daSKris Kennaway 	}
7017d56d374SYoshinobu Inoue 	rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
702de68a0daSKris Kennaway 	rcvmhdr.msg_controllen = rcvcmsglen;
7037d56d374SYoshinobu Inoue 
7047d56d374SYoshinobu Inoue 	if (options & SO_DEBUG)
7057d56d374SYoshinobu Inoue 		(void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
7067d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
7077d56d374SYoshinobu Inoue 	if (options & SO_DONTROUTE)
7087d56d374SYoshinobu Inoue 		(void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
7097d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
7107d56d374SYoshinobu Inoue #ifdef IPSEC
7117d56d374SYoshinobu Inoue #ifdef IPSEC_POLICY_IPSEC
7127d56d374SYoshinobu Inoue 	/*
7137d56d374SYoshinobu Inoue 	 * do not raise error even if setsockopt fails, kernel may have ipsec
7147d56d374SYoshinobu Inoue 	 * turned off.
7157d56d374SYoshinobu Inoue 	 */
7167d56d374SYoshinobu Inoue 	if (setpolicy(rcvsock, "in bypass") < 0)
717d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
7187d56d374SYoshinobu Inoue 	if (setpolicy(rcvsock, "out bypass") < 0)
719d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
720de68a0daSKris Kennaway #else
721de68a0daSKris Kennaway     {
722de68a0daSKris Kennaway 	int level = IPSEC_LEVEL_NONE;
723de68a0daSKris Kennaway 
724de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
725de68a0daSKris Kennaway 	    sizeof(level));
726de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
727de68a0daSKris Kennaway 	    sizeof(level));
728de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL
729de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
730de68a0daSKris Kennaway 	    sizeof(level));
731de68a0daSKris Kennaway #else
732de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
733de68a0daSKris Kennaway 	    sizeof(level));
734de68a0daSKris Kennaway #endif
735de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL
736de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
737de68a0daSKris Kennaway 	    sizeof(level));
738de68a0daSKris Kennaway #endif
739de68a0daSKris Kennaway     }
7407d56d374SYoshinobu Inoue #endif /*IPSEC_POLICY_IPSEC*/
7417d56d374SYoshinobu Inoue #endif /*IPSEC*/
7427d56d374SYoshinobu Inoue 
743de68a0daSKris Kennaway #ifdef SO_SNDBUF
74484a1a4cfSHajimu UMEMOTO 	i = datalen;
745aa96470cSMichael Tuexen 	if (i == 0)
746aa96470cSMichael Tuexen 		i = 1;
74784a1a4cfSHajimu UMEMOTO 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&i,
748aa96470cSMichael Tuexen 	    sizeof(i)) < 0) {
749de68a0daSKris Kennaway 		perror("setsockopt(SO_SNDBUF)");
7507d56d374SYoshinobu Inoue 		exit(6);
7517d56d374SYoshinobu Inoue 	}
752de68a0daSKris Kennaway #endif /* SO_SNDBUF */
7537d56d374SYoshinobu Inoue 	if (options & SO_DEBUG)
7547d56d374SYoshinobu Inoue 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
7557d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
7567d56d374SYoshinobu Inoue 	if (options & SO_DONTROUTE)
7577d56d374SYoshinobu Inoue 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
7587d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
759de68a0daSKris Kennaway #ifdef USE_RFC2292BIS
760de68a0daSKris Kennaway 	if (rth) {/* XXX: there is no library to finalize the header... */
761de68a0daSKris Kennaway 		rth->ip6r_len = rth->ip6r_segleft * 2;
762de68a0daSKris Kennaway 		if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR,
763de68a0daSKris Kennaway 		    (void *)rth, (rth->ip6r_len + 1) << 3)) {
764c449e284SHajimu UMEMOTO 			fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n",
765de68a0daSKris Kennaway 			    strerror(errno));
766de68a0daSKris Kennaway 			exit(1);
767de68a0daSKris Kennaway 		}
768de68a0daSKris Kennaway 	}
769de68a0daSKris Kennaway #else  /* old advanced API */
7707d56d374SYoshinobu Inoue 	if (cmsg != NULL) {
7717d56d374SYoshinobu Inoue 		inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
772de68a0daSKris Kennaway 		if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_PKTOPTIONS,
773de68a0daSKris Kennaway 		    rtbuf, cmsg->cmsg_len) < 0) {
774c449e284SHajimu UMEMOTO 			fprintf(stderr, "setsockopt(IPV6_PKTOPTIONS): %s\n",
775de68a0daSKris Kennaway 			    strerror(errno));
776de68a0daSKris Kennaway 			exit(1);
7777d56d374SYoshinobu Inoue 		}
778de68a0daSKris Kennaway 	}
779de68a0daSKris Kennaway #endif /* USE_RFC2292BIS */
7807d56d374SYoshinobu Inoue #ifdef IPSEC
7817d56d374SYoshinobu Inoue #ifdef IPSEC_POLICY_IPSEC
7827d56d374SYoshinobu Inoue 	/*
7837d56d374SYoshinobu Inoue 	 * do not raise error even if setsockopt fails, kernel may have ipsec
7847d56d374SYoshinobu Inoue 	 * turned off.
7857d56d374SYoshinobu Inoue 	 */
7867d56d374SYoshinobu Inoue 	if (setpolicy(sndsock, "in bypass") < 0)
787d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
7887d56d374SYoshinobu Inoue 	if (setpolicy(sndsock, "out bypass") < 0)
789d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
790de68a0daSKris Kennaway #else
791de68a0daSKris Kennaway     {
792de68a0daSKris Kennaway 	int level = IPSEC_LEVEL_BYPASS;
793de68a0daSKris Kennaway 
794de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
795de68a0daSKris Kennaway 	    sizeof(level));
796de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
797de68a0daSKris Kennaway 	    sizeof(level));
798de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL
799de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
800de68a0daSKris Kennaway 	    sizeof(level));
801de68a0daSKris Kennaway #else
802de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
803de68a0daSKris Kennaway 	    sizeof(level));
804de68a0daSKris Kennaway #endif
805de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL
806de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
807de68a0daSKris Kennaway 	    sizeof(level));
808de68a0daSKris Kennaway #endif
809de68a0daSKris Kennaway     }
8107d56d374SYoshinobu Inoue #endif /*IPSEC_POLICY_IPSEC*/
8117d56d374SYoshinobu Inoue #endif /*IPSEC*/
8127d56d374SYoshinobu Inoue 
8137d56d374SYoshinobu Inoue 	/*
8147d56d374SYoshinobu Inoue 	 * Source selection
8157d56d374SYoshinobu Inoue 	 */
816de68a0daSKris Kennaway 	bzero(&Src, sizeof(Src));
8177d56d374SYoshinobu Inoue 	if (source) {
818de68a0daSKris Kennaway 		struct addrinfo hints, *res;
819de68a0daSKris Kennaway 		int error;
820de68a0daSKris Kennaway 
821de68a0daSKris Kennaway 		memset(&hints, 0, sizeof(hints));
822de68a0daSKris Kennaway 		hints.ai_family = AF_INET6;
823de68a0daSKris Kennaway 		hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
824de68a0daSKris Kennaway 		hints.ai_flags = AI_NUMERICHOST;
825de68a0daSKris Kennaway 		error = getaddrinfo(source, "0", &hints, &res);
826de68a0daSKris Kennaway 		if (error) {
827c449e284SHajimu UMEMOTO 			printf("traceroute6: %s: %s\n", source,
828de68a0daSKris Kennaway 			    gai_strerror(error));
8297d56d374SYoshinobu Inoue 			exit(1);
8307d56d374SYoshinobu Inoue 		}
831de68a0daSKris Kennaway 		if (res->ai_addrlen > sizeof(Src)) {
832c449e284SHajimu UMEMOTO 			printf("traceroute6: %s: %s\n", source,
833de68a0daSKris Kennaway 			    gai_strerror(error));
834de68a0daSKris Kennaway 			exit(1);
835de68a0daSKris Kennaway 		}
836de68a0daSKris Kennaway 		memcpy(&Src, res->ai_addr, res->ai_addrlen);
837de68a0daSKris Kennaway 		freeaddrinfo(res);
8387d56d374SYoshinobu Inoue 	} else {
8397d56d374SYoshinobu Inoue 		struct sockaddr_in6 Nxt;
84084a1a4cfSHajimu UMEMOTO 		int dummy;
84184a1a4cfSHajimu UMEMOTO 		socklen_t len;
8427d56d374SYoshinobu Inoue 
8437d56d374SYoshinobu Inoue 		Nxt = Dst;
8447d56d374SYoshinobu Inoue 		Nxt.sin6_port = htons(DUMMY_PORT);
8457d56d374SYoshinobu Inoue 		if (cmsg != NULL)
8467d56d374SYoshinobu Inoue 			bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr,
8477d56d374SYoshinobu Inoue 			    sizeof(Nxt.sin6_addr));
8487d56d374SYoshinobu Inoue 		if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
8497d56d374SYoshinobu Inoue 			perror("socket");
850de68a0daSKris Kennaway 			exit(1);
8517d56d374SYoshinobu Inoue 		}
852de68a0daSKris Kennaway 		if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) {
8537d56d374SYoshinobu Inoue 			perror("connect");
854de68a0daSKris Kennaway 			exit(1);
8557d56d374SYoshinobu Inoue 		}
856de68a0daSKris Kennaway 		len = sizeof(Src);
857de68a0daSKris Kennaway 		if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) {
858de68a0daSKris Kennaway 			perror("getsockname");
859de68a0daSKris Kennaway 			exit(1);
860de68a0daSKris Kennaway 		}
861de68a0daSKris Kennaway 		if (getnameinfo((struct sockaddr *)&Src, Src.sin6_len,
862d24cb249SHajimu UMEMOTO 		    src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) {
863c449e284SHajimu UMEMOTO 			fprintf(stderr, "getnameinfo failed for source\n");
864de68a0daSKris Kennaway 			exit(1);
865de68a0daSKris Kennaway 		}
866de68a0daSKris Kennaway 		source = src0;
8677d56d374SYoshinobu Inoue 		close(dummy);
8687d56d374SYoshinobu Inoue 	}
869de68a0daSKris Kennaway 
87084a1a4cfSHajimu UMEMOTO 	Src.sin6_port = htons(0);
871de68a0daSKris Kennaway 	if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) {
872de68a0daSKris Kennaway 		perror("bind");
8737d56d374SYoshinobu Inoue 		exit(1);
8747d56d374SYoshinobu Inoue 	}
8757d56d374SYoshinobu Inoue 
87684a1a4cfSHajimu UMEMOTO 	{
877c449e284SHajimu UMEMOTO 		socklen_t len;
878de68a0daSKris Kennaway 
879de68a0daSKris Kennaway 		len = sizeof(Src);
88084a1a4cfSHajimu UMEMOTO 		if (getsockname(sndsock, (struct sockaddr *)&Src, &len) < 0) {
881de68a0daSKris Kennaway 			perror("getsockname");
882de68a0daSKris Kennaway 			exit(1);
883de68a0daSKris Kennaway 		}
88484a1a4cfSHajimu UMEMOTO 		srcport = ntohs(Src.sin6_port);
885de68a0daSKris Kennaway 	}
886de68a0daSKris Kennaway 
887d429d720SHajimu UMEMOTO 	if (as_path) {
888d429d720SHajimu UMEMOTO 		asn = as_setup(as_server);
889d429d720SHajimu UMEMOTO 		if (asn == NULL) {
890d429d720SHajimu UMEMOTO 			fprintf(stderr,
891d429d720SHajimu UMEMOTO 			    "traceroute6: as_setup failed, AS# lookups"
892d429d720SHajimu UMEMOTO 			    " disabled\n");
893d429d720SHajimu UMEMOTO 			(void)fflush(stderr);
894d429d720SHajimu UMEMOTO 			as_path = 0;
895d429d720SHajimu UMEMOTO 		}
896d429d720SHajimu UMEMOTO 	}
897d429d720SHajimu UMEMOTO 
8987d56d374SYoshinobu Inoue 	/*
8997d56d374SYoshinobu Inoue 	 * Message to users
9007d56d374SYoshinobu Inoue 	 */
901de68a0daSKris Kennaway 	if (getnameinfo((struct sockaddr *)&Dst, Dst.sin6_len, hbuf,
902d24cb249SHajimu UMEMOTO 	    sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
90333841545SHajimu UMEMOTO 		strlcpy(hbuf, "(invalid)", sizeof(hbuf));
904c449e284SHajimu UMEMOTO 	fprintf(stderr, "traceroute6");
905c449e284SHajimu UMEMOTO 	fprintf(stderr, " to %s (%s)", hostname, hbuf);
9067d56d374SYoshinobu Inoue 	if (source)
907c449e284SHajimu UMEMOTO 		fprintf(stderr, " from %s", source);
90884a1a4cfSHajimu UMEMOTO 	fprintf(stderr, ", %lu hops max, %lu byte packets\n",
909d55fae02SMichael Tuexen 	    max_hops,
910d55fae02SMichael Tuexen 	    datalen + ((useproto == IPPROTO_UDP) ? sizeof(struct udphdr) : 0));
9117d56d374SYoshinobu Inoue 	(void) fflush(stderr);
9127d56d374SYoshinobu Inoue 
913de68a0daSKris Kennaway 	if (first_hop > 1)
91484a1a4cfSHajimu UMEMOTO 		printf("Skipping %lu intermediate hops\n", first_hop - 1);
915de68a0daSKris Kennaway 
9167d56d374SYoshinobu Inoue 	/*
9177d56d374SYoshinobu Inoue 	 * Main loop
9187d56d374SYoshinobu Inoue 	 */
919de68a0daSKris Kennaway 	for (hops = first_hop; hops <= max_hops; ++hops) {
9207d56d374SYoshinobu Inoue 		struct in6_addr lastaddr;
9217d56d374SYoshinobu Inoue 		int got_there = 0;
922f42640a3SUlrich Spörlein 		unsigned unreachable = 0;
9237d56d374SYoshinobu Inoue 
92484a1a4cfSHajimu UMEMOTO 		printf("%2lu ", hops);
9257d56d374SYoshinobu Inoue 		bzero(&lastaddr, sizeof(lastaddr));
9267d56d374SYoshinobu Inoue 		for (probe = 0; probe < nprobes; ++probe) {
9277d56d374SYoshinobu Inoue 			int cc;
9287d56d374SYoshinobu Inoue 			struct timeval t1, t2;
9297d56d374SYoshinobu Inoue 
93084a1a4cfSHajimu UMEMOTO 			(void) gettimeofday(&t1, NULL);
9317d56d374SYoshinobu Inoue 			send_probe(++seq, hops);
9327d56d374SYoshinobu Inoue 			while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) {
93384a1a4cfSHajimu UMEMOTO 				(void) gettimeofday(&t2, NULL);
9347d56d374SYoshinobu Inoue 				if ((i = packet_ok(&rcvmhdr, cc, seq))) {
9357d56d374SYoshinobu Inoue 					if (!IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr,
9367d56d374SYoshinobu Inoue 					    &lastaddr)) {
93759876f93SChristian S.J. Peron 						if (probe > 0)
93859876f93SChristian S.J. Peron 							fputs("\n   ", stdout);
9397d56d374SYoshinobu Inoue 						print(&rcvmhdr, cc);
9407d56d374SYoshinobu Inoue 						lastaddr = Rcv.sin6_addr;
9417d56d374SYoshinobu Inoue 					}
942c449e284SHajimu UMEMOTO 					printf("  %.3f ms", deltaT(&t1, &t2));
9437d56d374SYoshinobu Inoue 					switch (i - 1) {
9447d56d374SYoshinobu Inoue 					case ICMP6_DST_UNREACH_NOROUTE:
9457d56d374SYoshinobu Inoue 						++unreachable;
946c449e284SHajimu UMEMOTO 						printf(" !N");
9477d56d374SYoshinobu Inoue 						break;
9487d56d374SYoshinobu Inoue 					case ICMP6_DST_UNREACH_ADMIN:
9497d56d374SYoshinobu Inoue 						++unreachable;
950c449e284SHajimu UMEMOTO 						printf(" !P");
9517d56d374SYoshinobu Inoue 						break;
9527d56d374SYoshinobu Inoue 					case ICMP6_DST_UNREACH_NOTNEIGHBOR:
9537d56d374SYoshinobu Inoue 						++unreachable;
954c449e284SHajimu UMEMOTO 						printf(" !S");
9557d56d374SYoshinobu Inoue 						break;
9567d56d374SYoshinobu Inoue 					case ICMP6_DST_UNREACH_ADDR:
9577d56d374SYoshinobu Inoue 						++unreachable;
958c449e284SHajimu UMEMOTO 						printf(" !A");
9597d56d374SYoshinobu Inoue 						break;
9607d56d374SYoshinobu Inoue 					case ICMP6_DST_UNREACH_NOPORT:
9617d56d374SYoshinobu Inoue 						if (rcvhlim >= 0 &&
9627d56d374SYoshinobu Inoue 						    rcvhlim <= 1)
963c449e284SHajimu UMEMOTO 							printf(" !");
9647d56d374SYoshinobu Inoue 						++got_there;
9657d56d374SYoshinobu Inoue 						break;
9667d56d374SYoshinobu Inoue 					}
9677d56d374SYoshinobu Inoue 					break;
968161ab37dSHiroki Sato 				} else if (deltaT(&t1, &t2) > waittime * 1000) {
969161ab37dSHiroki Sato 					cc = 0;
970161ab37dSHiroki Sato 					break;
9717d56d374SYoshinobu Inoue 				}
9727d56d374SYoshinobu Inoue 			}
9737d56d374SYoshinobu Inoue 			if (cc == 0)
974c449e284SHajimu UMEMOTO 				printf(" *");
9757d56d374SYoshinobu Inoue 			(void) fflush(stdout);
9767d56d374SYoshinobu Inoue 		}
9777d56d374SYoshinobu Inoue 		putchar('\n');
9787d56d374SYoshinobu Inoue 		if (got_there ||
9797d56d374SYoshinobu Inoue 		    (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) {
9807d56d374SYoshinobu Inoue 			exit(0);
9817d56d374SYoshinobu Inoue 		}
9827d56d374SYoshinobu Inoue 	}
983d429d720SHajimu UMEMOTO 	if (as_path)
984d429d720SHajimu UMEMOTO 		as_shutdown(asn);
9857d56d374SYoshinobu Inoue 
9867d56d374SYoshinobu Inoue 	exit(0);
9877d56d374SYoshinobu Inoue }
9887d56d374SYoshinobu Inoue 
9897d56d374SYoshinobu Inoue int
990aa96470cSMichael Tuexen wait_for_reply(int sock, struct msghdr *mhdr)
9917d56d374SYoshinobu Inoue {
9922a1c5efaSKris Kennaway #ifdef HAVE_POLL
9932a1c5efaSKris Kennaway 	struct pollfd pfd[1];
9947d56d374SYoshinobu Inoue 	int cc = 0;
9957d56d374SYoshinobu Inoue 
9962a1c5efaSKris Kennaway 	pfd[0].fd = sock;
9972a1c5efaSKris Kennaway 	pfd[0].events = POLLIN;
9982a1c5efaSKris Kennaway 	pfd[0].revents = 0;
9997d56d374SYoshinobu Inoue 
10002a1c5efaSKris Kennaway 	if (poll(pfd, 1, waittime * 1000) > 0)
10017d56d374SYoshinobu Inoue 		cc = recvmsg(rcvsock, mhdr, 0);
10027d56d374SYoshinobu Inoue 
10037d56d374SYoshinobu Inoue 	return(cc);
10042a1c5efaSKris Kennaway #else
10052a1c5efaSKris Kennaway 	fd_set *fdsp;
10062a1c5efaSKris Kennaway 	struct timeval wait;
10072a1c5efaSKris Kennaway 	int cc = 0, fdsn;
10082a1c5efaSKris Kennaway 
10092a1c5efaSKris Kennaway 	fdsn = howmany(sock + 1, NFDBITS) * sizeof(fd_mask);
10102a1c5efaSKris Kennaway 	if ((fdsp = (fd_set *)malloc(fdsn)) == NULL)
10112a1c5efaSKris Kennaway 		err(1, "malloc");
10122a1c5efaSKris Kennaway 	memset(fdsp, 0, fdsn);
10132a1c5efaSKris Kennaway 	FD_SET(sock, fdsp);
10142a1c5efaSKris Kennaway 	wait.tv_sec = waittime; wait.tv_usec = 0;
10152a1c5efaSKris Kennaway 
10162a1c5efaSKris Kennaway 	if (select(sock+1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0)
10172a1c5efaSKris Kennaway 		cc = recvmsg(rcvsock, mhdr, 0);
10182a1c5efaSKris Kennaway 
10192a1c5efaSKris Kennaway 	free(fdsp);
10202a1c5efaSKris Kennaway 	return(cc);
10212a1c5efaSKris Kennaway #endif
10227d56d374SYoshinobu Inoue }
10237d56d374SYoshinobu Inoue 
10247d56d374SYoshinobu Inoue #ifdef IPSEC
10257d56d374SYoshinobu Inoue #ifdef IPSEC_POLICY_IPSEC
10267d56d374SYoshinobu Inoue int
10277d56d374SYoshinobu Inoue setpolicy(so, policy)
10287d56d374SYoshinobu Inoue 	int so;
10297d56d374SYoshinobu Inoue 	char *policy;
10307d56d374SYoshinobu Inoue {
10317d56d374SYoshinobu Inoue 	char *buf;
10327d56d374SYoshinobu Inoue 
10337d56d374SYoshinobu Inoue 	buf = ipsec_set_policy(policy, strlen(policy));
10347d56d374SYoshinobu Inoue 	if (buf == NULL) {
1035de68a0daSKris Kennaway 		warnx("%s", ipsec_strerror());
10367d56d374SYoshinobu Inoue 		return -1;
10377d56d374SYoshinobu Inoue 	}
10387d56d374SYoshinobu Inoue 	(void)setsockopt(so, IPPROTO_IPV6, IPV6_IPSEC_POLICY,
10397d56d374SYoshinobu Inoue 	    buf, ipsec_get_policylen(buf));
10407d56d374SYoshinobu Inoue 
10417d56d374SYoshinobu Inoue 	free(buf);
10427d56d374SYoshinobu Inoue 
10437d56d374SYoshinobu Inoue 	return 0;
10447d56d374SYoshinobu Inoue }
10457d56d374SYoshinobu Inoue #endif
10467d56d374SYoshinobu Inoue #endif
10477d56d374SYoshinobu Inoue 
10487d56d374SYoshinobu Inoue void
1049aa96470cSMichael Tuexen send_probe(int seq, u_long hops)
10507d56d374SYoshinobu Inoue {
1051d7b63fafSDavid Malone 	struct icmp6_hdr *icp;
10529d8b46c8SMichael Tuexen 	struct sctphdr *sctp;
10539d8b46c8SMichael Tuexen 	struct sctp_chunkhdr *chk;
10549d8b46c8SMichael Tuexen 	struct tcphdr *tcp;
10557d56d374SYoshinobu Inoue 	int i;
10567d56d374SYoshinobu Inoue 
105784a1a4cfSHajimu UMEMOTO 	i = hops;
10587d56d374SYoshinobu Inoue 	if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
105984a1a4cfSHajimu UMEMOTO 	    (char *)&i, sizeof(i)) < 0) {
10607d56d374SYoshinobu Inoue 		perror("setsockopt IPV6_UNICAST_HOPS");
10617d56d374SYoshinobu Inoue 	}
10627d56d374SYoshinobu Inoue 
10637d56d374SYoshinobu Inoue 	Dst.sin6_port = htons(port + seq);
10647d56d374SYoshinobu Inoue 
1065d7b63fafSDavid Malone 	switch (useproto) {
1066d7b63fafSDavid Malone 	case IPPROTO_ICMPV6:
1067d7b63fafSDavid Malone 		icp = (struct icmp6_hdr *)outpacket;
106884a1a4cfSHajimu UMEMOTO 
106984a1a4cfSHajimu UMEMOTO 		icp->icmp6_type = ICMP6_ECHO_REQUEST;
107084a1a4cfSHajimu UMEMOTO 		icp->icmp6_code = 0;
107184a1a4cfSHajimu UMEMOTO 		icp->icmp6_cksum = 0;
107284a1a4cfSHajimu UMEMOTO 		icp->icmp6_id = ident;
107384a1a4cfSHajimu UMEMOTO 		icp->icmp6_seq = htons(seq);
1074d7b63fafSDavid Malone 		break;
1075d7b63fafSDavid Malone 	case IPPROTO_UDP:
1076d7b63fafSDavid Malone 		break;
1077d7b63fafSDavid Malone 	case IPPROTO_NONE:
1078d7b63fafSDavid Malone 		/* No space for anything. No harm as seq/tv32 are decorative. */
1079d7b63fafSDavid Malone 		break;
10809d8b46c8SMichael Tuexen 	case IPPROTO_SCTP:
10819d8b46c8SMichael Tuexen 		sctp = (struct sctphdr *)outpacket;
10829d8b46c8SMichael Tuexen 
10839d8b46c8SMichael Tuexen 		sctp->src_port = htons(ident);
10849d8b46c8SMichael Tuexen 		sctp->dest_port = htons(port + seq);
10859d8b46c8SMichael Tuexen 		sctp->v_tag = (sctp->src_port << 16) | sctp->dest_port;
10869d8b46c8SMichael Tuexen 		sctp->checksum = htonl(0);
10879d8b46c8SMichael Tuexen 		if (datalen >= (u_long)(sizeof(struct sctphdr) +
10889d8b46c8SMichael Tuexen 		    sizeof(struct sctp_chunkhdr))) {
10899d8b46c8SMichael Tuexen 			chk = (struct sctp_chunkhdr *)(sctp + 1);
10909d8b46c8SMichael Tuexen 			chk->chunk_type = SCTP_SHUTDOWN_ACK;
10919d8b46c8SMichael Tuexen 			chk->chunk_flags = 0;
10929d8b46c8SMichael Tuexen 			chk->chunk_length = htons(4);
10939d8b46c8SMichael Tuexen 		}
10949d8b46c8SMichael Tuexen 		if (datalen >= (u_long)(sizeof(struct sctphdr) +
10959d8b46c8SMichael Tuexen 		    2 * sizeof(struct sctp_chunkhdr))) {
10969d8b46c8SMichael Tuexen 			chk = chk + 1;
10979d8b46c8SMichael Tuexen 			chk->chunk_type = SCTP_PAD_CHUNK;
10989d8b46c8SMichael Tuexen 			chk->chunk_flags = 0;
10999d8b46c8SMichael Tuexen 			chk->chunk_length = htons((u_int16_t)(datalen -
11009d8b46c8SMichael Tuexen 			    sizeof(struct sctphdr) -
11019d8b46c8SMichael Tuexen 			    sizeof(struct sctp_chunkhdr)));
11029d8b46c8SMichael Tuexen 		}
11039d8b46c8SMichael Tuexen 		sctp->checksum = sctp_crc32c(outpacket, datalen);
11049d8b46c8SMichael Tuexen 		break;
11059d8b46c8SMichael Tuexen 	case IPPROTO_TCP:
11069d8b46c8SMichael Tuexen 		tcp = (struct tcphdr *)outpacket;
11079d8b46c8SMichael Tuexen 
11089d8b46c8SMichael Tuexen 		tcp->th_sport = htons(ident);
11099d8b46c8SMichael Tuexen 		tcp->th_dport = htons(port + seq);
11109d8b46c8SMichael Tuexen 		tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport;
11119d8b46c8SMichael Tuexen 		tcp->th_ack = 0;
11129d8b46c8SMichael Tuexen 		tcp->th_off = 5;
11139d8b46c8SMichael Tuexen 		tcp->th_flags = TH_SYN;
11149d8b46c8SMichael Tuexen 		tcp->th_sum = 0;
11159d8b46c8SMichael Tuexen 		tcp->th_sum = tcp_chksum(&Src, &Dst, outpacket, datalen);
11169d8b46c8SMichael Tuexen 		break;
1117d7b63fafSDavid Malone 	default:
1118d7b63fafSDavid Malone 		fprintf(stderr, "Unknown probe protocol %d.\n", useproto);
1119d7b63fafSDavid Malone 		exit(1);
112084a1a4cfSHajimu UMEMOTO 	}
11217d56d374SYoshinobu Inoue 
11227d56d374SYoshinobu Inoue 	i = sendto(sndsock, (char *)outpacket, datalen, 0,
1123de68a0daSKris Kennaway 	    (struct sockaddr *)&Dst, Dst.sin6_len);
1124f42640a3SUlrich Spörlein 	if (i < 0 || (u_long)i != datalen)  {
11257d56d374SYoshinobu Inoue 		if (i < 0)
11267d56d374SYoshinobu Inoue 			perror("sendto");
112784a1a4cfSHajimu UMEMOTO 		printf("traceroute6: wrote %s %lu chars, ret=%d\n",
1128c449e284SHajimu UMEMOTO 		    hostname, datalen, i);
11297d56d374SYoshinobu Inoue 		(void) fflush(stdout);
11307d56d374SYoshinobu Inoue 	}
11317d56d374SYoshinobu Inoue }
11327d56d374SYoshinobu Inoue 
11337d56d374SYoshinobu Inoue int
1134aa96470cSMichael Tuexen get_hoplim(struct msghdr *mhdr)
11357d56d374SYoshinobu Inoue {
11367d56d374SYoshinobu Inoue 	struct cmsghdr *cm;
11377d56d374SYoshinobu Inoue 
11387d56d374SYoshinobu Inoue 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
11397d56d374SYoshinobu Inoue 	    cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
11407d56d374SYoshinobu Inoue 		if (cm->cmsg_level == IPPROTO_IPV6 &&
11417d56d374SYoshinobu Inoue 		    cm->cmsg_type == IPV6_HOPLIMIT &&
11427d56d374SYoshinobu Inoue 		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
11437d56d374SYoshinobu Inoue 			return(*(int *)CMSG_DATA(cm));
11447d56d374SYoshinobu Inoue 	}
11457d56d374SYoshinobu Inoue 
11467d56d374SYoshinobu Inoue 	return(-1);
11477d56d374SYoshinobu Inoue }
11487d56d374SYoshinobu Inoue 
11497d56d374SYoshinobu Inoue double
1150aa96470cSMichael Tuexen deltaT(struct timeval *t1p, struct timeval *t2p)
11517d56d374SYoshinobu Inoue {
1152e961704aSDavid Malone 	double dt;
11537d56d374SYoshinobu Inoue 
11547d56d374SYoshinobu Inoue 	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
11557d56d374SYoshinobu Inoue 	    (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
11567d56d374SYoshinobu Inoue 	return (dt);
11577d56d374SYoshinobu Inoue }
11587d56d374SYoshinobu Inoue 
11597d56d374SYoshinobu Inoue /*
11607d56d374SYoshinobu Inoue  * Convert an ICMP "type" field to a printable string.
11617d56d374SYoshinobu Inoue  */
1162f42640a3SUlrich Spörlein const char *
1163f42640a3SUlrich Spörlein pr_type(int t0)
11647d56d374SYoshinobu Inoue {
11657d56d374SYoshinobu Inoue 	u_char t = t0 & 0xff;
1166f42640a3SUlrich Spörlein 	const char *cp;
11677d56d374SYoshinobu Inoue 
11687d56d374SYoshinobu Inoue 	switch (t) {
11697d56d374SYoshinobu Inoue 	case ICMP6_DST_UNREACH:
11707d56d374SYoshinobu Inoue 		cp = "Destination Unreachable";
11717d56d374SYoshinobu Inoue 		break;
11727d56d374SYoshinobu Inoue 	case ICMP6_PACKET_TOO_BIG:
1173c449e284SHajimu UMEMOTO 		cp = "Packet Too Big";
11747d56d374SYoshinobu Inoue 		break;
11757d56d374SYoshinobu Inoue 	case ICMP6_TIME_EXCEEDED:
11767d56d374SYoshinobu Inoue 		cp = "Time Exceeded";
11777d56d374SYoshinobu Inoue 		break;
11787d56d374SYoshinobu Inoue 	case ICMP6_PARAM_PROB:
11797d56d374SYoshinobu Inoue 		cp = "Parameter Problem";
11807d56d374SYoshinobu Inoue 		break;
11817d56d374SYoshinobu Inoue 	case ICMP6_ECHO_REQUEST:
11827d56d374SYoshinobu Inoue 		cp = "Echo Request";
11837d56d374SYoshinobu Inoue 		break;
11847d56d374SYoshinobu Inoue 	case ICMP6_ECHO_REPLY:
11857d56d374SYoshinobu Inoue 		cp = "Echo Reply";
11867d56d374SYoshinobu Inoue 		break;
11877d56d374SYoshinobu Inoue 	case ICMP6_MEMBERSHIP_QUERY:
11887d56d374SYoshinobu Inoue 		cp = "Group Membership Query";
11897d56d374SYoshinobu Inoue 		break;
11907d56d374SYoshinobu Inoue 	case ICMP6_MEMBERSHIP_REPORT:
11917d56d374SYoshinobu Inoue 		cp = "Group Membership Report";
11927d56d374SYoshinobu Inoue 		break;
11937d56d374SYoshinobu Inoue 	case ICMP6_MEMBERSHIP_REDUCTION:
11947d56d374SYoshinobu Inoue 		cp = "Group Membership Reduction";
11957d56d374SYoshinobu Inoue 		break;
11967d56d374SYoshinobu Inoue 	case ND_ROUTER_SOLICIT:
11977d56d374SYoshinobu Inoue 		cp = "Router Solicitation";
11987d56d374SYoshinobu Inoue 		break;
11997d56d374SYoshinobu Inoue 	case ND_ROUTER_ADVERT:
12007d56d374SYoshinobu Inoue 		cp = "Router Advertisement";
12017d56d374SYoshinobu Inoue 		break;
12027d56d374SYoshinobu Inoue 	case ND_NEIGHBOR_SOLICIT:
12037d56d374SYoshinobu Inoue 		cp = "Neighbor Solicitation";
12047d56d374SYoshinobu Inoue 		break;
12057d56d374SYoshinobu Inoue 	case ND_NEIGHBOR_ADVERT:
12067d56d374SYoshinobu Inoue 		cp = "Neighbor Advertisement";
12077d56d374SYoshinobu Inoue 		break;
12087d56d374SYoshinobu Inoue 	case ND_REDIRECT:
1209de68a0daSKris Kennaway 		cp = "Redirect";
12107d56d374SYoshinobu Inoue 		break;
12117d56d374SYoshinobu Inoue 	default:
12127d56d374SYoshinobu Inoue 		cp = "Unknown";
12137d56d374SYoshinobu Inoue 		break;
12147d56d374SYoshinobu Inoue 	}
12157d56d374SYoshinobu Inoue 	return cp;
12167d56d374SYoshinobu Inoue }
12177d56d374SYoshinobu Inoue 
12187d56d374SYoshinobu Inoue int
1219aa96470cSMichael Tuexen packet_ok(struct msghdr *mhdr, int cc, int seq)
12207d56d374SYoshinobu Inoue {
1221e961704aSDavid Malone 	struct icmp6_hdr *icp;
12227d56d374SYoshinobu Inoue 	struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
12237d56d374SYoshinobu Inoue 	u_char type, code;
12247d56d374SYoshinobu Inoue 	char *buf = (char *)mhdr->msg_iov[0].iov_base;
12257d56d374SYoshinobu Inoue 	struct cmsghdr *cm;
12267d56d374SYoshinobu Inoue 	int *hlimp;
1227de68a0daSKris Kennaway 	char hbuf[NI_MAXHOST];
12287d56d374SYoshinobu Inoue 
1229de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1230de68a0daSKris Kennaway 	int hlen;
1231de68a0daSKris Kennaway 	struct ip6_hdr *ip;
1232de68a0daSKris Kennaway #endif
1233de68a0daSKris Kennaway 
1234de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1235de68a0daSKris Kennaway 	ip = (struct ip6_hdr *) buf;
1236de68a0daSKris Kennaway 	hlen = sizeof(struct ip6_hdr);
1237de68a0daSKris Kennaway 	if (cc < hlen + sizeof(struct icmp6_hdr)) {
1238de68a0daSKris Kennaway 		if (verbose) {
1239de68a0daSKris Kennaway 			if (getnameinfo((struct sockaddr *)from, from->sin6_len,
1240d24cb249SHajimu UMEMOTO 			    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
124133841545SHajimu UMEMOTO 				strlcpy(hbuf, "invalid", sizeof(hbuf));
1242c449e284SHajimu UMEMOTO 			printf("packet too short (%d bytes) from %s\n", cc,
1243de68a0daSKris Kennaway 			    hbuf);
1244de68a0daSKris Kennaway 		}
1245de68a0daSKris Kennaway 		return (0);
1246de68a0daSKris Kennaway 	}
1247de68a0daSKris Kennaway 	cc -= hlen;
1248de68a0daSKris Kennaway 	icp = (struct icmp6_hdr *)(buf + hlen);
1249de68a0daSKris Kennaway #else
1250f42640a3SUlrich Spörlein 	if (cc < (int)sizeof(struct icmp6_hdr)) {
1251de68a0daSKris Kennaway 		if (verbose) {
1252de68a0daSKris Kennaway 			if (getnameinfo((struct sockaddr *)from, from->sin6_len,
1253d24cb249SHajimu UMEMOTO 			    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
125433841545SHajimu UMEMOTO 				strlcpy(hbuf, "invalid", sizeof(hbuf));
1255c449e284SHajimu UMEMOTO 			printf("data too short (%d bytes) from %s\n", cc, hbuf);
1256de68a0daSKris Kennaway 		}
12577d56d374SYoshinobu Inoue 		return(0);
12587d56d374SYoshinobu Inoue 	}
12597d56d374SYoshinobu Inoue 	icp = (struct icmp6_hdr *)buf;
1260de68a0daSKris Kennaway #endif
12617d56d374SYoshinobu Inoue 	/* get optional information via advanced API */
12627d56d374SYoshinobu Inoue 	rcvpktinfo = NULL;
12637d56d374SYoshinobu Inoue 	hlimp = NULL;
12647d56d374SYoshinobu Inoue 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
12657d56d374SYoshinobu Inoue 	    cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
12667d56d374SYoshinobu Inoue 		if (cm->cmsg_level == IPPROTO_IPV6 &&
12677d56d374SYoshinobu Inoue 		    cm->cmsg_type == IPV6_PKTINFO &&
12687d56d374SYoshinobu Inoue 		    cm->cmsg_len ==
12697d56d374SYoshinobu Inoue 		    CMSG_LEN(sizeof(struct in6_pktinfo)))
12707d56d374SYoshinobu Inoue 			rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm));
12717d56d374SYoshinobu Inoue 
12727d56d374SYoshinobu Inoue 		if (cm->cmsg_level == IPPROTO_IPV6 &&
12737d56d374SYoshinobu Inoue 		    cm->cmsg_type == IPV6_HOPLIMIT &&
12747d56d374SYoshinobu Inoue 		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
12757d56d374SYoshinobu Inoue 			hlimp = (int *)CMSG_DATA(cm);
12767d56d374SYoshinobu Inoue 	}
12777d56d374SYoshinobu Inoue 	if (rcvpktinfo == NULL || hlimp == NULL) {
12787d56d374SYoshinobu Inoue 		warnx("failed to get received hop limit or packet info");
1279de68a0daSKris Kennaway #if 0
12807d56d374SYoshinobu Inoue 		return(0);
1281de68a0daSKris Kennaway #else
1282de68a0daSKris Kennaway 		rcvhlim = 0;	/*XXX*/
1283de68a0daSKris Kennaway #endif
12847d56d374SYoshinobu Inoue 	}
1285de68a0daSKris Kennaway 	else
12867d56d374SYoshinobu Inoue 		rcvhlim = *hlimp;
12877d56d374SYoshinobu Inoue 
12887d56d374SYoshinobu Inoue 	type = icp->icmp6_type;
12897d56d374SYoshinobu Inoue 	code = icp->icmp6_code;
12907d56d374SYoshinobu Inoue 	if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
12917d56d374SYoshinobu Inoue 	    || type == ICMP6_DST_UNREACH) {
12927d56d374SYoshinobu Inoue 		struct ip6_hdr *hip;
1293aa96470cSMichael Tuexen 		struct icmp6_hdr *icmp;
12949d8b46c8SMichael Tuexen 		struct sctphdr *sctp;
12959d8b46c8SMichael Tuexen 		struct tcphdr *tcp;
1296aa96470cSMichael Tuexen 		struct udphdr *udp;
1297d7b63fafSDavid Malone 		void *up;
12987d56d374SYoshinobu Inoue 
12997d56d374SYoshinobu Inoue 		hip = (struct ip6_hdr *)(icp + 1);
1300d7b63fafSDavid Malone 		if ((up = get_uphdr(hip, (u_char *)(buf + cc))) == NULL) {
13017d56d374SYoshinobu Inoue 			if (verbose)
13027d56d374SYoshinobu Inoue 				warnx("failed to get upper layer header");
13037d56d374SYoshinobu Inoue 			return(0);
13047d56d374SYoshinobu Inoue 		}
1305d7b63fafSDavid Malone 		switch (useproto) {
1306d7b63fafSDavid Malone 		case IPPROTO_ICMPV6:
1307aa96470cSMichael Tuexen 			icmp = (struct icmp6_hdr *)up;
1308aa96470cSMichael Tuexen 			if (icmp->icmp6_id == ident &&
1309aa96470cSMichael Tuexen 			    icmp->icmp6_seq == htons(seq))
1310d7b63fafSDavid Malone 				return (type == ICMP6_TIME_EXCEEDED ?
1311d7b63fafSDavid Malone 				    -1 : code + 1);
1312d7b63fafSDavid Malone 			break;
1313d7b63fafSDavid Malone 		case IPPROTO_UDP:
1314aa96470cSMichael Tuexen 			udp = (struct udphdr *)up;
1315aa96470cSMichael Tuexen 			if (udp->uh_sport == htons(srcport) &&
1316aa96470cSMichael Tuexen 			    udp->uh_dport == htons(port + seq))
1317d7b63fafSDavid Malone 				return (type == ICMP6_TIME_EXCEEDED ?
1318d7b63fafSDavid Malone 				    -1 : code + 1);
1319d7b63fafSDavid Malone 			break;
13209d8b46c8SMichael Tuexen 		case IPPROTO_SCTP:
13219d8b46c8SMichael Tuexen 			sctp = (struct sctphdr *)up;
13229d8b46c8SMichael Tuexen 			if (sctp->src_port == htons(ident) &&
13239d8b46c8SMichael Tuexen 			    sctp->dest_port == htons(port + seq) &&
13249d8b46c8SMichael Tuexen 			    sctp->v_tag ==
13259d8b46c8SMichael Tuexen 			    (u_int32_t)((sctp->src_port << 16) | sctp->dest_port))
13269d8b46c8SMichael Tuexen 				return (type == ICMP6_TIME_EXCEEDED ?
13279d8b46c8SMichael Tuexen 				    -1 : code + 1);
13289d8b46c8SMichael Tuexen 			break;
13299d8b46c8SMichael Tuexen 		case IPPROTO_TCP:
13309d8b46c8SMichael Tuexen 			tcp = (struct tcphdr *)up;
13319d8b46c8SMichael Tuexen 			if (tcp->th_sport == htons(ident) &&
13329d8b46c8SMichael Tuexen 			    tcp->th_dport == htons(port + seq) &&
13339d8b46c8SMichael Tuexen 			    tcp->th_seq ==
13349d8b46c8SMichael Tuexen 			    (tcp_seq)((tcp->th_sport << 16) | tcp->th_dport))
13359d8b46c8SMichael Tuexen 				return (type == ICMP6_TIME_EXCEEDED ?
13369d8b46c8SMichael Tuexen 				    -1 : code + 1);
13379d8b46c8SMichael Tuexen 			break;
1338d7b63fafSDavid Malone 		case IPPROTO_NONE:
133984a1a4cfSHajimu UMEMOTO 			return (type == ICMP6_TIME_EXCEEDED ?  -1 : code + 1);
1340d7b63fafSDavid Malone 		default:
1341d7b63fafSDavid Malone 			fprintf(stderr, "Unknown probe proto %d.\n", useproto);
1342d7b63fafSDavid Malone 			break;
1343d7b63fafSDavid Malone 		}
1344d7b63fafSDavid Malone 	} else if (useproto == IPPROTO_ICMPV6 && type == ICMP6_ECHO_REPLY) {
134584a1a4cfSHajimu UMEMOTO 		if (icp->icmp6_id == ident &&
134684a1a4cfSHajimu UMEMOTO 		    icp->icmp6_seq == htons(seq))
134784a1a4cfSHajimu UMEMOTO 			return (ICMP6_DST_UNREACH_NOPORT + 1);
13487d56d374SYoshinobu Inoue 	}
13497d56d374SYoshinobu Inoue 	if (verbose) {
1350de68a0daSKris Kennaway 		char sbuf[NI_MAXHOST+1], dbuf[INET6_ADDRSTRLEN];
1351e961704aSDavid Malone 		u_int8_t *p;
1352e961704aSDavid Malone 		int i;
13537d56d374SYoshinobu Inoue 
1354de68a0daSKris Kennaway 		if (getnameinfo((struct sockaddr *)from, from->sin6_len,
1355d24cb249SHajimu UMEMOTO 		    sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0)
1356c449e284SHajimu UMEMOTO 			strlcpy(sbuf, "invalid", sizeof(sbuf));
1357c449e284SHajimu UMEMOTO 		printf("\n%d bytes from %s to %s", cc, sbuf,
1358de68a0daSKris Kennaway 		    rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1359c449e284SHajimu UMEMOTO 		    dbuf, sizeof(dbuf)) : "?");
1360c449e284SHajimu UMEMOTO 		printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
13617d56d374SYoshinobu Inoue 		    icp->icmp6_code);
1362de68a0daSKris Kennaway 		p = (u_int8_t *)(icp + 1);
1363de68a0daSKris Kennaway #define WIDTH	16
1364de68a0daSKris Kennaway 		for (i = 0; i < cc; i++) {
1365de68a0daSKris Kennaway 			if (i % WIDTH == 0)
1366c449e284SHajimu UMEMOTO 				printf("%04x:", i);
1367de68a0daSKris Kennaway 			if (i % 4 == 0)
1368c449e284SHajimu UMEMOTO 				printf(" ");
1369c449e284SHajimu UMEMOTO 			printf("%02x", p[i]);
1370de68a0daSKris Kennaway 			if (i % WIDTH == WIDTH - 1)
1371c449e284SHajimu UMEMOTO 				printf("\n");
1372de68a0daSKris Kennaway 		}
1373de68a0daSKris Kennaway 		if (cc % WIDTH != 0)
1374c449e284SHajimu UMEMOTO 			printf("\n");
13757d56d374SYoshinobu Inoue 	}
13767d56d374SYoshinobu Inoue 	return(0);
13777d56d374SYoshinobu Inoue }
13787d56d374SYoshinobu Inoue 
13797d56d374SYoshinobu Inoue /*
138084a1a4cfSHajimu UMEMOTO  * Increment pointer until find the UDP or ICMP header.
13817d56d374SYoshinobu Inoue  */
1382d7b63fafSDavid Malone void *
1383aa96470cSMichael Tuexen get_uphdr(struct ip6_hdr *ip6, u_char *lim)
13847d56d374SYoshinobu Inoue {
13857d56d374SYoshinobu Inoue 	u_char *cp = (u_char *)ip6, nh;
13867d56d374SYoshinobu Inoue 	int hlen;
1387d7b63fafSDavid Malone 	static u_char none_hdr[1]; /* Fake pointer for IPPROTO_NONE. */
13887d56d374SYoshinobu Inoue 
1389d7b63fafSDavid Malone 	if (cp + sizeof(*ip6) > lim)
13907d56d374SYoshinobu Inoue 		return(NULL);
13917d56d374SYoshinobu Inoue 
13927d56d374SYoshinobu Inoue 	nh = ip6->ip6_nxt;
13937d56d374SYoshinobu Inoue 	cp += sizeof(struct ip6_hdr);
13947d56d374SYoshinobu Inoue 
1395d7b63fafSDavid Malone 	while (lim - cp >= (nh == IPPROTO_NONE ? 0 : 8)) {
13967d56d374SYoshinobu Inoue 		switch (nh) {
13977d56d374SYoshinobu Inoue 		case IPPROTO_ESP:
13987d56d374SYoshinobu Inoue 			return(NULL);
139984a1a4cfSHajimu UMEMOTO 		case IPPROTO_ICMPV6:
1400d7b63fafSDavid Malone 			return(useproto == nh ? cp : NULL);
14019d8b46c8SMichael Tuexen 		case IPPROTO_SCTP:
14029d8b46c8SMichael Tuexen 		case IPPROTO_TCP:
14037d56d374SYoshinobu Inoue 		case IPPROTO_UDP:
1404d7b63fafSDavid Malone 			return(useproto == nh ? cp : NULL);
1405d7b63fafSDavid Malone 		case IPPROTO_NONE:
1406d7b63fafSDavid Malone 			return(useproto == nh ? none_hdr : NULL);
14077d56d374SYoshinobu Inoue 		case IPPROTO_FRAGMENT:
14087d56d374SYoshinobu Inoue 			hlen = sizeof(struct ip6_frag);
14097d56d374SYoshinobu Inoue 			nh = ((struct ip6_frag *)cp)->ip6f_nxt;
14107d56d374SYoshinobu Inoue 			break;
14117d56d374SYoshinobu Inoue 		case IPPROTO_AH:
14127d56d374SYoshinobu Inoue 			hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2;
14137d56d374SYoshinobu Inoue 			nh = ((struct ip6_ext *)cp)->ip6e_nxt;
14147d56d374SYoshinobu Inoue 			break;
14157d56d374SYoshinobu Inoue 		default:
14167d56d374SYoshinobu Inoue 			hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3;
14177d56d374SYoshinobu Inoue 			nh = ((struct ip6_ext *)cp)->ip6e_nxt;
14187d56d374SYoshinobu Inoue 			break;
14197d56d374SYoshinobu Inoue 		}
14207d56d374SYoshinobu Inoue 
14217d56d374SYoshinobu Inoue 		cp += hlen;
14227d56d374SYoshinobu Inoue 	}
14237d56d374SYoshinobu Inoue 
14247d56d374SYoshinobu Inoue 	return(NULL);
14257d56d374SYoshinobu Inoue }
14267d56d374SYoshinobu Inoue 
14277d56d374SYoshinobu Inoue void
1428aa96470cSMichael Tuexen print(struct msghdr *mhdr, int cc)
14297d56d374SYoshinobu Inoue {
14307d56d374SYoshinobu Inoue 	struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
1431de68a0daSKris Kennaway 	char hbuf[NI_MAXHOST];
14327d56d374SYoshinobu Inoue 
1433de68a0daSKris Kennaway 	if (getnameinfo((struct sockaddr *)from, from->sin6_len,
1434d24cb249SHajimu UMEMOTO 	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
143533841545SHajimu UMEMOTO 		strlcpy(hbuf, "invalid", sizeof(hbuf));
1436d429d720SHajimu UMEMOTO 	if (as_path)
1437d429d720SHajimu UMEMOTO 		printf(" [AS%u]", as_lookup(asn, hbuf, AF_INET6));
1438de68a0daSKris Kennaway 	if (nflag)
1439c449e284SHajimu UMEMOTO 		printf(" %s", hbuf);
1440de68a0daSKris Kennaway 	else if (lflag)
1441c449e284SHajimu UMEMOTO 		printf(" %s (%s)", inetname((struct sockaddr *)from), hbuf);
1442de68a0daSKris Kennaway 	else
1443c449e284SHajimu UMEMOTO 		printf(" %s", inetname((struct sockaddr *)from));
14447d56d374SYoshinobu Inoue 
14457d56d374SYoshinobu Inoue 	if (verbose) {
1446de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1447c449e284SHajimu UMEMOTO 		printf(" %d bytes to %s", cc,
1448de68a0daSKris Kennaway 		    rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1449c449e284SHajimu UMEMOTO 		    hbuf, sizeof(hbuf)) : "?");
1450de68a0daSKris Kennaway #else
1451c449e284SHajimu UMEMOTO 		printf(" %d bytes of data to %s", cc,
1452de68a0daSKris Kennaway 		    rcvpktinfo ?  inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1453c449e284SHajimu UMEMOTO 		    hbuf, sizeof(hbuf)) : "?");
1454de68a0daSKris Kennaway #endif
14557d56d374SYoshinobu Inoue 	}
14567d56d374SYoshinobu Inoue }
14577d56d374SYoshinobu Inoue 
14587d56d374SYoshinobu Inoue /*
14597d56d374SYoshinobu Inoue  * Construct an Internet address representation.
14607d56d374SYoshinobu Inoue  * If the nflag has been supplied, give
14617d56d374SYoshinobu Inoue  * numeric value, otherwise try for symbolic name.
14627d56d374SYoshinobu Inoue  */
1463de68a0daSKris Kennaway const char *
1464aa96470cSMichael Tuexen inetname(struct sockaddr *sa)
14657d56d374SYoshinobu Inoue {
1466e961704aSDavid Malone 	static char line[NI_MAXHOST], domain[MAXHOSTNAMELEN + 1];
14677d56d374SYoshinobu Inoue 	static int first = 1;
1468e961704aSDavid Malone 	char *cp;
14697d56d374SYoshinobu Inoue 
14707d56d374SYoshinobu Inoue 	if (first && !nflag) {
14717d56d374SYoshinobu Inoue 		first = 0;
1472c449e284SHajimu UMEMOTO 		if (gethostname(domain, sizeof(domain)) == 0 &&
1473c449e284SHajimu UMEMOTO 		    (cp = strchr(domain, '.')))
147433841545SHajimu UMEMOTO 			(void) strlcpy(domain, cp + 1, sizeof(domain));
14757d56d374SYoshinobu Inoue 		else
14767d56d374SYoshinobu Inoue 			domain[0] = 0;
14777d56d374SYoshinobu Inoue 	}
1478de68a0daSKris Kennaway 	cp = NULL;
14797d56d374SYoshinobu Inoue 	if (!nflag) {
1480de68a0daSKris Kennaway 		if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
1481de68a0daSKris Kennaway 		    NI_NAMEREQD) == 0) {
1482c449e284SHajimu UMEMOTO 			if ((cp = strchr(line, '.')) &&
14837d56d374SYoshinobu Inoue 			    !strcmp(cp + 1, domain))
14847d56d374SYoshinobu Inoue 				*cp = 0;
1485de68a0daSKris Kennaway 			cp = line;
14867d56d374SYoshinobu Inoue 		}
14877d56d374SYoshinobu Inoue 	}
14887d56d374SYoshinobu Inoue 	if (cp)
1489de68a0daSKris Kennaway 		return cp;
1490de68a0daSKris Kennaway 
1491de68a0daSKris Kennaway 	if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
1492d24cb249SHajimu UMEMOTO 	    NI_NUMERICHOST) != 0)
149333841545SHajimu UMEMOTO 		strlcpy(line, "invalid", sizeof(line));
1494de68a0daSKris Kennaway 	return line;
14957d56d374SYoshinobu Inoue }
14967d56d374SYoshinobu Inoue 
14979d8b46c8SMichael Tuexen /*
14989d8b46c8SMichael Tuexen  * CRC32C routine for the Stream Control Transmission Protocol
14999d8b46c8SMichael Tuexen  */
15009d8b46c8SMichael Tuexen 
15019d8b46c8SMichael Tuexen #define CRC32C(c, d) (c = (c>>8) ^ crc_c[(c^(d))&0xFF])
15029d8b46c8SMichael Tuexen 
15039d8b46c8SMichael Tuexen static u_int32_t crc_c[256] = {
15049d8b46c8SMichael Tuexen 	0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
15059d8b46c8SMichael Tuexen 	0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
15069d8b46c8SMichael Tuexen 	0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
15079d8b46c8SMichael Tuexen 	0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
15089d8b46c8SMichael Tuexen 	0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
15099d8b46c8SMichael Tuexen 	0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
15109d8b46c8SMichael Tuexen 	0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
15119d8b46c8SMichael Tuexen 	0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
15129d8b46c8SMichael Tuexen 	0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
15139d8b46c8SMichael Tuexen 	0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
15149d8b46c8SMichael Tuexen 	0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
15159d8b46c8SMichael Tuexen 	0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
15169d8b46c8SMichael Tuexen 	0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
15179d8b46c8SMichael Tuexen 	0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
15189d8b46c8SMichael Tuexen 	0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
15199d8b46c8SMichael Tuexen 	0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
15209d8b46c8SMichael Tuexen 	0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
15219d8b46c8SMichael Tuexen 	0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
15229d8b46c8SMichael Tuexen 	0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
15239d8b46c8SMichael Tuexen 	0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
15249d8b46c8SMichael Tuexen 	0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
15259d8b46c8SMichael Tuexen 	0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
15269d8b46c8SMichael Tuexen 	0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
15279d8b46c8SMichael Tuexen 	0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
15289d8b46c8SMichael Tuexen 	0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
15299d8b46c8SMichael Tuexen 	0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
15309d8b46c8SMichael Tuexen 	0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
15319d8b46c8SMichael Tuexen 	0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
15329d8b46c8SMichael Tuexen 	0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
15339d8b46c8SMichael Tuexen 	0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
15349d8b46c8SMichael Tuexen 	0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
15359d8b46c8SMichael Tuexen 	0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
15369d8b46c8SMichael Tuexen 	0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
15379d8b46c8SMichael Tuexen 	0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
15389d8b46c8SMichael Tuexen 	0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
15399d8b46c8SMichael Tuexen 	0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
15409d8b46c8SMichael Tuexen 	0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
15419d8b46c8SMichael Tuexen 	0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
15429d8b46c8SMichael Tuexen 	0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
15439d8b46c8SMichael Tuexen 	0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
15449d8b46c8SMichael Tuexen 	0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
15459d8b46c8SMichael Tuexen 	0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
15469d8b46c8SMichael Tuexen 	0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
15479d8b46c8SMichael Tuexen 	0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
15489d8b46c8SMichael Tuexen 	0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
15499d8b46c8SMichael Tuexen 	0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
15509d8b46c8SMichael Tuexen 	0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
15519d8b46c8SMichael Tuexen 	0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
15529d8b46c8SMichael Tuexen 	0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
15539d8b46c8SMichael Tuexen 	0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
15549d8b46c8SMichael Tuexen 	0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
15559d8b46c8SMichael Tuexen 	0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
15569d8b46c8SMichael Tuexen 	0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
15579d8b46c8SMichael Tuexen 	0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
15589d8b46c8SMichael Tuexen 	0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
15599d8b46c8SMichael Tuexen 	0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
15609d8b46c8SMichael Tuexen 	0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
15619d8b46c8SMichael Tuexen 	0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
15629d8b46c8SMichael Tuexen 	0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
15639d8b46c8SMichael Tuexen 	0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
15649d8b46c8SMichael Tuexen 	0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
15659d8b46c8SMichael Tuexen 	0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
15669d8b46c8SMichael Tuexen 	0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
15679d8b46c8SMichael Tuexen 	0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
15689d8b46c8SMichael Tuexen };
15699d8b46c8SMichael Tuexen 
15709d8b46c8SMichael Tuexen u_int32_t
15719d8b46c8SMichael Tuexen sctp_crc32c(void *packet, u_int32_t len)
15729d8b46c8SMichael Tuexen {
15739d8b46c8SMichael Tuexen 	u_int32_t i, crc32c;
15749d8b46c8SMichael Tuexen 	u_int8_t byte0, byte1, byte2, byte3;
15759d8b46c8SMichael Tuexen 	u_int8_t *buf = (u_int8_t *)packet;
15769d8b46c8SMichael Tuexen 
15779d8b46c8SMichael Tuexen 	crc32c = ~0;
15789d8b46c8SMichael Tuexen 	for (i = 0; i < len; i++)
15799d8b46c8SMichael Tuexen 		CRC32C(crc32c, buf[i]);
15809d8b46c8SMichael Tuexen 	crc32c = ~crc32c;
15819d8b46c8SMichael Tuexen 	byte0  = crc32c & 0xff;
15829d8b46c8SMichael Tuexen 	byte1  = (crc32c>>8) & 0xff;
15839d8b46c8SMichael Tuexen 	byte2  = (crc32c>>16) & 0xff;
15849d8b46c8SMichael Tuexen 	byte3  = (crc32c>>24) & 0xff;
15859d8b46c8SMichael Tuexen 	crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
15869d8b46c8SMichael Tuexen 	return htonl(crc32c);
15879d8b46c8SMichael Tuexen }
15889d8b46c8SMichael Tuexen 
15899d8b46c8SMichael Tuexen u_int16_t
15909d8b46c8SMichael Tuexen in_cksum(u_int16_t *addr, int len)
15919d8b46c8SMichael Tuexen {
15929d8b46c8SMichael Tuexen 	int nleft = len;
15939d8b46c8SMichael Tuexen 	u_int16_t *w = addr;
15949d8b46c8SMichael Tuexen 	u_int16_t answer;
15959d8b46c8SMichael Tuexen 	int sum = 0;
15969d8b46c8SMichael Tuexen 
15979d8b46c8SMichael Tuexen 	/*
15989d8b46c8SMichael Tuexen 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
15999d8b46c8SMichael Tuexen 	 *  we add sequential 16 bit words to it, and at the end, fold
16009d8b46c8SMichael Tuexen 	 *  back all the carry bits from the top 16 bits into the lower
16019d8b46c8SMichael Tuexen 	 *  16 bits.
16029d8b46c8SMichael Tuexen 	 */
16039d8b46c8SMichael Tuexen 	while (nleft > 1)  {
16049d8b46c8SMichael Tuexen 		sum += *w++;
16059d8b46c8SMichael Tuexen 		nleft -= 2;
16069d8b46c8SMichael Tuexen 	}
16079d8b46c8SMichael Tuexen 
16089d8b46c8SMichael Tuexen 	/* mop up an odd byte, if necessary */
16099d8b46c8SMichael Tuexen 	if (nleft == 1)
16109d8b46c8SMichael Tuexen 		sum += *(u_char *)w;
16119d8b46c8SMichael Tuexen 
16129d8b46c8SMichael Tuexen 	/*
16139d8b46c8SMichael Tuexen 	 * add back carry outs from top 16 bits to low 16 bits
16149d8b46c8SMichael Tuexen 	 */
16159d8b46c8SMichael Tuexen 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
16169d8b46c8SMichael Tuexen 	sum += (sum >> 16);			/* add carry */
16179d8b46c8SMichael Tuexen 	answer = ~sum;				/* truncate to 16 bits */
16189d8b46c8SMichael Tuexen 	return (answer);
16199d8b46c8SMichael Tuexen }
16209d8b46c8SMichael Tuexen 
16219d8b46c8SMichael Tuexen u_int16_t
16229d8b46c8SMichael Tuexen tcp_chksum(struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
16239d8b46c8SMichael Tuexen     void *payload, u_int32_t len)
16249d8b46c8SMichael Tuexen {
16259d8b46c8SMichael Tuexen 	struct {
16269d8b46c8SMichael Tuexen 		struct in6_addr src;
16279d8b46c8SMichael Tuexen 		struct in6_addr dst;
16289d8b46c8SMichael Tuexen 		u_int32_t len;
16299d8b46c8SMichael Tuexen 		u_int8_t zero[3];
16309d8b46c8SMichael Tuexen 		u_int8_t next;
16319d8b46c8SMichael Tuexen 	} pseudo_hdr;
16329d8b46c8SMichael Tuexen 	u_int16_t sum[2];
16339d8b46c8SMichael Tuexen 
16349d8b46c8SMichael Tuexen 	pseudo_hdr.src = src->sin6_addr;
16359d8b46c8SMichael Tuexen 	pseudo_hdr.dst = dst->sin6_addr;
16369d8b46c8SMichael Tuexen 	pseudo_hdr.len = htonl(len);
16379d8b46c8SMichael Tuexen 	pseudo_hdr.zero[0] = 0;
16389d8b46c8SMichael Tuexen 	pseudo_hdr.zero[1] = 0;
16399d8b46c8SMichael Tuexen 	pseudo_hdr.zero[2] = 0;
16409d8b46c8SMichael Tuexen 	pseudo_hdr.next = IPPROTO_TCP;
16419d8b46c8SMichael Tuexen 
16429d8b46c8SMichael Tuexen 	sum[1] = in_cksum((u_int16_t *)&pseudo_hdr, sizeof(pseudo_hdr));
16439d8b46c8SMichael Tuexen 	sum[0] = in_cksum(payload, len);
16449d8b46c8SMichael Tuexen 
16459d8b46c8SMichael Tuexen 	return (~in_cksum(sum, sizeof(sum)));
16469d8b46c8SMichael Tuexen }
16479d8b46c8SMichael Tuexen 
16487d56d374SYoshinobu Inoue void
1649aa96470cSMichael Tuexen usage(void)
16507d56d374SYoshinobu Inoue {
165184a1a4cfSHajimu UMEMOTO 
165284a1a4cfSHajimu UMEMOTO 	fprintf(stderr,
16539d8b46c8SMichael Tuexen "usage: traceroute6 [-adIlnNrSTUv] [-A as_server] [-f firsthop] [-g gateway]\n"
16540d7d117cSHajimu UMEMOTO "       [-m hoplimit] [-p port] [-q probes] [-s src] [-w waittime] target\n"
16550d7d117cSHajimu UMEMOTO "       [datalen]\n");
16567d56d374SYoshinobu Inoue 	exit(1);
16577d56d374SYoshinobu Inoue }
1658