1e961704aSDavid Malone /* $KAME: traceroute6.c,v 1.68 2004/01/25 11:16:12 suz Exp $ */ 2de68a0daSKris Kennaway 38a16b7a1SPedro F. Giffuni /*- 48a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 58a16b7a1SPedro F. Giffuni * 67d56d374SYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 77d56d374SYoshinobu Inoue * All rights reserved. 87d56d374SYoshinobu Inoue * 97d56d374SYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 107d56d374SYoshinobu Inoue * modification, are permitted provided that the following conditions 117d56d374SYoshinobu Inoue * are met: 127d56d374SYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 137d56d374SYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 147d56d374SYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 157d56d374SYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 167d56d374SYoshinobu Inoue * documentation and/or other materials provided with the distribution. 177d56d374SYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 187d56d374SYoshinobu Inoue * may be used to endorse or promote products derived from this software 197d56d374SYoshinobu Inoue * without specific prior written permission. 207d56d374SYoshinobu Inoue * 217d56d374SYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 227d56d374SYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 237d56d374SYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 247d56d374SYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 257d56d374SYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 267d56d374SYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 277d56d374SYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 287d56d374SYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 297d56d374SYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 307d56d374SYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 317d56d374SYoshinobu Inoue * SUCH DAMAGE. 327d56d374SYoshinobu Inoue */ 337d56d374SYoshinobu Inoue 347d56d374SYoshinobu Inoue /*- 357d56d374SYoshinobu Inoue * Copyright (c) 1990, 1993 367d56d374SYoshinobu Inoue * The Regents of the University of California. All rights reserved. 377d56d374SYoshinobu Inoue * 387d56d374SYoshinobu Inoue * This code is derived from software contributed to Berkeley by 397d56d374SYoshinobu Inoue * Van Jacobson. 407d56d374SYoshinobu Inoue * 417d56d374SYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 427d56d374SYoshinobu Inoue * modification, are permitted provided that the following conditions 437d56d374SYoshinobu Inoue * are met: 447d56d374SYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 457d56d374SYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 467d56d374SYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 477d56d374SYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 487d56d374SYoshinobu Inoue * documentation and/or other materials provided with the distribution. 49fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 507d56d374SYoshinobu Inoue * may be used to endorse or promote products derived from this software 517d56d374SYoshinobu Inoue * without specific prior written permission. 527d56d374SYoshinobu Inoue * 537d56d374SYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 547d56d374SYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 557d56d374SYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 567d56d374SYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 577d56d374SYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 587d56d374SYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 597d56d374SYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 607d56d374SYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 617d56d374SYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 627d56d374SYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 637d56d374SYoshinobu Inoue * SUCH DAMAGE. 647d56d374SYoshinobu Inoue */ 657d56d374SYoshinobu Inoue 667d56d374SYoshinobu Inoue /* 677d56d374SYoshinobu Inoue * traceroute host - trace the route ip packets follow going to "host". 687d56d374SYoshinobu Inoue * 697d56d374SYoshinobu Inoue * Attempt to trace the route an ip packet would follow to some 707d56d374SYoshinobu Inoue * internet host. We find out intermediate hops by launching probe 717d56d374SYoshinobu Inoue * packets with a small ttl (time to live) then listening for an 727d56d374SYoshinobu Inoue * icmp "time exceeded" reply from a gateway. We start our probes 737d56d374SYoshinobu Inoue * with a ttl of one and increase by one until we get an icmp "port 747d56d374SYoshinobu Inoue * unreachable" (which means we got to "host") or hit a max (which 757d56d374SYoshinobu Inoue * defaults to 30 hops & can be changed with the -m flag). Three 767d56d374SYoshinobu Inoue * probes (change with -q flag) are sent at each ttl setting and a 777d56d374SYoshinobu Inoue * line is printed showing the ttl, address of the gateway and 787d56d374SYoshinobu Inoue * round trip time of each probe. If the probe answers come from 797d56d374SYoshinobu Inoue * different gateways, the address of each responding system will 807d56d374SYoshinobu Inoue * be printed. If there is no response within a 5 sec. timeout 817d56d374SYoshinobu Inoue * interval (changed with the -w flag), a "*" is printed for that 827d56d374SYoshinobu Inoue * probe. 837d56d374SYoshinobu Inoue * 847d56d374SYoshinobu Inoue * Probe packets are UDP format. We don't want the destination 857d56d374SYoshinobu Inoue * host to process them so the destination port is set to an 867d56d374SYoshinobu Inoue * unlikely value (if some clod on the destination is using that 877d56d374SYoshinobu Inoue * value, it can be changed with the -p flag). 887d56d374SYoshinobu Inoue * 897d56d374SYoshinobu Inoue * A sample use might be: 907d56d374SYoshinobu Inoue * 917d56d374SYoshinobu Inoue * [yak 71]% traceroute nis.nsf.net. 927d56d374SYoshinobu Inoue * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet 937d56d374SYoshinobu Inoue * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms 947d56d374SYoshinobu Inoue * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 957d56d374SYoshinobu Inoue * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 967d56d374SYoshinobu Inoue * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms 977d56d374SYoshinobu Inoue * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms 987d56d374SYoshinobu Inoue * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms 997d56d374SYoshinobu Inoue * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms 1007d56d374SYoshinobu Inoue * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms 1017d56d374SYoshinobu Inoue * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms 1027d56d374SYoshinobu Inoue * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms 1037d56d374SYoshinobu Inoue * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms 1047d56d374SYoshinobu Inoue * 1057d56d374SYoshinobu Inoue * Note that lines 2 & 3 are the same. This is due to a buggy 1067d56d374SYoshinobu Inoue * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards 1077d56d374SYoshinobu Inoue * packets with a zero ttl. 1087d56d374SYoshinobu Inoue * 1097d56d374SYoshinobu Inoue * A more interesting example is: 1107d56d374SYoshinobu Inoue * 1117d56d374SYoshinobu Inoue * [yak 72]% traceroute allspice.lcs.mit.edu. 1127d56d374SYoshinobu Inoue * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max 1137d56d374SYoshinobu Inoue * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 1147d56d374SYoshinobu Inoue * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms 1157d56d374SYoshinobu Inoue * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms 1167d56d374SYoshinobu Inoue * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms 1177d56d374SYoshinobu Inoue * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms 1187d56d374SYoshinobu Inoue * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms 1197d56d374SYoshinobu Inoue * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms 1207d56d374SYoshinobu Inoue * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms 1217d56d374SYoshinobu Inoue * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms 1227d56d374SYoshinobu Inoue * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms 1237d56d374SYoshinobu Inoue * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms 1247d56d374SYoshinobu Inoue * 12 * * * 1257d56d374SYoshinobu Inoue * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms 1267d56d374SYoshinobu Inoue * 14 * * * 1277d56d374SYoshinobu Inoue * 15 * * * 1287d56d374SYoshinobu Inoue * 16 * * * 1297d56d374SYoshinobu Inoue * 17 * * * 1307d56d374SYoshinobu Inoue * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms 1317d56d374SYoshinobu Inoue * 1327d56d374SYoshinobu Inoue * (I start to see why I'm having so much trouble with mail to 1337d56d374SYoshinobu Inoue * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away 1347d56d374SYoshinobu Inoue * either don't send ICMP "time exceeded" messages or send them 1357d56d374SYoshinobu Inoue * with a ttl too small to reach us. 14 - 17 are running the 1367d56d374SYoshinobu Inoue * MIT C Gateway code that doesn't send "time exceeded"s. God 1377d56d374SYoshinobu Inoue * only knows what's going on with 12. 1387d56d374SYoshinobu Inoue * 1397d56d374SYoshinobu Inoue * The silent gateway 12 in the above may be the result of a bug in 1407d56d374SYoshinobu Inoue * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) 1417d56d374SYoshinobu Inoue * sends an unreachable message using whatever ttl remains in the 1427d56d374SYoshinobu Inoue * original datagram. Since, for gateways, the remaining ttl is 1437d56d374SYoshinobu Inoue * zero, the icmp "time exceeded" is guaranteed to not make it back 1447d56d374SYoshinobu Inoue * to us. The behavior of this bug is slightly more interesting 1457d56d374SYoshinobu Inoue * when it appears on the destination system: 1467d56d374SYoshinobu Inoue * 1477d56d374SYoshinobu Inoue * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 1487d56d374SYoshinobu Inoue * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms 1497d56d374SYoshinobu Inoue * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms 1507d56d374SYoshinobu Inoue * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms 1517d56d374SYoshinobu Inoue * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms 1527d56d374SYoshinobu Inoue * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms 1537d56d374SYoshinobu Inoue * 7 * * * 1547d56d374SYoshinobu Inoue * 8 * * * 1557d56d374SYoshinobu Inoue * 9 * * * 1567d56d374SYoshinobu Inoue * 10 * * * 1577d56d374SYoshinobu Inoue * 11 * * * 1587d56d374SYoshinobu Inoue * 12 * * * 1597d56d374SYoshinobu Inoue * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! 1607d56d374SYoshinobu Inoue * 1617d56d374SYoshinobu Inoue * Notice that there are 12 "gateways" (13 is the final 1627d56d374SYoshinobu Inoue * destination) and exactly the last half of them are "missing". 1637d56d374SYoshinobu Inoue * What's really happening is that rip (a Sun-3 running Sun OS3.5) 1647d56d374SYoshinobu Inoue * is using the ttl from our arriving datagram as the ttl in its 1657d56d374SYoshinobu Inoue * icmp reply. So, the reply will time out on the return path 1667d56d374SYoshinobu Inoue * (with no notice sent to anyone since icmp's aren't sent for 1677d56d374SYoshinobu Inoue * icmp's) until we probe with a ttl that's at least twice the path 1687d56d374SYoshinobu Inoue * length. I.e., rip is really only 7 hops away. A reply that 1697d56d374SYoshinobu Inoue * returns with a ttl of 1 is a clue this problem exists. 1707d56d374SYoshinobu Inoue * Traceroute prints a "!" after the time if the ttl is <= 1. 1717d56d374SYoshinobu Inoue * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or 1727d56d374SYoshinobu Inoue * non-standard (HPUX) software, expect to see this problem 1737d56d374SYoshinobu Inoue * frequently and/or take care picking the target host of your 1747d56d374SYoshinobu Inoue * probes. 1757d56d374SYoshinobu Inoue * 1767d56d374SYoshinobu Inoue * Other possible annotations after the time are !H, !N, !P (got a host, 1777d56d374SYoshinobu Inoue * network or protocol unreachable, respectively), !S or !F (source 1787d56d374SYoshinobu Inoue * route failed or fragmentation needed -- neither of these should 1797d56d374SYoshinobu Inoue * ever occur and the associated gateway is busted if you see one). If 1807d56d374SYoshinobu Inoue * almost all the probes result in some kind of unreachable, traceroute 1817d56d374SYoshinobu Inoue * will give up and exit. 1827d56d374SYoshinobu Inoue * 1837d56d374SYoshinobu Inoue * Notes 1847d56d374SYoshinobu Inoue * ----- 1857d56d374SYoshinobu Inoue * This program must be run by root or be setuid. (I suggest that 1867d56d374SYoshinobu Inoue * you *don't* make it setuid -- casual use could result in a lot 1877d56d374SYoshinobu Inoue * of unnecessary traffic on our poor, congested nets.) 1887d56d374SYoshinobu Inoue * 1897d56d374SYoshinobu Inoue * This program requires a kernel mod that does not appear in any 1907d56d374SYoshinobu Inoue * system available from Berkeley: A raw ip socket using proto 1917d56d374SYoshinobu Inoue * IPPROTO_RAW must interpret the data sent as an ip datagram (as 1929d5abbddSJens Schweikhardt * opposed to data to be wrapped in an ip datagram). See the README 1937d56d374SYoshinobu Inoue * file that came with the source to this program for a description 1947d56d374SYoshinobu Inoue * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may 1957d56d374SYoshinobu Inoue * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE 1967d56d374SYoshinobu Inoue * MODIFIED TO RUN THIS PROGRAM. 1977d56d374SYoshinobu Inoue * 1987d56d374SYoshinobu Inoue * The udp port usage may appear bizarre (well, ok, it is bizarre). 1997d56d374SYoshinobu Inoue * The problem is that an icmp message only contains 8 bytes of 2007d56d374SYoshinobu Inoue * data from the original datagram. 8 bytes is the size of a udp 2017d56d374SYoshinobu Inoue * header so, if we want to associate replies with the original 2027d56d374SYoshinobu Inoue * datagram, the necessary information must be encoded into the 2037d56d374SYoshinobu Inoue * udp header (the ip id could be used but there's no way to 2047d56d374SYoshinobu Inoue * interlock with the kernel's assignment of ip id's and, anyway, 2057d56d374SYoshinobu Inoue * it would have taken a lot more kernel hacking to allow this 2067d56d374SYoshinobu Inoue * code to set the ip id). So, to allow two or more users to 2077d56d374SYoshinobu Inoue * use traceroute simultaneously, we use this task's pid as the 2087d56d374SYoshinobu Inoue * source port (the high bit is set to move the port number out 2097d56d374SYoshinobu Inoue * of the "likely" range). To keep track of which probe is being 2107d56d374SYoshinobu Inoue * replied to (so times and/or hop counts don't get confused by a 2117d56d374SYoshinobu Inoue * reply that was delayed in transit), we increment the destination 2127d56d374SYoshinobu Inoue * port number before each probe. 2137d56d374SYoshinobu Inoue * 2147d56d374SYoshinobu Inoue * Don't use this as a coding example. I was trying to find a 2157d56d374SYoshinobu Inoue * routing problem and this code sort-of popped out after 48 hours 2167d56d374SYoshinobu Inoue * without sleep. I was amazed it ever compiled, much less ran. 2177d56d374SYoshinobu Inoue * 2187d56d374SYoshinobu Inoue * I stole the idea for this program from Steve Deering. Since 2197d56d374SYoshinobu Inoue * the first release, I've learned that had I attended the right 2207d56d374SYoshinobu Inoue * IETF working group meetings, I also could have stolen it from Guy 2217d56d374SYoshinobu Inoue * Almes or Matt Mathis. I don't know (or care) who came up with 2227d56d374SYoshinobu Inoue * the idea first. I envy the originators' perspicacity and I'm 2237d56d374SYoshinobu Inoue * glad they didn't keep the idea a secret. 2247d56d374SYoshinobu Inoue * 2257d56d374SYoshinobu Inoue * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or 2267d56d374SYoshinobu Inoue * enhancements to the original distribution. 2277d56d374SYoshinobu Inoue * 2287d56d374SYoshinobu Inoue * I've hacked up a round-trip-route version of this that works by 2297d56d374SYoshinobu Inoue * sending a loose-source-routed udp datagram through the destination 2307d56d374SYoshinobu Inoue * back to yourself. Unfortunately, SO many gateways botch source 2317d56d374SYoshinobu Inoue * routing, the thing is almost worthless. Maybe one day... 2327d56d374SYoshinobu Inoue * 2337d56d374SYoshinobu Inoue * -- Van Jacobson (van@helios.ee.lbl.gov) 2347d56d374SYoshinobu Inoue * Tue Dec 20 03:50:13 PST 1988 2357d56d374SYoshinobu Inoue */ 2367d56d374SYoshinobu Inoue 2377d56d374SYoshinobu Inoue #include <sys/param.h> 238cc432e23SMariusz Zaborski #include <sys/capsicum.h> 2397d56d374SYoshinobu Inoue #include <sys/time.h> 2407d56d374SYoshinobu Inoue #include <sys/socket.h> 2417d56d374SYoshinobu Inoue #include <sys/uio.h> 2427d56d374SYoshinobu Inoue #include <sys/file.h> 2437d56d374SYoshinobu Inoue #include <sys/ioctl.h> 24484a1a4cfSHajimu UMEMOTO #include <sys/sysctl.h> 2457d56d374SYoshinobu Inoue 2467d56d374SYoshinobu Inoue #include <netinet/in.h> 2477d56d374SYoshinobu Inoue 2487d56d374SYoshinobu Inoue #include <arpa/inet.h> 2497d56d374SYoshinobu Inoue 250cc432e23SMariusz Zaborski #include <libcasper.h> 251cc432e23SMariusz Zaborski #include <casper/cap_dns.h> 252cc432e23SMariusz Zaborski #include <capsicum_helpers.h> 253cc432e23SMariusz Zaborski 2547d56d374SYoshinobu Inoue #include <netdb.h> 2557d56d374SYoshinobu Inoue #include <stdio.h> 2567d56d374SYoshinobu Inoue #include <err.h> 2572a1c5efaSKris Kennaway #ifdef HAVE_POLL 2582a1c5efaSKris Kennaway #include <poll.h> 2592a1c5efaSKris Kennaway #endif 2607d56d374SYoshinobu Inoue #include <errno.h> 2617d56d374SYoshinobu Inoue #include <stdlib.h> 2627d56d374SYoshinobu Inoue #include <string.h> 2637d56d374SYoshinobu Inoue #include <unistd.h> 2647d56d374SYoshinobu Inoue 265*0c2218d1SJose Luis Duran #include <netinet/ip.h> 2667d56d374SYoshinobu Inoue #include <netinet/ip6.h> 2677d56d374SYoshinobu Inoue #include <netinet/icmp6.h> 2689d8b46c8SMichael Tuexen #include <netinet/sctp.h> 26951eff8efSMichael Tuexen #include <netinet/sctp_header.h> 2709d8b46c8SMichael Tuexen #include <netinet/tcp.h> 2717d56d374SYoshinobu Inoue #include <netinet/udp.h> 2727d56d374SYoshinobu Inoue 2737d56d374SYoshinobu Inoue #ifdef IPSEC 2747d56d374SYoshinobu Inoue #include <net/route.h> 2758409aedfSGeorge V. Neville-Neil #include <netipsec/ipsec.h> 2767d56d374SYoshinobu Inoue #endif 2777d56d374SYoshinobu Inoue 278d429d720SHajimu UMEMOTO #include "as.h" 279d429d720SHajimu UMEMOTO 2807d56d374SYoshinobu Inoue #define DUMMY_PORT 10010 2817d56d374SYoshinobu Inoue 2827d56d374SYoshinobu Inoue #define MAXPACKET 65535 /* max ip packet size */ 2837d56d374SYoshinobu Inoue 284ca19d0d7SMark Johnston static u_char packet[512]; /* last inbound (icmp) packet */ 285ca19d0d7SMark Johnston static char *outpacket; /* last output packet */ 2867d56d374SYoshinobu Inoue 287784bddbcSKevin Lo int main(int, char *[]); 288784bddbcSKevin Lo int wait_for_reply(int, struct msghdr *); 289ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 290784bddbcSKevin Lo int setpolicy(int so, char *policy); 291de68a0daSKris Kennaway #endif 292784bddbcSKevin Lo void send_probe(int, u_long); 293d7b63fafSDavid Malone void *get_uphdr(struct ip6_hdr *, u_char *); 294cc432e23SMariusz Zaborski void capdns_open(void); 295784bddbcSKevin Lo int get_hoplim(struct msghdr *); 296784bddbcSKevin Lo double deltaT(struct timeval *, struct timeval *); 297f42640a3SUlrich Spörlein const char *pr_type(int); 298*0c2218d1SJose Luis Duran int packet_ok(struct msghdr *, int, int, u_char *, u_char *, u_char *); 299784bddbcSKevin Lo void print(struct msghdr *, int); 300784bddbcSKevin Lo const char *inetname(struct sockaddr *); 3019d8b46c8SMichael Tuexen u_int32_t sctp_crc32c(void *, u_int32_t); 3029d8b46c8SMichael Tuexen u_int16_t in_cksum(u_int16_t *addr, int); 303cc432e23SMariusz Zaborski u_int16_t udp_cksum(struct sockaddr_in6 *, struct sockaddr_in6 *, 304cc432e23SMariusz Zaborski void *, u_int32_t); 3059d8b46c8SMichael Tuexen u_int16_t tcp_chksum(struct sockaddr_in6 *, struct sockaddr_in6 *, 3069d8b46c8SMichael Tuexen void *, u_int32_t); 307784bddbcSKevin Lo void usage(void); 3087d56d374SYoshinobu Inoue 309ca19d0d7SMark Johnston static int rcvsock; /* receive (icmp) socket file descriptor */ 310ca19d0d7SMark Johnston static int sndsock; /* send (raw/udp) socket file descriptor */ 3117d56d374SYoshinobu Inoue 312ca19d0d7SMark Johnston static struct msghdr rcvmhdr; 313ca19d0d7SMark Johnston static struct iovec rcviov[2]; 314ca19d0d7SMark Johnston static int rcvhlim; 315ca19d0d7SMark Johnston static struct in6_pktinfo *rcvpktinfo; 3167d56d374SYoshinobu Inoue 317ca19d0d7SMark Johnston static struct sockaddr_in6 Src, Dst, Rcv; 318ca19d0d7SMark Johnston static u_long datalen = 20; /* How much data */ 31984a1a4cfSHajimu UMEMOTO #define ICMP6ECHOLEN 8 320de68a0daSKris Kennaway /* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */ 321ca19d0d7SMark Johnston static char rtbuf[2064]; 322ca19d0d7SMark Johnston static struct ip6_rthdr *rth; 323ca19d0d7SMark Johnston static struct cmsghdr *cmsg; 3247d56d374SYoshinobu Inoue 325ca19d0d7SMark Johnston static char *source = NULL; 326ca19d0d7SMark Johnston static char *hostname; 3277d56d374SYoshinobu Inoue 328cc432e23SMariusz Zaborski static cap_channel_t *capdns; 329cc432e23SMariusz Zaborski 330ca19d0d7SMark Johnston static u_long nprobes = 3; 331ca19d0d7SMark Johnston static u_long first_hop = 1; 332ca19d0d7SMark Johnston static u_long max_hops = 30; 333ca19d0d7SMark Johnston static u_int16_t srcport; 334ca19d0d7SMark Johnston static u_int16_t port = 32768 + 666; /* start udp dest port # for probe packets */ 335ca19d0d7SMark Johnston static u_int16_t ident; 336c7090651SMichael Tuexen static int tclass = -1; 337ca19d0d7SMark Johnston static int options; /* socket options */ 338ca19d0d7SMark Johnston static int verbose; 339ca19d0d7SMark Johnston static int waittime = 5; /* time to wait for response (in seconds) */ 340ca19d0d7SMark Johnston static int nflag; /* print addresses numerically */ 341ca19d0d7SMark Johnston static int useproto = IPPROTO_UDP; /* protocol to use to send packet */ 342ca19d0d7SMark Johnston static int lflag; /* print both numerical address & hostname */ 343ca19d0d7SMark Johnston static int as_path; /* print as numbers for each hop */ 344*0c2218d1SJose Luis Duran static int ecnflag; /* ECN bleaching detection flag */ 345ca19d0d7SMark Johnston static char *as_server = NULL; 346ca19d0d7SMark Johnston static void *asn; 3477d56d374SYoshinobu Inoue 3487d56d374SYoshinobu Inoue int 349aa96470cSMichael Tuexen main(int argc, char *argv[]) 3507d56d374SYoshinobu Inoue { 35184a1a4cfSHajimu UMEMOTO int mib[4] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM }; 352e961704aSDavid Malone char hbuf[NI_MAXHOST], src0[NI_MAXHOST], *ep; 353f42640a3SUlrich Spörlein int ch, i, on = 1, seq, rcvcmsglen, error; 354e961704aSDavid Malone struct addrinfo hints, *res; 355e961704aSDavid Malone static u_char *rcvcmsgbuf; 356c7090651SMichael Tuexen u_long probe, hops, lport, ltclass; 357e961704aSDavid Malone struct hostent *hp; 358f42640a3SUlrich Spörlein size_t size, minlen; 35919c7ed84SKevin Lo uid_t uid; 360*0c2218d1SJose Luis Duran u_char type, code, ecn; 361ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 362ca19d0d7SMark Johnston char ipsec_inpolicy[] = "in bypass"; 363ca19d0d7SMark Johnston char ipsec_outpolicy[] = "out bypass"; 364ca19d0d7SMark Johnston #endif 365cc432e23SMariusz Zaborski cap_rights_t rights; 366cc432e23SMariusz Zaborski 367cc432e23SMariusz Zaborski capdns_open(); 3687d56d374SYoshinobu Inoue 36953c9088fSYoshinobu Inoue /* 37053c9088fSYoshinobu Inoue * Receive ICMP 37153c9088fSYoshinobu Inoue */ 37253c9088fSYoshinobu Inoue if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 373de68a0daSKris Kennaway perror("socket(ICMPv6)"); 37453c9088fSYoshinobu Inoue exit(5); 37553c9088fSYoshinobu Inoue } 376de68a0daSKris Kennaway 37784a1a4cfSHajimu UMEMOTO size = sizeof(i); 37884a1a4cfSHajimu UMEMOTO (void) sysctl(mib, sizeof(mib) / sizeof(mib[0]), &i, &size, NULL, 0); 37984a1a4cfSHajimu UMEMOTO max_hops = i; 38084a1a4cfSHajimu UMEMOTO 381de68a0daSKris Kennaway /* specify to tell receiving interface */ 382de68a0daSKris Kennaway #ifdef IPV6_RECVPKTINFO 383de68a0daSKris Kennaway if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 384de68a0daSKris Kennaway sizeof(on)) < 0) 385de68a0daSKris Kennaway err(1, "setsockopt(IPV6_RECVPKTINFO)"); 386de68a0daSKris Kennaway #else /* old adv. API */ 387de68a0daSKris Kennaway if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_PKTINFO, &on, 388de68a0daSKris Kennaway sizeof(on)) < 0) 389de68a0daSKris Kennaway err(1, "setsockopt(IPV6_PKTINFO)"); 390de68a0daSKris Kennaway #endif 391de68a0daSKris Kennaway 392de68a0daSKris Kennaway /* specify to tell value of hoplimit field of received IP6 hdr */ 393de68a0daSKris Kennaway #ifdef IPV6_RECVHOPLIMIT 394de68a0daSKris Kennaway if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, 395de68a0daSKris Kennaway sizeof(on)) < 0) 396de68a0daSKris Kennaway err(1, "setsockopt(IPV6_RECVHOPLIMIT)"); 397de68a0daSKris Kennaway #else /* old adv. API */ 398de68a0daSKris Kennaway if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, 399de68a0daSKris Kennaway sizeof(on)) < 0) 400de68a0daSKris Kennaway err(1, "setsockopt(IPV6_HOPLIMIT)"); 401de68a0daSKris Kennaway #endif 402de68a0daSKris Kennaway 4037d56d374SYoshinobu Inoue seq = 0; 4049d8b46c8SMichael Tuexen ident = htons(getpid() & 0xffff); /* same as ping6 */ 4057d56d374SYoshinobu Inoue 406*0c2218d1SJose Luis Duran while ((ch = getopt(argc, argv, "aA:dEf:g:Ilm:nNp:q:rs:St:TUvw:")) != -1) 4077d56d374SYoshinobu Inoue switch (ch) { 408d429d720SHajimu UMEMOTO case 'a': 409d429d720SHajimu UMEMOTO as_path = 1; 410d429d720SHajimu UMEMOTO break; 411d429d720SHajimu UMEMOTO case 'A': 412d429d720SHajimu UMEMOTO as_path = 1; 413d429d720SHajimu UMEMOTO as_server = optarg; 414d429d720SHajimu UMEMOTO break; 4157d56d374SYoshinobu Inoue case 'd': 4167d56d374SYoshinobu Inoue options |= SO_DEBUG; 4177d56d374SYoshinobu Inoue break; 418*0c2218d1SJose Luis Duran case 'E': 419*0c2218d1SJose Luis Duran ecnflag = 1; 420*0c2218d1SJose Luis Duran break; 421de68a0daSKris Kennaway case 'f': 42233841545SHajimu UMEMOTO ep = NULL; 42384a1a4cfSHajimu UMEMOTO errno = 0; 42433841545SHajimu UMEMOTO first_hop = strtoul(optarg, &ep, 0); 42584a1a4cfSHajimu UMEMOTO if (errno || !*optarg || *ep || first_hop > 255) { 426c449e284SHajimu UMEMOTO fprintf(stderr, 42733841545SHajimu UMEMOTO "traceroute6: invalid min hoplimit.\n"); 42833841545SHajimu UMEMOTO exit(1); 42933841545SHajimu UMEMOTO } 4307d56d374SYoshinobu Inoue break; 4317d56d374SYoshinobu Inoue case 'g': 432cc432e23SMariusz Zaborski /* XXX use after capability mode is entered */ 4337d56d374SYoshinobu Inoue hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno); 4347d56d374SYoshinobu Inoue if (hp == NULL) { 435c449e284SHajimu UMEMOTO fprintf(stderr, 4367d56d374SYoshinobu Inoue "traceroute6: unknown host %s\n", optarg); 4377d56d374SYoshinobu Inoue exit(1); 4387d56d374SYoshinobu Inoue } 439de68a0daSKris Kennaway if (rth == NULL) { 440de68a0daSKris Kennaway /* 441de68a0daSKris Kennaway * XXX: We can't detect the number of 442de68a0daSKris Kennaway * intermediate nodes yet. 443de68a0daSKris Kennaway */ 444de68a0daSKris Kennaway if ((rth = inet6_rth_init((void *)rtbuf, 445c449e284SHajimu UMEMOTO sizeof(rtbuf), IPV6_RTHDR_TYPE_0, 446de68a0daSKris Kennaway 0)) == NULL) { 447c449e284SHajimu UMEMOTO fprintf(stderr, 448de68a0daSKris Kennaway "inet6_rth_init failed.\n"); 449de68a0daSKris Kennaway exit(1); 450de68a0daSKris Kennaway } 451de68a0daSKris Kennaway } 452de68a0daSKris Kennaway if (inet6_rth_add((void *)rth, 453de68a0daSKris Kennaway (struct in6_addr *)hp->h_addr)) { 454c449e284SHajimu UMEMOTO fprintf(stderr, 455de68a0daSKris Kennaway "inet6_rth_add failed for %s\n", 456de68a0daSKris Kennaway optarg); 457de68a0daSKris Kennaway exit(1); 458de68a0daSKris Kennaway } 459de68a0daSKris Kennaway freehostent(hp); 460de68a0daSKris Kennaway break; 46184a1a4cfSHajimu UMEMOTO case 'I': 462d7b63fafSDavid Malone useproto = IPPROTO_ICMPV6; 46384a1a4cfSHajimu UMEMOTO break; 464de68a0daSKris Kennaway case 'l': 465de68a0daSKris Kennaway lflag++; 4667d56d374SYoshinobu Inoue break; 4677d56d374SYoshinobu Inoue case 'm': 46833841545SHajimu UMEMOTO ep = NULL; 46984a1a4cfSHajimu UMEMOTO errno = 0; 47033841545SHajimu UMEMOTO max_hops = strtoul(optarg, &ep, 0); 47184a1a4cfSHajimu UMEMOTO if (errno || !*optarg || *ep || max_hops > 255) { 472c449e284SHajimu UMEMOTO fprintf(stderr, 47333841545SHajimu UMEMOTO "traceroute6: invalid max hoplimit.\n"); 47433841545SHajimu UMEMOTO exit(1); 47533841545SHajimu UMEMOTO } 4767d56d374SYoshinobu Inoue break; 4777d56d374SYoshinobu Inoue case 'n': 4787d56d374SYoshinobu Inoue nflag++; 4797d56d374SYoshinobu Inoue break; 480d7b63fafSDavid Malone case 'N': 481d7b63fafSDavid Malone useproto = IPPROTO_NONE; 482d7b63fafSDavid Malone break; 4837d56d374SYoshinobu Inoue case 'p': 48433841545SHajimu UMEMOTO ep = NULL; 48584a1a4cfSHajimu UMEMOTO errno = 0; 48684a1a4cfSHajimu UMEMOTO lport = strtoul(optarg, &ep, 0); 48784a1a4cfSHajimu UMEMOTO if (errno || !*optarg || *ep) { 48884a1a4cfSHajimu UMEMOTO fprintf(stderr, "traceroute6: invalid port.\n"); 48933841545SHajimu UMEMOTO exit(1); 49033841545SHajimu UMEMOTO } 49184a1a4cfSHajimu UMEMOTO if (lport == 0 || lport != (lport & 0xffff)) { 492c449e284SHajimu UMEMOTO fprintf(stderr, 49384a1a4cfSHajimu UMEMOTO "traceroute6: port out of range.\n"); 4947d56d374SYoshinobu Inoue exit(1); 4957d56d374SYoshinobu Inoue } 49684a1a4cfSHajimu UMEMOTO port = lport & 0xffff; 4977d56d374SYoshinobu Inoue break; 4987d56d374SYoshinobu Inoue case 'q': 49933841545SHajimu UMEMOTO ep = NULL; 50084a1a4cfSHajimu UMEMOTO errno = 0; 50133841545SHajimu UMEMOTO nprobes = strtoul(optarg, &ep, 0); 50284a1a4cfSHajimu UMEMOTO if (errno || !*optarg || *ep) { 503c449e284SHajimu UMEMOTO fprintf(stderr, 50433841545SHajimu UMEMOTO "traceroute6: invalid nprobes.\n"); 50533841545SHajimu UMEMOTO exit(1); 50633841545SHajimu UMEMOTO } 5077d56d374SYoshinobu Inoue if (nprobes < 1) { 508c449e284SHajimu UMEMOTO fprintf(stderr, 5097d56d374SYoshinobu Inoue "traceroute6: nprobes must be >0.\n"); 5107d56d374SYoshinobu Inoue exit(1); 5117d56d374SYoshinobu Inoue } 5127d56d374SYoshinobu Inoue break; 5137d56d374SYoshinobu Inoue case 'r': 5147d56d374SYoshinobu Inoue options |= SO_DONTROUTE; 5157d56d374SYoshinobu Inoue break; 5167d56d374SYoshinobu Inoue case 's': 5177d56d374SYoshinobu Inoue /* 5187d56d374SYoshinobu Inoue * set the ip source address of the outbound 5197d56d374SYoshinobu Inoue * probe (e.g., on a multi-homed host). 5207d56d374SYoshinobu Inoue */ 5217d56d374SYoshinobu Inoue source = optarg; 5227d56d374SYoshinobu Inoue break; 5239d8b46c8SMichael Tuexen case 'S': 5249d8b46c8SMichael Tuexen useproto = IPPROTO_SCTP; 5259d8b46c8SMichael Tuexen break; 526c7090651SMichael Tuexen case 't': 527c7090651SMichael Tuexen ep = NULL; 528c7090651SMichael Tuexen errno = 0; 529c7090651SMichael Tuexen ltclass = strtoul(optarg, &ep, 0); 530c7090651SMichael Tuexen if (errno || !*optarg || *ep || ltclass > 255) { 531c7090651SMichael Tuexen fprintf(stderr, 532c7090651SMichael Tuexen "traceroute6: invalid traffic class.\n"); 533c7090651SMichael Tuexen exit(1); 534c7090651SMichael Tuexen } 535c7090651SMichael Tuexen tclass = (int)ltclass; 536c7090651SMichael Tuexen break; 5379d8b46c8SMichael Tuexen case 'T': 5389d8b46c8SMichael Tuexen useproto = IPPROTO_TCP; 5399d8b46c8SMichael Tuexen break; 540d7b63fafSDavid Malone case 'U': 541d7b63fafSDavid Malone useproto = IPPROTO_UDP; 542d7b63fafSDavid Malone break; 543aa96470cSMichael Tuexen case 'v': 544aa96470cSMichael Tuexen verbose++; 545aa96470cSMichael Tuexen break; 5467d56d374SYoshinobu Inoue case 'w': 54733841545SHajimu UMEMOTO ep = NULL; 54884a1a4cfSHajimu UMEMOTO errno = 0; 54933841545SHajimu UMEMOTO waittime = strtoul(optarg, &ep, 0); 55084a1a4cfSHajimu UMEMOTO if (errno || !*optarg || *ep) { 551c449e284SHajimu UMEMOTO fprintf(stderr, 55233841545SHajimu UMEMOTO "traceroute6: invalid wait time.\n"); 55333841545SHajimu UMEMOTO exit(1); 55433841545SHajimu UMEMOTO } 555eea319c4SMaxim Konovalov if (waittime < 1) { 556c449e284SHajimu UMEMOTO fprintf(stderr, 557eea319c4SMaxim Konovalov "traceroute6: wait must be >= 1 sec.\n"); 5587d56d374SYoshinobu Inoue exit(1); 5597d56d374SYoshinobu Inoue } 5607d56d374SYoshinobu Inoue break; 5617d56d374SYoshinobu Inoue default: 5627d56d374SYoshinobu Inoue usage(); 5637d56d374SYoshinobu Inoue } 5647d56d374SYoshinobu Inoue argc -= optind; 5657d56d374SYoshinobu Inoue argv += optind; 5667d56d374SYoshinobu Inoue 567d7b63fafSDavid Malone /* 568d7b63fafSDavid Malone * Open socket to send probe packets. 569d7b63fafSDavid Malone */ 570d7b63fafSDavid Malone switch (useproto) { 571d7b63fafSDavid Malone case IPPROTO_ICMPV6: 572d7b63fafSDavid Malone case IPPROTO_NONE: 5739d8b46c8SMichael Tuexen case IPPROTO_SCTP: 5749d8b46c8SMichael Tuexen case IPPROTO_TCP: 5752d0fb1b3SMichael Tuexen case IPPROTO_UDP: 5769d8b46c8SMichael Tuexen if ((sndsock = socket(AF_INET6, SOCK_RAW, useproto)) < 0) { 577d7b63fafSDavid Malone perror("socket(SOCK_RAW)"); 578d7b63fafSDavid Malone exit(5); 579d7b63fafSDavid Malone } 580d7b63fafSDavid Malone break; 581d7b63fafSDavid Malone default: 582aa96470cSMichael Tuexen fprintf(stderr, "traceroute6: unknown probe protocol %d\n", 583d7b63fafSDavid Malone useproto); 584d7b63fafSDavid Malone exit(5); 585d7b63fafSDavid Malone } 58684a1a4cfSHajimu UMEMOTO if (max_hops < first_hop) { 58784a1a4cfSHajimu UMEMOTO fprintf(stderr, 58884a1a4cfSHajimu UMEMOTO "traceroute6: max hoplimit must be larger than first hoplimit.\n"); 58984a1a4cfSHajimu UMEMOTO exit(1); 59084a1a4cfSHajimu UMEMOTO } 59184a1a4cfSHajimu UMEMOTO 592*0c2218d1SJose Luis Duran if (ecnflag) { 593*0c2218d1SJose Luis Duran if (tclass != -1) { 594*0c2218d1SJose Luis Duran tclass &= ~IPTOS_ECN_MASK; 595*0c2218d1SJose Luis Duran } else { 596*0c2218d1SJose Luis Duran tclass = 0; 597*0c2218d1SJose Luis Duran } 598*0c2218d1SJose Luis Duran tclass |= IPTOS_ECN_ECT1; 599*0c2218d1SJose Luis Duran } 600*0c2218d1SJose Luis Duran 601d7b63fafSDavid Malone /* revoke privs */ 602d7b63fafSDavid Malone uid = getuid(); 603d7b63fafSDavid Malone if (setresuid(uid, uid, uid) == -1) { 604d7b63fafSDavid Malone perror("setresuid"); 605d7b63fafSDavid Malone exit(1); 606d7b63fafSDavid Malone } 607d7b63fafSDavid Malone 608c7090651SMichael Tuexen if (tclass != -1) { 609c7090651SMichael Tuexen if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_TCLASS, &tclass, 610c7090651SMichael Tuexen sizeof(int)) == -1) { 611c7090651SMichael Tuexen perror("setsockopt(IPV6_TCLASS)"); 612c7090651SMichael Tuexen exit(7); 613c7090651SMichael Tuexen } 614c7090651SMichael Tuexen } 615d7b63fafSDavid Malone 61633841545SHajimu UMEMOTO if (argc < 1 || argc > 2) 6177d56d374SYoshinobu Inoue usage(); 6187d56d374SYoshinobu Inoue 619de68a0daSKris Kennaway #if 1 6207d56d374SYoshinobu Inoue setvbuf(stdout, NULL, _IOLBF, BUFSIZ); 621de68a0daSKris Kennaway #else 622de68a0daSKris Kennaway setlinebuf(stdout); 623de68a0daSKris Kennaway #endif 6247d56d374SYoshinobu Inoue 62539865d64SYoshinobu Inoue memset(&hints, 0, sizeof(hints)); 62639865d64SYoshinobu Inoue hints.ai_family = PF_INET6; 62739865d64SYoshinobu Inoue hints.ai_socktype = SOCK_RAW; 62839865d64SYoshinobu Inoue hints.ai_protocol = IPPROTO_ICMPV6; 62939865d64SYoshinobu Inoue hints.ai_flags = AI_CANONNAME; 630cc432e23SMariusz Zaborski 631cc432e23SMariusz Zaborski error = cap_getaddrinfo(capdns, *argv, NULL, &hints, &res); 632cc432e23SMariusz Zaborski 63339865d64SYoshinobu Inoue if (error) { 634c449e284SHajimu UMEMOTO fprintf(stderr, 63539865d64SYoshinobu Inoue "traceroute6: %s\n", gai_strerror(error)); 6367d56d374SYoshinobu Inoue exit(1); 6377d56d374SYoshinobu Inoue } 638de68a0daSKris Kennaway if (res->ai_addrlen != sizeof(Dst)) { 639c449e284SHajimu UMEMOTO fprintf(stderr, 640de68a0daSKris Kennaway "traceroute6: size of sockaddr mismatch\n"); 641de68a0daSKris Kennaway exit(1); 642de68a0daSKris Kennaway } 64339865d64SYoshinobu Inoue memcpy(&Dst, res->ai_addr, res->ai_addrlen); 64439865d64SYoshinobu Inoue hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv; 64533841545SHajimu UMEMOTO if (!hostname) { 646c449e284SHajimu UMEMOTO fprintf(stderr, "traceroute6: not enough core\n"); 64733841545SHajimu UMEMOTO exit(1); 64833841545SHajimu UMEMOTO } 64984a1a4cfSHajimu UMEMOTO if (res->ai_next) { 650cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, res->ai_addr, res->ai_addrlen, hbuf, 65184a1a4cfSHajimu UMEMOTO sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 65284a1a4cfSHajimu UMEMOTO strlcpy(hbuf, "?", sizeof(hbuf)); 65384a1a4cfSHajimu UMEMOTO fprintf(stderr, "traceroute6: Warning: %s has multiple " 65484a1a4cfSHajimu UMEMOTO "addresses; using %s\n", hostname, hbuf); 65584a1a4cfSHajimu UMEMOTO } 656ca19d0d7SMark Johnston freeaddrinfo(res); 65733841545SHajimu UMEMOTO if (*++argv) { 65833841545SHajimu UMEMOTO ep = NULL; 65984a1a4cfSHajimu UMEMOTO errno = 0; 66033841545SHajimu UMEMOTO datalen = strtoul(*argv, &ep, 0); 661aa96470cSMichael Tuexen if (errno || *ep) { 662c449e284SHajimu UMEMOTO fprintf(stderr, 66333841545SHajimu UMEMOTO "traceroute6: invalid packet length.\n"); 66433841545SHajimu UMEMOTO exit(1); 66533841545SHajimu UMEMOTO } 66633841545SHajimu UMEMOTO } 667d7b63fafSDavid Malone switch (useproto) { 668d7b63fafSDavid Malone case IPPROTO_ICMPV6: 669aa96470cSMichael Tuexen minlen = ICMP6ECHOLEN; 670d7b63fafSDavid Malone break; 671d7b63fafSDavid Malone case IPPROTO_UDP: 672aa96470cSMichael Tuexen minlen = sizeof(struct udphdr); 673d7b63fafSDavid Malone break; 674d7b63fafSDavid Malone case IPPROTO_NONE: 675d7b63fafSDavid Malone minlen = 0; 676d7b63fafSDavid Malone datalen = 0; 677d7b63fafSDavid Malone break; 6789d8b46c8SMichael Tuexen case IPPROTO_SCTP: 6799d8b46c8SMichael Tuexen minlen = sizeof(struct sctphdr); 6809d8b46c8SMichael Tuexen break; 6819d8b46c8SMichael Tuexen case IPPROTO_TCP: 6829d8b46c8SMichael Tuexen minlen = sizeof(struct tcphdr); 6839d8b46c8SMichael Tuexen break; 684d7b63fafSDavid Malone default: 685d7b63fafSDavid Malone fprintf(stderr, "traceroute6: unknown probe protocol %d.\n", 686d7b63fafSDavid Malone useproto); 687d7b63fafSDavid Malone exit(1); 688d7b63fafSDavid Malone } 68984a1a4cfSHajimu UMEMOTO if (datalen < minlen) 69084a1a4cfSHajimu UMEMOTO datalen = minlen; 69184a1a4cfSHajimu UMEMOTO else if (datalen >= MAXPACKET) { 692c449e284SHajimu UMEMOTO fprintf(stderr, 693f42640a3SUlrich Spörlein "traceroute6: packet size must be %zu <= s < %d.\n", 694f42640a3SUlrich Spörlein minlen, MAXPACKET); 6957d56d374SYoshinobu Inoue exit(1); 6967d56d374SYoshinobu Inoue } 69751eff8efSMichael Tuexen if ((useproto == IPPROTO_SCTP) && (datalen & 3)) { 69851eff8efSMichael Tuexen fprintf(stderr, 69951eff8efSMichael Tuexen "traceroute6: packet size must be a multiple of 4.\n"); 70051eff8efSMichael Tuexen exit(1); 70151eff8efSMichael Tuexen } 702f42640a3SUlrich Spörlein outpacket = malloc(datalen); 7037d56d374SYoshinobu Inoue if (!outpacket) { 704de68a0daSKris Kennaway perror("malloc"); 7057d56d374SYoshinobu Inoue exit(1); 7067d56d374SYoshinobu Inoue } 7077d56d374SYoshinobu Inoue (void) bzero((char *)outpacket, datalen); 7087d56d374SYoshinobu Inoue 7097d56d374SYoshinobu Inoue /* initialize msghdr for receiving packets */ 7107d56d374SYoshinobu Inoue rcviov[0].iov_base = (caddr_t)packet; 7117d56d374SYoshinobu Inoue rcviov[0].iov_len = sizeof(packet); 712de68a0daSKris Kennaway rcvmhdr.msg_name = (caddr_t)&Rcv; 713de68a0daSKris Kennaway rcvmhdr.msg_namelen = sizeof(Rcv); 7147d56d374SYoshinobu Inoue rcvmhdr.msg_iov = rcviov; 7157d56d374SYoshinobu Inoue rcvmhdr.msg_iovlen = 1; 716e961704aSDavid Malone rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 717e961704aSDavid Malone CMSG_SPACE(sizeof(int)); 718de68a0daSKris Kennaway if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) { 719c449e284SHajimu UMEMOTO fprintf(stderr, "traceroute6: malloc failed\n"); 720de68a0daSKris Kennaway exit(1); 721de68a0daSKris Kennaway } 7227d56d374SYoshinobu Inoue rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; 723de68a0daSKris Kennaway rcvmhdr.msg_controllen = rcvcmsglen; 7247d56d374SYoshinobu Inoue 7257d56d374SYoshinobu Inoue if (options & SO_DEBUG) 7267d56d374SYoshinobu Inoue (void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, 7277d56d374SYoshinobu Inoue (char *)&on, sizeof(on)); 7287d56d374SYoshinobu Inoue if (options & SO_DONTROUTE) 7297d56d374SYoshinobu Inoue (void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, 7307d56d374SYoshinobu Inoue (char *)&on, sizeof(on)); 731ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 7327d56d374SYoshinobu Inoue /* 7337d56d374SYoshinobu Inoue * do not raise error even if setsockopt fails, kernel may have ipsec 7347d56d374SYoshinobu Inoue * turned off. 7357d56d374SYoshinobu Inoue */ 736ca19d0d7SMark Johnston if (setpolicy(rcvsock, ipsec_inpolicy) < 0) 737d94e8c62SKris Kennaway errx(1, "%s", ipsec_strerror()); 738ca19d0d7SMark Johnston if (setpolicy(rcvsock, ipsec_outpolicy) < 0) 739d94e8c62SKris Kennaway errx(1, "%s", ipsec_strerror()); 740de68a0daSKris Kennaway #else 741de68a0daSKris Kennaway { 742de68a0daSKris Kennaway int level = IPSEC_LEVEL_NONE; 743de68a0daSKris Kennaway 744de68a0daSKris Kennaway (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, 745de68a0daSKris Kennaway sizeof(level)); 746de68a0daSKris Kennaway (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, 747de68a0daSKris Kennaway sizeof(level)); 748de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL 749de68a0daSKris Kennaway (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, 750de68a0daSKris Kennaway sizeof(level)); 751de68a0daSKris Kennaway #else 752de68a0daSKris Kennaway (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, 753de68a0daSKris Kennaway sizeof(level)); 754de68a0daSKris Kennaway #endif 755de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL 756de68a0daSKris Kennaway (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, 757de68a0daSKris Kennaway sizeof(level)); 758de68a0daSKris Kennaway #endif 759de68a0daSKris Kennaway } 760ca19d0d7SMark Johnston #endif /* !(IPSEC && IPSEC_POLICY_IPSEC) */ 7617d56d374SYoshinobu Inoue 762de68a0daSKris Kennaway #ifdef SO_SNDBUF 76384a1a4cfSHajimu UMEMOTO i = datalen; 764aa96470cSMichael Tuexen if (i == 0) 765aa96470cSMichael Tuexen i = 1; 76684a1a4cfSHajimu UMEMOTO if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&i, 767aa96470cSMichael Tuexen sizeof(i)) < 0) { 768de68a0daSKris Kennaway perror("setsockopt(SO_SNDBUF)"); 7697d56d374SYoshinobu Inoue exit(6); 7707d56d374SYoshinobu Inoue } 771de68a0daSKris Kennaway #endif /* SO_SNDBUF */ 7727d56d374SYoshinobu Inoue if (options & SO_DEBUG) 7737d56d374SYoshinobu Inoue (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 7747d56d374SYoshinobu Inoue (char *)&on, sizeof(on)); 7757d56d374SYoshinobu Inoue if (options & SO_DONTROUTE) 7767d56d374SYoshinobu Inoue (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, 7777d56d374SYoshinobu Inoue (char *)&on, sizeof(on)); 778de68a0daSKris Kennaway if (rth) {/* XXX: there is no library to finalize the header... */ 779de68a0daSKris Kennaway rth->ip6r_len = rth->ip6r_segleft * 2; 780de68a0daSKris Kennaway if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR, 781de68a0daSKris Kennaway (void *)rth, (rth->ip6r_len + 1) << 3)) { 782c449e284SHajimu UMEMOTO fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n", 783de68a0daSKris Kennaway strerror(errno)); 784de68a0daSKris Kennaway exit(1); 785de68a0daSKris Kennaway } 786de68a0daSKris Kennaway } 787ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 7887d56d374SYoshinobu Inoue /* 7897d56d374SYoshinobu Inoue * do not raise error even if setsockopt fails, kernel may have ipsec 7907d56d374SYoshinobu Inoue * turned off. 7917d56d374SYoshinobu Inoue */ 792ca19d0d7SMark Johnston if (setpolicy(sndsock, ipsec_inpolicy) < 0) 793d94e8c62SKris Kennaway errx(1, "%s", ipsec_strerror()); 794ca19d0d7SMark Johnston if (setpolicy(sndsock, ipsec_outpolicy) < 0) 795d94e8c62SKris Kennaway errx(1, "%s", ipsec_strerror()); 796de68a0daSKris Kennaway #else 797de68a0daSKris Kennaway { 798de68a0daSKris Kennaway int level = IPSEC_LEVEL_BYPASS; 799de68a0daSKris Kennaway 800de68a0daSKris Kennaway (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, 801de68a0daSKris Kennaway sizeof(level)); 802de68a0daSKris Kennaway (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, 803de68a0daSKris Kennaway sizeof(level)); 804de68a0daSKris Kennaway #ifdef IP_AUTH_TRANS_LEVEL 805de68a0daSKris Kennaway (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, 806de68a0daSKris Kennaway sizeof(level)); 807de68a0daSKris Kennaway #else 808de68a0daSKris Kennaway (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, 809de68a0daSKris Kennaway sizeof(level)); 810de68a0daSKris Kennaway #endif 811de68a0daSKris Kennaway #ifdef IP_AUTH_NETWORK_LEVEL 812de68a0daSKris Kennaway (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, 813de68a0daSKris Kennaway sizeof(level)); 814de68a0daSKris Kennaway #endif 815de68a0daSKris Kennaway } 816ca19d0d7SMark Johnston #endif /* !(IPSEC && IPSEC_POLICY_IPSEC) */ 8177d56d374SYoshinobu Inoue 8187d56d374SYoshinobu Inoue /* 8197d56d374SYoshinobu Inoue * Source selection 8207d56d374SYoshinobu Inoue */ 821de68a0daSKris Kennaway bzero(&Src, sizeof(Src)); 8227d56d374SYoshinobu Inoue if (source) { 823de68a0daSKris Kennaway memset(&hints, 0, sizeof(hints)); 824de68a0daSKris Kennaway hints.ai_family = AF_INET6; 825de68a0daSKris Kennaway hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 826de68a0daSKris Kennaway hints.ai_flags = AI_NUMERICHOST; 827cc432e23SMariusz Zaborski error = cap_getaddrinfo(capdns, source, "0", &hints, &res); 828de68a0daSKris Kennaway if (error) { 829c449e284SHajimu UMEMOTO printf("traceroute6: %s: %s\n", source, 830de68a0daSKris Kennaway gai_strerror(error)); 8317d56d374SYoshinobu Inoue exit(1); 8327d56d374SYoshinobu Inoue } 833de68a0daSKris Kennaway if (res->ai_addrlen > sizeof(Src)) { 834c449e284SHajimu UMEMOTO printf("traceroute6: %s: %s\n", source, 835de68a0daSKris Kennaway gai_strerror(error)); 836de68a0daSKris Kennaway exit(1); 837de68a0daSKris Kennaway } 838de68a0daSKris Kennaway memcpy(&Src, res->ai_addr, res->ai_addrlen); 839de68a0daSKris Kennaway freeaddrinfo(res); 8407d56d374SYoshinobu Inoue } else { 8417d56d374SYoshinobu Inoue struct sockaddr_in6 Nxt; 84284a1a4cfSHajimu UMEMOTO int dummy; 84384a1a4cfSHajimu UMEMOTO socklen_t len; 8447d56d374SYoshinobu Inoue 8457d56d374SYoshinobu Inoue Nxt = Dst; 8467d56d374SYoshinobu Inoue Nxt.sin6_port = htons(DUMMY_PORT); 8477d56d374SYoshinobu Inoue if (cmsg != NULL) 8487d56d374SYoshinobu Inoue bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr, 8497d56d374SYoshinobu Inoue sizeof(Nxt.sin6_addr)); 8507d56d374SYoshinobu Inoue if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 8517d56d374SYoshinobu Inoue perror("socket"); 852de68a0daSKris Kennaway exit(1); 8537d56d374SYoshinobu Inoue } 854de68a0daSKris Kennaway if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) { 8557d56d374SYoshinobu Inoue perror("connect"); 856de68a0daSKris Kennaway exit(1); 8577d56d374SYoshinobu Inoue } 858de68a0daSKris Kennaway len = sizeof(Src); 859de68a0daSKris Kennaway if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) { 860de68a0daSKris Kennaway perror("getsockname"); 861de68a0daSKris Kennaway exit(1); 862de68a0daSKris Kennaway } 863cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)&Src, Src.sin6_len, 864d24cb249SHajimu UMEMOTO src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) { 865c449e284SHajimu UMEMOTO fprintf(stderr, "getnameinfo failed for source\n"); 866de68a0daSKris Kennaway exit(1); 867de68a0daSKris Kennaway } 868de68a0daSKris Kennaway source = src0; 8697d56d374SYoshinobu Inoue close(dummy); 8707d56d374SYoshinobu Inoue } 871de68a0daSKris Kennaway 87284a1a4cfSHajimu UMEMOTO Src.sin6_port = htons(0); 873de68a0daSKris Kennaway if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) { 874de68a0daSKris Kennaway perror("bind"); 8757d56d374SYoshinobu Inoue exit(1); 8767d56d374SYoshinobu Inoue } 8777d56d374SYoshinobu Inoue 87884a1a4cfSHajimu UMEMOTO { 879c449e284SHajimu UMEMOTO socklen_t len; 880de68a0daSKris Kennaway 881de68a0daSKris Kennaway len = sizeof(Src); 88284a1a4cfSHajimu UMEMOTO if (getsockname(sndsock, (struct sockaddr *)&Src, &len) < 0) { 883de68a0daSKris Kennaway perror("getsockname"); 884de68a0daSKris Kennaway exit(1); 885de68a0daSKris Kennaway } 88684a1a4cfSHajimu UMEMOTO srcport = ntohs(Src.sin6_port); 887de68a0daSKris Kennaway } 888de68a0daSKris Kennaway 889d429d720SHajimu UMEMOTO if (as_path) { 890d429d720SHajimu UMEMOTO asn = as_setup(as_server); 891d429d720SHajimu UMEMOTO if (asn == NULL) { 892d429d720SHajimu UMEMOTO fprintf(stderr, 893d429d720SHajimu UMEMOTO "traceroute6: as_setup failed, AS# lookups" 894d429d720SHajimu UMEMOTO " disabled\n"); 895d429d720SHajimu UMEMOTO (void)fflush(stderr); 896d429d720SHajimu UMEMOTO as_path = 0; 897d429d720SHajimu UMEMOTO } 898d429d720SHajimu UMEMOTO } 899d429d720SHajimu UMEMOTO 9007d56d374SYoshinobu Inoue /* 9017d56d374SYoshinobu Inoue * Message to users 9027d56d374SYoshinobu Inoue */ 903cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)&Dst, Dst.sin6_len, hbuf, 904d24cb249SHajimu UMEMOTO sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) 90533841545SHajimu UMEMOTO strlcpy(hbuf, "(invalid)", sizeof(hbuf)); 906c449e284SHajimu UMEMOTO fprintf(stderr, "traceroute6"); 907c449e284SHajimu UMEMOTO fprintf(stderr, " to %s (%s)", hostname, hbuf); 9087d56d374SYoshinobu Inoue if (source) 909c449e284SHajimu UMEMOTO fprintf(stderr, " from %s", source); 91084a1a4cfSHajimu UMEMOTO fprintf(stderr, ", %lu hops max, %lu byte packets\n", 911d55fae02SMichael Tuexen max_hops, 912d55fae02SMichael Tuexen datalen + ((useproto == IPPROTO_UDP) ? sizeof(struct udphdr) : 0)); 9137d56d374SYoshinobu Inoue (void) fflush(stderr); 9147d56d374SYoshinobu Inoue 915de68a0daSKris Kennaway if (first_hop > 1) 91684a1a4cfSHajimu UMEMOTO printf("Skipping %lu intermediate hops\n", first_hop - 1); 917de68a0daSKris Kennaway 918cc432e23SMariusz Zaborski if (connect(sndsock, (struct sockaddr *)&Dst, 919cc432e23SMariusz Zaborski sizeof(Dst)) != 0) { 920cc432e23SMariusz Zaborski fprintf(stderr, "connect: %s\n", strerror(errno)); 921cc432e23SMariusz Zaborski exit(1); 922cc432e23SMariusz Zaborski } 923cc432e23SMariusz Zaborski 924cc432e23SMariusz Zaborski /* 925cc432e23SMariusz Zaborski * Here we enter capability mode. Further down access to global 926cc432e23SMariusz Zaborski * namespaces (e.g filesystem) is restricted (see capsicum(4)). 927cc432e23SMariusz Zaborski * We must connect(2) our socket before this point. 928cc432e23SMariusz Zaborski */ 929cc432e23SMariusz Zaborski if (caph_enter_casper() < 0) { 930cc432e23SMariusz Zaborski fprintf(stderr, "caph_enter_casper: %s\n", strerror(errno)); 931cc432e23SMariusz Zaborski exit(1); 932cc432e23SMariusz Zaborski } 933cc432e23SMariusz Zaborski 934cc432e23SMariusz Zaborski cap_rights_init(&rights, CAP_SEND, CAP_SETSOCKOPT); 935cc432e23SMariusz Zaborski if (caph_rights_limit(sndsock, &rights) < 0) { 936cc432e23SMariusz Zaborski fprintf(stderr, "caph_rights_limit sndsock: %s\n", 937cc432e23SMariusz Zaborski strerror(errno)); 938cc432e23SMariusz Zaborski exit(1); 939cc432e23SMariusz Zaborski } 9408ff4fc03SMichael Tuexen cap_rights_init(&rights, CAP_RECV, CAP_EVENT); 941b8ae450fSMark Johnston if (caph_rights_limit(rcvsock, &rights) < 0) { 942b8ae450fSMark Johnston fprintf(stderr, "caph_rights_limit rcvsock: %s\n", 943b8ae450fSMark Johnston strerror(errno)); 944b8ae450fSMark Johnston exit(1); 945b8ae450fSMark Johnston } 946cc432e23SMariusz Zaborski 9477d56d374SYoshinobu Inoue /* 9487d56d374SYoshinobu Inoue * Main loop 9497d56d374SYoshinobu Inoue */ 950de68a0daSKris Kennaway for (hops = first_hop; hops <= max_hops; ++hops) { 9517d56d374SYoshinobu Inoue struct in6_addr lastaddr; 9527d56d374SYoshinobu Inoue int got_there = 0; 953f42640a3SUlrich Spörlein unsigned unreachable = 0; 9547d56d374SYoshinobu Inoue 95584a1a4cfSHajimu UMEMOTO printf("%2lu ", hops); 9567d56d374SYoshinobu Inoue bzero(&lastaddr, sizeof(lastaddr)); 9577d56d374SYoshinobu Inoue for (probe = 0; probe < nprobes; ++probe) { 9587d56d374SYoshinobu Inoue int cc; 9597d56d374SYoshinobu Inoue struct timeval t1, t2; 9607d56d374SYoshinobu Inoue 96184a1a4cfSHajimu UMEMOTO (void) gettimeofday(&t1, NULL); 9627d56d374SYoshinobu Inoue send_probe(++seq, hops); 9637d56d374SYoshinobu Inoue while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) { 96484a1a4cfSHajimu UMEMOTO (void) gettimeofday(&t2, NULL); 965*0c2218d1SJose Luis Duran if (packet_ok(&rcvmhdr, cc, seq, &type, &code, &ecn)) { 9667d56d374SYoshinobu Inoue if (!IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr, 9677d56d374SYoshinobu Inoue &lastaddr)) { 96859876f93SChristian S.J. Peron if (probe > 0) 96959876f93SChristian S.J. Peron fputs("\n ", stdout); 9707d56d374SYoshinobu Inoue print(&rcvmhdr, cc); 9717d56d374SYoshinobu Inoue lastaddr = Rcv.sin6_addr; 9727d56d374SYoshinobu Inoue } 973c449e284SHajimu UMEMOTO printf(" %.3f ms", deltaT(&t1, &t2)); 974*0c2218d1SJose Luis Duran if (ecnflag) { 975*0c2218d1SJose Luis Duran switch (ecn) { 976*0c2218d1SJose Luis Duran case IPTOS_ECN_ECT1: 977*0c2218d1SJose Luis Duran printf(" (ecn=passed)"); 978*0c2218d1SJose Luis Duran break; 979*0c2218d1SJose Luis Duran case IPTOS_ECN_NOTECT: 980*0c2218d1SJose Luis Duran printf(" (ecn=bleached)"); 981*0c2218d1SJose Luis Duran break; 982*0c2218d1SJose Luis Duran case IPTOS_ECN_CE: 983*0c2218d1SJose Luis Duran printf(" (ecn=congested)"); 984*0c2218d1SJose Luis Duran break; 985*0c2218d1SJose Luis Duran default: 986*0c2218d1SJose Luis Duran printf(" (ecn=mangled)"); 987*0c2218d1SJose Luis Duran break; 988*0c2218d1SJose Luis Duran } 989*0c2218d1SJose Luis Duran } 99064694fdcSMichael Tuexen if (type == ICMP6_DST_UNREACH) { 99164694fdcSMichael Tuexen switch (code) { 9927d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH_NOROUTE: 9937d56d374SYoshinobu Inoue ++unreachable; 994c449e284SHajimu UMEMOTO printf(" !N"); 9957d56d374SYoshinobu Inoue break; 9967d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH_ADMIN: 9977d56d374SYoshinobu Inoue ++unreachable; 998c449e284SHajimu UMEMOTO printf(" !P"); 9997d56d374SYoshinobu Inoue break; 10007d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH_NOTNEIGHBOR: 10017d56d374SYoshinobu Inoue ++unreachable; 1002c449e284SHajimu UMEMOTO printf(" !S"); 10037d56d374SYoshinobu Inoue break; 10047d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH_ADDR: 10057d56d374SYoshinobu Inoue ++unreachable; 1006c449e284SHajimu UMEMOTO printf(" !A"); 10077d56d374SYoshinobu Inoue break; 10087d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH_NOPORT: 10097d56d374SYoshinobu Inoue if (rcvhlim >= 0 && 10107d56d374SYoshinobu Inoue rcvhlim <= 1) 1011c449e284SHajimu UMEMOTO printf(" !"); 10127d56d374SYoshinobu Inoue ++got_there; 10137d56d374SYoshinobu Inoue break; 10147d56d374SYoshinobu Inoue } 10151f69b3fbSMichael Tuexen } else if (type == ICMP6_PARAM_PROB && 10161f69b3fbSMichael Tuexen code == ICMP6_PARAMPROB_NEXTHEADER) { 10171f69b3fbSMichael Tuexen printf(" !H"); 10181f69b3fbSMichael Tuexen ++got_there; 101964694fdcSMichael Tuexen } else if (type == ICMP6_ECHO_REPLY) { 102064694fdcSMichael Tuexen if (rcvhlim >= 0 && 102164694fdcSMichael Tuexen rcvhlim <= 1) 102264694fdcSMichael Tuexen printf(" !"); 102364694fdcSMichael Tuexen ++got_there; 102464694fdcSMichael Tuexen } 10257d56d374SYoshinobu Inoue break; 1026161ab37dSHiroki Sato } else if (deltaT(&t1, &t2) > waittime * 1000) { 1027161ab37dSHiroki Sato cc = 0; 1028161ab37dSHiroki Sato break; 10297d56d374SYoshinobu Inoue } 10307d56d374SYoshinobu Inoue } 10317d56d374SYoshinobu Inoue if (cc == 0) 1032c449e284SHajimu UMEMOTO printf(" *"); 10337d56d374SYoshinobu Inoue (void) fflush(stdout); 10347d56d374SYoshinobu Inoue } 10357d56d374SYoshinobu Inoue putchar('\n'); 10367d56d374SYoshinobu Inoue if (got_there || 10377d56d374SYoshinobu Inoue (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) { 10387d56d374SYoshinobu Inoue exit(0); 10397d56d374SYoshinobu Inoue } 10407d56d374SYoshinobu Inoue } 1041d429d720SHajimu UMEMOTO if (as_path) 1042d429d720SHajimu UMEMOTO as_shutdown(asn); 10437d56d374SYoshinobu Inoue 10447d56d374SYoshinobu Inoue exit(0); 10457d56d374SYoshinobu Inoue } 10467d56d374SYoshinobu Inoue 10477d56d374SYoshinobu Inoue int 1048aa96470cSMichael Tuexen wait_for_reply(int sock, struct msghdr *mhdr) 10497d56d374SYoshinobu Inoue { 10502a1c5efaSKris Kennaway #ifdef HAVE_POLL 10512a1c5efaSKris Kennaway struct pollfd pfd[1]; 10527d56d374SYoshinobu Inoue int cc = 0; 10537d56d374SYoshinobu Inoue 10542a1c5efaSKris Kennaway pfd[0].fd = sock; 10552a1c5efaSKris Kennaway pfd[0].events = POLLIN; 10562a1c5efaSKris Kennaway pfd[0].revents = 0; 10577d56d374SYoshinobu Inoue 10588ff4fc03SMichael Tuexen if (poll(pfd, 1, waittime * 1000) > 0 && 10598ff4fc03SMichael Tuexen pfd[0].revents & POLLIN) 10607d56d374SYoshinobu Inoue cc = recvmsg(rcvsock, mhdr, 0); 10617d56d374SYoshinobu Inoue 10627d56d374SYoshinobu Inoue return (cc); 10632a1c5efaSKris Kennaway #else 10642a1c5efaSKris Kennaway fd_set *fdsp; 10652a1c5efaSKris Kennaway struct timeval wait; 10662a1c5efaSKris Kennaway int cc = 0, fdsn; 10672a1c5efaSKris Kennaway 10682a1c5efaSKris Kennaway fdsn = howmany(sock + 1, NFDBITS) * sizeof(fd_mask); 10692a1c5efaSKris Kennaway if ((fdsp = (fd_set *)malloc(fdsn)) == NULL) 10702a1c5efaSKris Kennaway err(1, "malloc"); 10712a1c5efaSKris Kennaway memset(fdsp, 0, fdsn); 10722a1c5efaSKris Kennaway FD_SET(sock, fdsp); 10732a1c5efaSKris Kennaway wait.tv_sec = waittime; wait.tv_usec = 0; 10742a1c5efaSKris Kennaway 10752a1c5efaSKris Kennaway if (select(sock + 1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0) 10762a1c5efaSKris Kennaway cc = recvmsg(rcvsock, mhdr, 0); 10772a1c5efaSKris Kennaway 10782a1c5efaSKris Kennaway free(fdsp); 10792a1c5efaSKris Kennaway return (cc); 10802a1c5efaSKris Kennaway #endif 10817d56d374SYoshinobu Inoue } 10827d56d374SYoshinobu Inoue 1083ca19d0d7SMark Johnston #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 10847d56d374SYoshinobu Inoue int 1085ca19d0d7SMark Johnston setpolicy(int so, char *policy) 10867d56d374SYoshinobu Inoue { 10877d56d374SYoshinobu Inoue char *buf; 10887d56d374SYoshinobu Inoue 10897d56d374SYoshinobu Inoue buf = ipsec_set_policy(policy, strlen(policy)); 10907d56d374SYoshinobu Inoue if (buf == NULL) { 1091de68a0daSKris Kennaway warnx("%s", ipsec_strerror()); 1092777e494aSJose Luis Duran return (-1); 10937d56d374SYoshinobu Inoue } 10947d56d374SYoshinobu Inoue (void)setsockopt(so, IPPROTO_IPV6, IPV6_IPSEC_POLICY, 10957d56d374SYoshinobu Inoue buf, ipsec_get_policylen(buf)); 10967d56d374SYoshinobu Inoue 10977d56d374SYoshinobu Inoue free(buf); 10987d56d374SYoshinobu Inoue 1099777e494aSJose Luis Duran return (0); 11007d56d374SYoshinobu Inoue } 11017d56d374SYoshinobu Inoue #endif 11027d56d374SYoshinobu Inoue 11037d56d374SYoshinobu Inoue void 1104aa96470cSMichael Tuexen send_probe(int seq, u_long hops) 11057d56d374SYoshinobu Inoue { 1106d7b63fafSDavid Malone struct icmp6_hdr *icp; 11079d8b46c8SMichael Tuexen struct sctphdr *sctp; 1108cc432e23SMariusz Zaborski struct udphdr *outudp; 11099d8b46c8SMichael Tuexen struct sctp_chunkhdr *chk; 111051eff8efSMichael Tuexen struct sctp_init_chunk *init; 111151eff8efSMichael Tuexen struct sctp_paramhdr *param; 11129d8b46c8SMichael Tuexen struct tcphdr *tcp; 11137d56d374SYoshinobu Inoue int i; 11147d56d374SYoshinobu Inoue 111584a1a4cfSHajimu UMEMOTO i = hops; 11167d56d374SYoshinobu Inoue if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 111784a1a4cfSHajimu UMEMOTO (char *)&i, sizeof(i)) < 0) { 11187d56d374SYoshinobu Inoue perror("setsockopt IPV6_UNICAST_HOPS"); 11197d56d374SYoshinobu Inoue } 11207d56d374SYoshinobu Inoue 11217d56d374SYoshinobu Inoue Dst.sin6_port = htons(port + seq); 11227d56d374SYoshinobu Inoue 1123d7b63fafSDavid Malone switch (useproto) { 1124d7b63fafSDavid Malone case IPPROTO_ICMPV6: 1125d7b63fafSDavid Malone icp = (struct icmp6_hdr *)outpacket; 112684a1a4cfSHajimu UMEMOTO 112784a1a4cfSHajimu UMEMOTO icp->icmp6_type = ICMP6_ECHO_REQUEST; 112884a1a4cfSHajimu UMEMOTO icp->icmp6_code = 0; 112984a1a4cfSHajimu UMEMOTO icp->icmp6_cksum = 0; 113084a1a4cfSHajimu UMEMOTO icp->icmp6_id = ident; 113184a1a4cfSHajimu UMEMOTO icp->icmp6_seq = htons(seq); 1132d7b63fafSDavid Malone break; 1133d7b63fafSDavid Malone case IPPROTO_UDP: 1134cc432e23SMariusz Zaborski outudp = (struct udphdr *) outpacket; 1135cc432e23SMariusz Zaborski outudp->uh_sport = htons(ident); 1136cc432e23SMariusz Zaborski outudp->uh_dport = htons(port + seq); 1137cc432e23SMariusz Zaborski outudp->uh_ulen = htons(datalen); 11381d712c05SZhenlei Huang outudp->uh_sum = 0; 1139cc432e23SMariusz Zaborski outudp->uh_sum = udp_cksum(&Src, &Dst, outpacket, datalen); 1140d7b63fafSDavid Malone break; 1141d7b63fafSDavid Malone case IPPROTO_NONE: 1142d7b63fafSDavid Malone /* No space for anything. No harm as seq/tv32 are decorative. */ 1143d7b63fafSDavid Malone break; 11449d8b46c8SMichael Tuexen case IPPROTO_SCTP: 11459d8b46c8SMichael Tuexen sctp = (struct sctphdr *)outpacket; 11469d8b46c8SMichael Tuexen 11479d8b46c8SMichael Tuexen sctp->src_port = htons(ident); 11489d8b46c8SMichael Tuexen sctp->dest_port = htons(port + seq); 114951eff8efSMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) + 115051eff8efSMichael Tuexen sizeof(struct sctp_init_chunk))) { 115151eff8efSMichael Tuexen sctp->v_tag = 0; 115251eff8efSMichael Tuexen } else { 11539d8b46c8SMichael Tuexen sctp->v_tag = (sctp->src_port << 16) | sctp->dest_port; 115451eff8efSMichael Tuexen } 11559d8b46c8SMichael Tuexen sctp->checksum = htonl(0); 11569d8b46c8SMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) + 115751eff8efSMichael Tuexen sizeof(struct sctp_init_chunk))) { 115851eff8efSMichael Tuexen /* 115951eff8efSMichael Tuexen * Send a packet containing an INIT chunk. This works 116051eff8efSMichael Tuexen * better in case of firewalls on the path, but 116151eff8efSMichael Tuexen * results in a probe packet containing at least 116251eff8efSMichael Tuexen * 32 bytes of payload. For shorter payloads, use 116351eff8efSMichael Tuexen * SHUTDOWN-ACK chunks. 116451eff8efSMichael Tuexen */ 116551eff8efSMichael Tuexen init = (struct sctp_init_chunk *)(sctp + 1); 116651eff8efSMichael Tuexen init->ch.chunk_type = SCTP_INITIATION; 116751eff8efSMichael Tuexen init->ch.chunk_flags = 0; 116851eff8efSMichael Tuexen init->ch.chunk_length = htons((u_int16_t)(datalen - 116951eff8efSMichael Tuexen sizeof(struct sctphdr))); 117051eff8efSMichael Tuexen init->init.initiate_tag = (sctp->src_port << 16) | 117151eff8efSMichael Tuexen sctp->dest_port; 117251eff8efSMichael Tuexen init->init.a_rwnd = htonl(1500); 117351eff8efSMichael Tuexen init->init.num_outbound_streams = htons(1); 117451eff8efSMichael Tuexen init->init.num_inbound_streams = htons(1); 117551eff8efSMichael Tuexen init->init.initial_tsn = htonl(0); 117651eff8efSMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) + 117751eff8efSMichael Tuexen sizeof(struct sctp_init_chunk) + 117851eff8efSMichael Tuexen sizeof(struct sctp_paramhdr))) { 117951eff8efSMichael Tuexen param = (struct sctp_paramhdr *)(init + 1); 118051eff8efSMichael Tuexen param->param_type = htons(SCTP_PAD); 118151eff8efSMichael Tuexen param->param_length = 118251eff8efSMichael Tuexen htons((u_int16_t)(datalen - 118351eff8efSMichael Tuexen sizeof(struct sctphdr) - 118451eff8efSMichael Tuexen sizeof(struct sctp_init_chunk))); 118551eff8efSMichael Tuexen } 118651eff8efSMichael Tuexen } else { 118751eff8efSMichael Tuexen /* 118851eff8efSMichael Tuexen * Send a packet containing a SHUTDOWN-ACK chunk, 118951eff8efSMichael Tuexen * possibly followed by a PAD chunk. 119051eff8efSMichael Tuexen */ 119151eff8efSMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) + 11929d8b46c8SMichael Tuexen sizeof(struct sctp_chunkhdr))) { 11939d8b46c8SMichael Tuexen chk = (struct sctp_chunkhdr *)(sctp + 1); 11949d8b46c8SMichael Tuexen chk->chunk_type = SCTP_SHUTDOWN_ACK; 11959d8b46c8SMichael Tuexen chk->chunk_flags = 0; 11969d8b46c8SMichael Tuexen chk->chunk_length = htons(4); 11979d8b46c8SMichael Tuexen } 11989d8b46c8SMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) + 11999d8b46c8SMichael Tuexen 2 * sizeof(struct sctp_chunkhdr))) { 12009d8b46c8SMichael Tuexen chk = chk + 1; 12019d8b46c8SMichael Tuexen chk->chunk_type = SCTP_PAD_CHUNK; 12029d8b46c8SMichael Tuexen chk->chunk_flags = 0; 12039d8b46c8SMichael Tuexen chk->chunk_length = htons((u_int16_t)(datalen - 12049d8b46c8SMichael Tuexen sizeof(struct sctphdr) - 12059d8b46c8SMichael Tuexen sizeof(struct sctp_chunkhdr))); 12069d8b46c8SMichael Tuexen } 120751eff8efSMichael Tuexen } 12089d8b46c8SMichael Tuexen sctp->checksum = sctp_crc32c(outpacket, datalen); 12099d8b46c8SMichael Tuexen break; 12109d8b46c8SMichael Tuexen case IPPROTO_TCP: 12119d8b46c8SMichael Tuexen tcp = (struct tcphdr *)outpacket; 12129d8b46c8SMichael Tuexen 12139d8b46c8SMichael Tuexen tcp->th_sport = htons(ident); 12149d8b46c8SMichael Tuexen tcp->th_dport = htons(port + seq); 12159d8b46c8SMichael Tuexen tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport; 12169d8b46c8SMichael Tuexen tcp->th_ack = 0; 12179d8b46c8SMichael Tuexen tcp->th_off = 5; 12189d8b46c8SMichael Tuexen tcp->th_flags = TH_SYN; 12199d8b46c8SMichael Tuexen tcp->th_sum = 0; 12209d8b46c8SMichael Tuexen tcp->th_sum = tcp_chksum(&Src, &Dst, outpacket, datalen); 12219d8b46c8SMichael Tuexen break; 1222d7b63fafSDavid Malone default: 1223d7b63fafSDavid Malone fprintf(stderr, "Unknown probe protocol %d.\n", useproto); 1224d7b63fafSDavid Malone exit(1); 122584a1a4cfSHajimu UMEMOTO } 12267d56d374SYoshinobu Inoue 1227cc432e23SMariusz Zaborski i = send(sndsock, (char *)outpacket, datalen, 0); 1228f42640a3SUlrich Spörlein if (i < 0 || (u_long)i != datalen) { 12297d56d374SYoshinobu Inoue if (i < 0) 1230cc432e23SMariusz Zaborski perror("send"); 123184a1a4cfSHajimu UMEMOTO printf("traceroute6: wrote %s %lu chars, ret=%d\n", 1232c449e284SHajimu UMEMOTO hostname, datalen, i); 12337d56d374SYoshinobu Inoue (void) fflush(stdout); 12347d56d374SYoshinobu Inoue } 12357d56d374SYoshinobu Inoue } 12367d56d374SYoshinobu Inoue 12377d56d374SYoshinobu Inoue int 1238aa96470cSMichael Tuexen get_hoplim(struct msghdr *mhdr) 12397d56d374SYoshinobu Inoue { 12407d56d374SYoshinobu Inoue struct cmsghdr *cm; 12417d56d374SYoshinobu Inoue 12427d56d374SYoshinobu Inoue for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 12437d56d374SYoshinobu Inoue cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 12447d56d374SYoshinobu Inoue if (cm->cmsg_level == IPPROTO_IPV6 && 12457d56d374SYoshinobu Inoue cm->cmsg_type == IPV6_HOPLIMIT && 12467d56d374SYoshinobu Inoue cm->cmsg_len == CMSG_LEN(sizeof(int))) 12477d56d374SYoshinobu Inoue return (*(int *)CMSG_DATA(cm)); 12487d56d374SYoshinobu Inoue } 12497d56d374SYoshinobu Inoue 12507d56d374SYoshinobu Inoue return (-1); 12517d56d374SYoshinobu Inoue } 12527d56d374SYoshinobu Inoue 12537d56d374SYoshinobu Inoue double 1254aa96470cSMichael Tuexen deltaT(struct timeval *t1p, struct timeval *t2p) 12557d56d374SYoshinobu Inoue { 1256e961704aSDavid Malone double dt; 12577d56d374SYoshinobu Inoue 12587d56d374SYoshinobu Inoue dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + 12597d56d374SYoshinobu Inoue (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; 12607d56d374SYoshinobu Inoue return (dt); 12617d56d374SYoshinobu Inoue } 12627d56d374SYoshinobu Inoue 12637d56d374SYoshinobu Inoue /* 12647d56d374SYoshinobu Inoue * Convert an ICMP "type" field to a printable string. 12657d56d374SYoshinobu Inoue */ 1266f42640a3SUlrich Spörlein const char * 1267f42640a3SUlrich Spörlein pr_type(int t0) 12687d56d374SYoshinobu Inoue { 12697d56d374SYoshinobu Inoue u_char t = t0 & 0xff; 1270f42640a3SUlrich Spörlein const char *cp; 12717d56d374SYoshinobu Inoue 12727d56d374SYoshinobu Inoue switch (t) { 12737d56d374SYoshinobu Inoue case ICMP6_DST_UNREACH: 12747d56d374SYoshinobu Inoue cp = "Destination Unreachable"; 12757d56d374SYoshinobu Inoue break; 12767d56d374SYoshinobu Inoue case ICMP6_PACKET_TOO_BIG: 1277c449e284SHajimu UMEMOTO cp = "Packet Too Big"; 12787d56d374SYoshinobu Inoue break; 12797d56d374SYoshinobu Inoue case ICMP6_TIME_EXCEEDED: 12807d56d374SYoshinobu Inoue cp = "Time Exceeded"; 12817d56d374SYoshinobu Inoue break; 12827d56d374SYoshinobu Inoue case ICMP6_PARAM_PROB: 12837d56d374SYoshinobu Inoue cp = "Parameter Problem"; 12847d56d374SYoshinobu Inoue break; 12857d56d374SYoshinobu Inoue case ICMP6_ECHO_REQUEST: 12867d56d374SYoshinobu Inoue cp = "Echo Request"; 12877d56d374SYoshinobu Inoue break; 12887d56d374SYoshinobu Inoue case ICMP6_ECHO_REPLY: 12897d56d374SYoshinobu Inoue cp = "Echo Reply"; 12907d56d374SYoshinobu Inoue break; 12917d56d374SYoshinobu Inoue case ICMP6_MEMBERSHIP_QUERY: 12927d56d374SYoshinobu Inoue cp = "Group Membership Query"; 12937d56d374SYoshinobu Inoue break; 12947d56d374SYoshinobu Inoue case ICMP6_MEMBERSHIP_REPORT: 12957d56d374SYoshinobu Inoue cp = "Group Membership Report"; 12967d56d374SYoshinobu Inoue break; 12977d56d374SYoshinobu Inoue case ICMP6_MEMBERSHIP_REDUCTION: 12987d56d374SYoshinobu Inoue cp = "Group Membership Reduction"; 12997d56d374SYoshinobu Inoue break; 13007d56d374SYoshinobu Inoue case ND_ROUTER_SOLICIT: 13017d56d374SYoshinobu Inoue cp = "Router Solicitation"; 13027d56d374SYoshinobu Inoue break; 13037d56d374SYoshinobu Inoue case ND_ROUTER_ADVERT: 13047d56d374SYoshinobu Inoue cp = "Router Advertisement"; 13057d56d374SYoshinobu Inoue break; 13067d56d374SYoshinobu Inoue case ND_NEIGHBOR_SOLICIT: 13077d56d374SYoshinobu Inoue cp = "Neighbor Solicitation"; 13087d56d374SYoshinobu Inoue break; 13097d56d374SYoshinobu Inoue case ND_NEIGHBOR_ADVERT: 13107d56d374SYoshinobu Inoue cp = "Neighbor Advertisement"; 13117d56d374SYoshinobu Inoue break; 13127d56d374SYoshinobu Inoue case ND_REDIRECT: 1313de68a0daSKris Kennaway cp = "Redirect"; 13147d56d374SYoshinobu Inoue break; 13157d56d374SYoshinobu Inoue default: 13167d56d374SYoshinobu Inoue cp = "Unknown"; 13177d56d374SYoshinobu Inoue break; 13187d56d374SYoshinobu Inoue } 1319777e494aSJose Luis Duran return (cp); 13207d56d374SYoshinobu Inoue } 13217d56d374SYoshinobu Inoue 13227d56d374SYoshinobu Inoue int 1323*0c2218d1SJose Luis Duran packet_ok(struct msghdr *mhdr, int cc, int seq, u_char *type, u_char *code, 1324*0c2218d1SJose Luis Duran u_char *ecn) 13257d56d374SYoshinobu Inoue { 1326e961704aSDavid Malone struct icmp6_hdr *icp; 13277d56d374SYoshinobu Inoue struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; 13287d56d374SYoshinobu Inoue char *buf = (char *)mhdr->msg_iov[0].iov_base; 13297d56d374SYoshinobu Inoue struct cmsghdr *cm; 13307d56d374SYoshinobu Inoue int *hlimp; 1331de68a0daSKris Kennaway char hbuf[NI_MAXHOST]; 13327d56d374SYoshinobu Inoue 1333de68a0daSKris Kennaway #ifdef OLDRAWSOCKET 1334de68a0daSKris Kennaway int hlen; 1335de68a0daSKris Kennaway struct ip6_hdr *ip; 1336de68a0daSKris Kennaway #endif 1337de68a0daSKris Kennaway 1338de68a0daSKris Kennaway #ifdef OLDRAWSOCKET 1339de68a0daSKris Kennaway ip = (struct ip6_hdr *) buf; 1340de68a0daSKris Kennaway hlen = sizeof(struct ip6_hdr); 1341de68a0daSKris Kennaway if (cc < hlen + sizeof(struct icmp6_hdr)) { 1342de68a0daSKris Kennaway if (verbose) { 1343cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len, 1344d24cb249SHajimu UMEMOTO hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 134533841545SHajimu UMEMOTO strlcpy(hbuf, "invalid", sizeof(hbuf)); 1346c449e284SHajimu UMEMOTO printf("packet too short (%d bytes) from %s\n", cc, 1347de68a0daSKris Kennaway hbuf); 1348de68a0daSKris Kennaway } 1349de68a0daSKris Kennaway return (0); 1350de68a0daSKris Kennaway } 1351de68a0daSKris Kennaway cc -= hlen; 1352de68a0daSKris Kennaway icp = (struct icmp6_hdr *)(buf + hlen); 1353de68a0daSKris Kennaway #else 1354f42640a3SUlrich Spörlein if (cc < (int)sizeof(struct icmp6_hdr)) { 1355de68a0daSKris Kennaway if (verbose) { 1356cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len, 1357d24cb249SHajimu UMEMOTO hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 135833841545SHajimu UMEMOTO strlcpy(hbuf, "invalid", sizeof(hbuf)); 1359c449e284SHajimu UMEMOTO printf("data too short (%d bytes) from %s\n", cc, hbuf); 1360de68a0daSKris Kennaway } 13617d56d374SYoshinobu Inoue return (0); 13627d56d374SYoshinobu Inoue } 13637d56d374SYoshinobu Inoue icp = (struct icmp6_hdr *)buf; 1364de68a0daSKris Kennaway #endif 13657d56d374SYoshinobu Inoue /* get optional information via advanced API */ 13667d56d374SYoshinobu Inoue rcvpktinfo = NULL; 13677d56d374SYoshinobu Inoue hlimp = NULL; 13687d56d374SYoshinobu Inoue for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 13697d56d374SYoshinobu Inoue cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 13707d56d374SYoshinobu Inoue if (cm->cmsg_level == IPPROTO_IPV6 && 13717d56d374SYoshinobu Inoue cm->cmsg_type == IPV6_PKTINFO && 13727d56d374SYoshinobu Inoue cm->cmsg_len == 13737d56d374SYoshinobu Inoue CMSG_LEN(sizeof(struct in6_pktinfo))) 13747d56d374SYoshinobu Inoue rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm)); 13757d56d374SYoshinobu Inoue 13767d56d374SYoshinobu Inoue if (cm->cmsg_level == IPPROTO_IPV6 && 13777d56d374SYoshinobu Inoue cm->cmsg_type == IPV6_HOPLIMIT && 13787d56d374SYoshinobu Inoue cm->cmsg_len == CMSG_LEN(sizeof(int))) 13797d56d374SYoshinobu Inoue hlimp = (int *)CMSG_DATA(cm); 13807d56d374SYoshinobu Inoue } 13817d56d374SYoshinobu Inoue if (rcvpktinfo == NULL || hlimp == NULL) { 13827d56d374SYoshinobu Inoue warnx("failed to get received hop limit or packet info"); 1383de68a0daSKris Kennaway #if 0 13847d56d374SYoshinobu Inoue return (0); 1385de68a0daSKris Kennaway #else 1386de68a0daSKris Kennaway rcvhlim = 0; /*XXX*/ 1387de68a0daSKris Kennaway #endif 1388777e494aSJose Luis Duran } else 13897d56d374SYoshinobu Inoue rcvhlim = *hlimp; 13907d56d374SYoshinobu Inoue 139164694fdcSMichael Tuexen *type = icp->icmp6_type; 139264694fdcSMichael Tuexen *code = icp->icmp6_code; 139364694fdcSMichael Tuexen if ((*type == ICMP6_TIME_EXCEEDED && 139464694fdcSMichael Tuexen *code == ICMP6_TIME_EXCEED_TRANSIT) || 13951f69b3fbSMichael Tuexen (*type == ICMP6_DST_UNREACH) || 13961f69b3fbSMichael Tuexen (*type == ICMP6_PARAM_PROB && 13971f69b3fbSMichael Tuexen *code == ICMP6_PARAMPROB_NEXTHEADER)) { 13987d56d374SYoshinobu Inoue struct ip6_hdr *hip; 1399aa96470cSMichael Tuexen struct icmp6_hdr *icmp; 140051eff8efSMichael Tuexen struct sctp_init_chunk *init; 14019d8b46c8SMichael Tuexen struct sctphdr *sctp; 14029d8b46c8SMichael Tuexen struct tcphdr *tcp; 1403aa96470cSMichael Tuexen struct udphdr *udp; 1404d7b63fafSDavid Malone void *up; 14057d56d374SYoshinobu Inoue 14067d56d374SYoshinobu Inoue hip = (struct ip6_hdr *)(icp + 1); 1407*0c2218d1SJose Luis Duran *ecn = ntohl(hip->ip6_flow & IPV6_ECN_MASK) >> 20; 1408d7b63fafSDavid Malone if ((up = get_uphdr(hip, (u_char *)(buf + cc))) == NULL) { 14097d56d374SYoshinobu Inoue if (verbose) 14107d56d374SYoshinobu Inoue warnx("failed to get upper layer header"); 14117d56d374SYoshinobu Inoue return (0); 14127d56d374SYoshinobu Inoue } 1413d7b63fafSDavid Malone switch (useproto) { 1414d7b63fafSDavid Malone case IPPROTO_ICMPV6: 1415aa96470cSMichael Tuexen icmp = (struct icmp6_hdr *)up; 1416aa96470cSMichael Tuexen if (icmp->icmp6_id == ident && 1417aa96470cSMichael Tuexen icmp->icmp6_seq == htons(seq)) 141864694fdcSMichael Tuexen return (1); 1419d7b63fafSDavid Malone break; 1420d7b63fafSDavid Malone case IPPROTO_UDP: 1421aa96470cSMichael Tuexen udp = (struct udphdr *)up; 1422cc432e23SMariusz Zaborski if (udp->uh_sport == htons(ident) && 1423aa96470cSMichael Tuexen udp->uh_dport == htons(port + seq)) 142464694fdcSMichael Tuexen return (1); 1425d7b63fafSDavid Malone break; 14269d8b46c8SMichael Tuexen case IPPROTO_SCTP: 14279d8b46c8SMichael Tuexen sctp = (struct sctphdr *)up; 142851eff8efSMichael Tuexen if (sctp->src_port != htons(ident) || 142951eff8efSMichael Tuexen sctp->dest_port != htons(port + seq)) { 143051eff8efSMichael Tuexen break; 143151eff8efSMichael Tuexen } 143251eff8efSMichael Tuexen if (datalen >= (u_long)(sizeof(struct sctphdr) + 143351eff8efSMichael Tuexen sizeof(struct sctp_init_chunk))) { 143451eff8efSMichael Tuexen if (sctp->v_tag != 0) { 143551eff8efSMichael Tuexen break; 143651eff8efSMichael Tuexen } 143751eff8efSMichael Tuexen init = (struct sctp_init_chunk *)(sctp + 1); 143851eff8efSMichael Tuexen /* Check the initiate tag, if available. */ 143951eff8efSMichael Tuexen if ((char *)&init->init.a_rwnd > buf + cc) { 144064694fdcSMichael Tuexen return (1); 144151eff8efSMichael Tuexen } 144251eff8efSMichael Tuexen if (init->init.initiate_tag == (u_int32_t) 144351eff8efSMichael Tuexen ((sctp->src_port << 16) | sctp->dest_port)) { 144464694fdcSMichael Tuexen return (1); 144551eff8efSMichael Tuexen } 144651eff8efSMichael Tuexen } else { 144751eff8efSMichael Tuexen if (sctp->v_tag == 144851eff8efSMichael Tuexen (u_int32_t)((sctp->src_port << 16) | 144951eff8efSMichael Tuexen sctp->dest_port)) { 145064694fdcSMichael Tuexen return (1); 145151eff8efSMichael Tuexen } 145251eff8efSMichael Tuexen } 14539d8b46c8SMichael Tuexen break; 14549d8b46c8SMichael Tuexen case IPPROTO_TCP: 14559d8b46c8SMichael Tuexen tcp = (struct tcphdr *)up; 14569d8b46c8SMichael Tuexen if (tcp->th_sport == htons(ident) && 14579d8b46c8SMichael Tuexen tcp->th_dport == htons(port + seq) && 14589d8b46c8SMichael Tuexen tcp->th_seq == 14599d8b46c8SMichael Tuexen (tcp_seq)((tcp->th_sport << 16) | tcp->th_dport)) 146064694fdcSMichael Tuexen return (1); 14619d8b46c8SMichael Tuexen break; 1462d7b63fafSDavid Malone case IPPROTO_NONE: 146364694fdcSMichael Tuexen return (1); 1464d7b63fafSDavid Malone default: 1465d7b63fafSDavid Malone fprintf(stderr, "Unknown probe proto %d.\n", useproto); 1466d7b63fafSDavid Malone break; 1467d7b63fafSDavid Malone } 146864694fdcSMichael Tuexen } else if (useproto == IPPROTO_ICMPV6 && *type == ICMP6_ECHO_REPLY) { 146984a1a4cfSHajimu UMEMOTO if (icp->icmp6_id == ident && 147084a1a4cfSHajimu UMEMOTO icp->icmp6_seq == htons(seq)) 147164694fdcSMichael Tuexen return (1); 14727d56d374SYoshinobu Inoue } 14737d56d374SYoshinobu Inoue if (verbose) { 1474de68a0daSKris Kennaway char sbuf[NI_MAXHOST + 1], dbuf[INET6_ADDRSTRLEN]; 1475e961704aSDavid Malone u_int8_t *p; 1476e961704aSDavid Malone int i; 14777d56d374SYoshinobu Inoue 1478cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len, 1479d24cb249SHajimu UMEMOTO sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0) 1480c449e284SHajimu UMEMOTO strlcpy(sbuf, "invalid", sizeof(sbuf)); 1481c449e284SHajimu UMEMOTO printf("\n%d bytes from %s to %s", cc, sbuf, 1482de68a0daSKris Kennaway rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1483c449e284SHajimu UMEMOTO dbuf, sizeof(dbuf)) : "?"); 148464694fdcSMichael Tuexen printf(": icmp type %d (%s) code %d\n", *type, pr_type(*type), 148564694fdcSMichael Tuexen *code); 1486de68a0daSKris Kennaway p = (u_int8_t *)(icp + 1); 1487de68a0daSKris Kennaway #define WIDTH 16 1488de68a0daSKris Kennaway for (i = 0; i < cc; i++) { 1489de68a0daSKris Kennaway if (i % WIDTH == 0) 1490c449e284SHajimu UMEMOTO printf("%04x:", i); 1491de68a0daSKris Kennaway if (i % 4 == 0) 1492c449e284SHajimu UMEMOTO printf(" "); 1493c449e284SHajimu UMEMOTO printf("%02x", p[i]); 1494de68a0daSKris Kennaway if (i % WIDTH == WIDTH - 1) 1495c449e284SHajimu UMEMOTO printf("\n"); 1496de68a0daSKris Kennaway } 1497de68a0daSKris Kennaway if (cc % WIDTH != 0) 1498c449e284SHajimu UMEMOTO printf("\n"); 14997d56d374SYoshinobu Inoue } 15007d56d374SYoshinobu Inoue return (0); 15017d56d374SYoshinobu Inoue } 15027d56d374SYoshinobu Inoue 15037d56d374SYoshinobu Inoue /* 150484a1a4cfSHajimu UMEMOTO * Increment pointer until find the UDP or ICMP header. 15057d56d374SYoshinobu Inoue */ 1506d7b63fafSDavid Malone void * 1507aa96470cSMichael Tuexen get_uphdr(struct ip6_hdr *ip6, u_char *lim) 15087d56d374SYoshinobu Inoue { 15097d56d374SYoshinobu Inoue u_char *cp = (u_char *)ip6, nh; 15107d56d374SYoshinobu Inoue int hlen; 1511d7b63fafSDavid Malone static u_char none_hdr[1]; /* Fake pointer for IPPROTO_NONE. */ 15127d56d374SYoshinobu Inoue 1513d7b63fafSDavid Malone if (cp + sizeof(*ip6) > lim) 15147d56d374SYoshinobu Inoue return (NULL); 15157d56d374SYoshinobu Inoue 15167d56d374SYoshinobu Inoue nh = ip6->ip6_nxt; 15177d56d374SYoshinobu Inoue cp += sizeof(struct ip6_hdr); 15187d56d374SYoshinobu Inoue 1519d7b63fafSDavid Malone while (lim - cp >= (nh == IPPROTO_NONE ? 0 : 8)) { 15207d56d374SYoshinobu Inoue switch (nh) { 15217d56d374SYoshinobu Inoue case IPPROTO_ESP: 15227d56d374SYoshinobu Inoue return (NULL); 152384a1a4cfSHajimu UMEMOTO case IPPROTO_ICMPV6: 1524d7b63fafSDavid Malone return (useproto == nh ? cp : NULL); 15259d8b46c8SMichael Tuexen case IPPROTO_SCTP: 15269d8b46c8SMichael Tuexen case IPPROTO_TCP: 15277d56d374SYoshinobu Inoue case IPPROTO_UDP: 1528d7b63fafSDavid Malone return (useproto == nh ? cp : NULL); 1529d7b63fafSDavid Malone case IPPROTO_NONE: 1530d7b63fafSDavid Malone return (useproto == nh ? none_hdr : NULL); 15317d56d374SYoshinobu Inoue case IPPROTO_FRAGMENT: 15327d56d374SYoshinobu Inoue hlen = sizeof(struct ip6_frag); 15337d56d374SYoshinobu Inoue nh = ((struct ip6_frag *)cp)->ip6f_nxt; 15347d56d374SYoshinobu Inoue break; 15357d56d374SYoshinobu Inoue case IPPROTO_AH: 15367d56d374SYoshinobu Inoue hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2; 15377d56d374SYoshinobu Inoue nh = ((struct ip6_ext *)cp)->ip6e_nxt; 15387d56d374SYoshinobu Inoue break; 15397d56d374SYoshinobu Inoue default: 15407d56d374SYoshinobu Inoue hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3; 15417d56d374SYoshinobu Inoue nh = ((struct ip6_ext *)cp)->ip6e_nxt; 15427d56d374SYoshinobu Inoue break; 15437d56d374SYoshinobu Inoue } 15447d56d374SYoshinobu Inoue 15457d56d374SYoshinobu Inoue cp += hlen; 15467d56d374SYoshinobu Inoue } 15477d56d374SYoshinobu Inoue 15487d56d374SYoshinobu Inoue return (NULL); 15497d56d374SYoshinobu Inoue } 15507d56d374SYoshinobu Inoue 15517d56d374SYoshinobu Inoue void 15525c3bf25fSAdrian Chadd capdns_open(void) 1553cc432e23SMariusz Zaborski { 15545c3bf25fSAdrian Chadd #ifdef WITH_CASPER 1555cc432e23SMariusz Zaborski const char *types[] = { "NAME", "ADDR" }; 1556cc432e23SMariusz Zaborski int families[1]; 1557cc432e23SMariusz Zaborski cap_channel_t *casper; 1558cc432e23SMariusz Zaborski 1559cc432e23SMariusz Zaborski casper = cap_init(); 1560cc432e23SMariusz Zaborski if (casper == NULL) 1561cc432e23SMariusz Zaborski errx(1, "unable to create casper process"); 1562cc432e23SMariusz Zaborski capdns = cap_service_open(casper, "system.dns"); 1563cc432e23SMariusz Zaborski if (capdns == NULL) 1564cc432e23SMariusz Zaborski errx(1, "unable to open system.dns service"); 1565cc432e23SMariusz Zaborski if (cap_dns_type_limit(capdns, types, nitems(types)) < 0) 1566cc432e23SMariusz Zaborski errx(1, "unable to limit access to system.dns service"); 1567cc432e23SMariusz Zaborski families[0] = AF_INET6; 1568cc432e23SMariusz Zaborski if (cap_dns_family_limit(capdns, families, nitems(families)) < 0) 1569cc432e23SMariusz Zaborski errx(1, "unable to limit access to system.dns service"); 1570cc432e23SMariusz Zaborski cap_close(casper); 15715c3bf25fSAdrian Chadd #endif /* WITH_CASPER */ 1572cc432e23SMariusz Zaborski } 1573cc432e23SMariusz Zaborski 1574cc432e23SMariusz Zaborski void 1575aa96470cSMichael Tuexen print(struct msghdr *mhdr, int cc) 15767d56d374SYoshinobu Inoue { 15777d56d374SYoshinobu Inoue struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; 1578de68a0daSKris Kennaway char hbuf[NI_MAXHOST]; 15797d56d374SYoshinobu Inoue 1580cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, (struct sockaddr *)from, from->sin6_len, 1581d24cb249SHajimu UMEMOTO hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 158233841545SHajimu UMEMOTO strlcpy(hbuf, "invalid", sizeof(hbuf)); 1583d429d720SHajimu UMEMOTO if (as_path) 1584d429d720SHajimu UMEMOTO printf(" [AS%u]", as_lookup(asn, hbuf, AF_INET6)); 1585de68a0daSKris Kennaway if (nflag) 1586c449e284SHajimu UMEMOTO printf(" %s", hbuf); 1587de68a0daSKris Kennaway else if (lflag) 1588c449e284SHajimu UMEMOTO printf(" %s (%s)", inetname((struct sockaddr *)from), hbuf); 1589de68a0daSKris Kennaway else 1590c449e284SHajimu UMEMOTO printf(" %s", inetname((struct sockaddr *)from)); 15917d56d374SYoshinobu Inoue 15927d56d374SYoshinobu Inoue if (verbose) { 1593de68a0daSKris Kennaway #ifdef OLDRAWSOCKET 1594c449e284SHajimu UMEMOTO printf(" %d bytes to %s", cc, 1595de68a0daSKris Kennaway rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1596c449e284SHajimu UMEMOTO hbuf, sizeof(hbuf)) : "?"); 1597de68a0daSKris Kennaway #else 1598c449e284SHajimu UMEMOTO printf(" %d bytes of data to %s", cc, 1599de68a0daSKris Kennaway rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1600c449e284SHajimu UMEMOTO hbuf, sizeof(hbuf)) : "?"); 1601de68a0daSKris Kennaway #endif 16027d56d374SYoshinobu Inoue } 16037d56d374SYoshinobu Inoue } 16047d56d374SYoshinobu Inoue 16057d56d374SYoshinobu Inoue /* 16067d56d374SYoshinobu Inoue * Construct an Internet address representation. 16077d56d374SYoshinobu Inoue * If the nflag has been supplied, give 16087d56d374SYoshinobu Inoue * numeric value, otherwise try for symbolic name. 16097d56d374SYoshinobu Inoue */ 1610de68a0daSKris Kennaway const char * 1611aa96470cSMichael Tuexen inetname(struct sockaddr *sa) 16127d56d374SYoshinobu Inoue { 1613e961704aSDavid Malone static char line[NI_MAXHOST], domain[MAXHOSTNAMELEN + 1]; 16147d56d374SYoshinobu Inoue static int first = 1; 1615e961704aSDavid Malone char *cp; 16167d56d374SYoshinobu Inoue 16177d56d374SYoshinobu Inoue if (first && !nflag) { 16187d56d374SYoshinobu Inoue first = 0; 1619c449e284SHajimu UMEMOTO if (gethostname(domain, sizeof(domain)) == 0 && 1620c449e284SHajimu UMEMOTO (cp = strchr(domain, '.'))) 162133841545SHajimu UMEMOTO (void) strlcpy(domain, cp + 1, sizeof(domain)); 16227d56d374SYoshinobu Inoue else 16237d56d374SYoshinobu Inoue domain[0] = 0; 16247d56d374SYoshinobu Inoue } 1625de68a0daSKris Kennaway cp = NULL; 16267d56d374SYoshinobu Inoue if (!nflag) { 1627cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, sa, sa->sa_len, line, sizeof(line), NULL, 0, 1628de68a0daSKris Kennaway NI_NAMEREQD) == 0) { 1629c449e284SHajimu UMEMOTO if ((cp = strchr(line, '.')) && 16307d56d374SYoshinobu Inoue !strcmp(cp + 1, domain)) 16317d56d374SYoshinobu Inoue *cp = 0; 1632de68a0daSKris Kennaway cp = line; 16337d56d374SYoshinobu Inoue } 16347d56d374SYoshinobu Inoue } 16357d56d374SYoshinobu Inoue if (cp) 1636777e494aSJose Luis Duran return (cp); 1637de68a0daSKris Kennaway 1638cc432e23SMariusz Zaborski if (cap_getnameinfo(capdns, sa, sa->sa_len, line, sizeof(line), NULL, 0, 1639d24cb249SHajimu UMEMOTO NI_NUMERICHOST) != 0) 164033841545SHajimu UMEMOTO strlcpy(line, "invalid", sizeof(line)); 1641777e494aSJose Luis Duran return (line); 16427d56d374SYoshinobu Inoue } 16437d56d374SYoshinobu Inoue 16449d8b46c8SMichael Tuexen /* 16459d8b46c8SMichael Tuexen * CRC32C routine for the Stream Control Transmission Protocol 16469d8b46c8SMichael Tuexen */ 16479d8b46c8SMichael Tuexen 16489d8b46c8SMichael Tuexen #define CRC32C(c, d) (c = (c >> 8) ^ crc_c[(c ^ (d)) & 0xFF]) 16499d8b46c8SMichael Tuexen 16509d8b46c8SMichael Tuexen static u_int32_t crc_c[256] = { 16519d8b46c8SMichael Tuexen 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 16529d8b46c8SMichael Tuexen 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 16539d8b46c8SMichael Tuexen 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 16549d8b46c8SMichael Tuexen 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, 16559d8b46c8SMichael Tuexen 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 16569d8b46c8SMichael Tuexen 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, 16579d8b46c8SMichael Tuexen 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 16589d8b46c8SMichael Tuexen 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, 16599d8b46c8SMichael Tuexen 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 16609d8b46c8SMichael Tuexen 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, 16619d8b46c8SMichael Tuexen 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 16629d8b46c8SMichael Tuexen 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 16639d8b46c8SMichael Tuexen 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 16649d8b46c8SMichael Tuexen 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, 16659d8b46c8SMichael Tuexen 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 16669d8b46c8SMichael Tuexen 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 16679d8b46c8SMichael Tuexen 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 16689d8b46c8SMichael Tuexen 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, 16699d8b46c8SMichael Tuexen 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 16709d8b46c8SMichael Tuexen 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, 16719d8b46c8SMichael Tuexen 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 16729d8b46c8SMichael Tuexen 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, 16739d8b46c8SMichael Tuexen 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 16749d8b46c8SMichael Tuexen 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, 16759d8b46c8SMichael Tuexen 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 16769d8b46c8SMichael Tuexen 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, 16779d8b46c8SMichael Tuexen 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 16789d8b46c8SMichael Tuexen 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, 16799d8b46c8SMichael Tuexen 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 16809d8b46c8SMichael Tuexen 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, 16819d8b46c8SMichael Tuexen 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 16829d8b46c8SMichael Tuexen 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 16839d8b46c8SMichael Tuexen 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 16849d8b46c8SMichael Tuexen 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, 16859d8b46c8SMichael Tuexen 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 16869d8b46c8SMichael Tuexen 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 16879d8b46c8SMichael Tuexen 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 16889d8b46c8SMichael Tuexen 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, 16899d8b46c8SMichael Tuexen 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 16909d8b46c8SMichael Tuexen 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, 16919d8b46c8SMichael Tuexen 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 16929d8b46c8SMichael Tuexen 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, 16939d8b46c8SMichael Tuexen 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 16949d8b46c8SMichael Tuexen 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, 16959d8b46c8SMichael Tuexen 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 16969d8b46c8SMichael Tuexen 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, 16979d8b46c8SMichael Tuexen 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 16989d8b46c8SMichael Tuexen 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, 16999d8b46c8SMichael Tuexen 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 17009d8b46c8SMichael Tuexen 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, 17019d8b46c8SMichael Tuexen 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 17029d8b46c8SMichael Tuexen 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 17039d8b46c8SMichael Tuexen 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 17049d8b46c8SMichael Tuexen 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, 17059d8b46c8SMichael Tuexen 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 17069d8b46c8SMichael Tuexen 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 17079d8b46c8SMichael Tuexen 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 17089d8b46c8SMichael Tuexen 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, 17099d8b46c8SMichael Tuexen 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 17109d8b46c8SMichael Tuexen 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, 17119d8b46c8SMichael Tuexen 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 17129d8b46c8SMichael Tuexen 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 17139d8b46c8SMichael Tuexen 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 17149d8b46c8SMichael Tuexen 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 17159d8b46c8SMichael Tuexen }; 17169d8b46c8SMichael Tuexen 17179d8b46c8SMichael Tuexen u_int32_t 1718ca19d0d7SMark Johnston sctp_crc32c(void *pack, u_int32_t len) 17199d8b46c8SMichael Tuexen { 17209d8b46c8SMichael Tuexen u_int32_t i, crc32c; 17219d8b46c8SMichael Tuexen u_int8_t byte0, byte1, byte2, byte3; 1722ca19d0d7SMark Johnston u_int8_t *buf = (u_int8_t *)pack; 17239d8b46c8SMichael Tuexen 17249d8b46c8SMichael Tuexen crc32c = ~0; 17259d8b46c8SMichael Tuexen for (i = 0; i < len; i++) 17269d8b46c8SMichael Tuexen CRC32C(crc32c, buf[i]); 17279d8b46c8SMichael Tuexen crc32c = ~crc32c; 17289d8b46c8SMichael Tuexen byte0 = crc32c & 0xff; 17299d8b46c8SMichael Tuexen byte1 = (crc32c >> 8) & 0xff; 17309d8b46c8SMichael Tuexen byte2 = (crc32c >> 16) & 0xff; 17319d8b46c8SMichael Tuexen byte3 = (crc32c >> 24) & 0xff; 17329d8b46c8SMichael Tuexen crc32c = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); 1733777e494aSJose Luis Duran return (htonl(crc32c)); 17349d8b46c8SMichael Tuexen } 17359d8b46c8SMichael Tuexen 17369d8b46c8SMichael Tuexen u_int16_t 17379d8b46c8SMichael Tuexen in_cksum(u_int16_t *addr, int len) 17389d8b46c8SMichael Tuexen { 17399d8b46c8SMichael Tuexen int nleft = len; 17409d8b46c8SMichael Tuexen u_int16_t *w = addr; 17419d8b46c8SMichael Tuexen u_int16_t answer; 17429d8b46c8SMichael Tuexen int sum = 0; 17439d8b46c8SMichael Tuexen 17449d8b46c8SMichael Tuexen /* 17459d8b46c8SMichael Tuexen * Our algorithm is simple, using a 32 bit accumulator (sum), 17469d8b46c8SMichael Tuexen * we add sequential 16 bit words to it, and at the end, fold 17479d8b46c8SMichael Tuexen * back all the carry bits from the top 16 bits into the lower 17489d8b46c8SMichael Tuexen * 16 bits. 17499d8b46c8SMichael Tuexen */ 17509d8b46c8SMichael Tuexen while (nleft > 1) { 17519d8b46c8SMichael Tuexen sum += *w++; 17529d8b46c8SMichael Tuexen nleft -= 2; 17539d8b46c8SMichael Tuexen } 17549d8b46c8SMichael Tuexen 17559d8b46c8SMichael Tuexen /* mop up an odd byte, if necessary */ 17569d8b46c8SMichael Tuexen if (nleft == 1) 17579d8b46c8SMichael Tuexen sum += *(u_char *)w; 17589d8b46c8SMichael Tuexen 17599d8b46c8SMichael Tuexen /* 17609d8b46c8SMichael Tuexen * add back carry outs from top 16 bits to low 16 bits 17619d8b46c8SMichael Tuexen */ 17629d8b46c8SMichael Tuexen sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 17639d8b46c8SMichael Tuexen sum += (sum >> 16); /* add carry */ 17649d8b46c8SMichael Tuexen answer = ~sum; /* truncate to 16 bits */ 17659d8b46c8SMichael Tuexen return (answer); 17669d8b46c8SMichael Tuexen } 17679d8b46c8SMichael Tuexen 17689d8b46c8SMichael Tuexen u_int16_t 1769cc432e23SMariusz Zaborski udp_cksum(struct sockaddr_in6 *src, struct sockaddr_in6 *dst, 1770cc432e23SMariusz Zaborski void *payload, u_int32_t len) 1771cc432e23SMariusz Zaborski { 1772cc432e23SMariusz Zaborski struct { 1773cc432e23SMariusz Zaborski struct in6_addr src; 1774cc432e23SMariusz Zaborski struct in6_addr dst; 1775cc432e23SMariusz Zaborski u_int32_t len; 1776cc432e23SMariusz Zaborski u_int8_t zero[3]; 1777cc432e23SMariusz Zaborski u_int8_t next; 1778cc432e23SMariusz Zaborski } pseudo_hdr; 1779cc432e23SMariusz Zaborski u_int16_t sum[2]; 1780cc432e23SMariusz Zaborski 1781cc432e23SMariusz Zaborski pseudo_hdr.src = src->sin6_addr; 1782cc432e23SMariusz Zaborski pseudo_hdr.dst = dst->sin6_addr; 1783cc432e23SMariusz Zaborski pseudo_hdr.len = htonl(len); 1784cc432e23SMariusz Zaborski pseudo_hdr.zero[0] = 0; 1785cc432e23SMariusz Zaborski pseudo_hdr.zero[1] = 0; 1786cc432e23SMariusz Zaborski pseudo_hdr.zero[2] = 0; 1787cc432e23SMariusz Zaborski pseudo_hdr.next = IPPROTO_UDP; 1788cc432e23SMariusz Zaborski 1789cc432e23SMariusz Zaborski sum[1] = in_cksum((u_int16_t *)&pseudo_hdr, sizeof(pseudo_hdr)); 1790cc432e23SMariusz Zaborski sum[0] = in_cksum(payload, len); 1791cc432e23SMariusz Zaborski 1792cc432e23SMariusz Zaborski return (~in_cksum(sum, sizeof(sum))); 1793cc432e23SMariusz Zaborski } 1794cc432e23SMariusz Zaborski 1795cc432e23SMariusz Zaborski u_int16_t 17969d8b46c8SMichael Tuexen tcp_chksum(struct sockaddr_in6 *src, struct sockaddr_in6 *dst, 17979d8b46c8SMichael Tuexen void *payload, u_int32_t len) 17989d8b46c8SMichael Tuexen { 17999d8b46c8SMichael Tuexen struct { 18009d8b46c8SMichael Tuexen struct in6_addr src; 18019d8b46c8SMichael Tuexen struct in6_addr dst; 18029d8b46c8SMichael Tuexen u_int32_t len; 18039d8b46c8SMichael Tuexen u_int8_t zero[3]; 18049d8b46c8SMichael Tuexen u_int8_t next; 18059d8b46c8SMichael Tuexen } pseudo_hdr; 18069d8b46c8SMichael Tuexen u_int16_t sum[2]; 18079d8b46c8SMichael Tuexen 18089d8b46c8SMichael Tuexen pseudo_hdr.src = src->sin6_addr; 18099d8b46c8SMichael Tuexen pseudo_hdr.dst = dst->sin6_addr; 18109d8b46c8SMichael Tuexen pseudo_hdr.len = htonl(len); 18119d8b46c8SMichael Tuexen pseudo_hdr.zero[0] = 0; 18129d8b46c8SMichael Tuexen pseudo_hdr.zero[1] = 0; 18139d8b46c8SMichael Tuexen pseudo_hdr.zero[2] = 0; 18149d8b46c8SMichael Tuexen pseudo_hdr.next = IPPROTO_TCP; 18159d8b46c8SMichael Tuexen 18169d8b46c8SMichael Tuexen sum[1] = in_cksum((u_int16_t *)&pseudo_hdr, sizeof(pseudo_hdr)); 18179d8b46c8SMichael Tuexen sum[0] = in_cksum(payload, len); 18189d8b46c8SMichael Tuexen 18199d8b46c8SMichael Tuexen return (~in_cksum(sum, sizeof(sum))); 18209d8b46c8SMichael Tuexen } 18219d8b46c8SMichael Tuexen 18227d56d374SYoshinobu Inoue void 1823aa96470cSMichael Tuexen usage(void) 18247d56d374SYoshinobu Inoue { 182584a1a4cfSHajimu UMEMOTO 182684a1a4cfSHajimu UMEMOTO fprintf(stderr, 1827*0c2218d1SJose Luis Duran "usage: traceroute6 [-adEIlnNrSTUv] [-A as_server] [-f firsthop] [-g gateway]\n" 18280d7d117cSHajimu UMEMOTO " [-m hoplimit] [-p port] [-q probes] [-s src] [-w waittime] target\n" 18290d7d117cSHajimu UMEMOTO " [datalen]\n"); 18307d56d374SYoshinobu Inoue exit(1); 18317d56d374SYoshinobu Inoue } 1832