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 /*
677d56d374SYoshinobu Inoue * traceroute host - trace the route ip packets follow going to "host".
687d56d374SYoshinobu Inoue *
697d56d374SYoshinobu Inoue * Attempt to trace the route an ip packet would follow to some
707d56d374SYoshinobu Inoue * internet host. We find out intermediate hops by launching probe
717d56d374SYoshinobu Inoue * packets with a small ttl (time to live) then listening for an
727d56d374SYoshinobu Inoue * icmp "time exceeded" reply from a gateway. We start our probes
737d56d374SYoshinobu Inoue * with a ttl of one and increase by one until we get an icmp "port
747d56d374SYoshinobu Inoue * unreachable" (which means we got to "host") or hit a max (which
7500aa6353SJose Luis Duran * defaults to net.inet.ip.ttl hops & can be changed with the -m flag).
7600aa6353SJose Luis Duran * Three probes (change with -q flag) are sent at each ttl setting and
7700aa6353SJose Luis Duran * a line is printed showing the ttl, address of the gateway and
787d56d374SYoshinobu Inoue * round trip time of each probe. If the probe answers come from
797d56d374SYoshinobu Inoue * different gateways, the address of each responding system will
807d56d374SYoshinobu Inoue * be printed. If there is no response within a 5 sec. timeout
817d56d374SYoshinobu Inoue * interval (changed with the -w flag), a "*" is printed for that
827d56d374SYoshinobu Inoue * probe.
837d56d374SYoshinobu Inoue *
847d56d374SYoshinobu Inoue * Probe packets are UDP format. We don't want the destination
857d56d374SYoshinobu Inoue * host to process them so the destination port is set to an
867d56d374SYoshinobu Inoue * unlikely value (if some clod on the destination is using that
877d56d374SYoshinobu Inoue * value, it can be changed with the -p flag).
887d56d374SYoshinobu Inoue *
897d56d374SYoshinobu Inoue * A sample use might be:
907d56d374SYoshinobu Inoue *
917d56d374SYoshinobu Inoue * [yak 71]% traceroute nis.nsf.net.
9200aa6353SJose Luis Duran * traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 40 byte packets
937d56d374SYoshinobu Inoue * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
947d56d374SYoshinobu Inoue * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
957d56d374SYoshinobu Inoue * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
967d56d374SYoshinobu Inoue * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
977d56d374SYoshinobu Inoue * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
987d56d374SYoshinobu Inoue * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
997d56d374SYoshinobu Inoue * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
1007d56d374SYoshinobu Inoue * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
1017d56d374SYoshinobu Inoue * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
1027d56d374SYoshinobu Inoue * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
1037d56d374SYoshinobu Inoue * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
1047d56d374SYoshinobu Inoue *
1057d56d374SYoshinobu Inoue * Note that lines 2 & 3 are the same. This is due to a buggy
1067d56d374SYoshinobu Inoue * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
1077d56d374SYoshinobu Inoue * packets with a zero ttl.
1087d56d374SYoshinobu Inoue *
1097d56d374SYoshinobu Inoue * A more interesting example is:
1107d56d374SYoshinobu Inoue *
1117d56d374SYoshinobu Inoue * [yak 72]% traceroute allspice.lcs.mit.edu.
11200aa6353SJose Luis Duran * traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max, 40 byte packets
1137d56d374SYoshinobu Inoue * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
1147d56d374SYoshinobu Inoue * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
1157d56d374SYoshinobu Inoue * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
1167d56d374SYoshinobu Inoue * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
1177d56d374SYoshinobu Inoue * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
1187d56d374SYoshinobu Inoue * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
1197d56d374SYoshinobu Inoue * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
1207d56d374SYoshinobu Inoue * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
1217d56d374SYoshinobu Inoue * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
1227d56d374SYoshinobu Inoue * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
1237d56d374SYoshinobu Inoue * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
1247d56d374SYoshinobu Inoue * 12 * * *
1257d56d374SYoshinobu Inoue * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
1267d56d374SYoshinobu Inoue * 14 * * *
1277d56d374SYoshinobu Inoue * 15 * * *
1287d56d374SYoshinobu Inoue * 16 * * *
1297d56d374SYoshinobu Inoue * 17 * * *
1307d56d374SYoshinobu Inoue * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
1317d56d374SYoshinobu Inoue *
1327d56d374SYoshinobu Inoue * (I start to see why I'm having so much trouble with mail to
1337d56d374SYoshinobu Inoue * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away
1347d56d374SYoshinobu Inoue * either don't send ICMP "time exceeded" messages or send them
1357d56d374SYoshinobu Inoue * with a ttl too small to reach us. 14 - 17 are running the
1367d56d374SYoshinobu Inoue * MIT C Gateway code that doesn't send "time exceeded"s. God
1377d56d374SYoshinobu Inoue * only knows what's going on with 12.
1387d56d374SYoshinobu Inoue *
1397d56d374SYoshinobu Inoue * The silent gateway 12 in the above may be the result of a bug in
1407d56d374SYoshinobu Inoue * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3)
1417d56d374SYoshinobu Inoue * sends an unreachable message using whatever ttl remains in the
1427d56d374SYoshinobu Inoue * original datagram. Since, for gateways, the remaining ttl is
1437d56d374SYoshinobu Inoue * zero, the icmp "time exceeded" is guaranteed to not make it back
1447d56d374SYoshinobu Inoue * to us. The behavior of this bug is slightly more interesting
1457d56d374SYoshinobu Inoue * when it appears on the destination system:
1467d56d374SYoshinobu Inoue *
1477d56d374SYoshinobu Inoue * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
1487d56d374SYoshinobu Inoue * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
1497d56d374SYoshinobu Inoue * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
1507d56d374SYoshinobu Inoue * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
1517d56d374SYoshinobu Inoue * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
1527d56d374SYoshinobu Inoue * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
1537d56d374SYoshinobu Inoue * 7 * * *
1547d56d374SYoshinobu Inoue * 8 * * *
1557d56d374SYoshinobu Inoue * 9 * * *
1567d56d374SYoshinobu Inoue * 10 * * *
1577d56d374SYoshinobu Inoue * 11 * * *
1587d56d374SYoshinobu Inoue * 12 * * *
1597d56d374SYoshinobu Inoue * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
1607d56d374SYoshinobu Inoue *
1617d56d374SYoshinobu Inoue * Notice that there are 12 "gateways" (13 is the final
1627d56d374SYoshinobu Inoue * destination) and exactly the last half of them are "missing".
1637d56d374SYoshinobu Inoue * What's really happening is that rip (a Sun-3 running Sun OS3.5)
1647d56d374SYoshinobu Inoue * is using the ttl from our arriving datagram as the ttl in its
1657d56d374SYoshinobu Inoue * icmp reply. So, the reply will time out on the return path
1667d56d374SYoshinobu Inoue * (with no notice sent to anyone since icmp's aren't sent for
1677d56d374SYoshinobu Inoue * icmp's) until we probe with a ttl that's at least twice the path
1687d56d374SYoshinobu Inoue * length. I.e., rip is really only 7 hops away. A reply that
1697d56d374SYoshinobu Inoue * returns with a ttl of 1 is a clue this problem exists.
1707d56d374SYoshinobu Inoue * Traceroute prints a "!" after the time if the ttl is <= 1.
1717d56d374SYoshinobu Inoue * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
1727d56d374SYoshinobu Inoue * non-standard (HPUX) software, expect to see this problem
1737d56d374SYoshinobu Inoue * frequently and/or take care picking the target host of your
1747d56d374SYoshinobu Inoue * probes.
1757d56d374SYoshinobu Inoue *
1767d56d374SYoshinobu Inoue * Other possible annotations after the time are !H, !N, !P (got a host,
1777d56d374SYoshinobu Inoue * network or protocol unreachable, respectively), !S or !F (source
1787d56d374SYoshinobu Inoue * route failed or fragmentation needed -- neither of these should
1797d56d374SYoshinobu Inoue * ever occur and the associated gateway is busted if you see one). If
1807d56d374SYoshinobu Inoue * almost all the probes result in some kind of unreachable, traceroute
1817d56d374SYoshinobu Inoue * will give up and exit.
1827d56d374SYoshinobu Inoue *
1837d56d374SYoshinobu Inoue * Notes
1847d56d374SYoshinobu Inoue * -----
1857d56d374SYoshinobu Inoue * This program must be run by root or be setuid. (I suggest that
1867d56d374SYoshinobu Inoue * you *don't* make it setuid -- casual use could result in a lot
1877d56d374SYoshinobu Inoue * of unnecessary traffic on our poor, congested nets.)
1887d56d374SYoshinobu Inoue *
1897d56d374SYoshinobu Inoue * This program requires a kernel mod that does not appear in any
1907d56d374SYoshinobu Inoue * system available from Berkeley: A raw ip socket using proto
1917d56d374SYoshinobu Inoue * IPPROTO_RAW must interpret the data sent as an ip datagram (as
1929d5abbddSJens Schweikhardt * opposed to data to be wrapped in an ip datagram). See the README
1937d56d374SYoshinobu Inoue * file that came with the source to this program for a description
1947d56d374SYoshinobu Inoue * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may
1957d56d374SYoshinobu Inoue * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
1967d56d374SYoshinobu Inoue * MODIFIED TO RUN THIS PROGRAM.
1977d56d374SYoshinobu Inoue *
1987d56d374SYoshinobu Inoue * The udp port usage may appear bizarre (well, ok, it is bizarre).
1997d56d374SYoshinobu Inoue * The problem is that an icmp message only contains 8 bytes of
2007d56d374SYoshinobu Inoue * data from the original datagram. 8 bytes is the size of a udp
2017d56d374SYoshinobu Inoue * header so, if we want to associate replies with the original
2027d56d374SYoshinobu Inoue * datagram, the necessary information must be encoded into the
2037d56d374SYoshinobu Inoue * udp header (the ip id could be used but there's no way to
2047d56d374SYoshinobu Inoue * interlock with the kernel's assignment of ip id's and, anyway,
2057d56d374SYoshinobu Inoue * it would have taken a lot more kernel hacking to allow this
2067d56d374SYoshinobu Inoue * code to set the ip id). So, to allow two or more users to
2077d56d374SYoshinobu Inoue * use traceroute simultaneously, we use this task's pid as the
2087d56d374SYoshinobu Inoue * source port (the high bit is set to move the port number out
2097d56d374SYoshinobu Inoue * of the "likely" range). To keep track of which probe is being
2107d56d374SYoshinobu Inoue * replied to (so times and/or hop counts don't get confused by a
2117d56d374SYoshinobu Inoue * reply that was delayed in transit), we increment the destination
2127d56d374SYoshinobu Inoue * port number before each probe.
2137d56d374SYoshinobu Inoue *
2147d56d374SYoshinobu Inoue * Don't use this as a coding example. I was trying to find a
2157d56d374SYoshinobu Inoue * routing problem and this code sort-of popped out after 48 hours
2167d56d374SYoshinobu Inoue * without sleep. I was amazed it ever compiled, much less ran.
2177d56d374SYoshinobu Inoue *
2187d56d374SYoshinobu Inoue * I stole the idea for this program from Steve Deering. Since
2197d56d374SYoshinobu Inoue * the first release, I've learned that had I attended the right
2207d56d374SYoshinobu Inoue * IETF working group meetings, I also could have stolen it from Guy
2217d56d374SYoshinobu Inoue * Almes or Matt Mathis. I don't know (or care) who came up with
2227d56d374SYoshinobu Inoue * the idea first. I envy the originators' perspicacity and I'm
2237d56d374SYoshinobu Inoue * glad they didn't keep the idea a secret.
2247d56d374SYoshinobu Inoue *
2257d56d374SYoshinobu Inoue * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
2267d56d374SYoshinobu Inoue * enhancements to the original distribution.
2277d56d374SYoshinobu Inoue *
2287d56d374SYoshinobu Inoue * I've hacked up a round-trip-route version of this that works by
2297d56d374SYoshinobu Inoue * sending a loose-source-routed udp datagram through the destination
2307d56d374SYoshinobu Inoue * back to yourself. Unfortunately, SO many gateways botch source
2317d56d374SYoshinobu Inoue * routing, the thing is almost worthless. Maybe one day...
2327d56d374SYoshinobu Inoue *
23300aa6353SJose Luis Duran * -- Van Jacobson (van@ee.lbl.gov)
2347d56d374SYoshinobu Inoue * Tue Dec 20 03:50:13 PST 1988
2357d56d374SYoshinobu Inoue */
2367d56d374SYoshinobu Inoue
2377d56d374SYoshinobu Inoue #include <sys/param.h>
238cc432e23SMariusz Zaborski #include <sys/capsicum.h>
2397d56d374SYoshinobu Inoue #include <sys/time.h>
2407d56d374SYoshinobu Inoue #include <sys/socket.h>
2417d56d374SYoshinobu Inoue #include <sys/uio.h>
2427d56d374SYoshinobu Inoue #include <sys/file.h>
2437d56d374SYoshinobu Inoue #include <sys/ioctl.h>
24484a1a4cfSHajimu UMEMOTO #include <sys/sysctl.h>
2457d56d374SYoshinobu Inoue
2467d56d374SYoshinobu Inoue #include <netinet/in.h>
2477d56d374SYoshinobu Inoue
2487d56d374SYoshinobu Inoue #include <arpa/inet.h>
2497d56d374SYoshinobu Inoue
250cc432e23SMariusz Zaborski #include <libcasper.h>
251cc432e23SMariusz Zaborski #include <casper/cap_dns.h>
252cc432e23SMariusz Zaborski #include <capsicum_helpers.h>
253cc432e23SMariusz Zaborski
2547d56d374SYoshinobu Inoue #include <netdb.h>
2557d56d374SYoshinobu Inoue #include <stdio.h>
2567d56d374SYoshinobu Inoue #include <err.h>
2572a1c5efaSKris Kennaway #ifdef HAVE_POLL
2582a1c5efaSKris Kennaway #include <poll.h>
2592a1c5efaSKris Kennaway #endif
2607d56d374SYoshinobu Inoue #include <errno.h>
2617d56d374SYoshinobu Inoue #include <stdlib.h>
2627d56d374SYoshinobu Inoue #include <string.h>
2637d56d374SYoshinobu Inoue #include <unistd.h>
2647d56d374SYoshinobu Inoue
2650c2218d1SJose Luis Duran #include <netinet/ip.h>
2667d56d374SYoshinobu Inoue #include <netinet/ip6.h>
2677d56d374SYoshinobu Inoue #include <netinet/icmp6.h>
2689d8b46c8SMichael Tuexen #include <netinet/sctp.h>
26951eff8efSMichael Tuexen #include <netinet/sctp_header.h>
2709d8b46c8SMichael Tuexen #include <netinet/tcp.h>
2717d56d374SYoshinobu Inoue #include <netinet/udp.h>
2727d56d374SYoshinobu Inoue
2737d56d374SYoshinobu Inoue #ifdef IPSEC
2747d56d374SYoshinobu Inoue #include <net/route.h>
2758409aedfSGeorge V. Neville-Neil #include <netipsec/ipsec.h>
2767d56d374SYoshinobu Inoue #endif
2777d56d374SYoshinobu Inoue
278d429d720SHajimu UMEMOTO #include "as.h"
279d429d720SHajimu UMEMOTO
2807d56d374SYoshinobu Inoue #define DUMMY_PORT 10010
2817d56d374SYoshinobu Inoue
2827d56d374SYoshinobu Inoue #define MAXPACKET 65535 /* max ip packet size */
2837d56d374SYoshinobu Inoue
284ca19d0d7SMark Johnston static u_char packet[512]; /* last inbound (icmp) packet */
285ca19d0d7SMark Johnston static char *outpacket; /* last output packet */
2867d56d374SYoshinobu Inoue
287784bddbcSKevin Lo int main(int, char *[]);
288784bddbcSKevin Lo int wait_for_reply(int, struct msghdr *);
289ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
290784bddbcSKevin Lo int setpolicy(int so, char *policy);
291de68a0daSKris Kennaway #endif
292784bddbcSKevin Lo void send_probe(int, u_long);
293d7b63fafSDavid Malone void *get_uphdr(struct ip6_hdr *, u_char *);
294cc432e23SMariusz Zaborski void capdns_open(void);
295784bddbcSKevin Lo int get_hoplim(struct msghdr *);
296784bddbcSKevin Lo double deltaT(struct timeval *, struct timeval *);
297f42640a3SUlrich Spörlein const char *pr_type(int);
2980c2218d1SJose Luis Duran int packet_ok(struct msghdr *, int, int, u_char *, u_char *, u_char *);
299784bddbcSKevin Lo void print(struct msghdr *, int);
300784bddbcSKevin Lo const char *inetname(struct sockaddr *);
3019d8b46c8SMichael Tuexen u_int32_t sctp_crc32c(void *, u_int32_t);
3029d8b46c8SMichael Tuexen u_int16_t in_cksum(u_int16_t *addr, int);
303cc432e23SMariusz Zaborski u_int16_t udp_cksum(struct sockaddr_in6 *, struct sockaddr_in6 *,
304cc432e23SMariusz Zaborski void *, u_int32_t);
3059d8b46c8SMichael Tuexen u_int16_t tcp_chksum(struct sockaddr_in6 *, struct sockaddr_in6 *,
3069d8b46c8SMichael Tuexen void *, u_int32_t);
307784bddbcSKevin Lo void usage(void);
3087d56d374SYoshinobu Inoue
309ca19d0d7SMark Johnston static int rcvsock; /* receive (icmp) socket file descriptor */
310ca19d0d7SMark Johnston static int sndsock; /* send (raw/udp) socket file descriptor */
3117d56d374SYoshinobu Inoue
312ca19d0d7SMark Johnston static struct msghdr rcvmhdr;
313ca19d0d7SMark Johnston static struct iovec rcviov[2];
314ca19d0d7SMark Johnston static int rcvhlim;
315ca19d0d7SMark Johnston static struct in6_pktinfo *rcvpktinfo;
3167d56d374SYoshinobu Inoue
317ca19d0d7SMark Johnston static struct sockaddr_in6 Src, Dst, Rcv;
318ca19d0d7SMark Johnston static u_long datalen = 20; /* How much data */
31984a1a4cfSHajimu UMEMOTO #define ICMP6ECHOLEN 8
320de68a0daSKris Kennaway /* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */
321ca19d0d7SMark Johnston static char rtbuf[2064];
322ca19d0d7SMark Johnston static struct ip6_rthdr *rth;
323ca19d0d7SMark Johnston static struct cmsghdr *cmsg;
3247d56d374SYoshinobu Inoue
325ca19d0d7SMark Johnston static char *source = NULL;
326ca19d0d7SMark Johnston static char *hostname;
3277d56d374SYoshinobu Inoue
328cc432e23SMariusz Zaborski static cap_channel_t *capdns;
329cc432e23SMariusz Zaborski
330ca19d0d7SMark Johnston static u_long nprobes = 3;
331ca19d0d7SMark Johnston static u_long first_hop = 1;
332ca19d0d7SMark Johnston static u_long max_hops = 30;
333ca19d0d7SMark Johnston static u_int16_t srcport;
334ca19d0d7SMark Johnston static u_int16_t port = 32768 + 666; /* start udp dest port # for probe packets */
335ca19d0d7SMark Johnston static u_int16_t ident;
336c7090651SMichael Tuexen static int tclass = -1;
337ca19d0d7SMark Johnston static int options; /* socket options */
338ca19d0d7SMark Johnston static int verbose;
339ca19d0d7SMark Johnston static int waittime = 5; /* time to wait for response (in seconds) */
340ca19d0d7SMark Johnston static int nflag; /* print addresses numerically */
341ca19d0d7SMark Johnston static int useproto = IPPROTO_UDP; /* protocol to use to send packet */
342ca19d0d7SMark Johnston static int as_path; /* print as numbers for each hop */
3430c2218d1SJose Luis Duran static int ecnflag; /* ECN bleaching detection flag */
344ca19d0d7SMark Johnston static char *as_server = NULL;
345ca19d0d7SMark Johnston static void *asn;
3467d56d374SYoshinobu Inoue
3477d56d374SYoshinobu Inoue int
main(int argc,char * argv[])348aa96470cSMichael Tuexen main(int argc, char *argv[])
3497d56d374SYoshinobu Inoue {
35084a1a4cfSHajimu UMEMOTO int mib[4] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM };
351e961704aSDavid Malone char hbuf[NI_MAXHOST], src0[NI_MAXHOST], *ep;
352f42640a3SUlrich Spörlein int ch, i, on = 1, seq, rcvcmsglen, error;
353e961704aSDavid Malone struct addrinfo hints, *res;
354e961704aSDavid Malone static u_char *rcvcmsgbuf;
355c7090651SMichael Tuexen u_long probe, hops, lport, ltclass;
356e961704aSDavid Malone struct hostent *hp;
357f42640a3SUlrich Spörlein size_t size, minlen;
35819c7ed84SKevin Lo uid_t uid;
3590c2218d1SJose Luis Duran u_char type, code, ecn;
360ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
361ca19d0d7SMark Johnston char ipsec_inpolicy[] = "in bypass";
362ca19d0d7SMark Johnston char ipsec_outpolicy[] = "out bypass";
363ca19d0d7SMark Johnston #endif
364cc432e23SMariusz Zaborski cap_rights_t rights;
365cc432e23SMariusz Zaborski
366cc432e23SMariusz Zaborski capdns_open();
3677d56d374SYoshinobu Inoue
36853c9088fSYoshinobu Inoue /*
36953c9088fSYoshinobu Inoue * Receive ICMP
37053c9088fSYoshinobu Inoue */
37153c9088fSYoshinobu Inoue if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
372de68a0daSKris Kennaway perror("socket(ICMPv6)");
37353c9088fSYoshinobu Inoue exit(5);
37453c9088fSYoshinobu Inoue }
375de68a0daSKris Kennaway
37684a1a4cfSHajimu UMEMOTO size = sizeof(i);
37784a1a4cfSHajimu UMEMOTO (void) sysctl(mib, sizeof(mib) / sizeof(mib[0]), &i, &size, NULL, 0);
37884a1a4cfSHajimu UMEMOTO max_hops = i;
37984a1a4cfSHajimu UMEMOTO
380de68a0daSKris Kennaway /* specify to tell receiving interface */
381de68a0daSKris Kennaway #ifdef IPV6_RECVPKTINFO
382de68a0daSKris Kennaway if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
383de68a0daSKris Kennaway sizeof(on)) < 0)
384de68a0daSKris Kennaway err(1, "setsockopt(IPV6_RECVPKTINFO)");
385de68a0daSKris Kennaway #else /* old adv. API */
386de68a0daSKris Kennaway if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
387de68a0daSKris Kennaway sizeof(on)) < 0)
388de68a0daSKris Kennaway err(1, "setsockopt(IPV6_PKTINFO)");
389de68a0daSKris Kennaway #endif
390de68a0daSKris Kennaway
391de68a0daSKris Kennaway /* specify to tell value of hoplimit field of received IP6 hdr */
392de68a0daSKris Kennaway #ifdef IPV6_RECVHOPLIMIT
393de68a0daSKris Kennaway if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
394de68a0daSKris Kennaway sizeof(on)) < 0)
395de68a0daSKris Kennaway err(1, "setsockopt(IPV6_RECVHOPLIMIT)");
396de68a0daSKris Kennaway #else /* old adv. API */
397de68a0daSKris Kennaway if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
398de68a0daSKris Kennaway sizeof(on)) < 0)
399de68a0daSKris Kennaway err(1, "setsockopt(IPV6_HOPLIMIT)");
400de68a0daSKris Kennaway #endif
401de68a0daSKris Kennaway
4027d56d374SYoshinobu Inoue seq = 0;
4039d8b46c8SMichael Tuexen ident = htons(getpid() & 0xffff); /* same as ping6 */
4047d56d374SYoshinobu Inoue
4050c2218d1SJose Luis Duran while ((ch = getopt(argc, argv, "aA:dEf:g:Ilm:nNp:q:rs:St:TUvw:")) != -1)
4067d56d374SYoshinobu Inoue switch (ch) {
407d429d720SHajimu UMEMOTO case 'a':
408d429d720SHajimu UMEMOTO as_path = 1;
409d429d720SHajimu UMEMOTO break;
410d429d720SHajimu UMEMOTO case 'A':
411d429d720SHajimu UMEMOTO as_path = 1;
412d429d720SHajimu UMEMOTO as_server = optarg;
413d429d720SHajimu UMEMOTO break;
4147d56d374SYoshinobu Inoue case 'd':
4157d56d374SYoshinobu Inoue options |= SO_DEBUG;
4167d56d374SYoshinobu Inoue break;
4170c2218d1SJose Luis Duran case 'E':
4180c2218d1SJose Luis Duran ecnflag = 1;
4190c2218d1SJose Luis Duran break;
420de68a0daSKris Kennaway case 'f':
42133841545SHajimu UMEMOTO ep = NULL;
42284a1a4cfSHajimu UMEMOTO errno = 0;
42333841545SHajimu UMEMOTO first_hop = strtoul(optarg, &ep, 0);
42484a1a4cfSHajimu UMEMOTO if (errno || !*optarg || *ep || first_hop > 255) {
425c449e284SHajimu UMEMOTO fprintf(stderr,
42633841545SHajimu UMEMOTO "traceroute6: invalid min hoplimit.\n");
42733841545SHajimu UMEMOTO exit(1);
42833841545SHajimu UMEMOTO }
4297d56d374SYoshinobu Inoue break;
4307d56d374SYoshinobu Inoue case 'g':
431cc432e23SMariusz Zaborski /* XXX use after capability mode is entered */
4327d56d374SYoshinobu Inoue hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno);
4337d56d374SYoshinobu Inoue if (hp == NULL) {
434c449e284SHajimu UMEMOTO fprintf(stderr,
4357d56d374SYoshinobu Inoue "traceroute6: unknown host %s\n", optarg);
4367d56d374SYoshinobu Inoue exit(1);
4377d56d374SYoshinobu Inoue }
438de68a0daSKris Kennaway if (rth == NULL) {
439de68a0daSKris Kennaway /*
440de68a0daSKris Kennaway * XXX: We can't detect the number of
441de68a0daSKris Kennaway * intermediate nodes yet.
442de68a0daSKris Kennaway */
443de68a0daSKris Kennaway if ((rth = inet6_rth_init((void *)rtbuf,
444c449e284SHajimu UMEMOTO sizeof(rtbuf), IPV6_RTHDR_TYPE_0,
445de68a0daSKris Kennaway 0)) == NULL) {
446c449e284SHajimu UMEMOTO fprintf(stderr,
447de68a0daSKris Kennaway "inet6_rth_init failed.\n");
448de68a0daSKris Kennaway exit(1);
449de68a0daSKris Kennaway }
450de68a0daSKris Kennaway }
451de68a0daSKris Kennaway if (inet6_rth_add((void *)rth,
452de68a0daSKris Kennaway (struct in6_addr *)hp->h_addr)) {
453c449e284SHajimu UMEMOTO fprintf(stderr,
454de68a0daSKris Kennaway "inet6_rth_add failed for %s\n",
455de68a0daSKris Kennaway optarg);
456de68a0daSKris Kennaway exit(1);
457de68a0daSKris Kennaway }
458de68a0daSKris Kennaway freehostent(hp);
459de68a0daSKris Kennaway break;
46084a1a4cfSHajimu UMEMOTO case 'I':
461d7b63fafSDavid Malone useproto = IPPROTO_ICMPV6;
46284a1a4cfSHajimu UMEMOTO break;
463de68a0daSKris Kennaway case 'l':
4647d56d374SYoshinobu Inoue break;
4657d56d374SYoshinobu Inoue case 'm':
46633841545SHajimu UMEMOTO ep = NULL;
46784a1a4cfSHajimu UMEMOTO errno = 0;
46833841545SHajimu UMEMOTO max_hops = strtoul(optarg, &ep, 0);
46984a1a4cfSHajimu UMEMOTO if (errno || !*optarg || *ep || max_hops > 255) {
470c449e284SHajimu UMEMOTO fprintf(stderr,
47133841545SHajimu UMEMOTO "traceroute6: invalid max hoplimit.\n");
47233841545SHajimu UMEMOTO exit(1);
47333841545SHajimu UMEMOTO }
4747d56d374SYoshinobu Inoue break;
4757d56d374SYoshinobu Inoue case 'n':
4767d56d374SYoshinobu Inoue nflag++;
4777d56d374SYoshinobu Inoue break;
478d7b63fafSDavid Malone case 'N':
479d7b63fafSDavid Malone useproto = IPPROTO_NONE;
480d7b63fafSDavid Malone break;
4817d56d374SYoshinobu Inoue case 'p':
48233841545SHajimu UMEMOTO ep = NULL;
48384a1a4cfSHajimu UMEMOTO errno = 0;
48484a1a4cfSHajimu UMEMOTO lport = strtoul(optarg, &ep, 0);
48584a1a4cfSHajimu UMEMOTO if (errno || !*optarg || *ep) {
48684a1a4cfSHajimu UMEMOTO fprintf(stderr, "traceroute6: invalid port.\n");
48733841545SHajimu UMEMOTO exit(1);
48833841545SHajimu UMEMOTO }
48984a1a4cfSHajimu UMEMOTO if (lport == 0 || lport != (lport & 0xffff)) {
490c449e284SHajimu UMEMOTO fprintf(stderr,
49184a1a4cfSHajimu UMEMOTO "traceroute6: port out of range.\n");
4927d56d374SYoshinobu Inoue exit(1);
4937d56d374SYoshinobu Inoue }
49484a1a4cfSHajimu UMEMOTO port = lport & 0xffff;
4957d56d374SYoshinobu Inoue break;
4967d56d374SYoshinobu Inoue case 'q':
49733841545SHajimu UMEMOTO ep = NULL;
49884a1a4cfSHajimu UMEMOTO errno = 0;
49933841545SHajimu UMEMOTO nprobes = strtoul(optarg, &ep, 0);
50084a1a4cfSHajimu UMEMOTO if (errno || !*optarg || *ep) {
501c449e284SHajimu UMEMOTO fprintf(stderr,
50233841545SHajimu UMEMOTO "traceroute6: invalid nprobes.\n");
50333841545SHajimu UMEMOTO exit(1);
50433841545SHajimu UMEMOTO }
5057d56d374SYoshinobu Inoue if (nprobes < 1) {
506c449e284SHajimu UMEMOTO fprintf(stderr,
5077d56d374SYoshinobu Inoue "traceroute6: nprobes must be >0.\n");
5087d56d374SYoshinobu Inoue exit(1);
5097d56d374SYoshinobu Inoue }
5107d56d374SYoshinobu Inoue break;
5117d56d374SYoshinobu Inoue case 'r':
5127d56d374SYoshinobu Inoue options |= SO_DONTROUTE;
5137d56d374SYoshinobu Inoue break;
5147d56d374SYoshinobu Inoue case 's':
5157d56d374SYoshinobu Inoue /*
5167d56d374SYoshinobu Inoue * set the ip source address of the outbound
5177d56d374SYoshinobu Inoue * probe (e.g., on a multi-homed host).
5187d56d374SYoshinobu Inoue */
5197d56d374SYoshinobu Inoue source = optarg;
5207d56d374SYoshinobu Inoue break;
5219d8b46c8SMichael Tuexen case 'S':
5229d8b46c8SMichael Tuexen useproto = IPPROTO_SCTP;
5239d8b46c8SMichael Tuexen break;
524c7090651SMichael Tuexen case 't':
525c7090651SMichael Tuexen ep = NULL;
526c7090651SMichael Tuexen errno = 0;
527c7090651SMichael Tuexen ltclass = strtoul(optarg, &ep, 0);
528c7090651SMichael Tuexen if (errno || !*optarg || *ep || ltclass > 255) {
529c7090651SMichael Tuexen fprintf(stderr,
530c7090651SMichael Tuexen "traceroute6: invalid traffic class.\n");
531c7090651SMichael Tuexen exit(1);
532c7090651SMichael Tuexen }
533c7090651SMichael Tuexen tclass = (int)ltclass;
534c7090651SMichael Tuexen break;
5359d8b46c8SMichael Tuexen case 'T':
5369d8b46c8SMichael Tuexen useproto = IPPROTO_TCP;
5379d8b46c8SMichael Tuexen break;
538d7b63fafSDavid Malone case 'U':
539d7b63fafSDavid Malone useproto = IPPROTO_UDP;
540d7b63fafSDavid Malone break;
541aa96470cSMichael Tuexen case 'v':
542aa96470cSMichael Tuexen verbose++;
543aa96470cSMichael Tuexen break;
5447d56d374SYoshinobu Inoue case 'w':
54533841545SHajimu UMEMOTO ep = NULL;
54684a1a4cfSHajimu UMEMOTO errno = 0;
54733841545SHajimu UMEMOTO waittime = strtoul(optarg, &ep, 0);
54884a1a4cfSHajimu UMEMOTO if (errno || !*optarg || *ep) {
549c449e284SHajimu UMEMOTO fprintf(stderr,
55033841545SHajimu UMEMOTO "traceroute6: invalid wait time.\n");
55133841545SHajimu UMEMOTO exit(1);
55233841545SHajimu UMEMOTO }
553eea319c4SMaxim Konovalov if (waittime < 1) {
554c449e284SHajimu UMEMOTO fprintf(stderr,
555eea319c4SMaxim Konovalov "traceroute6: wait must be >= 1 sec.\n");
5567d56d374SYoshinobu Inoue exit(1);
5577d56d374SYoshinobu Inoue }
5587d56d374SYoshinobu Inoue break;
5597d56d374SYoshinobu Inoue default:
5607d56d374SYoshinobu Inoue usage();
5617d56d374SYoshinobu Inoue }
5627d56d374SYoshinobu Inoue argc -= optind;
5637d56d374SYoshinobu Inoue argv += optind;
5647d56d374SYoshinobu Inoue
565d7b63fafSDavid Malone /*
566d7b63fafSDavid Malone * Open socket to send probe packets.
567d7b63fafSDavid Malone */
568d7b63fafSDavid Malone switch (useproto) {
569d7b63fafSDavid Malone case IPPROTO_ICMPV6:
570d7b63fafSDavid Malone case IPPROTO_NONE:
5719d8b46c8SMichael Tuexen case IPPROTO_SCTP:
5729d8b46c8SMichael Tuexen case IPPROTO_TCP:
5732d0fb1b3SMichael Tuexen case IPPROTO_UDP:
5749d8b46c8SMichael Tuexen if ((sndsock = socket(AF_INET6, SOCK_RAW, useproto)) < 0) {
575d7b63fafSDavid Malone perror("socket(SOCK_RAW)");
576d7b63fafSDavid Malone exit(5);
577d7b63fafSDavid Malone }
578d7b63fafSDavid Malone break;
579d7b63fafSDavid Malone default:
580aa96470cSMichael Tuexen fprintf(stderr, "traceroute6: unknown probe protocol %d\n",
581d7b63fafSDavid Malone useproto);
582d7b63fafSDavid Malone exit(5);
583d7b63fafSDavid Malone }
58484a1a4cfSHajimu UMEMOTO if (max_hops < first_hop) {
58584a1a4cfSHajimu UMEMOTO fprintf(stderr,
58684a1a4cfSHajimu UMEMOTO "traceroute6: max hoplimit must be larger than first hoplimit.\n");
58784a1a4cfSHajimu UMEMOTO exit(1);
58884a1a4cfSHajimu UMEMOTO }
58984a1a4cfSHajimu UMEMOTO
5900c2218d1SJose Luis Duran if (ecnflag) {
5910c2218d1SJose Luis Duran if (tclass != -1) {
5920c2218d1SJose Luis Duran tclass &= ~IPTOS_ECN_MASK;
5930c2218d1SJose Luis Duran } else {
5940c2218d1SJose Luis Duran tclass = 0;
5950c2218d1SJose Luis Duran }
5960c2218d1SJose Luis Duran tclass |= IPTOS_ECN_ECT1;
5970c2218d1SJose Luis Duran }
5980c2218d1SJose Luis Duran
599d7b63fafSDavid Malone /* revoke privs */
600d7b63fafSDavid Malone uid = getuid();
601d7b63fafSDavid Malone if (setresuid(uid, uid, uid) == -1) {
602d7b63fafSDavid Malone perror("setresuid");
603d7b63fafSDavid Malone exit(1);
604d7b63fafSDavid Malone }
605d7b63fafSDavid Malone
606c7090651SMichael Tuexen if (tclass != -1) {
607c7090651SMichael Tuexen if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_TCLASS, &tclass,
608c7090651SMichael Tuexen sizeof(int)) == -1) {
609c7090651SMichael Tuexen perror("setsockopt(IPV6_TCLASS)");
610c7090651SMichael Tuexen exit(7);
611c7090651SMichael Tuexen }
612c7090651SMichael Tuexen }
613d7b63fafSDavid Malone
61433841545SHajimu UMEMOTO if (argc < 1 || argc > 2)
6157d56d374SYoshinobu Inoue usage();
6167d56d374SYoshinobu Inoue
617de68a0daSKris Kennaway #if 1
6187d56d374SYoshinobu Inoue setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
619de68a0daSKris Kennaway #else
620de68a0daSKris Kennaway setlinebuf(stdout);
621de68a0daSKris Kennaway #endif
6227d56d374SYoshinobu Inoue
62339865d64SYoshinobu Inoue memset(&hints, 0, sizeof(hints));
62439865d64SYoshinobu Inoue hints.ai_family = PF_INET6;
62539865d64SYoshinobu Inoue hints.ai_socktype = SOCK_RAW;
62639865d64SYoshinobu Inoue hints.ai_protocol = IPPROTO_ICMPV6;
62739865d64SYoshinobu Inoue hints.ai_flags = AI_CANONNAME;
628cc432e23SMariusz Zaborski
629cc432e23SMariusz Zaborski error = cap_getaddrinfo(capdns, *argv, NULL, &hints, &res);
630cc432e23SMariusz Zaborski
63139865d64SYoshinobu Inoue if (error) {
632c449e284SHajimu UMEMOTO fprintf(stderr,
63339865d64SYoshinobu Inoue "traceroute6: %s\n", gai_strerror(error));
6347d56d374SYoshinobu Inoue exit(1);
6357d56d374SYoshinobu Inoue }
636de68a0daSKris Kennaway if (res->ai_addrlen != sizeof(Dst)) {
637c449e284SHajimu UMEMOTO fprintf(stderr,
638de68a0daSKris Kennaway "traceroute6: size of sockaddr mismatch\n");
639de68a0daSKris Kennaway exit(1);
640de68a0daSKris Kennaway }
64139865d64SYoshinobu Inoue memcpy(&Dst, res->ai_addr, res->ai_addrlen);
64239865d64SYoshinobu Inoue hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv;
64333841545SHajimu UMEMOTO if (!hostname) {
644c449e284SHajimu UMEMOTO fprintf(stderr, "traceroute6: not enough core\n");
64533841545SHajimu UMEMOTO exit(1);
64633841545SHajimu UMEMOTO }
64784a1a4cfSHajimu UMEMOTO if (res->ai_next) {
648cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, res->ai_addr, res->ai_addrlen, hbuf,
64984a1a4cfSHajimu UMEMOTO sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
65084a1a4cfSHajimu UMEMOTO strlcpy(hbuf, "?", sizeof(hbuf));
65184a1a4cfSHajimu UMEMOTO fprintf(stderr, "traceroute6: Warning: %s has multiple "
65284a1a4cfSHajimu UMEMOTO "addresses; using %s\n", hostname, hbuf);
65384a1a4cfSHajimu UMEMOTO }
654ca19d0d7SMark Johnston freeaddrinfo(res);
65533841545SHajimu UMEMOTO if (*++argv) {
65633841545SHajimu UMEMOTO ep = NULL;
65784a1a4cfSHajimu UMEMOTO errno = 0;
65833841545SHajimu UMEMOTO datalen = strtoul(*argv, &ep, 0);
659aa96470cSMichael Tuexen if (errno || *ep) {
660c449e284SHajimu UMEMOTO fprintf(stderr,
66133841545SHajimu UMEMOTO "traceroute6: invalid packet length.\n");
66233841545SHajimu UMEMOTO exit(1);
66333841545SHajimu UMEMOTO }
66433841545SHajimu UMEMOTO }
665d7b63fafSDavid Malone switch (useproto) {
666d7b63fafSDavid Malone case IPPROTO_ICMPV6:
667aa96470cSMichael Tuexen minlen = ICMP6ECHOLEN;
668d7b63fafSDavid Malone break;
669d7b63fafSDavid Malone case IPPROTO_UDP:
670aa96470cSMichael Tuexen minlen = sizeof(struct udphdr);
671d7b63fafSDavid Malone break;
672d7b63fafSDavid Malone case IPPROTO_NONE:
673d7b63fafSDavid Malone minlen = 0;
674d7b63fafSDavid Malone datalen = 0;
675d7b63fafSDavid Malone break;
6769d8b46c8SMichael Tuexen case IPPROTO_SCTP:
6779d8b46c8SMichael Tuexen minlen = sizeof(struct sctphdr);
6789d8b46c8SMichael Tuexen break;
6799d8b46c8SMichael Tuexen case IPPROTO_TCP:
6809d8b46c8SMichael Tuexen minlen = sizeof(struct tcphdr);
6819d8b46c8SMichael Tuexen break;
682d7b63fafSDavid Malone default:
683d7b63fafSDavid Malone fprintf(stderr, "traceroute6: unknown probe protocol %d.\n",
684d7b63fafSDavid Malone useproto);
685d7b63fafSDavid Malone exit(1);
686d7b63fafSDavid Malone }
68784a1a4cfSHajimu UMEMOTO if (datalen < minlen)
68884a1a4cfSHajimu UMEMOTO datalen = minlen;
68984a1a4cfSHajimu UMEMOTO else if (datalen >= MAXPACKET) {
690c449e284SHajimu UMEMOTO fprintf(stderr,
691f42640a3SUlrich Spörlein "traceroute6: packet size must be %zu <= s < %d.\n",
692f42640a3SUlrich Spörlein minlen, MAXPACKET);
6937d56d374SYoshinobu Inoue exit(1);
6947d56d374SYoshinobu Inoue }
69551eff8efSMichael Tuexen if ((useproto == IPPROTO_SCTP) && (datalen & 3)) {
69651eff8efSMichael Tuexen fprintf(stderr,
69751eff8efSMichael Tuexen "traceroute6: packet size must be a multiple of 4.\n");
69851eff8efSMichael Tuexen exit(1);
69951eff8efSMichael Tuexen }
700f42640a3SUlrich Spörlein outpacket = malloc(datalen);
7017d56d374SYoshinobu Inoue if (!outpacket) {
702de68a0daSKris Kennaway perror("malloc");
7037d56d374SYoshinobu Inoue exit(1);
7047d56d374SYoshinobu Inoue }
7057d56d374SYoshinobu Inoue (void) bzero((char *)outpacket, datalen);
7067d56d374SYoshinobu Inoue
7077d56d374SYoshinobu Inoue /* initialize msghdr for receiving packets */
7087d56d374SYoshinobu Inoue rcviov[0].iov_base = (caddr_t)packet;
7097d56d374SYoshinobu Inoue rcviov[0].iov_len = sizeof(packet);
710de68a0daSKris Kennaway rcvmhdr.msg_name = (caddr_t)&Rcv;
711de68a0daSKris Kennaway rcvmhdr.msg_namelen = sizeof(Rcv);
7127d56d374SYoshinobu Inoue rcvmhdr.msg_iov = rcviov;
7137d56d374SYoshinobu Inoue rcvmhdr.msg_iovlen = 1;
714e961704aSDavid Malone rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
715e961704aSDavid Malone CMSG_SPACE(sizeof(int));
716de68a0daSKris Kennaway if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) {
717c449e284SHajimu UMEMOTO fprintf(stderr, "traceroute6: malloc failed\n");
718de68a0daSKris Kennaway exit(1);
719de68a0daSKris Kennaway }
7207d56d374SYoshinobu Inoue rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
721de68a0daSKris Kennaway rcvmhdr.msg_controllen = rcvcmsglen;
7227d56d374SYoshinobu Inoue
7237d56d374SYoshinobu Inoue if (options & SO_DEBUG)
7247d56d374SYoshinobu Inoue (void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
7257d56d374SYoshinobu Inoue (char *)&on, sizeof(on));
7267d56d374SYoshinobu Inoue if (options & SO_DONTROUTE)
7277d56d374SYoshinobu Inoue (void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
7287d56d374SYoshinobu Inoue (char *)&on, sizeof(on));
729ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
7307d56d374SYoshinobu Inoue /*
7317d56d374SYoshinobu Inoue * do not raise error even if setsockopt fails, kernel may have ipsec
7327d56d374SYoshinobu Inoue * turned off.
7337d56d374SYoshinobu Inoue */
734ca19d0d7SMark Johnston if (setpolicy(rcvsock, ipsec_inpolicy) < 0)
735d94e8c62SKris Kennaway errx(1, "%s", ipsec_strerror());
736ca19d0d7SMark Johnston if (setpolicy(rcvsock, ipsec_outpolicy) < 0)
737d94e8c62SKris Kennaway errx(1, "%s", ipsec_strerror());
738de68a0daSKris Kennaway #else
739de68a0daSKris Kennaway {
740de68a0daSKris Kennaway int level = IPSEC_LEVEL_NONE;
741de68a0daSKris Kennaway
742de68a0daSKris Kennaway (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
743de68a0daSKris Kennaway sizeof(level));
744de68a0daSKris Kennaway (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
745de68a0daSKris Kennaway sizeof(level));
746de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL
747de68a0daSKris Kennaway (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
748de68a0daSKris Kennaway sizeof(level));
749de68a0daSKris Kennaway #else
750de68a0daSKris Kennaway (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
751de68a0daSKris Kennaway sizeof(level));
752de68a0daSKris Kennaway #endif
753de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL
754de68a0daSKris Kennaway (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
755de68a0daSKris Kennaway sizeof(level));
756de68a0daSKris Kennaway #endif
757de68a0daSKris Kennaway }
758ca19d0d7SMark Johnston #endif /* !(IPSEC && IPSEC_POLICY_IPSEC) */
7597d56d374SYoshinobu Inoue
760de68a0daSKris Kennaway #ifdef SO_SNDBUF
76184a1a4cfSHajimu UMEMOTO i = datalen;
762aa96470cSMichael Tuexen if (i == 0)
763aa96470cSMichael Tuexen i = 1;
76484a1a4cfSHajimu UMEMOTO if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&i,
765aa96470cSMichael Tuexen sizeof(i)) < 0) {
766de68a0daSKris Kennaway perror("setsockopt(SO_SNDBUF)");
7677d56d374SYoshinobu Inoue exit(6);
7687d56d374SYoshinobu Inoue }
769de68a0daSKris Kennaway #endif /* SO_SNDBUF */
7707d56d374SYoshinobu Inoue if (options & SO_DEBUG)
7717d56d374SYoshinobu Inoue (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
7727d56d374SYoshinobu Inoue (char *)&on, sizeof(on));
7737d56d374SYoshinobu Inoue if (options & SO_DONTROUTE)
7747d56d374SYoshinobu Inoue (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
7757d56d374SYoshinobu Inoue (char *)&on, sizeof(on));
776de68a0daSKris Kennaway if (rth) {/* XXX: there is no library to finalize the header... */
777de68a0daSKris Kennaway rth->ip6r_len = rth->ip6r_segleft * 2;
778de68a0daSKris Kennaway if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR,
779de68a0daSKris Kennaway (void *)rth, (rth->ip6r_len + 1) << 3)) {
780c449e284SHajimu UMEMOTO fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n",
781de68a0daSKris Kennaway strerror(errno));
782de68a0daSKris Kennaway exit(1);
783de68a0daSKris Kennaway }
784de68a0daSKris Kennaway }
785ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
7867d56d374SYoshinobu Inoue /*
7877d56d374SYoshinobu Inoue * do not raise error even if setsockopt fails, kernel may have ipsec
7887d56d374SYoshinobu Inoue * turned off.
7897d56d374SYoshinobu Inoue */
790ca19d0d7SMark Johnston if (setpolicy(sndsock, ipsec_inpolicy) < 0)
791d94e8c62SKris Kennaway errx(1, "%s", ipsec_strerror());
792ca19d0d7SMark Johnston if (setpolicy(sndsock, ipsec_outpolicy) < 0)
793d94e8c62SKris Kennaway errx(1, "%s", ipsec_strerror());
794de68a0daSKris Kennaway #else
795de68a0daSKris Kennaway {
796de68a0daSKris Kennaway int level = IPSEC_LEVEL_BYPASS;
797de68a0daSKris Kennaway
798de68a0daSKris Kennaway (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
799de68a0daSKris Kennaway sizeof(level));
800de68a0daSKris Kennaway (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
801de68a0daSKris Kennaway sizeof(level));
802de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL
803de68a0daSKris Kennaway (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
804de68a0daSKris Kennaway sizeof(level));
805de68a0daSKris Kennaway #else
806de68a0daSKris Kennaway (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
807de68a0daSKris Kennaway sizeof(level));
808de68a0daSKris Kennaway #endif
809de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL
810de68a0daSKris Kennaway (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
811de68a0daSKris Kennaway sizeof(level));
812de68a0daSKris Kennaway #endif
813de68a0daSKris Kennaway }
814ca19d0d7SMark Johnston #endif /* !(IPSEC && IPSEC_POLICY_IPSEC) */
8157d56d374SYoshinobu Inoue
8167d56d374SYoshinobu Inoue /*
8177d56d374SYoshinobu Inoue * Source selection
8187d56d374SYoshinobu Inoue */
819de68a0daSKris Kennaway bzero(&Src, sizeof(Src));
8207d56d374SYoshinobu Inoue if (source) {
821de68a0daSKris Kennaway memset(&hints, 0, sizeof(hints));
822de68a0daSKris Kennaway hints.ai_family = AF_INET6;
823de68a0daSKris Kennaway hints.ai_socktype = SOCK_DGRAM; /*dummy*/
824de68a0daSKris Kennaway hints.ai_flags = AI_NUMERICHOST;
825cc432e23SMariusz Zaborski error = cap_getaddrinfo(capdns, source, "0", &hints, &res);
826de68a0daSKris Kennaway if (error) {
827c449e284SHajimu UMEMOTO printf("traceroute6: %s: %s\n", source,
828de68a0daSKris Kennaway gai_strerror(error));
8297d56d374SYoshinobu Inoue exit(1);
8307d56d374SYoshinobu Inoue }
831de68a0daSKris Kennaway if (res->ai_addrlen > sizeof(Src)) {
832c449e284SHajimu UMEMOTO printf("traceroute6: %s: %s\n", source,
833de68a0daSKris Kennaway gai_strerror(error));
834de68a0daSKris Kennaway exit(1);
835de68a0daSKris Kennaway }
836de68a0daSKris Kennaway memcpy(&Src, res->ai_addr, res->ai_addrlen);
837de68a0daSKris Kennaway freeaddrinfo(res);
8387d56d374SYoshinobu Inoue } else {
8397d56d374SYoshinobu Inoue struct sockaddr_in6 Nxt;
84084a1a4cfSHajimu UMEMOTO int dummy;
84184a1a4cfSHajimu UMEMOTO socklen_t len;
8427d56d374SYoshinobu Inoue
8437d56d374SYoshinobu Inoue Nxt = Dst;
8447d56d374SYoshinobu Inoue Nxt.sin6_port = htons(DUMMY_PORT);
8457d56d374SYoshinobu Inoue if (cmsg != NULL)
8467d56d374SYoshinobu Inoue bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr,
8477d56d374SYoshinobu Inoue sizeof(Nxt.sin6_addr));
8487d56d374SYoshinobu Inoue if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
8497d56d374SYoshinobu Inoue perror("socket");
850de68a0daSKris Kennaway exit(1);
8517d56d374SYoshinobu Inoue }
852de68a0daSKris Kennaway if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) {
8537d56d374SYoshinobu Inoue perror("connect");
854de68a0daSKris Kennaway exit(1);
8557d56d374SYoshinobu Inoue }
856de68a0daSKris Kennaway len = sizeof(Src);
857de68a0daSKris Kennaway if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) {
858de68a0daSKris Kennaway perror("getsockname");
859de68a0daSKris Kennaway exit(1);
860de68a0daSKris Kennaway }
861cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)&Src, Src.sin6_len,
862d24cb249SHajimu UMEMOTO src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) {
863c449e284SHajimu UMEMOTO fprintf(stderr, "getnameinfo failed for source\n");
864de68a0daSKris Kennaway exit(1);
865de68a0daSKris Kennaway }
866de68a0daSKris Kennaway source = src0;
8677d56d374SYoshinobu Inoue close(dummy);
8687d56d374SYoshinobu Inoue }
869de68a0daSKris Kennaway
87084a1a4cfSHajimu UMEMOTO Src.sin6_port = htons(0);
871de68a0daSKris Kennaway if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) {
872de68a0daSKris Kennaway perror("bind");
8737d56d374SYoshinobu Inoue exit(1);
8747d56d374SYoshinobu Inoue }
8757d56d374SYoshinobu Inoue
87684a1a4cfSHajimu UMEMOTO {
877c449e284SHajimu UMEMOTO socklen_t len;
878de68a0daSKris Kennaway
879de68a0daSKris Kennaway len = sizeof(Src);
88084a1a4cfSHajimu UMEMOTO if (getsockname(sndsock, (struct sockaddr *)&Src, &len) < 0) {
881de68a0daSKris Kennaway perror("getsockname");
882de68a0daSKris Kennaway exit(1);
883de68a0daSKris Kennaway }
88484a1a4cfSHajimu UMEMOTO srcport = ntohs(Src.sin6_port);
885de68a0daSKris Kennaway }
886de68a0daSKris Kennaway
887d429d720SHajimu UMEMOTO if (as_path) {
888d429d720SHajimu UMEMOTO asn = as_setup(as_server);
889d429d720SHajimu UMEMOTO if (asn == NULL) {
890d429d720SHajimu UMEMOTO fprintf(stderr,
891d429d720SHajimu UMEMOTO "traceroute6: as_setup failed, AS# lookups"
892d429d720SHajimu UMEMOTO " disabled\n");
893d429d720SHajimu UMEMOTO (void)fflush(stderr);
894d429d720SHajimu UMEMOTO as_path = 0;
895d429d720SHajimu UMEMOTO }
896d429d720SHajimu UMEMOTO }
897d429d720SHajimu UMEMOTO
8987d56d374SYoshinobu Inoue /*
8997d56d374SYoshinobu Inoue * Message to users
9007d56d374SYoshinobu Inoue */
901cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)&Dst, Dst.sin6_len, hbuf,
902d24cb249SHajimu UMEMOTO sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
90333841545SHajimu UMEMOTO strlcpy(hbuf, "(invalid)", sizeof(hbuf));
904c449e284SHajimu UMEMOTO fprintf(stderr, "traceroute6");
905c449e284SHajimu UMEMOTO fprintf(stderr, " to %s (%s)", hostname, hbuf);
9067d56d374SYoshinobu Inoue if (source)
907c449e284SHajimu UMEMOTO fprintf(stderr, " from %s", source);
90884a1a4cfSHajimu UMEMOTO fprintf(stderr, ", %lu hops max, %lu byte packets\n",
909d55fae02SMichael Tuexen max_hops,
910d55fae02SMichael Tuexen datalen + ((useproto == IPPROTO_UDP) ? sizeof(struct udphdr) : 0));
9117d56d374SYoshinobu Inoue (void) fflush(stderr);
9127d56d374SYoshinobu Inoue
913de68a0daSKris Kennaway if (first_hop > 1)
91484a1a4cfSHajimu UMEMOTO printf("Skipping %lu intermediate hops\n", first_hop - 1);
915de68a0daSKris Kennaway
916cc432e23SMariusz Zaborski if (connect(sndsock, (struct sockaddr *)&Dst,
917cc432e23SMariusz Zaborski sizeof(Dst)) != 0) {
918cc432e23SMariusz Zaborski fprintf(stderr, "connect: %s\n", strerror(errno));
919cc432e23SMariusz Zaborski exit(1);
920cc432e23SMariusz Zaborski }
921cc432e23SMariusz Zaborski
922cc432e23SMariusz Zaborski /*
923cc432e23SMariusz Zaborski * Here we enter capability mode. Further down access to global
924cc432e23SMariusz Zaborski * namespaces (e.g filesystem) is restricted (see capsicum(4)).
925cc432e23SMariusz Zaborski * We must connect(2) our socket before this point.
926cc432e23SMariusz Zaborski */
927cc432e23SMariusz Zaborski if (caph_enter_casper() < 0) {
928cc432e23SMariusz Zaborski fprintf(stderr, "caph_enter_casper: %s\n", strerror(errno));
929cc432e23SMariusz Zaborski exit(1);
930cc432e23SMariusz Zaborski }
931cc432e23SMariusz Zaborski
932cc432e23SMariusz Zaborski cap_rights_init(&rights, CAP_SEND, CAP_SETSOCKOPT);
933cc432e23SMariusz Zaborski if (caph_rights_limit(sndsock, &rights) < 0) {
934cc432e23SMariusz Zaborski fprintf(stderr, "caph_rights_limit sndsock: %s\n",
935cc432e23SMariusz Zaborski strerror(errno));
936cc432e23SMariusz Zaborski exit(1);
937cc432e23SMariusz Zaborski }
9388ff4fc03SMichael Tuexen cap_rights_init(&rights, CAP_RECV, CAP_EVENT);
939b8ae450fSMark Johnston if (caph_rights_limit(rcvsock, &rights) < 0) {
940b8ae450fSMark Johnston fprintf(stderr, "caph_rights_limit rcvsock: %s\n",
941b8ae450fSMark Johnston strerror(errno));
942b8ae450fSMark Johnston exit(1);
943b8ae450fSMark Johnston }
944cc432e23SMariusz Zaborski
9457d56d374SYoshinobu Inoue /*
9467d56d374SYoshinobu Inoue * Main loop
9477d56d374SYoshinobu Inoue */
948de68a0daSKris Kennaway for (hops = first_hop; hops <= max_hops; ++hops) {
9497d56d374SYoshinobu Inoue struct in6_addr lastaddr;
9507d56d374SYoshinobu Inoue int got_there = 0;
951f42640a3SUlrich Spörlein unsigned unreachable = 0;
9527d56d374SYoshinobu Inoue
95384a1a4cfSHajimu UMEMOTO printf("%2lu ", hops);
9547d56d374SYoshinobu Inoue bzero(&lastaddr, sizeof(lastaddr));
9557d56d374SYoshinobu Inoue for (probe = 0; probe < nprobes; ++probe) {
9567d56d374SYoshinobu Inoue int cc;
9577d56d374SYoshinobu Inoue struct timeval t1, t2;
9587d56d374SYoshinobu Inoue
95984a1a4cfSHajimu UMEMOTO (void) gettimeofday(&t1, NULL);
9607d56d374SYoshinobu Inoue send_probe(++seq, hops);
9617d56d374SYoshinobu Inoue while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) {
96284a1a4cfSHajimu UMEMOTO (void) gettimeofday(&t2, NULL);
9630c2218d1SJose Luis Duran if (packet_ok(&rcvmhdr, cc, seq, &type, &code, &ecn)) {
9647d56d374SYoshinobu Inoue if (!IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr,
9657d56d374SYoshinobu Inoue &lastaddr)) {
96659876f93SChristian S.J. Peron if (probe > 0)
96759876f93SChristian S.J. Peron fputs("\n ", stdout);
9687d56d374SYoshinobu Inoue print(&rcvmhdr, cc);
9697d56d374SYoshinobu Inoue lastaddr = Rcv.sin6_addr;
9707d56d374SYoshinobu Inoue }
971c449e284SHajimu UMEMOTO printf(" %.3f ms", deltaT(&t1, &t2));
9720c2218d1SJose Luis Duran if (ecnflag) {
9730c2218d1SJose Luis Duran switch (ecn) {
9740c2218d1SJose Luis Duran case IPTOS_ECN_ECT1:
9750c2218d1SJose Luis Duran printf(" (ecn=passed)");
9760c2218d1SJose Luis Duran break;
9770c2218d1SJose Luis Duran case IPTOS_ECN_NOTECT:
9780c2218d1SJose Luis Duran printf(" (ecn=bleached)");
9790c2218d1SJose Luis Duran break;
9800c2218d1SJose Luis Duran case IPTOS_ECN_CE:
9810c2218d1SJose Luis Duran printf(" (ecn=congested)");
9820c2218d1SJose Luis Duran break;
9830c2218d1SJose Luis Duran default:
9840c2218d1SJose Luis Duran printf(" (ecn=mangled)");
9850c2218d1SJose Luis Duran break;
9860c2218d1SJose Luis Duran }
9870c2218d1SJose Luis Duran }
98864694fdcSMichael Tuexen if (type == ICMP6_DST_UNREACH) {
98964694fdcSMichael Tuexen switch (code) {
9907d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH_NOROUTE:
9917d56d374SYoshinobu Inoue ++unreachable;
992c449e284SHajimu UMEMOTO printf(" !N");
9937d56d374SYoshinobu Inoue break;
9947d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH_ADMIN:
9957d56d374SYoshinobu Inoue ++unreachable;
996c449e284SHajimu UMEMOTO printf(" !P");
9977d56d374SYoshinobu Inoue break;
9987d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH_NOTNEIGHBOR:
9997d56d374SYoshinobu Inoue ++unreachable;
1000c449e284SHajimu UMEMOTO printf(" !S");
10017d56d374SYoshinobu Inoue break;
10027d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH_ADDR:
10037d56d374SYoshinobu Inoue ++unreachable;
1004c449e284SHajimu UMEMOTO printf(" !A");
10057d56d374SYoshinobu Inoue break;
10067d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH_NOPORT:
10077d56d374SYoshinobu Inoue if (rcvhlim >= 0 &&
10087d56d374SYoshinobu Inoue rcvhlim <= 1)
1009c449e284SHajimu UMEMOTO printf(" !");
10107d56d374SYoshinobu Inoue ++got_there;
10117d56d374SYoshinobu Inoue break;
10127d56d374SYoshinobu Inoue }
10131f69b3fbSMichael Tuexen } else if (type == ICMP6_PARAM_PROB &&
10141f69b3fbSMichael Tuexen code == ICMP6_PARAMPROB_NEXTHEADER) {
10151f69b3fbSMichael Tuexen printf(" !H");
10161f69b3fbSMichael Tuexen ++got_there;
101764694fdcSMichael Tuexen } else if (type == ICMP6_ECHO_REPLY) {
101864694fdcSMichael Tuexen if (rcvhlim >= 0 &&
101964694fdcSMichael Tuexen rcvhlim <= 1)
102064694fdcSMichael Tuexen printf(" !");
102164694fdcSMichael Tuexen ++got_there;
102264694fdcSMichael Tuexen }
10237d56d374SYoshinobu Inoue break;
1024161ab37dSHiroki Sato } else if (deltaT(&t1, &t2) > waittime * 1000) {
1025161ab37dSHiroki Sato cc = 0;
1026161ab37dSHiroki Sato break;
10277d56d374SYoshinobu Inoue }
10287d56d374SYoshinobu Inoue }
10297d56d374SYoshinobu Inoue if (cc == 0)
1030c449e284SHajimu UMEMOTO printf(" *");
10317d56d374SYoshinobu Inoue (void) fflush(stdout);
10327d56d374SYoshinobu Inoue }
10337d56d374SYoshinobu Inoue putchar('\n');
10347d56d374SYoshinobu Inoue if (got_there ||
10357d56d374SYoshinobu Inoue (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) {
10367d56d374SYoshinobu Inoue exit(0);
10377d56d374SYoshinobu Inoue }
10387d56d374SYoshinobu Inoue }
1039d429d720SHajimu UMEMOTO if (as_path)
1040d429d720SHajimu UMEMOTO as_shutdown(asn);
10417d56d374SYoshinobu Inoue
10427d56d374SYoshinobu Inoue exit(0);
10437d56d374SYoshinobu Inoue }
10447d56d374SYoshinobu Inoue
10457d56d374SYoshinobu Inoue int
wait_for_reply(int sock,struct msghdr * mhdr)1046aa96470cSMichael Tuexen wait_for_reply(int sock, struct msghdr *mhdr)
10477d56d374SYoshinobu Inoue {
10482a1c5efaSKris Kennaway #ifdef HAVE_POLL
10492a1c5efaSKris Kennaway struct pollfd pfd[1];
10507d56d374SYoshinobu Inoue int cc = 0;
10517d56d374SYoshinobu Inoue
10522a1c5efaSKris Kennaway pfd[0].fd = sock;
10532a1c5efaSKris Kennaway pfd[0].events = POLLIN;
10542a1c5efaSKris Kennaway pfd[0].revents = 0;
10557d56d374SYoshinobu Inoue
10568ff4fc03SMichael Tuexen if (poll(pfd, 1, waittime * 1000) > 0 &&
10578ff4fc03SMichael Tuexen pfd[0].revents & POLLIN)
10587d56d374SYoshinobu Inoue cc = recvmsg(rcvsock, mhdr, 0);
10597d56d374SYoshinobu Inoue
10607d56d374SYoshinobu Inoue return (cc);
10612a1c5efaSKris Kennaway #else
10622a1c5efaSKris Kennaway fd_set *fdsp;
10632a1c5efaSKris Kennaway struct timeval wait;
10642a1c5efaSKris Kennaway int cc = 0, fdsn;
10652a1c5efaSKris Kennaway
10662a1c5efaSKris Kennaway fdsn = howmany(sock + 1, NFDBITS) * sizeof(fd_mask);
10672a1c5efaSKris Kennaway if ((fdsp = (fd_set *)malloc(fdsn)) == NULL)
10682a1c5efaSKris Kennaway err(1, "malloc");
10692a1c5efaSKris Kennaway memset(fdsp, 0, fdsn);
10702a1c5efaSKris Kennaway FD_SET(sock, fdsp);
10712a1c5efaSKris Kennaway wait.tv_sec = waittime; wait.tv_usec = 0;
10722a1c5efaSKris Kennaway
10732a1c5efaSKris Kennaway if (select(sock + 1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0)
10742a1c5efaSKris Kennaway cc = recvmsg(rcvsock, mhdr, 0);
10752a1c5efaSKris Kennaway
10762a1c5efaSKris Kennaway free(fdsp);
10772a1c5efaSKris Kennaway return (cc);
10782a1c5efaSKris Kennaway #endif
10797d56d374SYoshinobu Inoue }
10807d56d374SYoshinobu Inoue
1081ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
10827d56d374SYoshinobu Inoue int
setpolicy(int so,char * policy)1083ca19d0d7SMark Johnston setpolicy(int so, char *policy)
10847d56d374SYoshinobu Inoue {
10857d56d374SYoshinobu Inoue char *buf;
10867d56d374SYoshinobu Inoue
10877d56d374SYoshinobu Inoue buf = ipsec_set_policy(policy, strlen(policy));
10887d56d374SYoshinobu Inoue if (buf == NULL) {
1089de68a0daSKris Kennaway warnx("%s", ipsec_strerror());
1090777e494aSJose Luis Duran return (-1);
10917d56d374SYoshinobu Inoue }
10927d56d374SYoshinobu Inoue (void)setsockopt(so, IPPROTO_IPV6, IPV6_IPSEC_POLICY,
10937d56d374SYoshinobu Inoue buf, ipsec_get_policylen(buf));
10947d56d374SYoshinobu Inoue
10957d56d374SYoshinobu Inoue free(buf);
10967d56d374SYoshinobu Inoue
1097777e494aSJose Luis Duran return (0);
10987d56d374SYoshinobu Inoue }
10997d56d374SYoshinobu Inoue #endif
11007d56d374SYoshinobu Inoue
11017d56d374SYoshinobu Inoue void
send_probe(int seq,u_long hops)1102aa96470cSMichael Tuexen send_probe(int seq, u_long hops)
11037d56d374SYoshinobu Inoue {
1104d7b63fafSDavid Malone struct icmp6_hdr *icp;
11059d8b46c8SMichael Tuexen struct sctphdr *sctp;
1106cc432e23SMariusz Zaborski struct udphdr *outudp;
11079d8b46c8SMichael Tuexen struct sctp_chunkhdr *chk;
110851eff8efSMichael Tuexen struct sctp_init_chunk *init;
110951eff8efSMichael Tuexen struct sctp_paramhdr *param;
11109d8b46c8SMichael Tuexen struct tcphdr *tcp;
11117d56d374SYoshinobu Inoue int i;
11127d56d374SYoshinobu Inoue
111384a1a4cfSHajimu UMEMOTO i = hops;
11147d56d374SYoshinobu Inoue if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
111584a1a4cfSHajimu UMEMOTO (char *)&i, sizeof(i)) < 0) {
11167d56d374SYoshinobu Inoue perror("setsockopt IPV6_UNICAST_HOPS");
11177d56d374SYoshinobu Inoue }
11187d56d374SYoshinobu Inoue
11197d56d374SYoshinobu Inoue Dst.sin6_port = htons(port + seq);
11207d56d374SYoshinobu Inoue
1121d7b63fafSDavid Malone switch (useproto) {
1122d7b63fafSDavid Malone case IPPROTO_ICMPV6:
1123d7b63fafSDavid Malone icp = (struct icmp6_hdr *)outpacket;
112484a1a4cfSHajimu UMEMOTO
112584a1a4cfSHajimu UMEMOTO icp->icmp6_type = ICMP6_ECHO_REQUEST;
112684a1a4cfSHajimu UMEMOTO icp->icmp6_code = 0;
112784a1a4cfSHajimu UMEMOTO icp->icmp6_cksum = 0;
112884a1a4cfSHajimu UMEMOTO icp->icmp6_id = ident;
112984a1a4cfSHajimu UMEMOTO icp->icmp6_seq = htons(seq);
1130d7b63fafSDavid Malone break;
1131d7b63fafSDavid Malone case IPPROTO_UDP:
1132cc432e23SMariusz Zaborski outudp = (struct udphdr *) outpacket;
1133cc432e23SMariusz Zaborski outudp->uh_sport = htons(ident);
1134cc432e23SMariusz Zaborski outudp->uh_dport = htons(port + seq);
1135cc432e23SMariusz Zaborski outudp->uh_ulen = htons(datalen);
11361d712c05SZhenlei Huang outudp->uh_sum = 0;
1137cc432e23SMariusz Zaborski outudp->uh_sum = udp_cksum(&Src, &Dst, outpacket, datalen);
1138d7b63fafSDavid Malone break;
1139d7b63fafSDavid Malone case IPPROTO_NONE:
1140d7b63fafSDavid Malone /* No space for anything. No harm as seq/tv32 are decorative. */
1141d7b63fafSDavid Malone break;
11429d8b46c8SMichael Tuexen case IPPROTO_SCTP:
11439d8b46c8SMichael Tuexen sctp = (struct sctphdr *)outpacket;
11449d8b46c8SMichael Tuexen
11459d8b46c8SMichael Tuexen sctp->src_port = htons(ident);
11469d8b46c8SMichael Tuexen sctp->dest_port = htons(port + seq);
114751eff8efSMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) +
114851eff8efSMichael Tuexen sizeof(struct sctp_init_chunk))) {
114951eff8efSMichael Tuexen sctp->v_tag = 0;
115051eff8efSMichael Tuexen } else {
11519d8b46c8SMichael Tuexen sctp->v_tag = (sctp->src_port << 16) | sctp->dest_port;
115251eff8efSMichael Tuexen }
11539d8b46c8SMichael Tuexen sctp->checksum = htonl(0);
11549d8b46c8SMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) +
115551eff8efSMichael Tuexen sizeof(struct sctp_init_chunk))) {
115651eff8efSMichael Tuexen /*
115751eff8efSMichael Tuexen * Send a packet containing an INIT chunk. This works
115851eff8efSMichael Tuexen * better in case of firewalls on the path, but
115951eff8efSMichael Tuexen * results in a probe packet containing at least
116051eff8efSMichael Tuexen * 32 bytes of payload. For shorter payloads, use
116151eff8efSMichael Tuexen * SHUTDOWN-ACK chunks.
116251eff8efSMichael Tuexen */
116351eff8efSMichael Tuexen init = (struct sctp_init_chunk *)(sctp + 1);
116451eff8efSMichael Tuexen init->ch.chunk_type = SCTP_INITIATION;
116551eff8efSMichael Tuexen init->ch.chunk_flags = 0;
116651eff8efSMichael Tuexen init->ch.chunk_length = htons((u_int16_t)(datalen -
116751eff8efSMichael Tuexen sizeof(struct sctphdr)));
116851eff8efSMichael Tuexen init->init.initiate_tag = (sctp->src_port << 16) |
116951eff8efSMichael Tuexen sctp->dest_port;
117051eff8efSMichael Tuexen init->init.a_rwnd = htonl(1500);
117151eff8efSMichael Tuexen init->init.num_outbound_streams = htons(1);
117251eff8efSMichael Tuexen init->init.num_inbound_streams = htons(1);
117351eff8efSMichael Tuexen init->init.initial_tsn = htonl(0);
117451eff8efSMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) +
117551eff8efSMichael Tuexen sizeof(struct sctp_init_chunk) +
117651eff8efSMichael Tuexen sizeof(struct sctp_paramhdr))) {
117751eff8efSMichael Tuexen param = (struct sctp_paramhdr *)(init + 1);
117851eff8efSMichael Tuexen param->param_type = htons(SCTP_PAD);
117951eff8efSMichael Tuexen param->param_length =
118051eff8efSMichael Tuexen htons((u_int16_t)(datalen -
118151eff8efSMichael Tuexen sizeof(struct sctphdr) -
118251eff8efSMichael Tuexen sizeof(struct sctp_init_chunk)));
118351eff8efSMichael Tuexen }
118451eff8efSMichael Tuexen } else {
118551eff8efSMichael Tuexen /*
118651eff8efSMichael Tuexen * Send a packet containing a SHUTDOWN-ACK chunk,
118751eff8efSMichael Tuexen * possibly followed by a PAD chunk.
118851eff8efSMichael Tuexen */
118951eff8efSMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) +
11909d8b46c8SMichael Tuexen sizeof(struct sctp_chunkhdr))) {
11919d8b46c8SMichael Tuexen chk = (struct sctp_chunkhdr *)(sctp + 1);
11929d8b46c8SMichael Tuexen chk->chunk_type = SCTP_SHUTDOWN_ACK;
11939d8b46c8SMichael Tuexen chk->chunk_flags = 0;
11949d8b46c8SMichael Tuexen chk->chunk_length = htons(4);
11959d8b46c8SMichael Tuexen }
11969d8b46c8SMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) +
11979d8b46c8SMichael Tuexen 2 * sizeof(struct sctp_chunkhdr))) {
11989d8b46c8SMichael Tuexen chk = chk + 1;
11999d8b46c8SMichael Tuexen chk->chunk_type = SCTP_PAD_CHUNK;
12009d8b46c8SMichael Tuexen chk->chunk_flags = 0;
12019d8b46c8SMichael Tuexen chk->chunk_length = htons((u_int16_t)(datalen -
12029d8b46c8SMichael Tuexen sizeof(struct sctphdr) -
12039d8b46c8SMichael Tuexen sizeof(struct sctp_chunkhdr)));
12049d8b46c8SMichael Tuexen }
120551eff8efSMichael Tuexen }
12069d8b46c8SMichael Tuexen sctp->checksum = sctp_crc32c(outpacket, datalen);
12079d8b46c8SMichael Tuexen break;
12089d8b46c8SMichael Tuexen case IPPROTO_TCP:
12099d8b46c8SMichael Tuexen tcp = (struct tcphdr *)outpacket;
12109d8b46c8SMichael Tuexen
12119d8b46c8SMichael Tuexen tcp->th_sport = htons(ident);
12129d8b46c8SMichael Tuexen tcp->th_dport = htons(port + seq);
12139d8b46c8SMichael Tuexen tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport;
12149d8b46c8SMichael Tuexen tcp->th_ack = 0;
12159d8b46c8SMichael Tuexen tcp->th_off = 5;
1216*0fc7bdc9SRichard Scheffenegger __tcp_set_flags(tcp, TH_SYN);
12179d8b46c8SMichael Tuexen tcp->th_sum = 0;
12189d8b46c8SMichael Tuexen tcp->th_sum = tcp_chksum(&Src, &Dst, outpacket, datalen);
12199d8b46c8SMichael Tuexen break;
1220d7b63fafSDavid Malone default:
1221d7b63fafSDavid Malone fprintf(stderr, "Unknown probe protocol %d.\n", useproto);
1222d7b63fafSDavid Malone exit(1);
122384a1a4cfSHajimu UMEMOTO }
12247d56d374SYoshinobu Inoue
1225cc432e23SMariusz Zaborski i = send(sndsock, (char *)outpacket, datalen, 0);
1226f42640a3SUlrich Spörlein if (i < 0 || (u_long)i != datalen) {
12277d56d374SYoshinobu Inoue if (i < 0)
1228cc432e23SMariusz Zaborski perror("send");
122984a1a4cfSHajimu UMEMOTO printf("traceroute6: wrote %s %lu chars, ret=%d\n",
1230c449e284SHajimu UMEMOTO hostname, datalen, i);
12317d56d374SYoshinobu Inoue (void) fflush(stdout);
12327d56d374SYoshinobu Inoue }
12337d56d374SYoshinobu Inoue }
12347d56d374SYoshinobu Inoue
12357d56d374SYoshinobu Inoue int
get_hoplim(struct msghdr * mhdr)1236aa96470cSMichael Tuexen get_hoplim(struct msghdr *mhdr)
12377d56d374SYoshinobu Inoue {
12387d56d374SYoshinobu Inoue struct cmsghdr *cm;
12397d56d374SYoshinobu Inoue
12407d56d374SYoshinobu Inoue for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
12417d56d374SYoshinobu Inoue cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
12427d56d374SYoshinobu Inoue if (cm->cmsg_level == IPPROTO_IPV6 &&
12437d56d374SYoshinobu Inoue cm->cmsg_type == IPV6_HOPLIMIT &&
12447d56d374SYoshinobu Inoue cm->cmsg_len == CMSG_LEN(sizeof(int)))
12457d56d374SYoshinobu Inoue return (*(int *)CMSG_DATA(cm));
12467d56d374SYoshinobu Inoue }
12477d56d374SYoshinobu Inoue
12487d56d374SYoshinobu Inoue return (-1);
12497d56d374SYoshinobu Inoue }
12507d56d374SYoshinobu Inoue
12517d56d374SYoshinobu Inoue double
deltaT(struct timeval * t1p,struct timeval * t2p)1252aa96470cSMichael Tuexen deltaT(struct timeval *t1p, struct timeval *t2p)
12537d56d374SYoshinobu Inoue {
1254e961704aSDavid Malone double dt;
12557d56d374SYoshinobu Inoue
12567d56d374SYoshinobu Inoue dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
12577d56d374SYoshinobu Inoue (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
12587d56d374SYoshinobu Inoue return (dt);
12597d56d374SYoshinobu Inoue }
12607d56d374SYoshinobu Inoue
12617d56d374SYoshinobu Inoue /*
12627d56d374SYoshinobu Inoue * Convert an ICMP "type" field to a printable string.
12637d56d374SYoshinobu Inoue */
1264f42640a3SUlrich Spörlein const char *
pr_type(int t0)1265f42640a3SUlrich Spörlein pr_type(int t0)
12667d56d374SYoshinobu Inoue {
12677d56d374SYoshinobu Inoue u_char t = t0 & 0xff;
1268f42640a3SUlrich Spörlein const char *cp;
12697d56d374SYoshinobu Inoue
12707d56d374SYoshinobu Inoue switch (t) {
12717d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH:
12727d56d374SYoshinobu Inoue cp = "Destination Unreachable";
12737d56d374SYoshinobu Inoue break;
12747d56d374SYoshinobu Inoue case ICMP6_PACKET_TOO_BIG:
1275c449e284SHajimu UMEMOTO cp = "Packet Too Big";
12767d56d374SYoshinobu Inoue break;
12777d56d374SYoshinobu Inoue case ICMP6_TIME_EXCEEDED:
12787d56d374SYoshinobu Inoue cp = "Time Exceeded";
12797d56d374SYoshinobu Inoue break;
12807d56d374SYoshinobu Inoue case ICMP6_PARAM_PROB:
12817d56d374SYoshinobu Inoue cp = "Parameter Problem";
12827d56d374SYoshinobu Inoue break;
12837d56d374SYoshinobu Inoue case ICMP6_ECHO_REQUEST:
12847d56d374SYoshinobu Inoue cp = "Echo Request";
12857d56d374SYoshinobu Inoue break;
12867d56d374SYoshinobu Inoue case ICMP6_ECHO_REPLY:
12877d56d374SYoshinobu Inoue cp = "Echo Reply";
12887d56d374SYoshinobu Inoue break;
12897d56d374SYoshinobu Inoue case ICMP6_MEMBERSHIP_QUERY:
12907d56d374SYoshinobu Inoue cp = "Group Membership Query";
12917d56d374SYoshinobu Inoue break;
12927d56d374SYoshinobu Inoue case ICMP6_MEMBERSHIP_REPORT:
12937d56d374SYoshinobu Inoue cp = "Group Membership Report";
12947d56d374SYoshinobu Inoue break;
12957d56d374SYoshinobu Inoue case ICMP6_MEMBERSHIP_REDUCTION:
12967d56d374SYoshinobu Inoue cp = "Group Membership Reduction";
12977d56d374SYoshinobu Inoue break;
12987d56d374SYoshinobu Inoue case ND_ROUTER_SOLICIT:
12997d56d374SYoshinobu Inoue cp = "Router Solicitation";
13007d56d374SYoshinobu Inoue break;
13017d56d374SYoshinobu Inoue case ND_ROUTER_ADVERT:
13027d56d374SYoshinobu Inoue cp = "Router Advertisement";
13037d56d374SYoshinobu Inoue break;
13047d56d374SYoshinobu Inoue case ND_NEIGHBOR_SOLICIT:
13057d56d374SYoshinobu Inoue cp = "Neighbor Solicitation";
13067d56d374SYoshinobu Inoue break;
13077d56d374SYoshinobu Inoue case ND_NEIGHBOR_ADVERT:
13087d56d374SYoshinobu Inoue cp = "Neighbor Advertisement";
13097d56d374SYoshinobu Inoue break;
13107d56d374SYoshinobu Inoue case ND_REDIRECT:
1311de68a0daSKris Kennaway cp = "Redirect";
13127d56d374SYoshinobu Inoue break;
13137d56d374SYoshinobu Inoue default:
13147d56d374SYoshinobu Inoue cp = "Unknown";
13157d56d374SYoshinobu Inoue break;
13167d56d374SYoshinobu Inoue }
1317777e494aSJose Luis Duran return (cp);
13187d56d374SYoshinobu Inoue }
13197d56d374SYoshinobu Inoue
13207d56d374SYoshinobu Inoue int
packet_ok(struct msghdr * mhdr,int cc,int seq,u_char * type,u_char * code,u_char * ecn)13210c2218d1SJose Luis Duran packet_ok(struct msghdr *mhdr, int cc, int seq, u_char *type, u_char *code,
13220c2218d1SJose Luis Duran u_char *ecn)
13237d56d374SYoshinobu Inoue {
1324e961704aSDavid Malone struct icmp6_hdr *icp;
13257d56d374SYoshinobu Inoue struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
13267d56d374SYoshinobu Inoue char *buf = (char *)mhdr->msg_iov[0].iov_base;
13277d56d374SYoshinobu Inoue struct cmsghdr *cm;
13287d56d374SYoshinobu Inoue int *hlimp;
1329de68a0daSKris Kennaway char hbuf[NI_MAXHOST];
13307d56d374SYoshinobu Inoue
1331de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1332de68a0daSKris Kennaway int hlen;
1333de68a0daSKris Kennaway struct ip6_hdr *ip;
1334de68a0daSKris Kennaway #endif
1335de68a0daSKris Kennaway
1336de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1337de68a0daSKris Kennaway ip = (struct ip6_hdr *) buf;
1338de68a0daSKris Kennaway hlen = sizeof(struct ip6_hdr);
1339de68a0daSKris Kennaway if (cc < hlen + sizeof(struct icmp6_hdr)) {
1340de68a0daSKris Kennaway if (verbose) {
1341cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len,
1342d24cb249SHajimu UMEMOTO hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
134333841545SHajimu UMEMOTO strlcpy(hbuf, "invalid", sizeof(hbuf));
1344c449e284SHajimu UMEMOTO printf("packet too short (%d bytes) from %s\n", cc,
1345de68a0daSKris Kennaway hbuf);
1346de68a0daSKris Kennaway }
1347de68a0daSKris Kennaway return (0);
1348de68a0daSKris Kennaway }
1349de68a0daSKris Kennaway cc -= hlen;
1350de68a0daSKris Kennaway icp = (struct icmp6_hdr *)(buf + hlen);
1351de68a0daSKris Kennaway #else
1352f42640a3SUlrich Spörlein if (cc < (int)sizeof(struct icmp6_hdr)) {
1353de68a0daSKris Kennaway if (verbose) {
1354cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len,
1355d24cb249SHajimu UMEMOTO hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
135633841545SHajimu UMEMOTO strlcpy(hbuf, "invalid", sizeof(hbuf));
1357c449e284SHajimu UMEMOTO printf("data too short (%d bytes) from %s\n", cc, hbuf);
1358de68a0daSKris Kennaway }
13597d56d374SYoshinobu Inoue return (0);
13607d56d374SYoshinobu Inoue }
13617d56d374SYoshinobu Inoue icp = (struct icmp6_hdr *)buf;
1362de68a0daSKris Kennaway #endif
13637d56d374SYoshinobu Inoue /* get optional information via advanced API */
13647d56d374SYoshinobu Inoue rcvpktinfo = NULL;
13657d56d374SYoshinobu Inoue hlimp = NULL;
13667d56d374SYoshinobu Inoue for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
13677d56d374SYoshinobu Inoue cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
13687d56d374SYoshinobu Inoue if (cm->cmsg_level == IPPROTO_IPV6 &&
13697d56d374SYoshinobu Inoue cm->cmsg_type == IPV6_PKTINFO &&
13707d56d374SYoshinobu Inoue cm->cmsg_len ==
13717d56d374SYoshinobu Inoue CMSG_LEN(sizeof(struct in6_pktinfo)))
13727d56d374SYoshinobu Inoue rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm));
13737d56d374SYoshinobu Inoue
13747d56d374SYoshinobu Inoue if (cm->cmsg_level == IPPROTO_IPV6 &&
13757d56d374SYoshinobu Inoue cm->cmsg_type == IPV6_HOPLIMIT &&
13767d56d374SYoshinobu Inoue cm->cmsg_len == CMSG_LEN(sizeof(int)))
13777d56d374SYoshinobu Inoue hlimp = (int *)CMSG_DATA(cm);
13787d56d374SYoshinobu Inoue }
13797d56d374SYoshinobu Inoue if (rcvpktinfo == NULL || hlimp == NULL) {
13807d56d374SYoshinobu Inoue warnx("failed to get received hop limit or packet info");
1381de68a0daSKris Kennaway #if 0
13827d56d374SYoshinobu Inoue return (0);
1383de68a0daSKris Kennaway #else
1384de68a0daSKris Kennaway rcvhlim = 0; /*XXX*/
1385de68a0daSKris Kennaway #endif
1386777e494aSJose Luis Duran } else
13877d56d374SYoshinobu Inoue rcvhlim = *hlimp;
13887d56d374SYoshinobu Inoue
138964694fdcSMichael Tuexen *type = icp->icmp6_type;
139064694fdcSMichael Tuexen *code = icp->icmp6_code;
139164694fdcSMichael Tuexen if ((*type == ICMP6_TIME_EXCEEDED &&
139264694fdcSMichael Tuexen *code == ICMP6_TIME_EXCEED_TRANSIT) ||
13931f69b3fbSMichael Tuexen (*type == ICMP6_DST_UNREACH) ||
13941f69b3fbSMichael Tuexen (*type == ICMP6_PARAM_PROB &&
13951f69b3fbSMichael Tuexen *code == ICMP6_PARAMPROB_NEXTHEADER)) {
13967d56d374SYoshinobu Inoue struct ip6_hdr *hip;
1397aa96470cSMichael Tuexen struct icmp6_hdr *icmp;
139851eff8efSMichael Tuexen struct sctp_init_chunk *init;
13999d8b46c8SMichael Tuexen struct sctphdr *sctp;
14009d8b46c8SMichael Tuexen struct tcphdr *tcp;
1401aa96470cSMichael Tuexen struct udphdr *udp;
1402d7b63fafSDavid Malone void *up;
14037d56d374SYoshinobu Inoue
14047d56d374SYoshinobu Inoue hip = (struct ip6_hdr *)(icp + 1);
14050c2218d1SJose Luis Duran *ecn = ntohl(hip->ip6_flow & IPV6_ECN_MASK) >> 20;
1406d7b63fafSDavid Malone if ((up = get_uphdr(hip, (u_char *)(buf + cc))) == NULL) {
14077d56d374SYoshinobu Inoue if (verbose)
14087d56d374SYoshinobu Inoue warnx("failed to get upper layer header");
14097d56d374SYoshinobu Inoue return (0);
14107d56d374SYoshinobu Inoue }
1411d7b63fafSDavid Malone switch (useproto) {
1412d7b63fafSDavid Malone case IPPROTO_ICMPV6:
1413aa96470cSMichael Tuexen icmp = (struct icmp6_hdr *)up;
1414aa96470cSMichael Tuexen if (icmp->icmp6_id == ident &&
1415aa96470cSMichael Tuexen icmp->icmp6_seq == htons(seq))
141664694fdcSMichael Tuexen return (1);
1417d7b63fafSDavid Malone break;
1418d7b63fafSDavid Malone case IPPROTO_UDP:
1419aa96470cSMichael Tuexen udp = (struct udphdr *)up;
1420cc432e23SMariusz Zaborski if (udp->uh_sport == htons(ident) &&
1421aa96470cSMichael Tuexen udp->uh_dport == htons(port + seq))
142264694fdcSMichael Tuexen return (1);
1423d7b63fafSDavid Malone break;
14249d8b46c8SMichael Tuexen case IPPROTO_SCTP:
14259d8b46c8SMichael Tuexen sctp = (struct sctphdr *)up;
142651eff8efSMichael Tuexen if (sctp->src_port != htons(ident) ||
142751eff8efSMichael Tuexen sctp->dest_port != htons(port + seq)) {
142851eff8efSMichael Tuexen break;
142951eff8efSMichael Tuexen }
143051eff8efSMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) +
143151eff8efSMichael Tuexen sizeof(struct sctp_init_chunk))) {
143251eff8efSMichael Tuexen if (sctp->v_tag != 0) {
143351eff8efSMichael Tuexen break;
143451eff8efSMichael Tuexen }
143551eff8efSMichael Tuexen init = (struct sctp_init_chunk *)(sctp + 1);
143651eff8efSMichael Tuexen /* Check the initiate tag, if available. */
143751eff8efSMichael Tuexen if ((char *)&init->init.a_rwnd > buf + cc) {
143864694fdcSMichael Tuexen return (1);
143951eff8efSMichael Tuexen }
144051eff8efSMichael Tuexen if (init->init.initiate_tag == (u_int32_t)
144151eff8efSMichael Tuexen ((sctp->src_port << 16) | sctp->dest_port)) {
144264694fdcSMichael Tuexen return (1);
144351eff8efSMichael Tuexen }
144451eff8efSMichael Tuexen } else {
144551eff8efSMichael Tuexen if (sctp->v_tag ==
144651eff8efSMichael Tuexen (u_int32_t)((sctp->src_port << 16) |
144751eff8efSMichael Tuexen sctp->dest_port)) {
144864694fdcSMichael Tuexen return (1);
144951eff8efSMichael Tuexen }
145051eff8efSMichael Tuexen }
14519d8b46c8SMichael Tuexen break;
14529d8b46c8SMichael Tuexen case IPPROTO_TCP:
14539d8b46c8SMichael Tuexen tcp = (struct tcphdr *)up;
14549d8b46c8SMichael Tuexen if (tcp->th_sport == htons(ident) &&
14559d8b46c8SMichael Tuexen tcp->th_dport == htons(port + seq) &&
14569d8b46c8SMichael Tuexen tcp->th_seq ==
14579d8b46c8SMichael Tuexen (tcp_seq)((tcp->th_sport << 16) | tcp->th_dport))
145864694fdcSMichael Tuexen return (1);
14599d8b46c8SMichael Tuexen break;
1460d7b63fafSDavid Malone case IPPROTO_NONE:
146164694fdcSMichael Tuexen return (1);
1462d7b63fafSDavid Malone default:
1463d7b63fafSDavid Malone fprintf(stderr, "Unknown probe proto %d.\n", useproto);
1464d7b63fafSDavid Malone break;
1465d7b63fafSDavid Malone }
146664694fdcSMichael Tuexen } else if (useproto == IPPROTO_ICMPV6 && *type == ICMP6_ECHO_REPLY) {
146784a1a4cfSHajimu UMEMOTO if (icp->icmp6_id == ident &&
146884a1a4cfSHajimu UMEMOTO icp->icmp6_seq == htons(seq))
146964694fdcSMichael Tuexen return (1);
14707d56d374SYoshinobu Inoue }
14717d56d374SYoshinobu Inoue if (verbose) {
1472de68a0daSKris Kennaway char sbuf[NI_MAXHOST + 1], dbuf[INET6_ADDRSTRLEN];
1473e961704aSDavid Malone u_int8_t *p;
1474e961704aSDavid Malone int i;
14757d56d374SYoshinobu Inoue
1476cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len,
1477d24cb249SHajimu UMEMOTO sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0)
1478c449e284SHajimu UMEMOTO strlcpy(sbuf, "invalid", sizeof(sbuf));
1479c449e284SHajimu UMEMOTO printf("\n%d bytes from %s to %s", cc, sbuf,
1480de68a0daSKris Kennaway rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1481c449e284SHajimu UMEMOTO dbuf, sizeof(dbuf)) : "?");
148264694fdcSMichael Tuexen printf(": icmp type %d (%s) code %d\n", *type, pr_type(*type),
148364694fdcSMichael Tuexen *code);
1484de68a0daSKris Kennaway p = (u_int8_t *)(icp + 1);
1485de68a0daSKris Kennaway #define WIDTH 16
1486de68a0daSKris Kennaway for (i = 0; i < cc; i++) {
1487de68a0daSKris Kennaway if (i % WIDTH == 0)
1488c449e284SHajimu UMEMOTO printf("%04x:", i);
1489de68a0daSKris Kennaway if (i % 4 == 0)
1490c449e284SHajimu UMEMOTO printf(" ");
1491c449e284SHajimu UMEMOTO printf("%02x", p[i]);
1492de68a0daSKris Kennaway if (i % WIDTH == WIDTH - 1)
1493c449e284SHajimu UMEMOTO printf("\n");
1494de68a0daSKris Kennaway }
1495de68a0daSKris Kennaway if (cc % WIDTH != 0)
1496c449e284SHajimu UMEMOTO printf("\n");
14977d56d374SYoshinobu Inoue }
14987d56d374SYoshinobu Inoue return (0);
14997d56d374SYoshinobu Inoue }
15007d56d374SYoshinobu Inoue
15017d56d374SYoshinobu Inoue /*
150284a1a4cfSHajimu UMEMOTO * Increment pointer until find the UDP or ICMP header.
15037d56d374SYoshinobu Inoue */
1504d7b63fafSDavid Malone void *
get_uphdr(struct ip6_hdr * ip6,u_char * lim)1505aa96470cSMichael Tuexen get_uphdr(struct ip6_hdr *ip6, u_char *lim)
15067d56d374SYoshinobu Inoue {
15077d56d374SYoshinobu Inoue u_char *cp = (u_char *)ip6, nh;
15087d56d374SYoshinobu Inoue int hlen;
1509d7b63fafSDavid Malone static u_char none_hdr[1]; /* Fake pointer for IPPROTO_NONE. */
15107d56d374SYoshinobu Inoue
1511d7b63fafSDavid Malone if (cp + sizeof(*ip6) > lim)
15127d56d374SYoshinobu Inoue return (NULL);
15137d56d374SYoshinobu Inoue
15147d56d374SYoshinobu Inoue nh = ip6->ip6_nxt;
15157d56d374SYoshinobu Inoue cp += sizeof(struct ip6_hdr);
15167d56d374SYoshinobu Inoue
1517d7b63fafSDavid Malone while (lim - cp >= (nh == IPPROTO_NONE ? 0 : 8)) {
15187d56d374SYoshinobu Inoue switch (nh) {
15197d56d374SYoshinobu Inoue case IPPROTO_ESP:
15207d56d374SYoshinobu Inoue return (NULL);
152184a1a4cfSHajimu UMEMOTO case IPPROTO_ICMPV6:
1522d7b63fafSDavid Malone return (useproto == nh ? cp : NULL);
15239d8b46c8SMichael Tuexen case IPPROTO_SCTP:
15249d8b46c8SMichael Tuexen case IPPROTO_TCP:
15257d56d374SYoshinobu Inoue case IPPROTO_UDP:
1526d7b63fafSDavid Malone return (useproto == nh ? cp : NULL);
1527d7b63fafSDavid Malone case IPPROTO_NONE:
1528d7b63fafSDavid Malone return (useproto == nh ? none_hdr : NULL);
15297d56d374SYoshinobu Inoue case IPPROTO_FRAGMENT:
15307d56d374SYoshinobu Inoue hlen = sizeof(struct ip6_frag);
15317d56d374SYoshinobu Inoue nh = ((struct ip6_frag *)cp)->ip6f_nxt;
15327d56d374SYoshinobu Inoue break;
15337d56d374SYoshinobu Inoue case IPPROTO_AH:
15347d56d374SYoshinobu Inoue hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2;
15357d56d374SYoshinobu Inoue nh = ((struct ip6_ext *)cp)->ip6e_nxt;
15367d56d374SYoshinobu Inoue break;
15377d56d374SYoshinobu Inoue default:
15387d56d374SYoshinobu Inoue hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3;
15397d56d374SYoshinobu Inoue nh = ((struct ip6_ext *)cp)->ip6e_nxt;
15407d56d374SYoshinobu Inoue break;
15417d56d374SYoshinobu Inoue }
15427d56d374SYoshinobu Inoue
15437d56d374SYoshinobu Inoue cp += hlen;
15447d56d374SYoshinobu Inoue }
15457d56d374SYoshinobu Inoue
15467d56d374SYoshinobu Inoue return (NULL);
15477d56d374SYoshinobu Inoue }
15487d56d374SYoshinobu Inoue
15497d56d374SYoshinobu Inoue void
capdns_open(void)15505c3bf25fSAdrian Chadd capdns_open(void)
1551cc432e23SMariusz Zaborski {
15525c3bf25fSAdrian Chadd #ifdef WITH_CASPER
1553cc432e23SMariusz Zaborski const char *types[] = { "NAME", "ADDR" };
1554cc432e23SMariusz Zaborski int families[1];
1555cc432e23SMariusz Zaborski cap_channel_t *casper;
1556cc432e23SMariusz Zaborski
1557cc432e23SMariusz Zaborski casper = cap_init();
1558cc432e23SMariusz Zaborski if (casper == NULL)
1559cc432e23SMariusz Zaborski errx(1, "unable to create casper process");
1560cc432e23SMariusz Zaborski capdns = cap_service_open(casper, "system.dns");
1561cc432e23SMariusz Zaborski if (capdns == NULL)
1562cc432e23SMariusz Zaborski errx(1, "unable to open system.dns service");
1563cc432e23SMariusz Zaborski if (cap_dns_type_limit(capdns, types, nitems(types)) < 0)
1564cc432e23SMariusz Zaborski errx(1, "unable to limit access to system.dns service");
1565cc432e23SMariusz Zaborski families[0] = AF_INET6;
1566cc432e23SMariusz Zaborski if (cap_dns_family_limit(capdns, families, nitems(families)) < 0)
1567cc432e23SMariusz Zaborski errx(1, "unable to limit access to system.dns service");
1568cc432e23SMariusz Zaborski cap_close(casper);
15695c3bf25fSAdrian Chadd #endif /* WITH_CASPER */
1570cc432e23SMariusz Zaborski }
1571cc432e23SMariusz Zaborski
1572cc432e23SMariusz Zaborski void
print(struct msghdr * mhdr,int cc)1573aa96470cSMichael Tuexen print(struct msghdr *mhdr, int cc)
15747d56d374SYoshinobu Inoue {
15757d56d374SYoshinobu Inoue struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
1576de68a0daSKris Kennaway char hbuf[NI_MAXHOST];
15777d56d374SYoshinobu Inoue
1578cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len,
1579d24cb249SHajimu UMEMOTO hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
158033841545SHajimu UMEMOTO strlcpy(hbuf, "invalid", sizeof(hbuf));
1581d429d720SHajimu UMEMOTO if (as_path)
1582d429d720SHajimu UMEMOTO printf(" [AS%u]", as_lookup(asn, hbuf, AF_INET6));
1583de68a0daSKris Kennaway if (nflag)
1584c449e284SHajimu UMEMOTO printf(" %s", hbuf);
1585de68a0daSKris Kennaway else
15860a49be72SLexi Winter printf(" %s (%s)", inetname((struct sockaddr *)from), hbuf);
15877d56d374SYoshinobu Inoue
15887d56d374SYoshinobu Inoue if (verbose) {
1589de68a0daSKris Kennaway #ifdef OLDRAWSOCKET
1590c449e284SHajimu UMEMOTO printf(" %d bytes to %s", cc,
1591de68a0daSKris Kennaway rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1592c449e284SHajimu UMEMOTO hbuf, sizeof(hbuf)) : "?");
1593de68a0daSKris Kennaway #else
1594c449e284SHajimu UMEMOTO printf(" %d bytes of data to %s", cc,
1595de68a0daSKris Kennaway rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
1596c449e284SHajimu UMEMOTO hbuf, sizeof(hbuf)) : "?");
1597de68a0daSKris Kennaway #endif
15987d56d374SYoshinobu Inoue }
15997d56d374SYoshinobu Inoue }
16007d56d374SYoshinobu Inoue
16017d56d374SYoshinobu Inoue /*
16027d56d374SYoshinobu Inoue * Construct an Internet address representation.
16037d56d374SYoshinobu Inoue * If the nflag has been supplied, give
16047d56d374SYoshinobu Inoue * numeric value, otherwise try for symbolic name.
16057d56d374SYoshinobu Inoue */
1606de68a0daSKris Kennaway const char *
inetname(struct sockaddr * sa)1607aa96470cSMichael Tuexen inetname(struct sockaddr *sa)
16087d56d374SYoshinobu Inoue {
1609e961704aSDavid Malone static char line[NI_MAXHOST], domain[MAXHOSTNAMELEN + 1];
16107d56d374SYoshinobu Inoue static int first = 1;
1611e961704aSDavid Malone char *cp;
16127d56d374SYoshinobu Inoue
16137d56d374SYoshinobu Inoue if (first && !nflag) {
16147d56d374SYoshinobu Inoue first = 0;
1615c449e284SHajimu UMEMOTO if (gethostname(domain, sizeof(domain)) == 0 &&
1616c449e284SHajimu UMEMOTO (cp = strchr(domain, '.')))
161733841545SHajimu UMEMOTO (void) strlcpy(domain, cp + 1, sizeof(domain));
16187d56d374SYoshinobu Inoue else
16197d56d374SYoshinobu Inoue domain[0] = 0;
16207d56d374SYoshinobu Inoue }
1621de68a0daSKris Kennaway cp = NULL;
16227d56d374SYoshinobu Inoue if (!nflag) {
1623cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, sa, sa->sa_len, line, sizeof(line), NULL, 0,
1624de68a0daSKris Kennaway NI_NAMEREQD) == 0) {
1625c449e284SHajimu UMEMOTO if ((cp = strchr(line, '.')) &&
16267d56d374SYoshinobu Inoue !strcmp(cp + 1, domain))
16277d56d374SYoshinobu Inoue *cp = 0;
1628de68a0daSKris Kennaway cp = line;
16297d56d374SYoshinobu Inoue }
16307d56d374SYoshinobu Inoue }
16317d56d374SYoshinobu Inoue if (cp)
1632777e494aSJose Luis Duran return (cp);
1633de68a0daSKris Kennaway
1634cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, sa, sa->sa_len, line, sizeof(line), NULL, 0,
1635d24cb249SHajimu UMEMOTO NI_NUMERICHOST) != 0)
163633841545SHajimu UMEMOTO strlcpy(line, "invalid", sizeof(line));
1637777e494aSJose Luis Duran return (line);
16387d56d374SYoshinobu Inoue }
16397d56d374SYoshinobu Inoue
16409d8b46c8SMichael Tuexen /*
16419d8b46c8SMichael Tuexen * CRC32C routine for the Stream Control Transmission Protocol
16429d8b46c8SMichael Tuexen */
16439d8b46c8SMichael Tuexen
16449d8b46c8SMichael Tuexen #define CRC32C(c, d) (c = (c >> 8) ^ crc_c[(c ^ (d)) & 0xFF])
16459d8b46c8SMichael Tuexen
16469d8b46c8SMichael Tuexen static u_int32_t crc_c[256] = {
16479d8b46c8SMichael Tuexen 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
16489d8b46c8SMichael Tuexen 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
16499d8b46c8SMichael Tuexen 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
16509d8b46c8SMichael Tuexen 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
16519d8b46c8SMichael Tuexen 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
16529d8b46c8SMichael Tuexen 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
16539d8b46c8SMichael Tuexen 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
16549d8b46c8SMichael Tuexen 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
16559d8b46c8SMichael Tuexen 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
16569d8b46c8SMichael Tuexen 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
16579d8b46c8SMichael Tuexen 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
16589d8b46c8SMichael Tuexen 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
16599d8b46c8SMichael Tuexen 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
16609d8b46c8SMichael Tuexen 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
16619d8b46c8SMichael Tuexen 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
16629d8b46c8SMichael Tuexen 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
16639d8b46c8SMichael Tuexen 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
16649d8b46c8SMichael Tuexen 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
16659d8b46c8SMichael Tuexen 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
16669d8b46c8SMichael Tuexen 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
16679d8b46c8SMichael Tuexen 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
16689d8b46c8SMichael Tuexen 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
16699d8b46c8SMichael Tuexen 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
16709d8b46c8SMichael Tuexen 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
16719d8b46c8SMichael Tuexen 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
16729d8b46c8SMichael Tuexen 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
16739d8b46c8SMichael Tuexen 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
16749d8b46c8SMichael Tuexen 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
16759d8b46c8SMichael Tuexen 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
16769d8b46c8SMichael Tuexen 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
16779d8b46c8SMichael Tuexen 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
16789d8b46c8SMichael Tuexen 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
16799d8b46c8SMichael Tuexen 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
16809d8b46c8SMichael Tuexen 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
16819d8b46c8SMichael Tuexen 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
16829d8b46c8SMichael Tuexen 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
16839d8b46c8SMichael Tuexen 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
16849d8b46c8SMichael Tuexen 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
16859d8b46c8SMichael Tuexen 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
16869d8b46c8SMichael Tuexen 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
16879d8b46c8SMichael Tuexen 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
16889d8b46c8SMichael Tuexen 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
16899d8b46c8SMichael Tuexen 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
16909d8b46c8SMichael Tuexen 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
16919d8b46c8SMichael Tuexen 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
16929d8b46c8SMichael Tuexen 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
16939d8b46c8SMichael Tuexen 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
16949d8b46c8SMichael Tuexen 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
16959d8b46c8SMichael Tuexen 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
16969d8b46c8SMichael Tuexen 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
16979d8b46c8SMichael Tuexen 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
16989d8b46c8SMichael Tuexen 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
16999d8b46c8SMichael Tuexen 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
17009d8b46c8SMichael Tuexen 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
17019d8b46c8SMichael Tuexen 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
17029d8b46c8SMichael Tuexen 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
17039d8b46c8SMichael Tuexen 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
17049d8b46c8SMichael Tuexen 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
17059d8b46c8SMichael Tuexen 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
17069d8b46c8SMichael Tuexen 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
17079d8b46c8SMichael Tuexen 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
17089d8b46c8SMichael Tuexen 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
17099d8b46c8SMichael Tuexen 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
17109d8b46c8SMichael Tuexen 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
17119d8b46c8SMichael Tuexen };
17129d8b46c8SMichael Tuexen
17139d8b46c8SMichael Tuexen u_int32_t
sctp_crc32c(void * pack,u_int32_t len)1714ca19d0d7SMark Johnston sctp_crc32c(void *pack, u_int32_t len)
17159d8b46c8SMichael Tuexen {
17169d8b46c8SMichael Tuexen u_int32_t i, crc32c;
17179d8b46c8SMichael Tuexen u_int8_t byte0, byte1, byte2, byte3;
1718ca19d0d7SMark Johnston u_int8_t *buf = (u_int8_t *)pack;
17199d8b46c8SMichael Tuexen
17209d8b46c8SMichael Tuexen crc32c = ~0;
17219d8b46c8SMichael Tuexen for (i = 0; i < len; i++)
17229d8b46c8SMichael Tuexen CRC32C(crc32c, buf[i]);
17239d8b46c8SMichael Tuexen crc32c = ~crc32c;
17249d8b46c8SMichael Tuexen byte0 = crc32c & 0xff;
17259d8b46c8SMichael Tuexen byte1 = (crc32c >> 8) & 0xff;
17269d8b46c8SMichael Tuexen byte2 = (crc32c >> 16) & 0xff;
17279d8b46c8SMichael Tuexen byte3 = (crc32c >> 24) & 0xff;
17289d8b46c8SMichael Tuexen crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
1729777e494aSJose Luis Duran return (htonl(crc32c));
17309d8b46c8SMichael Tuexen }
17319d8b46c8SMichael Tuexen
17329d8b46c8SMichael Tuexen u_int16_t
in_cksum(u_int16_t * addr,int len)17339d8b46c8SMichael Tuexen in_cksum(u_int16_t *addr, int len)
17349d8b46c8SMichael Tuexen {
17359d8b46c8SMichael Tuexen int nleft = len;
17369d8b46c8SMichael Tuexen u_int16_t *w = addr;
17379d8b46c8SMichael Tuexen u_int16_t answer;
17389d8b46c8SMichael Tuexen int sum = 0;
17399d8b46c8SMichael Tuexen
17409d8b46c8SMichael Tuexen /*
17419d8b46c8SMichael Tuexen * Our algorithm is simple, using a 32 bit accumulator (sum),
17429d8b46c8SMichael Tuexen * we add sequential 16 bit words to it, and at the end, fold
17439d8b46c8SMichael Tuexen * back all the carry bits from the top 16 bits into the lower
17449d8b46c8SMichael Tuexen * 16 bits.
17459d8b46c8SMichael Tuexen */
17469d8b46c8SMichael Tuexen while (nleft > 1) {
17479d8b46c8SMichael Tuexen sum += *w++;
17489d8b46c8SMichael Tuexen nleft -= 2;
17499d8b46c8SMichael Tuexen }
17509d8b46c8SMichael Tuexen
17519d8b46c8SMichael Tuexen /* mop up an odd byte, if necessary */
17529d8b46c8SMichael Tuexen if (nleft == 1)
17539d8b46c8SMichael Tuexen sum += *(u_char *)w;
17549d8b46c8SMichael Tuexen
17559d8b46c8SMichael Tuexen /*
17569d8b46c8SMichael Tuexen * add back carry outs from top 16 bits to low 16 bits
17579d8b46c8SMichael Tuexen */
17589d8b46c8SMichael Tuexen sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
17599d8b46c8SMichael Tuexen sum += (sum >> 16); /* add carry */
17609d8b46c8SMichael Tuexen answer = ~sum; /* truncate to 16 bits */
17619d8b46c8SMichael Tuexen return (answer);
17629d8b46c8SMichael Tuexen }
17639d8b46c8SMichael Tuexen
17649d8b46c8SMichael Tuexen u_int16_t
udp_cksum(struct sockaddr_in6 * src,struct sockaddr_in6 * dst,void * payload,u_int32_t len)1765cc432e23SMariusz Zaborski udp_cksum(struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
1766cc432e23SMariusz Zaborski void *payload, u_int32_t len)
1767cc432e23SMariusz Zaborski {
1768cc432e23SMariusz Zaborski struct {
1769cc432e23SMariusz Zaborski struct in6_addr src;
1770cc432e23SMariusz Zaborski struct in6_addr dst;
1771cc432e23SMariusz Zaborski u_int32_t len;
1772cc432e23SMariusz Zaborski u_int8_t zero[3];
1773cc432e23SMariusz Zaborski u_int8_t next;
1774cc432e23SMariusz Zaborski } pseudo_hdr;
1775cc432e23SMariusz Zaborski u_int16_t sum[2];
1776cc432e23SMariusz Zaborski
1777cc432e23SMariusz Zaborski pseudo_hdr.src = src->sin6_addr;
1778cc432e23SMariusz Zaborski pseudo_hdr.dst = dst->sin6_addr;
1779cc432e23SMariusz Zaborski pseudo_hdr.len = htonl(len);
1780cc432e23SMariusz Zaborski pseudo_hdr.zero[0] = 0;
1781cc432e23SMariusz Zaborski pseudo_hdr.zero[1] = 0;
1782cc432e23SMariusz Zaborski pseudo_hdr.zero[2] = 0;
1783cc432e23SMariusz Zaborski pseudo_hdr.next = IPPROTO_UDP;
1784cc432e23SMariusz Zaborski
1785cc432e23SMariusz Zaborski sum[1] = in_cksum((u_int16_t *)&pseudo_hdr, sizeof(pseudo_hdr));
1786cc432e23SMariusz Zaborski sum[0] = in_cksum(payload, len);
1787cc432e23SMariusz Zaborski
1788cc432e23SMariusz Zaborski return (~in_cksum(sum, sizeof(sum)));
1789cc432e23SMariusz Zaborski }
1790cc432e23SMariusz Zaborski
1791cc432e23SMariusz Zaborski u_int16_t
tcp_chksum(struct sockaddr_in6 * src,struct sockaddr_in6 * dst,void * payload,u_int32_t len)17929d8b46c8SMichael Tuexen tcp_chksum(struct sockaddr_in6 *src, struct sockaddr_in6 *dst,
17939d8b46c8SMichael Tuexen void *payload, u_int32_t len)
17949d8b46c8SMichael Tuexen {
17959d8b46c8SMichael Tuexen struct {
17969d8b46c8SMichael Tuexen struct in6_addr src;
17979d8b46c8SMichael Tuexen struct in6_addr dst;
17989d8b46c8SMichael Tuexen u_int32_t len;
17999d8b46c8SMichael Tuexen u_int8_t zero[3];
18009d8b46c8SMichael Tuexen u_int8_t next;
18019d8b46c8SMichael Tuexen } pseudo_hdr;
18029d8b46c8SMichael Tuexen u_int16_t sum[2];
18039d8b46c8SMichael Tuexen
18049d8b46c8SMichael Tuexen pseudo_hdr.src = src->sin6_addr;
18059d8b46c8SMichael Tuexen pseudo_hdr.dst = dst->sin6_addr;
18069d8b46c8SMichael Tuexen pseudo_hdr.len = htonl(len);
18079d8b46c8SMichael Tuexen pseudo_hdr.zero[0] = 0;
18089d8b46c8SMichael Tuexen pseudo_hdr.zero[1] = 0;
18099d8b46c8SMichael Tuexen pseudo_hdr.zero[2] = 0;
18109d8b46c8SMichael Tuexen pseudo_hdr.next = IPPROTO_TCP;
18119d8b46c8SMichael Tuexen
18129d8b46c8SMichael Tuexen sum[1] = in_cksum((u_int16_t *)&pseudo_hdr, sizeof(pseudo_hdr));
18139d8b46c8SMichael Tuexen sum[0] = in_cksum(payload, len);
18149d8b46c8SMichael Tuexen
18159d8b46c8SMichael Tuexen return (~in_cksum(sum, sizeof(sum)));
18169d8b46c8SMichael Tuexen }
18179d8b46c8SMichael Tuexen
18187d56d374SYoshinobu Inoue void
usage(void)1819aa96470cSMichael Tuexen usage(void)
18207d56d374SYoshinobu Inoue {
182184a1a4cfSHajimu UMEMOTO fprintf(stderr,
1822ba09352bSJose Luis Duran "Usage: traceroute6 [-adEIlnNrSTUv] [-A as_server] [-f firsthop] [-g gateway]\n"
1823ba09352bSJose Luis Duran "\t[-m hoplimit] [-p port] [-q probes] [-s src] [-t tclass]\n"
1824ba09352bSJose Luis Duran "\t[-w waittime] target [datalen]\n");
18257d56d374SYoshinobu Inoue exit(1);
18267d56d374SYoshinobu Inoue }
1827