xref: /freebsd/usr.sbin/traceroute6/traceroute6.c (revision 1d712c05370dca8cbf81d1ecd9acd606fdcacaf4)
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>
252cc432e23SMariusz 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 
264cc432e23SMariusz Zaborski #include <libcasper.h>
265cc432e23SMariusz Zaborski #include <casper/cap_dns.h>
266cc432e23SMariusz Zaborski #include <capsicum_helpers.h>
267cc432e23SMariusz 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 *);
307cc432e23SMariusz 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);
316cc432e23SMariusz Zaborski u_int16_t udp_cksum(struct sockaddr_in6 *, struct sockaddr_in6 *,
317cc432e23SMariusz 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 
341cc432e23SMariusz Zaborski static cap_channel_t *capdns;
342cc432e23SMariusz 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;
349c7090651SMichael Tuexen static int tclass = -1;
350ca19d0d7SMark Johnston static int options;			/* socket options */
351ca19d0d7SMark Johnston static int verbose;
352ca19d0d7SMark Johnston static int waittime = 5;		/* time to wait for response (in seconds) */
353ca19d0d7SMark Johnston static int nflag;			/* print addresses numerically */
354ca19d0d7SMark Johnston static int useproto = IPPROTO_UDP;	/* protocol to use to send packet */
355ca19d0d7SMark Johnston static int lflag;			/* print both numerical address & hostname */
356ca19d0d7SMark Johnston static int as_path;			/* print as numbers for each hop */
357ca19d0d7SMark Johnston static char *as_server = NULL;
358ca19d0d7SMark Johnston static void *asn;
3597d56d374SYoshinobu Inoue 
3607d56d374SYoshinobu Inoue int
361aa96470cSMichael Tuexen main(int argc, char *argv[])
3627d56d374SYoshinobu Inoue {
36384a1a4cfSHajimu UMEMOTO 	int mib[4] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM };
364e961704aSDavid Malone 	char hbuf[NI_MAXHOST], src0[NI_MAXHOST], *ep;
365f42640a3SUlrich Spörlein 	int ch, i, on = 1, seq, rcvcmsglen, error;
366e961704aSDavid Malone 	struct addrinfo hints, *res;
367e961704aSDavid Malone 	static u_char *rcvcmsgbuf;
368c7090651SMichael Tuexen 	u_long probe, hops, lport, ltclass;
369e961704aSDavid Malone 	struct hostent *hp;
370f42640a3SUlrich Spörlein 	size_t size, minlen;
37119c7ed84SKevin Lo 	uid_t uid;
37264694fdcSMichael Tuexen 	u_char type, code;
373ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
374ca19d0d7SMark Johnston 	char ipsec_inpolicy[] = "in bypass";
375ca19d0d7SMark Johnston 	char ipsec_outpolicy[] = "out bypass";
376ca19d0d7SMark Johnston #endif
377cc432e23SMariusz Zaborski 	cap_rights_t rights;
378cc432e23SMariusz Zaborski 
379cc432e23SMariusz Zaborski 	capdns_open();
3807d56d374SYoshinobu Inoue 
38153c9088fSYoshinobu Inoue 	/*
38253c9088fSYoshinobu Inoue 	 * Receive ICMP
38353c9088fSYoshinobu Inoue 	 */
38453c9088fSYoshinobu Inoue 	if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
385de68a0daSKris Kennaway 		perror("socket(ICMPv6)");
38653c9088fSYoshinobu Inoue 		exit(5);
38753c9088fSYoshinobu Inoue 	}
388de68a0daSKris Kennaway 
38984a1a4cfSHajimu UMEMOTO 	size = sizeof(i);
39084a1a4cfSHajimu UMEMOTO 	(void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &i, &size, NULL, 0);
39184a1a4cfSHajimu UMEMOTO 	max_hops = i;
39284a1a4cfSHajimu UMEMOTO 
393de68a0daSKris Kennaway 	/* specify to tell receiving interface */
394de68a0daSKris Kennaway #ifdef IPV6_RECVPKTINFO
395de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
396de68a0daSKris Kennaway 	    sizeof(on)) < 0)
397de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_RECVPKTINFO)");
398de68a0daSKris Kennaway #else  /* old adv. API */
399de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
400de68a0daSKris Kennaway 	    sizeof(on)) < 0)
401de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_PKTINFO)");
402de68a0daSKris Kennaway #endif
403de68a0daSKris Kennaway 
404de68a0daSKris Kennaway 	/* specify to tell value of hoplimit field of received IP6 hdr */
405de68a0daSKris Kennaway #ifdef IPV6_RECVHOPLIMIT
406de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
407de68a0daSKris Kennaway 	    sizeof(on)) < 0)
408de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_RECVHOPLIMIT)");
409de68a0daSKris Kennaway #else  /* old adv. API */
410de68a0daSKris Kennaway 	if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
411de68a0daSKris Kennaway 	    sizeof(on)) < 0)
412de68a0daSKris Kennaway 		err(1, "setsockopt(IPV6_HOPLIMIT)");
413de68a0daSKris Kennaway #endif
414de68a0daSKris Kennaway 
4157d56d374SYoshinobu Inoue 	seq = 0;
4169d8b46c8SMichael Tuexen 	ident = htons(getpid() & 0xffff); /* same as ping6 */
4177d56d374SYoshinobu Inoue 
418c7090651SMichael Tuexen 	while ((ch = getopt(argc, argv, "aA:df:g:Ilm:nNp:q:rs:St:TUvw:")) != -1)
4197d56d374SYoshinobu Inoue 		switch (ch) {
420d429d720SHajimu UMEMOTO 		case 'a':
421d429d720SHajimu UMEMOTO 			as_path = 1;
422d429d720SHajimu UMEMOTO 			break;
423d429d720SHajimu UMEMOTO 		case 'A':
424d429d720SHajimu UMEMOTO 			as_path = 1;
425d429d720SHajimu UMEMOTO 			as_server = optarg;
426d429d720SHajimu UMEMOTO 			break;
4277d56d374SYoshinobu Inoue 		case 'd':
4287d56d374SYoshinobu Inoue 			options |= SO_DEBUG;
4297d56d374SYoshinobu Inoue 			break;
430de68a0daSKris Kennaway 		case 'f':
43133841545SHajimu UMEMOTO 			ep = NULL;
43284a1a4cfSHajimu UMEMOTO 			errno = 0;
43333841545SHajimu UMEMOTO 			first_hop = strtoul(optarg, &ep, 0);
43484a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep || first_hop > 255) {
435c449e284SHajimu UMEMOTO 				fprintf(stderr,
43633841545SHajimu UMEMOTO 				    "traceroute6: invalid min hoplimit.\n");
43733841545SHajimu UMEMOTO 				exit(1);
43833841545SHajimu UMEMOTO 			}
4397d56d374SYoshinobu Inoue 			break;
4407d56d374SYoshinobu Inoue 		case 'g':
441cc432e23SMariusz Zaborski 			/* XXX use after capability mode is entered */
4427d56d374SYoshinobu Inoue 			hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno);
4437d56d374SYoshinobu Inoue 			if (hp == NULL) {
444c449e284SHajimu UMEMOTO 				fprintf(stderr,
4457d56d374SYoshinobu Inoue 				    "traceroute6: unknown host %s\n", optarg);
4467d56d374SYoshinobu Inoue 				exit(1);
4477d56d374SYoshinobu Inoue 			}
448de68a0daSKris Kennaway 			if (rth == NULL) {
449de68a0daSKris Kennaway 				/*
450de68a0daSKris Kennaway 				 * XXX: We can't detect the number of
451de68a0daSKris Kennaway 				 * intermediate nodes yet.
452de68a0daSKris Kennaway 				 */
453de68a0daSKris Kennaway 				if ((rth = inet6_rth_init((void *)rtbuf,
454c449e284SHajimu UMEMOTO 				    sizeof(rtbuf), IPV6_RTHDR_TYPE_0,
455de68a0daSKris Kennaway 				    0)) == NULL) {
456c449e284SHajimu UMEMOTO 					fprintf(stderr,
457de68a0daSKris Kennaway 					    "inet6_rth_init failed.\n");
458de68a0daSKris Kennaway 					exit(1);
459de68a0daSKris Kennaway 				}
460de68a0daSKris Kennaway 			}
461de68a0daSKris Kennaway 			if (inet6_rth_add((void *)rth,
462de68a0daSKris Kennaway 			    (struct in6_addr *)hp->h_addr)) {
463c449e284SHajimu UMEMOTO 				fprintf(stderr,
464de68a0daSKris Kennaway 				    "inet6_rth_add failed for %s\n",
465de68a0daSKris Kennaway 				    optarg);
466de68a0daSKris Kennaway 				exit(1);
467de68a0daSKris Kennaway 			}
468de68a0daSKris Kennaway 			freehostent(hp);
469de68a0daSKris Kennaway 			break;
47084a1a4cfSHajimu UMEMOTO 		case 'I':
471d7b63fafSDavid Malone 			useproto = IPPROTO_ICMPV6;
47284a1a4cfSHajimu UMEMOTO 			break;
473de68a0daSKris Kennaway 		case 'l':
474de68a0daSKris Kennaway 			lflag++;
4757d56d374SYoshinobu Inoue 			break;
4767d56d374SYoshinobu Inoue 		case 'm':
47733841545SHajimu UMEMOTO 			ep = NULL;
47884a1a4cfSHajimu UMEMOTO 			errno = 0;
47933841545SHajimu UMEMOTO 			max_hops = strtoul(optarg, &ep, 0);
48084a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep || max_hops > 255) {
481c449e284SHajimu UMEMOTO 				fprintf(stderr,
48233841545SHajimu UMEMOTO 				    "traceroute6: invalid max hoplimit.\n");
48333841545SHajimu UMEMOTO 				exit(1);
48433841545SHajimu UMEMOTO 			}
4857d56d374SYoshinobu Inoue 			break;
4867d56d374SYoshinobu Inoue 		case 'n':
4877d56d374SYoshinobu Inoue 			nflag++;
4887d56d374SYoshinobu Inoue 			break;
489d7b63fafSDavid Malone 		case 'N':
490d7b63fafSDavid Malone 			useproto = IPPROTO_NONE;
491d7b63fafSDavid Malone 			break;
4927d56d374SYoshinobu Inoue 		case 'p':
49333841545SHajimu UMEMOTO 			ep = NULL;
49484a1a4cfSHajimu UMEMOTO 			errno = 0;
49584a1a4cfSHajimu UMEMOTO 			lport = strtoul(optarg, &ep, 0);
49684a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep) {
49784a1a4cfSHajimu UMEMOTO 				fprintf(stderr, "traceroute6: invalid port.\n");
49833841545SHajimu UMEMOTO 				exit(1);
49933841545SHajimu UMEMOTO 			}
50084a1a4cfSHajimu UMEMOTO 			if (lport == 0 || lport != (lport & 0xffff)) {
501c449e284SHajimu UMEMOTO 				fprintf(stderr,
50284a1a4cfSHajimu UMEMOTO 				    "traceroute6: port out of range.\n");
5037d56d374SYoshinobu Inoue 				exit(1);
5047d56d374SYoshinobu Inoue 			}
50584a1a4cfSHajimu UMEMOTO 			port = lport & 0xffff;
5067d56d374SYoshinobu Inoue 			break;
5077d56d374SYoshinobu Inoue 		case 'q':
50833841545SHajimu UMEMOTO 			ep = NULL;
50984a1a4cfSHajimu UMEMOTO 			errno = 0;
51033841545SHajimu UMEMOTO 			nprobes = strtoul(optarg, &ep, 0);
51184a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep) {
512c449e284SHajimu UMEMOTO 				fprintf(stderr,
51333841545SHajimu UMEMOTO 				    "traceroute6: invalid nprobes.\n");
51433841545SHajimu UMEMOTO 				exit(1);
51533841545SHajimu UMEMOTO 			}
5167d56d374SYoshinobu Inoue 			if (nprobes < 1) {
517c449e284SHajimu UMEMOTO 				fprintf(stderr,
5187d56d374SYoshinobu Inoue 				    "traceroute6: nprobes must be >0.\n");
5197d56d374SYoshinobu Inoue 				exit(1);
5207d56d374SYoshinobu Inoue 			}
5217d56d374SYoshinobu Inoue 			break;
5227d56d374SYoshinobu Inoue 		case 'r':
5237d56d374SYoshinobu Inoue 			options |= SO_DONTROUTE;
5247d56d374SYoshinobu Inoue 			break;
5257d56d374SYoshinobu Inoue 		case 's':
5267d56d374SYoshinobu Inoue 			/*
5277d56d374SYoshinobu Inoue 			 * set the ip source address of the outbound
5287d56d374SYoshinobu Inoue 			 * probe (e.g., on a multi-homed host).
5297d56d374SYoshinobu Inoue 			 */
5307d56d374SYoshinobu Inoue 			source = optarg;
5317d56d374SYoshinobu Inoue 			break;
5329d8b46c8SMichael Tuexen 		case 'S':
5339d8b46c8SMichael Tuexen 			useproto = IPPROTO_SCTP;
5349d8b46c8SMichael Tuexen 			break;
535c7090651SMichael Tuexen 		case 't':
536c7090651SMichael Tuexen 			ep = NULL;
537c7090651SMichael Tuexen 			errno = 0;
538c7090651SMichael Tuexen 			ltclass = strtoul(optarg, &ep, 0);
539c7090651SMichael Tuexen 			if (errno || !*optarg || *ep || ltclass > 255) {
540c7090651SMichael Tuexen 				fprintf(stderr,
541c7090651SMichael Tuexen 				    "traceroute6: invalid traffic class.\n");
542c7090651SMichael Tuexen 				exit(1);
543c7090651SMichael Tuexen 			}
544c7090651SMichael Tuexen 			tclass = (int)ltclass;
545c7090651SMichael Tuexen 			break;
5469d8b46c8SMichael Tuexen 		case 'T':
5479d8b46c8SMichael Tuexen 			useproto = IPPROTO_TCP;
5489d8b46c8SMichael Tuexen 			break;
549d7b63fafSDavid Malone 		case 'U':
550d7b63fafSDavid Malone 			useproto = IPPROTO_UDP;
551d7b63fafSDavid Malone 			break;
552aa96470cSMichael Tuexen 		case 'v':
553aa96470cSMichael Tuexen 			verbose++;
554aa96470cSMichael Tuexen 			break;
5557d56d374SYoshinobu Inoue 		case 'w':
55633841545SHajimu UMEMOTO 			ep = NULL;
55784a1a4cfSHajimu UMEMOTO 			errno = 0;
55833841545SHajimu UMEMOTO 			waittime = strtoul(optarg, &ep, 0);
55984a1a4cfSHajimu UMEMOTO 			if (errno || !*optarg || *ep) {
560c449e284SHajimu UMEMOTO 				fprintf(stderr,
56133841545SHajimu UMEMOTO 				    "traceroute6: invalid wait time.\n");
56233841545SHajimu UMEMOTO 				exit(1);
56333841545SHajimu UMEMOTO 			}
564eea319c4SMaxim Konovalov 			if (waittime < 1) {
565c449e284SHajimu UMEMOTO 				fprintf(stderr,
566eea319c4SMaxim Konovalov 				    "traceroute6: wait must be >= 1 sec.\n");
5677d56d374SYoshinobu Inoue 				exit(1);
5687d56d374SYoshinobu Inoue 			}
5697d56d374SYoshinobu Inoue 			break;
5707d56d374SYoshinobu Inoue 		default:
5717d56d374SYoshinobu Inoue 			usage();
5727d56d374SYoshinobu Inoue 		}
5737d56d374SYoshinobu Inoue 	argc -= optind;
5747d56d374SYoshinobu Inoue 	argv += optind;
5757d56d374SYoshinobu Inoue 
576d7b63fafSDavid Malone 	/*
577d7b63fafSDavid Malone 	 * Open socket to send probe packets.
578d7b63fafSDavid Malone 	 */
579d7b63fafSDavid Malone 	switch (useproto) {
580d7b63fafSDavid Malone 	case IPPROTO_ICMPV6:
581d7b63fafSDavid Malone 	case IPPROTO_NONE:
5829d8b46c8SMichael Tuexen 	case IPPROTO_SCTP:
5839d8b46c8SMichael Tuexen 	case IPPROTO_TCP:
5842d0fb1b3SMichael Tuexen 	case IPPROTO_UDP:
5859d8b46c8SMichael Tuexen 		if ((sndsock = socket(AF_INET6, SOCK_RAW, useproto)) < 0) {
586d7b63fafSDavid Malone 			perror("socket(SOCK_RAW)");
587d7b63fafSDavid Malone 			exit(5);
588d7b63fafSDavid Malone 		}
589d7b63fafSDavid Malone 		break;
590d7b63fafSDavid Malone 	default:
591aa96470cSMichael Tuexen 		fprintf(stderr, "traceroute6: unknown probe protocol %d\n",
592d7b63fafSDavid Malone 		    useproto);
593d7b63fafSDavid Malone 		exit(5);
594d7b63fafSDavid Malone 	}
59584a1a4cfSHajimu UMEMOTO 	if (max_hops < first_hop) {
59684a1a4cfSHajimu UMEMOTO 		fprintf(stderr,
59784a1a4cfSHajimu UMEMOTO 		    "traceroute6: max hoplimit must be larger than first hoplimit.\n");
59884a1a4cfSHajimu UMEMOTO 		exit(1);
59984a1a4cfSHajimu UMEMOTO 	}
60084a1a4cfSHajimu UMEMOTO 
601d7b63fafSDavid Malone 	/* revoke privs */
602d7b63fafSDavid Malone 	uid = getuid();
603d7b63fafSDavid Malone 	if (setresuid(uid, uid, uid) == -1) {
604d7b63fafSDavid Malone 		perror("setresuid");
605d7b63fafSDavid Malone 		exit(1);
606d7b63fafSDavid Malone 	}
607d7b63fafSDavid Malone 
608c7090651SMichael Tuexen 	if (tclass != -1) {
609c7090651SMichael Tuexen 		if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_TCLASS, &tclass,
610c7090651SMichael Tuexen 		    sizeof(int)) == -1) {
611c7090651SMichael Tuexen 			perror("setsockopt(IPV6_TCLASS)");
612c7090651SMichael Tuexen 			exit(7);
613c7090651SMichael Tuexen 		}
614c7090651SMichael Tuexen 	}
615d7b63fafSDavid Malone 
61633841545SHajimu UMEMOTO 	if (argc < 1 || argc > 2)
6177d56d374SYoshinobu Inoue 		usage();
6187d56d374SYoshinobu Inoue 
619de68a0daSKris Kennaway #if 1
6207d56d374SYoshinobu Inoue 	setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
621de68a0daSKris Kennaway #else
622de68a0daSKris Kennaway 	setlinebuf(stdout);
623de68a0daSKris Kennaway #endif
6247d56d374SYoshinobu Inoue 
62539865d64SYoshinobu Inoue 	memset(&hints, 0, sizeof(hints));
62639865d64SYoshinobu Inoue 	hints.ai_family = PF_INET6;
62739865d64SYoshinobu Inoue 	hints.ai_socktype = SOCK_RAW;
62839865d64SYoshinobu Inoue 	hints.ai_protocol = IPPROTO_ICMPV6;
62939865d64SYoshinobu Inoue 	hints.ai_flags = AI_CANONNAME;
630cc432e23SMariusz Zaborski 
631cc432e23SMariusz Zaborski 	error = cap_getaddrinfo(capdns, *argv, NULL, &hints, &res);
632cc432e23SMariusz Zaborski 
63339865d64SYoshinobu Inoue 	if (error) {
634c449e284SHajimu UMEMOTO 		fprintf(stderr,
63539865d64SYoshinobu Inoue 		    "traceroute6: %s\n", gai_strerror(error));
6367d56d374SYoshinobu Inoue 		exit(1);
6377d56d374SYoshinobu Inoue 	}
638de68a0daSKris Kennaway 	if (res->ai_addrlen != sizeof(Dst)) {
639c449e284SHajimu UMEMOTO 		fprintf(stderr,
640de68a0daSKris Kennaway 		    "traceroute6: size of sockaddr mismatch\n");
641de68a0daSKris Kennaway 		exit(1);
642de68a0daSKris Kennaway 	}
64339865d64SYoshinobu Inoue 	memcpy(&Dst, res->ai_addr, res->ai_addrlen);
64439865d64SYoshinobu Inoue 	hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv;
64533841545SHajimu UMEMOTO 	if (!hostname) {
646c449e284SHajimu UMEMOTO 		fprintf(stderr, "traceroute6: not enough core\n");
64733841545SHajimu UMEMOTO 		exit(1);
64833841545SHajimu UMEMOTO 	}
64984a1a4cfSHajimu UMEMOTO 	if (res->ai_next) {
650cc432e23SMariusz Zaborski 		if (cap_getnameinfo(capdns, res->ai_addr, res->ai_addrlen, hbuf,
65184a1a4cfSHajimu UMEMOTO 		    sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
65284a1a4cfSHajimu UMEMOTO 			strlcpy(hbuf, "?", sizeof(hbuf));
65384a1a4cfSHajimu UMEMOTO 		fprintf(stderr, "traceroute6: Warning: %s has multiple "
65484a1a4cfSHajimu UMEMOTO 		    "addresses; using %s\n", hostname, hbuf);
65584a1a4cfSHajimu UMEMOTO 	}
656ca19d0d7SMark Johnston 	freeaddrinfo(res);
65733841545SHajimu UMEMOTO 	if (*++argv) {
65833841545SHajimu UMEMOTO 		ep = NULL;
65984a1a4cfSHajimu UMEMOTO 		errno = 0;
66033841545SHajimu UMEMOTO 		datalen = strtoul(*argv, &ep, 0);
661aa96470cSMichael Tuexen 		if (errno || *ep) {
662c449e284SHajimu UMEMOTO 			fprintf(stderr,
66333841545SHajimu UMEMOTO 			    "traceroute6: invalid packet length.\n");
66433841545SHajimu UMEMOTO 			exit(1);
66533841545SHajimu UMEMOTO 		}
66633841545SHajimu UMEMOTO 	}
667d7b63fafSDavid Malone 	switch (useproto) {
668d7b63fafSDavid Malone 	case IPPROTO_ICMPV6:
669aa96470cSMichael Tuexen 		minlen = ICMP6ECHOLEN;
670d7b63fafSDavid Malone 		break;
671d7b63fafSDavid Malone 	case IPPROTO_UDP:
672aa96470cSMichael Tuexen 		minlen = sizeof(struct udphdr);
673d7b63fafSDavid Malone 		break;
674d7b63fafSDavid Malone 	case IPPROTO_NONE:
675d7b63fafSDavid Malone 		minlen = 0;
676d7b63fafSDavid Malone 		datalen = 0;
677d7b63fafSDavid Malone 		break;
6789d8b46c8SMichael Tuexen 	case IPPROTO_SCTP:
6799d8b46c8SMichael Tuexen 		minlen = sizeof(struct sctphdr);
6809d8b46c8SMichael Tuexen 		break;
6819d8b46c8SMichael Tuexen 	case IPPROTO_TCP:
6829d8b46c8SMichael Tuexen 		minlen = sizeof(struct tcphdr);
6839d8b46c8SMichael Tuexen 		break;
684d7b63fafSDavid Malone 	default:
685d7b63fafSDavid Malone 		fprintf(stderr, "traceroute6: unknown probe protocol %d.\n",
686d7b63fafSDavid Malone 		    useproto);
687d7b63fafSDavid Malone 		exit(1);
688d7b63fafSDavid Malone 	}
68984a1a4cfSHajimu UMEMOTO 	if (datalen < minlen)
69084a1a4cfSHajimu UMEMOTO 		datalen = minlen;
69184a1a4cfSHajimu UMEMOTO 	else if (datalen >= MAXPACKET) {
692c449e284SHajimu UMEMOTO 		fprintf(stderr,
693f42640a3SUlrich Spörlein 		    "traceroute6: packet size must be %zu <= s < %d.\n",
694f42640a3SUlrich Spörlein 		    minlen, MAXPACKET);
6957d56d374SYoshinobu Inoue 		exit(1);
6967d56d374SYoshinobu Inoue 	}
69751eff8efSMichael Tuexen 	if ((useproto == IPPROTO_SCTP) && (datalen & 3)) {
69851eff8efSMichael Tuexen 		fprintf(stderr,
69951eff8efSMichael Tuexen 		    "traceroute6: packet size must be a multiple of 4.\n");
70051eff8efSMichael Tuexen 		exit(1);
70151eff8efSMichael Tuexen 	}
702f42640a3SUlrich Spörlein 	outpacket = malloc(datalen);
7037d56d374SYoshinobu Inoue 	if (!outpacket) {
704de68a0daSKris Kennaway 		perror("malloc");
7057d56d374SYoshinobu Inoue 		exit(1);
7067d56d374SYoshinobu Inoue 	}
7077d56d374SYoshinobu Inoue 	(void) bzero((char *)outpacket, datalen);
7087d56d374SYoshinobu Inoue 
7097d56d374SYoshinobu Inoue 	/* initialize msghdr for receiving packets */
7107d56d374SYoshinobu Inoue 	rcviov[0].iov_base = (caddr_t)packet;
7117d56d374SYoshinobu Inoue 	rcviov[0].iov_len = sizeof(packet);
712de68a0daSKris Kennaway 	rcvmhdr.msg_name = (caddr_t)&Rcv;
713de68a0daSKris Kennaway 	rcvmhdr.msg_namelen = sizeof(Rcv);
7147d56d374SYoshinobu Inoue 	rcvmhdr.msg_iov = rcviov;
7157d56d374SYoshinobu Inoue 	rcvmhdr.msg_iovlen = 1;
716e961704aSDavid Malone 	rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
717e961704aSDavid Malone 	    CMSG_SPACE(sizeof(int));
718de68a0daSKris Kennaway 	if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) {
719c449e284SHajimu UMEMOTO 		fprintf(stderr, "traceroute6: malloc failed\n");
720de68a0daSKris Kennaway 		exit(1);
721de68a0daSKris Kennaway 	}
7227d56d374SYoshinobu Inoue 	rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
723de68a0daSKris Kennaway 	rcvmhdr.msg_controllen = rcvcmsglen;
7247d56d374SYoshinobu Inoue 
7257d56d374SYoshinobu Inoue 	if (options & SO_DEBUG)
7267d56d374SYoshinobu Inoue 		(void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
7277d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
7287d56d374SYoshinobu Inoue 	if (options & SO_DONTROUTE)
7297d56d374SYoshinobu Inoue 		(void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
7307d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
731ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
7327d56d374SYoshinobu Inoue 	/*
7337d56d374SYoshinobu Inoue 	 * do not raise error even if setsockopt fails, kernel may have ipsec
7347d56d374SYoshinobu Inoue 	 * turned off.
7357d56d374SYoshinobu Inoue 	 */
736ca19d0d7SMark Johnston 	if (setpolicy(rcvsock, ipsec_inpolicy) < 0)
737d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
738ca19d0d7SMark Johnston 	if (setpolicy(rcvsock, ipsec_outpolicy) < 0)
739d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
740de68a0daSKris Kennaway #else
741de68a0daSKris Kennaway     {
742de68a0daSKris Kennaway 	int level = IPSEC_LEVEL_NONE;
743de68a0daSKris Kennaway 
744de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
745de68a0daSKris Kennaway 	    sizeof(level));
746de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
747de68a0daSKris Kennaway 	    sizeof(level));
748de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL
749de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
750de68a0daSKris Kennaway 	    sizeof(level));
751de68a0daSKris Kennaway #else
752de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
753de68a0daSKris Kennaway 	    sizeof(level));
754de68a0daSKris Kennaway #endif
755de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL
756de68a0daSKris Kennaway 	(void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
757de68a0daSKris Kennaway 	    sizeof(level));
758de68a0daSKris Kennaway #endif
759de68a0daSKris Kennaway     }
760ca19d0d7SMark Johnston #endif /* !(IPSEC && IPSEC_POLICY_IPSEC) */
7617d56d374SYoshinobu Inoue 
762de68a0daSKris Kennaway #ifdef SO_SNDBUF
76384a1a4cfSHajimu UMEMOTO 	i = datalen;
764aa96470cSMichael Tuexen 	if (i == 0)
765aa96470cSMichael Tuexen 		i = 1;
76684a1a4cfSHajimu UMEMOTO 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&i,
767aa96470cSMichael Tuexen 	    sizeof(i)) < 0) {
768de68a0daSKris Kennaway 		perror("setsockopt(SO_SNDBUF)");
7697d56d374SYoshinobu Inoue 		exit(6);
7707d56d374SYoshinobu Inoue 	}
771de68a0daSKris Kennaway #endif /* SO_SNDBUF */
7727d56d374SYoshinobu Inoue 	if (options & SO_DEBUG)
7737d56d374SYoshinobu Inoue 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
7747d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
7757d56d374SYoshinobu Inoue 	if (options & SO_DONTROUTE)
7767d56d374SYoshinobu Inoue 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
7777d56d374SYoshinobu Inoue 		    (char *)&on, sizeof(on));
778de68a0daSKris Kennaway 	if (rth) {/* XXX: there is no library to finalize the header... */
779de68a0daSKris Kennaway 		rth->ip6r_len = rth->ip6r_segleft * 2;
780de68a0daSKris Kennaway 		if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR,
781de68a0daSKris Kennaway 		    (void *)rth, (rth->ip6r_len + 1) << 3)) {
782c449e284SHajimu UMEMOTO 			fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n",
783de68a0daSKris Kennaway 			    strerror(errno));
784de68a0daSKris Kennaway 			exit(1);
785de68a0daSKris Kennaway 		}
786de68a0daSKris Kennaway 	}
787ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
7887d56d374SYoshinobu Inoue 	/*
7897d56d374SYoshinobu Inoue 	 * do not raise error even if setsockopt fails, kernel may have ipsec
7907d56d374SYoshinobu Inoue 	 * turned off.
7917d56d374SYoshinobu Inoue 	 */
792ca19d0d7SMark Johnston 	if (setpolicy(sndsock, ipsec_inpolicy) < 0)
793d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
794ca19d0d7SMark Johnston 	if (setpolicy(sndsock, ipsec_outpolicy) < 0)
795d94e8c62SKris Kennaway 		errx(1, "%s", ipsec_strerror());
796de68a0daSKris Kennaway #else
797de68a0daSKris Kennaway     {
798de68a0daSKris Kennaway 	int level = IPSEC_LEVEL_BYPASS;
799de68a0daSKris Kennaway 
800de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
801de68a0daSKris Kennaway 	    sizeof(level));
802de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
803de68a0daSKris Kennaway 	    sizeof(level));
804de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL
805de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
806de68a0daSKris Kennaway 	    sizeof(level));
807de68a0daSKris Kennaway #else
808de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
809de68a0daSKris Kennaway 	    sizeof(level));
810de68a0daSKris Kennaway #endif
811de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL
812de68a0daSKris Kennaway 	(void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
813de68a0daSKris Kennaway 	    sizeof(level));
814de68a0daSKris Kennaway #endif
815de68a0daSKris Kennaway     }
816ca19d0d7SMark Johnston #endif /* !(IPSEC && IPSEC_POLICY_IPSEC) */
8177d56d374SYoshinobu Inoue 
8187d56d374SYoshinobu Inoue 	/*
8197d56d374SYoshinobu Inoue 	 * Source selection
8207d56d374SYoshinobu Inoue 	 */
821de68a0daSKris Kennaway 	bzero(&Src, sizeof(Src));
8227d56d374SYoshinobu Inoue 	if (source) {
823de68a0daSKris Kennaway 		memset(&hints, 0, sizeof(hints));
824de68a0daSKris Kennaway 		hints.ai_family = AF_INET6;
825de68a0daSKris Kennaway 		hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
826de68a0daSKris Kennaway 		hints.ai_flags = AI_NUMERICHOST;
827cc432e23SMariusz Zaborski 		error = cap_getaddrinfo(capdns, source, "0", &hints, &res);
828de68a0daSKris Kennaway 		if (error) {
829c449e284SHajimu UMEMOTO 			printf("traceroute6: %s: %s\n", source,
830de68a0daSKris Kennaway 			    gai_strerror(error));
8317d56d374SYoshinobu Inoue 			exit(1);
8327d56d374SYoshinobu Inoue 		}
833de68a0daSKris Kennaway 		if (res->ai_addrlen > sizeof(Src)) {
834c449e284SHajimu UMEMOTO 			printf("traceroute6: %s: %s\n", source,
835de68a0daSKris Kennaway 			    gai_strerror(error));
836de68a0daSKris Kennaway 			exit(1);
837de68a0daSKris Kennaway 		}
838de68a0daSKris Kennaway 		memcpy(&Src, res->ai_addr, res->ai_addrlen);
839de68a0daSKris Kennaway 		freeaddrinfo(res);
8407d56d374SYoshinobu Inoue 	} else {
8417d56d374SYoshinobu Inoue 		struct sockaddr_in6 Nxt;
84284a1a4cfSHajimu UMEMOTO 		int dummy;
84384a1a4cfSHajimu UMEMOTO 		socklen_t len;
8447d56d374SYoshinobu Inoue 
8457d56d374SYoshinobu Inoue 		Nxt = Dst;
8467d56d374SYoshinobu Inoue 		Nxt.sin6_port = htons(DUMMY_PORT);
8477d56d374SYoshinobu Inoue 		if (cmsg != NULL)
8487d56d374SYoshinobu Inoue 			bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr,
8497d56d374SYoshinobu Inoue 			    sizeof(Nxt.sin6_addr));
8507d56d374SYoshinobu Inoue 		if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
8517d56d374SYoshinobu Inoue 			perror("socket");
852de68a0daSKris Kennaway 			exit(1);
8537d56d374SYoshinobu Inoue 		}
854de68a0daSKris Kennaway 		if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) {
8557d56d374SYoshinobu Inoue 			perror("connect");
856de68a0daSKris Kennaway 			exit(1);
8577d56d374SYoshinobu Inoue 		}
858de68a0daSKris Kennaway 		len = sizeof(Src);
859de68a0daSKris Kennaway 		if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) {
860de68a0daSKris Kennaway 			perror("getsockname");
861de68a0daSKris Kennaway 			exit(1);
862de68a0daSKris Kennaway 		}
863cc432e23SMariusz Zaborski 		if (cap_getnameinfo(capdns, (struct sockaddr *)&Src, Src.sin6_len,
864d24cb249SHajimu UMEMOTO 		    src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) {
865c449e284SHajimu UMEMOTO 			fprintf(stderr, "getnameinfo failed for source\n");
866de68a0daSKris Kennaway 			exit(1);
867de68a0daSKris Kennaway 		}
868de68a0daSKris Kennaway 		source = src0;
8697d56d374SYoshinobu Inoue 		close(dummy);
8707d56d374SYoshinobu Inoue 	}
871de68a0daSKris Kennaway 
87284a1a4cfSHajimu UMEMOTO 	Src.sin6_port = htons(0);
873de68a0daSKris Kennaway 	if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) {
874de68a0daSKris Kennaway 		perror("bind");
8757d56d374SYoshinobu Inoue 		exit(1);
8767d56d374SYoshinobu Inoue 	}
8777d56d374SYoshinobu Inoue 
87884a1a4cfSHajimu UMEMOTO 	{
879c449e284SHajimu UMEMOTO 		socklen_t len;
880de68a0daSKris Kennaway 
881de68a0daSKris Kennaway 		len = sizeof(Src);
88284a1a4cfSHajimu UMEMOTO 		if (getsockname(sndsock, (struct sockaddr *)&Src, &len) < 0) {
883de68a0daSKris Kennaway 			perror("getsockname");
884de68a0daSKris Kennaway 			exit(1);
885de68a0daSKris Kennaway 		}
88684a1a4cfSHajimu UMEMOTO 		srcport = ntohs(Src.sin6_port);
887de68a0daSKris Kennaway 	}
888de68a0daSKris Kennaway 
889d429d720SHajimu UMEMOTO 	if (as_path) {
890d429d720SHajimu UMEMOTO 		asn = as_setup(as_server);
891d429d720SHajimu UMEMOTO 		if (asn == NULL) {
892d429d720SHajimu UMEMOTO 			fprintf(stderr,
893d429d720SHajimu UMEMOTO 			    "traceroute6: as_setup failed, AS# lookups"
894d429d720SHajimu UMEMOTO 			    " disabled\n");
895d429d720SHajimu UMEMOTO 			(void)fflush(stderr);
896d429d720SHajimu UMEMOTO 			as_path = 0;
897d429d720SHajimu UMEMOTO 		}
898d429d720SHajimu UMEMOTO 	}
899d429d720SHajimu UMEMOTO 
9007d56d374SYoshinobu Inoue 	/*
9017d56d374SYoshinobu Inoue 	 * Message to users
9027d56d374SYoshinobu Inoue 	 */
903cc432e23SMariusz Zaborski 	if (cap_getnameinfo(capdns, (struct sockaddr *)&Dst, Dst.sin6_len, hbuf,
904d24cb249SHajimu UMEMOTO 	    sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
90533841545SHajimu UMEMOTO 		strlcpy(hbuf, "(invalid)", sizeof(hbuf));
906c449e284SHajimu UMEMOTO 	fprintf(stderr, "traceroute6");
907c449e284SHajimu UMEMOTO 	fprintf(stderr, " to %s (%s)", hostname, hbuf);
9087d56d374SYoshinobu Inoue 	if (source)
909c449e284SHajimu UMEMOTO 		fprintf(stderr, " from %s", source);
91084a1a4cfSHajimu UMEMOTO 	fprintf(stderr, ", %lu hops max, %lu byte packets\n",
911d55fae02SMichael Tuexen 	    max_hops,
912d55fae02SMichael Tuexen 	    datalen + ((useproto == IPPROTO_UDP) ? sizeof(struct udphdr) : 0));
9137d56d374SYoshinobu Inoue 	(void) fflush(stderr);
9147d56d374SYoshinobu Inoue 
915de68a0daSKris Kennaway 	if (first_hop > 1)
91684a1a4cfSHajimu UMEMOTO 		printf("Skipping %lu intermediate hops\n", first_hop - 1);
917de68a0daSKris Kennaway 
918cc432e23SMariusz Zaborski 	if (connect(sndsock, (struct sockaddr *)&Dst,
919cc432e23SMariusz Zaborski 	    sizeof(Dst)) != 0) {
920cc432e23SMariusz Zaborski 		fprintf(stderr, "connect: %s\n", strerror(errno));
921cc432e23SMariusz Zaborski 		exit(1);
922cc432e23SMariusz Zaborski 	}
923cc432e23SMariusz Zaborski 
924cc432e23SMariusz Zaborski 	/*
925cc432e23SMariusz Zaborski 	 * Here we enter capability mode. Further down access to global
926cc432e23SMariusz Zaborski 	 * namespaces (e.g filesystem) is restricted (see capsicum(4)).
927cc432e23SMariusz Zaborski 	 * We must connect(2) our socket before this point.
928cc432e23SMariusz Zaborski 	 */
929cc432e23SMariusz Zaborski 	if (caph_enter_casper() < 0) {
930cc432e23SMariusz Zaborski 		fprintf(stderr, "caph_enter_casper: %s\n", strerror(errno));
931cc432e23SMariusz Zaborski 		exit(1);
932cc432e23SMariusz Zaborski 	}
933cc432e23SMariusz Zaborski 
934cc432e23SMariusz Zaborski 	cap_rights_init(&rights, CAP_SEND, CAP_SETSOCKOPT);
935cc432e23SMariusz Zaborski 	if (caph_rights_limit(sndsock, &rights) < 0) {
936cc432e23SMariusz Zaborski 		fprintf(stderr, "caph_rights_limit sndsock: %s\n",
937cc432e23SMariusz Zaborski 		    strerror(errno));
938cc432e23SMariusz Zaborski 		exit(1);
939cc432e23SMariusz Zaborski 	}
940b8ae450fSMark Johnston 	cap_rights_init(&rights, CAP_RECV);
941b8ae450fSMark Johnston 	if (caph_rights_limit(rcvsock, &rights) < 0) {
942b8ae450fSMark Johnston 		fprintf(stderr, "caph_rights_limit rcvsock: %s\n",
943b8ae450fSMark Johnston 		    strerror(errno));
944b8ae450fSMark Johnston 		exit(1);
945b8ae450fSMark Johnston 	}
946cc432e23SMariusz Zaborski 
9477d56d374SYoshinobu Inoue 	/*
9487d56d374SYoshinobu Inoue 	 * Main loop
9497d56d374SYoshinobu Inoue 	 */
950de68a0daSKris Kennaway 	for (hops = first_hop; hops <= max_hops; ++hops) {
9517d56d374SYoshinobu Inoue 		struct in6_addr lastaddr;
9527d56d374SYoshinobu Inoue 		int got_there = 0;
953f42640a3SUlrich Spörlein 		unsigned unreachable = 0;
9547d56d374SYoshinobu Inoue 
95584a1a4cfSHajimu UMEMOTO 		printf("%2lu ", hops);
9567d56d374SYoshinobu Inoue 		bzero(&lastaddr, sizeof(lastaddr));
9577d56d374SYoshinobu Inoue 		for (probe = 0; probe < nprobes; ++probe) {
9587d56d374SYoshinobu Inoue 			int cc;
9597d56d374SYoshinobu Inoue 			struct timeval t1, t2;
9607d56d374SYoshinobu Inoue 
96184a1a4cfSHajimu UMEMOTO 			(void) gettimeofday(&t1, NULL);
9627d56d374SYoshinobu Inoue 			send_probe(++seq, hops);
9637d56d374SYoshinobu Inoue 			while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) {
96484a1a4cfSHajimu UMEMOTO 				(void) gettimeofday(&t2, NULL);
96564694fdcSMichael Tuexen 				if (packet_ok(&rcvmhdr, cc, seq, &type, &code)) {
9667d56d374SYoshinobu Inoue 					if (!IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr,
9677d56d374SYoshinobu Inoue 					    &lastaddr)) {
96859876f93SChristian S.J. Peron 						if (probe > 0)
96959876f93SChristian S.J. Peron 							fputs("\n   ", stdout);
9707d56d374SYoshinobu Inoue 						print(&rcvmhdr, cc);
9717d56d374SYoshinobu Inoue 						lastaddr = Rcv.sin6_addr;
9727d56d374SYoshinobu Inoue 					}
973c449e284SHajimu UMEMOTO 					printf("  %.3f ms", deltaT(&t1, &t2));
97464694fdcSMichael Tuexen 					if (type == ICMP6_DST_UNREACH) {
97564694fdcSMichael Tuexen 						switch (code) {
9767d56d374SYoshinobu Inoue 						case ICMP6_DST_UNREACH_NOROUTE:
9777d56d374SYoshinobu Inoue 							++unreachable;
978c449e284SHajimu UMEMOTO 							printf(" !N");
9797d56d374SYoshinobu Inoue 							break;
9807d56d374SYoshinobu Inoue 						case ICMP6_DST_UNREACH_ADMIN:
9817d56d374SYoshinobu Inoue 							++unreachable;
982c449e284SHajimu UMEMOTO 							printf(" !P");
9837d56d374SYoshinobu Inoue 							break;
9847d56d374SYoshinobu Inoue 						case ICMP6_DST_UNREACH_NOTNEIGHBOR:
9857d56d374SYoshinobu Inoue 							++unreachable;
986c449e284SHajimu UMEMOTO 							printf(" !S");
9877d56d374SYoshinobu Inoue 							break;
9887d56d374SYoshinobu Inoue 						case ICMP6_DST_UNREACH_ADDR:
9897d56d374SYoshinobu Inoue 							++unreachable;
990c449e284SHajimu UMEMOTO 							printf(" !A");
9917d56d374SYoshinobu Inoue 							break;
9927d56d374SYoshinobu Inoue 						case ICMP6_DST_UNREACH_NOPORT:
9937d56d374SYoshinobu Inoue 							if (rcvhlim >= 0 &&
9947d56d374SYoshinobu Inoue 							    rcvhlim <= 1)
995c449e284SHajimu UMEMOTO 								printf(" !");
9967d56d374SYoshinobu Inoue 							++got_there;
9977d56d374SYoshinobu Inoue 							break;
9987d56d374SYoshinobu Inoue 						}
9991f69b3fbSMichael Tuexen 					} else if (type == ICMP6_PARAM_PROB &&
10001f69b3fbSMichael Tuexen 					    code == ICMP6_PARAMPROB_NEXTHEADER) {
10011f69b3fbSMichael Tuexen 						printf(" !H");
10021f69b3fbSMichael Tuexen 						++got_there;
100364694fdcSMichael Tuexen 					} else if (type == ICMP6_ECHO_REPLY) {
100464694fdcSMichael Tuexen 						if (rcvhlim >= 0 &&
100564694fdcSMichael Tuexen 						    rcvhlim <= 1)
100664694fdcSMichael Tuexen 							printf(" !");
100764694fdcSMichael Tuexen 						++got_there;
100864694fdcSMichael Tuexen 					}
10097d56d374SYoshinobu Inoue 					break;
1010161ab37dSHiroki Sato 				} else if (deltaT(&t1, &t2) > waittime * 1000) {
1011161ab37dSHiroki Sato 					cc = 0;
1012161ab37dSHiroki Sato 					break;
10137d56d374SYoshinobu Inoue 				}
10147d56d374SYoshinobu Inoue 			}
10157d56d374SYoshinobu Inoue 			if (cc == 0)
1016c449e284SHajimu UMEMOTO 				printf(" *");
10177d56d374SYoshinobu Inoue 			(void) fflush(stdout);
10187d56d374SYoshinobu Inoue 		}
10197d56d374SYoshinobu Inoue 		putchar('\n');
10207d56d374SYoshinobu Inoue 		if (got_there ||
10217d56d374SYoshinobu Inoue 		    (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) {
10227d56d374SYoshinobu Inoue 			exit(0);
10237d56d374SYoshinobu Inoue 		}
10247d56d374SYoshinobu Inoue 	}
1025d429d720SHajimu UMEMOTO 	if (as_path)
1026d429d720SHajimu UMEMOTO 		as_shutdown(asn);
10277d56d374SYoshinobu Inoue 
10287d56d374SYoshinobu Inoue 	exit(0);
10297d56d374SYoshinobu Inoue }
10307d56d374SYoshinobu Inoue 
10317d56d374SYoshinobu Inoue int
1032aa96470cSMichael Tuexen wait_for_reply(int sock, struct msghdr *mhdr)
10337d56d374SYoshinobu Inoue {
10342a1c5efaSKris Kennaway #ifdef HAVE_POLL
10352a1c5efaSKris Kennaway 	struct pollfd pfd[1];
10367d56d374SYoshinobu Inoue 	int cc = 0;
10377d56d374SYoshinobu Inoue 
10382a1c5efaSKris Kennaway 	pfd[0].fd = sock;
10392a1c5efaSKris Kennaway 	pfd[0].events = POLLIN;
10402a1c5efaSKris Kennaway 	pfd[0].revents = 0;
10417d56d374SYoshinobu Inoue 
10422a1c5efaSKris Kennaway 	if (poll(pfd, 1, waittime * 1000) > 0)
10437d56d374SYoshinobu Inoue 		cc = recvmsg(rcvsock, mhdr, 0);
10447d56d374SYoshinobu Inoue 
10457d56d374SYoshinobu Inoue 	return (cc);
10462a1c5efaSKris Kennaway #else
10472a1c5efaSKris Kennaway 	fd_set *fdsp;
10482a1c5efaSKris Kennaway 	struct timeval wait;
10492a1c5efaSKris Kennaway 	int cc = 0, fdsn;
10502a1c5efaSKris Kennaway 
10512a1c5efaSKris Kennaway 	fdsn = howmany(sock + 1, NFDBITS) * sizeof(fd_mask);
10522a1c5efaSKris Kennaway 	if ((fdsp = (fd_set *)malloc(fdsn)) == NULL)
10532a1c5efaSKris Kennaway 		err(1, "malloc");
10542a1c5efaSKris Kennaway 	memset(fdsp, 0, fdsn);
10552a1c5efaSKris Kennaway 	FD_SET(sock, fdsp);
10562a1c5efaSKris Kennaway 	wait.tv_sec = waittime; wait.tv_usec = 0;
10572a1c5efaSKris Kennaway 
10582a1c5efaSKris Kennaway 	if (select(sock+1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0)
10592a1c5efaSKris Kennaway 		cc = recvmsg(rcvsock, mhdr, 0);
10602a1c5efaSKris Kennaway 
10612a1c5efaSKris Kennaway 	free(fdsp);
10622a1c5efaSKris Kennaway 	return (cc);
10632a1c5efaSKris Kennaway #endif
10647d56d374SYoshinobu Inoue }
10657d56d374SYoshinobu Inoue 
1066ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
10677d56d374SYoshinobu Inoue int
1068ca19d0d7SMark Johnston setpolicy(int so, char *policy)
10697d56d374SYoshinobu Inoue {
10707d56d374SYoshinobu Inoue 	char *buf;
10717d56d374SYoshinobu Inoue 
10727d56d374SYoshinobu Inoue 	buf = ipsec_set_policy(policy, strlen(policy));
10737d56d374SYoshinobu Inoue 	if (buf == NULL) {
1074de68a0daSKris Kennaway 		warnx("%s", ipsec_strerror());
10757d56d374SYoshinobu Inoue 		return -1;
10767d56d374SYoshinobu Inoue 	}
10777d56d374SYoshinobu Inoue 	(void)setsockopt(so, IPPROTO_IPV6, IPV6_IPSEC_POLICY,
10787d56d374SYoshinobu Inoue 	    buf, ipsec_get_policylen(buf));
10797d56d374SYoshinobu Inoue 
10807d56d374SYoshinobu Inoue 	free(buf);
10817d56d374SYoshinobu Inoue 
10827d56d374SYoshinobu Inoue 	return 0;
10837d56d374SYoshinobu Inoue }
10847d56d374SYoshinobu Inoue #endif
10857d56d374SYoshinobu Inoue 
10867d56d374SYoshinobu Inoue void
1087aa96470cSMichael Tuexen send_probe(int seq, u_long hops)
10887d56d374SYoshinobu Inoue {
1089d7b63fafSDavid Malone 	struct icmp6_hdr *icp;
10909d8b46c8SMichael Tuexen 	struct sctphdr *sctp;
1091cc432e23SMariusz Zaborski 	struct udphdr *outudp;
10929d8b46c8SMichael Tuexen 	struct sctp_chunkhdr *chk;
109351eff8efSMichael Tuexen 	struct sctp_init_chunk *init;
109451eff8efSMichael Tuexen 	struct sctp_paramhdr *param;
10959d8b46c8SMichael Tuexen 	struct tcphdr *tcp;
10967d56d374SYoshinobu Inoue 	int i;
10977d56d374SYoshinobu Inoue 
109884a1a4cfSHajimu UMEMOTO 	i = hops;
10997d56d374SYoshinobu Inoue 	if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
110084a1a4cfSHajimu UMEMOTO 	    (char *)&i, sizeof(i)) < 0) {
11017d56d374SYoshinobu Inoue 		perror("setsockopt IPV6_UNICAST_HOPS");
11027d56d374SYoshinobu Inoue 	}
11037d56d374SYoshinobu Inoue 
11047d56d374SYoshinobu Inoue 	Dst.sin6_port = htons(port + seq);
11057d56d374SYoshinobu Inoue 
1106d7b63fafSDavid Malone 	switch (useproto) {
1107d7b63fafSDavid Malone 	case IPPROTO_ICMPV6:
1108d7b63fafSDavid Malone 		icp = (struct icmp6_hdr *)outpacket;
110984a1a4cfSHajimu UMEMOTO 
111084a1a4cfSHajimu UMEMOTO 		icp->icmp6_type = ICMP6_ECHO_REQUEST;
111184a1a4cfSHajimu UMEMOTO 		icp->icmp6_code = 0;
111284a1a4cfSHajimu UMEMOTO 		icp->icmp6_cksum = 0;
111384a1a4cfSHajimu UMEMOTO 		icp->icmp6_id = ident;
111484a1a4cfSHajimu UMEMOTO 		icp->icmp6_seq = htons(seq);
1115d7b63fafSDavid Malone 		break;
1116d7b63fafSDavid Malone 	case IPPROTO_UDP:
1117cc432e23SMariusz Zaborski 		outudp = (struct udphdr *) outpacket;
1118cc432e23SMariusz Zaborski 		outudp->uh_sport = htons(ident);
1119cc432e23SMariusz Zaborski 		outudp->uh_dport = htons(port+seq);
1120cc432e23SMariusz Zaborski 		outudp->uh_ulen = htons(datalen);
1121*1d712c05SZhenlei Huang 		outudp->uh_sum = 0;
1122cc432e23SMariusz Zaborski 		outudp->uh_sum = udp_cksum(&Src, &Dst, outpacket, datalen);
1123d7b63fafSDavid Malone 		break;
1124d7b63fafSDavid Malone 	case IPPROTO_NONE:
1125d7b63fafSDavid Malone 		/* No space for anything. No harm as seq/tv32 are decorative. */
1126d7b63fafSDavid Malone 		break;
11279d8b46c8SMichael Tuexen 	case IPPROTO_SCTP:
11289d8b46c8SMichael Tuexen 		sctp = (struct sctphdr *)outpacket;
11299d8b46c8SMichael Tuexen 
11309d8b46c8SMichael Tuexen 		sctp->src_port = htons(ident);
11319d8b46c8SMichael Tuexen 		sctp->dest_port = htons(port + seq);
113251eff8efSMichael Tuexen 		if (datalen >= (u_long)(sizeof(struct sctphdr) +
113351eff8efSMichael Tuexen 		    sizeof(struct sctp_init_chunk))) {
113451eff8efSMichael Tuexen 			sctp->v_tag = 0;
113551eff8efSMichael Tuexen 		} else {
11369d8b46c8SMichael Tuexen 			sctp->v_tag = (sctp->src_port << 16) | sctp->dest_port;
113751eff8efSMichael Tuexen 		}
11389d8b46c8SMichael Tuexen 		sctp->checksum = htonl(0);
11399d8b46c8SMichael Tuexen 		if (datalen >= (u_long)(sizeof(struct sctphdr) +
114051eff8efSMichael Tuexen 		    sizeof(struct sctp_init_chunk))) {
114151eff8efSMichael Tuexen 			/*
114251eff8efSMichael Tuexen 			 * Send a packet containing an INIT chunk. This works
114351eff8efSMichael Tuexen 			 * better in case of firewalls on the path, but
114451eff8efSMichael Tuexen 			 * results in a probe packet containing at least
114551eff8efSMichael Tuexen 			 * 32 bytes of payload. For shorter payloads, use
114651eff8efSMichael Tuexen 			 * SHUTDOWN-ACK chunks.
114751eff8efSMichael Tuexen 			 */
114851eff8efSMichael Tuexen 			init = (struct sctp_init_chunk *)(sctp + 1);
114951eff8efSMichael Tuexen 			init->ch.chunk_type = SCTP_INITIATION;
115051eff8efSMichael Tuexen 			init->ch.chunk_flags = 0;
115151eff8efSMichael Tuexen 			init->ch.chunk_length = htons((u_int16_t)(datalen -
115251eff8efSMichael Tuexen 			    sizeof(struct sctphdr)));
115351eff8efSMichael Tuexen 			init->init.initiate_tag = (sctp->src_port << 16) |
115451eff8efSMichael Tuexen 			    sctp->dest_port;
115551eff8efSMichael Tuexen 			init->init.a_rwnd = htonl(1500);
115651eff8efSMichael Tuexen 			init->init.num_outbound_streams = htons(1);
115751eff8efSMichael Tuexen 			init->init.num_inbound_streams = htons(1);
115851eff8efSMichael Tuexen 			init->init.initial_tsn = htonl(0);
115951eff8efSMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
116051eff8efSMichael Tuexen 			    sizeof(struct sctp_init_chunk) +
116151eff8efSMichael Tuexen 			    sizeof(struct sctp_paramhdr))) {
116251eff8efSMichael Tuexen 				param = (struct sctp_paramhdr *)(init + 1);
116351eff8efSMichael Tuexen 				param->param_type = htons(SCTP_PAD);
116451eff8efSMichael Tuexen 				param->param_length =
116551eff8efSMichael Tuexen 				    htons((u_int16_t)(datalen -
116651eff8efSMichael Tuexen 				    sizeof(struct sctphdr) -
116751eff8efSMichael Tuexen 				    sizeof(struct sctp_init_chunk)));
116851eff8efSMichael Tuexen 			}
116951eff8efSMichael Tuexen 		} else {
117051eff8efSMichael Tuexen 			/*
117151eff8efSMichael Tuexen 			 * Send a packet containing a SHUTDOWN-ACK chunk,
117251eff8efSMichael Tuexen 			 * possibly followed by a PAD chunk.
117351eff8efSMichael Tuexen 			 */
117451eff8efSMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
11759d8b46c8SMichael Tuexen 			    sizeof(struct sctp_chunkhdr))) {
11769d8b46c8SMichael Tuexen 				chk = (struct sctp_chunkhdr *)(sctp + 1);
11779d8b46c8SMichael Tuexen 				chk->chunk_type = SCTP_SHUTDOWN_ACK;
11789d8b46c8SMichael Tuexen 				chk->chunk_flags = 0;
11799d8b46c8SMichael Tuexen 				chk->chunk_length = htons(4);
11809d8b46c8SMichael Tuexen 			}
11819d8b46c8SMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
11829d8b46c8SMichael Tuexen 			    2 * sizeof(struct sctp_chunkhdr))) {
11839d8b46c8SMichael Tuexen 				chk = chk + 1;
11849d8b46c8SMichael Tuexen 				chk->chunk_type = SCTP_PAD_CHUNK;
11859d8b46c8SMichael Tuexen 				chk->chunk_flags = 0;
11869d8b46c8SMichael Tuexen 				chk->chunk_length = htons((u_int16_t)(datalen -
11879d8b46c8SMichael Tuexen 				    sizeof(struct sctphdr) -
11889d8b46c8SMichael Tuexen 				    sizeof(struct sctp_chunkhdr)));
11899d8b46c8SMichael Tuexen 			}
119051eff8efSMichael Tuexen 		}
11919d8b46c8SMichael Tuexen 		sctp->checksum = sctp_crc32c(outpacket, datalen);
11929d8b46c8SMichael Tuexen 		break;
11939d8b46c8SMichael Tuexen 	case IPPROTO_TCP:
11949d8b46c8SMichael Tuexen 		tcp = (struct tcphdr *)outpacket;
11959d8b46c8SMichael Tuexen 
11969d8b46c8SMichael Tuexen 		tcp->th_sport = htons(ident);
11979d8b46c8SMichael Tuexen 		tcp->th_dport = htons(port + seq);
11989d8b46c8SMichael Tuexen 		tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport;
11999d8b46c8SMichael Tuexen 		tcp->th_ack = 0;
12009d8b46c8SMichael Tuexen 		tcp->th_off = 5;
12019d8b46c8SMichael Tuexen 		tcp->th_flags = TH_SYN;
12029d8b46c8SMichael Tuexen 		tcp->th_sum = 0;
12039d8b46c8SMichael Tuexen 		tcp->th_sum = tcp_chksum(&Src, &Dst, outpacket, datalen);
12049d8b46c8SMichael Tuexen 		break;
1205d7b63fafSDavid Malone 	default:
1206d7b63fafSDavid Malone 		fprintf(stderr, "Unknown probe protocol %d.\n", useproto);
1207d7b63fafSDavid Malone 		exit(1);
120884a1a4cfSHajimu UMEMOTO 	}
12097d56d374SYoshinobu Inoue 
1210cc432e23SMariusz Zaborski 	i = send(sndsock, (char *)outpacket, datalen, 0);
1211f42640a3SUlrich Spörlein 	if (i < 0 || (u_long)i != datalen)  {
12127d56d374SYoshinobu Inoue 		if (i < 0)
1213cc432e23SMariusz Zaborski 			perror("send");
121484a1a4cfSHajimu UMEMOTO 		printf("traceroute6: wrote %s %lu chars, ret=%d\n",
1215c449e284SHajimu UMEMOTO 		    hostname, datalen, i);
12167d56d374SYoshinobu Inoue 		(void) fflush(stdout);
12177d56d374SYoshinobu Inoue 	}
12187d56d374SYoshinobu Inoue }
12197d56d374SYoshinobu Inoue 
12207d56d374SYoshinobu Inoue int
1221aa96470cSMichael Tuexen get_hoplim(struct msghdr *mhdr)
12227d56d374SYoshinobu Inoue {
12237d56d374SYoshinobu Inoue 	struct cmsghdr *cm;
12247d56d374SYoshinobu Inoue 
12257d56d374SYoshinobu Inoue 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
12267d56d374SYoshinobu Inoue 	    cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
12277d56d374SYoshinobu Inoue 		if (cm->cmsg_level == IPPROTO_IPV6 &&
12287d56d374SYoshinobu Inoue 		    cm->cmsg_type == IPV6_HOPLIMIT &&
12297d56d374SYoshinobu Inoue 		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
12307d56d374SYoshinobu Inoue 			return (*(int *)CMSG_DATA(cm));
12317d56d374SYoshinobu Inoue 	}
12327d56d374SYoshinobu Inoue 
12337d56d374SYoshinobu Inoue 	return (-1);
12347d56d374SYoshinobu Inoue }
12357d56d374SYoshinobu Inoue 
12367d56d374SYoshinobu Inoue double
1237aa96470cSMichael Tuexen deltaT(struct timeval *t1p, struct timeval *t2p)
12387d56d374SYoshinobu Inoue {
1239e961704aSDavid Malone 	double dt;
12407d56d374SYoshinobu Inoue 
12417d56d374SYoshinobu Inoue 	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
12427d56d374SYoshinobu Inoue 	    (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
12437d56d374SYoshinobu Inoue 	return (dt);
12447d56d374SYoshinobu Inoue }
12457d56d374SYoshinobu Inoue 
12467d56d374SYoshinobu Inoue /*
12477d56d374SYoshinobu Inoue  * Convert an ICMP "type" field to a printable string.
12487d56d374SYoshinobu Inoue  */
1249f42640a3SUlrich Spörlein const char *
1250f42640a3SUlrich Spörlein pr_type(int t0)
12517d56d374SYoshinobu Inoue {
12527d56d374SYoshinobu Inoue 	u_char t = t0 & 0xff;
1253f42640a3SUlrich Spörlein 	const char *cp;
12547d56d374SYoshinobu Inoue 
12557d56d374SYoshinobu Inoue 	switch (t) {
12567d56d374SYoshinobu Inoue 	case ICMP6_DST_UNREACH:
12577d56d374SYoshinobu Inoue 		cp = "Destination Unreachable";
12587d56d374SYoshinobu Inoue 		break;
12597d56d374SYoshinobu Inoue 	case ICMP6_PACKET_TOO_BIG:
1260c449e284SHajimu UMEMOTO 		cp = "Packet Too Big";
12617d56d374SYoshinobu Inoue 		break;
12627d56d374SYoshinobu Inoue 	case ICMP6_TIME_EXCEEDED:
12637d56d374SYoshinobu Inoue 		cp = "Time Exceeded";
12647d56d374SYoshinobu Inoue 		break;
12657d56d374SYoshinobu Inoue 	case ICMP6_PARAM_PROB:
12667d56d374SYoshinobu Inoue 		cp = "Parameter Problem";
12677d56d374SYoshinobu Inoue 		break;
12687d56d374SYoshinobu Inoue 	case ICMP6_ECHO_REQUEST:
12697d56d374SYoshinobu Inoue 		cp = "Echo Request";
12707d56d374SYoshinobu Inoue 		break;
12717d56d374SYoshinobu Inoue 	case ICMP6_ECHO_REPLY:
12727d56d374SYoshinobu Inoue 		cp = "Echo Reply";
12737d56d374SYoshinobu Inoue 		break;
12747d56d374SYoshinobu Inoue 	case ICMP6_MEMBERSHIP_QUERY:
12757d56d374SYoshinobu Inoue 		cp = "Group Membership Query";
12767d56d374SYoshinobu Inoue 		break;
12777d56d374SYoshinobu Inoue 	case ICMP6_MEMBERSHIP_REPORT:
12787d56d374SYoshinobu Inoue 		cp = "Group Membership Report";
12797d56d374SYoshinobu Inoue 		break;
12807d56d374SYoshinobu Inoue 	case ICMP6_MEMBERSHIP_REDUCTION:
12817d56d374SYoshinobu Inoue 		cp = "Group Membership Reduction";
12827d56d374SYoshinobu Inoue 		break;
12837d56d374SYoshinobu Inoue 	case ND_ROUTER_SOLICIT:
12847d56d374SYoshinobu Inoue 		cp = "Router Solicitation";
12857d56d374SYoshinobu Inoue 		break;
12867d56d374SYoshinobu Inoue 	case ND_ROUTER_ADVERT:
12877d56d374SYoshinobu Inoue 		cp = "Router Advertisement";
12887d56d374SYoshinobu Inoue 		break;
12897d56d374SYoshinobu Inoue 	case ND_NEIGHBOR_SOLICIT:
12907d56d374SYoshinobu Inoue 		cp = "Neighbor Solicitation";
12917d56d374SYoshinobu Inoue 		break;
12927d56d374SYoshinobu Inoue 	case ND_NEIGHBOR_ADVERT:
12937d56d374SYoshinobu Inoue 		cp = "Neighbor Advertisement";
12947d56d374SYoshinobu Inoue 		break;
12957d56d374SYoshinobu Inoue 	case ND_REDIRECT:
1296de68a0daSKris Kennaway 		cp = "Redirect";
12977d56d374SYoshinobu Inoue 		break;
12987d56d374SYoshinobu Inoue 	default:
12997d56d374SYoshinobu Inoue 		cp = "Unknown";
13007d56d374SYoshinobu Inoue 		break;
13017d56d374SYoshinobu Inoue 	}
13027d56d374SYoshinobu Inoue 	return cp;
13037d56d374SYoshinobu Inoue }
13047d56d374SYoshinobu Inoue 
13057d56d374SYoshinobu Inoue int
130664694fdcSMichael Tuexen packet_ok(struct msghdr *mhdr, int cc, int seq, u_char *type, u_char *code)
13077d56d374SYoshinobu Inoue {
1308e961704aSDavid Malone 	struct icmp6_hdr *icp;
13097d56d374SYoshinobu Inoue 	struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
13107d56d374SYoshinobu Inoue 	char *buf = (char *)mhdr->msg_iov[0].iov_base;
13117d56d374SYoshinobu Inoue 	struct cmsghdr *cm;
13127d56d374SYoshinobu Inoue 	int *hlimp;
1313de68a0daSKris Kennaway 	char hbuf[NI_MAXHOST];
13147d56d374SYoshinobu Inoue 
1315de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1316de68a0daSKris Kennaway 	int hlen;
1317de68a0daSKris Kennaway 	struct ip6_hdr *ip;
1318de68a0daSKris Kennaway #endif
1319de68a0daSKris Kennaway 
1320de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1321de68a0daSKris Kennaway 	ip = (struct ip6_hdr *) buf;
1322de68a0daSKris Kennaway 	hlen = sizeof(struct ip6_hdr);
1323de68a0daSKris Kennaway 	if (cc < hlen + sizeof(struct icmp6_hdr)) {
1324de68a0daSKris Kennaway 		if (verbose) {
1325cc432e23SMariusz Zaborski 			if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len,
1326d24cb249SHajimu UMEMOTO 			    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
132733841545SHajimu UMEMOTO 				strlcpy(hbuf, "invalid", sizeof(hbuf));
1328c449e284SHajimu UMEMOTO 			printf("packet too short (%d bytes) from %s\n", cc,
1329de68a0daSKris Kennaway 			    hbuf);
1330de68a0daSKris Kennaway 		}
1331de68a0daSKris Kennaway 		return (0);
1332de68a0daSKris Kennaway 	}
1333de68a0daSKris Kennaway 	cc -= hlen;
1334de68a0daSKris Kennaway 	icp = (struct icmp6_hdr *)(buf + hlen);
1335de68a0daSKris Kennaway #else
1336f42640a3SUlrich Spörlein 	if (cc < (int)sizeof(struct icmp6_hdr)) {
1337de68a0daSKris Kennaway 		if (verbose) {
1338cc432e23SMariusz Zaborski 			if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len,
1339d24cb249SHajimu UMEMOTO 			    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
134033841545SHajimu UMEMOTO 				strlcpy(hbuf, "invalid", sizeof(hbuf));
1341c449e284SHajimu UMEMOTO 			printf("data too short (%d bytes) from %s\n", cc, hbuf);
1342de68a0daSKris Kennaway 		}
13437d56d374SYoshinobu Inoue 		return (0);
13447d56d374SYoshinobu Inoue 	}
13457d56d374SYoshinobu Inoue 	icp = (struct icmp6_hdr *)buf;
1346de68a0daSKris Kennaway #endif
13477d56d374SYoshinobu Inoue 	/* get optional information via advanced API */
13487d56d374SYoshinobu Inoue 	rcvpktinfo = NULL;
13497d56d374SYoshinobu Inoue 	hlimp = NULL;
13507d56d374SYoshinobu Inoue 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
13517d56d374SYoshinobu Inoue 	    cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
13527d56d374SYoshinobu Inoue 		if (cm->cmsg_level == IPPROTO_IPV6 &&
13537d56d374SYoshinobu Inoue 		    cm->cmsg_type == IPV6_PKTINFO &&
13547d56d374SYoshinobu Inoue 		    cm->cmsg_len ==
13557d56d374SYoshinobu Inoue 		    CMSG_LEN(sizeof(struct in6_pktinfo)))
13567d56d374SYoshinobu Inoue 			rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm));
13577d56d374SYoshinobu Inoue 
13587d56d374SYoshinobu Inoue 		if (cm->cmsg_level == IPPROTO_IPV6 &&
13597d56d374SYoshinobu Inoue 		    cm->cmsg_type == IPV6_HOPLIMIT &&
13607d56d374SYoshinobu Inoue 		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
13617d56d374SYoshinobu Inoue 			hlimp = (int *)CMSG_DATA(cm);
13627d56d374SYoshinobu Inoue 	}
13637d56d374SYoshinobu Inoue 	if (rcvpktinfo == NULL || hlimp == NULL) {
13647d56d374SYoshinobu Inoue 		warnx("failed to get received hop limit or packet info");
1365de68a0daSKris Kennaway #if 0
13667d56d374SYoshinobu Inoue 		return (0);
1367de68a0daSKris Kennaway #else
1368de68a0daSKris Kennaway 		rcvhlim = 0;	/*XXX*/
1369de68a0daSKris Kennaway #endif
13707d56d374SYoshinobu Inoue 	}
1371de68a0daSKris Kennaway 	else
13727d56d374SYoshinobu Inoue 		rcvhlim = *hlimp;
13737d56d374SYoshinobu Inoue 
137464694fdcSMichael Tuexen 	*type = icp->icmp6_type;
137564694fdcSMichael Tuexen 	*code = icp->icmp6_code;
137664694fdcSMichael Tuexen 	if ((*type == ICMP6_TIME_EXCEEDED &&
137764694fdcSMichael Tuexen 	    *code == ICMP6_TIME_EXCEED_TRANSIT) ||
13781f69b3fbSMichael Tuexen 	    (*type == ICMP6_DST_UNREACH) ||
13791f69b3fbSMichael Tuexen 	    (*type == ICMP6_PARAM_PROB &&
13801f69b3fbSMichael Tuexen 	    *code == ICMP6_PARAMPROB_NEXTHEADER)) {
13817d56d374SYoshinobu Inoue 		struct ip6_hdr *hip;
1382aa96470cSMichael Tuexen 		struct icmp6_hdr *icmp;
138351eff8efSMichael Tuexen 		struct sctp_init_chunk *init;
13849d8b46c8SMichael Tuexen 		struct sctphdr *sctp;
13859d8b46c8SMichael Tuexen 		struct tcphdr *tcp;
1386aa96470cSMichael Tuexen 		struct udphdr *udp;
1387d7b63fafSDavid Malone 		void *up;
13887d56d374SYoshinobu Inoue 
13897d56d374SYoshinobu Inoue 		hip = (struct ip6_hdr *)(icp + 1);
1390d7b63fafSDavid Malone 		if ((up = get_uphdr(hip, (u_char *)(buf + cc))) == NULL) {
13917d56d374SYoshinobu Inoue 			if (verbose)
13927d56d374SYoshinobu Inoue 				warnx("failed to get upper layer header");
13937d56d374SYoshinobu Inoue 			return (0);
13947d56d374SYoshinobu Inoue 		}
1395d7b63fafSDavid Malone 		switch (useproto) {
1396d7b63fafSDavid Malone 		case IPPROTO_ICMPV6:
1397aa96470cSMichael Tuexen 			icmp = (struct icmp6_hdr *)up;
1398aa96470cSMichael Tuexen 			if (icmp->icmp6_id == ident &&
1399aa96470cSMichael Tuexen 			    icmp->icmp6_seq == htons(seq))
140064694fdcSMichael Tuexen 				return (1);
1401d7b63fafSDavid Malone 			break;
1402d7b63fafSDavid Malone 		case IPPROTO_UDP:
1403aa96470cSMichael Tuexen 			udp = (struct udphdr *)up;
1404cc432e23SMariusz Zaborski 			if (udp->uh_sport == htons(ident) &&
1405aa96470cSMichael Tuexen 			    udp->uh_dport == htons(port + seq))
140664694fdcSMichael Tuexen 				return (1);
1407d7b63fafSDavid Malone 			break;
14089d8b46c8SMichael Tuexen 		case IPPROTO_SCTP:
14099d8b46c8SMichael Tuexen 			sctp = (struct sctphdr *)up;
141051eff8efSMichael Tuexen 			if (sctp->src_port != htons(ident) ||
141151eff8efSMichael Tuexen 			    sctp->dest_port != htons(port + seq)) {
141251eff8efSMichael Tuexen 				break;
141351eff8efSMichael Tuexen 			}
141451eff8efSMichael Tuexen 			if (datalen >= (u_long)(sizeof(struct sctphdr) +
141551eff8efSMichael Tuexen 			    sizeof(struct sctp_init_chunk))) {
141651eff8efSMichael Tuexen 				if (sctp->v_tag != 0) {
141751eff8efSMichael Tuexen 					break;
141851eff8efSMichael Tuexen 				}
141951eff8efSMichael Tuexen 				init = (struct sctp_init_chunk *)(sctp + 1);
142051eff8efSMichael Tuexen 				/* Check the initiate tag, if available. */
142151eff8efSMichael Tuexen 				if ((char *)&init->init.a_rwnd > buf + cc) {
142264694fdcSMichael Tuexen 					return (1);
142351eff8efSMichael Tuexen 				}
142451eff8efSMichael Tuexen 				if (init->init.initiate_tag == (u_int32_t)
142551eff8efSMichael Tuexen 				    ((sctp->src_port << 16) | sctp->dest_port)) {
142664694fdcSMichael Tuexen 					return (1);
142751eff8efSMichael Tuexen 				}
142851eff8efSMichael Tuexen 			} else {
142951eff8efSMichael Tuexen 				if (sctp->v_tag ==
143051eff8efSMichael Tuexen 				    (u_int32_t)((sctp->src_port << 16) |
143151eff8efSMichael Tuexen 				    sctp->dest_port)) {
143264694fdcSMichael Tuexen 					return (1);
143351eff8efSMichael Tuexen 				}
143451eff8efSMichael Tuexen 			}
14359d8b46c8SMichael Tuexen 			break;
14369d8b46c8SMichael Tuexen 		case IPPROTO_TCP:
14379d8b46c8SMichael Tuexen 			tcp = (struct tcphdr *)up;
14389d8b46c8SMichael Tuexen 			if (tcp->th_sport == htons(ident) &&
14399d8b46c8SMichael Tuexen 			    tcp->th_dport == htons(port + seq) &&
14409d8b46c8SMichael Tuexen 			    tcp->th_seq ==
14419d8b46c8SMichael Tuexen 			    (tcp_seq)((tcp->th_sport << 16) | tcp->th_dport))
144264694fdcSMichael Tuexen 				return (1);
14439d8b46c8SMichael Tuexen 			break;
1444d7b63fafSDavid Malone 		case IPPROTO_NONE:
144564694fdcSMichael Tuexen 			return (1);
1446d7b63fafSDavid Malone 		default:
1447d7b63fafSDavid Malone 			fprintf(stderr, "Unknown probe proto %d.\n", useproto);
1448d7b63fafSDavid Malone 			break;
1449d7b63fafSDavid Malone 		}
145064694fdcSMichael Tuexen 	} else if (useproto == IPPROTO_ICMPV6 && *type == ICMP6_ECHO_REPLY) {
145184a1a4cfSHajimu UMEMOTO 		if (icp->icmp6_id == ident &&
145284a1a4cfSHajimu UMEMOTO 		    icp->icmp6_seq == htons(seq))
145364694fdcSMichael Tuexen 			return (1);
14547d56d374SYoshinobu Inoue 	}
14557d56d374SYoshinobu Inoue 	if (verbose) {
1456de68a0daSKris Kennaway 		char sbuf[NI_MAXHOST+1], dbuf[INET6_ADDRSTRLEN];
1457e961704aSDavid Malone 		u_int8_t *p;
1458e961704aSDavid Malone 		int i;
14597d56d374SYoshinobu Inoue 
1460cc432e23SMariusz Zaborski 		if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len,
1461d24cb249SHajimu UMEMOTO 		    sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0)
1462c449e284SHajimu UMEMOTO 			strlcpy(sbuf, "invalid", sizeof(sbuf));
1463c449e284SHajimu UMEMOTO 		printf("\n%d bytes from %s to %s", cc, sbuf,
1464de68a0daSKris Kennaway 		    rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1465c449e284SHajimu UMEMOTO 		    dbuf, sizeof(dbuf)) : "?");
146664694fdcSMichael Tuexen 		printf(": icmp type %d (%s) code %d\n", *type, pr_type(*type),
146764694fdcSMichael Tuexen 		    *code);
1468de68a0daSKris Kennaway 		p = (u_int8_t *)(icp + 1);
1469de68a0daSKris Kennaway #define WIDTH	16
1470de68a0daSKris Kennaway 		for (i = 0; i < cc; i++) {
1471de68a0daSKris Kennaway 			if (i % WIDTH == 0)
1472c449e284SHajimu UMEMOTO 				printf("%04x:", i);
1473de68a0daSKris Kennaway 			if (i % 4 == 0)
1474c449e284SHajimu UMEMOTO 				printf(" ");
1475c449e284SHajimu UMEMOTO 			printf("%02x", p[i]);
1476de68a0daSKris Kennaway 			if (i % WIDTH == WIDTH - 1)
1477c449e284SHajimu UMEMOTO 				printf("\n");
1478de68a0daSKris Kennaway 		}
1479de68a0daSKris Kennaway 		if (cc % WIDTH != 0)
1480c449e284SHajimu UMEMOTO 			printf("\n");
14817d56d374SYoshinobu Inoue 	}
14827d56d374SYoshinobu Inoue 	return (0);
14837d56d374SYoshinobu Inoue }
14847d56d374SYoshinobu Inoue 
14857d56d374SYoshinobu Inoue /*
148684a1a4cfSHajimu UMEMOTO  * Increment pointer until find the UDP or ICMP header.
14877d56d374SYoshinobu Inoue  */
1488d7b63fafSDavid Malone void *
1489aa96470cSMichael Tuexen get_uphdr(struct ip6_hdr *ip6, u_char *lim)
14907d56d374SYoshinobu Inoue {
14917d56d374SYoshinobu Inoue 	u_char *cp = (u_char *)ip6, nh;
14927d56d374SYoshinobu Inoue 	int hlen;
1493d7b63fafSDavid Malone 	static u_char none_hdr[1]; /* Fake pointer for IPPROTO_NONE. */
14947d56d374SYoshinobu Inoue 
1495d7b63fafSDavid Malone 	if (cp + sizeof(*ip6) > lim)
14967d56d374SYoshinobu Inoue 		return (NULL);
14977d56d374SYoshinobu Inoue 
14987d56d374SYoshinobu Inoue 	nh = ip6->ip6_nxt;
14997d56d374SYoshinobu Inoue 	cp += sizeof(struct ip6_hdr);
15007d56d374SYoshinobu Inoue 
1501d7b63fafSDavid Malone 	while (lim - cp >= (nh == IPPROTO_NONE ? 0 : 8)) {
15027d56d374SYoshinobu Inoue 		switch (nh) {
15037d56d374SYoshinobu Inoue 		case IPPROTO_ESP:
15047d56d374SYoshinobu Inoue 			return (NULL);
150584a1a4cfSHajimu UMEMOTO 		case IPPROTO_ICMPV6:
1506d7b63fafSDavid Malone 			return (useproto == nh ? cp : NULL);
15079d8b46c8SMichael Tuexen 		case IPPROTO_SCTP:
15089d8b46c8SMichael Tuexen 		case IPPROTO_TCP:
15097d56d374SYoshinobu Inoue 		case IPPROTO_UDP:
1510d7b63fafSDavid Malone 			return (useproto == nh ? cp : NULL);
1511d7b63fafSDavid Malone 		case IPPROTO_NONE:
1512d7b63fafSDavid Malone 			return (useproto == nh ? none_hdr : NULL);
15137d56d374SYoshinobu Inoue 		case IPPROTO_FRAGMENT:
15147d56d374SYoshinobu Inoue 			hlen = sizeof(struct ip6_frag);
15157d56d374SYoshinobu Inoue 			nh = ((struct ip6_frag *)cp)->ip6f_nxt;
15167d56d374SYoshinobu Inoue 			break;
15177d56d374SYoshinobu Inoue 		case IPPROTO_AH:
15187d56d374SYoshinobu Inoue 			hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2;
15197d56d374SYoshinobu Inoue 			nh = ((struct ip6_ext *)cp)->ip6e_nxt;
15207d56d374SYoshinobu Inoue 			break;
15217d56d374SYoshinobu Inoue 		default:
15227d56d374SYoshinobu Inoue 			hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3;
15237d56d374SYoshinobu Inoue 			nh = ((struct ip6_ext *)cp)->ip6e_nxt;
15247d56d374SYoshinobu Inoue 			break;
15257d56d374SYoshinobu Inoue 		}
15267d56d374SYoshinobu Inoue 
15277d56d374SYoshinobu Inoue 		cp += hlen;
15287d56d374SYoshinobu Inoue 	}
15297d56d374SYoshinobu Inoue 
15307d56d374SYoshinobu Inoue 	return (NULL);
15317d56d374SYoshinobu Inoue }
15327d56d374SYoshinobu Inoue 
15337d56d374SYoshinobu Inoue void
15345c3bf25fSAdrian Chadd capdns_open(void)
1535cc432e23SMariusz Zaborski {
15365c3bf25fSAdrian Chadd #ifdef	WITH_CASPER
1537cc432e23SMariusz Zaborski 	const char *types[] = { "NAME", "ADDR" };
1538cc432e23SMariusz Zaborski 	int families[1];
1539cc432e23SMariusz Zaborski 	cap_channel_t *casper;
1540cc432e23SMariusz Zaborski 
1541cc432e23SMariusz Zaborski 	casper = cap_init();
1542cc432e23SMariusz Zaborski 	if (casper == NULL)
1543cc432e23SMariusz Zaborski 		errx(1, "unable to create casper process");
1544cc432e23SMariusz Zaborski 	capdns = cap_service_open(casper, "system.dns");
1545cc432e23SMariusz Zaborski 	if (capdns == NULL)
1546cc432e23SMariusz Zaborski 		errx(1, "unable to open system.dns service");
1547cc432e23SMariusz Zaborski 	if (cap_dns_type_limit(capdns, types, nitems(types)) < 0)
1548cc432e23SMariusz Zaborski 		errx(1, "unable to limit access to system.dns service");
1549cc432e23SMariusz Zaborski 	families[0] = AF_INET6;
1550cc432e23SMariusz Zaborski 	if (cap_dns_family_limit(capdns, families, nitems(families)) < 0)
1551cc432e23SMariusz Zaborski 		errx(1, "unable to limit access to system.dns service");
1552cc432e23SMariusz Zaborski 	cap_close(casper);
15535c3bf25fSAdrian Chadd #endif	/* WITH_CASPER */
1554cc432e23SMariusz Zaborski }
1555cc432e23SMariusz Zaborski 
1556cc432e23SMariusz Zaborski void
1557aa96470cSMichael Tuexen print(struct msghdr *mhdr, int cc)
15587d56d374SYoshinobu Inoue {
15597d56d374SYoshinobu Inoue 	struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
1560de68a0daSKris Kennaway 	char hbuf[NI_MAXHOST];
15617d56d374SYoshinobu Inoue 
1562cc432e23SMariusz Zaborski 	if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len,
1563d24cb249SHajimu UMEMOTO 	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
156433841545SHajimu UMEMOTO 		strlcpy(hbuf, "invalid", sizeof(hbuf));
1565d429d720SHajimu UMEMOTO 	if (as_path)
1566d429d720SHajimu UMEMOTO 		printf(" [AS%u]", as_lookup(asn, hbuf, AF_INET6));
1567de68a0daSKris Kennaway 	if (nflag)
1568c449e284SHajimu UMEMOTO 		printf(" %s", hbuf);
1569de68a0daSKris Kennaway 	else if (lflag)
1570c449e284SHajimu UMEMOTO 		printf(" %s (%s)", inetname((struct sockaddr *)from), hbuf);
1571de68a0daSKris Kennaway 	else
1572c449e284SHajimu UMEMOTO 		printf(" %s", inetname((struct sockaddr *)from));
15737d56d374SYoshinobu Inoue 
15747d56d374SYoshinobu Inoue 	if (verbose) {
1575de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1576c449e284SHajimu UMEMOTO 		printf(" %d bytes to %s", cc,
1577de68a0daSKris Kennaway 		    rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1578c449e284SHajimu UMEMOTO 		    hbuf, sizeof(hbuf)) : "?");
1579de68a0daSKris Kennaway #else
1580c449e284SHajimu UMEMOTO 		printf(" %d bytes of data to %s", cc,
1581de68a0daSKris Kennaway 		    rcvpktinfo ?  inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1582c449e284SHajimu UMEMOTO 		    hbuf, sizeof(hbuf)) : "?");
1583de68a0daSKris Kennaway #endif
15847d56d374SYoshinobu Inoue 	}
15857d56d374SYoshinobu Inoue }
15867d56d374SYoshinobu Inoue 
15877d56d374SYoshinobu Inoue /*
15887d56d374SYoshinobu Inoue  * Construct an Internet address representation.
15897d56d374SYoshinobu Inoue  * If the nflag has been supplied, give
15907d56d374SYoshinobu Inoue  * numeric value, otherwise try for symbolic name.
15917d56d374SYoshinobu Inoue  */
1592de68a0daSKris Kennaway const char *
1593aa96470cSMichael Tuexen inetname(struct sockaddr *sa)
15947d56d374SYoshinobu Inoue {
1595e961704aSDavid Malone 	static char line[NI_MAXHOST], domain[MAXHOSTNAMELEN + 1];
15967d56d374SYoshinobu Inoue 	static int first = 1;
1597e961704aSDavid Malone 	char *cp;
15987d56d374SYoshinobu Inoue 
15997d56d374SYoshinobu Inoue 	if (first && !nflag) {
16007d56d374SYoshinobu Inoue 		first = 0;
1601c449e284SHajimu UMEMOTO 		if (gethostname(domain, sizeof(domain)) == 0 &&
1602c449e284SHajimu UMEMOTO 		    (cp = strchr(domain, '.')))
160333841545SHajimu UMEMOTO 			(void) strlcpy(domain, cp + 1, sizeof(domain));
16047d56d374SYoshinobu Inoue 		else
16057d56d374SYoshinobu Inoue 			domain[0] = 0;
16067d56d374SYoshinobu Inoue 	}
1607de68a0daSKris Kennaway 	cp = NULL;
16087d56d374SYoshinobu Inoue 	if (!nflag) {
1609cc432e23SMariusz Zaborski 		if (cap_getnameinfo(capdns, sa, sa->sa_len, line, sizeof(line), NULL, 0,
1610de68a0daSKris Kennaway 		    NI_NAMEREQD) == 0) {
1611c449e284SHajimu UMEMOTO 			if ((cp = strchr(line, '.')) &&
16127d56d374SYoshinobu Inoue 			    !strcmp(cp + 1, domain))
16137d56d374SYoshinobu Inoue 				*cp = 0;
1614de68a0daSKris Kennaway 			cp = line;
16157d56d374SYoshinobu Inoue 		}
16167d56d374SYoshinobu Inoue 	}
16177d56d374SYoshinobu Inoue 	if (cp)
1618de68a0daSKris Kennaway 		return cp;
1619de68a0daSKris Kennaway 
1620cc432e23SMariusz Zaborski 	if (cap_getnameinfo(capdns, sa, sa->sa_len, line, sizeof(line), NULL, 0,
1621d24cb249SHajimu UMEMOTO 	    NI_NUMERICHOST) != 0)
162233841545SHajimu UMEMOTO 		strlcpy(line, "invalid", sizeof(line));
1623de68a0daSKris Kennaway 	return line;
16247d56d374SYoshinobu Inoue }
16257d56d374SYoshinobu Inoue 
16269d8b46c8SMichael Tuexen /*
16279d8b46c8SMichael Tuexen  * CRC32C routine for the Stream Control Transmission Protocol
16289d8b46c8SMichael Tuexen  */
16299d8b46c8SMichael Tuexen 
16309d8b46c8SMichael Tuexen #define CRC32C(c, d) (c = (c>>8) ^ crc_c[(c^(d))&0xFF])
16319d8b46c8SMichael Tuexen 
16329d8b46c8SMichael Tuexen static u_int32_t crc_c[256] = {
16339d8b46c8SMichael Tuexen 	0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
16349d8b46c8SMichael Tuexen 	0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
16359d8b46c8SMichael Tuexen 	0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
16369d8b46c8SMichael Tuexen 	0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
16379d8b46c8SMichael Tuexen 	0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
16389d8b46c8SMichael Tuexen 	0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
16399d8b46c8SMichael Tuexen 	0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
16409d8b46c8SMichael Tuexen 	0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
16419d8b46c8SMichael Tuexen 	0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
16429d8b46c8SMichael Tuexen 	0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
16439d8b46c8SMichael Tuexen 	0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
16449d8b46c8SMichael Tuexen 	0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
16459d8b46c8SMichael Tuexen 	0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
16469d8b46c8SMichael Tuexen 	0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
16479d8b46c8SMichael Tuexen 	0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
16489d8b46c8SMichael Tuexen 	0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
16499d8b46c8SMichael Tuexen 	0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
16509d8b46c8SMichael Tuexen 	0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
16519d8b46c8SMichael Tuexen 	0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
16529d8b46c8SMichael Tuexen 	0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
16539d8b46c8SMichael Tuexen 	0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
16549d8b46c8SMichael Tuexen 	0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
16559d8b46c8SMichael Tuexen 	0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
16569d8b46c8SMichael Tuexen 	0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
16579d8b46c8SMichael Tuexen 	0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
16589d8b46c8SMichael Tuexen 	0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
16599d8b46c8SMichael Tuexen 	0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
16609d8b46c8SMichael Tuexen 	0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
16619d8b46c8SMichael Tuexen 	0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
16629d8b46c8SMichael Tuexen 	0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
16639d8b46c8SMichael Tuexen 	0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
16649d8b46c8SMichael Tuexen 	0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
16659d8b46c8SMichael Tuexen 	0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
16669d8b46c8SMichael Tuexen 	0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
16679d8b46c8SMichael Tuexen 	0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
16689d8b46c8SMichael Tuexen 	0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
16699d8b46c8SMichael Tuexen 	0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
16709d8b46c8SMichael Tuexen 	0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
16719d8b46c8SMichael Tuexen 	0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
16729d8b46c8SMichael Tuexen 	0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
16739d8b46c8SMichael Tuexen 	0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
16749d8b46c8SMichael Tuexen 	0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
16759d8b46c8SMichael Tuexen 	0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
16769d8b46c8SMichael Tuexen 	0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
16779d8b46c8SMichael Tuexen 	0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
16789d8b46c8SMichael Tuexen 	0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
16799d8b46c8SMichael Tuexen 	0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
16809d8b46c8SMichael Tuexen 	0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
16819d8b46c8SMichael Tuexen 	0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
16829d8b46c8SMichael Tuexen 	0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
16839d8b46c8SMichael Tuexen 	0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
16849d8b46c8SMichael Tuexen 	0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
16859d8b46c8SMichael Tuexen 	0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
16869d8b46c8SMichael Tuexen 	0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
16879d8b46c8SMichael Tuexen 	0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
16889d8b46c8SMichael Tuexen 	0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
16899d8b46c8SMichael Tuexen 	0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
16909d8b46c8SMichael Tuexen 	0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
16919d8b46c8SMichael Tuexen 	0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
16929d8b46c8SMichael Tuexen 	0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
16939d8b46c8SMichael Tuexen 	0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
16949d8b46c8SMichael Tuexen 	0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
16959d8b46c8SMichael Tuexen 	0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
16969d8b46c8SMichael Tuexen 	0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
16979d8b46c8SMichael Tuexen };
16989d8b46c8SMichael Tuexen 
16999d8b46c8SMichael Tuexen u_int32_t
1700ca19d0d7SMark Johnston sctp_crc32c(void *pack, u_int32_t len)
17019d8b46c8SMichael Tuexen {
17029d8b46c8SMichael Tuexen 	u_int32_t i, crc32c;
17039d8b46c8SMichael Tuexen 	u_int8_t byte0, byte1, byte2, byte3;
1704ca19d0d7SMark Johnston 	u_int8_t *buf = (u_int8_t *)pack;
17059d8b46c8SMichael Tuexen 
17069d8b46c8SMichael Tuexen 	crc32c = ~0;
17079d8b46c8SMichael Tuexen 	for (i = 0; i < len; i++)
17089d8b46c8SMichael Tuexen 		CRC32C(crc32c, buf[i]);
17099d8b46c8SMichael Tuexen 	crc32c = ~crc32c;
17109d8b46c8SMichael Tuexen 	byte0  = crc32c & 0xff;
17119d8b46c8SMichael Tuexen 	byte1  = (crc32c>>8) & 0xff;
17129d8b46c8SMichael Tuexen 	byte2  = (crc32c>>16) & 0xff;
17139d8b46c8SMichael Tuexen 	byte3  = (crc32c>>24) & 0xff;
17149d8b46c8SMichael Tuexen 	crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
17159d8b46c8SMichael Tuexen 	return htonl(crc32c);
17169d8b46c8SMichael Tuexen }
17179d8b46c8SMichael Tuexen 
17189d8b46c8SMichael Tuexen u_int16_t
17199d8b46c8SMichael Tuexen in_cksum(u_int16_t *addr, int len)
17209d8b46c8SMichael Tuexen {
17219d8b46c8SMichael Tuexen 	int nleft = len;
17229d8b46c8SMichael Tuexen 	u_int16_t *w = addr;
17239d8b46c8SMichael Tuexen 	u_int16_t answer;
17249d8b46c8SMichael Tuexen 	int sum = 0;
17259d8b46c8SMichael Tuexen 
17269d8b46c8SMichael Tuexen 	/*
17279d8b46c8SMichael Tuexen 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
17289d8b46c8SMichael Tuexen 	 *  we add sequential 16 bit words to it, and at the end, fold
17299d8b46c8SMichael Tuexen 	 *  back all the carry bits from the top 16 bits into the lower
17309d8b46c8SMichael Tuexen 	 *  16 bits.
17319d8b46c8SMichael Tuexen 	 */
17329d8b46c8SMichael Tuexen 	while (nleft > 1)  {
17339d8b46c8SMichael Tuexen 		sum += *w++;
17349d8b46c8SMichael Tuexen 		nleft -= 2;
17359d8b46c8SMichael Tuexen 	}
17369d8b46c8SMichael Tuexen 
17379d8b46c8SMichael Tuexen 	/* mop up an odd byte, if necessary */
17389d8b46c8SMichael Tuexen 	if (nleft == 1)
17399d8b46c8SMichael Tuexen 		sum += *(u_char *)w;
17409d8b46c8SMichael Tuexen 
17419d8b46c8SMichael Tuexen 	/*
17429d8b46c8SMichael Tuexen 	 * add back carry outs from top 16 bits to low 16 bits
17439d8b46c8SMichael Tuexen 	 */
17449d8b46c8SMichael Tuexen 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
17459d8b46c8SMichael Tuexen 	sum += (sum >> 16);			/* add carry */
17469d8b46c8SMichael Tuexen 	answer = ~sum;				/* truncate to 16 bits */
17479d8b46c8SMichael Tuexen 	return (answer);
17489d8b46c8SMichael Tuexen }
17499d8b46c8SMichael Tuexen 
17509d8b46c8SMichael Tuexen u_int16_t
1751cc432e23SMariusz Zaborski udp_cksum(struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
1752cc432e23SMariusz Zaborski     void *payload, u_int32_t len)
1753cc432e23SMariusz Zaborski {
1754cc432e23SMariusz Zaborski 	struct {
1755cc432e23SMariusz Zaborski 		struct in6_addr src;
1756cc432e23SMariusz Zaborski 		struct in6_addr dst;
1757cc432e23SMariusz Zaborski 		u_int32_t len;
1758cc432e23SMariusz Zaborski 		u_int8_t zero[3];
1759cc432e23SMariusz Zaborski 		u_int8_t next;
1760cc432e23SMariusz Zaborski 	} pseudo_hdr;
1761cc432e23SMariusz Zaborski 	u_int16_t sum[2];
1762cc432e23SMariusz Zaborski 
1763cc432e23SMariusz Zaborski 	pseudo_hdr.src = src->sin6_addr;
1764cc432e23SMariusz Zaborski 	pseudo_hdr.dst = dst->sin6_addr;
1765cc432e23SMariusz Zaborski 	pseudo_hdr.len = htonl(len);
1766cc432e23SMariusz Zaborski 	pseudo_hdr.zero[0] = 0;
1767cc432e23SMariusz Zaborski 	pseudo_hdr.zero[1] = 0;
1768cc432e23SMariusz Zaborski 	pseudo_hdr.zero[2] = 0;
1769cc432e23SMariusz Zaborski 	pseudo_hdr.next = IPPROTO_UDP;
1770cc432e23SMariusz Zaborski 
1771cc432e23SMariusz Zaborski 	sum[1] = in_cksum((u_int16_t *)&pseudo_hdr, sizeof(pseudo_hdr));
1772cc432e23SMariusz Zaborski 	sum[0] = in_cksum(payload, len);
1773cc432e23SMariusz Zaborski 
1774cc432e23SMariusz Zaborski 	return (~in_cksum(sum, sizeof(sum)));
1775cc432e23SMariusz Zaborski }
1776cc432e23SMariusz Zaborski 
1777cc432e23SMariusz Zaborski u_int16_t
17789d8b46c8SMichael Tuexen tcp_chksum(struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
17799d8b46c8SMichael Tuexen     void *payload, u_int32_t len)
17809d8b46c8SMichael Tuexen {
17819d8b46c8SMichael Tuexen 	struct {
17829d8b46c8SMichael Tuexen 		struct in6_addr src;
17839d8b46c8SMichael Tuexen 		struct in6_addr dst;
17849d8b46c8SMichael Tuexen 		u_int32_t len;
17859d8b46c8SMichael Tuexen 		u_int8_t zero[3];
17869d8b46c8SMichael Tuexen 		u_int8_t next;
17879d8b46c8SMichael Tuexen 	} pseudo_hdr;
17889d8b46c8SMichael Tuexen 	u_int16_t sum[2];
17899d8b46c8SMichael Tuexen 
17909d8b46c8SMichael Tuexen 	pseudo_hdr.src = src->sin6_addr;
17919d8b46c8SMichael Tuexen 	pseudo_hdr.dst = dst->sin6_addr;
17929d8b46c8SMichael Tuexen 	pseudo_hdr.len = htonl(len);
17939d8b46c8SMichael Tuexen 	pseudo_hdr.zero[0] = 0;
17949d8b46c8SMichael Tuexen 	pseudo_hdr.zero[1] = 0;
17959d8b46c8SMichael Tuexen 	pseudo_hdr.zero[2] = 0;
17969d8b46c8SMichael Tuexen 	pseudo_hdr.next = IPPROTO_TCP;
17979d8b46c8SMichael Tuexen 
17989d8b46c8SMichael Tuexen 	sum[1] = in_cksum((u_int16_t *)&pseudo_hdr, sizeof(pseudo_hdr));
17999d8b46c8SMichael Tuexen 	sum[0] = in_cksum(payload, len);
18009d8b46c8SMichael Tuexen 
18019d8b46c8SMichael Tuexen 	return (~in_cksum(sum, sizeof(sum)));
18029d8b46c8SMichael Tuexen }
18039d8b46c8SMichael Tuexen 
18047d56d374SYoshinobu Inoue void
1805aa96470cSMichael Tuexen usage(void)
18067d56d374SYoshinobu Inoue {
180784a1a4cfSHajimu UMEMOTO 
180884a1a4cfSHajimu UMEMOTO 	fprintf(stderr,
18099d8b46c8SMichael Tuexen "usage: traceroute6 [-adIlnNrSTUv] [-A as_server] [-f firsthop] [-g gateway]\n"
18100d7d117cSHajimu UMEMOTO "       [-m hoplimit] [-p port] [-q probes] [-s src] [-w waittime] target\n"
18110d7d117cSHajimu UMEMOTO "       [datalen]\n");
18127d56d374SYoshinobu Inoue 	exit(1);
18137d56d374SYoshinobu Inoue }
1814