1e961704aSDavid Malone /* $KAME: traceroute6.c,v 1.68 2004/01/25 11:16:12 suz Exp $ */ 2de68a0daSKris Kennaway 38a16b7a1SPedro F. Giffuni /*- 48a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 58a16b7a1SPedro F. Giffuni * 67d56d374SYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 77d56d374SYoshinobu Inoue * All rights reserved. 87d56d374SYoshinobu Inoue * 97d56d374SYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 107d56d374SYoshinobu Inoue * modification, are permitted provided that the following conditions 117d56d374SYoshinobu Inoue * are met: 127d56d374SYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 137d56d374SYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 147d56d374SYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 157d56d374SYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 167d56d374SYoshinobu Inoue * documentation and/or other materials provided with the distribution. 177d56d374SYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 187d56d374SYoshinobu Inoue * may be used to endorse or promote products derived from this software 197d56d374SYoshinobu Inoue * without specific prior written permission. 207d56d374SYoshinobu Inoue * 217d56d374SYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 227d56d374SYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 237d56d374SYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 247d56d374SYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 257d56d374SYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 267d56d374SYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 277d56d374SYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 287d56d374SYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 297d56d374SYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 307d56d374SYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 317d56d374SYoshinobu Inoue * SUCH DAMAGE. 327d56d374SYoshinobu Inoue */ 337d56d374SYoshinobu Inoue 347d56d374SYoshinobu Inoue /*- 357d56d374SYoshinobu Inoue * Copyright (c) 1990, 1993 367d56d374SYoshinobu Inoue * The Regents of the University of California. All rights reserved. 377d56d374SYoshinobu Inoue * 387d56d374SYoshinobu Inoue * This code is derived from software contributed to Berkeley by 397d56d374SYoshinobu Inoue * Van Jacobson. 407d56d374SYoshinobu Inoue * 417d56d374SYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 427d56d374SYoshinobu Inoue * modification, are permitted provided that the following conditions 437d56d374SYoshinobu Inoue * are met: 447d56d374SYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 457d56d374SYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 467d56d374SYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 477d56d374SYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 487d56d374SYoshinobu Inoue * documentation and/or other materials provided with the distribution. 49fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 507d56d374SYoshinobu Inoue * may be used to endorse or promote products derived from this software 517d56d374SYoshinobu Inoue * without specific prior written permission. 527d56d374SYoshinobu Inoue * 537d56d374SYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 547d56d374SYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 557d56d374SYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 567d56d374SYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 577d56d374SYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 587d56d374SYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 597d56d374SYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 607d56d374SYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 617d56d374SYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 627d56d374SYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 637d56d374SYoshinobu Inoue * SUCH DAMAGE. 647d56d374SYoshinobu Inoue */ 657d56d374SYoshinobu Inoue 667d56d374SYoshinobu Inoue #ifndef lint 67f42640a3SUlrich Spörlein static const char copyright[] = 687d56d374SYoshinobu Inoue "@(#) Copyright (c) 1990, 1993\n\ 697d56d374SYoshinobu Inoue The Regents of the University of California. All rights reserved.\n"; 707d56d374SYoshinobu Inoue #endif /* not lint */ 717d56d374SYoshinobu Inoue 727d56d374SYoshinobu Inoue #ifndef lint 73de68a0daSKris Kennaway #if 0 747d56d374SYoshinobu Inoue static char sccsid[] = "@(#)traceroute.c 8.1 (Berkeley) 6/6/93"; 75de68a0daSKris Kennaway #endif 76de68a0daSKris Kennaway static const char rcsid[] = 77de68a0daSKris Kennaway "$FreeBSD$"; 787d56d374SYoshinobu Inoue #endif /* not lint */ 797d56d374SYoshinobu Inoue 807d56d374SYoshinobu Inoue /* 817d56d374SYoshinobu Inoue * traceroute host - trace the route ip packets follow going to "host". 827d56d374SYoshinobu Inoue * 837d56d374SYoshinobu Inoue * Attempt to trace the route an ip packet would follow to some 847d56d374SYoshinobu Inoue * internet host. We find out intermediate hops by launching probe 857d56d374SYoshinobu Inoue * packets with a small ttl (time to live) then listening for an 867d56d374SYoshinobu Inoue * icmp "time exceeded" reply from a gateway. We start our probes 877d56d374SYoshinobu Inoue * with a ttl of one and increase by one until we get an icmp "port 887d56d374SYoshinobu Inoue * unreachable" (which means we got to "host") or hit a max (which 897d56d374SYoshinobu Inoue * defaults to 30 hops & can be changed with the -m flag). Three 907d56d374SYoshinobu Inoue * probes (change with -q flag) are sent at each ttl setting and a 917d56d374SYoshinobu Inoue * line is printed showing the ttl, address of the gateway and 927d56d374SYoshinobu Inoue * round trip time of each probe. If the probe answers come from 937d56d374SYoshinobu Inoue * different gateways, the address of each responding system will 947d56d374SYoshinobu Inoue * be printed. If there is no response within a 5 sec. timeout 957d56d374SYoshinobu Inoue * interval (changed with the -w flag), a "*" is printed for that 967d56d374SYoshinobu Inoue * probe. 977d56d374SYoshinobu Inoue * 987d56d374SYoshinobu Inoue * Probe packets are UDP format. We don't want the destination 997d56d374SYoshinobu Inoue * host to process them so the destination port is set to an 1007d56d374SYoshinobu Inoue * unlikely value (if some clod on the destination is using that 1017d56d374SYoshinobu Inoue * value, it can be changed with the -p flag). 1027d56d374SYoshinobu Inoue * 1037d56d374SYoshinobu Inoue * A sample use might be: 1047d56d374SYoshinobu Inoue * 1057d56d374SYoshinobu Inoue * [yak 71]% traceroute nis.nsf.net. 1067d56d374SYoshinobu Inoue * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet 1077d56d374SYoshinobu Inoue * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms 1087d56d374SYoshinobu Inoue * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 1097d56d374SYoshinobu Inoue * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 1107d56d374SYoshinobu Inoue * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms 1117d56d374SYoshinobu Inoue * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms 1127d56d374SYoshinobu Inoue * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms 1137d56d374SYoshinobu Inoue * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms 1147d56d374SYoshinobu Inoue * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms 1157d56d374SYoshinobu Inoue * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms 1167d56d374SYoshinobu Inoue * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms 1177d56d374SYoshinobu Inoue * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms 1187d56d374SYoshinobu Inoue * 1197d56d374SYoshinobu Inoue * Note that lines 2 & 3 are the same. This is due to a buggy 1207d56d374SYoshinobu Inoue * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards 1217d56d374SYoshinobu Inoue * packets with a zero ttl. 1227d56d374SYoshinobu Inoue * 1237d56d374SYoshinobu Inoue * A more interesting example is: 1247d56d374SYoshinobu Inoue * 1257d56d374SYoshinobu Inoue * [yak 72]% traceroute allspice.lcs.mit.edu. 1267d56d374SYoshinobu Inoue * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max 1277d56d374SYoshinobu Inoue * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 1287d56d374SYoshinobu Inoue * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms 1297d56d374SYoshinobu Inoue * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms 1307d56d374SYoshinobu Inoue * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms 1317d56d374SYoshinobu Inoue * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms 1327d56d374SYoshinobu Inoue * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms 1337d56d374SYoshinobu Inoue * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms 1347d56d374SYoshinobu Inoue * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms 1357d56d374SYoshinobu Inoue * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms 1367d56d374SYoshinobu Inoue * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms 1377d56d374SYoshinobu Inoue * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms 1387d56d374SYoshinobu Inoue * 12 * * * 1397d56d374SYoshinobu Inoue * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms 1407d56d374SYoshinobu Inoue * 14 * * * 1417d56d374SYoshinobu Inoue * 15 * * * 1427d56d374SYoshinobu Inoue * 16 * * * 1437d56d374SYoshinobu Inoue * 17 * * * 1447d56d374SYoshinobu Inoue * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms 1457d56d374SYoshinobu Inoue * 1467d56d374SYoshinobu Inoue * (I start to see why I'm having so much trouble with mail to 1477d56d374SYoshinobu Inoue * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away 1487d56d374SYoshinobu Inoue * either don't send ICMP "time exceeded" messages or send them 1497d56d374SYoshinobu Inoue * with a ttl too small to reach us. 14 - 17 are running the 1507d56d374SYoshinobu Inoue * MIT C Gateway code that doesn't send "time exceeded"s. God 1517d56d374SYoshinobu Inoue * only knows what's going on with 12. 1527d56d374SYoshinobu Inoue * 1537d56d374SYoshinobu Inoue * The silent gateway 12 in the above may be the result of a bug in 1547d56d374SYoshinobu Inoue * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) 1557d56d374SYoshinobu Inoue * sends an unreachable message using whatever ttl remains in the 1567d56d374SYoshinobu Inoue * original datagram. Since, for gateways, the remaining ttl is 1577d56d374SYoshinobu Inoue * zero, the icmp "time exceeded" is guaranteed to not make it back 1587d56d374SYoshinobu Inoue * to us. The behavior of this bug is slightly more interesting 1597d56d374SYoshinobu Inoue * when it appears on the destination system: 1607d56d374SYoshinobu Inoue * 1617d56d374SYoshinobu Inoue * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 1627d56d374SYoshinobu Inoue * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms 1637d56d374SYoshinobu Inoue * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms 1647d56d374SYoshinobu Inoue * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms 1657d56d374SYoshinobu Inoue * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms 1667d56d374SYoshinobu Inoue * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms 1677d56d374SYoshinobu Inoue * 7 * * * 1687d56d374SYoshinobu Inoue * 8 * * * 1697d56d374SYoshinobu Inoue * 9 * * * 1707d56d374SYoshinobu Inoue * 10 * * * 1717d56d374SYoshinobu Inoue * 11 * * * 1727d56d374SYoshinobu Inoue * 12 * * * 1737d56d374SYoshinobu Inoue * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! 1747d56d374SYoshinobu Inoue * 1757d56d374SYoshinobu Inoue * Notice that there are 12 "gateways" (13 is the final 1767d56d374SYoshinobu Inoue * destination) and exactly the last half of them are "missing". 1777d56d374SYoshinobu Inoue * What's really happening is that rip (a Sun-3 running Sun OS3.5) 1787d56d374SYoshinobu Inoue * is using the ttl from our arriving datagram as the ttl in its 1797d56d374SYoshinobu Inoue * icmp reply. So, the reply will time out on the return path 1807d56d374SYoshinobu Inoue * (with no notice sent to anyone since icmp's aren't sent for 1817d56d374SYoshinobu Inoue * icmp's) until we probe with a ttl that's at least twice the path 1827d56d374SYoshinobu Inoue * length. I.e., rip is really only 7 hops away. A reply that 1837d56d374SYoshinobu Inoue * returns with a ttl of 1 is a clue this problem exists. 1847d56d374SYoshinobu Inoue * Traceroute prints a "!" after the time if the ttl is <= 1. 1857d56d374SYoshinobu Inoue * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or 1867d56d374SYoshinobu Inoue * non-standard (HPUX) software, expect to see this problem 1877d56d374SYoshinobu Inoue * frequently and/or take care picking the target host of your 1887d56d374SYoshinobu Inoue * probes. 1897d56d374SYoshinobu Inoue * 1907d56d374SYoshinobu Inoue * Other possible annotations after the time are !H, !N, !P (got a host, 1917d56d374SYoshinobu Inoue * network or protocol unreachable, respectively), !S or !F (source 1927d56d374SYoshinobu Inoue * route failed or fragmentation needed -- neither of these should 1937d56d374SYoshinobu Inoue * ever occur and the associated gateway is busted if you see one). If 1947d56d374SYoshinobu Inoue * almost all the probes result in some kind of unreachable, traceroute 1957d56d374SYoshinobu Inoue * will give up and exit. 1967d56d374SYoshinobu Inoue * 1977d56d374SYoshinobu Inoue * Notes 1987d56d374SYoshinobu Inoue * ----- 1997d56d374SYoshinobu Inoue * This program must be run by root or be setuid. (I suggest that 2007d56d374SYoshinobu Inoue * you *don't* make it setuid -- casual use could result in a lot 2017d56d374SYoshinobu Inoue * of unnecessary traffic on our poor, congested nets.) 2027d56d374SYoshinobu Inoue * 2037d56d374SYoshinobu Inoue * This program requires a kernel mod that does not appear in any 2047d56d374SYoshinobu Inoue * system available from Berkeley: A raw ip socket using proto 2057d56d374SYoshinobu Inoue * IPPROTO_RAW must interpret the data sent as an ip datagram (as 2069d5abbddSJens Schweikhardt * opposed to data to be wrapped in an ip datagram). See the README 2077d56d374SYoshinobu Inoue * file that came with the source to this program for a description 2087d56d374SYoshinobu Inoue * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may 2097d56d374SYoshinobu Inoue * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE 2107d56d374SYoshinobu Inoue * MODIFIED TO RUN THIS PROGRAM. 2117d56d374SYoshinobu Inoue * 2127d56d374SYoshinobu Inoue * The udp port usage may appear bizarre (well, ok, it is bizarre). 2137d56d374SYoshinobu Inoue * The problem is that an icmp message only contains 8 bytes of 2147d56d374SYoshinobu Inoue * data from the original datagram. 8 bytes is the size of a udp 2157d56d374SYoshinobu Inoue * header so, if we want to associate replies with the original 2167d56d374SYoshinobu Inoue * datagram, the necessary information must be encoded into the 2177d56d374SYoshinobu Inoue * udp header (the ip id could be used but there's no way to 2187d56d374SYoshinobu Inoue * interlock with the kernel's assignment of ip id's and, anyway, 2197d56d374SYoshinobu Inoue * it would have taken a lot more kernel hacking to allow this 2207d56d374SYoshinobu Inoue * code to set the ip id). So, to allow two or more users to 2217d56d374SYoshinobu Inoue * use traceroute simultaneously, we use this task's pid as the 2227d56d374SYoshinobu Inoue * source port (the high bit is set to move the port number out 2237d56d374SYoshinobu Inoue * of the "likely" range). To keep track of which probe is being 2247d56d374SYoshinobu Inoue * replied to (so times and/or hop counts don't get confused by a 2257d56d374SYoshinobu Inoue * reply that was delayed in transit), we increment the destination 2267d56d374SYoshinobu Inoue * port number before each probe. 2277d56d374SYoshinobu Inoue * 2287d56d374SYoshinobu Inoue * Don't use this as a coding example. I was trying to find a 2297d56d374SYoshinobu Inoue * routing problem and this code sort-of popped out after 48 hours 2307d56d374SYoshinobu Inoue * without sleep. I was amazed it ever compiled, much less ran. 2317d56d374SYoshinobu Inoue * 2327d56d374SYoshinobu Inoue * I stole the idea for this program from Steve Deering. Since 2337d56d374SYoshinobu Inoue * the first release, I've learned that had I attended the right 2347d56d374SYoshinobu Inoue * IETF working group meetings, I also could have stolen it from Guy 2357d56d374SYoshinobu Inoue * Almes or Matt Mathis. I don't know (or care) who came up with 2367d56d374SYoshinobu Inoue * the idea first. I envy the originators' perspicacity and I'm 2377d56d374SYoshinobu Inoue * glad they didn't keep the idea a secret. 2387d56d374SYoshinobu Inoue * 2397d56d374SYoshinobu Inoue * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or 2407d56d374SYoshinobu Inoue * enhancements to the original distribution. 2417d56d374SYoshinobu Inoue * 2427d56d374SYoshinobu Inoue * I've hacked up a round-trip-route version of this that works by 2437d56d374SYoshinobu Inoue * sending a loose-source-routed udp datagram through the destination 2447d56d374SYoshinobu Inoue * back to yourself. Unfortunately, SO many gateways botch source 2457d56d374SYoshinobu Inoue * routing, the thing is almost worthless. Maybe one day... 2467d56d374SYoshinobu Inoue * 2477d56d374SYoshinobu Inoue * -- Van Jacobson (van@helios.ee.lbl.gov) 2487d56d374SYoshinobu Inoue * Tue Dec 20 03:50:13 PST 1988 2497d56d374SYoshinobu Inoue */ 2507d56d374SYoshinobu Inoue 2517d56d374SYoshinobu Inoue #include <sys/param.h> 252cc432e23SMariusz Zaborski #include <sys/capsicum.h> 2537d56d374SYoshinobu Inoue #include <sys/time.h> 2547d56d374SYoshinobu Inoue #include <sys/socket.h> 2557d56d374SYoshinobu Inoue #include <sys/uio.h> 2567d56d374SYoshinobu Inoue #include <sys/file.h> 2577d56d374SYoshinobu Inoue #include <sys/ioctl.h> 25884a1a4cfSHajimu UMEMOTO #include <sys/sysctl.h> 2597d56d374SYoshinobu Inoue 2607d56d374SYoshinobu Inoue #include <netinet/in.h> 2617d56d374SYoshinobu Inoue 2627d56d374SYoshinobu Inoue #include <arpa/inet.h> 2637d56d374SYoshinobu Inoue 264cc432e23SMariusz Zaborski #include <libcasper.h> 265cc432e23SMariusz Zaborski #include <casper/cap_dns.h> 266cc432e23SMariusz Zaborski #include <capsicum_helpers.h> 267cc432e23SMariusz Zaborski 2687d56d374SYoshinobu Inoue #include <netdb.h> 2697d56d374SYoshinobu Inoue #include <stdio.h> 2707d56d374SYoshinobu Inoue #include <err.h> 2712a1c5efaSKris Kennaway #ifdef HAVE_POLL 2722a1c5efaSKris Kennaway #include <poll.h> 2732a1c5efaSKris Kennaway #endif 2747d56d374SYoshinobu Inoue #include <errno.h> 2757d56d374SYoshinobu Inoue #include <stdlib.h> 2767d56d374SYoshinobu Inoue #include <string.h> 2777d56d374SYoshinobu Inoue #include <unistd.h> 2787d56d374SYoshinobu Inoue 2797d56d374SYoshinobu Inoue #include <netinet/ip6.h> 2807d56d374SYoshinobu Inoue #include <netinet/icmp6.h> 2819d8b46c8SMichael Tuexen #include <netinet/sctp.h> 28251eff8efSMichael Tuexen #include <netinet/sctp_header.h> 2839d8b46c8SMichael Tuexen #include <netinet/tcp.h> 2847d56d374SYoshinobu Inoue #include <netinet/udp.h> 2857d56d374SYoshinobu Inoue 2867d56d374SYoshinobu Inoue #ifdef IPSEC 2877d56d374SYoshinobu Inoue #include <net/route.h> 2888409aedfSGeorge V. Neville-Neil #include <netipsec/ipsec.h> 2897d56d374SYoshinobu Inoue #endif 2907d56d374SYoshinobu Inoue 291d429d720SHajimu UMEMOTO #include "as.h" 292d429d720SHajimu UMEMOTO 2937d56d374SYoshinobu Inoue #define DUMMY_PORT 10010 2947d56d374SYoshinobu Inoue 2957d56d374SYoshinobu Inoue #define MAXPACKET 65535 /* max ip packet size */ 2967d56d374SYoshinobu Inoue 297ca19d0d7SMark Johnston static u_char packet[512]; /* last inbound (icmp) packet */ 298ca19d0d7SMark Johnston static char *outpacket; /* last output packet */ 2997d56d374SYoshinobu Inoue 300784bddbcSKevin Lo int main(int, char *[]); 301784bddbcSKevin Lo int wait_for_reply(int, struct msghdr *); 302ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 303784bddbcSKevin Lo int setpolicy(int so, char *policy); 304de68a0daSKris Kennaway #endif 305784bddbcSKevin Lo void send_probe(int, u_long); 306d7b63fafSDavid Malone void *get_uphdr(struct ip6_hdr *, u_char *); 307cc432e23SMariusz Zaborski void capdns_open(void); 308784bddbcSKevin Lo int get_hoplim(struct msghdr *); 309784bddbcSKevin Lo double deltaT(struct timeval *, struct timeval *); 310f42640a3SUlrich Spörlein const char *pr_type(int); 31164694fdcSMichael Tuexen int packet_ok(struct msghdr *, int, int, u_char *, u_char *); 312784bddbcSKevin Lo void print(struct msghdr *, int); 313784bddbcSKevin Lo const char *inetname(struct sockaddr *); 3149d8b46c8SMichael Tuexen u_int32_t sctp_crc32c(void *, u_int32_t); 3159d8b46c8SMichael Tuexen u_int16_t in_cksum(u_int16_t *addr, int); 316cc432e23SMariusz Zaborski u_int16_t udp_cksum(struct sockaddr_in6 *, struct sockaddr_in6 *, 317cc432e23SMariusz Zaborski void *, u_int32_t); 3189d8b46c8SMichael Tuexen u_int16_t tcp_chksum(struct sockaddr_in6 *, struct sockaddr_in6 *, 3199d8b46c8SMichael Tuexen void *, u_int32_t); 320784bddbcSKevin Lo void usage(void); 3217d56d374SYoshinobu Inoue 322ca19d0d7SMark Johnston static int rcvsock; /* receive (icmp) socket file descriptor */ 323ca19d0d7SMark Johnston static int sndsock; /* send (raw/udp) socket file descriptor */ 3247d56d374SYoshinobu Inoue 325ca19d0d7SMark Johnston static struct msghdr rcvmhdr; 326ca19d0d7SMark Johnston static struct iovec rcviov[2]; 327ca19d0d7SMark Johnston static int rcvhlim; 328ca19d0d7SMark Johnston static struct in6_pktinfo *rcvpktinfo; 3297d56d374SYoshinobu Inoue 330ca19d0d7SMark Johnston static struct sockaddr_in6 Src, Dst, Rcv; 331ca19d0d7SMark Johnston static u_long datalen = 20; /* How much data */ 33284a1a4cfSHajimu UMEMOTO #define ICMP6ECHOLEN 8 333de68a0daSKris Kennaway /* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */ 334ca19d0d7SMark Johnston static char rtbuf[2064]; 335ca19d0d7SMark Johnston static struct ip6_rthdr *rth; 336ca19d0d7SMark Johnston static struct cmsghdr *cmsg; 3377d56d374SYoshinobu Inoue 338ca19d0d7SMark Johnston static char *source = NULL; 339ca19d0d7SMark Johnston static char *hostname; 3407d56d374SYoshinobu Inoue 341cc432e23SMariusz Zaborski static cap_channel_t *capdns; 342cc432e23SMariusz Zaborski 343ca19d0d7SMark Johnston static u_long nprobes = 3; 344ca19d0d7SMark Johnston static u_long first_hop = 1; 345ca19d0d7SMark Johnston static u_long max_hops = 30; 346ca19d0d7SMark Johnston static u_int16_t srcport; 347ca19d0d7SMark Johnston static u_int16_t port = 32768+666; /* start udp dest port # for probe packets */ 348ca19d0d7SMark Johnston static u_int16_t ident; 349ca19d0d7SMark Johnston static int options; /* socket options */ 350ca19d0d7SMark Johnston static int verbose; 351ca19d0d7SMark Johnston static int waittime = 5; /* time to wait for response (in seconds) */ 352ca19d0d7SMark Johnston static int nflag; /* print addresses numerically */ 353ca19d0d7SMark Johnston static int useproto = IPPROTO_UDP; /* protocol to use to send packet */ 354ca19d0d7SMark Johnston static int lflag; /* print both numerical address & hostname */ 355ca19d0d7SMark Johnston static int as_path; /* print as numbers for each hop */ 356ca19d0d7SMark Johnston static char *as_server = NULL; 357ca19d0d7SMark Johnston static void *asn; 3587d56d374SYoshinobu Inoue 3597d56d374SYoshinobu Inoue int 360aa96470cSMichael Tuexen main(int argc, char *argv[]) 3617d56d374SYoshinobu Inoue { 36284a1a4cfSHajimu UMEMOTO int mib[4] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM }; 363e961704aSDavid Malone char hbuf[NI_MAXHOST], src0[NI_MAXHOST], *ep; 364f42640a3SUlrich Spörlein int ch, i, on = 1, seq, rcvcmsglen, error; 365e961704aSDavid Malone struct addrinfo hints, *res; 366e961704aSDavid Malone static u_char *rcvcmsgbuf; 367e961704aSDavid Malone u_long probe, hops, lport; 368e961704aSDavid Malone struct hostent *hp; 369f42640a3SUlrich Spörlein size_t size, minlen; 37019c7ed84SKevin Lo uid_t uid; 37164694fdcSMichael Tuexen u_char type, code; 372ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 373ca19d0d7SMark Johnston char ipsec_inpolicy[] = "in bypass"; 374ca19d0d7SMark Johnston char ipsec_outpolicy[] = "out bypass"; 375ca19d0d7SMark Johnston #endif 376cc432e23SMariusz Zaborski cap_rights_t rights; 377cc432e23SMariusz Zaborski 378cc432e23SMariusz Zaborski capdns_open(); 3797d56d374SYoshinobu Inoue 38053c9088fSYoshinobu Inoue /* 38153c9088fSYoshinobu Inoue * Receive ICMP 38253c9088fSYoshinobu Inoue */ 38353c9088fSYoshinobu Inoue if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 384de68a0daSKris Kennaway perror("socket(ICMPv6)"); 38553c9088fSYoshinobu Inoue exit(5); 38653c9088fSYoshinobu Inoue } 387de68a0daSKris Kennaway 38884a1a4cfSHajimu UMEMOTO size = sizeof(i); 38984a1a4cfSHajimu UMEMOTO (void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &i, &size, NULL, 0); 39084a1a4cfSHajimu UMEMOTO max_hops = i; 39184a1a4cfSHajimu UMEMOTO 392de68a0daSKris Kennaway /* specify to tell receiving interface */ 393de68a0daSKris Kennaway #ifdef IPV6_RECVPKTINFO 394de68a0daSKris Kennaway if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 395de68a0daSKris Kennaway sizeof(on)) < 0) 396de68a0daSKris Kennaway err(1, "setsockopt(IPV6_RECVPKTINFO)"); 397de68a0daSKris Kennaway #else /* old adv. API */ 398de68a0daSKris Kennaway if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_PKTINFO, &on, 399de68a0daSKris Kennaway sizeof(on)) < 0) 400de68a0daSKris Kennaway err(1, "setsockopt(IPV6_PKTINFO)"); 401de68a0daSKris Kennaway #endif 402de68a0daSKris Kennaway 403de68a0daSKris Kennaway /* specify to tell value of hoplimit field of received IP6 hdr */ 404de68a0daSKris Kennaway #ifdef IPV6_RECVHOPLIMIT 405de68a0daSKris Kennaway if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, 406de68a0daSKris Kennaway sizeof(on)) < 0) 407de68a0daSKris Kennaway err(1, "setsockopt(IPV6_RECVHOPLIMIT)"); 408de68a0daSKris Kennaway #else /* old adv. API */ 409de68a0daSKris Kennaway if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, 410de68a0daSKris Kennaway sizeof(on)) < 0) 411de68a0daSKris Kennaway err(1, "setsockopt(IPV6_HOPLIMIT)"); 412de68a0daSKris Kennaway #endif 413de68a0daSKris Kennaway 4147d56d374SYoshinobu Inoue seq = 0; 4159d8b46c8SMichael Tuexen ident = htons(getpid() & 0xffff); /* same as ping6 */ 4167d56d374SYoshinobu Inoue 4179d8b46c8SMichael Tuexen while ((ch = getopt(argc, argv, "aA:df:g:Ilm:nNp:q:rs:STUvw:")) != -1) 4187d56d374SYoshinobu Inoue switch (ch) { 419d429d720SHajimu UMEMOTO case 'a': 420d429d720SHajimu UMEMOTO as_path = 1; 421d429d720SHajimu UMEMOTO break; 422d429d720SHajimu UMEMOTO case 'A': 423d429d720SHajimu UMEMOTO as_path = 1; 424d429d720SHajimu UMEMOTO as_server = optarg; 425d429d720SHajimu UMEMOTO break; 4267d56d374SYoshinobu Inoue case 'd': 4277d56d374SYoshinobu Inoue options |= SO_DEBUG; 4287d56d374SYoshinobu Inoue break; 429de68a0daSKris Kennaway case 'f': 43033841545SHajimu UMEMOTO ep = NULL; 43184a1a4cfSHajimu UMEMOTO errno = 0; 43233841545SHajimu UMEMOTO first_hop = strtoul(optarg, &ep, 0); 43384a1a4cfSHajimu UMEMOTO if (errno || !*optarg || *ep || first_hop > 255) { 434c449e284SHajimu UMEMOTO fprintf(stderr, 43533841545SHajimu UMEMOTO "traceroute6: invalid min hoplimit.\n"); 43633841545SHajimu UMEMOTO exit(1); 43733841545SHajimu UMEMOTO } 4387d56d374SYoshinobu Inoue break; 4397d56d374SYoshinobu Inoue case 'g': 440cc432e23SMariusz Zaborski /* XXX use after capability mode is entered */ 4417d56d374SYoshinobu Inoue hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno); 4427d56d374SYoshinobu Inoue if (hp == NULL) { 443c449e284SHajimu UMEMOTO fprintf(stderr, 4447d56d374SYoshinobu Inoue "traceroute6: unknown host %s\n", optarg); 4457d56d374SYoshinobu Inoue exit(1); 4467d56d374SYoshinobu Inoue } 447de68a0daSKris Kennaway if (rth == NULL) { 448de68a0daSKris Kennaway /* 449de68a0daSKris Kennaway * XXX: We can't detect the number of 450de68a0daSKris Kennaway * intermediate nodes yet. 451de68a0daSKris Kennaway */ 452de68a0daSKris Kennaway if ((rth = inet6_rth_init((void *)rtbuf, 453c449e284SHajimu UMEMOTO sizeof(rtbuf), IPV6_RTHDR_TYPE_0, 454de68a0daSKris Kennaway 0)) == NULL) { 455c449e284SHajimu UMEMOTO fprintf(stderr, 456de68a0daSKris Kennaway "inet6_rth_init failed.\n"); 457de68a0daSKris Kennaway exit(1); 458de68a0daSKris Kennaway } 459de68a0daSKris Kennaway } 460de68a0daSKris Kennaway if (inet6_rth_add((void *)rth, 461de68a0daSKris Kennaway (struct in6_addr *)hp->h_addr)) { 462c449e284SHajimu UMEMOTO fprintf(stderr, 463de68a0daSKris Kennaway "inet6_rth_add failed for %s\n", 464de68a0daSKris Kennaway optarg); 465de68a0daSKris Kennaway exit(1); 466de68a0daSKris Kennaway } 467de68a0daSKris Kennaway freehostent(hp); 468de68a0daSKris Kennaway break; 46984a1a4cfSHajimu UMEMOTO case 'I': 470d7b63fafSDavid Malone useproto = IPPROTO_ICMPV6; 47184a1a4cfSHajimu UMEMOTO break; 472de68a0daSKris Kennaway case 'l': 473de68a0daSKris Kennaway lflag++; 4747d56d374SYoshinobu Inoue break; 4757d56d374SYoshinobu Inoue case 'm': 47633841545SHajimu UMEMOTO ep = NULL; 47784a1a4cfSHajimu UMEMOTO errno = 0; 47833841545SHajimu UMEMOTO max_hops = strtoul(optarg, &ep, 0); 47984a1a4cfSHajimu UMEMOTO if (errno || !*optarg || *ep || max_hops > 255) { 480c449e284SHajimu UMEMOTO fprintf(stderr, 48133841545SHajimu UMEMOTO "traceroute6: invalid max hoplimit.\n"); 48233841545SHajimu UMEMOTO exit(1); 48333841545SHajimu UMEMOTO } 4847d56d374SYoshinobu Inoue break; 4857d56d374SYoshinobu Inoue case 'n': 4867d56d374SYoshinobu Inoue nflag++; 4877d56d374SYoshinobu Inoue break; 488d7b63fafSDavid Malone case 'N': 489d7b63fafSDavid Malone useproto = IPPROTO_NONE; 490d7b63fafSDavid Malone break; 4917d56d374SYoshinobu Inoue case 'p': 49233841545SHajimu UMEMOTO ep = NULL; 49384a1a4cfSHajimu UMEMOTO errno = 0; 49484a1a4cfSHajimu UMEMOTO lport = strtoul(optarg, &ep, 0); 49584a1a4cfSHajimu UMEMOTO if (errno || !*optarg || *ep) { 49684a1a4cfSHajimu UMEMOTO fprintf(stderr, "traceroute6: invalid port.\n"); 49733841545SHajimu UMEMOTO exit(1); 49833841545SHajimu UMEMOTO } 49984a1a4cfSHajimu UMEMOTO if (lport == 0 || lport != (lport & 0xffff)) { 500c449e284SHajimu UMEMOTO fprintf(stderr, 50184a1a4cfSHajimu UMEMOTO "traceroute6: port out of range.\n"); 5027d56d374SYoshinobu Inoue exit(1); 5037d56d374SYoshinobu Inoue } 50484a1a4cfSHajimu UMEMOTO port = lport & 0xffff; 5057d56d374SYoshinobu Inoue break; 5067d56d374SYoshinobu Inoue case 'q': 50733841545SHajimu UMEMOTO ep = NULL; 50884a1a4cfSHajimu UMEMOTO errno = 0; 50933841545SHajimu UMEMOTO nprobes = strtoul(optarg, &ep, 0); 51084a1a4cfSHajimu UMEMOTO if (errno || !*optarg || *ep) { 511c449e284SHajimu UMEMOTO fprintf(stderr, 51233841545SHajimu UMEMOTO "traceroute6: invalid nprobes.\n"); 51333841545SHajimu UMEMOTO exit(1); 51433841545SHajimu UMEMOTO } 5157d56d374SYoshinobu Inoue if (nprobes < 1) { 516c449e284SHajimu UMEMOTO fprintf(stderr, 5177d56d374SYoshinobu Inoue "traceroute6: nprobes must be >0.\n"); 5187d56d374SYoshinobu Inoue exit(1); 5197d56d374SYoshinobu Inoue } 5207d56d374SYoshinobu Inoue break; 5217d56d374SYoshinobu Inoue case 'r': 5227d56d374SYoshinobu Inoue options |= SO_DONTROUTE; 5237d56d374SYoshinobu Inoue break; 5247d56d374SYoshinobu Inoue case 's': 5257d56d374SYoshinobu Inoue /* 5267d56d374SYoshinobu Inoue * set the ip source address of the outbound 5277d56d374SYoshinobu Inoue * probe (e.g., on a multi-homed host). 5287d56d374SYoshinobu Inoue */ 5297d56d374SYoshinobu Inoue source = optarg; 5307d56d374SYoshinobu Inoue break; 5319d8b46c8SMichael Tuexen case 'S': 5329d8b46c8SMichael Tuexen useproto = IPPROTO_SCTP; 5339d8b46c8SMichael Tuexen break; 5349d8b46c8SMichael Tuexen case 'T': 5359d8b46c8SMichael Tuexen useproto = IPPROTO_TCP; 5369d8b46c8SMichael Tuexen break; 537d7b63fafSDavid Malone case 'U': 538d7b63fafSDavid Malone useproto = IPPROTO_UDP; 539d7b63fafSDavid Malone break; 540aa96470cSMichael Tuexen case 'v': 541aa96470cSMichael Tuexen verbose++; 542aa96470cSMichael Tuexen break; 5437d56d374SYoshinobu Inoue case 'w': 54433841545SHajimu UMEMOTO ep = NULL; 54584a1a4cfSHajimu UMEMOTO errno = 0; 54633841545SHajimu UMEMOTO waittime = strtoul(optarg, &ep, 0); 54784a1a4cfSHajimu UMEMOTO if (errno || !*optarg || *ep) { 548c449e284SHajimu UMEMOTO fprintf(stderr, 54933841545SHajimu UMEMOTO "traceroute6: invalid wait time.\n"); 55033841545SHajimu UMEMOTO exit(1); 55133841545SHajimu UMEMOTO } 552eea319c4SMaxim Konovalov if (waittime < 1) { 553c449e284SHajimu UMEMOTO fprintf(stderr, 554eea319c4SMaxim Konovalov "traceroute6: wait must be >= 1 sec.\n"); 5557d56d374SYoshinobu Inoue exit(1); 5567d56d374SYoshinobu Inoue } 5577d56d374SYoshinobu Inoue break; 5587d56d374SYoshinobu Inoue default: 5597d56d374SYoshinobu Inoue usage(); 5607d56d374SYoshinobu Inoue } 5617d56d374SYoshinobu Inoue argc -= optind; 5627d56d374SYoshinobu Inoue argv += optind; 5637d56d374SYoshinobu Inoue 564d7b63fafSDavid Malone /* 565d7b63fafSDavid Malone * Open socket to send probe packets. 566d7b63fafSDavid Malone */ 567d7b63fafSDavid Malone switch (useproto) { 568d7b63fafSDavid Malone case IPPROTO_ICMPV6: 569d7b63fafSDavid Malone sndsock = rcvsock; 570d7b63fafSDavid Malone break; 571d7b63fafSDavid Malone case IPPROTO_NONE: 5729d8b46c8SMichael Tuexen case IPPROTO_SCTP: 5739d8b46c8SMichael Tuexen case IPPROTO_TCP: 574*2d0fb1b3SMichael Tuexen case IPPROTO_UDP: 5759d8b46c8SMichael Tuexen if ((sndsock = socket(AF_INET6, SOCK_RAW, useproto)) < 0) { 576d7b63fafSDavid Malone perror("socket(SOCK_RAW)"); 577d7b63fafSDavid Malone exit(5); 578d7b63fafSDavid Malone } 579d7b63fafSDavid Malone break; 580d7b63fafSDavid Malone default: 581aa96470cSMichael Tuexen fprintf(stderr, "traceroute6: unknown probe protocol %d\n", 582d7b63fafSDavid Malone useproto); 583d7b63fafSDavid Malone exit(5); 584d7b63fafSDavid Malone } 58584a1a4cfSHajimu UMEMOTO if (max_hops < first_hop) { 58684a1a4cfSHajimu UMEMOTO fprintf(stderr, 58784a1a4cfSHajimu UMEMOTO "traceroute6: max hoplimit must be larger than first hoplimit.\n"); 58884a1a4cfSHajimu UMEMOTO exit(1); 58984a1a4cfSHajimu UMEMOTO } 59084a1a4cfSHajimu UMEMOTO 591d7b63fafSDavid Malone /* revoke privs */ 592d7b63fafSDavid Malone uid = getuid(); 593d7b63fafSDavid Malone if (setresuid(uid, uid, uid) == -1) { 594d7b63fafSDavid Malone perror("setresuid"); 595d7b63fafSDavid Malone exit(1); 596d7b63fafSDavid Malone } 597d7b63fafSDavid Malone 598d7b63fafSDavid Malone 59933841545SHajimu UMEMOTO if (argc < 1 || argc > 2) 6007d56d374SYoshinobu Inoue usage(); 6017d56d374SYoshinobu Inoue 602de68a0daSKris Kennaway #if 1 6037d56d374SYoshinobu Inoue setvbuf(stdout, NULL, _IOLBF, BUFSIZ); 604de68a0daSKris Kennaway #else 605de68a0daSKris Kennaway setlinebuf(stdout); 606de68a0daSKris Kennaway #endif 6077d56d374SYoshinobu Inoue 60839865d64SYoshinobu Inoue memset(&hints, 0, sizeof(hints)); 60939865d64SYoshinobu Inoue hints.ai_family = PF_INET6; 61039865d64SYoshinobu Inoue hints.ai_socktype = SOCK_RAW; 61139865d64SYoshinobu Inoue hints.ai_protocol = IPPROTO_ICMPV6; 61239865d64SYoshinobu Inoue hints.ai_flags = AI_CANONNAME; 613cc432e23SMariusz Zaborski 614cc432e23SMariusz Zaborski error = cap_getaddrinfo(capdns, *argv, NULL, &hints, &res); 615cc432e23SMariusz Zaborski 61639865d64SYoshinobu Inoue if (error) { 617c449e284SHajimu UMEMOTO fprintf(stderr, 61839865d64SYoshinobu Inoue "traceroute6: %s\n", gai_strerror(error)); 6197d56d374SYoshinobu Inoue exit(1); 6207d56d374SYoshinobu Inoue } 621de68a0daSKris Kennaway if (res->ai_addrlen != sizeof(Dst)) { 622c449e284SHajimu UMEMOTO fprintf(stderr, 623de68a0daSKris Kennaway "traceroute6: size of sockaddr mismatch\n"); 624de68a0daSKris Kennaway exit(1); 625de68a0daSKris Kennaway } 62639865d64SYoshinobu Inoue memcpy(&Dst, res->ai_addr, res->ai_addrlen); 62739865d64SYoshinobu Inoue hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv; 62833841545SHajimu UMEMOTO if (!hostname) { 629c449e284SHajimu UMEMOTO fprintf(stderr, "traceroute6: not enough core\n"); 63033841545SHajimu UMEMOTO exit(1); 63133841545SHajimu UMEMOTO } 63284a1a4cfSHajimu UMEMOTO if (res->ai_next) { 633cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, res->ai_addr, res->ai_addrlen, hbuf, 63484a1a4cfSHajimu UMEMOTO sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 63584a1a4cfSHajimu UMEMOTO strlcpy(hbuf, "?", sizeof(hbuf)); 63684a1a4cfSHajimu UMEMOTO fprintf(stderr, "traceroute6: Warning: %s has multiple " 63784a1a4cfSHajimu UMEMOTO "addresses; using %s\n", hostname, hbuf); 63884a1a4cfSHajimu UMEMOTO } 639ca19d0d7SMark Johnston freeaddrinfo(res); 64033841545SHajimu UMEMOTO if (*++argv) { 64133841545SHajimu UMEMOTO ep = NULL; 64284a1a4cfSHajimu UMEMOTO errno = 0; 64333841545SHajimu UMEMOTO datalen = strtoul(*argv, &ep, 0); 644aa96470cSMichael Tuexen if (errno || *ep) { 645c449e284SHajimu UMEMOTO fprintf(stderr, 64633841545SHajimu UMEMOTO "traceroute6: invalid packet length.\n"); 64733841545SHajimu UMEMOTO exit(1); 64833841545SHajimu UMEMOTO } 64933841545SHajimu UMEMOTO } 650d7b63fafSDavid Malone switch (useproto) { 651d7b63fafSDavid Malone case IPPROTO_ICMPV6: 652aa96470cSMichael Tuexen minlen = ICMP6ECHOLEN; 653d7b63fafSDavid Malone break; 654d7b63fafSDavid Malone case IPPROTO_UDP: 655aa96470cSMichael Tuexen minlen = sizeof(struct udphdr); 656d7b63fafSDavid Malone break; 657d7b63fafSDavid Malone case IPPROTO_NONE: 658d7b63fafSDavid Malone minlen = 0; 659d7b63fafSDavid Malone datalen = 0; 660d7b63fafSDavid Malone break; 6619d8b46c8SMichael Tuexen case IPPROTO_SCTP: 6629d8b46c8SMichael Tuexen minlen = sizeof(struct sctphdr); 6639d8b46c8SMichael Tuexen break; 6649d8b46c8SMichael Tuexen case IPPROTO_TCP: 6659d8b46c8SMichael Tuexen minlen = sizeof(struct tcphdr); 6669d8b46c8SMichael Tuexen break; 667d7b63fafSDavid Malone default: 668d7b63fafSDavid Malone fprintf(stderr, "traceroute6: unknown probe protocol %d.\n", 669d7b63fafSDavid Malone useproto); 670d7b63fafSDavid Malone exit(1); 671d7b63fafSDavid Malone } 67284a1a4cfSHajimu UMEMOTO if (datalen < minlen) 67384a1a4cfSHajimu UMEMOTO datalen = minlen; 67484a1a4cfSHajimu UMEMOTO else if (datalen >= MAXPACKET) { 675c449e284SHajimu UMEMOTO fprintf(stderr, 676f42640a3SUlrich Spörlein "traceroute6: packet size must be %zu <= s < %d.\n", 677f42640a3SUlrich Spörlein minlen, MAXPACKET); 6787d56d374SYoshinobu Inoue exit(1); 6797d56d374SYoshinobu Inoue } 680aa96470cSMichael Tuexen if (useproto == IPPROTO_UDP) 681aa96470cSMichael Tuexen datalen -= sizeof(struct udphdr); 68251eff8efSMichael Tuexen if ((useproto == IPPROTO_SCTP) && (datalen & 3)) { 68351eff8efSMichael Tuexen fprintf(stderr, 68451eff8efSMichael Tuexen "traceroute6: packet size must be a multiple of 4.\n"); 68551eff8efSMichael Tuexen exit(1); 68651eff8efSMichael Tuexen } 687f42640a3SUlrich Spörlein outpacket = malloc(datalen); 6887d56d374SYoshinobu Inoue if (!outpacket) { 689de68a0daSKris Kennaway perror("malloc"); 6907d56d374SYoshinobu Inoue exit(1); 6917d56d374SYoshinobu Inoue } 6927d56d374SYoshinobu Inoue (void) bzero((char *)outpacket, datalen); 6937d56d374SYoshinobu Inoue 6947d56d374SYoshinobu Inoue /* initialize msghdr for receiving packets */ 6957d56d374SYoshinobu Inoue rcviov[0].iov_base = (caddr_t)packet; 6967d56d374SYoshinobu Inoue rcviov[0].iov_len = sizeof(packet); 697de68a0daSKris Kennaway rcvmhdr.msg_name = (caddr_t)&Rcv; 698de68a0daSKris Kennaway rcvmhdr.msg_namelen = sizeof(Rcv); 6997d56d374SYoshinobu Inoue rcvmhdr.msg_iov = rcviov; 7007d56d374SYoshinobu Inoue rcvmhdr.msg_iovlen = 1; 701e961704aSDavid Malone rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 702e961704aSDavid Malone CMSG_SPACE(sizeof(int)); 703de68a0daSKris Kennaway if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) { 704c449e284SHajimu UMEMOTO fprintf(stderr, "traceroute6: malloc failed\n"); 705de68a0daSKris Kennaway exit(1); 706de68a0daSKris Kennaway } 7077d56d374SYoshinobu Inoue rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; 708de68a0daSKris Kennaway rcvmhdr.msg_controllen = rcvcmsglen; 7097d56d374SYoshinobu Inoue 7107d56d374SYoshinobu Inoue if (options & SO_DEBUG) 7117d56d374SYoshinobu Inoue (void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, 7127d56d374SYoshinobu Inoue (char *)&on, sizeof(on)); 7137d56d374SYoshinobu Inoue if (options & SO_DONTROUTE) 7147d56d374SYoshinobu Inoue (void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, 7157d56d374SYoshinobu Inoue (char *)&on, sizeof(on)); 716ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 7177d56d374SYoshinobu Inoue /* 7187d56d374SYoshinobu Inoue * do not raise error even if setsockopt fails, kernel may have ipsec 7197d56d374SYoshinobu Inoue * turned off. 7207d56d374SYoshinobu Inoue */ 721ca19d0d7SMark Johnston if (setpolicy(rcvsock, ipsec_inpolicy) < 0) 722d94e8c62SKris Kennaway errx(1, "%s", ipsec_strerror()); 723ca19d0d7SMark Johnston if (setpolicy(rcvsock, ipsec_outpolicy) < 0) 724d94e8c62SKris Kennaway errx(1, "%s", ipsec_strerror()); 725de68a0daSKris Kennaway #else 726de68a0daSKris Kennaway { 727de68a0daSKris Kennaway int level = IPSEC_LEVEL_NONE; 728de68a0daSKris Kennaway 729de68a0daSKris Kennaway (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, 730de68a0daSKris Kennaway sizeof(level)); 731de68a0daSKris Kennaway (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, 732de68a0daSKris Kennaway sizeof(level)); 733de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL 734de68a0daSKris Kennaway (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, 735de68a0daSKris Kennaway sizeof(level)); 736de68a0daSKris Kennaway #else 737de68a0daSKris Kennaway (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, 738de68a0daSKris Kennaway sizeof(level)); 739de68a0daSKris Kennaway #endif 740de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL 741de68a0daSKris Kennaway (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, 742de68a0daSKris Kennaway sizeof(level)); 743de68a0daSKris Kennaway #endif 744de68a0daSKris Kennaway } 745ca19d0d7SMark Johnston #endif /* !(IPSEC && IPSEC_POLICY_IPSEC) */ 7467d56d374SYoshinobu Inoue 747de68a0daSKris Kennaway #ifdef SO_SNDBUF 74884a1a4cfSHajimu UMEMOTO i = datalen; 749aa96470cSMichael Tuexen if (i == 0) 750aa96470cSMichael Tuexen i = 1; 75184a1a4cfSHajimu UMEMOTO if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&i, 752aa96470cSMichael Tuexen sizeof(i)) < 0) { 753de68a0daSKris Kennaway perror("setsockopt(SO_SNDBUF)"); 7547d56d374SYoshinobu Inoue exit(6); 7557d56d374SYoshinobu Inoue } 756de68a0daSKris Kennaway #endif /* SO_SNDBUF */ 7577d56d374SYoshinobu Inoue if (options & SO_DEBUG) 7587d56d374SYoshinobu Inoue (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 7597d56d374SYoshinobu Inoue (char *)&on, sizeof(on)); 7607d56d374SYoshinobu Inoue if (options & SO_DONTROUTE) 7617d56d374SYoshinobu Inoue (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, 7627d56d374SYoshinobu Inoue (char *)&on, sizeof(on)); 763de68a0daSKris Kennaway if (rth) {/* XXX: there is no library to finalize the header... */ 764de68a0daSKris Kennaway rth->ip6r_len = rth->ip6r_segleft * 2; 765de68a0daSKris Kennaway if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR, 766de68a0daSKris Kennaway (void *)rth, (rth->ip6r_len + 1) << 3)) { 767c449e284SHajimu UMEMOTO fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n", 768de68a0daSKris Kennaway strerror(errno)); 769de68a0daSKris Kennaway exit(1); 770de68a0daSKris Kennaway } 771de68a0daSKris Kennaway } 772ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 7737d56d374SYoshinobu Inoue /* 7747d56d374SYoshinobu Inoue * do not raise error even if setsockopt fails, kernel may have ipsec 7757d56d374SYoshinobu Inoue * turned off. 7767d56d374SYoshinobu Inoue */ 777ca19d0d7SMark Johnston if (setpolicy(sndsock, ipsec_inpolicy) < 0) 778d94e8c62SKris Kennaway errx(1, "%s", ipsec_strerror()); 779ca19d0d7SMark Johnston if (setpolicy(sndsock, ipsec_outpolicy) < 0) 780d94e8c62SKris Kennaway errx(1, "%s", ipsec_strerror()); 781de68a0daSKris Kennaway #else 782de68a0daSKris Kennaway { 783de68a0daSKris Kennaway int level = IPSEC_LEVEL_BYPASS; 784de68a0daSKris Kennaway 785de68a0daSKris Kennaway (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, 786de68a0daSKris Kennaway sizeof(level)); 787de68a0daSKris Kennaway (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, 788de68a0daSKris Kennaway sizeof(level)); 789de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL 790de68a0daSKris Kennaway (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, 791de68a0daSKris Kennaway sizeof(level)); 792de68a0daSKris Kennaway #else 793de68a0daSKris Kennaway (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, 794de68a0daSKris Kennaway sizeof(level)); 795de68a0daSKris Kennaway #endif 796de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL 797de68a0daSKris Kennaway (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, 798de68a0daSKris Kennaway sizeof(level)); 799de68a0daSKris Kennaway #endif 800de68a0daSKris Kennaway } 801ca19d0d7SMark Johnston #endif /* !(IPSEC && IPSEC_POLICY_IPSEC) */ 8027d56d374SYoshinobu Inoue 8037d56d374SYoshinobu Inoue /* 8047d56d374SYoshinobu Inoue * Source selection 8057d56d374SYoshinobu Inoue */ 806de68a0daSKris Kennaway bzero(&Src, sizeof(Src)); 8077d56d374SYoshinobu Inoue if (source) { 808de68a0daSKris Kennaway memset(&hints, 0, sizeof(hints)); 809de68a0daSKris Kennaway hints.ai_family = AF_INET6; 810de68a0daSKris Kennaway hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 811de68a0daSKris Kennaway hints.ai_flags = AI_NUMERICHOST; 812cc432e23SMariusz Zaborski error = cap_getaddrinfo(capdns, source, "0", &hints, &res); 813de68a0daSKris Kennaway if (error) { 814c449e284SHajimu UMEMOTO printf("traceroute6: %s: %s\n", source, 815de68a0daSKris Kennaway gai_strerror(error)); 8167d56d374SYoshinobu Inoue exit(1); 8177d56d374SYoshinobu Inoue } 818de68a0daSKris Kennaway if (res->ai_addrlen > sizeof(Src)) { 819c449e284SHajimu UMEMOTO printf("traceroute6: %s: %s\n", source, 820de68a0daSKris Kennaway gai_strerror(error)); 821de68a0daSKris Kennaway exit(1); 822de68a0daSKris Kennaway } 823de68a0daSKris Kennaway memcpy(&Src, res->ai_addr, res->ai_addrlen); 824de68a0daSKris Kennaway freeaddrinfo(res); 8257d56d374SYoshinobu Inoue } else { 8267d56d374SYoshinobu Inoue struct sockaddr_in6 Nxt; 82784a1a4cfSHajimu UMEMOTO int dummy; 82884a1a4cfSHajimu UMEMOTO socklen_t len; 8297d56d374SYoshinobu Inoue 8307d56d374SYoshinobu Inoue Nxt = Dst; 8317d56d374SYoshinobu Inoue Nxt.sin6_port = htons(DUMMY_PORT); 8327d56d374SYoshinobu Inoue if (cmsg != NULL) 8337d56d374SYoshinobu Inoue bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr, 8347d56d374SYoshinobu Inoue sizeof(Nxt.sin6_addr)); 8357d56d374SYoshinobu Inoue if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 8367d56d374SYoshinobu Inoue perror("socket"); 837de68a0daSKris Kennaway exit(1); 8387d56d374SYoshinobu Inoue } 839de68a0daSKris Kennaway if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) { 8407d56d374SYoshinobu Inoue perror("connect"); 841de68a0daSKris Kennaway exit(1); 8427d56d374SYoshinobu Inoue } 843de68a0daSKris Kennaway len = sizeof(Src); 844de68a0daSKris Kennaway if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) { 845de68a0daSKris Kennaway perror("getsockname"); 846de68a0daSKris Kennaway exit(1); 847de68a0daSKris Kennaway } 848cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)&Src, Src.sin6_len, 849d24cb249SHajimu UMEMOTO src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) { 850c449e284SHajimu UMEMOTO fprintf(stderr, "getnameinfo failed for source\n"); 851de68a0daSKris Kennaway exit(1); 852de68a0daSKris Kennaway } 853de68a0daSKris Kennaway source = src0; 8547d56d374SYoshinobu Inoue close(dummy); 8557d56d374SYoshinobu Inoue } 856de68a0daSKris Kennaway 85784a1a4cfSHajimu UMEMOTO Src.sin6_port = htons(0); 858de68a0daSKris Kennaway if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) { 859de68a0daSKris Kennaway perror("bind"); 8607d56d374SYoshinobu Inoue exit(1); 8617d56d374SYoshinobu Inoue } 8627d56d374SYoshinobu Inoue 86384a1a4cfSHajimu UMEMOTO { 864c449e284SHajimu UMEMOTO socklen_t len; 865de68a0daSKris Kennaway 866de68a0daSKris Kennaway len = sizeof(Src); 86784a1a4cfSHajimu UMEMOTO if (getsockname(sndsock, (struct sockaddr *)&Src, &len) < 0) { 868de68a0daSKris Kennaway perror("getsockname"); 869de68a0daSKris Kennaway exit(1); 870de68a0daSKris Kennaway } 87184a1a4cfSHajimu UMEMOTO srcport = ntohs(Src.sin6_port); 872de68a0daSKris Kennaway } 873de68a0daSKris Kennaway 874d429d720SHajimu UMEMOTO if (as_path) { 875d429d720SHajimu UMEMOTO asn = as_setup(as_server); 876d429d720SHajimu UMEMOTO if (asn == NULL) { 877d429d720SHajimu UMEMOTO fprintf(stderr, 878d429d720SHajimu UMEMOTO "traceroute6: as_setup failed, AS# lookups" 879d429d720SHajimu UMEMOTO " disabled\n"); 880d429d720SHajimu UMEMOTO (void)fflush(stderr); 881d429d720SHajimu UMEMOTO as_path = 0; 882d429d720SHajimu UMEMOTO } 883d429d720SHajimu UMEMOTO } 884d429d720SHajimu UMEMOTO 8857d56d374SYoshinobu Inoue /* 8867d56d374SYoshinobu Inoue * Message to users 8877d56d374SYoshinobu Inoue */ 888cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)&Dst, Dst.sin6_len, hbuf, 889d24cb249SHajimu UMEMOTO sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) 89033841545SHajimu UMEMOTO strlcpy(hbuf, "(invalid)", sizeof(hbuf)); 891c449e284SHajimu UMEMOTO fprintf(stderr, "traceroute6"); 892c449e284SHajimu UMEMOTO fprintf(stderr, " to %s (%s)", hostname, hbuf); 8937d56d374SYoshinobu Inoue if (source) 894c449e284SHajimu UMEMOTO fprintf(stderr, " from %s", source); 89584a1a4cfSHajimu UMEMOTO fprintf(stderr, ", %lu hops max, %lu byte packets\n", 896d55fae02SMichael Tuexen max_hops, 897d55fae02SMichael Tuexen datalen + ((useproto == IPPROTO_UDP) ? sizeof(struct udphdr) : 0)); 8987d56d374SYoshinobu Inoue (void) fflush(stderr); 8997d56d374SYoshinobu Inoue 900de68a0daSKris Kennaway if (first_hop > 1) 90184a1a4cfSHajimu UMEMOTO printf("Skipping %lu intermediate hops\n", first_hop - 1); 902de68a0daSKris Kennaway 903cc432e23SMariusz Zaborski if (connect(sndsock, (struct sockaddr *)&Dst, 904cc432e23SMariusz Zaborski sizeof(Dst)) != 0) { 905cc432e23SMariusz Zaborski fprintf(stderr, "connect: %s\n", strerror(errno)); 906cc432e23SMariusz Zaborski exit(1); 907cc432e23SMariusz Zaborski } 908cc432e23SMariusz Zaborski 909cc432e23SMariusz Zaborski /* 910cc432e23SMariusz Zaborski * Here we enter capability mode. Further down access to global 911cc432e23SMariusz Zaborski * namespaces (e.g filesystem) is restricted (see capsicum(4)). 912cc432e23SMariusz Zaborski * We must connect(2) our socket before this point. 913cc432e23SMariusz Zaborski */ 914cc432e23SMariusz Zaborski 915cc432e23SMariusz Zaborski if (caph_enter_casper() < 0) { 916cc432e23SMariusz Zaborski fprintf(stderr, "caph_enter_casper: %s\n", strerror(errno)); 917cc432e23SMariusz Zaborski exit(1); 918cc432e23SMariusz Zaborski } 919cc432e23SMariusz Zaborski 920cc432e23SMariusz Zaborski cap_rights_init(&rights, CAP_SEND, CAP_SETSOCKOPT); 921cc432e23SMariusz Zaborski if (caph_rights_limit(sndsock, &rights) < 0) { 922cc432e23SMariusz Zaborski fprintf(stderr, "caph_rights_limit sndsock: %s\n", 923cc432e23SMariusz Zaborski strerror(errno)); 924cc432e23SMariusz Zaborski exit(1); 925cc432e23SMariusz Zaborski } 926cc432e23SMariusz Zaborski 9277d56d374SYoshinobu Inoue /* 9287d56d374SYoshinobu Inoue * Main loop 9297d56d374SYoshinobu Inoue */ 930de68a0daSKris Kennaway for (hops = first_hop; hops <= max_hops; ++hops) { 9317d56d374SYoshinobu Inoue struct in6_addr lastaddr; 9327d56d374SYoshinobu Inoue int got_there = 0; 933f42640a3SUlrich Spörlein unsigned unreachable = 0; 9347d56d374SYoshinobu Inoue 93584a1a4cfSHajimu UMEMOTO printf("%2lu ", hops); 9367d56d374SYoshinobu Inoue bzero(&lastaddr, sizeof(lastaddr)); 9377d56d374SYoshinobu Inoue for (probe = 0; probe < nprobes; ++probe) { 9387d56d374SYoshinobu Inoue int cc; 9397d56d374SYoshinobu Inoue struct timeval t1, t2; 9407d56d374SYoshinobu Inoue 94184a1a4cfSHajimu UMEMOTO (void) gettimeofday(&t1, NULL); 9427d56d374SYoshinobu Inoue send_probe(++seq, hops); 9437d56d374SYoshinobu Inoue while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) { 94484a1a4cfSHajimu UMEMOTO (void) gettimeofday(&t2, NULL); 94564694fdcSMichael Tuexen if (packet_ok(&rcvmhdr, cc, seq, &type, &code)) { 9467d56d374SYoshinobu Inoue if (!IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr, 9477d56d374SYoshinobu Inoue &lastaddr)) { 94859876f93SChristian S.J. Peron if (probe > 0) 94959876f93SChristian S.J. Peron fputs("\n ", stdout); 9507d56d374SYoshinobu Inoue print(&rcvmhdr, cc); 9517d56d374SYoshinobu Inoue lastaddr = Rcv.sin6_addr; 9527d56d374SYoshinobu Inoue } 953c449e284SHajimu UMEMOTO printf(" %.3f ms", deltaT(&t1, &t2)); 95464694fdcSMichael Tuexen if (type == ICMP6_DST_UNREACH) { 95564694fdcSMichael Tuexen switch (code) { 9567d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH_NOROUTE: 9577d56d374SYoshinobu Inoue ++unreachable; 958c449e284SHajimu UMEMOTO printf(" !N"); 9597d56d374SYoshinobu Inoue break; 9607d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH_ADMIN: 9617d56d374SYoshinobu Inoue ++unreachable; 962c449e284SHajimu UMEMOTO printf(" !P"); 9637d56d374SYoshinobu Inoue break; 9647d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH_NOTNEIGHBOR: 9657d56d374SYoshinobu Inoue ++unreachable; 966c449e284SHajimu UMEMOTO printf(" !S"); 9677d56d374SYoshinobu Inoue break; 9687d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH_ADDR: 9697d56d374SYoshinobu Inoue ++unreachable; 970c449e284SHajimu UMEMOTO printf(" !A"); 9717d56d374SYoshinobu Inoue break; 9727d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH_NOPORT: 9737d56d374SYoshinobu Inoue if (rcvhlim >= 0 && 9747d56d374SYoshinobu Inoue rcvhlim <= 1) 975c449e284SHajimu UMEMOTO printf(" !"); 9767d56d374SYoshinobu Inoue ++got_there; 9777d56d374SYoshinobu Inoue break; 9787d56d374SYoshinobu Inoue } 9791f69b3fbSMichael Tuexen } else if (type == ICMP6_PARAM_PROB && 9801f69b3fbSMichael Tuexen code == ICMP6_PARAMPROB_NEXTHEADER) { 9811f69b3fbSMichael Tuexen printf(" !H"); 9821f69b3fbSMichael Tuexen ++got_there; 98364694fdcSMichael Tuexen } else if (type == ICMP6_ECHO_REPLY) { 98464694fdcSMichael Tuexen if (rcvhlim >= 0 && 98564694fdcSMichael Tuexen rcvhlim <= 1) 98664694fdcSMichael Tuexen printf(" !"); 98764694fdcSMichael Tuexen ++got_there; 98864694fdcSMichael Tuexen } 9897d56d374SYoshinobu Inoue break; 990161ab37dSHiroki Sato } else if (deltaT(&t1, &t2) > waittime * 1000) { 991161ab37dSHiroki Sato cc = 0; 992161ab37dSHiroki Sato break; 9937d56d374SYoshinobu Inoue } 9947d56d374SYoshinobu Inoue } 9957d56d374SYoshinobu Inoue if (cc == 0) 996c449e284SHajimu UMEMOTO printf(" *"); 9977d56d374SYoshinobu Inoue (void) fflush(stdout); 9987d56d374SYoshinobu Inoue } 9997d56d374SYoshinobu Inoue putchar('\n'); 10007d56d374SYoshinobu Inoue if (got_there || 10017d56d374SYoshinobu Inoue (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) { 10027d56d374SYoshinobu Inoue exit(0); 10037d56d374SYoshinobu Inoue } 10047d56d374SYoshinobu Inoue } 1005d429d720SHajimu UMEMOTO if (as_path) 1006d429d720SHajimu UMEMOTO as_shutdown(asn); 10077d56d374SYoshinobu Inoue 10087d56d374SYoshinobu Inoue exit(0); 10097d56d374SYoshinobu Inoue } 10107d56d374SYoshinobu Inoue 10117d56d374SYoshinobu Inoue int 1012aa96470cSMichael Tuexen wait_for_reply(int sock, struct msghdr *mhdr) 10137d56d374SYoshinobu Inoue { 10142a1c5efaSKris Kennaway #ifdef HAVE_POLL 10152a1c5efaSKris Kennaway struct pollfd pfd[1]; 10167d56d374SYoshinobu Inoue int cc = 0; 10177d56d374SYoshinobu Inoue 10182a1c5efaSKris Kennaway pfd[0].fd = sock; 10192a1c5efaSKris Kennaway pfd[0].events = POLLIN; 10202a1c5efaSKris Kennaway pfd[0].revents = 0; 10217d56d374SYoshinobu Inoue 10222a1c5efaSKris Kennaway if (poll(pfd, 1, waittime * 1000) > 0) 10237d56d374SYoshinobu Inoue cc = recvmsg(rcvsock, mhdr, 0); 10247d56d374SYoshinobu Inoue 10257d56d374SYoshinobu Inoue return (cc); 10262a1c5efaSKris Kennaway #else 10272a1c5efaSKris Kennaway fd_set *fdsp; 10282a1c5efaSKris Kennaway struct timeval wait; 10292a1c5efaSKris Kennaway int cc = 0, fdsn; 10302a1c5efaSKris Kennaway 10312a1c5efaSKris Kennaway fdsn = howmany(sock + 1, NFDBITS) * sizeof(fd_mask); 10322a1c5efaSKris Kennaway if ((fdsp = (fd_set *)malloc(fdsn)) == NULL) 10332a1c5efaSKris Kennaway err(1, "malloc"); 10342a1c5efaSKris Kennaway memset(fdsp, 0, fdsn); 10352a1c5efaSKris Kennaway FD_SET(sock, fdsp); 10362a1c5efaSKris Kennaway wait.tv_sec = waittime; wait.tv_usec = 0; 10372a1c5efaSKris Kennaway 10382a1c5efaSKris Kennaway if (select(sock+1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0) 10392a1c5efaSKris Kennaway cc = recvmsg(rcvsock, mhdr, 0); 10402a1c5efaSKris Kennaway 10412a1c5efaSKris Kennaway free(fdsp); 10422a1c5efaSKris Kennaway return (cc); 10432a1c5efaSKris Kennaway #endif 10447d56d374SYoshinobu Inoue } 10457d56d374SYoshinobu Inoue 1046ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 10477d56d374SYoshinobu Inoue int 1048ca19d0d7SMark Johnston setpolicy(int so, char *policy) 10497d56d374SYoshinobu Inoue { 10507d56d374SYoshinobu Inoue char *buf; 10517d56d374SYoshinobu Inoue 10527d56d374SYoshinobu Inoue buf = ipsec_set_policy(policy, strlen(policy)); 10537d56d374SYoshinobu Inoue if (buf == NULL) { 1054de68a0daSKris Kennaway warnx("%s", ipsec_strerror()); 10557d56d374SYoshinobu Inoue return -1; 10567d56d374SYoshinobu Inoue } 10577d56d374SYoshinobu Inoue (void)setsockopt(so, IPPROTO_IPV6, IPV6_IPSEC_POLICY, 10587d56d374SYoshinobu Inoue buf, ipsec_get_policylen(buf)); 10597d56d374SYoshinobu Inoue 10607d56d374SYoshinobu Inoue free(buf); 10617d56d374SYoshinobu Inoue 10627d56d374SYoshinobu Inoue return 0; 10637d56d374SYoshinobu Inoue } 10647d56d374SYoshinobu Inoue #endif 10657d56d374SYoshinobu Inoue 10667d56d374SYoshinobu Inoue void 1067aa96470cSMichael Tuexen send_probe(int seq, u_long hops) 10687d56d374SYoshinobu Inoue { 1069d7b63fafSDavid Malone struct icmp6_hdr *icp; 10709d8b46c8SMichael Tuexen struct sctphdr *sctp; 1071cc432e23SMariusz Zaborski struct udphdr *outudp; 10729d8b46c8SMichael Tuexen struct sctp_chunkhdr *chk; 107351eff8efSMichael Tuexen struct sctp_init_chunk *init; 107451eff8efSMichael Tuexen struct sctp_paramhdr *param; 10759d8b46c8SMichael Tuexen struct tcphdr *tcp; 10767d56d374SYoshinobu Inoue int i; 10777d56d374SYoshinobu Inoue 107884a1a4cfSHajimu UMEMOTO i = hops; 10797d56d374SYoshinobu Inoue if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 108084a1a4cfSHajimu UMEMOTO (char *)&i, sizeof(i)) < 0) { 10817d56d374SYoshinobu Inoue perror("setsockopt IPV6_UNICAST_HOPS"); 10827d56d374SYoshinobu Inoue } 10837d56d374SYoshinobu Inoue 10847d56d374SYoshinobu Inoue Dst.sin6_port = htons(port + seq); 10857d56d374SYoshinobu Inoue 1086d7b63fafSDavid Malone switch (useproto) { 1087d7b63fafSDavid Malone case IPPROTO_ICMPV6: 1088d7b63fafSDavid Malone icp = (struct icmp6_hdr *)outpacket; 108984a1a4cfSHajimu UMEMOTO 109084a1a4cfSHajimu UMEMOTO icp->icmp6_type = ICMP6_ECHO_REQUEST; 109184a1a4cfSHajimu UMEMOTO icp->icmp6_code = 0; 109284a1a4cfSHajimu UMEMOTO icp->icmp6_cksum = 0; 109384a1a4cfSHajimu UMEMOTO icp->icmp6_id = ident; 109484a1a4cfSHajimu UMEMOTO icp->icmp6_seq = htons(seq); 1095d7b63fafSDavid Malone break; 1096d7b63fafSDavid Malone case IPPROTO_UDP: 1097cc432e23SMariusz Zaborski outudp = (struct udphdr *) outpacket; 1098cc432e23SMariusz Zaborski outudp->uh_sport = htons(ident); 1099cc432e23SMariusz Zaborski outudp->uh_dport = htons(port+seq); 1100cc432e23SMariusz Zaborski outudp->uh_ulen = htons(datalen); 1101cc432e23SMariusz Zaborski outudp->uh_sum = udp_cksum(&Src, &Dst, outpacket, datalen); 1102d7b63fafSDavid Malone break; 1103d7b63fafSDavid Malone case IPPROTO_NONE: 1104d7b63fafSDavid Malone /* No space for anything. No harm as seq/tv32 are decorative. */ 1105d7b63fafSDavid Malone break; 11069d8b46c8SMichael Tuexen case IPPROTO_SCTP: 11079d8b46c8SMichael Tuexen sctp = (struct sctphdr *)outpacket; 11089d8b46c8SMichael Tuexen 11099d8b46c8SMichael Tuexen sctp->src_port = htons(ident); 11109d8b46c8SMichael Tuexen sctp->dest_port = htons(port + seq); 111151eff8efSMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) + 111251eff8efSMichael Tuexen sizeof(struct sctp_init_chunk))) { 111351eff8efSMichael Tuexen sctp->v_tag = 0; 111451eff8efSMichael Tuexen } else { 11159d8b46c8SMichael Tuexen sctp->v_tag = (sctp->src_port << 16) | sctp->dest_port; 111651eff8efSMichael Tuexen } 11179d8b46c8SMichael Tuexen sctp->checksum = htonl(0); 11189d8b46c8SMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) + 111951eff8efSMichael Tuexen sizeof(struct sctp_init_chunk))) { 112051eff8efSMichael Tuexen /* 112151eff8efSMichael Tuexen * Send a packet containing an INIT chunk. This works 112251eff8efSMichael Tuexen * better in case of firewalls on the path, but 112351eff8efSMichael Tuexen * results in a probe packet containing at least 112451eff8efSMichael Tuexen * 32 bytes of payload. For shorter payloads, use 112551eff8efSMichael Tuexen * SHUTDOWN-ACK chunks. 112651eff8efSMichael Tuexen */ 112751eff8efSMichael Tuexen init = (struct sctp_init_chunk *)(sctp + 1); 112851eff8efSMichael Tuexen init->ch.chunk_type = SCTP_INITIATION; 112951eff8efSMichael Tuexen init->ch.chunk_flags = 0; 113051eff8efSMichael Tuexen init->ch.chunk_length = htons((u_int16_t)(datalen - 113151eff8efSMichael Tuexen sizeof(struct sctphdr))); 113251eff8efSMichael Tuexen init->init.initiate_tag = (sctp->src_port << 16) | 113351eff8efSMichael Tuexen sctp->dest_port; 113451eff8efSMichael Tuexen init->init.a_rwnd = htonl(1500); 113551eff8efSMichael Tuexen init->init.num_outbound_streams = htons(1); 113651eff8efSMichael Tuexen init->init.num_inbound_streams = htons(1); 113751eff8efSMichael Tuexen init->init.initial_tsn = htonl(0); 113851eff8efSMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) + 113951eff8efSMichael Tuexen sizeof(struct sctp_init_chunk) + 114051eff8efSMichael Tuexen sizeof(struct sctp_paramhdr))) { 114151eff8efSMichael Tuexen param = (struct sctp_paramhdr *)(init + 1); 114251eff8efSMichael Tuexen param->param_type = htons(SCTP_PAD); 114351eff8efSMichael Tuexen param->param_length = 114451eff8efSMichael Tuexen htons((u_int16_t)(datalen - 114551eff8efSMichael Tuexen sizeof(struct sctphdr) - 114651eff8efSMichael Tuexen sizeof(struct sctp_init_chunk))); 114751eff8efSMichael Tuexen } 114851eff8efSMichael Tuexen } else { 114951eff8efSMichael Tuexen /* 115051eff8efSMichael Tuexen * Send a packet containing a SHUTDOWN-ACK chunk, 115151eff8efSMichael Tuexen * possibly followed by a PAD chunk. 115251eff8efSMichael Tuexen */ 115351eff8efSMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) + 11549d8b46c8SMichael Tuexen sizeof(struct sctp_chunkhdr))) { 11559d8b46c8SMichael Tuexen chk = (struct sctp_chunkhdr *)(sctp + 1); 11569d8b46c8SMichael Tuexen chk->chunk_type = SCTP_SHUTDOWN_ACK; 11579d8b46c8SMichael Tuexen chk->chunk_flags = 0; 11589d8b46c8SMichael Tuexen chk->chunk_length = htons(4); 11599d8b46c8SMichael Tuexen } 11609d8b46c8SMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) + 11619d8b46c8SMichael Tuexen 2 * sizeof(struct sctp_chunkhdr))) { 11629d8b46c8SMichael Tuexen chk = chk + 1; 11639d8b46c8SMichael Tuexen chk->chunk_type = SCTP_PAD_CHUNK; 11649d8b46c8SMichael Tuexen chk->chunk_flags = 0; 11659d8b46c8SMichael Tuexen chk->chunk_length = htons((u_int16_t)(datalen - 11669d8b46c8SMichael Tuexen sizeof(struct sctphdr) - 11679d8b46c8SMichael Tuexen sizeof(struct sctp_chunkhdr))); 11689d8b46c8SMichael Tuexen } 116951eff8efSMichael Tuexen } 11709d8b46c8SMichael Tuexen sctp->checksum = sctp_crc32c(outpacket, datalen); 11719d8b46c8SMichael Tuexen break; 11729d8b46c8SMichael Tuexen case IPPROTO_TCP: 11739d8b46c8SMichael Tuexen tcp = (struct tcphdr *)outpacket; 11749d8b46c8SMichael Tuexen 11759d8b46c8SMichael Tuexen tcp->th_sport = htons(ident); 11769d8b46c8SMichael Tuexen tcp->th_dport = htons(port + seq); 11779d8b46c8SMichael Tuexen tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport; 11789d8b46c8SMichael Tuexen tcp->th_ack = 0; 11799d8b46c8SMichael Tuexen tcp->th_off = 5; 11809d8b46c8SMichael Tuexen tcp->th_flags = TH_SYN; 11819d8b46c8SMichael Tuexen tcp->th_sum = 0; 11829d8b46c8SMichael Tuexen tcp->th_sum = tcp_chksum(&Src, &Dst, outpacket, datalen); 11839d8b46c8SMichael Tuexen break; 1184d7b63fafSDavid Malone default: 1185d7b63fafSDavid Malone fprintf(stderr, "Unknown probe protocol %d.\n", useproto); 1186d7b63fafSDavid Malone exit(1); 118784a1a4cfSHajimu UMEMOTO } 11887d56d374SYoshinobu Inoue 1189cc432e23SMariusz Zaborski i = send(sndsock, (char *)outpacket, datalen, 0); 1190f42640a3SUlrich Spörlein if (i < 0 || (u_long)i != datalen) { 11917d56d374SYoshinobu Inoue if (i < 0) 1192cc432e23SMariusz Zaborski perror("send"); 119384a1a4cfSHajimu UMEMOTO printf("traceroute6: wrote %s %lu chars, ret=%d\n", 1194c449e284SHajimu UMEMOTO hostname, datalen, i); 11957d56d374SYoshinobu Inoue (void) fflush(stdout); 11967d56d374SYoshinobu Inoue } 11977d56d374SYoshinobu Inoue } 11987d56d374SYoshinobu Inoue 11997d56d374SYoshinobu Inoue int 1200aa96470cSMichael Tuexen get_hoplim(struct msghdr *mhdr) 12017d56d374SYoshinobu Inoue { 12027d56d374SYoshinobu Inoue struct cmsghdr *cm; 12037d56d374SYoshinobu Inoue 12047d56d374SYoshinobu Inoue for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 12057d56d374SYoshinobu Inoue cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 12067d56d374SYoshinobu Inoue if (cm->cmsg_level == IPPROTO_IPV6 && 12077d56d374SYoshinobu Inoue cm->cmsg_type == IPV6_HOPLIMIT && 12087d56d374SYoshinobu Inoue cm->cmsg_len == CMSG_LEN(sizeof(int))) 12097d56d374SYoshinobu Inoue return (*(int *)CMSG_DATA(cm)); 12107d56d374SYoshinobu Inoue } 12117d56d374SYoshinobu Inoue 12127d56d374SYoshinobu Inoue return (-1); 12137d56d374SYoshinobu Inoue } 12147d56d374SYoshinobu Inoue 12157d56d374SYoshinobu Inoue double 1216aa96470cSMichael Tuexen deltaT(struct timeval *t1p, struct timeval *t2p) 12177d56d374SYoshinobu Inoue { 1218e961704aSDavid Malone double dt; 12197d56d374SYoshinobu Inoue 12207d56d374SYoshinobu Inoue dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + 12217d56d374SYoshinobu Inoue (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; 12227d56d374SYoshinobu Inoue return (dt); 12237d56d374SYoshinobu Inoue } 12247d56d374SYoshinobu Inoue 12257d56d374SYoshinobu Inoue /* 12267d56d374SYoshinobu Inoue * Convert an ICMP "type" field to a printable string. 12277d56d374SYoshinobu Inoue */ 1228f42640a3SUlrich Spörlein const char * 1229f42640a3SUlrich Spörlein pr_type(int t0) 12307d56d374SYoshinobu Inoue { 12317d56d374SYoshinobu Inoue u_char t = t0 & 0xff; 1232f42640a3SUlrich Spörlein const char *cp; 12337d56d374SYoshinobu Inoue 12347d56d374SYoshinobu Inoue switch (t) { 12357d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH: 12367d56d374SYoshinobu Inoue cp = "Destination Unreachable"; 12377d56d374SYoshinobu Inoue break; 12387d56d374SYoshinobu Inoue case ICMP6_PACKET_TOO_BIG: 1239c449e284SHajimu UMEMOTO cp = "Packet Too Big"; 12407d56d374SYoshinobu Inoue break; 12417d56d374SYoshinobu Inoue case ICMP6_TIME_EXCEEDED: 12427d56d374SYoshinobu Inoue cp = "Time Exceeded"; 12437d56d374SYoshinobu Inoue break; 12447d56d374SYoshinobu Inoue case ICMP6_PARAM_PROB: 12457d56d374SYoshinobu Inoue cp = "Parameter Problem"; 12467d56d374SYoshinobu Inoue break; 12477d56d374SYoshinobu Inoue case ICMP6_ECHO_REQUEST: 12487d56d374SYoshinobu Inoue cp = "Echo Request"; 12497d56d374SYoshinobu Inoue break; 12507d56d374SYoshinobu Inoue case ICMP6_ECHO_REPLY: 12517d56d374SYoshinobu Inoue cp = "Echo Reply"; 12527d56d374SYoshinobu Inoue break; 12537d56d374SYoshinobu Inoue case ICMP6_MEMBERSHIP_QUERY: 12547d56d374SYoshinobu Inoue cp = "Group Membership Query"; 12557d56d374SYoshinobu Inoue break; 12567d56d374SYoshinobu Inoue case ICMP6_MEMBERSHIP_REPORT: 12577d56d374SYoshinobu Inoue cp = "Group Membership Report"; 12587d56d374SYoshinobu Inoue break; 12597d56d374SYoshinobu Inoue case ICMP6_MEMBERSHIP_REDUCTION: 12607d56d374SYoshinobu Inoue cp = "Group Membership Reduction"; 12617d56d374SYoshinobu Inoue break; 12627d56d374SYoshinobu Inoue case ND_ROUTER_SOLICIT: 12637d56d374SYoshinobu Inoue cp = "Router Solicitation"; 12647d56d374SYoshinobu Inoue break; 12657d56d374SYoshinobu Inoue case ND_ROUTER_ADVERT: 12667d56d374SYoshinobu Inoue cp = "Router Advertisement"; 12677d56d374SYoshinobu Inoue break; 12687d56d374SYoshinobu Inoue case ND_NEIGHBOR_SOLICIT: 12697d56d374SYoshinobu Inoue cp = "Neighbor Solicitation"; 12707d56d374SYoshinobu Inoue break; 12717d56d374SYoshinobu Inoue case ND_NEIGHBOR_ADVERT: 12727d56d374SYoshinobu Inoue cp = "Neighbor Advertisement"; 12737d56d374SYoshinobu Inoue break; 12747d56d374SYoshinobu Inoue case ND_REDIRECT: 1275de68a0daSKris Kennaway cp = "Redirect"; 12767d56d374SYoshinobu Inoue break; 12777d56d374SYoshinobu Inoue default: 12787d56d374SYoshinobu Inoue cp = "Unknown"; 12797d56d374SYoshinobu Inoue break; 12807d56d374SYoshinobu Inoue } 12817d56d374SYoshinobu Inoue return cp; 12827d56d374SYoshinobu Inoue } 12837d56d374SYoshinobu Inoue 12847d56d374SYoshinobu Inoue int 128564694fdcSMichael Tuexen packet_ok(struct msghdr *mhdr, int cc, int seq, u_char *type, u_char *code) 12867d56d374SYoshinobu Inoue { 1287e961704aSDavid Malone struct icmp6_hdr *icp; 12887d56d374SYoshinobu Inoue struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; 12897d56d374SYoshinobu Inoue char *buf = (char *)mhdr->msg_iov[0].iov_base; 12907d56d374SYoshinobu Inoue struct cmsghdr *cm; 12917d56d374SYoshinobu Inoue int *hlimp; 1292de68a0daSKris Kennaway char hbuf[NI_MAXHOST]; 12937d56d374SYoshinobu Inoue 1294de68a0daSKris Kennaway #ifdef OLDRAWSOCKET 1295de68a0daSKris Kennaway int hlen; 1296de68a0daSKris Kennaway struct ip6_hdr *ip; 1297de68a0daSKris Kennaway #endif 1298de68a0daSKris Kennaway 1299de68a0daSKris Kennaway #ifdef OLDRAWSOCKET 1300de68a0daSKris Kennaway ip = (struct ip6_hdr *) buf; 1301de68a0daSKris Kennaway hlen = sizeof(struct ip6_hdr); 1302de68a0daSKris Kennaway if (cc < hlen + sizeof(struct icmp6_hdr)) { 1303de68a0daSKris Kennaway if (verbose) { 1304cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len, 1305d24cb249SHajimu UMEMOTO hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 130633841545SHajimu UMEMOTO strlcpy(hbuf, "invalid", sizeof(hbuf)); 1307c449e284SHajimu UMEMOTO printf("packet too short (%d bytes) from %s\n", cc, 1308de68a0daSKris Kennaway hbuf); 1309de68a0daSKris Kennaway } 1310de68a0daSKris Kennaway return (0); 1311de68a0daSKris Kennaway } 1312de68a0daSKris Kennaway cc -= hlen; 1313de68a0daSKris Kennaway icp = (struct icmp6_hdr *)(buf + hlen); 1314de68a0daSKris Kennaway #else 1315f42640a3SUlrich Spörlein if (cc < (int)sizeof(struct icmp6_hdr)) { 1316de68a0daSKris Kennaway if (verbose) { 1317cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len, 1318d24cb249SHajimu UMEMOTO hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 131933841545SHajimu UMEMOTO strlcpy(hbuf, "invalid", sizeof(hbuf)); 1320c449e284SHajimu UMEMOTO printf("data too short (%d bytes) from %s\n", cc, hbuf); 1321de68a0daSKris Kennaway } 13227d56d374SYoshinobu Inoue return (0); 13237d56d374SYoshinobu Inoue } 13247d56d374SYoshinobu Inoue icp = (struct icmp6_hdr *)buf; 1325de68a0daSKris Kennaway #endif 13267d56d374SYoshinobu Inoue /* get optional information via advanced API */ 13277d56d374SYoshinobu Inoue rcvpktinfo = NULL; 13287d56d374SYoshinobu Inoue hlimp = NULL; 13297d56d374SYoshinobu Inoue for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 13307d56d374SYoshinobu Inoue cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 13317d56d374SYoshinobu Inoue if (cm->cmsg_level == IPPROTO_IPV6 && 13327d56d374SYoshinobu Inoue cm->cmsg_type == IPV6_PKTINFO && 13337d56d374SYoshinobu Inoue cm->cmsg_len == 13347d56d374SYoshinobu Inoue CMSG_LEN(sizeof(struct in6_pktinfo))) 13357d56d374SYoshinobu Inoue rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm)); 13367d56d374SYoshinobu Inoue 13377d56d374SYoshinobu Inoue if (cm->cmsg_level == IPPROTO_IPV6 && 13387d56d374SYoshinobu Inoue cm->cmsg_type == IPV6_HOPLIMIT && 13397d56d374SYoshinobu Inoue cm->cmsg_len == CMSG_LEN(sizeof(int))) 13407d56d374SYoshinobu Inoue hlimp = (int *)CMSG_DATA(cm); 13417d56d374SYoshinobu Inoue } 13427d56d374SYoshinobu Inoue if (rcvpktinfo == NULL || hlimp == NULL) { 13437d56d374SYoshinobu Inoue warnx("failed to get received hop limit or packet info"); 1344de68a0daSKris Kennaway #if 0 13457d56d374SYoshinobu Inoue return (0); 1346de68a0daSKris Kennaway #else 1347de68a0daSKris Kennaway rcvhlim = 0; /*XXX*/ 1348de68a0daSKris Kennaway #endif 13497d56d374SYoshinobu Inoue } 1350de68a0daSKris Kennaway else 13517d56d374SYoshinobu Inoue rcvhlim = *hlimp; 13527d56d374SYoshinobu Inoue 135364694fdcSMichael Tuexen *type = icp->icmp6_type; 135464694fdcSMichael Tuexen *code = icp->icmp6_code; 135564694fdcSMichael Tuexen if ((*type == ICMP6_TIME_EXCEEDED && 135664694fdcSMichael Tuexen *code == ICMP6_TIME_EXCEED_TRANSIT) || 13571f69b3fbSMichael Tuexen (*type == ICMP6_DST_UNREACH) || 13581f69b3fbSMichael Tuexen (*type == ICMP6_PARAM_PROB && 13591f69b3fbSMichael Tuexen *code == ICMP6_PARAMPROB_NEXTHEADER)) { 13607d56d374SYoshinobu Inoue struct ip6_hdr *hip; 1361aa96470cSMichael Tuexen struct icmp6_hdr *icmp; 136251eff8efSMichael Tuexen struct sctp_init_chunk *init; 13639d8b46c8SMichael Tuexen struct sctphdr *sctp; 13649d8b46c8SMichael Tuexen struct tcphdr *tcp; 1365aa96470cSMichael Tuexen struct udphdr *udp; 1366d7b63fafSDavid Malone void *up; 13677d56d374SYoshinobu Inoue 13687d56d374SYoshinobu Inoue hip = (struct ip6_hdr *)(icp + 1); 1369d7b63fafSDavid Malone if ((up = get_uphdr(hip, (u_char *)(buf + cc))) == NULL) { 13707d56d374SYoshinobu Inoue if (verbose) 13717d56d374SYoshinobu Inoue warnx("failed to get upper layer header"); 13727d56d374SYoshinobu Inoue return (0); 13737d56d374SYoshinobu Inoue } 1374d7b63fafSDavid Malone switch (useproto) { 1375d7b63fafSDavid Malone case IPPROTO_ICMPV6: 1376aa96470cSMichael Tuexen icmp = (struct icmp6_hdr *)up; 1377aa96470cSMichael Tuexen if (icmp->icmp6_id == ident && 1378aa96470cSMichael Tuexen icmp->icmp6_seq == htons(seq)) 137964694fdcSMichael Tuexen return (1); 1380d7b63fafSDavid Malone break; 1381d7b63fafSDavid Malone case IPPROTO_UDP: 1382aa96470cSMichael Tuexen udp = (struct udphdr *)up; 1383cc432e23SMariusz Zaborski if (udp->uh_sport == htons(ident) && 1384aa96470cSMichael Tuexen udp->uh_dport == htons(port + seq)) 138564694fdcSMichael Tuexen return (1); 1386d7b63fafSDavid Malone break; 13879d8b46c8SMichael Tuexen case IPPROTO_SCTP: 13889d8b46c8SMichael Tuexen sctp = (struct sctphdr *)up; 138951eff8efSMichael Tuexen if (sctp->src_port != htons(ident) || 139051eff8efSMichael Tuexen sctp->dest_port != htons(port + seq)) { 139151eff8efSMichael Tuexen break; 139251eff8efSMichael Tuexen } 139351eff8efSMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) + 139451eff8efSMichael Tuexen sizeof(struct sctp_init_chunk))) { 139551eff8efSMichael Tuexen if (sctp->v_tag != 0) { 139651eff8efSMichael Tuexen break; 139751eff8efSMichael Tuexen } 139851eff8efSMichael Tuexen init = (struct sctp_init_chunk *)(sctp + 1); 139951eff8efSMichael Tuexen /* Check the initiate tag, if available. */ 140051eff8efSMichael Tuexen if ((char *)&init->init.a_rwnd > buf + cc) { 140164694fdcSMichael Tuexen return (1); 140251eff8efSMichael Tuexen } 140351eff8efSMichael Tuexen if (init->init.initiate_tag == (u_int32_t) 140451eff8efSMichael Tuexen ((sctp->src_port << 16) | sctp->dest_port)) { 140564694fdcSMichael Tuexen return (1); 140651eff8efSMichael Tuexen } 140751eff8efSMichael Tuexen } else { 140851eff8efSMichael Tuexen if (sctp->v_tag == 140951eff8efSMichael Tuexen (u_int32_t)((sctp->src_port << 16) | 141051eff8efSMichael Tuexen sctp->dest_port)) { 141164694fdcSMichael Tuexen return (1); 141251eff8efSMichael Tuexen } 141351eff8efSMichael Tuexen } 14149d8b46c8SMichael Tuexen break; 14159d8b46c8SMichael Tuexen case IPPROTO_TCP: 14169d8b46c8SMichael Tuexen tcp = (struct tcphdr *)up; 14179d8b46c8SMichael Tuexen if (tcp->th_sport == htons(ident) && 14189d8b46c8SMichael Tuexen tcp->th_dport == htons(port + seq) && 14199d8b46c8SMichael Tuexen tcp->th_seq == 14209d8b46c8SMichael Tuexen (tcp_seq)((tcp->th_sport << 16) | tcp->th_dport)) 142164694fdcSMichael Tuexen return (1); 14229d8b46c8SMichael Tuexen break; 1423d7b63fafSDavid Malone case IPPROTO_NONE: 142464694fdcSMichael Tuexen return (1); 1425d7b63fafSDavid Malone default: 1426d7b63fafSDavid Malone fprintf(stderr, "Unknown probe proto %d.\n", useproto); 1427d7b63fafSDavid Malone break; 1428d7b63fafSDavid Malone } 142964694fdcSMichael Tuexen } else if (useproto == IPPROTO_ICMPV6 && *type == ICMP6_ECHO_REPLY) { 143084a1a4cfSHajimu UMEMOTO if (icp->icmp6_id == ident && 143184a1a4cfSHajimu UMEMOTO icp->icmp6_seq == htons(seq)) 143264694fdcSMichael Tuexen return (1); 14337d56d374SYoshinobu Inoue } 14347d56d374SYoshinobu Inoue if (verbose) { 1435de68a0daSKris Kennaway char sbuf[NI_MAXHOST+1], dbuf[INET6_ADDRSTRLEN]; 1436e961704aSDavid Malone u_int8_t *p; 1437e961704aSDavid Malone int i; 14387d56d374SYoshinobu Inoue 1439cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len, 1440d24cb249SHajimu UMEMOTO sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0) 1441c449e284SHajimu UMEMOTO strlcpy(sbuf, "invalid", sizeof(sbuf)); 1442c449e284SHajimu UMEMOTO printf("\n%d bytes from %s to %s", cc, sbuf, 1443de68a0daSKris Kennaway rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1444c449e284SHajimu UMEMOTO dbuf, sizeof(dbuf)) : "?"); 144564694fdcSMichael Tuexen printf(": icmp type %d (%s) code %d\n", *type, pr_type(*type), 144664694fdcSMichael Tuexen *code); 1447de68a0daSKris Kennaway p = (u_int8_t *)(icp + 1); 1448de68a0daSKris Kennaway #define WIDTH 16 1449de68a0daSKris Kennaway for (i = 0; i < cc; i++) { 1450de68a0daSKris Kennaway if (i % WIDTH == 0) 1451c449e284SHajimu UMEMOTO printf("%04x:", i); 1452de68a0daSKris Kennaway if (i % 4 == 0) 1453c449e284SHajimu UMEMOTO printf(" "); 1454c449e284SHajimu UMEMOTO printf("%02x", p[i]); 1455de68a0daSKris Kennaway if (i % WIDTH == WIDTH - 1) 1456c449e284SHajimu UMEMOTO printf("\n"); 1457de68a0daSKris Kennaway } 1458de68a0daSKris Kennaway if (cc % WIDTH != 0) 1459c449e284SHajimu UMEMOTO printf("\n"); 14607d56d374SYoshinobu Inoue } 14617d56d374SYoshinobu Inoue return (0); 14627d56d374SYoshinobu Inoue } 14637d56d374SYoshinobu Inoue 14647d56d374SYoshinobu Inoue /* 146584a1a4cfSHajimu UMEMOTO * Increment pointer until find the UDP or ICMP header. 14667d56d374SYoshinobu Inoue */ 1467d7b63fafSDavid Malone void * 1468aa96470cSMichael Tuexen get_uphdr(struct ip6_hdr *ip6, u_char *lim) 14697d56d374SYoshinobu Inoue { 14707d56d374SYoshinobu Inoue u_char *cp = (u_char *)ip6, nh; 14717d56d374SYoshinobu Inoue int hlen; 1472d7b63fafSDavid Malone static u_char none_hdr[1]; /* Fake pointer for IPPROTO_NONE. */ 14737d56d374SYoshinobu Inoue 1474d7b63fafSDavid Malone if (cp + sizeof(*ip6) > lim) 14757d56d374SYoshinobu Inoue return (NULL); 14767d56d374SYoshinobu Inoue 14777d56d374SYoshinobu Inoue nh = ip6->ip6_nxt; 14787d56d374SYoshinobu Inoue cp += sizeof(struct ip6_hdr); 14797d56d374SYoshinobu Inoue 1480d7b63fafSDavid Malone while (lim - cp >= (nh == IPPROTO_NONE ? 0 : 8)) { 14817d56d374SYoshinobu Inoue switch (nh) { 14827d56d374SYoshinobu Inoue case IPPROTO_ESP: 14837d56d374SYoshinobu Inoue return (NULL); 148484a1a4cfSHajimu UMEMOTO case IPPROTO_ICMPV6: 1485d7b63fafSDavid Malone return (useproto == nh ? cp : NULL); 14869d8b46c8SMichael Tuexen case IPPROTO_SCTP: 14879d8b46c8SMichael Tuexen case IPPROTO_TCP: 14887d56d374SYoshinobu Inoue case IPPROTO_UDP: 1489d7b63fafSDavid Malone return (useproto == nh ? cp : NULL); 1490d7b63fafSDavid Malone case IPPROTO_NONE: 1491d7b63fafSDavid Malone return (useproto == nh ? none_hdr : NULL); 14927d56d374SYoshinobu Inoue case IPPROTO_FRAGMENT: 14937d56d374SYoshinobu Inoue hlen = sizeof(struct ip6_frag); 14947d56d374SYoshinobu Inoue nh = ((struct ip6_frag *)cp)->ip6f_nxt; 14957d56d374SYoshinobu Inoue break; 14967d56d374SYoshinobu Inoue case IPPROTO_AH: 14977d56d374SYoshinobu Inoue hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2; 14987d56d374SYoshinobu Inoue nh = ((struct ip6_ext *)cp)->ip6e_nxt; 14997d56d374SYoshinobu Inoue break; 15007d56d374SYoshinobu Inoue default: 15017d56d374SYoshinobu Inoue hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3; 15027d56d374SYoshinobu Inoue nh = ((struct ip6_ext *)cp)->ip6e_nxt; 15037d56d374SYoshinobu Inoue break; 15047d56d374SYoshinobu Inoue } 15057d56d374SYoshinobu Inoue 15067d56d374SYoshinobu Inoue cp += hlen; 15077d56d374SYoshinobu Inoue } 15087d56d374SYoshinobu Inoue 15097d56d374SYoshinobu Inoue return (NULL); 15107d56d374SYoshinobu Inoue } 15117d56d374SYoshinobu Inoue 15127d56d374SYoshinobu Inoue void 1513cc432e23SMariusz Zaborski capdns_open() 1514cc432e23SMariusz Zaborski { 1515cc432e23SMariusz Zaborski const char *types[] = { "NAME", "ADDR" }; 1516cc432e23SMariusz Zaborski int families[1]; 1517cc432e23SMariusz Zaborski cap_channel_t *casper; 1518cc432e23SMariusz Zaborski 1519cc432e23SMariusz Zaborski casper = cap_init(); 1520cc432e23SMariusz Zaborski if (casper == NULL) 1521cc432e23SMariusz Zaborski errx(1, "unable to create casper process"); 1522cc432e23SMariusz Zaborski capdns = cap_service_open(casper, "system.dns"); 1523cc432e23SMariusz Zaborski if (capdns == NULL) 1524cc432e23SMariusz Zaborski errx(1, "unable to open system.dns service"); 1525cc432e23SMariusz Zaborski if (cap_dns_type_limit(capdns, types, nitems(types)) < 0) 1526cc432e23SMariusz Zaborski errx(1, "unable to limit access to system.dns service"); 1527cc432e23SMariusz Zaborski families[0] = AF_INET6; 1528cc432e23SMariusz Zaborski if (cap_dns_family_limit(capdns, families, nitems(families)) < 0) 1529cc432e23SMariusz Zaborski errx(1, "unable to limit access to system.dns service"); 1530cc432e23SMariusz Zaborski cap_close(casper); 1531cc432e23SMariusz Zaborski } 1532cc432e23SMariusz Zaborski 1533cc432e23SMariusz Zaborski void 1534aa96470cSMichael Tuexen print(struct msghdr *mhdr, int cc) 15357d56d374SYoshinobu Inoue { 15367d56d374SYoshinobu Inoue struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; 1537de68a0daSKris Kennaway char hbuf[NI_MAXHOST]; 15387d56d374SYoshinobu Inoue 1539cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len, 1540d24cb249SHajimu UMEMOTO hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 154133841545SHajimu UMEMOTO strlcpy(hbuf, "invalid", sizeof(hbuf)); 1542d429d720SHajimu UMEMOTO if (as_path) 1543d429d720SHajimu UMEMOTO printf(" [AS%u]", as_lookup(asn, hbuf, AF_INET6)); 1544de68a0daSKris Kennaway if (nflag) 1545c449e284SHajimu UMEMOTO printf(" %s", hbuf); 1546de68a0daSKris Kennaway else if (lflag) 1547c449e284SHajimu UMEMOTO printf(" %s (%s)", inetname((struct sockaddr *)from), hbuf); 1548de68a0daSKris Kennaway else 1549c449e284SHajimu UMEMOTO printf(" %s", inetname((struct sockaddr *)from)); 15507d56d374SYoshinobu Inoue 15517d56d374SYoshinobu Inoue if (verbose) { 1552de68a0daSKris Kennaway #ifdef OLDRAWSOCKET 1553c449e284SHajimu UMEMOTO printf(" %d bytes to %s", cc, 1554de68a0daSKris Kennaway rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1555c449e284SHajimu UMEMOTO hbuf, sizeof(hbuf)) : "?"); 1556de68a0daSKris Kennaway #else 1557c449e284SHajimu UMEMOTO printf(" %d bytes of data to %s", cc, 1558de68a0daSKris Kennaway rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1559c449e284SHajimu UMEMOTO hbuf, sizeof(hbuf)) : "?"); 1560de68a0daSKris Kennaway #endif 15617d56d374SYoshinobu Inoue } 15627d56d374SYoshinobu Inoue } 15637d56d374SYoshinobu Inoue 15647d56d374SYoshinobu Inoue /* 15657d56d374SYoshinobu Inoue * Construct an Internet address representation. 15667d56d374SYoshinobu Inoue * If the nflag has been supplied, give 15677d56d374SYoshinobu Inoue * numeric value, otherwise try for symbolic name. 15687d56d374SYoshinobu Inoue */ 1569de68a0daSKris Kennaway const char * 1570aa96470cSMichael Tuexen inetname(struct sockaddr *sa) 15717d56d374SYoshinobu Inoue { 1572e961704aSDavid Malone static char line[NI_MAXHOST], domain[MAXHOSTNAMELEN + 1]; 15737d56d374SYoshinobu Inoue static int first = 1; 1574e961704aSDavid Malone char *cp; 15757d56d374SYoshinobu Inoue 15767d56d374SYoshinobu Inoue if (first && !nflag) { 15777d56d374SYoshinobu Inoue first = 0; 1578c449e284SHajimu UMEMOTO if (gethostname(domain, sizeof(domain)) == 0 && 1579c449e284SHajimu UMEMOTO (cp = strchr(domain, '.'))) 158033841545SHajimu UMEMOTO (void) strlcpy(domain, cp + 1, sizeof(domain)); 15817d56d374SYoshinobu Inoue else 15827d56d374SYoshinobu Inoue domain[0] = 0; 15837d56d374SYoshinobu Inoue } 1584de68a0daSKris Kennaway cp = NULL; 15857d56d374SYoshinobu Inoue if (!nflag) { 1586cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, sa, sa->sa_len, line, sizeof(line), NULL, 0, 1587de68a0daSKris Kennaway NI_NAMEREQD) == 0) { 1588c449e284SHajimu UMEMOTO if ((cp = strchr(line, '.')) && 15897d56d374SYoshinobu Inoue !strcmp(cp + 1, domain)) 15907d56d374SYoshinobu Inoue *cp = 0; 1591de68a0daSKris Kennaway cp = line; 15927d56d374SYoshinobu Inoue } 15937d56d374SYoshinobu Inoue } 15947d56d374SYoshinobu Inoue if (cp) 1595de68a0daSKris Kennaway return cp; 1596de68a0daSKris Kennaway 1597cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, sa, sa->sa_len, line, sizeof(line), NULL, 0, 1598d24cb249SHajimu UMEMOTO NI_NUMERICHOST) != 0) 159933841545SHajimu UMEMOTO strlcpy(line, "invalid", sizeof(line)); 1600de68a0daSKris Kennaway return line; 16017d56d374SYoshinobu Inoue } 16027d56d374SYoshinobu Inoue 16039d8b46c8SMichael Tuexen /* 16049d8b46c8SMichael Tuexen * CRC32C routine for the Stream Control Transmission Protocol 16059d8b46c8SMichael Tuexen */ 16069d8b46c8SMichael Tuexen 16079d8b46c8SMichael Tuexen #define CRC32C(c, d) (c = (c>>8) ^ crc_c[(c^(d))&0xFF]) 16089d8b46c8SMichael Tuexen 16099d8b46c8SMichael Tuexen static u_int32_t crc_c[256] = { 16109d8b46c8SMichael Tuexen 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 16119d8b46c8SMichael Tuexen 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 16129d8b46c8SMichael Tuexen 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 16139d8b46c8SMichael Tuexen 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, 16149d8b46c8SMichael Tuexen 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 16159d8b46c8SMichael Tuexen 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, 16169d8b46c8SMichael Tuexen 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 16179d8b46c8SMichael Tuexen 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, 16189d8b46c8SMichael Tuexen 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 16199d8b46c8SMichael Tuexen 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, 16209d8b46c8SMichael Tuexen 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 16219d8b46c8SMichael Tuexen 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 16229d8b46c8SMichael Tuexen 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 16239d8b46c8SMichael Tuexen 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, 16249d8b46c8SMichael Tuexen 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 16259d8b46c8SMichael Tuexen 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 16269d8b46c8SMichael Tuexen 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 16279d8b46c8SMichael Tuexen 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, 16289d8b46c8SMichael Tuexen 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 16299d8b46c8SMichael Tuexen 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, 16309d8b46c8SMichael Tuexen 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 16319d8b46c8SMichael Tuexen 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, 16329d8b46c8SMichael Tuexen 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 16339d8b46c8SMichael Tuexen 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, 16349d8b46c8SMichael Tuexen 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 16359d8b46c8SMichael Tuexen 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, 16369d8b46c8SMichael Tuexen 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 16379d8b46c8SMichael Tuexen 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, 16389d8b46c8SMichael Tuexen 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 16399d8b46c8SMichael Tuexen 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, 16409d8b46c8SMichael Tuexen 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 16419d8b46c8SMichael Tuexen 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 16429d8b46c8SMichael Tuexen 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 16439d8b46c8SMichael Tuexen 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, 16449d8b46c8SMichael Tuexen 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 16459d8b46c8SMichael Tuexen 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 16469d8b46c8SMichael Tuexen 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 16479d8b46c8SMichael Tuexen 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, 16489d8b46c8SMichael Tuexen 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 16499d8b46c8SMichael Tuexen 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, 16509d8b46c8SMichael Tuexen 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 16519d8b46c8SMichael Tuexen 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, 16529d8b46c8SMichael Tuexen 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 16539d8b46c8SMichael Tuexen 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, 16549d8b46c8SMichael Tuexen 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 16559d8b46c8SMichael Tuexen 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, 16569d8b46c8SMichael Tuexen 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 16579d8b46c8SMichael Tuexen 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, 16589d8b46c8SMichael Tuexen 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 16599d8b46c8SMichael Tuexen 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, 16609d8b46c8SMichael Tuexen 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 16619d8b46c8SMichael Tuexen 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 16629d8b46c8SMichael Tuexen 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 16639d8b46c8SMichael Tuexen 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, 16649d8b46c8SMichael Tuexen 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 16659d8b46c8SMichael Tuexen 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 16669d8b46c8SMichael Tuexen 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 16679d8b46c8SMichael Tuexen 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, 16689d8b46c8SMichael Tuexen 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 16699d8b46c8SMichael Tuexen 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, 16709d8b46c8SMichael Tuexen 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 16719d8b46c8SMichael Tuexen 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 16729d8b46c8SMichael Tuexen 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 16739d8b46c8SMichael Tuexen 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 16749d8b46c8SMichael Tuexen }; 16759d8b46c8SMichael Tuexen 16769d8b46c8SMichael Tuexen u_int32_t 1677ca19d0d7SMark Johnston sctp_crc32c(void *pack, u_int32_t len) 16789d8b46c8SMichael Tuexen { 16799d8b46c8SMichael Tuexen u_int32_t i, crc32c; 16809d8b46c8SMichael Tuexen u_int8_t byte0, byte1, byte2, byte3; 1681ca19d0d7SMark Johnston u_int8_t *buf = (u_int8_t *)pack; 16829d8b46c8SMichael Tuexen 16839d8b46c8SMichael Tuexen crc32c = ~0; 16849d8b46c8SMichael Tuexen for (i = 0; i < len; i++) 16859d8b46c8SMichael Tuexen CRC32C(crc32c, buf[i]); 16869d8b46c8SMichael Tuexen crc32c = ~crc32c; 16879d8b46c8SMichael Tuexen byte0 = crc32c & 0xff; 16889d8b46c8SMichael Tuexen byte1 = (crc32c>>8) & 0xff; 16899d8b46c8SMichael Tuexen byte2 = (crc32c>>16) & 0xff; 16909d8b46c8SMichael Tuexen byte3 = (crc32c>>24) & 0xff; 16919d8b46c8SMichael Tuexen crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); 16929d8b46c8SMichael Tuexen return htonl(crc32c); 16939d8b46c8SMichael Tuexen } 16949d8b46c8SMichael Tuexen 16959d8b46c8SMichael Tuexen u_int16_t 16969d8b46c8SMichael Tuexen in_cksum(u_int16_t *addr, int len) 16979d8b46c8SMichael Tuexen { 16989d8b46c8SMichael Tuexen int nleft = len; 16999d8b46c8SMichael Tuexen u_int16_t *w = addr; 17009d8b46c8SMichael Tuexen u_int16_t answer; 17019d8b46c8SMichael Tuexen int sum = 0; 17029d8b46c8SMichael Tuexen 17039d8b46c8SMichael Tuexen /* 17049d8b46c8SMichael Tuexen * Our algorithm is simple, using a 32 bit accumulator (sum), 17059d8b46c8SMichael Tuexen * we add sequential 16 bit words to it, and at the end, fold 17069d8b46c8SMichael Tuexen * back all the carry bits from the top 16 bits into the lower 17079d8b46c8SMichael Tuexen * 16 bits. 17089d8b46c8SMichael Tuexen */ 17099d8b46c8SMichael Tuexen while (nleft > 1) { 17109d8b46c8SMichael Tuexen sum += *w++; 17119d8b46c8SMichael Tuexen nleft -= 2; 17129d8b46c8SMichael Tuexen } 17139d8b46c8SMichael Tuexen 17149d8b46c8SMichael Tuexen /* mop up an odd byte, if necessary */ 17159d8b46c8SMichael Tuexen if (nleft == 1) 17169d8b46c8SMichael Tuexen sum += *(u_char *)w; 17179d8b46c8SMichael Tuexen 17189d8b46c8SMichael Tuexen /* 17199d8b46c8SMichael Tuexen * add back carry outs from top 16 bits to low 16 bits 17209d8b46c8SMichael Tuexen */ 17219d8b46c8SMichael Tuexen sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 17229d8b46c8SMichael Tuexen sum += (sum >> 16); /* add carry */ 17239d8b46c8SMichael Tuexen answer = ~sum; /* truncate to 16 bits */ 17249d8b46c8SMichael Tuexen return (answer); 17259d8b46c8SMichael Tuexen } 17269d8b46c8SMichael Tuexen 17279d8b46c8SMichael Tuexen u_int16_t 1728cc432e23SMariusz Zaborski udp_cksum(struct sockaddr_in6 *src, struct sockaddr_in6 *dst, 1729cc432e23SMariusz Zaborski void *payload, u_int32_t len) 1730cc432e23SMariusz Zaborski { 1731cc432e23SMariusz Zaborski struct { 1732cc432e23SMariusz Zaborski struct in6_addr src; 1733cc432e23SMariusz Zaborski struct in6_addr dst; 1734cc432e23SMariusz Zaborski u_int32_t len; 1735cc432e23SMariusz Zaborski u_int8_t zero[3]; 1736cc432e23SMariusz Zaborski u_int8_t next; 1737cc432e23SMariusz Zaborski } pseudo_hdr; 1738cc432e23SMariusz Zaborski u_int16_t sum[2]; 1739cc432e23SMariusz Zaborski 1740cc432e23SMariusz Zaborski pseudo_hdr.src = src->sin6_addr; 1741cc432e23SMariusz Zaborski pseudo_hdr.dst = dst->sin6_addr; 1742cc432e23SMariusz Zaborski pseudo_hdr.len = htonl(len); 1743cc432e23SMariusz Zaborski pseudo_hdr.zero[0] = 0; 1744cc432e23SMariusz Zaborski pseudo_hdr.zero[1] = 0; 1745cc432e23SMariusz Zaborski pseudo_hdr.zero[2] = 0; 1746cc432e23SMariusz Zaborski pseudo_hdr.next = IPPROTO_UDP; 1747cc432e23SMariusz Zaborski 1748cc432e23SMariusz Zaborski sum[1] = in_cksum((u_int16_t *)&pseudo_hdr, sizeof(pseudo_hdr)); 1749cc432e23SMariusz Zaborski sum[0] = in_cksum(payload, len); 1750cc432e23SMariusz Zaborski 1751cc432e23SMariusz Zaborski return (~in_cksum(sum, sizeof(sum))); 1752cc432e23SMariusz Zaborski } 1753cc432e23SMariusz Zaborski 1754cc432e23SMariusz Zaborski u_int16_t 17559d8b46c8SMichael Tuexen tcp_chksum(struct sockaddr_in6 *src, struct sockaddr_in6 *dst, 17569d8b46c8SMichael Tuexen void *payload, u_int32_t len) 17579d8b46c8SMichael Tuexen { 17589d8b46c8SMichael Tuexen struct { 17599d8b46c8SMichael Tuexen struct in6_addr src; 17609d8b46c8SMichael Tuexen struct in6_addr dst; 17619d8b46c8SMichael Tuexen u_int32_t len; 17629d8b46c8SMichael Tuexen u_int8_t zero[3]; 17639d8b46c8SMichael Tuexen u_int8_t next; 17649d8b46c8SMichael Tuexen } pseudo_hdr; 17659d8b46c8SMichael Tuexen u_int16_t sum[2]; 17669d8b46c8SMichael Tuexen 17679d8b46c8SMichael Tuexen pseudo_hdr.src = src->sin6_addr; 17689d8b46c8SMichael Tuexen pseudo_hdr.dst = dst->sin6_addr; 17699d8b46c8SMichael Tuexen pseudo_hdr.len = htonl(len); 17709d8b46c8SMichael Tuexen pseudo_hdr.zero[0] = 0; 17719d8b46c8SMichael Tuexen pseudo_hdr.zero[1] = 0; 17729d8b46c8SMichael Tuexen pseudo_hdr.zero[2] = 0; 17739d8b46c8SMichael Tuexen pseudo_hdr.next = IPPROTO_TCP; 17749d8b46c8SMichael Tuexen 17759d8b46c8SMichael Tuexen sum[1] = in_cksum((u_int16_t *)&pseudo_hdr, sizeof(pseudo_hdr)); 17769d8b46c8SMichael Tuexen sum[0] = in_cksum(payload, len); 17779d8b46c8SMichael Tuexen 17789d8b46c8SMichael Tuexen return (~in_cksum(sum, sizeof(sum))); 17799d8b46c8SMichael Tuexen } 17809d8b46c8SMichael Tuexen 17817d56d374SYoshinobu Inoue void 1782aa96470cSMichael Tuexen usage(void) 17837d56d374SYoshinobu Inoue { 178484a1a4cfSHajimu UMEMOTO 178584a1a4cfSHajimu UMEMOTO fprintf(stderr, 17869d8b46c8SMichael Tuexen "usage: traceroute6 [-adIlnNrSTUv] [-A as_server] [-f firsthop] [-g gateway]\n" 17870d7d117cSHajimu UMEMOTO " [-m hoplimit] [-p port] [-q probes] [-s src] [-w waittime] target\n" 17880d7d117cSHajimu UMEMOTO " [datalen]\n"); 17897d56d374SYoshinobu Inoue exit(1); 17907d56d374SYoshinobu Inoue } 1791