xref: /freebsd/usr.sbin/traceroute6/traceroute6.c (revision ca19d0d78facb69c0776cff80f59aa3f07db9613)
1e961704aSDavid Malone /*	$KAME: traceroute6.c,v 1.68 2004/01/25 11:16:12 suz Exp $	*/
2de68a0daSKris Kennaway 
38a16b7a1SPedro F. Giffuni /*-
48a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
58a16b7a1SPedro F. Giffuni  *
67d56d374SYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
77d56d374SYoshinobu Inoue  * All rights reserved.
87d56d374SYoshinobu Inoue  *
97d56d374SYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
107d56d374SYoshinobu Inoue  * modification, are permitted provided that the following conditions
117d56d374SYoshinobu Inoue  * are met:
127d56d374SYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
137d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
147d56d374SYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
157d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
167d56d374SYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
177d56d374SYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
187d56d374SYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
197d56d374SYoshinobu Inoue  *    without specific prior written permission.
207d56d374SYoshinobu Inoue  *
217d56d374SYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
227d56d374SYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
237d56d374SYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
247d56d374SYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
257d56d374SYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
267d56d374SYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
277d56d374SYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
287d56d374SYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
297d56d374SYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
307d56d374SYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
317d56d374SYoshinobu Inoue  * SUCH DAMAGE.
327d56d374SYoshinobu Inoue  */
337d56d374SYoshinobu Inoue 
347d56d374SYoshinobu Inoue /*-
357d56d374SYoshinobu Inoue  * Copyright (c) 1990, 1993
367d56d374SYoshinobu Inoue  *	The Regents of the University of California.  All rights reserved.
377d56d374SYoshinobu Inoue  *
387d56d374SYoshinobu Inoue  * This code is derived from software contributed to Berkeley by
397d56d374SYoshinobu Inoue  * Van Jacobson.
407d56d374SYoshinobu Inoue  *
417d56d374SYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
427d56d374SYoshinobu Inoue  * modification, are permitted provided that the following conditions
437d56d374SYoshinobu Inoue  * are met:
447d56d374SYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
457d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
467d56d374SYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
477d56d374SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
487d56d374SYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
49fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
507d56d374SYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
517d56d374SYoshinobu Inoue  *    without specific prior written permission.
527d56d374SYoshinobu Inoue  *
537d56d374SYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
547d56d374SYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
557d56d374SYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
567d56d374SYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
577d56d374SYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
587d56d374SYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
597d56d374SYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
607d56d374SYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
617d56d374SYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
627d56d374SYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
637d56d374SYoshinobu Inoue  * SUCH DAMAGE.
647d56d374SYoshinobu Inoue  */
657d56d374SYoshinobu Inoue 
667d56d374SYoshinobu Inoue #ifndef lint
67f42640a3SUlrich Spörlein static const char copyright[] =
687d56d374SYoshinobu Inoue "@(#) Copyright (c) 1990, 1993\n\
697d56d374SYoshinobu Inoue 	The Regents of the University of California.  All rights reserved.\n";
707d56d374SYoshinobu Inoue #endif /* not lint */
717d56d374SYoshinobu Inoue 
727d56d374SYoshinobu Inoue #ifndef lint
73de68a0daSKris Kennaway #if 0
747d56d374SYoshinobu Inoue static char sccsid[] = "@(#)traceroute.c	8.1 (Berkeley) 6/6/93";
75de68a0daSKris Kennaway #endif
76de68a0daSKris Kennaway static const char rcsid[] =
77de68a0daSKris Kennaway   "$FreeBSD$";
787d56d374SYoshinobu Inoue #endif /* not lint */
797d56d374SYoshinobu Inoue 
807d56d374SYoshinobu Inoue /*
817d56d374SYoshinobu Inoue  * traceroute host  - trace the route ip packets follow going to "host".
827d56d374SYoshinobu Inoue  *
837d56d374SYoshinobu Inoue  * Attempt to trace the route an ip packet would follow to some
847d56d374SYoshinobu Inoue  * internet host.  We find out intermediate hops by launching probe
857d56d374SYoshinobu Inoue  * packets with a small ttl (time to live) then listening for an
867d56d374SYoshinobu Inoue  * icmp "time exceeded" reply from a gateway.  We start our probes
877d56d374SYoshinobu Inoue  * with a ttl of one and increase by one until we get an icmp "port
887d56d374SYoshinobu Inoue  * unreachable" (which means we got to "host") or hit a max (which
897d56d374SYoshinobu Inoue  * defaults to 30 hops & can be changed with the -m flag).  Three
907d56d374SYoshinobu Inoue  * probes (change with -q flag) are sent at each ttl setting and a
917d56d374SYoshinobu Inoue  * line is printed showing the ttl, address of the gateway and
927d56d374SYoshinobu Inoue  * round trip time of each probe.  If the probe answers come from
937d56d374SYoshinobu Inoue  * different gateways, the address of each responding system will
947d56d374SYoshinobu Inoue  * be printed.  If there is no response within a 5 sec. timeout
957d56d374SYoshinobu Inoue  * interval (changed with the -w flag), a "*" is printed for that
967d56d374SYoshinobu Inoue  * probe.
977d56d374SYoshinobu Inoue  *
987d56d374SYoshinobu Inoue  * Probe packets are UDP format.  We don't want the destination
997d56d374SYoshinobu Inoue  * host to process them so the destination port is set to an
1007d56d374SYoshinobu Inoue  * unlikely value (if some clod on the destination is using that
1017d56d374SYoshinobu Inoue  * value, it can be changed with the -p flag).
1027d56d374SYoshinobu Inoue  *
1037d56d374SYoshinobu Inoue  * A sample use might be:
1047d56d374SYoshinobu Inoue  *
1057d56d374SYoshinobu Inoue  *     [yak 71]% traceroute nis.nsf.net.
1067d56d374SYoshinobu Inoue  *     traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
1077d56d374SYoshinobu Inoue  *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
1087d56d374SYoshinobu Inoue  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
1097d56d374SYoshinobu Inoue  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
1107d56d374SYoshinobu Inoue  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
1117d56d374SYoshinobu Inoue  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
1127d56d374SYoshinobu Inoue  *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
1137d56d374SYoshinobu Inoue  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
1147d56d374SYoshinobu Inoue  *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
1157d56d374SYoshinobu Inoue  *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
1167d56d374SYoshinobu Inoue  *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
1177d56d374SYoshinobu Inoue  *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
1187d56d374SYoshinobu Inoue  *
1197d56d374SYoshinobu Inoue  * Note that lines 2 & 3 are the same.  This is due to a buggy
1207d56d374SYoshinobu Inoue  * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
1217d56d374SYoshinobu Inoue  * packets with a zero ttl.
1227d56d374SYoshinobu Inoue  *
1237d56d374SYoshinobu Inoue  * A more interesting example is:
1247d56d374SYoshinobu Inoue  *
1257d56d374SYoshinobu Inoue  *     [yak 72]% traceroute allspice.lcs.mit.edu.
1267d56d374SYoshinobu Inoue  *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
1277d56d374SYoshinobu Inoue  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
1287d56d374SYoshinobu Inoue  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
1297d56d374SYoshinobu Inoue  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
1307d56d374SYoshinobu Inoue  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
1317d56d374SYoshinobu Inoue  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
1327d56d374SYoshinobu Inoue  *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
1337d56d374SYoshinobu Inoue  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
1347d56d374SYoshinobu Inoue  *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
1357d56d374SYoshinobu Inoue  *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
1367d56d374SYoshinobu Inoue  *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
1377d56d374SYoshinobu Inoue  *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
1387d56d374SYoshinobu Inoue  *     12  * * *
1397d56d374SYoshinobu Inoue  *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
1407d56d374SYoshinobu Inoue  *     14  * * *
1417d56d374SYoshinobu Inoue  *     15  * * *
1427d56d374SYoshinobu Inoue  *     16  * * *
1437d56d374SYoshinobu Inoue  *     17  * * *
1447d56d374SYoshinobu Inoue  *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
1457d56d374SYoshinobu Inoue  *
1467d56d374SYoshinobu Inoue  * (I start to see why I'm having so much trouble with mail to
1477d56d374SYoshinobu Inoue  * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
1487d56d374SYoshinobu Inoue  * either don't send ICMP "time exceeded" messages or send them
1497d56d374SYoshinobu Inoue  * with a ttl too small to reach us.  14 - 17 are running the
1507d56d374SYoshinobu Inoue  * MIT C Gateway code that doesn't send "time exceeded"s.  God
1517d56d374SYoshinobu Inoue  * only knows what's going on with 12.
1527d56d374SYoshinobu Inoue  *
1537d56d374SYoshinobu Inoue  * The silent gateway 12 in the above may be the result of a bug in
1547d56d374SYoshinobu Inoue  * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
1557d56d374SYoshinobu Inoue  * sends an unreachable message using whatever ttl remains in the
1567d56d374SYoshinobu Inoue  * original datagram.  Since, for gateways, the remaining ttl is
1577d56d374SYoshinobu Inoue  * zero, the icmp "time exceeded" is guaranteed to not make it back
1587d56d374SYoshinobu Inoue  * to us.  The behavior of this bug is slightly more interesting
1597d56d374SYoshinobu Inoue  * when it appears on the destination system:
1607d56d374SYoshinobu Inoue  *
1617d56d374SYoshinobu Inoue  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
1627d56d374SYoshinobu Inoue  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
1637d56d374SYoshinobu Inoue  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
1647d56d374SYoshinobu Inoue  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
1657d56d374SYoshinobu Inoue  *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
1667d56d374SYoshinobu Inoue  *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
1677d56d374SYoshinobu Inoue  *      7  * * *
1687d56d374SYoshinobu Inoue  *      8  * * *
1697d56d374SYoshinobu Inoue  *      9  * * *
1707d56d374SYoshinobu Inoue  *     10  * * *
1717d56d374SYoshinobu Inoue  *     11  * * *
1727d56d374SYoshinobu Inoue  *     12  * * *
1737d56d374SYoshinobu Inoue  *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
1747d56d374SYoshinobu Inoue  *
1757d56d374SYoshinobu Inoue  * Notice that there are 12 "gateways" (13 is the final
1767d56d374SYoshinobu Inoue  * destination) and exactly the last half of them are "missing".
1777d56d374SYoshinobu Inoue  * What's really happening is that rip (a Sun-3 running Sun OS3.5)
1787d56d374SYoshinobu Inoue  * is using the ttl from our arriving datagram as the ttl in its
1797d56d374SYoshinobu Inoue  * icmp reply.  So, the reply will time out on the return path
1807d56d374SYoshinobu Inoue  * (with no notice sent to anyone since icmp's aren't sent for
1817d56d374SYoshinobu Inoue  * icmp's) until we probe with a ttl that's at least twice the path
1827d56d374SYoshinobu Inoue  * length.  I.e., rip is really only 7 hops away.  A reply that
1837d56d374SYoshinobu Inoue  * returns with a ttl of 1 is a clue this problem exists.
1847d56d374SYoshinobu Inoue  * Traceroute prints a "!" after the time if the ttl is <= 1.
1857d56d374SYoshinobu Inoue  * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
1867d56d374SYoshinobu Inoue  * non-standard (HPUX) software, expect to see this problem
1877d56d374SYoshinobu Inoue  * frequently and/or take care picking the target host of your
1887d56d374SYoshinobu Inoue  * probes.
1897d56d374SYoshinobu Inoue  *
1907d56d374SYoshinobu Inoue  * Other possible annotations after the time are !H, !N, !P (got a host,
1917d56d374SYoshinobu Inoue  * network or protocol unreachable, respectively), !S or !F (source
1927d56d374SYoshinobu Inoue  * route failed or fragmentation needed -- neither of these should
1937d56d374SYoshinobu Inoue  * ever occur and the associated gateway is busted if you see one).  If
1947d56d374SYoshinobu Inoue  * almost all the probes result in some kind of unreachable, traceroute
1957d56d374SYoshinobu Inoue  * will give up and exit.
1967d56d374SYoshinobu Inoue  *
1977d56d374SYoshinobu Inoue  * Notes
1987d56d374SYoshinobu Inoue  * -----
1997d56d374SYoshinobu Inoue  * This program must be run by root or be setuid.  (I suggest that
2007d56d374SYoshinobu Inoue  * you *don't* make it setuid -- casual use could result in a lot
2017d56d374SYoshinobu Inoue  * of unnecessary traffic on our poor, congested nets.)
2027d56d374SYoshinobu Inoue  *
2037d56d374SYoshinobu Inoue  * This program requires a kernel mod that does not appear in any
2047d56d374SYoshinobu Inoue  * system available from Berkeley:  A raw ip socket using proto
2057d56d374SYoshinobu Inoue  * IPPROTO_RAW must interpret the data sent as an ip datagram (as
2069d5abbddSJens Schweikhardt  * opposed to data to be wrapped in an ip datagram).  See the README
2077d56d374SYoshinobu Inoue  * file that came with the source to this program for a description
2087d56d374SYoshinobu Inoue  * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
2097d56d374SYoshinobu Inoue  * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
2107d56d374SYoshinobu Inoue  * MODIFIED TO RUN THIS PROGRAM.
2117d56d374SYoshinobu Inoue  *
2127d56d374SYoshinobu Inoue  * The udp port usage may appear bizarre (well, ok, it is bizarre).
2137d56d374SYoshinobu Inoue  * The problem is that an icmp message only contains 8 bytes of
2147d56d374SYoshinobu Inoue  * data from the original datagram.  8 bytes is the size of a udp
2157d56d374SYoshinobu Inoue  * header so, if we want to associate replies with the original
2167d56d374SYoshinobu Inoue  * datagram, the necessary information must be encoded into the
2177d56d374SYoshinobu Inoue  * udp header (the ip id could be used but there's no way to
2187d56d374SYoshinobu Inoue  * interlock with the kernel's assignment of ip id's and, anyway,
2197d56d374SYoshinobu Inoue  * it would have taken a lot more kernel hacking to allow this
2207d56d374SYoshinobu Inoue  * code to set the ip id).  So, to allow two or more users to
2217d56d374SYoshinobu Inoue  * use traceroute simultaneously, we use this task's pid as the
2227d56d374SYoshinobu Inoue  * source port (the high bit is set to move the port number out
2237d56d374SYoshinobu Inoue  * of the "likely" range).  To keep track of which probe is being
2247d56d374SYoshinobu Inoue  * replied to (so times and/or hop counts don't get confused by a
2257d56d374SYoshinobu Inoue  * reply that was delayed in transit), we increment the destination
2267d56d374SYoshinobu Inoue  * port number before each probe.
2277d56d374SYoshinobu Inoue  *
2287d56d374SYoshinobu Inoue  * Don't use this as a coding example.  I was trying to find a
2297d56d374SYoshinobu Inoue  * routing problem and this code sort-of popped out after 48 hours
2307d56d374SYoshinobu Inoue  * without sleep.  I was amazed it ever compiled, much less ran.
2317d56d374SYoshinobu Inoue  *
2327d56d374SYoshinobu Inoue  * I stole the idea for this program from Steve Deering.  Since
2337d56d374SYoshinobu Inoue  * the first release, I've learned that had I attended the right
2347d56d374SYoshinobu Inoue  * IETF working group meetings, I also could have stolen it from Guy
2357d56d374SYoshinobu Inoue  * Almes or Matt Mathis.  I don't know (or care) who came up with
2367d56d374SYoshinobu Inoue  * the idea first.  I envy the originators' perspicacity and I'm
2377d56d374SYoshinobu Inoue  * glad they didn't keep the idea a secret.
2387d56d374SYoshinobu Inoue  *
2397d56d374SYoshinobu Inoue  * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
2407d56d374SYoshinobu Inoue  * enhancements to the original distribution.
2417d56d374SYoshinobu Inoue  *
2427d56d374SYoshinobu Inoue  * I've hacked up a round-trip-route version of this that works by
2437d56d374SYoshinobu Inoue  * sending a loose-source-routed udp datagram through the destination
2447d56d374SYoshinobu Inoue  * back to yourself.  Unfortunately, SO many gateways botch source
2457d56d374SYoshinobu Inoue  * routing, the thing is almost worthless.  Maybe one day...
2467d56d374SYoshinobu Inoue  *
2477d56d374SYoshinobu Inoue  *  -- Van Jacobson (van@helios.ee.lbl.gov)
2487d56d374SYoshinobu Inoue  *     Tue Dec 20 03:50:13 PST 1988
2497d56d374SYoshinobu Inoue  */
2507d56d374SYoshinobu Inoue 
2517d56d374SYoshinobu Inoue #include <sys/param.h>
2527d56d374SYoshinobu Inoue #include <sys/time.h>
2537d56d374SYoshinobu Inoue #include <sys/socket.h>
2547d56d374SYoshinobu Inoue #include <sys/uio.h>
2557d56d374SYoshinobu Inoue #include <sys/file.h>
2567d56d374SYoshinobu Inoue #include <sys/ioctl.h>
25784a1a4cfSHajimu UMEMOTO #include <sys/sysctl.h>
2587d56d374SYoshinobu Inoue 
2597d56d374SYoshinobu Inoue #include <netinet/in.h>
2607d56d374SYoshinobu Inoue 
2617d56d374SYoshinobu Inoue #include <arpa/inet.h>
2627d56d374SYoshinobu Inoue 
2637d56d374SYoshinobu Inoue #include <netdb.h>
2647d56d374SYoshinobu Inoue #include <stdio.h>
2657d56d374SYoshinobu Inoue #include <err.h>
2662a1c5efaSKris Kennaway #ifdef HAVE_POLL
2672a1c5efaSKris Kennaway #include <poll.h>
2682a1c5efaSKris Kennaway #endif
2697d56d374SYoshinobu Inoue #include <errno.h>
2707d56d374SYoshinobu Inoue #include <stdlib.h>
2717d56d374SYoshinobu Inoue #include <string.h>
2727d56d374SYoshinobu Inoue #include <unistd.h>
2737d56d374SYoshinobu Inoue 
2747d56d374SYoshinobu Inoue #include <netinet/ip6.h>
2757d56d374SYoshinobu Inoue #include <netinet/icmp6.h>
2769d8b46c8SMichael Tuexen #include <netinet/sctp.h>
27751eff8efSMichael Tuexen #include <netinet/sctp_header.h>
2789d8b46c8SMichael Tuexen #include <netinet/tcp.h>
2797d56d374SYoshinobu Inoue #include <netinet/udp.h>
2807d56d374SYoshinobu Inoue 
2817d56d374SYoshinobu Inoue #ifdef IPSEC
2827d56d374SYoshinobu Inoue #include <net/route.h>
2838409aedfSGeorge V. Neville-Neil #include <netipsec/ipsec.h>
2847d56d374SYoshinobu Inoue #endif
2857d56d374SYoshinobu Inoue 
286d429d720SHajimu UMEMOTO #include "as.h"
287d429d720SHajimu UMEMOTO 
2887d56d374SYoshinobu Inoue #define DUMMY_PORT 10010
2897d56d374SYoshinobu Inoue 
2907d56d374SYoshinobu Inoue #define	MAXPACKET	65535	/* max ip packet size */
2917d56d374SYoshinobu Inoue 
292de68a0daSKris Kennaway #ifndef HAVE_GETIPNODEBYNAME
293de68a0daSKris Kennaway #define getipnodebyname(x, y, z, u)	gethostbyname2((x), (y))
294de68a0daSKris Kennaway #define freehostent(x)
295de68a0daSKris Kennaway #endif
296de68a0daSKris Kennaway 
297*ca19d0d7SMark Johnston static u_char	packet[512];		/* last inbound (icmp) packet */
298*ca19d0d7SMark Johnston static char 	*outpacket;		/* last output packet */
2997d56d374SYoshinobu Inoue 
300784bddbcSKevin Lo int	main(int, char *[]);
301784bddbcSKevin Lo int	wait_for_reply(int, struct msghdr *);
302*ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
303784bddbcSKevin Lo int	setpolicy(int so, char *policy);
304de68a0daSKris Kennaway #endif
305784bddbcSKevin Lo void	send_probe(int, u_long);
306d7b63fafSDavid Malone void	*get_uphdr(struct ip6_hdr *, u_char *);
307784bddbcSKevin Lo int	get_hoplim(struct msghdr *);
308784bddbcSKevin Lo double	deltaT(struct timeval *, struct timeval *);
309f42640a3SUlrich Spörlein const char *pr_type(int);
31064694fdcSMichael Tuexen int	packet_ok(struct msghdr *, int, int, u_char *, u_char *);
311784bddbcSKevin Lo void	print(struct msghdr *, int);
312784bddbcSKevin Lo const char *inetname(struct sockaddr *);
3139d8b46c8SMichael Tuexen u_int32_t sctp_crc32c(void *, u_int32_t);
3149d8b46c8SMichael Tuexen u_int16_t in_cksum(u_int16_t *addr, int);
3159d8b46c8SMichael Tuexen u_int16_t tcp_chksum(struct sockaddr_in6 *, struct sockaddr_in6 *,
3169d8b46c8SMichael Tuexen     void *, u_int32_t);
317784bddbcSKevin Lo void	usage(void);
3187d56d374SYoshinobu Inoue 
319*ca19d0d7SMark Johnston static int rcvsock;			/* receive (icmp) socket file descriptor */
320*ca19d0d7SMark Johnston static int sndsock;			/* send (raw/udp) socket file descriptor */
3217d56d374SYoshinobu Inoue 
322*ca19d0d7SMark Johnston static struct msghdr rcvmhdr;
323*ca19d0d7SMark Johnston static struct iovec rcviov[2];
324*ca19d0d7SMark Johnston static int rcvhlim;
325*ca19d0d7SMark Johnston static struct in6_pktinfo *rcvpktinfo;
3267d56d374SYoshinobu Inoue 
327*ca19d0d7SMark Johnston static struct sockaddr_in6 Src, Dst, Rcv;
328*ca19d0d7SMark Johnston static u_long datalen = 20;			/* How much data */
32984a1a4cfSHajimu UMEMOTO #define	ICMP6ECHOLEN	8
330de68a0daSKris Kennaway /* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */
331*ca19d0d7SMark Johnston static char rtbuf[2064];
332*ca19d0d7SMark Johnston static struct ip6_rthdr *rth;
333*ca19d0d7SMark Johnston static struct cmsghdr *cmsg;
3347d56d374SYoshinobu Inoue 
335*ca19d0d7SMark Johnston static char *source = NULL;
336*ca19d0d7SMark Johnston static char *hostname;
3377d56d374SYoshinobu Inoue 
338*ca19d0d7SMark Johnston static u_long nprobes = 3;
339*ca19d0d7SMark Johnston static u_long first_hop = 1;
340*ca19d0d7SMark Johnston static u_long max_hops = 30;
341*ca19d0d7SMark Johnston static u_int16_t srcport;
342*ca19d0d7SMark Johnston static u_int16_t port = 32768+666;	/* start udp dest port # for probe packets */
343*ca19d0d7SMark Johnston static u_int16_t ident;
344*ca19d0d7SMark Johnston static int options;			/* socket options */
345*ca19d0d7SMark Johnston static int verbose;
346*ca19d0d7SMark Johnston static int waittime = 5;		/* time to wait for response (in seconds) */
347*ca19d0d7SMark Johnston static int nflag;			/* print addresses numerically */
348*ca19d0d7SMark Johnston static int useproto = IPPROTO_UDP;	/* protocol to use to send packet */
349*ca19d0d7SMark Johnston static int lflag;			/* print both numerical address & hostname */
350*ca19d0d7SMark Johnston static int as_path;			/* print as numbers for each hop */
351*ca19d0d7SMark Johnston static char *as_server = NULL;
352*ca19d0d7SMark Johnston static void *asn;
3537d56d374SYoshinobu Inoue 
3547d56d374SYoshinobu Inoue int
355aa96470cSMichael Tuexen main(int argc, char *argv[])
3567d56d374SYoshinobu Inoue {
35784a1a4cfSHajimu UMEMOTO 	int mib[4] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM };
358e961704aSDavid Malone 	char hbuf[NI_MAXHOST], src0[NI_MAXHOST], *ep;
359f42640a3SUlrich Spörlein 	int ch, i, on = 1, seq, rcvcmsglen, error;
360e961704aSDavid Malone 	struct addrinfo hints, *res;
361e961704aSDavid Malone 	static u_char *rcvcmsgbuf;
362e961704aSDavid Malone 	u_long probe, hops, lport;
363e961704aSDavid Malone 	struct hostent *hp;
364f42640a3SUlrich Spörlein 	size_t size, minlen;
36519c7ed84SKevin Lo 	uid_t uid;
36664694fdcSMichael Tuexen 	u_char type, code;
367*ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
368*ca19d0d7SMark Johnston 	char ipsec_inpolicy[] = "in bypass";
369*ca19d0d7SMark Johnston 	char ipsec_outpolicy[] = "out bypass";
370*ca19d0d7SMark Johnston #endif
3717d56d374SYoshinobu Inoue 
37253c9088fSYoshinobu Inoue 	/*
37353c9088fSYoshinobu Inoue 	 * Receive ICMP
37453c9088fSYoshinobu Inoue 	 */
37553c9088fSYoshinobu Inoue 	if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
376de68a0daSKris Kennaway 		perror("socket(ICMPv6)");
37753c9088fSYoshinobu Inoue 		exit(5);
37853c9088fSYoshinobu Inoue 	}
379de68a0daSKris Kennaway 
38084a1a4cfSHajimu UMEMOTO 	size = sizeof(i);
38184a1a4cfSHajimu UMEMOTO 	(void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &i, &size, NULL, 0);
38284a1a4cfSHajimu UMEMOTO 	max_hops = i;
38384a1a4cfSHajimu UMEMOTO 
384de68a0daSKris Kennaway 	/* specify to tell receiving interface */
385de68a0daSKris Kennaway #ifdef IPV6_RECVPKTINFO
386de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
387de68a0daSKris Kennaway 	    sizeof(on)) < 0)
388de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_RECVPKTINFO)");
389de68a0daSKris Kennaway #else  /* old adv. API */
390de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
391de68a0daSKris Kennaway 	    sizeof(on)) < 0)
392de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_PKTINFO)");
393de68a0daSKris Kennaway #endif
394de68a0daSKris Kennaway 
395de68a0daSKris Kennaway 	/* specify to tell value of hoplimit field of received IP6 hdr */
396de68a0daSKris Kennaway #ifdef IPV6_RECVHOPLIMIT
397de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
398de68a0daSKris Kennaway 	    sizeof(on)) < 0)
399de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_RECVHOPLIMIT)");
400de68a0daSKris Kennaway #else  /* old adv. API */
401de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
402de68a0daSKris Kennaway 	    sizeof(on)) < 0)
403de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_HOPLIMIT)");
404de68a0daSKris Kennaway #endif
405de68a0daSKris Kennaway 
4067d56d374SYoshinobu Inoue 	seq = 0;
4079d8b46c8SMichael Tuexen 	ident = htons(getpid() & 0xffff); /* same as ping6 */
4087d56d374SYoshinobu Inoue 
4099d8b46c8SMichael Tuexen 	while ((ch = getopt(argc, argv, "aA:df:g:Ilm:nNp:q:rs:STUvw:")) != -1)
4107d56d374SYoshinobu Inoue 		switch (ch) {
411d429d720SHajimu UMEMOTO 		case 'a':
412d429d720SHajimu UMEMOTO 			as_path = 1;
413d429d720SHajimu UMEMOTO 			break;
414d429d720SHajimu UMEMOTO 		case 'A':
415d429d720SHajimu UMEMOTO 			as_path = 1;
416d429d720SHajimu UMEMOTO 			as_server = optarg;
417d429d720SHajimu UMEMOTO 			break;
4187d56d374SYoshinobu Inoue 		case 'd':
4197d56d374SYoshinobu Inoue 			options |= SO_DEBUG;
4207d56d374SYoshinobu Inoue 			break;
421de68a0daSKris Kennaway 		case 'f':
42233841545SHajimu UMEMOTO 			ep = NULL;
42384a1a4cfSHajimu UMEMOTO 			errno = 0;
42433841545SHajimu UMEMOTO 			first_hop = strtoul(optarg, &ep, 0);
42584a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep || first_hop > 255) {
426c449e284SHajimu UMEMOTO 				fprintf(stderr,
42733841545SHajimu UMEMOTO 				    "traceroute6: invalid min hoplimit.\n");
42833841545SHajimu UMEMOTO 				exit(1);
42933841545SHajimu UMEMOTO 			}
4307d56d374SYoshinobu Inoue 			break;
4317d56d374SYoshinobu Inoue 		case 'g':
4327d56d374SYoshinobu Inoue 			hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno);
4337d56d374SYoshinobu Inoue 			if (hp == NULL) {
434c449e284SHajimu UMEMOTO 				fprintf(stderr,
4357d56d374SYoshinobu Inoue 				    "traceroute6: unknown host %s\n", optarg);
4367d56d374SYoshinobu Inoue 				exit(1);
4377d56d374SYoshinobu Inoue 			}
438de68a0daSKris Kennaway 			if (rth == NULL) {
439de68a0daSKris Kennaway 				/*
440de68a0daSKris Kennaway 				 * XXX: We can't detect the number of
441de68a0daSKris Kennaway 				 * intermediate nodes yet.
442de68a0daSKris Kennaway 				 */
443de68a0daSKris Kennaway 				if ((rth = inet6_rth_init((void *)rtbuf,
444c449e284SHajimu UMEMOTO 				    sizeof(rtbuf), IPV6_RTHDR_TYPE_0,
445de68a0daSKris Kennaway 				    0)) == NULL) {
446c449e284SHajimu UMEMOTO 					fprintf(stderr,
447de68a0daSKris Kennaway 					    "inet6_rth_init failed.\n");
448de68a0daSKris Kennaway 					exit(1);
449de68a0daSKris Kennaway 				}
450de68a0daSKris Kennaway 			}
451de68a0daSKris Kennaway 			if (inet6_rth_add((void *)rth,
452de68a0daSKris Kennaway 			    (struct in6_addr *)hp->h_addr)) {
453c449e284SHajimu UMEMOTO 				fprintf(stderr,
454de68a0daSKris Kennaway 				    "inet6_rth_add failed for %s\n",
455de68a0daSKris Kennaway 				    optarg);
456de68a0daSKris Kennaway 				exit(1);
457de68a0daSKris Kennaway 			}
458de68a0daSKris Kennaway 			freehostent(hp);
459de68a0daSKris Kennaway 			break;
46084a1a4cfSHajimu UMEMOTO 		case 'I':
461d7b63fafSDavid Malone 			useproto = IPPROTO_ICMPV6;
46284a1a4cfSHajimu UMEMOTO 			break;
463de68a0daSKris Kennaway 		case 'l':
464de68a0daSKris Kennaway 			lflag++;
4657d56d374SYoshinobu Inoue 			break;
4667d56d374SYoshinobu Inoue 		case 'm':
46733841545SHajimu UMEMOTO 			ep = NULL;
46884a1a4cfSHajimu UMEMOTO 			errno = 0;
46933841545SHajimu UMEMOTO 			max_hops = strtoul(optarg, &ep, 0);
47084a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep || max_hops > 255) {
471c449e284SHajimu UMEMOTO 				fprintf(stderr,
47233841545SHajimu UMEMOTO 				    "traceroute6: invalid max hoplimit.\n");
47333841545SHajimu UMEMOTO 				exit(1);
47433841545SHajimu UMEMOTO 			}
4757d56d374SYoshinobu Inoue 			break;
4767d56d374SYoshinobu Inoue 		case 'n':
4777d56d374SYoshinobu Inoue 			nflag++;
4787d56d374SYoshinobu Inoue 			break;
479d7b63fafSDavid Malone 		case 'N':
480d7b63fafSDavid Malone 			useproto = IPPROTO_NONE;
481d7b63fafSDavid Malone 			break;
4827d56d374SYoshinobu Inoue 		case 'p':
48333841545SHajimu UMEMOTO 			ep = NULL;
48484a1a4cfSHajimu UMEMOTO 			errno = 0;
48584a1a4cfSHajimu UMEMOTO 			lport = strtoul(optarg, &ep, 0);
48684a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep) {
48784a1a4cfSHajimu UMEMOTO 				fprintf(stderr, "traceroute6: invalid port.\n");
48833841545SHajimu UMEMOTO 				exit(1);
48933841545SHajimu UMEMOTO 			}
49084a1a4cfSHajimu UMEMOTO 			if (lport == 0 || lport != (lport & 0xffff)) {
491c449e284SHajimu UMEMOTO 				fprintf(stderr,
49284a1a4cfSHajimu UMEMOTO 				    "traceroute6: port out of range.\n");
4937d56d374SYoshinobu Inoue 				exit(1);
4947d56d374SYoshinobu Inoue 			}
49584a1a4cfSHajimu UMEMOTO 			port = lport & 0xffff;
4967d56d374SYoshinobu Inoue 			break;
4977d56d374SYoshinobu Inoue 		case 'q':
49833841545SHajimu UMEMOTO 			ep = NULL;
49984a1a4cfSHajimu UMEMOTO 			errno = 0;
50033841545SHajimu UMEMOTO 			nprobes = strtoul(optarg, &ep, 0);
50184a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep) {
502c449e284SHajimu UMEMOTO 				fprintf(stderr,
50333841545SHajimu UMEMOTO 				    "traceroute6: invalid nprobes.\n");
50433841545SHajimu UMEMOTO 				exit(1);
50533841545SHajimu UMEMOTO 			}
5067d56d374SYoshinobu Inoue 			if (nprobes < 1) {
507c449e284SHajimu UMEMOTO 				fprintf(stderr,
5087d56d374SYoshinobu Inoue 				    "traceroute6: nprobes must be >0.\n");
5097d56d374SYoshinobu Inoue 				exit(1);
5107d56d374SYoshinobu Inoue 			}
5117d56d374SYoshinobu Inoue 			break;
5127d56d374SYoshinobu Inoue 		case 'r':
5137d56d374SYoshinobu Inoue 			options |= SO_DONTROUTE;
5147d56d374SYoshinobu Inoue 			break;
5157d56d374SYoshinobu Inoue 		case 's':
5167d56d374SYoshinobu Inoue 			/*
5177d56d374SYoshinobu Inoue 			 * set the ip source address of the outbound
5187d56d374SYoshinobu Inoue 			 * probe (e.g., on a multi-homed host).
5197d56d374SYoshinobu Inoue 			 */
5207d56d374SYoshinobu Inoue 			source = optarg;
5217d56d374SYoshinobu Inoue 			break;
5229d8b46c8SMichael Tuexen 		case 'S':
5239d8b46c8SMichael Tuexen 			useproto = IPPROTO_SCTP;
5249d8b46c8SMichael Tuexen 			break;
5259d8b46c8SMichael Tuexen 		case 'T':
5269d8b46c8SMichael Tuexen 			useproto = IPPROTO_TCP;
5279d8b46c8SMichael Tuexen 			break;
528d7b63fafSDavid Malone 		case 'U':
529d7b63fafSDavid Malone 			useproto = IPPROTO_UDP;
530d7b63fafSDavid Malone 			break;
531aa96470cSMichael Tuexen 		case 'v':
532aa96470cSMichael Tuexen 			verbose++;
533aa96470cSMichael Tuexen 			break;
5347d56d374SYoshinobu Inoue 		case 'w':
53533841545SHajimu UMEMOTO 			ep = NULL;
53684a1a4cfSHajimu UMEMOTO 			errno = 0;
53733841545SHajimu UMEMOTO 			waittime = strtoul(optarg, &ep, 0);
53884a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep) {
539c449e284SHajimu UMEMOTO 				fprintf(stderr,
54033841545SHajimu UMEMOTO 				    "traceroute6: invalid wait time.\n");
54133841545SHajimu UMEMOTO 				exit(1);
54233841545SHajimu UMEMOTO 			}
543eea319c4SMaxim Konovalov 			if (waittime < 1) {
544c449e284SHajimu UMEMOTO 				fprintf(stderr,
545eea319c4SMaxim Konovalov 				    "traceroute6: wait must be >= 1 sec.\n");
5467d56d374SYoshinobu Inoue 				exit(1);
5477d56d374SYoshinobu Inoue 			}
5487d56d374SYoshinobu Inoue 			break;
5497d56d374SYoshinobu Inoue 		default:
5507d56d374SYoshinobu Inoue 			usage();
5517d56d374SYoshinobu Inoue 		}
5527d56d374SYoshinobu Inoue 	argc -= optind;
5537d56d374SYoshinobu Inoue 	argv += optind;
5547d56d374SYoshinobu Inoue 
555d7b63fafSDavid Malone 	/*
556d7b63fafSDavid Malone 	 * Open socket to send probe packets.
557d7b63fafSDavid Malone 	 */
558d7b63fafSDavid Malone 	switch (useproto) {
559d7b63fafSDavid Malone 	case IPPROTO_ICMPV6:
560d7b63fafSDavid Malone 		sndsock = rcvsock;
561d7b63fafSDavid Malone 		break;
562d7b63fafSDavid Malone 	case IPPROTO_UDP:
563d7b63fafSDavid Malone 		if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
564d7b63fafSDavid Malone 			perror("socket(SOCK_DGRAM)");
565d7b63fafSDavid Malone 			exit(5);
566d7b63fafSDavid Malone 		}
567d7b63fafSDavid Malone 		break;
568d7b63fafSDavid Malone 	case IPPROTO_NONE:
5699d8b46c8SMichael Tuexen 	case IPPROTO_SCTP:
5709d8b46c8SMichael Tuexen 	case IPPROTO_TCP:
5719d8b46c8SMichael Tuexen 		if ((sndsock = socket(AF_INET6, SOCK_RAW, useproto)) < 0) {
572d7b63fafSDavid Malone 			perror("socket(SOCK_RAW)");
573d7b63fafSDavid Malone 			exit(5);
574d7b63fafSDavid Malone 		}
575d7b63fafSDavid Malone 		break;
576d7b63fafSDavid Malone 	default:
577aa96470cSMichael Tuexen 		fprintf(stderr, "traceroute6: unknown probe protocol %d\n",
578d7b63fafSDavid Malone 		    useproto);
579d7b63fafSDavid Malone 		exit(5);
580d7b63fafSDavid Malone 	}
58184a1a4cfSHajimu UMEMOTO 	if (max_hops < first_hop) {
58284a1a4cfSHajimu UMEMOTO 		fprintf(stderr,
58384a1a4cfSHajimu UMEMOTO 		    "traceroute6: max hoplimit must be larger than first hoplimit.\n");
58484a1a4cfSHajimu UMEMOTO 		exit(1);
58584a1a4cfSHajimu UMEMOTO 	}
58684a1a4cfSHajimu UMEMOTO 
587d7b63fafSDavid Malone 	/* revoke privs */
588d7b63fafSDavid Malone 	uid = getuid();
589d7b63fafSDavid Malone 	if (setresuid(uid, uid, uid) == -1) {
590d7b63fafSDavid Malone 		perror("setresuid");
591d7b63fafSDavid Malone 		exit(1);
592d7b63fafSDavid Malone 	}
593d7b63fafSDavid Malone 
594d7b63fafSDavid Malone 
59533841545SHajimu UMEMOTO 	if (argc < 1 || argc > 2)
5967d56d374SYoshinobu Inoue 		usage();
5977d56d374SYoshinobu Inoue 
598de68a0daSKris Kennaway #if 1
5997d56d374SYoshinobu Inoue 	setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
600de68a0daSKris Kennaway #else
601de68a0daSKris Kennaway 	setlinebuf(stdout);
602de68a0daSKris Kennaway #endif
6037d56d374SYoshinobu Inoue 
60439865d64SYoshinobu Inoue 	memset(&hints, 0, sizeof(hints));
60539865d64SYoshinobu Inoue 	hints.ai_family = PF_INET6;
60639865d64SYoshinobu Inoue 	hints.ai_socktype = SOCK_RAW;
60739865d64SYoshinobu Inoue 	hints.ai_protocol = IPPROTO_ICMPV6;
60839865d64SYoshinobu Inoue 	hints.ai_flags = AI_CANONNAME;
60939865d64SYoshinobu Inoue 	error = getaddrinfo(*argv, NULL, &hints, &res);
61039865d64SYoshinobu Inoue 	if (error) {
611c449e284SHajimu UMEMOTO 		fprintf(stderr,
61239865d64SYoshinobu Inoue 		    "traceroute6: %s\n", gai_strerror(error));
6137d56d374SYoshinobu Inoue 		exit(1);
6147d56d374SYoshinobu Inoue 	}
615de68a0daSKris Kennaway 	if (res->ai_addrlen != sizeof(Dst)) {
616c449e284SHajimu UMEMOTO 		fprintf(stderr,
617de68a0daSKris Kennaway 		    "traceroute6: size of sockaddr mismatch\n");
618de68a0daSKris Kennaway 		exit(1);
619de68a0daSKris Kennaway 	}
62039865d64SYoshinobu Inoue 	memcpy(&Dst, res->ai_addr, res->ai_addrlen);
62139865d64SYoshinobu Inoue 	hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv;
62233841545SHajimu UMEMOTO 	if (!hostname) {
623c449e284SHajimu UMEMOTO 		fprintf(stderr, "traceroute6: not enough core\n");
62433841545SHajimu UMEMOTO 		exit(1);
62533841545SHajimu UMEMOTO 	}
62684a1a4cfSHajimu UMEMOTO 	if (res->ai_next) {
62784a1a4cfSHajimu UMEMOTO 		if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf,
62884a1a4cfSHajimu UMEMOTO 		    sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
62984a1a4cfSHajimu UMEMOTO 			strlcpy(hbuf, "?", sizeof(hbuf));
63084a1a4cfSHajimu UMEMOTO 		fprintf(stderr, "traceroute6: Warning: %s has multiple "
63184a1a4cfSHajimu UMEMOTO 		    "addresses; using %s\n", hostname, hbuf);
63284a1a4cfSHajimu UMEMOTO 	}
633*ca19d0d7SMark Johnston 	freeaddrinfo(res);
63433841545SHajimu UMEMOTO 	if (*++argv) {
63533841545SHajimu UMEMOTO 		ep = NULL;
63684a1a4cfSHajimu UMEMOTO 		errno = 0;
63733841545SHajimu UMEMOTO 		datalen = strtoul(*argv, &ep, 0);
638aa96470cSMichael Tuexen 		if (errno || *ep) {
639c449e284SHajimu UMEMOTO 			fprintf(stderr,
64033841545SHajimu UMEMOTO 			    "traceroute6: invalid packet length.\n");
64133841545SHajimu UMEMOTO 			exit(1);
64233841545SHajimu UMEMOTO 		}
64333841545SHajimu UMEMOTO 	}
644d7b63fafSDavid Malone 	switch (useproto) {
645d7b63fafSDavid Malone 	case IPPROTO_ICMPV6:
646aa96470cSMichael Tuexen 		minlen = ICMP6ECHOLEN;
647d7b63fafSDavid Malone 		break;
648d7b63fafSDavid Malone 	case IPPROTO_UDP:
649aa96470cSMichael Tuexen 		minlen = sizeof(struct udphdr);
650d7b63fafSDavid Malone 		break;
651d7b63fafSDavid Malone 	case IPPROTO_NONE:
652d7b63fafSDavid Malone 		minlen = 0;
653d7b63fafSDavid Malone 		datalen = 0;
654d7b63fafSDavid Malone 		break;
6559d8b46c8SMichael Tuexen 	case IPPROTO_SCTP:
6569d8b46c8SMichael Tuexen 		minlen = sizeof(struct sctphdr);
6579d8b46c8SMichael Tuexen 		break;
6589d8b46c8SMichael Tuexen 	case IPPROTO_TCP:
6599d8b46c8SMichael Tuexen 		minlen = sizeof(struct tcphdr);
6609d8b46c8SMichael Tuexen 		break;
661d7b63fafSDavid Malone 	default:
662d7b63fafSDavid Malone 		fprintf(stderr, "traceroute6: unknown probe protocol %d.\n",
663d7b63fafSDavid Malone 		    useproto);
664d7b63fafSDavid Malone 		exit(1);
665d7b63fafSDavid Malone 	}
66684a1a4cfSHajimu UMEMOTO 	if (datalen < minlen)
66784a1a4cfSHajimu UMEMOTO 		datalen = minlen;
66884a1a4cfSHajimu UMEMOTO 	else if (datalen >= MAXPACKET) {
669c449e284SHajimu UMEMOTO 		fprintf(stderr,
670f42640a3SUlrich Spörlein 		    "traceroute6: packet size must be %zu <= s < %d.\n",
671f42640a3SUlrich Spörlein 		    minlen, MAXPACKET);
6727d56d374SYoshinobu Inoue 		exit(1);
6737d56d374SYoshinobu Inoue 	}
674aa96470cSMichael Tuexen 	if (useproto == IPPROTO_UDP)
675aa96470cSMichael Tuexen 		datalen -= sizeof(struct udphdr);
67651eff8efSMichael Tuexen 	if ((useproto == IPPROTO_SCTP) && (datalen & 3)) {
67751eff8efSMichael Tuexen 		fprintf(stderr,
67851eff8efSMichael Tuexen 		    "traceroute6: packet size must be a multiple of 4.\n");
67951eff8efSMichael Tuexen 		exit(1);
68051eff8efSMichael Tuexen 	}
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));
710*ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
7117d56d374SYoshinobu Inoue 	/*
7127d56d374SYoshinobu Inoue 	 * do not raise error even if setsockopt fails, kernel may have ipsec
7137d56d374SYoshinobu Inoue 	 * turned off.
7147d56d374SYoshinobu Inoue 	 */
715*ca19d0d7SMark Johnston 	if (setpolicy(rcvsock, ipsec_inpolicy) < 0)
716d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
717*ca19d0d7SMark Johnston 	if (setpolicy(rcvsock, ipsec_outpolicy) < 0)
718d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
719de68a0daSKris Kennaway #else
720de68a0daSKris Kennaway     {
721de68a0daSKris Kennaway 	int level = IPSEC_LEVEL_NONE;
722de68a0daSKris Kennaway 
723de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
724de68a0daSKris Kennaway 	    sizeof(level));
725de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
726de68a0daSKris Kennaway 	    sizeof(level));
727de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL
728de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
729de68a0daSKris Kennaway 	    sizeof(level));
730de68a0daSKris Kennaway #else
731de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
732de68a0daSKris Kennaway 	    sizeof(level));
733de68a0daSKris Kennaway #endif
734de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL
735de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
736de68a0daSKris Kennaway 	    sizeof(level));
737de68a0daSKris Kennaway #endif
738de68a0daSKris Kennaway     }
739*ca19d0d7SMark Johnston #endif /* !(IPSEC && IPSEC_POLICY_IPSEC) */
7407d56d374SYoshinobu Inoue 
741de68a0daSKris Kennaway #ifdef SO_SNDBUF
74284a1a4cfSHajimu UMEMOTO 	i = datalen;
743aa96470cSMichael Tuexen 	if (i == 0)
744aa96470cSMichael Tuexen 		i = 1;
74584a1a4cfSHajimu UMEMOTO 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&i,
746aa96470cSMichael Tuexen 	    sizeof(i)) < 0) {
747de68a0daSKris Kennaway 		perror("setsockopt(SO_SNDBUF)");
7487d56d374SYoshinobu Inoue 		exit(6);
7497d56d374SYoshinobu Inoue 	}
750de68a0daSKris Kennaway #endif /* SO_SNDBUF */
7517d56d374SYoshinobu Inoue 	if (options & SO_DEBUG)
7527d56d374SYoshinobu Inoue 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
7537d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
7547d56d374SYoshinobu Inoue 	if (options & SO_DONTROUTE)
7557d56d374SYoshinobu Inoue 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
7567d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
757de68a0daSKris Kennaway 	if (rth) {/* XXX: there is no library to finalize the header... */
758de68a0daSKris Kennaway 		rth->ip6r_len = rth->ip6r_segleft * 2;
759de68a0daSKris Kennaway 		if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR,
760de68a0daSKris Kennaway 		    (void *)rth, (rth->ip6r_len + 1) << 3)) {
761c449e284SHajimu UMEMOTO 			fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n",
762de68a0daSKris Kennaway 			    strerror(errno));
763de68a0daSKris Kennaway 			exit(1);
764de68a0daSKris Kennaway 		}
765de68a0daSKris Kennaway 	}
766*ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
7677d56d374SYoshinobu Inoue 	/*
7687d56d374SYoshinobu Inoue 	 * do not raise error even if setsockopt fails, kernel may have ipsec
7697d56d374SYoshinobu Inoue 	 * turned off.
7707d56d374SYoshinobu Inoue 	 */
771*ca19d0d7SMark Johnston 	if (setpolicy(sndsock, ipsec_inpolicy) < 0)
772d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
773*ca19d0d7SMark Johnston 	if (setpolicy(sndsock, ipsec_outpolicy) < 0)
774d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
775de68a0daSKris Kennaway #else
776de68a0daSKris Kennaway     {
777de68a0daSKris Kennaway 	int level = IPSEC_LEVEL_BYPASS;
778de68a0daSKris Kennaway 
779de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
780de68a0daSKris Kennaway 	    sizeof(level));
781de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
782de68a0daSKris Kennaway 	    sizeof(level));
783de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL
784de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
785de68a0daSKris Kennaway 	    sizeof(level));
786de68a0daSKris Kennaway #else
787de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
788de68a0daSKris Kennaway 	    sizeof(level));
789de68a0daSKris Kennaway #endif
790de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL
791de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
792de68a0daSKris Kennaway 	    sizeof(level));
793de68a0daSKris Kennaway #endif
794de68a0daSKris Kennaway     }
795*ca19d0d7SMark Johnston #endif /* !(IPSEC && IPSEC_POLICY_IPSEC) */
7967d56d374SYoshinobu Inoue 
7977d56d374SYoshinobu Inoue 	/*
7987d56d374SYoshinobu Inoue 	 * Source selection
7997d56d374SYoshinobu Inoue 	 */
800de68a0daSKris Kennaway 	bzero(&Src, sizeof(Src));
8017d56d374SYoshinobu Inoue 	if (source) {
802de68a0daSKris Kennaway 		memset(&hints, 0, sizeof(hints));
803de68a0daSKris Kennaway 		hints.ai_family = AF_INET6;
804de68a0daSKris Kennaway 		hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
805de68a0daSKris Kennaway 		hints.ai_flags = AI_NUMERICHOST;
806de68a0daSKris Kennaway 		error = getaddrinfo(source, "0", &hints, &res);
807de68a0daSKris Kennaway 		if (error) {
808c449e284SHajimu UMEMOTO 			printf("traceroute6: %s: %s\n", source,
809de68a0daSKris Kennaway 			    gai_strerror(error));
8107d56d374SYoshinobu Inoue 			exit(1);
8117d56d374SYoshinobu Inoue 		}
812de68a0daSKris Kennaway 		if (res->ai_addrlen > sizeof(Src)) {
813c449e284SHajimu UMEMOTO 			printf("traceroute6: %s: %s\n", source,
814de68a0daSKris Kennaway 			    gai_strerror(error));
815de68a0daSKris Kennaway 			exit(1);
816de68a0daSKris Kennaway 		}
817de68a0daSKris Kennaway 		memcpy(&Src, res->ai_addr, res->ai_addrlen);
818de68a0daSKris Kennaway 		freeaddrinfo(res);
8197d56d374SYoshinobu Inoue 	} else {
8207d56d374SYoshinobu Inoue 		struct sockaddr_in6 Nxt;
82184a1a4cfSHajimu UMEMOTO 		int dummy;
82284a1a4cfSHajimu UMEMOTO 		socklen_t len;
8237d56d374SYoshinobu Inoue 
8247d56d374SYoshinobu Inoue 		Nxt = Dst;
8257d56d374SYoshinobu Inoue 		Nxt.sin6_port = htons(DUMMY_PORT);
8267d56d374SYoshinobu Inoue 		if (cmsg != NULL)
8277d56d374SYoshinobu Inoue 			bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr,
8287d56d374SYoshinobu Inoue 			    sizeof(Nxt.sin6_addr));
8297d56d374SYoshinobu Inoue 		if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
8307d56d374SYoshinobu Inoue 			perror("socket");
831de68a0daSKris Kennaway 			exit(1);
8327d56d374SYoshinobu Inoue 		}
833de68a0daSKris Kennaway 		if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) {
8347d56d374SYoshinobu Inoue 			perror("connect");
835de68a0daSKris Kennaway 			exit(1);
8367d56d374SYoshinobu Inoue 		}
837de68a0daSKris Kennaway 		len = sizeof(Src);
838de68a0daSKris Kennaway 		if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) {
839de68a0daSKris Kennaway 			perror("getsockname");
840de68a0daSKris Kennaway 			exit(1);
841de68a0daSKris Kennaway 		}
842de68a0daSKris Kennaway 		if (getnameinfo((struct sockaddr *)&Src, Src.sin6_len,
843d24cb249SHajimu UMEMOTO 		    src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) {
844c449e284SHajimu UMEMOTO 			fprintf(stderr, "getnameinfo failed for source\n");
845de68a0daSKris Kennaway 			exit(1);
846de68a0daSKris Kennaway 		}
847de68a0daSKris Kennaway 		source = src0;
8487d56d374SYoshinobu Inoue 		close(dummy);
8497d56d374SYoshinobu Inoue 	}
850de68a0daSKris Kennaway 
85184a1a4cfSHajimu UMEMOTO 	Src.sin6_port = htons(0);
852de68a0daSKris Kennaway 	if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) {
853de68a0daSKris Kennaway 		perror("bind");
8547d56d374SYoshinobu Inoue 		exit(1);
8557d56d374SYoshinobu Inoue 	}
8567d56d374SYoshinobu Inoue 
85784a1a4cfSHajimu UMEMOTO 	{
858c449e284SHajimu UMEMOTO 		socklen_t len;
859de68a0daSKris Kennaway 
860de68a0daSKris Kennaway 		len = sizeof(Src);
86184a1a4cfSHajimu UMEMOTO 		if (getsockname(sndsock, (struct sockaddr *)&Src, &len) < 0) {
862de68a0daSKris Kennaway 			perror("getsockname");
863de68a0daSKris Kennaway 			exit(1);
864de68a0daSKris Kennaway 		}
86584a1a4cfSHajimu UMEMOTO 		srcport = ntohs(Src.sin6_port);
866de68a0daSKris Kennaway 	}
867de68a0daSKris Kennaway 
868d429d720SHajimu UMEMOTO 	if (as_path) {
869d429d720SHajimu UMEMOTO 		asn = as_setup(as_server);
870d429d720SHajimu UMEMOTO 		if (asn == NULL) {
871d429d720SHajimu UMEMOTO 			fprintf(stderr,
872d429d720SHajimu UMEMOTO 			    "traceroute6: as_setup failed, AS# lookups"
873d429d720SHajimu UMEMOTO 			    " disabled\n");
874d429d720SHajimu UMEMOTO 			(void)fflush(stderr);
875d429d720SHajimu UMEMOTO 			as_path = 0;
876d429d720SHajimu UMEMOTO 		}
877d429d720SHajimu UMEMOTO 	}
878d429d720SHajimu UMEMOTO 
8797d56d374SYoshinobu Inoue 	/*
8807d56d374SYoshinobu Inoue 	 * Message to users
8817d56d374SYoshinobu Inoue 	 */
882de68a0daSKris Kennaway 	if (getnameinfo((struct sockaddr *)&Dst, Dst.sin6_len, hbuf,
883d24cb249SHajimu UMEMOTO 	    sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
88433841545SHajimu UMEMOTO 		strlcpy(hbuf, "(invalid)", sizeof(hbuf));
885c449e284SHajimu UMEMOTO 	fprintf(stderr, "traceroute6");
886c449e284SHajimu UMEMOTO 	fprintf(stderr, " to %s (%s)", hostname, hbuf);
8877d56d374SYoshinobu Inoue 	if (source)
888c449e284SHajimu UMEMOTO 		fprintf(stderr, " from %s", source);
88984a1a4cfSHajimu UMEMOTO 	fprintf(stderr, ", %lu hops max, %lu byte packets\n",
890d55fae02SMichael Tuexen 	    max_hops,
891d55fae02SMichael Tuexen 	    datalen + ((useproto == IPPROTO_UDP) ? sizeof(struct udphdr) : 0));
8927d56d374SYoshinobu Inoue 	(void) fflush(stderr);
8937d56d374SYoshinobu Inoue 
894de68a0daSKris Kennaway 	if (first_hop > 1)
89584a1a4cfSHajimu UMEMOTO 		printf("Skipping %lu intermediate hops\n", first_hop - 1);
896de68a0daSKris Kennaway 
8977d56d374SYoshinobu Inoue 	/*
8987d56d374SYoshinobu Inoue 	 * Main loop
8997d56d374SYoshinobu Inoue 	 */
900de68a0daSKris Kennaway 	for (hops = first_hop; hops <= max_hops; ++hops) {
9017d56d374SYoshinobu Inoue 		struct in6_addr lastaddr;
9027d56d374SYoshinobu Inoue 		int got_there = 0;
903f42640a3SUlrich Spörlein 		unsigned unreachable = 0;
9047d56d374SYoshinobu Inoue 
90584a1a4cfSHajimu UMEMOTO 		printf("%2lu ", hops);
9067d56d374SYoshinobu Inoue 		bzero(&lastaddr, sizeof(lastaddr));
9077d56d374SYoshinobu Inoue 		for (probe = 0; probe < nprobes; ++probe) {
9087d56d374SYoshinobu Inoue 			int cc;
9097d56d374SYoshinobu Inoue 			struct timeval t1, t2;
9107d56d374SYoshinobu Inoue 
91184a1a4cfSHajimu UMEMOTO 			(void) gettimeofday(&t1, NULL);
9127d56d374SYoshinobu Inoue 			send_probe(++seq, hops);
9137d56d374SYoshinobu Inoue 			while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) {
91484a1a4cfSHajimu UMEMOTO 				(void) gettimeofday(&t2, NULL);
91564694fdcSMichael Tuexen 				if (packet_ok(&rcvmhdr, cc, seq, &type, &code)) {
9167d56d374SYoshinobu Inoue 					if (!IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr,
9177d56d374SYoshinobu Inoue 					    &lastaddr)) {
91859876f93SChristian S.J. Peron 						if (probe > 0)
91959876f93SChristian S.J. Peron 							fputs("\n   ", stdout);
9207d56d374SYoshinobu Inoue 						print(&rcvmhdr, cc);
9217d56d374SYoshinobu Inoue 						lastaddr = Rcv.sin6_addr;
9227d56d374SYoshinobu Inoue 					}
923c449e284SHajimu UMEMOTO 					printf("  %.3f ms", deltaT(&t1, &t2));
92464694fdcSMichael Tuexen 					if (type == ICMP6_DST_UNREACH) {
92564694fdcSMichael Tuexen 						switch (code) {
9267d56d374SYoshinobu Inoue 						case ICMP6_DST_UNREACH_NOROUTE:
9277d56d374SYoshinobu Inoue 							++unreachable;
928c449e284SHajimu UMEMOTO 							printf(" !N");
9297d56d374SYoshinobu Inoue 							break;
9307d56d374SYoshinobu Inoue 						case ICMP6_DST_UNREACH_ADMIN:
9317d56d374SYoshinobu Inoue 							++unreachable;
932c449e284SHajimu UMEMOTO 							printf(" !P");
9337d56d374SYoshinobu Inoue 							break;
9347d56d374SYoshinobu Inoue 						case ICMP6_DST_UNREACH_NOTNEIGHBOR:
9357d56d374SYoshinobu Inoue 							++unreachable;
936c449e284SHajimu UMEMOTO 							printf(" !S");
9377d56d374SYoshinobu Inoue 							break;
9387d56d374SYoshinobu Inoue 						case ICMP6_DST_UNREACH_ADDR:
9397d56d374SYoshinobu Inoue 							++unreachable;
940c449e284SHajimu UMEMOTO 							printf(" !A");
9417d56d374SYoshinobu Inoue 							break;
9427d56d374SYoshinobu Inoue 						case ICMP6_DST_UNREACH_NOPORT:
9437d56d374SYoshinobu Inoue 							if (rcvhlim >= 0 &&
9447d56d374SYoshinobu Inoue 							    rcvhlim <= 1)
945c449e284SHajimu UMEMOTO 								printf(" !");
9467d56d374SYoshinobu Inoue 							++got_there;
9477d56d374SYoshinobu Inoue 							break;
9487d56d374SYoshinobu Inoue 						}
9491f69b3fbSMichael Tuexen 					} else if (type == ICMP6_PARAM_PROB &&
9501f69b3fbSMichael Tuexen 					    code == ICMP6_PARAMPROB_NEXTHEADER) {
9511f69b3fbSMichael Tuexen 						printf(" !H");
9521f69b3fbSMichael Tuexen 						++got_there;
95364694fdcSMichael Tuexen 					} else if (type == ICMP6_ECHO_REPLY) {
95464694fdcSMichael Tuexen 						if (rcvhlim >= 0 &&
95564694fdcSMichael Tuexen 						    rcvhlim <= 1)
95664694fdcSMichael Tuexen 							printf(" !");
95764694fdcSMichael Tuexen 						++got_there;
95864694fdcSMichael Tuexen 					}
9597d56d374SYoshinobu Inoue 					break;
960161ab37dSHiroki Sato 				} else if (deltaT(&t1, &t2) > waittime * 1000) {
961161ab37dSHiroki Sato 					cc = 0;
962161ab37dSHiroki Sato 					break;
9637d56d374SYoshinobu Inoue 				}
9647d56d374SYoshinobu Inoue 			}
9657d56d374SYoshinobu Inoue 			if (cc == 0)
966c449e284SHajimu UMEMOTO 				printf(" *");
9677d56d374SYoshinobu Inoue 			(void) fflush(stdout);
9687d56d374SYoshinobu Inoue 		}
9697d56d374SYoshinobu Inoue 		putchar('\n');
9707d56d374SYoshinobu Inoue 		if (got_there ||
9717d56d374SYoshinobu Inoue 		    (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) {
9727d56d374SYoshinobu Inoue 			exit(0);
9737d56d374SYoshinobu Inoue 		}
9747d56d374SYoshinobu Inoue 	}
975d429d720SHajimu UMEMOTO 	if (as_path)
976d429d720SHajimu UMEMOTO 		as_shutdown(asn);
9777d56d374SYoshinobu Inoue 
9787d56d374SYoshinobu Inoue 	exit(0);
9797d56d374SYoshinobu Inoue }
9807d56d374SYoshinobu Inoue 
9817d56d374SYoshinobu Inoue int
982aa96470cSMichael Tuexen wait_for_reply(int sock, struct msghdr *mhdr)
9837d56d374SYoshinobu Inoue {
9842a1c5efaSKris Kennaway #ifdef HAVE_POLL
9852a1c5efaSKris Kennaway 	struct pollfd pfd[1];
9867d56d374SYoshinobu Inoue 	int cc = 0;
9877d56d374SYoshinobu Inoue 
9882a1c5efaSKris Kennaway 	pfd[0].fd = sock;
9892a1c5efaSKris Kennaway 	pfd[0].events = POLLIN;
9902a1c5efaSKris Kennaway 	pfd[0].revents = 0;
9917d56d374SYoshinobu Inoue 
9922a1c5efaSKris Kennaway 	if (poll(pfd, 1, waittime * 1000) > 0)
9937d56d374SYoshinobu Inoue 		cc = recvmsg(rcvsock, mhdr, 0);
9947d56d374SYoshinobu Inoue 
9957d56d374SYoshinobu Inoue 	return (cc);
9962a1c5efaSKris Kennaway #else
9972a1c5efaSKris Kennaway 	fd_set *fdsp;
9982a1c5efaSKris Kennaway 	struct timeval wait;
9992a1c5efaSKris Kennaway 	int cc = 0, fdsn;
10002a1c5efaSKris Kennaway 
10012a1c5efaSKris Kennaway 	fdsn = howmany(sock + 1, NFDBITS) * sizeof(fd_mask);
10022a1c5efaSKris Kennaway 	if ((fdsp = (fd_set *)malloc(fdsn)) == NULL)
10032a1c5efaSKris Kennaway 		err(1, "malloc");
10042a1c5efaSKris Kennaway 	memset(fdsp, 0, fdsn);
10052a1c5efaSKris Kennaway 	FD_SET(sock, fdsp);
10062a1c5efaSKris Kennaway 	wait.tv_sec = waittime; wait.tv_usec = 0;
10072a1c5efaSKris Kennaway 
10082a1c5efaSKris Kennaway 	if (select(sock+1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0)
10092a1c5efaSKris Kennaway 		cc = recvmsg(rcvsock, mhdr, 0);
10102a1c5efaSKris Kennaway 
10112a1c5efaSKris Kennaway 	free(fdsp);
10122a1c5efaSKris Kennaway 	return (cc);
10132a1c5efaSKris Kennaway #endif
10147d56d374SYoshinobu Inoue }
10157d56d374SYoshinobu Inoue 
1016*ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
10177d56d374SYoshinobu Inoue int
1018*ca19d0d7SMark Johnston setpolicy(int so, char *policy)
10197d56d374SYoshinobu Inoue {
10207d56d374SYoshinobu Inoue 	char *buf;
10217d56d374SYoshinobu Inoue 
10227d56d374SYoshinobu Inoue 	buf = ipsec_set_policy(policy, strlen(policy));
10237d56d374SYoshinobu Inoue 	if (buf == NULL) {
1024de68a0daSKris Kennaway 		warnx("%s", ipsec_strerror());
10257d56d374SYoshinobu Inoue 		return -1;
10267d56d374SYoshinobu Inoue 	}
10277d56d374SYoshinobu Inoue 	(void)setsockopt(so, IPPROTO_IPV6, IPV6_IPSEC_POLICY,
10287d56d374SYoshinobu Inoue 	    buf, ipsec_get_policylen(buf));
10297d56d374SYoshinobu Inoue 
10307d56d374SYoshinobu Inoue 	free(buf);
10317d56d374SYoshinobu Inoue 
10327d56d374SYoshinobu Inoue 	return 0;
10337d56d374SYoshinobu Inoue }
10347d56d374SYoshinobu Inoue #endif
10357d56d374SYoshinobu Inoue 
10367d56d374SYoshinobu Inoue void
1037aa96470cSMichael Tuexen send_probe(int seq, u_long hops)
10387d56d374SYoshinobu Inoue {
1039d7b63fafSDavid Malone 	struct icmp6_hdr *icp;
10409d8b46c8SMichael Tuexen 	struct sctphdr *sctp;
10419d8b46c8SMichael Tuexen 	struct sctp_chunkhdr *chk;
104251eff8efSMichael Tuexen 	struct sctp_init_chunk *init;
104351eff8efSMichael Tuexen 	struct sctp_paramhdr *param;
10449d8b46c8SMichael Tuexen 	struct tcphdr *tcp;
10457d56d374SYoshinobu Inoue 	int i;
10467d56d374SYoshinobu Inoue 
104784a1a4cfSHajimu UMEMOTO 	i = hops;
10487d56d374SYoshinobu Inoue 	if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
104984a1a4cfSHajimu UMEMOTO 	    (char *)&i, sizeof(i)) < 0) {
10507d56d374SYoshinobu Inoue 		perror("setsockopt IPV6_UNICAST_HOPS");
10517d56d374SYoshinobu Inoue 	}
10527d56d374SYoshinobu Inoue 
10537d56d374SYoshinobu Inoue 	Dst.sin6_port = htons(port + seq);
10547d56d374SYoshinobu Inoue 
1055d7b63fafSDavid Malone 	switch (useproto) {
1056d7b63fafSDavid Malone 	case IPPROTO_ICMPV6:
1057d7b63fafSDavid Malone 		icp = (struct icmp6_hdr *)outpacket;
105884a1a4cfSHajimu UMEMOTO 
105984a1a4cfSHajimu UMEMOTO 		icp->icmp6_type = ICMP6_ECHO_REQUEST;
106084a1a4cfSHajimu UMEMOTO 		icp->icmp6_code = 0;
106184a1a4cfSHajimu UMEMOTO 		icp->icmp6_cksum = 0;
106284a1a4cfSHajimu UMEMOTO 		icp->icmp6_id = ident;
106384a1a4cfSHajimu UMEMOTO 		icp->icmp6_seq = htons(seq);
1064d7b63fafSDavid Malone 		break;
1065d7b63fafSDavid Malone 	case IPPROTO_UDP:
1066d7b63fafSDavid Malone 		break;
1067d7b63fafSDavid Malone 	case IPPROTO_NONE:
1068d7b63fafSDavid Malone 		/* No space for anything. No harm as seq/tv32 are decorative. */
1069d7b63fafSDavid Malone 		break;
10709d8b46c8SMichael Tuexen 	case IPPROTO_SCTP:
10719d8b46c8SMichael Tuexen 		sctp = (struct sctphdr *)outpacket;
10729d8b46c8SMichael Tuexen 
10739d8b46c8SMichael Tuexen 		sctp->src_port = htons(ident);
10749d8b46c8SMichael Tuexen 		sctp->dest_port = htons(port + seq);
107551eff8efSMichael Tuexen 		if (datalen >= (u_long)(sizeof(struct sctphdr) +
107651eff8efSMichael Tuexen 		    sizeof(struct sctp_init_chunk))) {
107751eff8efSMichael Tuexen 			sctp->v_tag = 0;
107851eff8efSMichael Tuexen 		} else {
10799d8b46c8SMichael Tuexen 			sctp->v_tag = (sctp->src_port << 16) | sctp->dest_port;
108051eff8efSMichael Tuexen 		}
10819d8b46c8SMichael Tuexen 		sctp->checksum = htonl(0);
10829d8b46c8SMichael Tuexen 		if (datalen >= (u_long)(sizeof(struct sctphdr) +
108351eff8efSMichael Tuexen 		    sizeof(struct sctp_init_chunk))) {
108451eff8efSMichael Tuexen 			/*
108551eff8efSMichael Tuexen 			 * Send a packet containing an INIT chunk. This works
108651eff8efSMichael Tuexen 			 * better in case of firewalls on the path, but
108751eff8efSMichael Tuexen 			 * results in a probe packet containing at least
108851eff8efSMichael Tuexen 			 * 32 bytes of payload. For shorter payloads, use
108951eff8efSMichael Tuexen 			 * SHUTDOWN-ACK chunks.
109051eff8efSMichael Tuexen 			 */
109151eff8efSMichael Tuexen 			init = (struct sctp_init_chunk *)(sctp + 1);
109251eff8efSMichael Tuexen 			init->ch.chunk_type = SCTP_INITIATION;
109351eff8efSMichael Tuexen 			init->ch.chunk_flags = 0;
109451eff8efSMichael Tuexen 			init->ch.chunk_length = htons((u_int16_t)(datalen -
109551eff8efSMichael Tuexen 			    sizeof(struct sctphdr)));
109651eff8efSMichael Tuexen 			init->init.initiate_tag = (sctp->src_port << 16) |
109751eff8efSMichael Tuexen 			    sctp->dest_port;
109851eff8efSMichael Tuexen 			init->init.a_rwnd = htonl(1500);
109951eff8efSMichael Tuexen 			init->init.num_outbound_streams = htons(1);
110051eff8efSMichael Tuexen 			init->init.num_inbound_streams = htons(1);
110151eff8efSMichael Tuexen 			init->init.initial_tsn = htonl(0);
110251eff8efSMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
110351eff8efSMichael Tuexen 			    sizeof(struct sctp_init_chunk) +
110451eff8efSMichael Tuexen 			    sizeof(struct sctp_paramhdr))) {
110551eff8efSMichael Tuexen 				param = (struct sctp_paramhdr *)(init + 1);
110651eff8efSMichael Tuexen 				param->param_type = htons(SCTP_PAD);
110751eff8efSMichael Tuexen 				param->param_length =
110851eff8efSMichael Tuexen 				    htons((u_int16_t)(datalen -
110951eff8efSMichael Tuexen 				    sizeof(struct sctphdr) -
111051eff8efSMichael Tuexen 				    sizeof(struct sctp_init_chunk)));
111151eff8efSMichael Tuexen 			}
111251eff8efSMichael Tuexen 		} else {
111351eff8efSMichael Tuexen 			/*
111451eff8efSMichael Tuexen 			 * Send a packet containing a SHUTDOWN-ACK chunk,
111551eff8efSMichael Tuexen 			 * possibly followed by a PAD chunk.
111651eff8efSMichael Tuexen 			 */
111751eff8efSMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
11189d8b46c8SMichael Tuexen 			    sizeof(struct sctp_chunkhdr))) {
11199d8b46c8SMichael Tuexen 				chk = (struct sctp_chunkhdr *)(sctp + 1);
11209d8b46c8SMichael Tuexen 				chk->chunk_type = SCTP_SHUTDOWN_ACK;
11219d8b46c8SMichael Tuexen 				chk->chunk_flags = 0;
11229d8b46c8SMichael Tuexen 				chk->chunk_length = htons(4);
11239d8b46c8SMichael Tuexen 			}
11249d8b46c8SMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
11259d8b46c8SMichael Tuexen 			    2 * sizeof(struct sctp_chunkhdr))) {
11269d8b46c8SMichael Tuexen 				chk = chk + 1;
11279d8b46c8SMichael Tuexen 				chk->chunk_type = SCTP_PAD_CHUNK;
11289d8b46c8SMichael Tuexen 				chk->chunk_flags = 0;
11299d8b46c8SMichael Tuexen 				chk->chunk_length = htons((u_int16_t)(datalen -
11309d8b46c8SMichael Tuexen 				    sizeof(struct sctphdr) -
11319d8b46c8SMichael Tuexen 				    sizeof(struct sctp_chunkhdr)));
11329d8b46c8SMichael Tuexen 			}
113351eff8efSMichael Tuexen 		}
11349d8b46c8SMichael Tuexen 		sctp->checksum = sctp_crc32c(outpacket, datalen);
11359d8b46c8SMichael Tuexen 		break;
11369d8b46c8SMichael Tuexen 	case IPPROTO_TCP:
11379d8b46c8SMichael Tuexen 		tcp = (struct tcphdr *)outpacket;
11389d8b46c8SMichael Tuexen 
11399d8b46c8SMichael Tuexen 		tcp->th_sport = htons(ident);
11409d8b46c8SMichael Tuexen 		tcp->th_dport = htons(port + seq);
11419d8b46c8SMichael Tuexen 		tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport;
11429d8b46c8SMichael Tuexen 		tcp->th_ack = 0;
11439d8b46c8SMichael Tuexen 		tcp->th_off = 5;
11449d8b46c8SMichael Tuexen 		tcp->th_flags = TH_SYN;
11459d8b46c8SMichael Tuexen 		tcp->th_sum = 0;
11469d8b46c8SMichael Tuexen 		tcp->th_sum = tcp_chksum(&Src, &Dst, outpacket, datalen);
11479d8b46c8SMichael Tuexen 		break;
1148d7b63fafSDavid Malone 	default:
1149d7b63fafSDavid Malone 		fprintf(stderr, "Unknown probe protocol %d.\n", useproto);
1150d7b63fafSDavid Malone 		exit(1);
115184a1a4cfSHajimu UMEMOTO 	}
11527d56d374SYoshinobu Inoue 
11537d56d374SYoshinobu Inoue 	i = sendto(sndsock, (char *)outpacket, datalen, 0,
1154de68a0daSKris Kennaway 	    (struct sockaddr *)&Dst, Dst.sin6_len);
1155f42640a3SUlrich Spörlein 	if (i < 0 || (u_long)i != datalen)  {
11567d56d374SYoshinobu Inoue 		if (i < 0)
11577d56d374SYoshinobu Inoue 			perror("sendto");
115884a1a4cfSHajimu UMEMOTO 		printf("traceroute6: wrote %s %lu chars, ret=%d\n",
1159c449e284SHajimu UMEMOTO 		    hostname, datalen, i);
11607d56d374SYoshinobu Inoue 		(void) fflush(stdout);
11617d56d374SYoshinobu Inoue 	}
11627d56d374SYoshinobu Inoue }
11637d56d374SYoshinobu Inoue 
11647d56d374SYoshinobu Inoue int
1165aa96470cSMichael Tuexen get_hoplim(struct msghdr *mhdr)
11667d56d374SYoshinobu Inoue {
11677d56d374SYoshinobu Inoue 	struct cmsghdr *cm;
11687d56d374SYoshinobu Inoue 
11697d56d374SYoshinobu Inoue 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
11707d56d374SYoshinobu Inoue 	    cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
11717d56d374SYoshinobu Inoue 		if (cm->cmsg_level == IPPROTO_IPV6 &&
11727d56d374SYoshinobu Inoue 		    cm->cmsg_type == IPV6_HOPLIMIT &&
11737d56d374SYoshinobu Inoue 		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
11747d56d374SYoshinobu Inoue 			return (*(int *)CMSG_DATA(cm));
11757d56d374SYoshinobu Inoue 	}
11767d56d374SYoshinobu Inoue 
11777d56d374SYoshinobu Inoue 	return (-1);
11787d56d374SYoshinobu Inoue }
11797d56d374SYoshinobu Inoue 
11807d56d374SYoshinobu Inoue double
1181aa96470cSMichael Tuexen deltaT(struct timeval *t1p, struct timeval *t2p)
11827d56d374SYoshinobu Inoue {
1183e961704aSDavid Malone 	double dt;
11847d56d374SYoshinobu Inoue 
11857d56d374SYoshinobu Inoue 	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
11867d56d374SYoshinobu Inoue 	    (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
11877d56d374SYoshinobu Inoue 	return (dt);
11887d56d374SYoshinobu Inoue }
11897d56d374SYoshinobu Inoue 
11907d56d374SYoshinobu Inoue /*
11917d56d374SYoshinobu Inoue  * Convert an ICMP "type" field to a printable string.
11927d56d374SYoshinobu Inoue  */
1193f42640a3SUlrich Spörlein const char *
1194f42640a3SUlrich Spörlein pr_type(int t0)
11957d56d374SYoshinobu Inoue {
11967d56d374SYoshinobu Inoue 	u_char t = t0 & 0xff;
1197f42640a3SUlrich Spörlein 	const char *cp;
11987d56d374SYoshinobu Inoue 
11997d56d374SYoshinobu Inoue 	switch (t) {
12007d56d374SYoshinobu Inoue 	case ICMP6_DST_UNREACH:
12017d56d374SYoshinobu Inoue 		cp = "Destination Unreachable";
12027d56d374SYoshinobu Inoue 		break;
12037d56d374SYoshinobu Inoue 	case ICMP6_PACKET_TOO_BIG:
1204c449e284SHajimu UMEMOTO 		cp = "Packet Too Big";
12057d56d374SYoshinobu Inoue 		break;
12067d56d374SYoshinobu Inoue 	case ICMP6_TIME_EXCEEDED:
12077d56d374SYoshinobu Inoue 		cp = "Time Exceeded";
12087d56d374SYoshinobu Inoue 		break;
12097d56d374SYoshinobu Inoue 	case ICMP6_PARAM_PROB:
12107d56d374SYoshinobu Inoue 		cp = "Parameter Problem";
12117d56d374SYoshinobu Inoue 		break;
12127d56d374SYoshinobu Inoue 	case ICMP6_ECHO_REQUEST:
12137d56d374SYoshinobu Inoue 		cp = "Echo Request";
12147d56d374SYoshinobu Inoue 		break;
12157d56d374SYoshinobu Inoue 	case ICMP6_ECHO_REPLY:
12167d56d374SYoshinobu Inoue 		cp = "Echo Reply";
12177d56d374SYoshinobu Inoue 		break;
12187d56d374SYoshinobu Inoue 	case ICMP6_MEMBERSHIP_QUERY:
12197d56d374SYoshinobu Inoue 		cp = "Group Membership Query";
12207d56d374SYoshinobu Inoue 		break;
12217d56d374SYoshinobu Inoue 	case ICMP6_MEMBERSHIP_REPORT:
12227d56d374SYoshinobu Inoue 		cp = "Group Membership Report";
12237d56d374SYoshinobu Inoue 		break;
12247d56d374SYoshinobu Inoue 	case ICMP6_MEMBERSHIP_REDUCTION:
12257d56d374SYoshinobu Inoue 		cp = "Group Membership Reduction";
12267d56d374SYoshinobu Inoue 		break;
12277d56d374SYoshinobu Inoue 	case ND_ROUTER_SOLICIT:
12287d56d374SYoshinobu Inoue 		cp = "Router Solicitation";
12297d56d374SYoshinobu Inoue 		break;
12307d56d374SYoshinobu Inoue 	case ND_ROUTER_ADVERT:
12317d56d374SYoshinobu Inoue 		cp = "Router Advertisement";
12327d56d374SYoshinobu Inoue 		break;
12337d56d374SYoshinobu Inoue 	case ND_NEIGHBOR_SOLICIT:
12347d56d374SYoshinobu Inoue 		cp = "Neighbor Solicitation";
12357d56d374SYoshinobu Inoue 		break;
12367d56d374SYoshinobu Inoue 	case ND_NEIGHBOR_ADVERT:
12377d56d374SYoshinobu Inoue 		cp = "Neighbor Advertisement";
12387d56d374SYoshinobu Inoue 		break;
12397d56d374SYoshinobu Inoue 	case ND_REDIRECT:
1240de68a0daSKris Kennaway 		cp = "Redirect";
12417d56d374SYoshinobu Inoue 		break;
12427d56d374SYoshinobu Inoue 	default:
12437d56d374SYoshinobu Inoue 		cp = "Unknown";
12447d56d374SYoshinobu Inoue 		break;
12457d56d374SYoshinobu Inoue 	}
12467d56d374SYoshinobu Inoue 	return cp;
12477d56d374SYoshinobu Inoue }
12487d56d374SYoshinobu Inoue 
12497d56d374SYoshinobu Inoue int
125064694fdcSMichael Tuexen packet_ok(struct msghdr *mhdr, int cc, int seq, u_char *type, u_char *code)
12517d56d374SYoshinobu Inoue {
1252e961704aSDavid Malone 	struct icmp6_hdr *icp;
12537d56d374SYoshinobu Inoue 	struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
12547d56d374SYoshinobu Inoue 	char *buf = (char *)mhdr->msg_iov[0].iov_base;
12557d56d374SYoshinobu Inoue 	struct cmsghdr *cm;
12567d56d374SYoshinobu Inoue 	int *hlimp;
1257de68a0daSKris Kennaway 	char hbuf[NI_MAXHOST];
12587d56d374SYoshinobu Inoue 
1259de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1260de68a0daSKris Kennaway 	int hlen;
1261de68a0daSKris Kennaway 	struct ip6_hdr *ip;
1262de68a0daSKris Kennaway #endif
1263de68a0daSKris Kennaway 
1264de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1265de68a0daSKris Kennaway 	ip = (struct ip6_hdr *) buf;
1266de68a0daSKris Kennaway 	hlen = sizeof(struct ip6_hdr);
1267de68a0daSKris Kennaway 	if (cc < hlen + sizeof(struct icmp6_hdr)) {
1268de68a0daSKris Kennaway 		if (verbose) {
1269de68a0daSKris Kennaway 			if (getnameinfo((struct sockaddr *)from, from->sin6_len,
1270d24cb249SHajimu UMEMOTO 			    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
127133841545SHajimu UMEMOTO 				strlcpy(hbuf, "invalid", sizeof(hbuf));
1272c449e284SHajimu UMEMOTO 			printf("packet too short (%d bytes) from %s\n", cc,
1273de68a0daSKris Kennaway 			    hbuf);
1274de68a0daSKris Kennaway 		}
1275de68a0daSKris Kennaway 		return (0);
1276de68a0daSKris Kennaway 	}
1277de68a0daSKris Kennaway 	cc -= hlen;
1278de68a0daSKris Kennaway 	icp = (struct icmp6_hdr *)(buf + hlen);
1279de68a0daSKris Kennaway #else
1280f42640a3SUlrich Spörlein 	if (cc < (int)sizeof(struct icmp6_hdr)) {
1281de68a0daSKris Kennaway 		if (verbose) {
1282de68a0daSKris Kennaway 			if (getnameinfo((struct sockaddr *)from, from->sin6_len,
1283d24cb249SHajimu UMEMOTO 			    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
128433841545SHajimu UMEMOTO 				strlcpy(hbuf, "invalid", sizeof(hbuf));
1285c449e284SHajimu UMEMOTO 			printf("data too short (%d bytes) from %s\n", cc, hbuf);
1286de68a0daSKris Kennaway 		}
12877d56d374SYoshinobu Inoue 		return (0);
12887d56d374SYoshinobu Inoue 	}
12897d56d374SYoshinobu Inoue 	icp = (struct icmp6_hdr *)buf;
1290de68a0daSKris Kennaway #endif
12917d56d374SYoshinobu Inoue 	/* get optional information via advanced API */
12927d56d374SYoshinobu Inoue 	rcvpktinfo = NULL;
12937d56d374SYoshinobu Inoue 	hlimp = NULL;
12947d56d374SYoshinobu Inoue 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
12957d56d374SYoshinobu Inoue 	    cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
12967d56d374SYoshinobu Inoue 		if (cm->cmsg_level == IPPROTO_IPV6 &&
12977d56d374SYoshinobu Inoue 		    cm->cmsg_type == IPV6_PKTINFO &&
12987d56d374SYoshinobu Inoue 		    cm->cmsg_len ==
12997d56d374SYoshinobu Inoue 		    CMSG_LEN(sizeof(struct in6_pktinfo)))
13007d56d374SYoshinobu Inoue 			rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm));
13017d56d374SYoshinobu Inoue 
13027d56d374SYoshinobu Inoue 		if (cm->cmsg_level == IPPROTO_IPV6 &&
13037d56d374SYoshinobu Inoue 		    cm->cmsg_type == IPV6_HOPLIMIT &&
13047d56d374SYoshinobu Inoue 		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
13057d56d374SYoshinobu Inoue 			hlimp = (int *)CMSG_DATA(cm);
13067d56d374SYoshinobu Inoue 	}
13077d56d374SYoshinobu Inoue 	if (rcvpktinfo == NULL || hlimp == NULL) {
13087d56d374SYoshinobu Inoue 		warnx("failed to get received hop limit or packet info");
1309de68a0daSKris Kennaway #if 0
13107d56d374SYoshinobu Inoue 		return (0);
1311de68a0daSKris Kennaway #else
1312de68a0daSKris Kennaway 		rcvhlim = 0;	/*XXX*/
1313de68a0daSKris Kennaway #endif
13147d56d374SYoshinobu Inoue 	}
1315de68a0daSKris Kennaway 	else
13167d56d374SYoshinobu Inoue 		rcvhlim = *hlimp;
13177d56d374SYoshinobu Inoue 
131864694fdcSMichael Tuexen 	*type = icp->icmp6_type;
131964694fdcSMichael Tuexen 	*code = icp->icmp6_code;
132064694fdcSMichael Tuexen 	if ((*type == ICMP6_TIME_EXCEEDED &&
132164694fdcSMichael Tuexen 	    *code == ICMP6_TIME_EXCEED_TRANSIT) ||
13221f69b3fbSMichael Tuexen 	    (*type == ICMP6_DST_UNREACH) ||
13231f69b3fbSMichael Tuexen 	    (*type == ICMP6_PARAM_PROB &&
13241f69b3fbSMichael Tuexen 	    *code == ICMP6_PARAMPROB_NEXTHEADER)) {
13257d56d374SYoshinobu Inoue 		struct ip6_hdr *hip;
1326aa96470cSMichael Tuexen 		struct icmp6_hdr *icmp;
132751eff8efSMichael Tuexen 		struct sctp_init_chunk *init;
13289d8b46c8SMichael Tuexen 		struct sctphdr *sctp;
13299d8b46c8SMichael Tuexen 		struct tcphdr *tcp;
1330aa96470cSMichael Tuexen 		struct udphdr *udp;
1331d7b63fafSDavid Malone 		void *up;
13327d56d374SYoshinobu Inoue 
13337d56d374SYoshinobu Inoue 		hip = (struct ip6_hdr *)(icp + 1);
1334d7b63fafSDavid Malone 		if ((up = get_uphdr(hip, (u_char *)(buf + cc))) == NULL) {
13357d56d374SYoshinobu Inoue 			if (verbose)
13367d56d374SYoshinobu Inoue 				warnx("failed to get upper layer header");
13377d56d374SYoshinobu Inoue 			return (0);
13387d56d374SYoshinobu Inoue 		}
1339d7b63fafSDavid Malone 		switch (useproto) {
1340d7b63fafSDavid Malone 		case IPPROTO_ICMPV6:
1341aa96470cSMichael Tuexen 			icmp = (struct icmp6_hdr *)up;
1342aa96470cSMichael Tuexen 			if (icmp->icmp6_id == ident &&
1343aa96470cSMichael Tuexen 			    icmp->icmp6_seq == htons(seq))
134464694fdcSMichael Tuexen 				return (1);
1345d7b63fafSDavid Malone 			break;
1346d7b63fafSDavid Malone 		case IPPROTO_UDP:
1347aa96470cSMichael Tuexen 			udp = (struct udphdr *)up;
1348aa96470cSMichael Tuexen 			if (udp->uh_sport == htons(srcport) &&
1349aa96470cSMichael Tuexen 			    udp->uh_dport == htons(port + seq))
135064694fdcSMichael Tuexen 				return (1);
1351d7b63fafSDavid Malone 			break;
13529d8b46c8SMichael Tuexen 		case IPPROTO_SCTP:
13539d8b46c8SMichael Tuexen 			sctp = (struct sctphdr *)up;
135451eff8efSMichael Tuexen 			if (sctp->src_port != htons(ident) ||
135551eff8efSMichael Tuexen 			    sctp->dest_port != htons(port + seq)) {
135651eff8efSMichael Tuexen 				break;
135751eff8efSMichael Tuexen 			}
135851eff8efSMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
135951eff8efSMichael Tuexen 			    sizeof(struct sctp_init_chunk))) {
136051eff8efSMichael Tuexen 				if (sctp->v_tag != 0) {
136151eff8efSMichael Tuexen 					break;
136251eff8efSMichael Tuexen 				}
136351eff8efSMichael Tuexen 				init = (struct sctp_init_chunk *)(sctp + 1);
136451eff8efSMichael Tuexen 				/* Check the initiate tag, if available. */
136551eff8efSMichael Tuexen 				if ((char *)&init->init.a_rwnd > buf + cc) {
136664694fdcSMichael Tuexen 					return (1);
136751eff8efSMichael Tuexen 				}
136851eff8efSMichael Tuexen 				if (init->init.initiate_tag == (u_int32_t)
136951eff8efSMichael Tuexen 				    ((sctp->src_port << 16) | sctp->dest_port)) {
137064694fdcSMichael Tuexen 					return (1);
137151eff8efSMichael Tuexen 				}
137251eff8efSMichael Tuexen 			} else {
137351eff8efSMichael Tuexen 				if (sctp->v_tag ==
137451eff8efSMichael Tuexen 				    (u_int32_t)((sctp->src_port << 16) |
137551eff8efSMichael Tuexen 				    sctp->dest_port)) {
137664694fdcSMichael Tuexen 					return (1);
137751eff8efSMichael Tuexen 				}
137851eff8efSMichael Tuexen 			}
13799d8b46c8SMichael Tuexen 			break;
13809d8b46c8SMichael Tuexen 		case IPPROTO_TCP:
13819d8b46c8SMichael Tuexen 			tcp = (struct tcphdr *)up;
13829d8b46c8SMichael Tuexen 			if (tcp->th_sport == htons(ident) &&
13839d8b46c8SMichael Tuexen 			    tcp->th_dport == htons(port + seq) &&
13849d8b46c8SMichael Tuexen 			    tcp->th_seq ==
13859d8b46c8SMichael Tuexen 			    (tcp_seq)((tcp->th_sport << 16) | tcp->th_dport))
138664694fdcSMichael Tuexen 				return (1);
13879d8b46c8SMichael Tuexen 			break;
1388d7b63fafSDavid Malone 		case IPPROTO_NONE:
138964694fdcSMichael Tuexen 			return (1);
1390d7b63fafSDavid Malone 		default:
1391d7b63fafSDavid Malone 			fprintf(stderr, "Unknown probe proto %d.\n", useproto);
1392d7b63fafSDavid Malone 			break;
1393d7b63fafSDavid Malone 		}
139464694fdcSMichael Tuexen 	} else if (useproto == IPPROTO_ICMPV6 && *type == ICMP6_ECHO_REPLY) {
139584a1a4cfSHajimu UMEMOTO 		if (icp->icmp6_id == ident &&
139684a1a4cfSHajimu UMEMOTO 		    icp->icmp6_seq == htons(seq))
139764694fdcSMichael Tuexen 			return (1);
13987d56d374SYoshinobu Inoue 	}
13997d56d374SYoshinobu Inoue 	if (verbose) {
1400de68a0daSKris Kennaway 		char sbuf[NI_MAXHOST+1], dbuf[INET6_ADDRSTRLEN];
1401e961704aSDavid Malone 		u_int8_t *p;
1402e961704aSDavid Malone 		int i;
14037d56d374SYoshinobu Inoue 
1404de68a0daSKris Kennaway 		if (getnameinfo((struct sockaddr *)from, from->sin6_len,
1405d24cb249SHajimu UMEMOTO 		    sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0)
1406c449e284SHajimu UMEMOTO 			strlcpy(sbuf, "invalid", sizeof(sbuf));
1407c449e284SHajimu UMEMOTO 		printf("\n%d bytes from %s to %s", cc, sbuf,
1408de68a0daSKris Kennaway 		    rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1409c449e284SHajimu UMEMOTO 		    dbuf, sizeof(dbuf)) : "?");
141064694fdcSMichael Tuexen 		printf(": icmp type %d (%s) code %d\n", *type, pr_type(*type),
141164694fdcSMichael Tuexen 		    *code);
1412de68a0daSKris Kennaway 		p = (u_int8_t *)(icp + 1);
1413de68a0daSKris Kennaway #define WIDTH	16
1414de68a0daSKris Kennaway 		for (i = 0; i < cc; i++) {
1415de68a0daSKris Kennaway 			if (i % WIDTH == 0)
1416c449e284SHajimu UMEMOTO 				printf("%04x:", i);
1417de68a0daSKris Kennaway 			if (i % 4 == 0)
1418c449e284SHajimu UMEMOTO 				printf(" ");
1419c449e284SHajimu UMEMOTO 			printf("%02x", p[i]);
1420de68a0daSKris Kennaway 			if (i % WIDTH == WIDTH - 1)
1421c449e284SHajimu UMEMOTO 				printf("\n");
1422de68a0daSKris Kennaway 		}
1423de68a0daSKris Kennaway 		if (cc % WIDTH != 0)
1424c449e284SHajimu UMEMOTO 			printf("\n");
14257d56d374SYoshinobu Inoue 	}
14267d56d374SYoshinobu Inoue 	return (0);
14277d56d374SYoshinobu Inoue }
14287d56d374SYoshinobu Inoue 
14297d56d374SYoshinobu Inoue /*
143084a1a4cfSHajimu UMEMOTO  * Increment pointer until find the UDP or ICMP header.
14317d56d374SYoshinobu Inoue  */
1432d7b63fafSDavid Malone void *
1433aa96470cSMichael Tuexen get_uphdr(struct ip6_hdr *ip6, u_char *lim)
14347d56d374SYoshinobu Inoue {
14357d56d374SYoshinobu Inoue 	u_char *cp = (u_char *)ip6, nh;
14367d56d374SYoshinobu Inoue 	int hlen;
1437d7b63fafSDavid Malone 	static u_char none_hdr[1]; /* Fake pointer for IPPROTO_NONE. */
14387d56d374SYoshinobu Inoue 
1439d7b63fafSDavid Malone 	if (cp + sizeof(*ip6) > lim)
14407d56d374SYoshinobu Inoue 		return (NULL);
14417d56d374SYoshinobu Inoue 
14427d56d374SYoshinobu Inoue 	nh = ip6->ip6_nxt;
14437d56d374SYoshinobu Inoue 	cp += sizeof(struct ip6_hdr);
14447d56d374SYoshinobu Inoue 
1445d7b63fafSDavid Malone 	while (lim - cp >= (nh == IPPROTO_NONE ? 0 : 8)) {
14467d56d374SYoshinobu Inoue 		switch (nh) {
14477d56d374SYoshinobu Inoue 		case IPPROTO_ESP:
14487d56d374SYoshinobu Inoue 			return (NULL);
144984a1a4cfSHajimu UMEMOTO 		case IPPROTO_ICMPV6:
1450d7b63fafSDavid Malone 			return (useproto == nh ? cp : NULL);
14519d8b46c8SMichael Tuexen 		case IPPROTO_SCTP:
14529d8b46c8SMichael Tuexen 		case IPPROTO_TCP:
14537d56d374SYoshinobu Inoue 		case IPPROTO_UDP:
1454d7b63fafSDavid Malone 			return (useproto == nh ? cp : NULL);
1455d7b63fafSDavid Malone 		case IPPROTO_NONE:
1456d7b63fafSDavid Malone 			return (useproto == nh ? none_hdr : NULL);
14577d56d374SYoshinobu Inoue 		case IPPROTO_FRAGMENT:
14587d56d374SYoshinobu Inoue 			hlen = sizeof(struct ip6_frag);
14597d56d374SYoshinobu Inoue 			nh = ((struct ip6_frag *)cp)->ip6f_nxt;
14607d56d374SYoshinobu Inoue 			break;
14617d56d374SYoshinobu Inoue 		case IPPROTO_AH:
14627d56d374SYoshinobu Inoue 			hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2;
14637d56d374SYoshinobu Inoue 			nh = ((struct ip6_ext *)cp)->ip6e_nxt;
14647d56d374SYoshinobu Inoue 			break;
14657d56d374SYoshinobu Inoue 		default:
14667d56d374SYoshinobu Inoue 			hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3;
14677d56d374SYoshinobu Inoue 			nh = ((struct ip6_ext *)cp)->ip6e_nxt;
14687d56d374SYoshinobu Inoue 			break;
14697d56d374SYoshinobu Inoue 		}
14707d56d374SYoshinobu Inoue 
14717d56d374SYoshinobu Inoue 		cp += hlen;
14727d56d374SYoshinobu Inoue 	}
14737d56d374SYoshinobu Inoue 
14747d56d374SYoshinobu Inoue 	return (NULL);
14757d56d374SYoshinobu Inoue }
14767d56d374SYoshinobu Inoue 
14777d56d374SYoshinobu Inoue void
1478aa96470cSMichael Tuexen print(struct msghdr *mhdr, int cc)
14797d56d374SYoshinobu Inoue {
14807d56d374SYoshinobu Inoue 	struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
1481de68a0daSKris Kennaway 	char hbuf[NI_MAXHOST];
14827d56d374SYoshinobu Inoue 
1483de68a0daSKris Kennaway 	if (getnameinfo((struct sockaddr *)from, from->sin6_len,
1484d24cb249SHajimu UMEMOTO 	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
148533841545SHajimu UMEMOTO 		strlcpy(hbuf, "invalid", sizeof(hbuf));
1486d429d720SHajimu UMEMOTO 	if (as_path)
1487d429d720SHajimu UMEMOTO 		printf(" [AS%u]", as_lookup(asn, hbuf, AF_INET6));
1488de68a0daSKris Kennaway 	if (nflag)
1489c449e284SHajimu UMEMOTO 		printf(" %s", hbuf);
1490de68a0daSKris Kennaway 	else if (lflag)
1491c449e284SHajimu UMEMOTO 		printf(" %s (%s)", inetname((struct sockaddr *)from), hbuf);
1492de68a0daSKris Kennaway 	else
1493c449e284SHajimu UMEMOTO 		printf(" %s", inetname((struct sockaddr *)from));
14947d56d374SYoshinobu Inoue 
14957d56d374SYoshinobu Inoue 	if (verbose) {
1496de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1497c449e284SHajimu UMEMOTO 		printf(" %d bytes to %s", cc,
1498de68a0daSKris Kennaway 		    rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1499c449e284SHajimu UMEMOTO 		    hbuf, sizeof(hbuf)) : "?");
1500de68a0daSKris Kennaway #else
1501c449e284SHajimu UMEMOTO 		printf(" %d bytes of data to %s", cc,
1502de68a0daSKris Kennaway 		    rcvpktinfo ?  inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1503c449e284SHajimu UMEMOTO 		    hbuf, sizeof(hbuf)) : "?");
1504de68a0daSKris Kennaway #endif
15057d56d374SYoshinobu Inoue 	}
15067d56d374SYoshinobu Inoue }
15077d56d374SYoshinobu Inoue 
15087d56d374SYoshinobu Inoue /*
15097d56d374SYoshinobu Inoue  * Construct an Internet address representation.
15107d56d374SYoshinobu Inoue  * If the nflag has been supplied, give
15117d56d374SYoshinobu Inoue  * numeric value, otherwise try for symbolic name.
15127d56d374SYoshinobu Inoue  */
1513de68a0daSKris Kennaway const char *
1514aa96470cSMichael Tuexen inetname(struct sockaddr *sa)
15157d56d374SYoshinobu Inoue {
1516e961704aSDavid Malone 	static char line[NI_MAXHOST], domain[MAXHOSTNAMELEN + 1];
15177d56d374SYoshinobu Inoue 	static int first = 1;
1518e961704aSDavid Malone 	char *cp;
15197d56d374SYoshinobu Inoue 
15207d56d374SYoshinobu Inoue 	if (first && !nflag) {
15217d56d374SYoshinobu Inoue 		first = 0;
1522c449e284SHajimu UMEMOTO 		if (gethostname(domain, sizeof(domain)) == 0 &&
1523c449e284SHajimu UMEMOTO 		    (cp = strchr(domain, '.')))
152433841545SHajimu UMEMOTO 			(void) strlcpy(domain, cp + 1, sizeof(domain));
15257d56d374SYoshinobu Inoue 		else
15267d56d374SYoshinobu Inoue 			domain[0] = 0;
15277d56d374SYoshinobu Inoue 	}
1528de68a0daSKris Kennaway 	cp = NULL;
15297d56d374SYoshinobu Inoue 	if (!nflag) {
1530de68a0daSKris Kennaway 		if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
1531de68a0daSKris Kennaway 		    NI_NAMEREQD) == 0) {
1532c449e284SHajimu UMEMOTO 			if ((cp = strchr(line, '.')) &&
15337d56d374SYoshinobu Inoue 			    !strcmp(cp + 1, domain))
15347d56d374SYoshinobu Inoue 				*cp = 0;
1535de68a0daSKris Kennaway 			cp = line;
15367d56d374SYoshinobu Inoue 		}
15377d56d374SYoshinobu Inoue 	}
15387d56d374SYoshinobu Inoue 	if (cp)
1539de68a0daSKris Kennaway 		return cp;
1540de68a0daSKris Kennaway 
1541de68a0daSKris Kennaway 	if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
1542d24cb249SHajimu UMEMOTO 	    NI_NUMERICHOST) != 0)
154333841545SHajimu UMEMOTO 		strlcpy(line, "invalid", sizeof(line));
1544de68a0daSKris Kennaway 	return line;
15457d56d374SYoshinobu Inoue }
15467d56d374SYoshinobu Inoue 
15479d8b46c8SMichael Tuexen /*
15489d8b46c8SMichael Tuexen  * CRC32C routine for the Stream Control Transmission Protocol
15499d8b46c8SMichael Tuexen  */
15509d8b46c8SMichael Tuexen 
15519d8b46c8SMichael Tuexen #define CRC32C(c, d) (c = (c>>8) ^ crc_c[(c^(d))&0xFF])
15529d8b46c8SMichael Tuexen 
15539d8b46c8SMichael Tuexen static u_int32_t crc_c[256] = {
15549d8b46c8SMichael Tuexen 	0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
15559d8b46c8SMichael Tuexen 	0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
15569d8b46c8SMichael Tuexen 	0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
15579d8b46c8SMichael Tuexen 	0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
15589d8b46c8SMichael Tuexen 	0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
15599d8b46c8SMichael Tuexen 	0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
15609d8b46c8SMichael Tuexen 	0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
15619d8b46c8SMichael Tuexen 	0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
15629d8b46c8SMichael Tuexen 	0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
15639d8b46c8SMichael Tuexen 	0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
15649d8b46c8SMichael Tuexen 	0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
15659d8b46c8SMichael Tuexen 	0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
15669d8b46c8SMichael Tuexen 	0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
15679d8b46c8SMichael Tuexen 	0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
15689d8b46c8SMichael Tuexen 	0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
15699d8b46c8SMichael Tuexen 	0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
15709d8b46c8SMichael Tuexen 	0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
15719d8b46c8SMichael Tuexen 	0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
15729d8b46c8SMichael Tuexen 	0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
15739d8b46c8SMichael Tuexen 	0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
15749d8b46c8SMichael Tuexen 	0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
15759d8b46c8SMichael Tuexen 	0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
15769d8b46c8SMichael Tuexen 	0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
15779d8b46c8SMichael Tuexen 	0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
15789d8b46c8SMichael Tuexen 	0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
15799d8b46c8SMichael Tuexen 	0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
15809d8b46c8SMichael Tuexen 	0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
15819d8b46c8SMichael Tuexen 	0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
15829d8b46c8SMichael Tuexen 	0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
15839d8b46c8SMichael Tuexen 	0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
15849d8b46c8SMichael Tuexen 	0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
15859d8b46c8SMichael Tuexen 	0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
15869d8b46c8SMichael Tuexen 	0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
15879d8b46c8SMichael Tuexen 	0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
15889d8b46c8SMichael Tuexen 	0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
15899d8b46c8SMichael Tuexen 	0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
15909d8b46c8SMichael Tuexen 	0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
15919d8b46c8SMichael Tuexen 	0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
15929d8b46c8SMichael Tuexen 	0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
15939d8b46c8SMichael Tuexen 	0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
15949d8b46c8SMichael Tuexen 	0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
15959d8b46c8SMichael Tuexen 	0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
15969d8b46c8SMichael Tuexen 	0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
15979d8b46c8SMichael Tuexen 	0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
15989d8b46c8SMichael Tuexen 	0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
15999d8b46c8SMichael Tuexen 	0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
16009d8b46c8SMichael Tuexen 	0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
16019d8b46c8SMichael Tuexen 	0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
16029d8b46c8SMichael Tuexen 	0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
16039d8b46c8SMichael Tuexen 	0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
16049d8b46c8SMichael Tuexen 	0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
16059d8b46c8SMichael Tuexen 	0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
16069d8b46c8SMichael Tuexen 	0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
16079d8b46c8SMichael Tuexen 	0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
16089d8b46c8SMichael Tuexen 	0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
16099d8b46c8SMichael Tuexen 	0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
16109d8b46c8SMichael Tuexen 	0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
16119d8b46c8SMichael Tuexen 	0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
16129d8b46c8SMichael Tuexen 	0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
16139d8b46c8SMichael Tuexen 	0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
16149d8b46c8SMichael Tuexen 	0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
16159d8b46c8SMichael Tuexen 	0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
16169d8b46c8SMichael Tuexen 	0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
16179d8b46c8SMichael Tuexen 	0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
16189d8b46c8SMichael Tuexen };
16199d8b46c8SMichael Tuexen 
16209d8b46c8SMichael Tuexen u_int32_t
1621*ca19d0d7SMark Johnston sctp_crc32c(void *pack, u_int32_t len)
16229d8b46c8SMichael Tuexen {
16239d8b46c8SMichael Tuexen 	u_int32_t i, crc32c;
16249d8b46c8SMichael Tuexen 	u_int8_t byte0, byte1, byte2, byte3;
1625*ca19d0d7SMark Johnston 	u_int8_t *buf = (u_int8_t *)pack;
16269d8b46c8SMichael Tuexen 
16279d8b46c8SMichael Tuexen 	crc32c = ~0;
16289d8b46c8SMichael Tuexen 	for (i = 0; i < len; i++)
16299d8b46c8SMichael Tuexen 		CRC32C(crc32c, buf[i]);
16309d8b46c8SMichael Tuexen 	crc32c = ~crc32c;
16319d8b46c8SMichael Tuexen 	byte0  = crc32c & 0xff;
16329d8b46c8SMichael Tuexen 	byte1  = (crc32c>>8) & 0xff;
16339d8b46c8SMichael Tuexen 	byte2  = (crc32c>>16) & 0xff;
16349d8b46c8SMichael Tuexen 	byte3  = (crc32c>>24) & 0xff;
16359d8b46c8SMichael Tuexen 	crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
16369d8b46c8SMichael Tuexen 	return htonl(crc32c);
16379d8b46c8SMichael Tuexen }
16389d8b46c8SMichael Tuexen 
16399d8b46c8SMichael Tuexen u_int16_t
16409d8b46c8SMichael Tuexen in_cksum(u_int16_t *addr, int len)
16419d8b46c8SMichael Tuexen {
16429d8b46c8SMichael Tuexen 	int nleft = len;
16439d8b46c8SMichael Tuexen 	u_int16_t *w = addr;
16449d8b46c8SMichael Tuexen 	u_int16_t answer;
16459d8b46c8SMichael Tuexen 	int sum = 0;
16469d8b46c8SMichael Tuexen 
16479d8b46c8SMichael Tuexen 	/*
16489d8b46c8SMichael Tuexen 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
16499d8b46c8SMichael Tuexen 	 *  we add sequential 16 bit words to it, and at the end, fold
16509d8b46c8SMichael Tuexen 	 *  back all the carry bits from the top 16 bits into the lower
16519d8b46c8SMichael Tuexen 	 *  16 bits.
16529d8b46c8SMichael Tuexen 	 */
16539d8b46c8SMichael Tuexen 	while (nleft > 1)  {
16549d8b46c8SMichael Tuexen 		sum += *w++;
16559d8b46c8SMichael Tuexen 		nleft -= 2;
16569d8b46c8SMichael Tuexen 	}
16579d8b46c8SMichael Tuexen 
16589d8b46c8SMichael Tuexen 	/* mop up an odd byte, if necessary */
16599d8b46c8SMichael Tuexen 	if (nleft == 1)
16609d8b46c8SMichael Tuexen 		sum += *(u_char *)w;
16619d8b46c8SMichael Tuexen 
16629d8b46c8SMichael Tuexen 	/*
16639d8b46c8SMichael Tuexen 	 * add back carry outs from top 16 bits to low 16 bits
16649d8b46c8SMichael Tuexen 	 */
16659d8b46c8SMichael Tuexen 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
16669d8b46c8SMichael Tuexen 	sum += (sum >> 16);			/* add carry */
16679d8b46c8SMichael Tuexen 	answer = ~sum;				/* truncate to 16 bits */
16689d8b46c8SMichael Tuexen 	return (answer);
16699d8b46c8SMichael Tuexen }
16709d8b46c8SMichael Tuexen 
16719d8b46c8SMichael Tuexen u_int16_t
16729d8b46c8SMichael Tuexen tcp_chksum(struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
16739d8b46c8SMichael Tuexen     void *payload, u_int32_t len)
16749d8b46c8SMichael Tuexen {
16759d8b46c8SMichael Tuexen 	struct {
16769d8b46c8SMichael Tuexen 		struct in6_addr src;
16779d8b46c8SMichael Tuexen 		struct in6_addr dst;
16789d8b46c8SMichael Tuexen 		u_int32_t len;
16799d8b46c8SMichael Tuexen 		u_int8_t zero[3];
16809d8b46c8SMichael Tuexen 		u_int8_t next;
16819d8b46c8SMichael Tuexen 	} pseudo_hdr;
16829d8b46c8SMichael Tuexen 	u_int16_t sum[2];
16839d8b46c8SMichael Tuexen 
16849d8b46c8SMichael Tuexen 	pseudo_hdr.src = src->sin6_addr;
16859d8b46c8SMichael Tuexen 	pseudo_hdr.dst = dst->sin6_addr;
16869d8b46c8SMichael Tuexen 	pseudo_hdr.len = htonl(len);
16879d8b46c8SMichael Tuexen 	pseudo_hdr.zero[0] = 0;
16889d8b46c8SMichael Tuexen 	pseudo_hdr.zero[1] = 0;
16899d8b46c8SMichael Tuexen 	pseudo_hdr.zero[2] = 0;
16909d8b46c8SMichael Tuexen 	pseudo_hdr.next = IPPROTO_TCP;
16919d8b46c8SMichael Tuexen 
16929d8b46c8SMichael Tuexen 	sum[1] = in_cksum((u_int16_t *)&pseudo_hdr, sizeof(pseudo_hdr));
16939d8b46c8SMichael Tuexen 	sum[0] = in_cksum(payload, len);
16949d8b46c8SMichael Tuexen 
16959d8b46c8SMichael Tuexen 	return (~in_cksum(sum, sizeof(sum)));
16969d8b46c8SMichael Tuexen }
16979d8b46c8SMichael Tuexen 
16987d56d374SYoshinobu Inoue void
1699aa96470cSMichael Tuexen usage(void)
17007d56d374SYoshinobu Inoue {
170184a1a4cfSHajimu UMEMOTO 
170284a1a4cfSHajimu UMEMOTO 	fprintf(stderr,
17039d8b46c8SMichael Tuexen "usage: traceroute6 [-adIlnNrSTUv] [-A as_server] [-f firsthop] [-g gateway]\n"
17040d7d117cSHajimu UMEMOTO "       [-m hoplimit] [-p port] [-q probes] [-s src] [-w waittime] target\n"
17050d7d117cSHajimu UMEMOTO "       [datalen]\n");
17067d56d374SYoshinobu Inoue 	exit(1);
17077d56d374SYoshinobu Inoue }
1708