1130422Sdwmalone/* $KAME: traceroute6.c,v 1.68 2004/01/25 11:16:12 suz Exp $ */ 262637Skris 355163Sshin/* 455163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 555163Sshin * All rights reserved. 655163Sshin * 755163Sshin * Redistribution and use in source and binary forms, with or without 855163Sshin * modification, are permitted provided that the following conditions 955163Sshin * are met: 1055163Sshin * 1. Redistributions of source code must retain the above copyright 1155163Sshin * notice, this list of conditions and the following disclaimer. 1255163Sshin * 2. Redistributions in binary form must reproduce the above copyright 1355163Sshin * notice, this list of conditions and the following disclaimer in the 1455163Sshin * documentation and/or other materials provided with the distribution. 1555163Sshin * 3. Neither the name of the project nor the names of its contributors 1655163Sshin * may be used to endorse or promote products derived from this software 1755163Sshin * without specific prior written permission. 1855163Sshin * 1955163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2055163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2155163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2255163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2355163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2455163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2555163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2655163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2755163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2855163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2955163Sshin * SUCH DAMAGE. 3055163Sshin */ 3155163Sshin 3255163Sshin/*- 3355163Sshin * Copyright (c) 1990, 1993 3455163Sshin * The Regents of the University of California. All rights reserved. 3555163Sshin * 3655163Sshin * This code is derived from software contributed to Berkeley by 3755163Sshin * Van Jacobson. 3855163Sshin * 3955163Sshin * Redistribution and use in source and binary forms, with or without 4055163Sshin * modification, are permitted provided that the following conditions 4155163Sshin * are met: 4255163Sshin * 1. Redistributions of source code must retain the above copyright 4355163Sshin * notice, this list of conditions and the following disclaimer. 4455163Sshin * 2. Redistributions in binary form must reproduce the above copyright 4555163Sshin * notice, this list of conditions and the following disclaimer in the 4655163Sshin * documentation and/or other materials provided with the distribution. 4755163Sshin * 4. Neither the name of the University nor the names of its contributors 4855163Sshin * may be used to endorse or promote products derived from this software 4955163Sshin * without specific prior written permission. 5055163Sshin * 5155163Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5255163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5355163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5455163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5555163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5655163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5755163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5855163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5955163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6055163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6155163Sshin * SUCH DAMAGE. 6255163Sshin */ 6355163Sshin 6455163Sshin#ifndef lint 65216185Suqsstatic const char copyright[] = 6655163Sshin"@(#) Copyright (c) 1990, 1993\n\ 6755163Sshin The Regents of the University of California. All rights reserved.\n"; 6855163Sshin#endif /* not lint */ 6955163Sshin 7055163Sshin#ifndef lint 7162637Skris#if 0 7255163Sshinstatic char sccsid[] = "@(#)traceroute.c 8.1 (Berkeley) 6/6/93"; 7362637Skris#endif 7462637Skrisstatic const char rcsid[] = 7562637Skris "$FreeBSD$"; 7655163Sshin#endif /* not lint */ 7755163Sshin 7855163Sshin/* 7955163Sshin * traceroute host - trace the route ip packets follow going to "host". 8055163Sshin * 8155163Sshin * Attempt to trace the route an ip packet would follow to some 8255163Sshin * internet host. We find out intermediate hops by launching probe 8355163Sshin * packets with a small ttl (time to live) then listening for an 8455163Sshin * icmp "time exceeded" reply from a gateway. We start our probes 8555163Sshin * with a ttl of one and increase by one until we get an icmp "port 8655163Sshin * unreachable" (which means we got to "host") or hit a max (which 8755163Sshin * defaults to 30 hops & can be changed with the -m flag). Three 8855163Sshin * probes (change with -q flag) are sent at each ttl setting and a 8955163Sshin * line is printed showing the ttl, address of the gateway and 9055163Sshin * round trip time of each probe. If the probe answers come from 9155163Sshin * different gateways, the address of each responding system will 9255163Sshin * be printed. If there is no response within a 5 sec. timeout 9355163Sshin * interval (changed with the -w flag), a "*" is printed for that 9455163Sshin * probe. 9555163Sshin * 9655163Sshin * Probe packets are UDP format. We don't want the destination 9755163Sshin * host to process them so the destination port is set to an 9855163Sshin * unlikely value (if some clod on the destination is using that 9955163Sshin * value, it can be changed with the -p flag). 10055163Sshin * 10155163Sshin * A sample use might be: 10255163Sshin * 10355163Sshin * [yak 71]% traceroute nis.nsf.net. 10455163Sshin * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet 10555163Sshin * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms 10655163Sshin * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 10755163Sshin * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 10855163Sshin * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms 10955163Sshin * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms 11055163Sshin * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms 11155163Sshin * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms 11255163Sshin * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms 11355163Sshin * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms 11455163Sshin * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms 11555163Sshin * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms 11655163Sshin * 11755163Sshin * Note that lines 2 & 3 are the same. This is due to a buggy 11855163Sshin * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards 11955163Sshin * packets with a zero ttl. 12055163Sshin * 12155163Sshin * A more interesting example is: 12255163Sshin * 12355163Sshin * [yak 72]% traceroute allspice.lcs.mit.edu. 12455163Sshin * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max 12555163Sshin * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 12655163Sshin * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms 12755163Sshin * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms 12855163Sshin * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms 12955163Sshin * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms 13055163Sshin * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms 13155163Sshin * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms 13255163Sshin * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms 13355163Sshin * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms 13455163Sshin * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms 13555163Sshin * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms 13655163Sshin * 12 * * * 13755163Sshin * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms 13855163Sshin * 14 * * * 13955163Sshin * 15 * * * 14055163Sshin * 16 * * * 14155163Sshin * 17 * * * 14255163Sshin * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms 14355163Sshin * 14455163Sshin * (I start to see why I'm having so much trouble with mail to 14555163Sshin * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away 14655163Sshin * either don't send ICMP "time exceeded" messages or send them 14755163Sshin * with a ttl too small to reach us. 14 - 17 are running the 14855163Sshin * MIT C Gateway code that doesn't send "time exceeded"s. God 14955163Sshin * only knows what's going on with 12. 15055163Sshin * 15155163Sshin * The silent gateway 12 in the above may be the result of a bug in 15255163Sshin * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) 15355163Sshin * sends an unreachable message using whatever ttl remains in the 15455163Sshin * original datagram. Since, for gateways, the remaining ttl is 15555163Sshin * zero, the icmp "time exceeded" is guaranteed to not make it back 15655163Sshin * to us. The behavior of this bug is slightly more interesting 15755163Sshin * when it appears on the destination system: 15855163Sshin * 15955163Sshin * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 16055163Sshin * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms 16155163Sshin * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms 16255163Sshin * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms 16355163Sshin * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms 16455163Sshin * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms 16555163Sshin * 7 * * * 16655163Sshin * 8 * * * 16755163Sshin * 9 * * * 16855163Sshin * 10 * * * 16955163Sshin * 11 * * * 17055163Sshin * 12 * * * 17155163Sshin * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! 17255163Sshin * 17355163Sshin * Notice that there are 12 "gateways" (13 is the final 17455163Sshin * destination) and exactly the last half of them are "missing". 17555163Sshin * What's really happening is that rip (a Sun-3 running Sun OS3.5) 17655163Sshin * is using the ttl from our arriving datagram as the ttl in its 17755163Sshin * icmp reply. So, the reply will time out on the return path 17855163Sshin * (with no notice sent to anyone since icmp's aren't sent for 17955163Sshin * icmp's) until we probe with a ttl that's at least twice the path 18055163Sshin * length. I.e., rip is really only 7 hops away. A reply that 18155163Sshin * returns with a ttl of 1 is a clue this problem exists. 18255163Sshin * Traceroute prints a "!" after the time if the ttl is <= 1. 18355163Sshin * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or 18455163Sshin * non-standard (HPUX) software, expect to see this problem 18555163Sshin * frequently and/or take care picking the target host of your 18655163Sshin * probes. 18755163Sshin * 18855163Sshin * Other possible annotations after the time are !H, !N, !P (got a host, 18955163Sshin * network or protocol unreachable, respectively), !S or !F (source 19055163Sshin * route failed or fragmentation needed -- neither of these should 19155163Sshin * ever occur and the associated gateway is busted if you see one). If 19255163Sshin * almost all the probes result in some kind of unreachable, traceroute 19355163Sshin * will give up and exit. 19455163Sshin * 19555163Sshin * Notes 19655163Sshin * ----- 19755163Sshin * This program must be run by root or be setuid. (I suggest that 19855163Sshin * you *don't* make it setuid -- casual use could result in a lot 19955163Sshin * of unnecessary traffic on our poor, congested nets.) 20055163Sshin * 20155163Sshin * This program requires a kernel mod that does not appear in any 20255163Sshin * system available from Berkeley: A raw ip socket using proto 20355163Sshin * IPPROTO_RAW must interpret the data sent as an ip datagram (as 204108533Sschweikh * opposed to data to be wrapped in an ip datagram). See the README 20555163Sshin * file that came with the source to this program for a description 20655163Sshin * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may 20755163Sshin * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE 20855163Sshin * MODIFIED TO RUN THIS PROGRAM. 20955163Sshin * 21055163Sshin * The udp port usage may appear bizarre (well, ok, it is bizarre). 21155163Sshin * The problem is that an icmp message only contains 8 bytes of 21255163Sshin * data from the original datagram. 8 bytes is the size of a udp 21355163Sshin * header so, if we want to associate replies with the original 21455163Sshin * datagram, the necessary information must be encoded into the 21555163Sshin * udp header (the ip id could be used but there's no way to 21655163Sshin * interlock with the kernel's assignment of ip id's and, anyway, 21755163Sshin * it would have taken a lot more kernel hacking to allow this 21855163Sshin * code to set the ip id). So, to allow two or more users to 21955163Sshin * use traceroute simultaneously, we use this task's pid as the 22055163Sshin * source port (the high bit is set to move the port number out 22155163Sshin * of the "likely" range). To keep track of which probe is being 22255163Sshin * replied to (so times and/or hop counts don't get confused by a 22355163Sshin * reply that was delayed in transit), we increment the destination 22455163Sshin * port number before each probe. 22555163Sshin * 22655163Sshin * Don't use this as a coding example. I was trying to find a 22755163Sshin * routing problem and this code sort-of popped out after 48 hours 22855163Sshin * without sleep. I was amazed it ever compiled, much less ran. 22955163Sshin * 23055163Sshin * I stole the idea for this program from Steve Deering. Since 23155163Sshin * the first release, I've learned that had I attended the right 23255163Sshin * IETF working group meetings, I also could have stolen it from Guy 23355163Sshin * Almes or Matt Mathis. I don't know (or care) who came up with 23455163Sshin * the idea first. I envy the originators' perspicacity and I'm 23555163Sshin * glad they didn't keep the idea a secret. 23655163Sshin * 23755163Sshin * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or 23855163Sshin * enhancements to the original distribution. 23955163Sshin * 24055163Sshin * I've hacked up a round-trip-route version of this that works by 24155163Sshin * sending a loose-source-routed udp datagram through the destination 24255163Sshin * back to yourself. Unfortunately, SO many gateways botch source 24355163Sshin * routing, the thing is almost worthless. Maybe one day... 24455163Sshin * 24555163Sshin * -- Van Jacobson (van@helios.ee.lbl.gov) 24655163Sshin * Tue Dec 20 03:50:13 PST 1988 24755163Sshin */ 24855163Sshin 24955163Sshin#include <sys/param.h> 25055163Sshin#include <sys/time.h> 25155163Sshin#include <sys/socket.h> 25255163Sshin#include <sys/uio.h> 25355163Sshin#include <sys/file.h> 25455163Sshin#include <sys/ioctl.h> 255122574Sume#include <sys/sysctl.h> 25655163Sshin 25755163Sshin#include <netinet/in.h> 25855163Sshin 25955163Sshin#include <arpa/inet.h> 26055163Sshin 26155163Sshin#include <netdb.h> 26255163Sshin#include <stdio.h> 26355163Sshin#include <err.h> 26466808Skris#ifdef HAVE_POLL 26566808Skris#include <poll.h> 26666808Skris#endif 26755163Sshin#include <errno.h> 26855163Sshin#include <stdlib.h> 26955163Sshin#include <string.h> 27055163Sshin#include <unistd.h> 27155163Sshin 27255163Sshin#include <netinet/ip6.h> 27355163Sshin#include <netinet/icmp6.h> 27455163Sshin#include <netinet/udp.h> 27555163Sshin 27655163Sshin#ifdef IPSEC 27755163Sshin#include <net/route.h> 278171135Sgnn#include <netipsec/ipsec.h> 27955163Sshin#endif 28055163Sshin 281196475Sume#include "as.h" 282196475Sume 28362637Skris#define DUMMY_PORT 10010 28455163Sshin 28555163Sshin#define MAXPACKET 65535 /* max ip packet size */ 28655163Sshin 28762637Skris#ifndef HAVE_GETIPNODEBYNAME 28862637Skris#define getipnodebyname(x, y, z, u) gethostbyname2((x), (y)) 28962637Skris#define freehostent(x) 29062637Skris#endif 29162637Skris 29255163Sshin/* 29355163Sshin * format of a (udp) probe packet. 29455163Sshin */ 295122574Sumestruct tv32 { 296122574Sume u_int32_t tv32_sec; 297122574Sume u_int32_t tv32_usec; 298122574Sume}; 29955163Sshin 300130422Sdwmalonestruct opacket { 301130422Sdwmalone u_char seq; /* sequence number of this packet */ 302130422Sdwmalone u_char hops; /* hop limit of the packet */ 303130422Sdwmalone u_char pad[2]; 304130422Sdwmalone struct tv32 tv; /* time packet left */ 305130422Sdwmalone} __attribute__((__packed__)); 306130422Sdwmalone 30755163Sshinu_char packet[512]; /* last inbound (icmp) packet */ 30855163Sshinstruct opacket *outpacket; /* last output (udp) packet */ 30955163Sshin 310173412Skevloint main(int, char *[]); 311173412Skevloint wait_for_reply(int, struct msghdr *); 31262637Skris#ifdef IPSEC 31362637Skris#ifdef IPSEC_POLICY_IPSEC 314173412Skevloint setpolicy(int so, char *policy); 31562637Skris#endif 31662637Skris#endif 317173412Skevlovoid send_probe(int, u_long); 318176154Sdwmalonevoid *get_uphdr(struct ip6_hdr *, u_char *); 319173412Skevloint get_hoplim(struct msghdr *); 320173412Skevlodouble deltaT(struct timeval *, struct timeval *); 321216185Suqsconst char *pr_type(int); 322173412Skevloint packet_ok(struct msghdr *, int, int); 323173412Skevlovoid print(struct msghdr *, int); 324173412Skevloconst char *inetname(struct sockaddr *); 325173412Skevlovoid usage(void); 32655163Sshin 32755163Sshinint rcvsock; /* receive (icmp) socket file descriptor */ 32855163Sshinint sndsock; /* send (udp) socket file descriptor */ 32955163Sshin 33055163Sshinstruct msghdr rcvmhdr; 33155163Sshinstruct iovec rcviov[2]; 33255163Sshinint rcvhlim; 33355163Sshinstruct in6_pktinfo *rcvpktinfo; 33455163Sshin 33555163Sshinstruct sockaddr_in6 Src, Dst, Rcv; 336122574Sumeu_long datalen; /* How much data */ 337122574Sume#define ICMP6ECHOLEN 8 33862637Skris/* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */ 33962637Skrischar rtbuf[2064]; 34062637Skris#ifdef USE_RFC2292BIS 34162637Skrisstruct ip6_rthdr *rth; 34262637Skris#endif 34355163Sshinstruct cmsghdr *cmsg; 34455163Sshin 34555163Sshinchar *source = 0; 34655163Sshinchar *hostname; 34755163Sshin 348122574Sumeu_long nprobes = 3; 349122574Sumeu_long first_hop = 1; 350122574Sumeu_long max_hops = 30; 351122574Sumeu_int16_t srcport; 352122574Sumeu_int16_t port = 32768+666; /* start udp dest port # for probe packets */ 353122574Sumeu_int16_t ident; 35455163Sshinint options; /* socket options */ 35555163Sshinint verbose; 35655163Sshinint waittime = 5; /* time to wait for response (in seconds) */ 35755163Sshinint nflag; /* print addresses numerically */ 358176154Sdwmaloneint useproto = IPPROTO_UDP; /* protocol to use to send packet */ 35955163Sshinint lflag; /* print both numerical address & hostname */ 360196475Sumeint as_path; /* print as numbers for each hop */ 361196475Sumechar *as_server = NULL; 362196475Sumevoid *asn; 36355163Sshin 36455163Sshinint 36555163Sshinmain(argc, argv) 36655163Sshin int argc; 36755163Sshin char *argv[]; 36855163Sshin{ 369130422Sdwmalone int mib[4] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM }; 370130422Sdwmalone char hbuf[NI_MAXHOST], src0[NI_MAXHOST], *ep; 371216185Suqs int ch, i, on = 1, seq, rcvcmsglen, error; 37255658Sshin struct addrinfo hints, *res; 37362637Skris static u_char *rcvcmsgbuf; 374130422Sdwmalone u_long probe, hops, lport; 375130422Sdwmalone struct hostent *hp; 376216185Suqs size_t size, minlen; 377167314Skevlo uid_t uid; 37855163Sshin 37957439Sshin /* 38057439Sshin * Receive ICMP 38157439Sshin */ 38257439Sshin if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 38362637Skris perror("socket(ICMPv6)"); 38457439Sshin exit(5); 38557439Sshin } 38662637Skris 387122574Sume size = sizeof(i); 388122574Sume (void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &i, &size, NULL, 0); 389122574Sume max_hops = i; 390122574Sume 39162637Skris /* specify to tell receiving interface */ 39262637Skris#ifdef IPV6_RECVPKTINFO 39362637Skris if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 394121435Sume sizeof(on)) < 0) 39562637Skris err(1, "setsockopt(IPV6_RECVPKTINFO)"); 39662637Skris#else /* old adv. API */ 39762637Skris if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_PKTINFO, &on, 398121435Sume sizeof(on)) < 0) 39962637Skris err(1, "setsockopt(IPV6_PKTINFO)"); 40062637Skris#endif 40162637Skris 40262637Skris /* specify to tell value of hoplimit field of received IP6 hdr */ 40362637Skris#ifdef IPV6_RECVHOPLIMIT 40462637Skris if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, 405121435Sume sizeof(on)) < 0) 40662637Skris err(1, "setsockopt(IPV6_RECVHOPLIMIT)"); 40762637Skris#else /* old adv. API */ 40862637Skris if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, 409121435Sume sizeof(on)) < 0) 41062637Skris err(1, "setsockopt(IPV6_HOPLIMIT)"); 41162637Skris#endif 41262637Skris 41355163Sshin seq = 0; 414130422Sdwmalone 415196475Sume while ((ch = getopt(argc, argv, "aA:df:g:Ilm:nNp:q:rs:Uvw:")) != -1) 416121435Sume switch (ch) { 417196475Sume case 'a': 418196475Sume as_path = 1; 419196475Sume break; 420196475Sume case 'A': 421196475Sume as_path = 1; 422196475Sume as_server = optarg; 423196475Sume break; 42455163Sshin case 'd': 42555163Sshin options |= SO_DEBUG; 42655163Sshin break; 42762637Skris case 'f': 42878064Sume ep = NULL; 429122574Sume errno = 0; 43078064Sume first_hop = strtoul(optarg, &ep, 0); 431122574Sume if (errno || !*optarg || *ep || first_hop > 255) { 432121435Sume fprintf(stderr, 43378064Sume "traceroute6: invalid min hoplimit.\n"); 43478064Sume exit(1); 43578064Sume } 43655163Sshin break; 43755163Sshin case 'g': 43855163Sshin hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno); 43955163Sshin if (hp == NULL) { 440121435Sume fprintf(stderr, 44155163Sshin "traceroute6: unknown host %s\n", optarg); 44255163Sshin exit(1); 44355163Sshin } 44462637Skris#ifdef USE_RFC2292BIS 44562637Skris if (rth == NULL) { 44662637Skris /* 44762637Skris * XXX: We can't detect the number of 44862637Skris * intermediate nodes yet. 44962637Skris */ 45062637Skris if ((rth = inet6_rth_init((void *)rtbuf, 451121435Sume sizeof(rtbuf), IPV6_RTHDR_TYPE_0, 452121435Sume 0)) == NULL) { 453121435Sume fprintf(stderr, 454121435Sume "inet6_rth_init failed.\n"); 45562637Skris exit(1); 45662637Skris } 45762637Skris } 45862637Skris if (inet6_rth_add((void *)rth, 459121435Sume (struct in6_addr *)hp->h_addr)) { 460121435Sume fprintf(stderr, 461121435Sume "inet6_rth_add failed for %s\n", 462121435Sume optarg); 46362637Skris exit(1); 46462637Skris } 46562637Skris#else /* old advanced API */ 46655163Sshin if (cmsg == NULL) 46755163Sshin cmsg = inet6_rthdr_init(rtbuf, IPV6_RTHDR_TYPE_0); 468121435Sume inet6_rthdr_add(cmsg, (struct in6_addr *)hp->h_addr, 469121435Sume IPV6_RTHDR_LOOSE); 47062637Skris#endif 47162637Skris freehostent(hp); 47255163Sshin break; 473122574Sume case 'I': 474176154Sdwmalone useproto = IPPROTO_ICMPV6; 475122574Sume ident = htons(getpid() & 0xffff); /* same as ping6 */ 476122574Sume break; 47762637Skris case 'l': 47862637Skris lflag++; 47962637Skris break; 48055163Sshin case 'm': 48178064Sume ep = NULL; 482122574Sume errno = 0; 48378064Sume max_hops = strtoul(optarg, &ep, 0); 484122574Sume if (errno || !*optarg || *ep || max_hops > 255) { 485121435Sume fprintf(stderr, 48678064Sume "traceroute6: invalid max hoplimit.\n"); 48778064Sume exit(1); 48878064Sume } 48955163Sshin break; 49055163Sshin case 'n': 49155163Sshin nflag++; 49255163Sshin break; 493176154Sdwmalone case 'N': 494176154Sdwmalone useproto = IPPROTO_NONE; 495176154Sdwmalone break; 49655163Sshin case 'p': 49778064Sume ep = NULL; 498122574Sume errno = 0; 499122574Sume lport = strtoul(optarg, &ep, 0); 500122574Sume if (errno || !*optarg || *ep) { 501122574Sume fprintf(stderr, "traceroute6: invalid port.\n"); 50278064Sume exit(1); 50378064Sume } 504122574Sume if (lport == 0 || lport != (lport & 0xffff)) { 505121435Sume fprintf(stderr, 506122574Sume "traceroute6: port out of range.\n"); 50755163Sshin exit(1); 50855163Sshin } 509122574Sume port = lport & 0xffff; 51055163Sshin break; 51155163Sshin case 'q': 51278064Sume ep = NULL; 513122574Sume errno = 0; 51478064Sume nprobes = strtoul(optarg, &ep, 0); 515122574Sume if (errno || !*optarg || *ep) { 516121435Sume fprintf(stderr, 51778064Sume "traceroute6: invalid nprobes.\n"); 51878064Sume exit(1); 51978064Sume } 52055163Sshin if (nprobes < 1) { 521121435Sume fprintf(stderr, 52255163Sshin "traceroute6: nprobes must be >0.\n"); 52355163Sshin exit(1); 52455163Sshin } 52555163Sshin break; 52655163Sshin case 'r': 52755163Sshin options |= SO_DONTROUTE; 52855163Sshin break; 52955163Sshin case 's': 53055163Sshin /* 53155163Sshin * set the ip source address of the outbound 53255163Sshin * probe (e.g., on a multi-homed host). 53355163Sshin */ 53455163Sshin source = optarg; 53555163Sshin break; 53655163Sshin case 'v': 53755163Sshin verbose++; 53855163Sshin break; 539176154Sdwmalone case 'U': 540176154Sdwmalone useproto = IPPROTO_UDP; 541176154Sdwmalone break; 54255163Sshin case 'w': 54378064Sume ep = NULL; 544122574Sume errno = 0; 54578064Sume waittime = strtoul(optarg, &ep, 0); 546122574Sume if (errno || !*optarg || *ep) { 547121435Sume fprintf(stderr, 54878064Sume "traceroute6: invalid wait time.\n"); 54978064Sume exit(1); 55078064Sume } 551169144Smaxim if (waittime < 1) { 552121435Sume fprintf(stderr, 553169144Smaxim "traceroute6: wait must be >= 1 sec.\n"); 55455163Sshin exit(1); 55555163Sshin } 55655163Sshin break; 55755163Sshin default: 55855163Sshin usage(); 55955163Sshin } 56055163Sshin argc -= optind; 56155163Sshin argv += optind; 56255163Sshin 563176154Sdwmalone /* 564176154Sdwmalone * Open socket to send probe packets. 565176154Sdwmalone */ 566176154Sdwmalone switch (useproto) { 567176154Sdwmalone case IPPROTO_ICMPV6: 568176154Sdwmalone sndsock = rcvsock; 569176154Sdwmalone break; 570176154Sdwmalone case IPPROTO_UDP: 571176154Sdwmalone if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 572176154Sdwmalone perror("socket(SOCK_DGRAM)"); 573176154Sdwmalone exit(5); 574176154Sdwmalone } 575176154Sdwmalone break; 576176154Sdwmalone case IPPROTO_NONE: 577176154Sdwmalone if ((sndsock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) { 578176154Sdwmalone perror("socket(SOCK_RAW)"); 579176154Sdwmalone exit(5); 580176154Sdwmalone } 581176154Sdwmalone break; 582176154Sdwmalone default: 583176154Sdwmalone fprintf(stderr, "traceroute6: unknown probe protocol %d", 584176154Sdwmalone useproto); 585176154Sdwmalone exit(5); 586176154Sdwmalone } 587122574Sume if (max_hops < first_hop) { 588122574Sume fprintf(stderr, 589122574Sume "traceroute6: max hoplimit must be larger than first hoplimit.\n"); 590122574Sume exit(1); 591122574Sume } 592122574Sume 593176154Sdwmalone /* revoke privs */ 594176154Sdwmalone uid = getuid(); 595176154Sdwmalone if (setresuid(uid, uid, uid) == -1) { 596176154Sdwmalone perror("setresuid"); 597176154Sdwmalone exit(1); 598176154Sdwmalone } 599176154Sdwmalone 600176154Sdwmalone 60178064Sume if (argc < 1 || argc > 2) 60255163Sshin usage(); 60355163Sshin 60462637Skris#if 1 60555163Sshin setvbuf(stdout, NULL, _IOLBF, BUFSIZ); 60662637Skris#else 607130422Sdwmalone setlinebuf(stdout); 60862637Skris#endif 60955163Sshin 61055658Sshin memset(&hints, 0, sizeof(hints)); 61155658Sshin hints.ai_family = PF_INET6; 61255658Sshin hints.ai_socktype = SOCK_RAW; 61355658Sshin hints.ai_protocol = IPPROTO_ICMPV6; 61455658Sshin hints.ai_flags = AI_CANONNAME; 61555658Sshin error = getaddrinfo(*argv, NULL, &hints, &res); 61655658Sshin if (error) { 617121435Sume fprintf(stderr, 618121435Sume "traceroute6: %s\n", gai_strerror(error)); 61955658Sshin exit(1); 62055163Sshin } 62162637Skris if (res->ai_addrlen != sizeof(Dst)) { 622121435Sume fprintf(stderr, 623121435Sume "traceroute6: size of sockaddr mismatch\n"); 62462637Skris exit(1); 62562637Skris } 62655658Sshin memcpy(&Dst, res->ai_addr, res->ai_addrlen); 62755658Sshin hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv; 62878064Sume if (!hostname) { 629121435Sume fprintf(stderr, "traceroute6: not enough core\n"); 63078064Sume exit(1); 63178064Sume } 632122574Sume if (res->ai_next) { 633122574Sume if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, 634122574Sume sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 635122574Sume strlcpy(hbuf, "?", sizeof(hbuf)); 636122574Sume fprintf(stderr, "traceroute6: Warning: %s has multiple " 637122574Sume "addresses; using %s\n", hostname, hbuf); 638122574Sume } 63955163Sshin 64078064Sume if (*++argv) { 64178064Sume ep = NULL; 642122574Sume errno = 0; 64378064Sume datalen = strtoul(*argv, &ep, 0); 644122574Sume if (errno || !*argv || *ep) { 645121435Sume fprintf(stderr, 64678064Sume "traceroute6: invalid packet length.\n"); 64778064Sume exit(1); 64878064Sume } 64978064Sume } 650176154Sdwmalone switch (useproto) { 651176154Sdwmalone case IPPROTO_ICMPV6: 652122574Sume minlen = ICMP6ECHOLEN + sizeof(struct tv32); 653176154Sdwmalone break; 654176154Sdwmalone case IPPROTO_UDP: 655122574Sume minlen = sizeof(struct opacket); 656176154Sdwmalone break; 657176154Sdwmalone case IPPROTO_NONE: 658176154Sdwmalone minlen = 0; 659176154Sdwmalone datalen = 0; 660176154Sdwmalone break; 661176154Sdwmalone default: 662176154Sdwmalone fprintf(stderr, "traceroute6: unknown probe protocol %d.\n", 663176154Sdwmalone useproto); 664176154Sdwmalone exit(1); 665176154Sdwmalone } 666122574Sume if (datalen < minlen) 667122574Sume datalen = minlen; 668122574Sume else if (datalen >= MAXPACKET) { 669121435Sume fprintf(stderr, 670216185Suqs "traceroute6: packet size must be %zu <= s < %d.\n", 671216185Suqs minlen, MAXPACKET); 67255163Sshin exit(1); 67355163Sshin } 674216185Suqs outpacket = malloc(datalen); 675130422Sdwmalone if (!outpacket) { 67662637Skris perror("malloc"); 67755163Sshin exit(1); 67855163Sshin } 67955163Sshin (void) bzero((char *)outpacket, datalen); 68055163Sshin 68155163Sshin /* initialize msghdr for receiving packets */ 68255163Sshin rcviov[0].iov_base = (caddr_t)packet; 68355163Sshin rcviov[0].iov_len = sizeof(packet); 68462637Skris rcvmhdr.msg_name = (caddr_t)&Rcv; 68562637Skris rcvmhdr.msg_namelen = sizeof(Rcv); 68655163Sshin rcvmhdr.msg_iov = rcviov; 68755163Sshin rcvmhdr.msg_iovlen = 1; 688130422Sdwmalone rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 689130422Sdwmalone CMSG_SPACE(sizeof(int)); 69062637Skris if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) { 691121435Sume fprintf(stderr, "traceroute6: malloc failed\n"); 69262637Skris exit(1); 69362637Skris } 69455163Sshin rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; 69562637Skris rcvmhdr.msg_controllen = rcvcmsglen; 69655163Sshin 69755163Sshin if (options & SO_DEBUG) 69855163Sshin (void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, 699121435Sume (char *)&on, sizeof(on)); 70055163Sshin if (options & SO_DONTROUTE) 70155163Sshin (void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, 702121435Sume (char *)&on, sizeof(on)); 70355163Sshin#ifdef IPSEC 70455163Sshin#ifdef IPSEC_POLICY_IPSEC 70555163Sshin /* 70655163Sshin * do not raise error even if setsockopt fails, kernel may have ipsec 70755163Sshin * turned off. 70855163Sshin */ 70955163Sshin if (setpolicy(rcvsock, "in bypass") < 0) 71064276Skris errx(1, "%s", ipsec_strerror()); 71155163Sshin if (setpolicy(rcvsock, "out bypass") < 0) 71264276Skris errx(1, "%s", ipsec_strerror()); 71362637Skris#else 71462637Skris { 71562637Skris int level = IPSEC_LEVEL_NONE; 71662637Skris 71762637Skris (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, 718121435Sume sizeof(level)); 71962637Skris (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, 720121435Sume sizeof(level)); 72162637Skris#ifdef IP_AUTH_TRANS_LEVEL 72262637Skris (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, 723121435Sume sizeof(level)); 72462637Skris#else 72562637Skris (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, 726121435Sume sizeof(level)); 72762637Skris#endif 72862637Skris#ifdef IP_AUTH_NETWORK_LEVEL 72962637Skris (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, 730121435Sume sizeof(level)); 73162637Skris#endif 73262637Skris } 73355163Sshin#endif /*IPSEC_POLICY_IPSEC*/ 73455163Sshin#endif /*IPSEC*/ 73555163Sshin 73662637Skris#ifdef SO_SNDBUF 737122574Sume i = datalen; 738122574Sume if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&i, 739176154Sdwmalone sizeof(i)) < 0 && useproto != IPPROTO_NONE) { 74062637Skris perror("setsockopt(SO_SNDBUF)"); 74155163Sshin exit(6); 74255163Sshin } 74362637Skris#endif /* SO_SNDBUF */ 74455163Sshin if (options & SO_DEBUG) 74555163Sshin (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 746121435Sume (char *)&on, sizeof(on)); 74755163Sshin if (options & SO_DONTROUTE) 74855163Sshin (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, 749121435Sume (char *)&on, sizeof(on)); 75062637Skris#ifdef USE_RFC2292BIS 75162637Skris if (rth) {/* XXX: there is no library to finalize the header... */ 75262637Skris rth->ip6r_len = rth->ip6r_segleft * 2; 75362637Skris if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR, 754121435Sume (void *)rth, (rth->ip6r_len + 1) << 3)) { 755121435Sume fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n", 756121435Sume strerror(errno)); 75762637Skris exit(1); 75862637Skris } 75962637Skris } 76062637Skris#else /* old advanced API */ 76155163Sshin if (cmsg != NULL) { 76255163Sshin inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE); 76362637Skris if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_PKTOPTIONS, 764121435Sume rtbuf, cmsg->cmsg_len) < 0) { 765121435Sume fprintf(stderr, "setsockopt(IPV6_PKTOPTIONS): %s\n", 766121435Sume strerror(errno)); 76762637Skris exit(1); 76862637Skris } 76955163Sshin } 77062637Skris#endif /* USE_RFC2292BIS */ 77155163Sshin#ifdef IPSEC 77255163Sshin#ifdef IPSEC_POLICY_IPSEC 77355163Sshin /* 77455163Sshin * do not raise error even if setsockopt fails, kernel may have ipsec 77555163Sshin * turned off. 77655163Sshin */ 77755163Sshin if (setpolicy(sndsock, "in bypass") < 0) 77864276Skris errx(1, "%s", ipsec_strerror()); 77955163Sshin if (setpolicy(sndsock, "out bypass") < 0) 78064276Skris errx(1, "%s", ipsec_strerror()); 78162637Skris#else 78262637Skris { 78362637Skris int level = IPSEC_LEVEL_BYPASS; 78462637Skris 78562637Skris (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, 786121435Sume sizeof(level)); 78762637Skris (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, 788121435Sume sizeof(level)); 78962637Skris#ifdef IP_AUTH_TRANS_LEVEL 79062637Skris (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, 791121435Sume sizeof(level)); 79262637Skris#else 79362637Skris (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, 794121435Sume sizeof(level)); 79562637Skris#endif 79662637Skris#ifdef IP_AUTH_NETWORK_LEVEL 79762637Skris (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, 798121435Sume sizeof(level)); 79962637Skris#endif 80062637Skris } 80155163Sshin#endif /*IPSEC_POLICY_IPSEC*/ 80255163Sshin#endif /*IPSEC*/ 80355163Sshin 80455163Sshin /* 80555163Sshin * Source selection 80655163Sshin */ 80762637Skris bzero(&Src, sizeof(Src)); 80855163Sshin if (source) { 80962637Skris struct addrinfo hints, *res; 81062637Skris int error; 81162637Skris 81262637Skris memset(&hints, 0, sizeof(hints)); 81362637Skris hints.ai_family = AF_INET6; 81462637Skris hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 81562637Skris hints.ai_flags = AI_NUMERICHOST; 81662637Skris error = getaddrinfo(source, "0", &hints, &res); 81762637Skris if (error) { 818121435Sume printf("traceroute6: %s: %s\n", source, 81962637Skris gai_strerror(error)); 82055163Sshin exit(1); 82155163Sshin } 82262637Skris if (res->ai_addrlen > sizeof(Src)) { 823121435Sume printf("traceroute6: %s: %s\n", source, 82462637Skris gai_strerror(error)); 82562637Skris exit(1); 82662637Skris } 82762637Skris memcpy(&Src, res->ai_addr, res->ai_addrlen); 82862637Skris freeaddrinfo(res); 82955163Sshin } else { 83055163Sshin struct sockaddr_in6 Nxt; 831122574Sume int dummy; 832122574Sume socklen_t len; 83355163Sshin 83455163Sshin Nxt = Dst; 83555163Sshin Nxt.sin6_port = htons(DUMMY_PORT); 83655163Sshin if (cmsg != NULL) 83755163Sshin bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr, 838121435Sume sizeof(Nxt.sin6_addr)); 83955163Sshin if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 84062637Skris perror("socket"); 84162637Skris exit(1); 84255163Sshin } 84362637Skris if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) { 84455163Sshin perror("connect"); 84562637Skris exit(1); 84662637Skris } 84762637Skris len = sizeof(Src); 84862637Skris if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) { 84955163Sshin perror("getsockname"); 85062637Skris exit(1); 85155163Sshin } 85262637Skris if (getnameinfo((struct sockaddr *)&Src, Src.sin6_len, 853121316Sume src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) { 854121435Sume fprintf(stderr, "getnameinfo failed for source\n"); 85562637Skris exit(1); 85662637Skris } 85762637Skris source = src0; 85862637Skris close(dummy); 85955163Sshin } 86062637Skris 861122574Sume Src.sin6_port = htons(0); 86262637Skris if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) { 86362637Skris perror("bind"); 86462637Skris exit(1); 86555163Sshin } 86655163Sshin 867122574Sume { 868121435Sume socklen_t len; 86962637Skris 87062637Skris len = sizeof(Src); 871122574Sume if (getsockname(sndsock, (struct sockaddr *)&Src, &len) < 0) { 87262637Skris perror("getsockname"); 87362637Skris exit(1); 87462637Skris } 875122574Sume srcport = ntohs(Src.sin6_port); 87662637Skris } 87762637Skris 878196475Sume if (as_path) { 879196475Sume asn = as_setup(as_server); 880196475Sume if (asn == NULL) { 881196475Sume fprintf(stderr, 882196475Sume "traceroute6: as_setup failed, AS# lookups" 883196475Sume " disabled\n"); 884196475Sume (void)fflush(stderr); 885196475Sume as_path = 0; 886196475Sume } 887196475Sume } 888196475Sume 88955163Sshin /* 89055163Sshin * Message to users 89155163Sshin */ 89262637Skris if (getnameinfo((struct sockaddr *)&Dst, Dst.sin6_len, hbuf, 893121316Sume sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) 89478064Sume strlcpy(hbuf, "(invalid)", sizeof(hbuf)); 895121435Sume fprintf(stderr, "traceroute6"); 896121435Sume fprintf(stderr, " to %s (%s)", hostname, hbuf); 89755163Sshin if (source) 898121435Sume fprintf(stderr, " from %s", source); 899122574Sume fprintf(stderr, ", %lu hops max, %lu byte packets\n", 900121435Sume max_hops, datalen); 90155163Sshin (void) fflush(stderr); 90255163Sshin 90362637Skris if (first_hop > 1) 904122574Sume printf("Skipping %lu intermediate hops\n", first_hop - 1); 90562637Skris 90655163Sshin /* 90755163Sshin * Main loop 90855163Sshin */ 90962637Skris for (hops = first_hop; hops <= max_hops; ++hops) { 91055163Sshin struct in6_addr lastaddr; 91155163Sshin int got_there = 0; 912216185Suqs unsigned unreachable = 0; 91355163Sshin 914122574Sume printf("%2lu ", hops); 91555163Sshin bzero(&lastaddr, sizeof(lastaddr)); 91655163Sshin for (probe = 0; probe < nprobes; ++probe) { 91755163Sshin int cc; 91855163Sshin struct timeval t1, t2; 91955163Sshin 920122574Sume (void) gettimeofday(&t1, NULL); 92155163Sshin send_probe(++seq, hops); 92255163Sshin while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) { 923122574Sume (void) gettimeofday(&t2, NULL); 92455163Sshin if ((i = packet_ok(&rcvmhdr, cc, seq))) { 925130422Sdwmalone if (!IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr, 926121435Sume &lastaddr)) { 927172917Scsjp if (probe > 0) 928172917Scsjp fputs("\n ", stdout); 92955163Sshin print(&rcvmhdr, cc); 93055163Sshin lastaddr = Rcv.sin6_addr; 93155163Sshin } 932121435Sume printf(" %.3f ms", deltaT(&t1, &t2)); 933121435Sume switch (i - 1) { 93455163Sshin case ICMP6_DST_UNREACH_NOROUTE: 93555163Sshin ++unreachable; 936121435Sume printf(" !N"); 93755163Sshin break; 93855163Sshin case ICMP6_DST_UNREACH_ADMIN: 93955163Sshin ++unreachable; 940121435Sume printf(" !P"); 94155163Sshin break; 94255163Sshin case ICMP6_DST_UNREACH_NOTNEIGHBOR: 94355163Sshin ++unreachable; 944121435Sume printf(" !S"); 94555163Sshin break; 94655163Sshin case ICMP6_DST_UNREACH_ADDR: 94755163Sshin ++unreachable; 948121435Sume printf(" !A"); 94955163Sshin break; 95055163Sshin case ICMP6_DST_UNREACH_NOPORT: 95155163Sshin if (rcvhlim >= 0 && 95255163Sshin rcvhlim <= 1) 953121435Sume printf(" !"); 95455163Sshin ++got_there; 95555163Sshin break; 95655163Sshin } 95755163Sshin break; 95855163Sshin } 95955163Sshin } 96055163Sshin if (cc == 0) 961121435Sume printf(" *"); 96255163Sshin (void) fflush(stdout); 96355163Sshin } 96455163Sshin putchar('\n'); 96555163Sshin if (got_there || 96655163Sshin (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) { 96755163Sshin exit(0); 96855163Sshin } 96955163Sshin } 970196475Sume if (as_path) 971196475Sume as_shutdown(asn); 97255163Sshin 97355163Sshin exit(0); 97455163Sshin} 97555163Sshin 97655163Sshinint 97755163Sshinwait_for_reply(sock, mhdr) 97855163Sshin int sock; 97955163Sshin struct msghdr *mhdr; 98055163Sshin{ 98166808Skris#ifdef HAVE_POLL 98266808Skris struct pollfd pfd[1]; 98355163Sshin int cc = 0; 98455163Sshin 98566808Skris pfd[0].fd = sock; 98666808Skris pfd[0].events = POLLIN; 98766808Skris pfd[0].revents = 0; 98866808Skris 98966808Skris if (poll(pfd, 1, waittime * 1000) > 0) 99066808Skris cc = recvmsg(rcvsock, mhdr, 0); 99166808Skris 99266808Skris return(cc); 99366808Skris#else 99466808Skris fd_set *fdsp; 99566808Skris struct timeval wait; 99666808Skris int cc = 0, fdsn; 99766808Skris 99878064Sume fdsn = howmany(sock + 1, NFDBITS) * sizeof(fd_mask); 99966808Skris if ((fdsp = (fd_set *)malloc(fdsn)) == NULL) 100066808Skris err(1, "malloc"); 100166808Skris memset(fdsp, 0, fdsn); 100266808Skris FD_SET(sock, fdsp); 100355163Sshin wait.tv_sec = waittime; wait.tv_usec = 0; 100455163Sshin 100566808Skris if (select(sock+1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0) 100655163Sshin cc = recvmsg(rcvsock, mhdr, 0); 100755163Sshin 100866808Skris free(fdsp); 100955163Sshin return(cc); 101066808Skris#endif 101155163Sshin} 101255163Sshin 101355163Sshin#ifdef IPSEC 101455163Sshin#ifdef IPSEC_POLICY_IPSEC 101555163Sshinint 101655163Sshinsetpolicy(so, policy) 101755163Sshin int so; 101855163Sshin char *policy; 101955163Sshin{ 102055163Sshin char *buf; 102155163Sshin 102255163Sshin buf = ipsec_set_policy(policy, strlen(policy)); 102355163Sshin if (buf == NULL) { 102462637Skris warnx("%s", ipsec_strerror()); 102555163Sshin return -1; 102655163Sshin } 102755163Sshin (void)setsockopt(so, IPPROTO_IPV6, IPV6_IPSEC_POLICY, 1028121435Sume buf, ipsec_get_policylen(buf)); 102955163Sshin 103055163Sshin free(buf); 103155163Sshin 103255163Sshin return 0; 103355163Sshin} 103455163Sshin#endif 103555163Sshin#endif 103655163Sshin 103755163Sshinvoid 103855163Sshinsend_probe(seq, hops) 1039122574Sume int seq; 1040122574Sume u_long hops; 104155163Sshin{ 1042176154Sdwmalone struct icmp6_hdr *icp; 1043176154Sdwmalone struct opacket *op; 1044130422Sdwmalone struct timeval tv; 1045130422Sdwmalone struct tv32 tv32; 104655163Sshin int i; 104755163Sshin 1048122574Sume i = hops; 1049121435Sume if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 1050122574Sume (char *)&i, sizeof(i)) < 0) { 105155163Sshin perror("setsockopt IPV6_UNICAST_HOPS"); 105255163Sshin } 105355163Sshin 105455163Sshin Dst.sin6_port = htons(port + seq); 1055130422Sdwmalone (void) gettimeofday(&tv, NULL); 1056130422Sdwmalone tv32.tv32_sec = htonl(tv.tv_sec); 1057130422Sdwmalone tv32.tv32_usec = htonl(tv.tv_usec); 105855163Sshin 1059176154Sdwmalone switch (useproto) { 1060176154Sdwmalone case IPPROTO_ICMPV6: 1061176154Sdwmalone icp = (struct icmp6_hdr *)outpacket; 106255163Sshin 1063122574Sume icp->icmp6_type = ICMP6_ECHO_REQUEST; 1064122574Sume icp->icmp6_code = 0; 1065122574Sume icp->icmp6_cksum = 0; 1066122574Sume icp->icmp6_id = ident; 1067122574Sume icp->icmp6_seq = htons(seq); 1068130422Sdwmalone bcopy(&tv32, ((u_int8_t *)outpacket + ICMP6ECHOLEN), 1069130422Sdwmalone sizeof(tv32)); 1070176154Sdwmalone break; 1071176154Sdwmalone case IPPROTO_UDP: 1072176154Sdwmalone op = outpacket; 1073130422Sdwmalone 1074122574Sume op->seq = seq; 1075122574Sume op->hops = hops; 1076130422Sdwmalone bcopy(&tv32, &op->tv, sizeof tv32); 1077176154Sdwmalone break; 1078176154Sdwmalone case IPPROTO_NONE: 1079176154Sdwmalone /* No space for anything. No harm as seq/tv32 are decorative. */ 1080176154Sdwmalone break; 1081176154Sdwmalone default: 1082176154Sdwmalone fprintf(stderr, "Unknown probe protocol %d.\n", useproto); 1083176154Sdwmalone exit(1); 1084122574Sume } 1085122574Sume 1086121435Sume i = sendto(sndsock, (char *)outpacket, datalen, 0, 1087121435Sume (struct sockaddr *)&Dst, Dst.sin6_len); 1088216185Suqs if (i < 0 || (u_long)i != datalen) { 1089130422Sdwmalone if (i < 0) 109055163Sshin perror("sendto"); 1091122574Sume printf("traceroute6: wrote %s %lu chars, ret=%d\n", 1092121435Sume hostname, datalen, i); 109355163Sshin (void) fflush(stdout); 109455163Sshin } 109555163Sshin} 109655163Sshin 109755163Sshinint 109855163Sshinget_hoplim(mhdr) 109955163Sshin struct msghdr *mhdr; 110055163Sshin{ 110155163Sshin struct cmsghdr *cm; 110255163Sshin 110355163Sshin for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 1104121435Sume cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 110555163Sshin if (cm->cmsg_level == IPPROTO_IPV6 && 110655163Sshin cm->cmsg_type == IPV6_HOPLIMIT && 110755163Sshin cm->cmsg_len == CMSG_LEN(sizeof(int))) 110855163Sshin return(*(int *)CMSG_DATA(cm)); 110955163Sshin } 111055163Sshin 111155163Sshin return(-1); 111255163Sshin} 111355163Sshin 111455163Sshindouble 111555163SshindeltaT(t1p, t2p) 111655163Sshin struct timeval *t1p, *t2p; 111755163Sshin{ 1118130422Sdwmalone double dt; 111955163Sshin 112055163Sshin dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + 1121121435Sume (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; 112255163Sshin return (dt); 112355163Sshin} 112455163Sshin 112555163Sshin/* 112655163Sshin * Convert an ICMP "type" field to a printable string. 112755163Sshin */ 1128216185Suqsconst char * 1129216185Suqspr_type(int t0) 113055163Sshin{ 113155163Sshin u_char t = t0 & 0xff; 1132216185Suqs const char *cp; 113355163Sshin 113455163Sshin switch (t) { 113555163Sshin case ICMP6_DST_UNREACH: 113655163Sshin cp = "Destination Unreachable"; 113755163Sshin break; 113855163Sshin case ICMP6_PACKET_TOO_BIG: 1139121435Sume cp = "Packet Too Big"; 114055163Sshin break; 114155163Sshin case ICMP6_TIME_EXCEEDED: 114255163Sshin cp = "Time Exceeded"; 114355163Sshin break; 114455163Sshin case ICMP6_PARAM_PROB: 114555163Sshin cp = "Parameter Problem"; 114655163Sshin break; 114755163Sshin case ICMP6_ECHO_REQUEST: 114855163Sshin cp = "Echo Request"; 114955163Sshin break; 115055163Sshin case ICMP6_ECHO_REPLY: 115155163Sshin cp = "Echo Reply"; 115255163Sshin break; 115355163Sshin case ICMP6_MEMBERSHIP_QUERY: 115455163Sshin cp = "Group Membership Query"; 115555163Sshin break; 115655163Sshin case ICMP6_MEMBERSHIP_REPORT: 115755163Sshin cp = "Group Membership Report"; 115855163Sshin break; 115955163Sshin case ICMP6_MEMBERSHIP_REDUCTION: 116055163Sshin cp = "Group Membership Reduction"; 116155163Sshin break; 116255163Sshin case ND_ROUTER_SOLICIT: 116355163Sshin cp = "Router Solicitation"; 116455163Sshin break; 116555163Sshin case ND_ROUTER_ADVERT: 116655163Sshin cp = "Router Advertisement"; 116755163Sshin break; 116855163Sshin case ND_NEIGHBOR_SOLICIT: 116955163Sshin cp = "Neighbor Solicitation"; 117055163Sshin break; 117155163Sshin case ND_NEIGHBOR_ADVERT: 117255163Sshin cp = "Neighbor Advertisement"; 117355163Sshin break; 117455163Sshin case ND_REDIRECT: 117562637Skris cp = "Redirect"; 117655163Sshin break; 117755163Sshin default: 117855163Sshin cp = "Unknown"; 117955163Sshin break; 118055163Sshin } 118155163Sshin return cp; 118255163Sshin} 118355163Sshin 118455163Sshinint 118555163Sshinpacket_ok(mhdr, cc, seq) 118655163Sshin struct msghdr *mhdr; 118755163Sshin int cc; 118855163Sshin int seq; 118955163Sshin{ 1190130422Sdwmalone struct icmp6_hdr *icp; 119155163Sshin struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; 119255163Sshin u_char type, code; 119355163Sshin char *buf = (char *)mhdr->msg_iov[0].iov_base; 119455163Sshin struct cmsghdr *cm; 119555163Sshin int *hlimp; 119662637Skris char hbuf[NI_MAXHOST]; 119755163Sshin 119862637Skris#ifdef OLDRAWSOCKET 119962637Skris int hlen; 120062637Skris struct ip6_hdr *ip; 120162637Skris#endif 120262637Skris 120362637Skris#ifdef OLDRAWSOCKET 120462637Skris ip = (struct ip6_hdr *) buf; 120562637Skris hlen = sizeof(struct ip6_hdr); 120662637Skris if (cc < hlen + sizeof(struct icmp6_hdr)) { 120762637Skris if (verbose) { 120862637Skris if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1209121316Sume hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 121078064Sume strlcpy(hbuf, "invalid", sizeof(hbuf)); 1211121435Sume printf("packet too short (%d bytes) from %s\n", cc, 121262637Skris hbuf); 121362637Skris } 121462637Skris return (0); 121562637Skris } 121662637Skris cc -= hlen; 121762637Skris icp = (struct icmp6_hdr *)(buf + hlen); 121862637Skris#else 1219216185Suqs if (cc < (int)sizeof(struct icmp6_hdr)) { 122062637Skris if (verbose) { 122162637Skris if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1222121316Sume hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 122378064Sume strlcpy(hbuf, "invalid", sizeof(hbuf)); 1224121435Sume printf("data too short (%d bytes) from %s\n", cc, hbuf); 122562637Skris } 122655163Sshin return(0); 122755163Sshin } 122855163Sshin icp = (struct icmp6_hdr *)buf; 122962637Skris#endif 123055163Sshin /* get optional information via advanced API */ 123155163Sshin rcvpktinfo = NULL; 123255163Sshin hlimp = NULL; 123355163Sshin for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 1234121435Sume cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 123555163Sshin if (cm->cmsg_level == IPPROTO_IPV6 && 123655163Sshin cm->cmsg_type == IPV6_PKTINFO && 123755163Sshin cm->cmsg_len == 123855163Sshin CMSG_LEN(sizeof(struct in6_pktinfo))) 123955163Sshin rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm)); 124055163Sshin 124155163Sshin if (cm->cmsg_level == IPPROTO_IPV6 && 124255163Sshin cm->cmsg_type == IPV6_HOPLIMIT && 124355163Sshin cm->cmsg_len == CMSG_LEN(sizeof(int))) 124455163Sshin hlimp = (int *)CMSG_DATA(cm); 124555163Sshin } 124655163Sshin if (rcvpktinfo == NULL || hlimp == NULL) { 124755163Sshin warnx("failed to get received hop limit or packet info"); 124862637Skris#if 0 124955163Sshin return(0); 125062637Skris#else 125162637Skris rcvhlim = 0; /*XXX*/ 125262637Skris#endif 125355163Sshin } 125462637Skris else 125562637Skris rcvhlim = *hlimp; 125655163Sshin 125755163Sshin type = icp->icmp6_type; 125855163Sshin code = icp->icmp6_code; 125955163Sshin if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) 1260130422Sdwmalone || type == ICMP6_DST_UNREACH) { 126155163Sshin struct ip6_hdr *hip; 1262176154Sdwmalone void *up; 126355163Sshin 126455163Sshin hip = (struct ip6_hdr *)(icp + 1); 1265176154Sdwmalone if ((up = get_uphdr(hip, (u_char *)(buf + cc))) == NULL) { 126655163Sshin if (verbose) 126755163Sshin warnx("failed to get upper layer header"); 126855163Sshin return(0); 126955163Sshin } 1270176154Sdwmalone switch (useproto) { 1271176154Sdwmalone case IPPROTO_ICMPV6: 1272176154Sdwmalone if (((struct icmp6_hdr *)up)->icmp6_id == ident && 1273176154Sdwmalone ((struct icmp6_hdr *)up)->icmp6_seq == htons(seq)) 1274176154Sdwmalone return (type == ICMP6_TIME_EXCEEDED ? 1275176154Sdwmalone -1 : code + 1); 1276176154Sdwmalone break; 1277176154Sdwmalone case IPPROTO_UDP: 1278176154Sdwmalone if (((struct udphdr *)up)->uh_sport == htons(srcport) && 1279176154Sdwmalone ((struct udphdr *)up)->uh_dport == htons(port + seq)) 1280176154Sdwmalone return (type == ICMP6_TIME_EXCEEDED ? 1281176154Sdwmalone -1 : code + 1); 1282176154Sdwmalone break; 1283176154Sdwmalone case IPPROTO_NONE: 1284176154Sdwmalone return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1); 1285176154Sdwmalone default: 1286176154Sdwmalone fprintf(stderr, "Unknown probe proto %d.\n", useproto); 1287176154Sdwmalone break; 1288176154Sdwmalone } 1289176154Sdwmalone } else if (useproto == IPPROTO_ICMPV6 && type == ICMP6_ECHO_REPLY) { 1290122574Sume if (icp->icmp6_id == ident && 1291122574Sume icp->icmp6_seq == htons(seq)) 1292122574Sume return (ICMP6_DST_UNREACH_NOPORT + 1); 129355163Sshin } 129455163Sshin if (verbose) { 1295130422Sdwmalone char sbuf[NI_MAXHOST+1], dbuf[INET6_ADDRSTRLEN]; 1296130422Sdwmalone u_int8_t *p; 129755163Sshin int i; 129855163Sshin 129962637Skris if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1300121316Sume sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0) 1301121435Sume strlcpy(sbuf, "invalid", sizeof(sbuf)); 1302121435Sume printf("\n%d bytes from %s to %s", cc, sbuf, 130362637Skris rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1304121435Sume dbuf, sizeof(dbuf)) : "?"); 1305121435Sume printf(": icmp type %d (%s) code %d\n", type, pr_type(type), 1306121435Sume icp->icmp6_code); 130762637Skris p = (u_int8_t *)(icp + 1); 130862637Skris#define WIDTH 16 130962637Skris for (i = 0; i < cc; i++) { 131062637Skris if (i % WIDTH == 0) 1311121435Sume printf("%04x:", i); 131262637Skris if (i % 4 == 0) 1313121435Sume printf(" "); 1314121435Sume printf("%02x", p[i]); 131562637Skris if (i % WIDTH == WIDTH - 1) 1316121435Sume printf("\n"); 131762637Skris } 131862637Skris if (cc % WIDTH != 0) 1319121435Sume printf("\n"); 132055163Sshin } 132155163Sshin return(0); 132255163Sshin} 132355163Sshin 132455163Sshin/* 1325122574Sume * Increment pointer until find the UDP or ICMP header. 132655163Sshin */ 1327176154Sdwmalonevoid * 1328176154Sdwmaloneget_uphdr(ip6, lim) 132955163Sshin struct ip6_hdr *ip6; 133055163Sshin u_char *lim; 133155163Sshin{ 133255163Sshin u_char *cp = (u_char *)ip6, nh; 133355163Sshin int hlen; 1334176154Sdwmalone static u_char none_hdr[1]; /* Fake pointer for IPPROTO_NONE. */ 133555163Sshin 1336176154Sdwmalone if (cp + sizeof(*ip6) > lim) 133755163Sshin return(NULL); 133855163Sshin 133955163Sshin nh = ip6->ip6_nxt; 134055163Sshin cp += sizeof(struct ip6_hdr); 134155163Sshin 1342176154Sdwmalone while (lim - cp >= (nh == IPPROTO_NONE ? 0 : 8)) { 1343121435Sume switch (nh) { 1344121435Sume case IPPROTO_ESP: 1345121435Sume case IPPROTO_TCP: 1346122574Sume return(NULL); 1347121435Sume case IPPROTO_ICMPV6: 1348176154Sdwmalone return(useproto == nh ? cp : NULL); 1349121435Sume case IPPROTO_UDP: 1350176154Sdwmalone return(useproto == nh ? cp : NULL); 1351176154Sdwmalone case IPPROTO_NONE: 1352176154Sdwmalone return(useproto == nh ? none_hdr : NULL); 1353121435Sume case IPPROTO_FRAGMENT: 1354121435Sume hlen = sizeof(struct ip6_frag); 1355121435Sume nh = ((struct ip6_frag *)cp)->ip6f_nxt; 1356121435Sume break; 1357121435Sume case IPPROTO_AH: 1358121435Sume hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2; 1359121435Sume nh = ((struct ip6_ext *)cp)->ip6e_nxt; 1360121435Sume break; 1361121435Sume default: 1362121435Sume hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3; 1363121435Sume nh = ((struct ip6_ext *)cp)->ip6e_nxt; 1364121435Sume break; 136555163Sshin } 136655163Sshin 136755163Sshin cp += hlen; 136855163Sshin } 136955163Sshin 137055163Sshin return(NULL); 137155163Sshin} 137255163Sshin 137355163Sshinvoid 137455163Sshinprint(mhdr, cc) 137555163Sshin struct msghdr *mhdr; 137655163Sshin int cc; 137755163Sshin{ 137855163Sshin struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; 137962637Skris char hbuf[NI_MAXHOST]; 138055163Sshin 138162637Skris if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1382121316Sume hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 138378064Sume strlcpy(hbuf, "invalid", sizeof(hbuf)); 1384196475Sume if (as_path) 1385196475Sume printf(" [AS%u]", as_lookup(asn, hbuf, AF_INET6)); 138662637Skris if (nflag) 1387121435Sume printf(" %s", hbuf); 138862637Skris else if (lflag) 1389121435Sume printf(" %s (%s)", inetname((struct sockaddr *)from), hbuf); 139062637Skris else 1391121435Sume printf(" %s", inetname((struct sockaddr *)from)); 139255163Sshin 139355163Sshin if (verbose) { 139462637Skris#ifdef OLDRAWSOCKET 1395121435Sume printf(" %d bytes to %s", cc, 139662637Skris rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1397121435Sume hbuf, sizeof(hbuf)) : "?"); 139862637Skris#else 1399121435Sume printf(" %d bytes of data to %s", cc, 140062637Skris rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1401121435Sume hbuf, sizeof(hbuf)) : "?"); 140262637Skris#endif 140355163Sshin } 140455163Sshin} 140555163Sshin 140655163Sshin/* 140755163Sshin * Construct an Internet address representation. 140855163Sshin * If the nflag has been supplied, give 140955163Sshin * numeric value, otherwise try for symbolic name. 141055163Sshin */ 141162637Skrisconst char * 141262637Skrisinetname(sa) 141362637Skris struct sockaddr *sa; 141455163Sshin{ 1415130422Sdwmalone static char line[NI_MAXHOST], domain[MAXHOSTNAMELEN + 1]; 141655163Sshin static int first = 1; 1417130422Sdwmalone char *cp; 141855163Sshin 141955163Sshin if (first && !nflag) { 142055163Sshin first = 0; 1421121435Sume if (gethostname(domain, sizeof(domain)) == 0 && 1422121435Sume (cp = strchr(domain, '.'))) 142378064Sume (void) strlcpy(domain, cp + 1, sizeof(domain)); 142455163Sshin else 142555163Sshin domain[0] = 0; 142655163Sshin } 142762637Skris cp = NULL; 142855163Sshin if (!nflag) { 142962637Skris if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, 143062637Skris NI_NAMEREQD) == 0) { 1431121435Sume if ((cp = strchr(line, '.')) && 143255163Sshin !strcmp(cp + 1, domain)) 143355163Sshin *cp = 0; 143462637Skris cp = line; 143555163Sshin } 143655163Sshin } 143755163Sshin if (cp) 143862637Skris return cp; 143962637Skris 144062637Skris if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, 1441121316Sume NI_NUMERICHOST) != 0) 144278064Sume strlcpy(line, "invalid", sizeof(line)); 144362637Skris return line; 144455163Sshin} 144555163Sshin 144655163Sshinvoid 144755163Sshinusage() 144855163Sshin{ 1449122574Sume 1450122574Sume fprintf(stderr, 1451235138Sume"usage: traceroute6 [-adIlnNrUv] [-A as_server] [-f firsthop] [-g gateway]\n" 1452235138Sume" [-m hoplimit] [-p port] [-q probes] [-s src] [-w waittime] target\n" 1453235138Sume" [datalen]\n"); 145455163Sshin exit(1); 145555163Sshin} 1456