xref: /freebsd/usr.sbin/traceroute6/traceroute6.c (revision cc432e237c8e741bbc097e4e85e592fbbb30d3b5)
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>
252*cc432e23SMariusz Zaborski #include <sys/capsicum.h>
2537d56d374SYoshinobu Inoue #include <sys/time.h>
2547d56d374SYoshinobu Inoue #include <sys/socket.h>
2557d56d374SYoshinobu Inoue #include <sys/uio.h>
2567d56d374SYoshinobu Inoue #include <sys/file.h>
2577d56d374SYoshinobu Inoue #include <sys/ioctl.h>
25884a1a4cfSHajimu UMEMOTO #include <sys/sysctl.h>
2597d56d374SYoshinobu Inoue 
2607d56d374SYoshinobu Inoue #include <netinet/in.h>
2617d56d374SYoshinobu Inoue 
2627d56d374SYoshinobu Inoue #include <arpa/inet.h>
2637d56d374SYoshinobu Inoue 
264*cc432e23SMariusz Zaborski #include <libcasper.h>
265*cc432e23SMariusz Zaborski #include <casper/cap_dns.h>
266*cc432e23SMariusz Zaborski #include <capsicum_helpers.h>
267*cc432e23SMariusz Zaborski 
2687d56d374SYoshinobu Inoue #include <netdb.h>
2697d56d374SYoshinobu Inoue #include <stdio.h>
2707d56d374SYoshinobu Inoue #include <err.h>
2712a1c5efaSKris Kennaway #ifdef HAVE_POLL
2722a1c5efaSKris Kennaway #include <poll.h>
2732a1c5efaSKris Kennaway #endif
2747d56d374SYoshinobu Inoue #include <errno.h>
2757d56d374SYoshinobu Inoue #include <stdlib.h>
2767d56d374SYoshinobu Inoue #include <string.h>
2777d56d374SYoshinobu Inoue #include <unistd.h>
2787d56d374SYoshinobu Inoue 
2797d56d374SYoshinobu Inoue #include <netinet/ip6.h>
2807d56d374SYoshinobu Inoue #include <netinet/icmp6.h>
2819d8b46c8SMichael Tuexen #include <netinet/sctp.h>
28251eff8efSMichael Tuexen #include <netinet/sctp_header.h>
2839d8b46c8SMichael Tuexen #include <netinet/tcp.h>
2847d56d374SYoshinobu Inoue #include <netinet/udp.h>
2857d56d374SYoshinobu Inoue 
2867d56d374SYoshinobu Inoue #ifdef IPSEC
2877d56d374SYoshinobu Inoue #include <net/route.h>
2888409aedfSGeorge V. Neville-Neil #include <netipsec/ipsec.h>
2897d56d374SYoshinobu Inoue #endif
2907d56d374SYoshinobu Inoue 
291d429d720SHajimu UMEMOTO #include "as.h"
292d429d720SHajimu UMEMOTO 
2937d56d374SYoshinobu Inoue #define DUMMY_PORT 10010
2947d56d374SYoshinobu Inoue 
2957d56d374SYoshinobu Inoue #define	MAXPACKET	65535	/* max ip packet size */
2967d56d374SYoshinobu Inoue 
297ca19d0d7SMark Johnston static u_char	packet[512];		/* last inbound (icmp) packet */
298ca19d0d7SMark Johnston static char 	*outpacket;		/* last output packet */
2997d56d374SYoshinobu Inoue 
300784bddbcSKevin Lo int	main(int, char *[]);
301784bddbcSKevin Lo int	wait_for_reply(int, struct msghdr *);
302ca19d0d7SMark 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 *);
307*cc432e23SMariusz Zaborski void	capdns_open(void);
308784bddbcSKevin Lo int	get_hoplim(struct msghdr *);
309784bddbcSKevin Lo double	deltaT(struct timeval *, struct timeval *);
310f42640a3SUlrich Spörlein const char *pr_type(int);
31164694fdcSMichael Tuexen int	packet_ok(struct msghdr *, int, int, u_char *, u_char *);
312784bddbcSKevin Lo void	print(struct msghdr *, int);
313784bddbcSKevin Lo const char *inetname(struct sockaddr *);
3149d8b46c8SMichael Tuexen u_int32_t sctp_crc32c(void *, u_int32_t);
3159d8b46c8SMichael Tuexen u_int16_t in_cksum(u_int16_t *addr, int);
316*cc432e23SMariusz Zaborski u_int16_t udp_cksum(struct sockaddr_in6 *, struct sockaddr_in6 *,
317*cc432e23SMariusz Zaborski     void *, u_int32_t);
3189d8b46c8SMichael Tuexen u_int16_t tcp_chksum(struct sockaddr_in6 *, struct sockaddr_in6 *,
3199d8b46c8SMichael Tuexen     void *, u_int32_t);
320784bddbcSKevin Lo void	usage(void);
3217d56d374SYoshinobu Inoue 
322ca19d0d7SMark Johnston static int rcvsock;			/* receive (icmp) socket file descriptor */
323ca19d0d7SMark Johnston static int sndsock;			/* send (raw/udp) socket file descriptor */
3247d56d374SYoshinobu Inoue 
325ca19d0d7SMark Johnston static struct msghdr rcvmhdr;
326ca19d0d7SMark Johnston static struct iovec rcviov[2];
327ca19d0d7SMark Johnston static int rcvhlim;
328ca19d0d7SMark Johnston static struct in6_pktinfo *rcvpktinfo;
3297d56d374SYoshinobu Inoue 
330ca19d0d7SMark Johnston static struct sockaddr_in6 Src, Dst, Rcv;
331ca19d0d7SMark Johnston static u_long datalen = 20;			/* How much data */
33284a1a4cfSHajimu UMEMOTO #define	ICMP6ECHOLEN	8
333de68a0daSKris Kennaway /* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */
334ca19d0d7SMark Johnston static char rtbuf[2064];
335ca19d0d7SMark Johnston static struct ip6_rthdr *rth;
336ca19d0d7SMark Johnston static struct cmsghdr *cmsg;
3377d56d374SYoshinobu Inoue 
338ca19d0d7SMark Johnston static char *source = NULL;
339ca19d0d7SMark Johnston static char *hostname;
3407d56d374SYoshinobu Inoue 
341*cc432e23SMariusz Zaborski static cap_channel_t *capdns;
342*cc432e23SMariusz Zaborski 
343ca19d0d7SMark Johnston static u_long nprobes = 3;
344ca19d0d7SMark Johnston static u_long first_hop = 1;
345ca19d0d7SMark Johnston static u_long max_hops = 30;
346ca19d0d7SMark Johnston static u_int16_t srcport;
347ca19d0d7SMark Johnston static u_int16_t port = 32768+666;	/* start udp dest port # for probe packets */
348ca19d0d7SMark Johnston static u_int16_t ident;
349ca19d0d7SMark Johnston static int options;			/* socket options */
350ca19d0d7SMark Johnston static int verbose;
351ca19d0d7SMark Johnston static int waittime = 5;		/* time to wait for response (in seconds) */
352ca19d0d7SMark Johnston static int nflag;			/* print addresses numerically */
353ca19d0d7SMark Johnston static int useproto = IPPROTO_UDP;	/* protocol to use to send packet */
354ca19d0d7SMark Johnston static int lflag;			/* print both numerical address & hostname */
355ca19d0d7SMark Johnston static int as_path;			/* print as numbers for each hop */
356ca19d0d7SMark Johnston static char *as_server = NULL;
357ca19d0d7SMark Johnston static void *asn;
3587d56d374SYoshinobu Inoue 
3597d56d374SYoshinobu Inoue int
360aa96470cSMichael Tuexen main(int argc, char *argv[])
3617d56d374SYoshinobu Inoue {
36284a1a4cfSHajimu UMEMOTO 	int mib[4] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM };
363e961704aSDavid Malone 	char hbuf[NI_MAXHOST], src0[NI_MAXHOST], *ep;
364f42640a3SUlrich Spörlein 	int ch, i, on = 1, seq, rcvcmsglen, error;
365e961704aSDavid Malone 	struct addrinfo hints, *res;
366e961704aSDavid Malone 	static u_char *rcvcmsgbuf;
367e961704aSDavid Malone 	u_long probe, hops, lport;
368e961704aSDavid Malone 	struct hostent *hp;
369f42640a3SUlrich Spörlein 	size_t size, minlen;
37019c7ed84SKevin Lo 	uid_t uid;
37164694fdcSMichael Tuexen 	u_char type, code;
372ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
373ca19d0d7SMark Johnston 	char ipsec_inpolicy[] = "in bypass";
374ca19d0d7SMark Johnston 	char ipsec_outpolicy[] = "out bypass";
375ca19d0d7SMark Johnston #endif
376*cc432e23SMariusz Zaborski 	cap_rights_t rights;
377*cc432e23SMariusz Zaborski 
378*cc432e23SMariusz Zaborski 	capdns_open();
3797d56d374SYoshinobu Inoue 
38053c9088fSYoshinobu Inoue 	/*
38153c9088fSYoshinobu Inoue 	 * Receive ICMP
38253c9088fSYoshinobu Inoue 	 */
38353c9088fSYoshinobu Inoue 	if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
384de68a0daSKris Kennaway 		perror("socket(ICMPv6)");
38553c9088fSYoshinobu Inoue 		exit(5);
38653c9088fSYoshinobu Inoue 	}
387de68a0daSKris Kennaway 
38884a1a4cfSHajimu UMEMOTO 	size = sizeof(i);
38984a1a4cfSHajimu UMEMOTO 	(void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &i, &size, NULL, 0);
39084a1a4cfSHajimu UMEMOTO 	max_hops = i;
39184a1a4cfSHajimu UMEMOTO 
392de68a0daSKris Kennaway 	/* specify to tell receiving interface */
393de68a0daSKris Kennaway #ifdef IPV6_RECVPKTINFO
394de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
395de68a0daSKris Kennaway 	    sizeof(on)) < 0)
396de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_RECVPKTINFO)");
397de68a0daSKris Kennaway #else  /* old adv. API */
398de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
399de68a0daSKris Kennaway 	    sizeof(on)) < 0)
400de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_PKTINFO)");
401de68a0daSKris Kennaway #endif
402de68a0daSKris Kennaway 
403de68a0daSKris Kennaway 	/* specify to tell value of hoplimit field of received IP6 hdr */
404de68a0daSKris Kennaway #ifdef IPV6_RECVHOPLIMIT
405de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
406de68a0daSKris Kennaway 	    sizeof(on)) < 0)
407de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_RECVHOPLIMIT)");
408de68a0daSKris Kennaway #else  /* old adv. API */
409de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
410de68a0daSKris Kennaway 	    sizeof(on)) < 0)
411de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_HOPLIMIT)");
412de68a0daSKris Kennaway #endif
413de68a0daSKris Kennaway 
4147d56d374SYoshinobu Inoue 	seq = 0;
4159d8b46c8SMichael Tuexen 	ident = htons(getpid() & 0xffff); /* same as ping6 */
4167d56d374SYoshinobu Inoue 
4179d8b46c8SMichael Tuexen 	while ((ch = getopt(argc, argv, "aA:df:g:Ilm:nNp:q:rs:STUvw:")) != -1)
4187d56d374SYoshinobu Inoue 		switch (ch) {
419d429d720SHajimu UMEMOTO 		case 'a':
420d429d720SHajimu UMEMOTO 			as_path = 1;
421d429d720SHajimu UMEMOTO 			break;
422d429d720SHajimu UMEMOTO 		case 'A':
423d429d720SHajimu UMEMOTO 			as_path = 1;
424d429d720SHajimu UMEMOTO 			as_server = optarg;
425d429d720SHajimu UMEMOTO 			break;
4267d56d374SYoshinobu Inoue 		case 'd':
4277d56d374SYoshinobu Inoue 			options |= SO_DEBUG;
4287d56d374SYoshinobu Inoue 			break;
429de68a0daSKris Kennaway 		case 'f':
43033841545SHajimu UMEMOTO 			ep = NULL;
43184a1a4cfSHajimu UMEMOTO 			errno = 0;
43233841545SHajimu UMEMOTO 			first_hop = strtoul(optarg, &ep, 0);
43384a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep || first_hop > 255) {
434c449e284SHajimu UMEMOTO 				fprintf(stderr,
43533841545SHajimu UMEMOTO 				    "traceroute6: invalid min hoplimit.\n");
43633841545SHajimu UMEMOTO 				exit(1);
43733841545SHajimu UMEMOTO 			}
4387d56d374SYoshinobu Inoue 			break;
4397d56d374SYoshinobu Inoue 		case 'g':
440*cc432e23SMariusz Zaborski 			/* XXX use after capability mode is entered */
4417d56d374SYoshinobu Inoue 			hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno);
4427d56d374SYoshinobu Inoue 			if (hp == NULL) {
443c449e284SHajimu UMEMOTO 				fprintf(stderr,
4447d56d374SYoshinobu Inoue 				    "traceroute6: unknown host %s\n", optarg);
4457d56d374SYoshinobu Inoue 				exit(1);
4467d56d374SYoshinobu Inoue 			}
447de68a0daSKris Kennaway 			if (rth == NULL) {
448de68a0daSKris Kennaway 				/*
449de68a0daSKris Kennaway 				 * XXX: We can't detect the number of
450de68a0daSKris Kennaway 				 * intermediate nodes yet.
451de68a0daSKris Kennaway 				 */
452de68a0daSKris Kennaway 				if ((rth = inet6_rth_init((void *)rtbuf,
453c449e284SHajimu UMEMOTO 				    sizeof(rtbuf), IPV6_RTHDR_TYPE_0,
454de68a0daSKris Kennaway 				    0)) == NULL) {
455c449e284SHajimu UMEMOTO 					fprintf(stderr,
456de68a0daSKris Kennaway 					    "inet6_rth_init failed.\n");
457de68a0daSKris Kennaway 					exit(1);
458de68a0daSKris Kennaway 				}
459de68a0daSKris Kennaway 			}
460de68a0daSKris Kennaway 			if (inet6_rth_add((void *)rth,
461de68a0daSKris Kennaway 			    (struct in6_addr *)hp->h_addr)) {
462c449e284SHajimu UMEMOTO 				fprintf(stderr,
463de68a0daSKris Kennaway 				    "inet6_rth_add failed for %s\n",
464de68a0daSKris Kennaway 				    optarg);
465de68a0daSKris Kennaway 				exit(1);
466de68a0daSKris Kennaway 			}
467de68a0daSKris Kennaway 			freehostent(hp);
468de68a0daSKris Kennaway 			break;
46984a1a4cfSHajimu UMEMOTO 		case 'I':
470d7b63fafSDavid Malone 			useproto = IPPROTO_ICMPV6;
47184a1a4cfSHajimu UMEMOTO 			break;
472de68a0daSKris Kennaway 		case 'l':
473de68a0daSKris Kennaway 			lflag++;
4747d56d374SYoshinobu Inoue 			break;
4757d56d374SYoshinobu Inoue 		case 'm':
47633841545SHajimu UMEMOTO 			ep = NULL;
47784a1a4cfSHajimu UMEMOTO 			errno = 0;
47833841545SHajimu UMEMOTO 			max_hops = strtoul(optarg, &ep, 0);
47984a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep || max_hops > 255) {
480c449e284SHajimu UMEMOTO 				fprintf(stderr,
48133841545SHajimu UMEMOTO 				    "traceroute6: invalid max hoplimit.\n");
48233841545SHajimu UMEMOTO 				exit(1);
48333841545SHajimu UMEMOTO 			}
4847d56d374SYoshinobu Inoue 			break;
4857d56d374SYoshinobu Inoue 		case 'n':
4867d56d374SYoshinobu Inoue 			nflag++;
4877d56d374SYoshinobu Inoue 			break;
488d7b63fafSDavid Malone 		case 'N':
489d7b63fafSDavid Malone 			useproto = IPPROTO_NONE;
490d7b63fafSDavid Malone 			break;
4917d56d374SYoshinobu Inoue 		case 'p':
49233841545SHajimu UMEMOTO 			ep = NULL;
49384a1a4cfSHajimu UMEMOTO 			errno = 0;
49484a1a4cfSHajimu UMEMOTO 			lport = strtoul(optarg, &ep, 0);
49584a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep) {
49684a1a4cfSHajimu UMEMOTO 				fprintf(stderr, "traceroute6: invalid port.\n");
49733841545SHajimu UMEMOTO 				exit(1);
49833841545SHajimu UMEMOTO 			}
49984a1a4cfSHajimu UMEMOTO 			if (lport == 0 || lport != (lport & 0xffff)) {
500c449e284SHajimu UMEMOTO 				fprintf(stderr,
50184a1a4cfSHajimu UMEMOTO 				    "traceroute6: port out of range.\n");
5027d56d374SYoshinobu Inoue 				exit(1);
5037d56d374SYoshinobu Inoue 			}
50484a1a4cfSHajimu UMEMOTO 			port = lport & 0xffff;
5057d56d374SYoshinobu Inoue 			break;
5067d56d374SYoshinobu Inoue 		case 'q':
50733841545SHajimu UMEMOTO 			ep = NULL;
50884a1a4cfSHajimu UMEMOTO 			errno = 0;
50933841545SHajimu UMEMOTO 			nprobes = strtoul(optarg, &ep, 0);
51084a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep) {
511c449e284SHajimu UMEMOTO 				fprintf(stderr,
51233841545SHajimu UMEMOTO 				    "traceroute6: invalid nprobes.\n");
51333841545SHajimu UMEMOTO 				exit(1);
51433841545SHajimu UMEMOTO 			}
5157d56d374SYoshinobu Inoue 			if (nprobes < 1) {
516c449e284SHajimu UMEMOTO 				fprintf(stderr,
5177d56d374SYoshinobu Inoue 				    "traceroute6: nprobes must be >0.\n");
5187d56d374SYoshinobu Inoue 				exit(1);
5197d56d374SYoshinobu Inoue 			}
5207d56d374SYoshinobu Inoue 			break;
5217d56d374SYoshinobu Inoue 		case 'r':
5227d56d374SYoshinobu Inoue 			options |= SO_DONTROUTE;
5237d56d374SYoshinobu Inoue 			break;
5247d56d374SYoshinobu Inoue 		case 's':
5257d56d374SYoshinobu Inoue 			/*
5267d56d374SYoshinobu Inoue 			 * set the ip source address of the outbound
5277d56d374SYoshinobu Inoue 			 * probe (e.g., on a multi-homed host).
5287d56d374SYoshinobu Inoue 			 */
5297d56d374SYoshinobu Inoue 			source = optarg;
5307d56d374SYoshinobu Inoue 			break;
5319d8b46c8SMichael Tuexen 		case 'S':
5329d8b46c8SMichael Tuexen 			useproto = IPPROTO_SCTP;
5339d8b46c8SMichael Tuexen 			break;
5349d8b46c8SMichael Tuexen 		case 'T':
5359d8b46c8SMichael Tuexen 			useproto = IPPROTO_TCP;
5369d8b46c8SMichael Tuexen 			break;
537d7b63fafSDavid Malone 		case 'U':
538d7b63fafSDavid Malone 			useproto = IPPROTO_UDP;
539d7b63fafSDavid Malone 			break;
540aa96470cSMichael Tuexen 		case 'v':
541aa96470cSMichael Tuexen 			verbose++;
542aa96470cSMichael Tuexen 			break;
5437d56d374SYoshinobu Inoue 		case 'w':
54433841545SHajimu UMEMOTO 			ep = NULL;
54584a1a4cfSHajimu UMEMOTO 			errno = 0;
54633841545SHajimu UMEMOTO 			waittime = strtoul(optarg, &ep, 0);
54784a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep) {
548c449e284SHajimu UMEMOTO 				fprintf(stderr,
54933841545SHajimu UMEMOTO 				    "traceroute6: invalid wait time.\n");
55033841545SHajimu UMEMOTO 				exit(1);
55133841545SHajimu UMEMOTO 			}
552eea319c4SMaxim Konovalov 			if (waittime < 1) {
553c449e284SHajimu UMEMOTO 				fprintf(stderr,
554eea319c4SMaxim Konovalov 				    "traceroute6: wait must be >= 1 sec.\n");
5557d56d374SYoshinobu Inoue 				exit(1);
5567d56d374SYoshinobu Inoue 			}
5577d56d374SYoshinobu Inoue 			break;
5587d56d374SYoshinobu Inoue 		default:
5597d56d374SYoshinobu Inoue 			usage();
5607d56d374SYoshinobu Inoue 		}
5617d56d374SYoshinobu Inoue 	argc -= optind;
5627d56d374SYoshinobu Inoue 	argv += optind;
5637d56d374SYoshinobu Inoue 
564d7b63fafSDavid Malone 	/*
565d7b63fafSDavid Malone 	 * Open socket to send probe packets.
566d7b63fafSDavid Malone 	 */
567d7b63fafSDavid Malone 	switch (useproto) {
568d7b63fafSDavid Malone 	case IPPROTO_ICMPV6:
569d7b63fafSDavid Malone 		sndsock = rcvsock;
570d7b63fafSDavid Malone 		break;
571d7b63fafSDavid Malone 	case IPPROTO_UDP:
572*cc432e23SMariusz Zaborski 		if ((sndsock = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP)) < 0) {
573*cc432e23SMariusz Zaborski 			perror("socket(SOCK_RAW)");
574d7b63fafSDavid Malone 			exit(5);
575d7b63fafSDavid Malone 		}
576d7b63fafSDavid Malone 		break;
577d7b63fafSDavid Malone 	case IPPROTO_NONE:
5789d8b46c8SMichael Tuexen 	case IPPROTO_SCTP:
5799d8b46c8SMichael Tuexen 	case IPPROTO_TCP:
5809d8b46c8SMichael Tuexen 		if ((sndsock = socket(AF_INET6, SOCK_RAW, useproto)) < 0) {
581d7b63fafSDavid Malone 			perror("socket(SOCK_RAW)");
582d7b63fafSDavid Malone 			exit(5);
583d7b63fafSDavid Malone 		}
584d7b63fafSDavid Malone 		break;
585d7b63fafSDavid Malone 	default:
586aa96470cSMichael Tuexen 		fprintf(stderr, "traceroute6: unknown probe protocol %d\n",
587d7b63fafSDavid Malone 		    useproto);
588d7b63fafSDavid Malone 		exit(5);
589d7b63fafSDavid Malone 	}
59084a1a4cfSHajimu UMEMOTO 	if (max_hops < first_hop) {
59184a1a4cfSHajimu UMEMOTO 		fprintf(stderr,
59284a1a4cfSHajimu UMEMOTO 		    "traceroute6: max hoplimit must be larger than first hoplimit.\n");
59384a1a4cfSHajimu UMEMOTO 		exit(1);
59484a1a4cfSHajimu UMEMOTO 	}
59584a1a4cfSHajimu UMEMOTO 
596d7b63fafSDavid Malone 	/* revoke privs */
597d7b63fafSDavid Malone 	uid = getuid();
598d7b63fafSDavid Malone 	if (setresuid(uid, uid, uid) == -1) {
599d7b63fafSDavid Malone 		perror("setresuid");
600d7b63fafSDavid Malone 		exit(1);
601d7b63fafSDavid Malone 	}
602d7b63fafSDavid Malone 
603d7b63fafSDavid Malone 
60433841545SHajimu UMEMOTO 	if (argc < 1 || argc > 2)
6057d56d374SYoshinobu Inoue 		usage();
6067d56d374SYoshinobu Inoue 
607de68a0daSKris Kennaway #if 1
6087d56d374SYoshinobu Inoue 	setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
609de68a0daSKris Kennaway #else
610de68a0daSKris Kennaway 	setlinebuf(stdout);
611de68a0daSKris Kennaway #endif
6127d56d374SYoshinobu Inoue 
61339865d64SYoshinobu Inoue 	memset(&hints, 0, sizeof(hints));
61439865d64SYoshinobu Inoue 	hints.ai_family = PF_INET6;
61539865d64SYoshinobu Inoue 	hints.ai_socktype = SOCK_RAW;
61639865d64SYoshinobu Inoue 	hints.ai_protocol = IPPROTO_ICMPV6;
61739865d64SYoshinobu Inoue 	hints.ai_flags = AI_CANONNAME;
618*cc432e23SMariusz Zaborski 
619*cc432e23SMariusz Zaborski 	error = cap_getaddrinfo(capdns, *argv, NULL, &hints, &res);
620*cc432e23SMariusz Zaborski 
62139865d64SYoshinobu Inoue 	if (error) {
622c449e284SHajimu UMEMOTO 		fprintf(stderr,
62339865d64SYoshinobu Inoue 		    "traceroute6: %s\n", gai_strerror(error));
6247d56d374SYoshinobu Inoue 		exit(1);
6257d56d374SYoshinobu Inoue 	}
626de68a0daSKris Kennaway 	if (res->ai_addrlen != sizeof(Dst)) {
627c449e284SHajimu UMEMOTO 		fprintf(stderr,
628de68a0daSKris Kennaway 		    "traceroute6: size of sockaddr mismatch\n");
629de68a0daSKris Kennaway 		exit(1);
630de68a0daSKris Kennaway 	}
63139865d64SYoshinobu Inoue 	memcpy(&Dst, res->ai_addr, res->ai_addrlen);
63239865d64SYoshinobu Inoue 	hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv;
63333841545SHajimu UMEMOTO 	if (!hostname) {
634c449e284SHajimu UMEMOTO 		fprintf(stderr, "traceroute6: not enough core\n");
63533841545SHajimu UMEMOTO 		exit(1);
63633841545SHajimu UMEMOTO 	}
63784a1a4cfSHajimu UMEMOTO 	if (res->ai_next) {
638*cc432e23SMariusz Zaborski 		if (cap_getnameinfo(capdns, res->ai_addr, res->ai_addrlen, hbuf,
63984a1a4cfSHajimu UMEMOTO 		    sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
64084a1a4cfSHajimu UMEMOTO 			strlcpy(hbuf, "?", sizeof(hbuf));
64184a1a4cfSHajimu UMEMOTO 		fprintf(stderr, "traceroute6: Warning: %s has multiple "
64284a1a4cfSHajimu UMEMOTO 		    "addresses; using %s\n", hostname, hbuf);
64384a1a4cfSHajimu UMEMOTO 	}
644ca19d0d7SMark Johnston 	freeaddrinfo(res);
64533841545SHajimu UMEMOTO 	if (*++argv) {
64633841545SHajimu UMEMOTO 		ep = NULL;
64784a1a4cfSHajimu UMEMOTO 		errno = 0;
64833841545SHajimu UMEMOTO 		datalen = strtoul(*argv, &ep, 0);
649aa96470cSMichael Tuexen 		if (errno || *ep) {
650c449e284SHajimu UMEMOTO 			fprintf(stderr,
65133841545SHajimu UMEMOTO 			    "traceroute6: invalid packet length.\n");
65233841545SHajimu UMEMOTO 			exit(1);
65333841545SHajimu UMEMOTO 		}
65433841545SHajimu UMEMOTO 	}
655d7b63fafSDavid Malone 	switch (useproto) {
656d7b63fafSDavid Malone 	case IPPROTO_ICMPV6:
657aa96470cSMichael Tuexen 		minlen = ICMP6ECHOLEN;
658d7b63fafSDavid Malone 		break;
659d7b63fafSDavid Malone 	case IPPROTO_UDP:
660aa96470cSMichael Tuexen 		minlen = sizeof(struct udphdr);
661d7b63fafSDavid Malone 		break;
662d7b63fafSDavid Malone 	case IPPROTO_NONE:
663d7b63fafSDavid Malone 		minlen = 0;
664d7b63fafSDavid Malone 		datalen = 0;
665d7b63fafSDavid Malone 		break;
6669d8b46c8SMichael Tuexen 	case IPPROTO_SCTP:
6679d8b46c8SMichael Tuexen 		minlen = sizeof(struct sctphdr);
6689d8b46c8SMichael Tuexen 		break;
6699d8b46c8SMichael Tuexen 	case IPPROTO_TCP:
6709d8b46c8SMichael Tuexen 		minlen = sizeof(struct tcphdr);
6719d8b46c8SMichael Tuexen 		break;
672d7b63fafSDavid Malone 	default:
673d7b63fafSDavid Malone 		fprintf(stderr, "traceroute6: unknown probe protocol %d.\n",
674d7b63fafSDavid Malone 		    useproto);
675d7b63fafSDavid Malone 		exit(1);
676d7b63fafSDavid Malone 	}
67784a1a4cfSHajimu UMEMOTO 	if (datalen < minlen)
67884a1a4cfSHajimu UMEMOTO 		datalen = minlen;
67984a1a4cfSHajimu UMEMOTO 	else if (datalen >= MAXPACKET) {
680c449e284SHajimu UMEMOTO 		fprintf(stderr,
681f42640a3SUlrich Spörlein 		    "traceroute6: packet size must be %zu <= s < %d.\n",
682f42640a3SUlrich Spörlein 		    minlen, MAXPACKET);
6837d56d374SYoshinobu Inoue 		exit(1);
6847d56d374SYoshinobu Inoue 	}
685aa96470cSMichael Tuexen 	if (useproto == IPPROTO_UDP)
686aa96470cSMichael Tuexen 		datalen -= sizeof(struct udphdr);
68751eff8efSMichael Tuexen 	if ((useproto == IPPROTO_SCTP) && (datalen & 3)) {
68851eff8efSMichael Tuexen 		fprintf(stderr,
68951eff8efSMichael Tuexen 		    "traceroute6: packet size must be a multiple of 4.\n");
69051eff8efSMichael Tuexen 		exit(1);
69151eff8efSMichael Tuexen 	}
692f42640a3SUlrich Spörlein 	outpacket = malloc(datalen);
6937d56d374SYoshinobu Inoue 	if (!outpacket) {
694de68a0daSKris Kennaway 		perror("malloc");
6957d56d374SYoshinobu Inoue 		exit(1);
6967d56d374SYoshinobu Inoue 	}
6977d56d374SYoshinobu Inoue 	(void) bzero((char *)outpacket, datalen);
6987d56d374SYoshinobu Inoue 
6997d56d374SYoshinobu Inoue 	/* initialize msghdr for receiving packets */
7007d56d374SYoshinobu Inoue 	rcviov[0].iov_base = (caddr_t)packet;
7017d56d374SYoshinobu Inoue 	rcviov[0].iov_len = sizeof(packet);
702de68a0daSKris Kennaway 	rcvmhdr.msg_name = (caddr_t)&Rcv;
703de68a0daSKris Kennaway 	rcvmhdr.msg_namelen = sizeof(Rcv);
7047d56d374SYoshinobu Inoue 	rcvmhdr.msg_iov = rcviov;
7057d56d374SYoshinobu Inoue 	rcvmhdr.msg_iovlen = 1;
706e961704aSDavid Malone 	rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
707e961704aSDavid Malone 	    CMSG_SPACE(sizeof(int));
708de68a0daSKris Kennaway 	if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) {
709c449e284SHajimu UMEMOTO 		fprintf(stderr, "traceroute6: malloc failed\n");
710de68a0daSKris Kennaway 		exit(1);
711de68a0daSKris Kennaway 	}
7127d56d374SYoshinobu Inoue 	rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
713de68a0daSKris Kennaway 	rcvmhdr.msg_controllen = rcvcmsglen;
7147d56d374SYoshinobu Inoue 
7157d56d374SYoshinobu Inoue 	if (options & SO_DEBUG)
7167d56d374SYoshinobu Inoue 		(void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
7177d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
7187d56d374SYoshinobu Inoue 	if (options & SO_DONTROUTE)
7197d56d374SYoshinobu Inoue 		(void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
7207d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
721ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
7227d56d374SYoshinobu Inoue 	/*
7237d56d374SYoshinobu Inoue 	 * do not raise error even if setsockopt fails, kernel may have ipsec
7247d56d374SYoshinobu Inoue 	 * turned off.
7257d56d374SYoshinobu Inoue 	 */
726ca19d0d7SMark Johnston 	if (setpolicy(rcvsock, ipsec_inpolicy) < 0)
727d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
728ca19d0d7SMark Johnston 	if (setpolicy(rcvsock, ipsec_outpolicy) < 0)
729d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
730de68a0daSKris Kennaway #else
731de68a0daSKris Kennaway     {
732de68a0daSKris Kennaway 	int level = IPSEC_LEVEL_NONE;
733de68a0daSKris Kennaway 
734de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
735de68a0daSKris Kennaway 	    sizeof(level));
736de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
737de68a0daSKris Kennaway 	    sizeof(level));
738de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL
739de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
740de68a0daSKris Kennaway 	    sizeof(level));
741de68a0daSKris Kennaway #else
742de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
743de68a0daSKris Kennaway 	    sizeof(level));
744de68a0daSKris Kennaway #endif
745de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL
746de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
747de68a0daSKris Kennaway 	    sizeof(level));
748de68a0daSKris Kennaway #endif
749de68a0daSKris Kennaway     }
750ca19d0d7SMark Johnston #endif /* !(IPSEC && IPSEC_POLICY_IPSEC) */
7517d56d374SYoshinobu Inoue 
752de68a0daSKris Kennaway #ifdef SO_SNDBUF
75384a1a4cfSHajimu UMEMOTO 	i = datalen;
754aa96470cSMichael Tuexen 	if (i == 0)
755aa96470cSMichael Tuexen 		i = 1;
75684a1a4cfSHajimu UMEMOTO 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&i,
757aa96470cSMichael Tuexen 	    sizeof(i)) < 0) {
758de68a0daSKris Kennaway 		perror("setsockopt(SO_SNDBUF)");
7597d56d374SYoshinobu Inoue 		exit(6);
7607d56d374SYoshinobu Inoue 	}
761de68a0daSKris Kennaway #endif /* SO_SNDBUF */
7627d56d374SYoshinobu Inoue 	if (options & SO_DEBUG)
7637d56d374SYoshinobu Inoue 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
7647d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
7657d56d374SYoshinobu Inoue 	if (options & SO_DONTROUTE)
7667d56d374SYoshinobu Inoue 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
7677d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
768de68a0daSKris Kennaway 	if (rth) {/* XXX: there is no library to finalize the header... */
769de68a0daSKris Kennaway 		rth->ip6r_len = rth->ip6r_segleft * 2;
770de68a0daSKris Kennaway 		if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR,
771de68a0daSKris Kennaway 		    (void *)rth, (rth->ip6r_len + 1) << 3)) {
772c449e284SHajimu UMEMOTO 			fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n",
773de68a0daSKris Kennaway 			    strerror(errno));
774de68a0daSKris Kennaway 			exit(1);
775de68a0daSKris Kennaway 		}
776de68a0daSKris Kennaway 	}
777ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
7787d56d374SYoshinobu Inoue 	/*
7797d56d374SYoshinobu Inoue 	 * do not raise error even if setsockopt fails, kernel may have ipsec
7807d56d374SYoshinobu Inoue 	 * turned off.
7817d56d374SYoshinobu Inoue 	 */
782ca19d0d7SMark Johnston 	if (setpolicy(sndsock, ipsec_inpolicy) < 0)
783d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
784ca19d0d7SMark Johnston 	if (setpolicy(sndsock, ipsec_outpolicy) < 0)
785d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
786de68a0daSKris Kennaway #else
787de68a0daSKris Kennaway     {
788de68a0daSKris Kennaway 	int level = IPSEC_LEVEL_BYPASS;
789de68a0daSKris Kennaway 
790de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
791de68a0daSKris Kennaway 	    sizeof(level));
792de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
793de68a0daSKris Kennaway 	    sizeof(level));
794de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL
795de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
796de68a0daSKris Kennaway 	    sizeof(level));
797de68a0daSKris Kennaway #else
798de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
799de68a0daSKris Kennaway 	    sizeof(level));
800de68a0daSKris Kennaway #endif
801de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL
802de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
803de68a0daSKris Kennaway 	    sizeof(level));
804de68a0daSKris Kennaway #endif
805de68a0daSKris Kennaway     }
806ca19d0d7SMark Johnston #endif /* !(IPSEC && IPSEC_POLICY_IPSEC) */
8077d56d374SYoshinobu Inoue 
8087d56d374SYoshinobu Inoue 	/*
8097d56d374SYoshinobu Inoue 	 * Source selection
8107d56d374SYoshinobu Inoue 	 */
811de68a0daSKris Kennaway 	bzero(&Src, sizeof(Src));
8127d56d374SYoshinobu Inoue 	if (source) {
813de68a0daSKris Kennaway 		memset(&hints, 0, sizeof(hints));
814de68a0daSKris Kennaway 		hints.ai_family = AF_INET6;
815de68a0daSKris Kennaway 		hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
816de68a0daSKris Kennaway 		hints.ai_flags = AI_NUMERICHOST;
817*cc432e23SMariusz Zaborski 		error = cap_getaddrinfo(capdns, source, "0", &hints, &res);
818de68a0daSKris Kennaway 		if (error) {
819c449e284SHajimu UMEMOTO 			printf("traceroute6: %s: %s\n", source,
820de68a0daSKris Kennaway 			    gai_strerror(error));
8217d56d374SYoshinobu Inoue 			exit(1);
8227d56d374SYoshinobu Inoue 		}
823de68a0daSKris Kennaway 		if (res->ai_addrlen > sizeof(Src)) {
824c449e284SHajimu UMEMOTO 			printf("traceroute6: %s: %s\n", source,
825de68a0daSKris Kennaway 			    gai_strerror(error));
826de68a0daSKris Kennaway 			exit(1);
827de68a0daSKris Kennaway 		}
828de68a0daSKris Kennaway 		memcpy(&Src, res->ai_addr, res->ai_addrlen);
829de68a0daSKris Kennaway 		freeaddrinfo(res);
8307d56d374SYoshinobu Inoue 	} else {
8317d56d374SYoshinobu Inoue 		struct sockaddr_in6 Nxt;
83284a1a4cfSHajimu UMEMOTO 		int dummy;
83384a1a4cfSHajimu UMEMOTO 		socklen_t len;
8347d56d374SYoshinobu Inoue 
8357d56d374SYoshinobu Inoue 		Nxt = Dst;
8367d56d374SYoshinobu Inoue 		Nxt.sin6_port = htons(DUMMY_PORT);
8377d56d374SYoshinobu Inoue 		if (cmsg != NULL)
8387d56d374SYoshinobu Inoue 			bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr,
8397d56d374SYoshinobu Inoue 			    sizeof(Nxt.sin6_addr));
8407d56d374SYoshinobu Inoue 		if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
8417d56d374SYoshinobu Inoue 			perror("socket");
842de68a0daSKris Kennaway 			exit(1);
8437d56d374SYoshinobu Inoue 		}
844de68a0daSKris Kennaway 		if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) {
8457d56d374SYoshinobu Inoue 			perror("connect");
846de68a0daSKris Kennaway 			exit(1);
8477d56d374SYoshinobu Inoue 		}
848de68a0daSKris Kennaway 		len = sizeof(Src);
849de68a0daSKris Kennaway 		if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) {
850de68a0daSKris Kennaway 			perror("getsockname");
851de68a0daSKris Kennaway 			exit(1);
852de68a0daSKris Kennaway 		}
853*cc432e23SMariusz Zaborski 		if (cap_getnameinfo(capdns, (struct sockaddr *)&Src, Src.sin6_len,
854d24cb249SHajimu UMEMOTO 		    src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) {
855c449e284SHajimu UMEMOTO 			fprintf(stderr, "getnameinfo failed for source\n");
856de68a0daSKris Kennaway 			exit(1);
857de68a0daSKris Kennaway 		}
858de68a0daSKris Kennaway 		source = src0;
8597d56d374SYoshinobu Inoue 		close(dummy);
8607d56d374SYoshinobu Inoue 	}
861de68a0daSKris Kennaway 
86284a1a4cfSHajimu UMEMOTO 	Src.sin6_port = htons(0);
863de68a0daSKris Kennaway 	if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) {
864de68a0daSKris Kennaway 		perror("bind");
8657d56d374SYoshinobu Inoue 		exit(1);
8667d56d374SYoshinobu Inoue 	}
8677d56d374SYoshinobu Inoue 
86884a1a4cfSHajimu UMEMOTO 	{
869c449e284SHajimu UMEMOTO 		socklen_t len;
870de68a0daSKris Kennaway 
871de68a0daSKris Kennaway 		len = sizeof(Src);
87284a1a4cfSHajimu UMEMOTO 		if (getsockname(sndsock, (struct sockaddr *)&Src, &len) < 0) {
873de68a0daSKris Kennaway 			perror("getsockname");
874de68a0daSKris Kennaway 			exit(1);
875de68a0daSKris Kennaway 		}
87684a1a4cfSHajimu UMEMOTO 		srcport = ntohs(Src.sin6_port);
877de68a0daSKris Kennaway 	}
878de68a0daSKris Kennaway 
879d429d720SHajimu UMEMOTO 	if (as_path) {
880d429d720SHajimu UMEMOTO 		asn = as_setup(as_server);
881d429d720SHajimu UMEMOTO 		if (asn == NULL) {
882d429d720SHajimu UMEMOTO 			fprintf(stderr,
883d429d720SHajimu UMEMOTO 			    "traceroute6: as_setup failed, AS# lookups"
884d429d720SHajimu UMEMOTO 			    " disabled\n");
885d429d720SHajimu UMEMOTO 			(void)fflush(stderr);
886d429d720SHajimu UMEMOTO 			as_path = 0;
887d429d720SHajimu UMEMOTO 		}
888d429d720SHajimu UMEMOTO 	}
889d429d720SHajimu UMEMOTO 
8907d56d374SYoshinobu Inoue 	/*
8917d56d374SYoshinobu Inoue 	 * Message to users
8927d56d374SYoshinobu Inoue 	 */
893*cc432e23SMariusz Zaborski 	if (cap_getnameinfo(capdns, (struct sockaddr *)&Dst, Dst.sin6_len, hbuf,
894d24cb249SHajimu UMEMOTO 	    sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
89533841545SHajimu UMEMOTO 		strlcpy(hbuf, "(invalid)", sizeof(hbuf));
896c449e284SHajimu UMEMOTO 	fprintf(stderr, "traceroute6");
897c449e284SHajimu UMEMOTO 	fprintf(stderr, " to %s (%s)", hostname, hbuf);
8987d56d374SYoshinobu Inoue 	if (source)
899c449e284SHajimu UMEMOTO 		fprintf(stderr, " from %s", source);
90084a1a4cfSHajimu UMEMOTO 	fprintf(stderr, ", %lu hops max, %lu byte packets\n",
901d55fae02SMichael Tuexen 	    max_hops,
902d55fae02SMichael Tuexen 	    datalen + ((useproto == IPPROTO_UDP) ? sizeof(struct udphdr) : 0));
9037d56d374SYoshinobu Inoue 	(void) fflush(stderr);
9047d56d374SYoshinobu Inoue 
905de68a0daSKris Kennaway 	if (first_hop > 1)
90684a1a4cfSHajimu UMEMOTO 		printf("Skipping %lu intermediate hops\n", first_hop - 1);
907de68a0daSKris Kennaway 
908*cc432e23SMariusz Zaborski 	if (connect(sndsock, (struct sockaddr *)&Dst,
909*cc432e23SMariusz Zaborski 	    sizeof(Dst)) != 0) {
910*cc432e23SMariusz Zaborski 		fprintf(stderr, "connect: %s\n", strerror(errno));
911*cc432e23SMariusz Zaborski 		exit(1);
912*cc432e23SMariusz Zaborski 	}
913*cc432e23SMariusz Zaborski 
914*cc432e23SMariusz Zaborski 	/*
915*cc432e23SMariusz Zaborski 	 * Here we enter capability mode. Further down access to global
916*cc432e23SMariusz Zaborski 	 * namespaces (e.g filesystem) is restricted (see capsicum(4)).
917*cc432e23SMariusz Zaborski 	 * We must connect(2) our socket before this point.
918*cc432e23SMariusz Zaborski 	 */
919*cc432e23SMariusz Zaborski 
920*cc432e23SMariusz Zaborski 	if (caph_enter_casper() < 0) {
921*cc432e23SMariusz Zaborski 		fprintf(stderr, "caph_enter_casper: %s\n", strerror(errno));
922*cc432e23SMariusz Zaborski 		exit(1);
923*cc432e23SMariusz Zaborski 	}
924*cc432e23SMariusz Zaborski 
925*cc432e23SMariusz Zaborski 	cap_rights_init(&rights, CAP_SEND, CAP_SETSOCKOPT);
926*cc432e23SMariusz Zaborski 	if (caph_rights_limit(sndsock, &rights) < 0) {
927*cc432e23SMariusz Zaborski 		fprintf(stderr, "caph_rights_limit sndsock: %s\n",
928*cc432e23SMariusz Zaborski 		    strerror(errno));
929*cc432e23SMariusz Zaborski 		exit(1);
930*cc432e23SMariusz Zaborski 	}
931*cc432e23SMariusz Zaborski 
9327d56d374SYoshinobu Inoue 	/*
9337d56d374SYoshinobu Inoue 	 * Main loop
9347d56d374SYoshinobu Inoue 	 */
935de68a0daSKris Kennaway 	for (hops = first_hop; hops <= max_hops; ++hops) {
9367d56d374SYoshinobu Inoue 		struct in6_addr lastaddr;
9377d56d374SYoshinobu Inoue 		int got_there = 0;
938f42640a3SUlrich Spörlein 		unsigned unreachable = 0;
9397d56d374SYoshinobu Inoue 
94084a1a4cfSHajimu UMEMOTO 		printf("%2lu ", hops);
9417d56d374SYoshinobu Inoue 		bzero(&lastaddr, sizeof(lastaddr));
9427d56d374SYoshinobu Inoue 		for (probe = 0; probe < nprobes; ++probe) {
9437d56d374SYoshinobu Inoue 			int cc;
9447d56d374SYoshinobu Inoue 			struct timeval t1, t2;
9457d56d374SYoshinobu Inoue 
94684a1a4cfSHajimu UMEMOTO 			(void) gettimeofday(&t1, NULL);
9477d56d374SYoshinobu Inoue 			send_probe(++seq, hops);
9487d56d374SYoshinobu Inoue 			while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) {
94984a1a4cfSHajimu UMEMOTO 				(void) gettimeofday(&t2, NULL);
95064694fdcSMichael Tuexen 				if (packet_ok(&rcvmhdr, cc, seq, &type, &code)) {
9517d56d374SYoshinobu Inoue 					if (!IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr,
9527d56d374SYoshinobu Inoue 					    &lastaddr)) {
95359876f93SChristian S.J. Peron 						if (probe > 0)
95459876f93SChristian S.J. Peron 							fputs("\n   ", stdout);
9557d56d374SYoshinobu Inoue 						print(&rcvmhdr, cc);
9567d56d374SYoshinobu Inoue 						lastaddr = Rcv.sin6_addr;
9577d56d374SYoshinobu Inoue 					}
958c449e284SHajimu UMEMOTO 					printf("  %.3f ms", deltaT(&t1, &t2));
95964694fdcSMichael Tuexen 					if (type == ICMP6_DST_UNREACH) {
96064694fdcSMichael Tuexen 						switch (code) {
9617d56d374SYoshinobu Inoue 						case ICMP6_DST_UNREACH_NOROUTE:
9627d56d374SYoshinobu Inoue 							++unreachable;
963c449e284SHajimu UMEMOTO 							printf(" !N");
9647d56d374SYoshinobu Inoue 							break;
9657d56d374SYoshinobu Inoue 						case ICMP6_DST_UNREACH_ADMIN:
9667d56d374SYoshinobu Inoue 							++unreachable;
967c449e284SHajimu UMEMOTO 							printf(" !P");
9687d56d374SYoshinobu Inoue 							break;
9697d56d374SYoshinobu Inoue 						case ICMP6_DST_UNREACH_NOTNEIGHBOR:
9707d56d374SYoshinobu Inoue 							++unreachable;
971c449e284SHajimu UMEMOTO 							printf(" !S");
9727d56d374SYoshinobu Inoue 							break;
9737d56d374SYoshinobu Inoue 						case ICMP6_DST_UNREACH_ADDR:
9747d56d374SYoshinobu Inoue 							++unreachable;
975c449e284SHajimu UMEMOTO 							printf(" !A");
9767d56d374SYoshinobu Inoue 							break;
9777d56d374SYoshinobu Inoue 						case ICMP6_DST_UNREACH_NOPORT:
9787d56d374SYoshinobu Inoue 							if (rcvhlim >= 0 &&
9797d56d374SYoshinobu Inoue 							    rcvhlim <= 1)
980c449e284SHajimu UMEMOTO 								printf(" !");
9817d56d374SYoshinobu Inoue 							++got_there;
9827d56d374SYoshinobu Inoue 							break;
9837d56d374SYoshinobu Inoue 						}
9841f69b3fbSMichael Tuexen 					} else if (type == ICMP6_PARAM_PROB &&
9851f69b3fbSMichael Tuexen 					    code == ICMP6_PARAMPROB_NEXTHEADER) {
9861f69b3fbSMichael Tuexen 						printf(" !H");
9871f69b3fbSMichael Tuexen 						++got_there;
98864694fdcSMichael Tuexen 					} else if (type == ICMP6_ECHO_REPLY) {
98964694fdcSMichael Tuexen 						if (rcvhlim >= 0 &&
99064694fdcSMichael Tuexen 						    rcvhlim <= 1)
99164694fdcSMichael Tuexen 							printf(" !");
99264694fdcSMichael Tuexen 						++got_there;
99364694fdcSMichael Tuexen 					}
9947d56d374SYoshinobu Inoue 					break;
995161ab37dSHiroki Sato 				} else if (deltaT(&t1, &t2) > waittime * 1000) {
996161ab37dSHiroki Sato 					cc = 0;
997161ab37dSHiroki Sato 					break;
9987d56d374SYoshinobu Inoue 				}
9997d56d374SYoshinobu Inoue 			}
10007d56d374SYoshinobu Inoue 			if (cc == 0)
1001c449e284SHajimu UMEMOTO 				printf(" *");
10027d56d374SYoshinobu Inoue 			(void) fflush(stdout);
10037d56d374SYoshinobu Inoue 		}
10047d56d374SYoshinobu Inoue 		putchar('\n');
10057d56d374SYoshinobu Inoue 		if (got_there ||
10067d56d374SYoshinobu Inoue 		    (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) {
10077d56d374SYoshinobu Inoue 			exit(0);
10087d56d374SYoshinobu Inoue 		}
10097d56d374SYoshinobu Inoue 	}
1010d429d720SHajimu UMEMOTO 	if (as_path)
1011d429d720SHajimu UMEMOTO 		as_shutdown(asn);
10127d56d374SYoshinobu Inoue 
10137d56d374SYoshinobu Inoue 	exit(0);
10147d56d374SYoshinobu Inoue }
10157d56d374SYoshinobu Inoue 
10167d56d374SYoshinobu Inoue int
1017aa96470cSMichael Tuexen wait_for_reply(int sock, struct msghdr *mhdr)
10187d56d374SYoshinobu Inoue {
10192a1c5efaSKris Kennaway #ifdef HAVE_POLL
10202a1c5efaSKris Kennaway 	struct pollfd pfd[1];
10217d56d374SYoshinobu Inoue 	int cc = 0;
10227d56d374SYoshinobu Inoue 
10232a1c5efaSKris Kennaway 	pfd[0].fd = sock;
10242a1c5efaSKris Kennaway 	pfd[0].events = POLLIN;
10252a1c5efaSKris Kennaway 	pfd[0].revents = 0;
10267d56d374SYoshinobu Inoue 
10272a1c5efaSKris Kennaway 	if (poll(pfd, 1, waittime * 1000) > 0)
10287d56d374SYoshinobu Inoue 		cc = recvmsg(rcvsock, mhdr, 0);
10297d56d374SYoshinobu Inoue 
10307d56d374SYoshinobu Inoue 	return (cc);
10312a1c5efaSKris Kennaway #else
10322a1c5efaSKris Kennaway 	fd_set *fdsp;
10332a1c5efaSKris Kennaway 	struct timeval wait;
10342a1c5efaSKris Kennaway 	int cc = 0, fdsn;
10352a1c5efaSKris Kennaway 
10362a1c5efaSKris Kennaway 	fdsn = howmany(sock + 1, NFDBITS) * sizeof(fd_mask);
10372a1c5efaSKris Kennaway 	if ((fdsp = (fd_set *)malloc(fdsn)) == NULL)
10382a1c5efaSKris Kennaway 		err(1, "malloc");
10392a1c5efaSKris Kennaway 	memset(fdsp, 0, fdsn);
10402a1c5efaSKris Kennaway 	FD_SET(sock, fdsp);
10412a1c5efaSKris Kennaway 	wait.tv_sec = waittime; wait.tv_usec = 0;
10422a1c5efaSKris Kennaway 
10432a1c5efaSKris Kennaway 	if (select(sock+1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0)
10442a1c5efaSKris Kennaway 		cc = recvmsg(rcvsock, mhdr, 0);
10452a1c5efaSKris Kennaway 
10462a1c5efaSKris Kennaway 	free(fdsp);
10472a1c5efaSKris Kennaway 	return (cc);
10482a1c5efaSKris Kennaway #endif
10497d56d374SYoshinobu Inoue }
10507d56d374SYoshinobu Inoue 
1051ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
10527d56d374SYoshinobu Inoue int
1053ca19d0d7SMark Johnston setpolicy(int so, char *policy)
10547d56d374SYoshinobu Inoue {
10557d56d374SYoshinobu Inoue 	char *buf;
10567d56d374SYoshinobu Inoue 
10577d56d374SYoshinobu Inoue 	buf = ipsec_set_policy(policy, strlen(policy));
10587d56d374SYoshinobu Inoue 	if (buf == NULL) {
1059de68a0daSKris Kennaway 		warnx("%s", ipsec_strerror());
10607d56d374SYoshinobu Inoue 		return -1;
10617d56d374SYoshinobu Inoue 	}
10627d56d374SYoshinobu Inoue 	(void)setsockopt(so, IPPROTO_IPV6, IPV6_IPSEC_POLICY,
10637d56d374SYoshinobu Inoue 	    buf, ipsec_get_policylen(buf));
10647d56d374SYoshinobu Inoue 
10657d56d374SYoshinobu Inoue 	free(buf);
10667d56d374SYoshinobu Inoue 
10677d56d374SYoshinobu Inoue 	return 0;
10687d56d374SYoshinobu Inoue }
10697d56d374SYoshinobu Inoue #endif
10707d56d374SYoshinobu Inoue 
10717d56d374SYoshinobu Inoue void
1072aa96470cSMichael Tuexen send_probe(int seq, u_long hops)
10737d56d374SYoshinobu Inoue {
1074d7b63fafSDavid Malone 	struct icmp6_hdr *icp;
10759d8b46c8SMichael Tuexen 	struct sctphdr *sctp;
1076*cc432e23SMariusz Zaborski 	struct udphdr *outudp;
10779d8b46c8SMichael Tuexen 	struct sctp_chunkhdr *chk;
107851eff8efSMichael Tuexen 	struct sctp_init_chunk *init;
107951eff8efSMichael Tuexen 	struct sctp_paramhdr *param;
10809d8b46c8SMichael Tuexen 	struct tcphdr *tcp;
10817d56d374SYoshinobu Inoue 	int i;
10827d56d374SYoshinobu Inoue 
108384a1a4cfSHajimu UMEMOTO 	i = hops;
10847d56d374SYoshinobu Inoue 	if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
108584a1a4cfSHajimu UMEMOTO 	    (char *)&i, sizeof(i)) < 0) {
10867d56d374SYoshinobu Inoue 		perror("setsockopt IPV6_UNICAST_HOPS");
10877d56d374SYoshinobu Inoue 	}
10887d56d374SYoshinobu Inoue 
10897d56d374SYoshinobu Inoue 	Dst.sin6_port = htons(port + seq);
10907d56d374SYoshinobu Inoue 
1091d7b63fafSDavid Malone 	switch (useproto) {
1092d7b63fafSDavid Malone 	case IPPROTO_ICMPV6:
1093d7b63fafSDavid Malone 		icp = (struct icmp6_hdr *)outpacket;
109484a1a4cfSHajimu UMEMOTO 
109584a1a4cfSHajimu UMEMOTO 		icp->icmp6_type = ICMP6_ECHO_REQUEST;
109684a1a4cfSHajimu UMEMOTO 		icp->icmp6_code = 0;
109784a1a4cfSHajimu UMEMOTO 		icp->icmp6_cksum = 0;
109884a1a4cfSHajimu UMEMOTO 		icp->icmp6_id = ident;
109984a1a4cfSHajimu UMEMOTO 		icp->icmp6_seq = htons(seq);
1100d7b63fafSDavid Malone 		break;
1101d7b63fafSDavid Malone 	case IPPROTO_UDP:
1102*cc432e23SMariusz Zaborski 		outudp = (struct udphdr *) outpacket;
1103*cc432e23SMariusz Zaborski 		outudp->uh_sport = htons(ident);
1104*cc432e23SMariusz Zaborski 		outudp->uh_dport = htons(port+seq);
1105*cc432e23SMariusz Zaborski 		outudp->uh_ulen = htons(datalen);
1106*cc432e23SMariusz Zaborski 		outudp->uh_sum = udp_cksum(&Src, &Dst, outpacket, datalen);
1107d7b63fafSDavid Malone 		break;
1108d7b63fafSDavid Malone 	case IPPROTO_NONE:
1109d7b63fafSDavid Malone 		/* No space for anything. No harm as seq/tv32 are decorative. */
1110d7b63fafSDavid Malone 		break;
11119d8b46c8SMichael Tuexen 	case IPPROTO_SCTP:
11129d8b46c8SMichael Tuexen 		sctp = (struct sctphdr *)outpacket;
11139d8b46c8SMichael Tuexen 
11149d8b46c8SMichael Tuexen 		sctp->src_port = htons(ident);
11159d8b46c8SMichael Tuexen 		sctp->dest_port = htons(port + seq);
111651eff8efSMichael Tuexen 		if (datalen >= (u_long)(sizeof(struct sctphdr) +
111751eff8efSMichael Tuexen 		    sizeof(struct sctp_init_chunk))) {
111851eff8efSMichael Tuexen 			sctp->v_tag = 0;
111951eff8efSMichael Tuexen 		} else {
11209d8b46c8SMichael Tuexen 			sctp->v_tag = (sctp->src_port << 16) | sctp->dest_port;
112151eff8efSMichael Tuexen 		}
11229d8b46c8SMichael Tuexen 		sctp->checksum = htonl(0);
11239d8b46c8SMichael Tuexen 		if (datalen >= (u_long)(sizeof(struct sctphdr) +
112451eff8efSMichael Tuexen 		    sizeof(struct sctp_init_chunk))) {
112551eff8efSMichael Tuexen 			/*
112651eff8efSMichael Tuexen 			 * Send a packet containing an INIT chunk. This works
112751eff8efSMichael Tuexen 			 * better in case of firewalls on the path, but
112851eff8efSMichael Tuexen 			 * results in a probe packet containing at least
112951eff8efSMichael Tuexen 			 * 32 bytes of payload. For shorter payloads, use
113051eff8efSMichael Tuexen 			 * SHUTDOWN-ACK chunks.
113151eff8efSMichael Tuexen 			 */
113251eff8efSMichael Tuexen 			init = (struct sctp_init_chunk *)(sctp + 1);
113351eff8efSMichael Tuexen 			init->ch.chunk_type = SCTP_INITIATION;
113451eff8efSMichael Tuexen 			init->ch.chunk_flags = 0;
113551eff8efSMichael Tuexen 			init->ch.chunk_length = htons((u_int16_t)(datalen -
113651eff8efSMichael Tuexen 			    sizeof(struct sctphdr)));
113751eff8efSMichael Tuexen 			init->init.initiate_tag = (sctp->src_port << 16) |
113851eff8efSMichael Tuexen 			    sctp->dest_port;
113951eff8efSMichael Tuexen 			init->init.a_rwnd = htonl(1500);
114051eff8efSMichael Tuexen 			init->init.num_outbound_streams = htons(1);
114151eff8efSMichael Tuexen 			init->init.num_inbound_streams = htons(1);
114251eff8efSMichael Tuexen 			init->init.initial_tsn = htonl(0);
114351eff8efSMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
114451eff8efSMichael Tuexen 			    sizeof(struct sctp_init_chunk) +
114551eff8efSMichael Tuexen 			    sizeof(struct sctp_paramhdr))) {
114651eff8efSMichael Tuexen 				param = (struct sctp_paramhdr *)(init + 1);
114751eff8efSMichael Tuexen 				param->param_type = htons(SCTP_PAD);
114851eff8efSMichael Tuexen 				param->param_length =
114951eff8efSMichael Tuexen 				    htons((u_int16_t)(datalen -
115051eff8efSMichael Tuexen 				    sizeof(struct sctphdr) -
115151eff8efSMichael Tuexen 				    sizeof(struct sctp_init_chunk)));
115251eff8efSMichael Tuexen 			}
115351eff8efSMichael Tuexen 		} else {
115451eff8efSMichael Tuexen 			/*
115551eff8efSMichael Tuexen 			 * Send a packet containing a SHUTDOWN-ACK chunk,
115651eff8efSMichael Tuexen 			 * possibly followed by a PAD chunk.
115751eff8efSMichael Tuexen 			 */
115851eff8efSMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
11599d8b46c8SMichael Tuexen 			    sizeof(struct sctp_chunkhdr))) {
11609d8b46c8SMichael Tuexen 				chk = (struct sctp_chunkhdr *)(sctp + 1);
11619d8b46c8SMichael Tuexen 				chk->chunk_type = SCTP_SHUTDOWN_ACK;
11629d8b46c8SMichael Tuexen 				chk->chunk_flags = 0;
11639d8b46c8SMichael Tuexen 				chk->chunk_length = htons(4);
11649d8b46c8SMichael Tuexen 			}
11659d8b46c8SMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
11669d8b46c8SMichael Tuexen 			    2 * sizeof(struct sctp_chunkhdr))) {
11679d8b46c8SMichael Tuexen 				chk = chk + 1;
11689d8b46c8SMichael Tuexen 				chk->chunk_type = SCTP_PAD_CHUNK;
11699d8b46c8SMichael Tuexen 				chk->chunk_flags = 0;
11709d8b46c8SMichael Tuexen 				chk->chunk_length = htons((u_int16_t)(datalen -
11719d8b46c8SMichael Tuexen 				    sizeof(struct sctphdr) -
11729d8b46c8SMichael Tuexen 				    sizeof(struct sctp_chunkhdr)));
11739d8b46c8SMichael Tuexen 			}
117451eff8efSMichael Tuexen 		}
11759d8b46c8SMichael Tuexen 		sctp->checksum = sctp_crc32c(outpacket, datalen);
11769d8b46c8SMichael Tuexen 		break;
11779d8b46c8SMichael Tuexen 	case IPPROTO_TCP:
11789d8b46c8SMichael Tuexen 		tcp = (struct tcphdr *)outpacket;
11799d8b46c8SMichael Tuexen 
11809d8b46c8SMichael Tuexen 		tcp->th_sport = htons(ident);
11819d8b46c8SMichael Tuexen 		tcp->th_dport = htons(port + seq);
11829d8b46c8SMichael Tuexen 		tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport;
11839d8b46c8SMichael Tuexen 		tcp->th_ack = 0;
11849d8b46c8SMichael Tuexen 		tcp->th_off = 5;
11859d8b46c8SMichael Tuexen 		tcp->th_flags = TH_SYN;
11869d8b46c8SMichael Tuexen 		tcp->th_sum = 0;
11879d8b46c8SMichael Tuexen 		tcp->th_sum = tcp_chksum(&Src, &Dst, outpacket, datalen);
11889d8b46c8SMichael Tuexen 		break;
1189d7b63fafSDavid Malone 	default:
1190d7b63fafSDavid Malone 		fprintf(stderr, "Unknown probe protocol %d.\n", useproto);
1191d7b63fafSDavid Malone 		exit(1);
119284a1a4cfSHajimu UMEMOTO 	}
11937d56d374SYoshinobu Inoue 
1194*cc432e23SMariusz Zaborski 	i = send(sndsock, (char *)outpacket, datalen, 0);
1195f42640a3SUlrich Spörlein 	if (i < 0 || (u_long)i != datalen)  {
11967d56d374SYoshinobu Inoue 		if (i < 0)
1197*cc432e23SMariusz Zaborski 			perror("send");
119884a1a4cfSHajimu UMEMOTO 		printf("traceroute6: wrote %s %lu chars, ret=%d\n",
1199c449e284SHajimu UMEMOTO 		    hostname, datalen, i);
12007d56d374SYoshinobu Inoue 		(void) fflush(stdout);
12017d56d374SYoshinobu Inoue 	}
12027d56d374SYoshinobu Inoue }
12037d56d374SYoshinobu Inoue 
12047d56d374SYoshinobu Inoue int
1205aa96470cSMichael Tuexen get_hoplim(struct msghdr *mhdr)
12067d56d374SYoshinobu Inoue {
12077d56d374SYoshinobu Inoue 	struct cmsghdr *cm;
12087d56d374SYoshinobu Inoue 
12097d56d374SYoshinobu Inoue 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
12107d56d374SYoshinobu Inoue 	    cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
12117d56d374SYoshinobu Inoue 		if (cm->cmsg_level == IPPROTO_IPV6 &&
12127d56d374SYoshinobu Inoue 		    cm->cmsg_type == IPV6_HOPLIMIT &&
12137d56d374SYoshinobu Inoue 		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
12147d56d374SYoshinobu Inoue 			return (*(int *)CMSG_DATA(cm));
12157d56d374SYoshinobu Inoue 	}
12167d56d374SYoshinobu Inoue 
12177d56d374SYoshinobu Inoue 	return (-1);
12187d56d374SYoshinobu Inoue }
12197d56d374SYoshinobu Inoue 
12207d56d374SYoshinobu Inoue double
1221aa96470cSMichael Tuexen deltaT(struct timeval *t1p, struct timeval *t2p)
12227d56d374SYoshinobu Inoue {
1223e961704aSDavid Malone 	double dt;
12247d56d374SYoshinobu Inoue 
12257d56d374SYoshinobu Inoue 	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
12267d56d374SYoshinobu Inoue 	    (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
12277d56d374SYoshinobu Inoue 	return (dt);
12287d56d374SYoshinobu Inoue }
12297d56d374SYoshinobu Inoue 
12307d56d374SYoshinobu Inoue /*
12317d56d374SYoshinobu Inoue  * Convert an ICMP "type" field to a printable string.
12327d56d374SYoshinobu Inoue  */
1233f42640a3SUlrich Spörlein const char *
1234f42640a3SUlrich Spörlein pr_type(int t0)
12357d56d374SYoshinobu Inoue {
12367d56d374SYoshinobu Inoue 	u_char t = t0 & 0xff;
1237f42640a3SUlrich Spörlein 	const char *cp;
12387d56d374SYoshinobu Inoue 
12397d56d374SYoshinobu Inoue 	switch (t) {
12407d56d374SYoshinobu Inoue 	case ICMP6_DST_UNREACH:
12417d56d374SYoshinobu Inoue 		cp = "Destination Unreachable";
12427d56d374SYoshinobu Inoue 		break;
12437d56d374SYoshinobu Inoue 	case ICMP6_PACKET_TOO_BIG:
1244c449e284SHajimu UMEMOTO 		cp = "Packet Too Big";
12457d56d374SYoshinobu Inoue 		break;
12467d56d374SYoshinobu Inoue 	case ICMP6_TIME_EXCEEDED:
12477d56d374SYoshinobu Inoue 		cp = "Time Exceeded";
12487d56d374SYoshinobu Inoue 		break;
12497d56d374SYoshinobu Inoue 	case ICMP6_PARAM_PROB:
12507d56d374SYoshinobu Inoue 		cp = "Parameter Problem";
12517d56d374SYoshinobu Inoue 		break;
12527d56d374SYoshinobu Inoue 	case ICMP6_ECHO_REQUEST:
12537d56d374SYoshinobu Inoue 		cp = "Echo Request";
12547d56d374SYoshinobu Inoue 		break;
12557d56d374SYoshinobu Inoue 	case ICMP6_ECHO_REPLY:
12567d56d374SYoshinobu Inoue 		cp = "Echo Reply";
12577d56d374SYoshinobu Inoue 		break;
12587d56d374SYoshinobu Inoue 	case ICMP6_MEMBERSHIP_QUERY:
12597d56d374SYoshinobu Inoue 		cp = "Group Membership Query";
12607d56d374SYoshinobu Inoue 		break;
12617d56d374SYoshinobu Inoue 	case ICMP6_MEMBERSHIP_REPORT:
12627d56d374SYoshinobu Inoue 		cp = "Group Membership Report";
12637d56d374SYoshinobu Inoue 		break;
12647d56d374SYoshinobu Inoue 	case ICMP6_MEMBERSHIP_REDUCTION:
12657d56d374SYoshinobu Inoue 		cp = "Group Membership Reduction";
12667d56d374SYoshinobu Inoue 		break;
12677d56d374SYoshinobu Inoue 	case ND_ROUTER_SOLICIT:
12687d56d374SYoshinobu Inoue 		cp = "Router Solicitation";
12697d56d374SYoshinobu Inoue 		break;
12707d56d374SYoshinobu Inoue 	case ND_ROUTER_ADVERT:
12717d56d374SYoshinobu Inoue 		cp = "Router Advertisement";
12727d56d374SYoshinobu Inoue 		break;
12737d56d374SYoshinobu Inoue 	case ND_NEIGHBOR_SOLICIT:
12747d56d374SYoshinobu Inoue 		cp = "Neighbor Solicitation";
12757d56d374SYoshinobu Inoue 		break;
12767d56d374SYoshinobu Inoue 	case ND_NEIGHBOR_ADVERT:
12777d56d374SYoshinobu Inoue 		cp = "Neighbor Advertisement";
12787d56d374SYoshinobu Inoue 		break;
12797d56d374SYoshinobu Inoue 	case ND_REDIRECT:
1280de68a0daSKris Kennaway 		cp = "Redirect";
12817d56d374SYoshinobu Inoue 		break;
12827d56d374SYoshinobu Inoue 	default:
12837d56d374SYoshinobu Inoue 		cp = "Unknown";
12847d56d374SYoshinobu Inoue 		break;
12857d56d374SYoshinobu Inoue 	}
12867d56d374SYoshinobu Inoue 	return cp;
12877d56d374SYoshinobu Inoue }
12887d56d374SYoshinobu Inoue 
12897d56d374SYoshinobu Inoue int
129064694fdcSMichael Tuexen packet_ok(struct msghdr *mhdr, int cc, int seq, u_char *type, u_char *code)
12917d56d374SYoshinobu Inoue {
1292e961704aSDavid Malone 	struct icmp6_hdr *icp;
12937d56d374SYoshinobu Inoue 	struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
12947d56d374SYoshinobu Inoue 	char *buf = (char *)mhdr->msg_iov[0].iov_base;
12957d56d374SYoshinobu Inoue 	struct cmsghdr *cm;
12967d56d374SYoshinobu Inoue 	int *hlimp;
1297de68a0daSKris Kennaway 	char hbuf[NI_MAXHOST];
12987d56d374SYoshinobu Inoue 
1299de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1300de68a0daSKris Kennaway 	int hlen;
1301de68a0daSKris Kennaway 	struct ip6_hdr *ip;
1302de68a0daSKris Kennaway #endif
1303de68a0daSKris Kennaway 
1304de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1305de68a0daSKris Kennaway 	ip = (struct ip6_hdr *) buf;
1306de68a0daSKris Kennaway 	hlen = sizeof(struct ip6_hdr);
1307de68a0daSKris Kennaway 	if (cc < hlen + sizeof(struct icmp6_hdr)) {
1308de68a0daSKris Kennaway 		if (verbose) {
1309*cc432e23SMariusz Zaborski 			if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len,
1310d24cb249SHajimu UMEMOTO 			    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
131133841545SHajimu UMEMOTO 				strlcpy(hbuf, "invalid", sizeof(hbuf));
1312c449e284SHajimu UMEMOTO 			printf("packet too short (%d bytes) from %s\n", cc,
1313de68a0daSKris Kennaway 			    hbuf);
1314de68a0daSKris Kennaway 		}
1315de68a0daSKris Kennaway 		return (0);
1316de68a0daSKris Kennaway 	}
1317de68a0daSKris Kennaway 	cc -= hlen;
1318de68a0daSKris Kennaway 	icp = (struct icmp6_hdr *)(buf + hlen);
1319de68a0daSKris Kennaway #else
1320f42640a3SUlrich Spörlein 	if (cc < (int)sizeof(struct icmp6_hdr)) {
1321de68a0daSKris Kennaway 		if (verbose) {
1322*cc432e23SMariusz Zaborski 			if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len,
1323d24cb249SHajimu UMEMOTO 			    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
132433841545SHajimu UMEMOTO 				strlcpy(hbuf, "invalid", sizeof(hbuf));
1325c449e284SHajimu UMEMOTO 			printf("data too short (%d bytes) from %s\n", cc, hbuf);
1326de68a0daSKris Kennaway 		}
13277d56d374SYoshinobu Inoue 		return (0);
13287d56d374SYoshinobu Inoue 	}
13297d56d374SYoshinobu Inoue 	icp = (struct icmp6_hdr *)buf;
1330de68a0daSKris Kennaway #endif
13317d56d374SYoshinobu Inoue 	/* get optional information via advanced API */
13327d56d374SYoshinobu Inoue 	rcvpktinfo = NULL;
13337d56d374SYoshinobu Inoue 	hlimp = NULL;
13347d56d374SYoshinobu Inoue 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
13357d56d374SYoshinobu Inoue 	    cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
13367d56d374SYoshinobu Inoue 		if (cm->cmsg_level == IPPROTO_IPV6 &&
13377d56d374SYoshinobu Inoue 		    cm->cmsg_type == IPV6_PKTINFO &&
13387d56d374SYoshinobu Inoue 		    cm->cmsg_len ==
13397d56d374SYoshinobu Inoue 		    CMSG_LEN(sizeof(struct in6_pktinfo)))
13407d56d374SYoshinobu Inoue 			rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm));
13417d56d374SYoshinobu Inoue 
13427d56d374SYoshinobu Inoue 		if (cm->cmsg_level == IPPROTO_IPV6 &&
13437d56d374SYoshinobu Inoue 		    cm->cmsg_type == IPV6_HOPLIMIT &&
13447d56d374SYoshinobu Inoue 		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
13457d56d374SYoshinobu Inoue 			hlimp = (int *)CMSG_DATA(cm);
13467d56d374SYoshinobu Inoue 	}
13477d56d374SYoshinobu Inoue 	if (rcvpktinfo == NULL || hlimp == NULL) {
13487d56d374SYoshinobu Inoue 		warnx("failed to get received hop limit or packet info");
1349de68a0daSKris Kennaway #if 0
13507d56d374SYoshinobu Inoue 		return (0);
1351de68a0daSKris Kennaway #else
1352de68a0daSKris Kennaway 		rcvhlim = 0;	/*XXX*/
1353de68a0daSKris Kennaway #endif
13547d56d374SYoshinobu Inoue 	}
1355de68a0daSKris Kennaway 	else
13567d56d374SYoshinobu Inoue 		rcvhlim = *hlimp;
13577d56d374SYoshinobu Inoue 
135864694fdcSMichael Tuexen 	*type = icp->icmp6_type;
135964694fdcSMichael Tuexen 	*code = icp->icmp6_code;
136064694fdcSMichael Tuexen 	if ((*type == ICMP6_TIME_EXCEEDED &&
136164694fdcSMichael Tuexen 	    *code == ICMP6_TIME_EXCEED_TRANSIT) ||
13621f69b3fbSMichael Tuexen 	    (*type == ICMP6_DST_UNREACH) ||
13631f69b3fbSMichael Tuexen 	    (*type == ICMP6_PARAM_PROB &&
13641f69b3fbSMichael Tuexen 	    *code == ICMP6_PARAMPROB_NEXTHEADER)) {
13657d56d374SYoshinobu Inoue 		struct ip6_hdr *hip;
1366aa96470cSMichael Tuexen 		struct icmp6_hdr *icmp;
136751eff8efSMichael Tuexen 		struct sctp_init_chunk *init;
13689d8b46c8SMichael Tuexen 		struct sctphdr *sctp;
13699d8b46c8SMichael Tuexen 		struct tcphdr *tcp;
1370aa96470cSMichael Tuexen 		struct udphdr *udp;
1371d7b63fafSDavid Malone 		void *up;
13727d56d374SYoshinobu Inoue 
13737d56d374SYoshinobu Inoue 		hip = (struct ip6_hdr *)(icp + 1);
1374d7b63fafSDavid Malone 		if ((up = get_uphdr(hip, (u_char *)(buf + cc))) == NULL) {
13757d56d374SYoshinobu Inoue 			if (verbose)
13767d56d374SYoshinobu Inoue 				warnx("failed to get upper layer header");
13777d56d374SYoshinobu Inoue 			return (0);
13787d56d374SYoshinobu Inoue 		}
1379d7b63fafSDavid Malone 		switch (useproto) {
1380d7b63fafSDavid Malone 		case IPPROTO_ICMPV6:
1381aa96470cSMichael Tuexen 			icmp = (struct icmp6_hdr *)up;
1382aa96470cSMichael Tuexen 			if (icmp->icmp6_id == ident &&
1383aa96470cSMichael Tuexen 			    icmp->icmp6_seq == htons(seq))
138464694fdcSMichael Tuexen 				return (1);
1385d7b63fafSDavid Malone 			break;
1386d7b63fafSDavid Malone 		case IPPROTO_UDP:
1387aa96470cSMichael Tuexen 			udp = (struct udphdr *)up;
1388*cc432e23SMariusz Zaborski 			if (udp->uh_sport == htons(ident) &&
1389aa96470cSMichael Tuexen 			    udp->uh_dport == htons(port + seq))
139064694fdcSMichael Tuexen 				return (1);
1391d7b63fafSDavid Malone 			break;
13929d8b46c8SMichael Tuexen 		case IPPROTO_SCTP:
13939d8b46c8SMichael Tuexen 			sctp = (struct sctphdr *)up;
139451eff8efSMichael Tuexen 			if (sctp->src_port != htons(ident) ||
139551eff8efSMichael Tuexen 			    sctp->dest_port != htons(port + seq)) {
139651eff8efSMichael Tuexen 				break;
139751eff8efSMichael Tuexen 			}
139851eff8efSMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
139951eff8efSMichael Tuexen 			    sizeof(struct sctp_init_chunk))) {
140051eff8efSMichael Tuexen 				if (sctp->v_tag != 0) {
140151eff8efSMichael Tuexen 					break;
140251eff8efSMichael Tuexen 				}
140351eff8efSMichael Tuexen 				init = (struct sctp_init_chunk *)(sctp + 1);
140451eff8efSMichael Tuexen 				/* Check the initiate tag, if available. */
140551eff8efSMichael Tuexen 				if ((char *)&init->init.a_rwnd > buf + cc) {
140664694fdcSMichael Tuexen 					return (1);
140751eff8efSMichael Tuexen 				}
140851eff8efSMichael Tuexen 				if (init->init.initiate_tag == (u_int32_t)
140951eff8efSMichael Tuexen 				    ((sctp->src_port << 16) | sctp->dest_port)) {
141064694fdcSMichael Tuexen 					return (1);
141151eff8efSMichael Tuexen 				}
141251eff8efSMichael Tuexen 			} else {
141351eff8efSMichael Tuexen 				if (sctp->v_tag ==
141451eff8efSMichael Tuexen 				    (u_int32_t)((sctp->src_port << 16) |
141551eff8efSMichael Tuexen 				    sctp->dest_port)) {
141664694fdcSMichael Tuexen 					return (1);
141751eff8efSMichael Tuexen 				}
141851eff8efSMichael Tuexen 			}
14199d8b46c8SMichael Tuexen 			break;
14209d8b46c8SMichael Tuexen 		case IPPROTO_TCP:
14219d8b46c8SMichael Tuexen 			tcp = (struct tcphdr *)up;
14229d8b46c8SMichael Tuexen 			if (tcp->th_sport == htons(ident) &&
14239d8b46c8SMichael Tuexen 			    tcp->th_dport == htons(port + seq) &&
14249d8b46c8SMichael Tuexen 			    tcp->th_seq ==
14259d8b46c8SMichael Tuexen 			    (tcp_seq)((tcp->th_sport << 16) | tcp->th_dport))
142664694fdcSMichael Tuexen 				return (1);
14279d8b46c8SMichael Tuexen 			break;
1428d7b63fafSDavid Malone 		case IPPROTO_NONE:
142964694fdcSMichael Tuexen 			return (1);
1430d7b63fafSDavid Malone 		default:
1431d7b63fafSDavid Malone 			fprintf(stderr, "Unknown probe proto %d.\n", useproto);
1432d7b63fafSDavid Malone 			break;
1433d7b63fafSDavid Malone 		}
143464694fdcSMichael Tuexen 	} else if (useproto == IPPROTO_ICMPV6 && *type == ICMP6_ECHO_REPLY) {
143584a1a4cfSHajimu UMEMOTO 		if (icp->icmp6_id == ident &&
143684a1a4cfSHajimu UMEMOTO 		    icp->icmp6_seq == htons(seq))
143764694fdcSMichael Tuexen 			return (1);
14387d56d374SYoshinobu Inoue 	}
14397d56d374SYoshinobu Inoue 	if (verbose) {
1440de68a0daSKris Kennaway 		char sbuf[NI_MAXHOST+1], dbuf[INET6_ADDRSTRLEN];
1441e961704aSDavid Malone 		u_int8_t *p;
1442e961704aSDavid Malone 		int i;
14437d56d374SYoshinobu Inoue 
1444*cc432e23SMariusz Zaborski 		if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len,
1445d24cb249SHajimu UMEMOTO 		    sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0)
1446c449e284SHajimu UMEMOTO 			strlcpy(sbuf, "invalid", sizeof(sbuf));
1447c449e284SHajimu UMEMOTO 		printf("\n%d bytes from %s to %s", cc, sbuf,
1448de68a0daSKris Kennaway 		    rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1449c449e284SHajimu UMEMOTO 		    dbuf, sizeof(dbuf)) : "?");
145064694fdcSMichael Tuexen 		printf(": icmp type %d (%s) code %d\n", *type, pr_type(*type),
145164694fdcSMichael Tuexen 		    *code);
1452de68a0daSKris Kennaway 		p = (u_int8_t *)(icp + 1);
1453de68a0daSKris Kennaway #define WIDTH	16
1454de68a0daSKris Kennaway 		for (i = 0; i < cc; i++) {
1455de68a0daSKris Kennaway 			if (i % WIDTH == 0)
1456c449e284SHajimu UMEMOTO 				printf("%04x:", i);
1457de68a0daSKris Kennaway 			if (i % 4 == 0)
1458c449e284SHajimu UMEMOTO 				printf(" ");
1459c449e284SHajimu UMEMOTO 			printf("%02x", p[i]);
1460de68a0daSKris Kennaway 			if (i % WIDTH == WIDTH - 1)
1461c449e284SHajimu UMEMOTO 				printf("\n");
1462de68a0daSKris Kennaway 		}
1463de68a0daSKris Kennaway 		if (cc % WIDTH != 0)
1464c449e284SHajimu UMEMOTO 			printf("\n");
14657d56d374SYoshinobu Inoue 	}
14667d56d374SYoshinobu Inoue 	return (0);
14677d56d374SYoshinobu Inoue }
14687d56d374SYoshinobu Inoue 
14697d56d374SYoshinobu Inoue /*
147084a1a4cfSHajimu UMEMOTO  * Increment pointer until find the UDP or ICMP header.
14717d56d374SYoshinobu Inoue  */
1472d7b63fafSDavid Malone void *
1473aa96470cSMichael Tuexen get_uphdr(struct ip6_hdr *ip6, u_char *lim)
14747d56d374SYoshinobu Inoue {
14757d56d374SYoshinobu Inoue 	u_char *cp = (u_char *)ip6, nh;
14767d56d374SYoshinobu Inoue 	int hlen;
1477d7b63fafSDavid Malone 	static u_char none_hdr[1]; /* Fake pointer for IPPROTO_NONE. */
14787d56d374SYoshinobu Inoue 
1479d7b63fafSDavid Malone 	if (cp + sizeof(*ip6) > lim)
14807d56d374SYoshinobu Inoue 		return (NULL);
14817d56d374SYoshinobu Inoue 
14827d56d374SYoshinobu Inoue 	nh = ip6->ip6_nxt;
14837d56d374SYoshinobu Inoue 	cp += sizeof(struct ip6_hdr);
14847d56d374SYoshinobu Inoue 
1485d7b63fafSDavid Malone 	while (lim - cp >= (nh == IPPROTO_NONE ? 0 : 8)) {
14867d56d374SYoshinobu Inoue 		switch (nh) {
14877d56d374SYoshinobu Inoue 		case IPPROTO_ESP:
14887d56d374SYoshinobu Inoue 			return (NULL);
148984a1a4cfSHajimu UMEMOTO 		case IPPROTO_ICMPV6:
1490d7b63fafSDavid Malone 			return (useproto == nh ? cp : NULL);
14919d8b46c8SMichael Tuexen 		case IPPROTO_SCTP:
14929d8b46c8SMichael Tuexen 		case IPPROTO_TCP:
14937d56d374SYoshinobu Inoue 		case IPPROTO_UDP:
1494d7b63fafSDavid Malone 			return (useproto == nh ? cp : NULL);
1495d7b63fafSDavid Malone 		case IPPROTO_NONE:
1496d7b63fafSDavid Malone 			return (useproto == nh ? none_hdr : NULL);
14977d56d374SYoshinobu Inoue 		case IPPROTO_FRAGMENT:
14987d56d374SYoshinobu Inoue 			hlen = sizeof(struct ip6_frag);
14997d56d374SYoshinobu Inoue 			nh = ((struct ip6_frag *)cp)->ip6f_nxt;
15007d56d374SYoshinobu Inoue 			break;
15017d56d374SYoshinobu Inoue 		case IPPROTO_AH:
15027d56d374SYoshinobu Inoue 			hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2;
15037d56d374SYoshinobu Inoue 			nh = ((struct ip6_ext *)cp)->ip6e_nxt;
15047d56d374SYoshinobu Inoue 			break;
15057d56d374SYoshinobu Inoue 		default:
15067d56d374SYoshinobu Inoue 			hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3;
15077d56d374SYoshinobu Inoue 			nh = ((struct ip6_ext *)cp)->ip6e_nxt;
15087d56d374SYoshinobu Inoue 			break;
15097d56d374SYoshinobu Inoue 		}
15107d56d374SYoshinobu Inoue 
15117d56d374SYoshinobu Inoue 		cp += hlen;
15127d56d374SYoshinobu Inoue 	}
15137d56d374SYoshinobu Inoue 
15147d56d374SYoshinobu Inoue 	return (NULL);
15157d56d374SYoshinobu Inoue }
15167d56d374SYoshinobu Inoue 
15177d56d374SYoshinobu Inoue void
1518*cc432e23SMariusz Zaborski capdns_open()
1519*cc432e23SMariusz Zaborski {
1520*cc432e23SMariusz Zaborski 	const char *types[] = { "NAME", "ADDR" };
1521*cc432e23SMariusz Zaborski 	int families[1];
1522*cc432e23SMariusz Zaborski 	cap_channel_t *casper;
1523*cc432e23SMariusz Zaborski 
1524*cc432e23SMariusz Zaborski 	casper = cap_init();
1525*cc432e23SMariusz Zaborski 	if (casper == NULL)
1526*cc432e23SMariusz Zaborski 		errx(1, "unable to create casper process");
1527*cc432e23SMariusz Zaborski 	capdns = cap_service_open(casper, "system.dns");
1528*cc432e23SMariusz Zaborski 	if (capdns == NULL)
1529*cc432e23SMariusz Zaborski 		errx(1, "unable to open system.dns service");
1530*cc432e23SMariusz Zaborski 	if (cap_dns_type_limit(capdns, types, nitems(types)) < 0)
1531*cc432e23SMariusz Zaborski 		errx(1, "unable to limit access to system.dns service");
1532*cc432e23SMariusz Zaborski 	families[0] = AF_INET6;
1533*cc432e23SMariusz Zaborski 	if (cap_dns_family_limit(capdns, families, nitems(families)) < 0)
1534*cc432e23SMariusz Zaborski 		errx(1, "unable to limit access to system.dns service");
1535*cc432e23SMariusz Zaborski 	cap_close(casper);
1536*cc432e23SMariusz Zaborski }
1537*cc432e23SMariusz Zaborski 
1538*cc432e23SMariusz Zaborski void
1539aa96470cSMichael Tuexen print(struct msghdr *mhdr, int cc)
15407d56d374SYoshinobu Inoue {
15417d56d374SYoshinobu Inoue 	struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
1542de68a0daSKris Kennaway 	char hbuf[NI_MAXHOST];
15437d56d374SYoshinobu Inoue 
1544*cc432e23SMariusz Zaborski 	if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len,
1545d24cb249SHajimu UMEMOTO 	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
154633841545SHajimu UMEMOTO 		strlcpy(hbuf, "invalid", sizeof(hbuf));
1547d429d720SHajimu UMEMOTO 	if (as_path)
1548d429d720SHajimu UMEMOTO 		printf(" [AS%u]", as_lookup(asn, hbuf, AF_INET6));
1549de68a0daSKris Kennaway 	if (nflag)
1550c449e284SHajimu UMEMOTO 		printf(" %s", hbuf);
1551de68a0daSKris Kennaway 	else if (lflag)
1552c449e284SHajimu UMEMOTO 		printf(" %s (%s)", inetname((struct sockaddr *)from), hbuf);
1553de68a0daSKris Kennaway 	else
1554c449e284SHajimu UMEMOTO 		printf(" %s", inetname((struct sockaddr *)from));
15557d56d374SYoshinobu Inoue 
15567d56d374SYoshinobu Inoue 	if (verbose) {
1557de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1558c449e284SHajimu UMEMOTO 		printf(" %d bytes to %s", cc,
1559de68a0daSKris Kennaway 		    rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1560c449e284SHajimu UMEMOTO 		    hbuf, sizeof(hbuf)) : "?");
1561de68a0daSKris Kennaway #else
1562c449e284SHajimu UMEMOTO 		printf(" %d bytes of data to %s", cc,
1563de68a0daSKris Kennaway 		    rcvpktinfo ?  inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1564c449e284SHajimu UMEMOTO 		    hbuf, sizeof(hbuf)) : "?");
1565de68a0daSKris Kennaway #endif
15667d56d374SYoshinobu Inoue 	}
15677d56d374SYoshinobu Inoue }
15687d56d374SYoshinobu Inoue 
15697d56d374SYoshinobu Inoue /*
15707d56d374SYoshinobu Inoue  * Construct an Internet address representation.
15717d56d374SYoshinobu Inoue  * If the nflag has been supplied, give
15727d56d374SYoshinobu Inoue  * numeric value, otherwise try for symbolic name.
15737d56d374SYoshinobu Inoue  */
1574de68a0daSKris Kennaway const char *
1575aa96470cSMichael Tuexen inetname(struct sockaddr *sa)
15767d56d374SYoshinobu Inoue {
1577e961704aSDavid Malone 	static char line[NI_MAXHOST], domain[MAXHOSTNAMELEN + 1];
15787d56d374SYoshinobu Inoue 	static int first = 1;
1579e961704aSDavid Malone 	char *cp;
15807d56d374SYoshinobu Inoue 
15817d56d374SYoshinobu Inoue 	if (first && !nflag) {
15827d56d374SYoshinobu Inoue 		first = 0;
1583c449e284SHajimu UMEMOTO 		if (gethostname(domain, sizeof(domain)) == 0 &&
1584c449e284SHajimu UMEMOTO 		    (cp = strchr(domain, '.')))
158533841545SHajimu UMEMOTO 			(void) strlcpy(domain, cp + 1, sizeof(domain));
15867d56d374SYoshinobu Inoue 		else
15877d56d374SYoshinobu Inoue 			domain[0] = 0;
15887d56d374SYoshinobu Inoue 	}
1589de68a0daSKris Kennaway 	cp = NULL;
15907d56d374SYoshinobu Inoue 	if (!nflag) {
1591*cc432e23SMariusz Zaborski 		if (cap_getnameinfo(capdns, sa, sa->sa_len, line, sizeof(line), NULL, 0,
1592de68a0daSKris Kennaway 		    NI_NAMEREQD) == 0) {
1593c449e284SHajimu UMEMOTO 			if ((cp = strchr(line, '.')) &&
15947d56d374SYoshinobu Inoue 			    !strcmp(cp + 1, domain))
15957d56d374SYoshinobu Inoue 				*cp = 0;
1596de68a0daSKris Kennaway 			cp = line;
15977d56d374SYoshinobu Inoue 		}
15987d56d374SYoshinobu Inoue 	}
15997d56d374SYoshinobu Inoue 	if (cp)
1600de68a0daSKris Kennaway 		return cp;
1601de68a0daSKris Kennaway 
1602*cc432e23SMariusz Zaborski 	if (cap_getnameinfo(capdns, sa, sa->sa_len, line, sizeof(line), NULL, 0,
1603d24cb249SHajimu UMEMOTO 	    NI_NUMERICHOST) != 0)
160433841545SHajimu UMEMOTO 		strlcpy(line, "invalid", sizeof(line));
1605de68a0daSKris Kennaway 	return line;
16067d56d374SYoshinobu Inoue }
16077d56d374SYoshinobu Inoue 
16089d8b46c8SMichael Tuexen /*
16099d8b46c8SMichael Tuexen  * CRC32C routine for the Stream Control Transmission Protocol
16109d8b46c8SMichael Tuexen  */
16119d8b46c8SMichael Tuexen 
16129d8b46c8SMichael Tuexen #define CRC32C(c, d) (c = (c>>8) ^ crc_c[(c^(d))&0xFF])
16139d8b46c8SMichael Tuexen 
16149d8b46c8SMichael Tuexen static u_int32_t crc_c[256] = {
16159d8b46c8SMichael Tuexen 	0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
16169d8b46c8SMichael Tuexen 	0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
16179d8b46c8SMichael Tuexen 	0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
16189d8b46c8SMichael Tuexen 	0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
16199d8b46c8SMichael Tuexen 	0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
16209d8b46c8SMichael Tuexen 	0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
16219d8b46c8SMichael Tuexen 	0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
16229d8b46c8SMichael Tuexen 	0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
16239d8b46c8SMichael Tuexen 	0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
16249d8b46c8SMichael Tuexen 	0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
16259d8b46c8SMichael Tuexen 	0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
16269d8b46c8SMichael Tuexen 	0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
16279d8b46c8SMichael Tuexen 	0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
16289d8b46c8SMichael Tuexen 	0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
16299d8b46c8SMichael Tuexen 	0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
16309d8b46c8SMichael Tuexen 	0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
16319d8b46c8SMichael Tuexen 	0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
16329d8b46c8SMichael Tuexen 	0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
16339d8b46c8SMichael Tuexen 	0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
16349d8b46c8SMichael Tuexen 	0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
16359d8b46c8SMichael Tuexen 	0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
16369d8b46c8SMichael Tuexen 	0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
16379d8b46c8SMichael Tuexen 	0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
16389d8b46c8SMichael Tuexen 	0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
16399d8b46c8SMichael Tuexen 	0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
16409d8b46c8SMichael Tuexen 	0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
16419d8b46c8SMichael Tuexen 	0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
16429d8b46c8SMichael Tuexen 	0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
16439d8b46c8SMichael Tuexen 	0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
16449d8b46c8SMichael Tuexen 	0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
16459d8b46c8SMichael Tuexen 	0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
16469d8b46c8SMichael Tuexen 	0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
16479d8b46c8SMichael Tuexen 	0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
16489d8b46c8SMichael Tuexen 	0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
16499d8b46c8SMichael Tuexen 	0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
16509d8b46c8SMichael Tuexen 	0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
16519d8b46c8SMichael Tuexen 	0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
16529d8b46c8SMichael Tuexen 	0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
16539d8b46c8SMichael Tuexen 	0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
16549d8b46c8SMichael Tuexen 	0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
16559d8b46c8SMichael Tuexen 	0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
16569d8b46c8SMichael Tuexen 	0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
16579d8b46c8SMichael Tuexen 	0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
16589d8b46c8SMichael Tuexen 	0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
16599d8b46c8SMichael Tuexen 	0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
16609d8b46c8SMichael Tuexen 	0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
16619d8b46c8SMichael Tuexen 	0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
16629d8b46c8SMichael Tuexen 	0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
16639d8b46c8SMichael Tuexen 	0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
16649d8b46c8SMichael Tuexen 	0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
16659d8b46c8SMichael Tuexen 	0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
16669d8b46c8SMichael Tuexen 	0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
16679d8b46c8SMichael Tuexen 	0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
16689d8b46c8SMichael Tuexen 	0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
16699d8b46c8SMichael Tuexen 	0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
16709d8b46c8SMichael Tuexen 	0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
16719d8b46c8SMichael Tuexen 	0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
16729d8b46c8SMichael Tuexen 	0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
16739d8b46c8SMichael Tuexen 	0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
16749d8b46c8SMichael Tuexen 	0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
16759d8b46c8SMichael Tuexen 	0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
16769d8b46c8SMichael Tuexen 	0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
16779d8b46c8SMichael Tuexen 	0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
16789d8b46c8SMichael Tuexen 	0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
16799d8b46c8SMichael Tuexen };
16809d8b46c8SMichael Tuexen 
16819d8b46c8SMichael Tuexen u_int32_t
1682ca19d0d7SMark Johnston sctp_crc32c(void *pack, u_int32_t len)
16839d8b46c8SMichael Tuexen {
16849d8b46c8SMichael Tuexen 	u_int32_t i, crc32c;
16859d8b46c8SMichael Tuexen 	u_int8_t byte0, byte1, byte2, byte3;
1686ca19d0d7SMark Johnston 	u_int8_t *buf = (u_int8_t *)pack;
16879d8b46c8SMichael Tuexen 
16889d8b46c8SMichael Tuexen 	crc32c = ~0;
16899d8b46c8SMichael Tuexen 	for (i = 0; i < len; i++)
16909d8b46c8SMichael Tuexen 		CRC32C(crc32c, buf[i]);
16919d8b46c8SMichael Tuexen 	crc32c = ~crc32c;
16929d8b46c8SMichael Tuexen 	byte0  = crc32c & 0xff;
16939d8b46c8SMichael Tuexen 	byte1  = (crc32c>>8) & 0xff;
16949d8b46c8SMichael Tuexen 	byte2  = (crc32c>>16) & 0xff;
16959d8b46c8SMichael Tuexen 	byte3  = (crc32c>>24) & 0xff;
16969d8b46c8SMichael Tuexen 	crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
16979d8b46c8SMichael Tuexen 	return htonl(crc32c);
16989d8b46c8SMichael Tuexen }
16999d8b46c8SMichael Tuexen 
17009d8b46c8SMichael Tuexen u_int16_t
17019d8b46c8SMichael Tuexen in_cksum(u_int16_t *addr, int len)
17029d8b46c8SMichael Tuexen {
17039d8b46c8SMichael Tuexen 	int nleft = len;
17049d8b46c8SMichael Tuexen 	u_int16_t *w = addr;
17059d8b46c8SMichael Tuexen 	u_int16_t answer;
17069d8b46c8SMichael Tuexen 	int sum = 0;
17079d8b46c8SMichael Tuexen 
17089d8b46c8SMichael Tuexen 	/*
17099d8b46c8SMichael Tuexen 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
17109d8b46c8SMichael Tuexen 	 *  we add sequential 16 bit words to it, and at the end, fold
17119d8b46c8SMichael Tuexen 	 *  back all the carry bits from the top 16 bits into the lower
17129d8b46c8SMichael Tuexen 	 *  16 bits.
17139d8b46c8SMichael Tuexen 	 */
17149d8b46c8SMichael Tuexen 	while (nleft > 1)  {
17159d8b46c8SMichael Tuexen 		sum += *w++;
17169d8b46c8SMichael Tuexen 		nleft -= 2;
17179d8b46c8SMichael Tuexen 	}
17189d8b46c8SMichael Tuexen 
17199d8b46c8SMichael Tuexen 	/* mop up an odd byte, if necessary */
17209d8b46c8SMichael Tuexen 	if (nleft == 1)
17219d8b46c8SMichael Tuexen 		sum += *(u_char *)w;
17229d8b46c8SMichael Tuexen 
17239d8b46c8SMichael Tuexen 	/*
17249d8b46c8SMichael Tuexen 	 * add back carry outs from top 16 bits to low 16 bits
17259d8b46c8SMichael Tuexen 	 */
17269d8b46c8SMichael Tuexen 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
17279d8b46c8SMichael Tuexen 	sum += (sum >> 16);			/* add carry */
17289d8b46c8SMichael Tuexen 	answer = ~sum;				/* truncate to 16 bits */
17299d8b46c8SMichael Tuexen 	return (answer);
17309d8b46c8SMichael Tuexen }
17319d8b46c8SMichael Tuexen 
17329d8b46c8SMichael Tuexen u_int16_t
1733*cc432e23SMariusz Zaborski udp_cksum(struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
1734*cc432e23SMariusz Zaborski     void *payload, u_int32_t len)
1735*cc432e23SMariusz Zaborski {
1736*cc432e23SMariusz Zaborski 	struct {
1737*cc432e23SMariusz Zaborski 		struct in6_addr src;
1738*cc432e23SMariusz Zaborski 		struct in6_addr dst;
1739*cc432e23SMariusz Zaborski 		u_int32_t len;
1740*cc432e23SMariusz Zaborski 		u_int8_t zero[3];
1741*cc432e23SMariusz Zaborski 		u_int8_t next;
1742*cc432e23SMariusz Zaborski 	} pseudo_hdr;
1743*cc432e23SMariusz Zaborski 	u_int16_t sum[2];
1744*cc432e23SMariusz Zaborski 
1745*cc432e23SMariusz Zaborski 	pseudo_hdr.src = src->sin6_addr;
1746*cc432e23SMariusz Zaborski 	pseudo_hdr.dst = dst->sin6_addr;
1747*cc432e23SMariusz Zaborski 	pseudo_hdr.len = htonl(len);
1748*cc432e23SMariusz Zaborski 	pseudo_hdr.zero[0] = 0;
1749*cc432e23SMariusz Zaborski 	pseudo_hdr.zero[1] = 0;
1750*cc432e23SMariusz Zaborski 	pseudo_hdr.zero[2] = 0;
1751*cc432e23SMariusz Zaborski 	pseudo_hdr.next = IPPROTO_UDP;
1752*cc432e23SMariusz Zaborski 
1753*cc432e23SMariusz Zaborski 	sum[1] = in_cksum((u_int16_t *)&pseudo_hdr, sizeof(pseudo_hdr));
1754*cc432e23SMariusz Zaborski 	sum[0] = in_cksum(payload, len);
1755*cc432e23SMariusz Zaborski 
1756*cc432e23SMariusz Zaborski 	return (~in_cksum(sum, sizeof(sum)));
1757*cc432e23SMariusz Zaborski }
1758*cc432e23SMariusz Zaborski 
1759*cc432e23SMariusz Zaborski u_int16_t
17609d8b46c8SMichael Tuexen tcp_chksum(struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
17619d8b46c8SMichael Tuexen     void *payload, u_int32_t len)
17629d8b46c8SMichael Tuexen {
17639d8b46c8SMichael Tuexen 	struct {
17649d8b46c8SMichael Tuexen 		struct in6_addr src;
17659d8b46c8SMichael Tuexen 		struct in6_addr dst;
17669d8b46c8SMichael Tuexen 		u_int32_t len;
17679d8b46c8SMichael Tuexen 		u_int8_t zero[3];
17689d8b46c8SMichael Tuexen 		u_int8_t next;
17699d8b46c8SMichael Tuexen 	} pseudo_hdr;
17709d8b46c8SMichael Tuexen 	u_int16_t sum[2];
17719d8b46c8SMichael Tuexen 
17729d8b46c8SMichael Tuexen 	pseudo_hdr.src = src->sin6_addr;
17739d8b46c8SMichael Tuexen 	pseudo_hdr.dst = dst->sin6_addr;
17749d8b46c8SMichael Tuexen 	pseudo_hdr.len = htonl(len);
17759d8b46c8SMichael Tuexen 	pseudo_hdr.zero[0] = 0;
17769d8b46c8SMichael Tuexen 	pseudo_hdr.zero[1] = 0;
17779d8b46c8SMichael Tuexen 	pseudo_hdr.zero[2] = 0;
17789d8b46c8SMichael Tuexen 	pseudo_hdr.next = IPPROTO_TCP;
17799d8b46c8SMichael Tuexen 
17809d8b46c8SMichael Tuexen 	sum[1] = in_cksum((u_int16_t *)&pseudo_hdr, sizeof(pseudo_hdr));
17819d8b46c8SMichael Tuexen 	sum[0] = in_cksum(payload, len);
17829d8b46c8SMichael Tuexen 
17839d8b46c8SMichael Tuexen 	return (~in_cksum(sum, sizeof(sum)));
17849d8b46c8SMichael Tuexen }
17859d8b46c8SMichael Tuexen 
17867d56d374SYoshinobu Inoue void
1787aa96470cSMichael Tuexen usage(void)
17887d56d374SYoshinobu Inoue {
178984a1a4cfSHajimu UMEMOTO 
179084a1a4cfSHajimu UMEMOTO 	fprintf(stderr,
17919d8b46c8SMichael Tuexen "usage: traceroute6 [-adIlnNrSTUv] [-A as_server] [-f firsthop] [-g gateway]\n"
17920d7d117cSHajimu UMEMOTO "       [-m hoplimit] [-p port] [-q probes] [-s src] [-w waittime] target\n"
17930d7d117cSHajimu UMEMOTO "       [datalen]\n");
17947d56d374SYoshinobu Inoue 	exit(1);
17957d56d374SYoshinobu Inoue }
1796