traceroute6.c revision 64276
1139749Simp/* $KAME: traceroute6.c,v 1.29 2000/06/12 16:29:18 itojun Exp $ */ 2113584Ssimokawa 3103285Sikob/* 4103285Sikob * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5103285Sikob * All rights reserved. 6103285Sikob * 7103285Sikob * Redistribution and use in source and binary forms, with or without 8103285Sikob * modification, are permitted provided that the following conditions 9103285Sikob * are met: 10103285Sikob * 1. Redistributions of source code must retain the above copyright 11103285Sikob * notice, this list of conditions and the following disclaimer. 12103285Sikob * 2. Redistributions in binary form must reproduce the above copyright 13103285Sikob * notice, this list of conditions and the following disclaimer in the 14103285Sikob * documentation and/or other materials provided with the distribution. 15103285Sikob * 3. Neither the name of the project nor the names of its contributors 16103285Sikob * may be used to endorse or promote products derived from this software 17103285Sikob * without specific prior written permission. 18103285Sikob * 19103285Sikob * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20103285Sikob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21103285Sikob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22103285Sikob * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23103285Sikob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24103285Sikob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25103285Sikob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26103285Sikob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27103285Sikob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28103285Sikob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29103285Sikob * SUCH DAMAGE. 30103285Sikob */ 31103285Sikob 32103285Sikob/*- 33103285Sikob * Copyright (c) 1990, 1993 34103285Sikob * The Regents of the University of California. All rights reserved. 35103285Sikob * 36103285Sikob * This code is derived from software contributed to Berkeley by 37103285Sikob * Van Jacobson. 38103285Sikob * 39103285Sikob * Redistribution and use in source and binary forms, with or without 40103285Sikob * modification, are permitted provided that the following conditions 41103285Sikob * are met: 42193066Sjamie * 1. Redistributions of source code must retain the above copyright 43103285Sikob * notice, this list of conditions and the following disclaimer. 44129879Sphk * 2. Redistributions in binary form must reproduce the above copyright 45103285Sikob * notice, this list of conditions and the following disclaimer in the 46103285Sikob * documentation and/or other materials provided with the distribution. 47103285Sikob * 3. All advertising materials mentioning features or use of this software 48169806Ssimokawa * must display the following acknowledgement: 49103285Sikob * This product includes software developed by the University of 50170374Ssimokawa * California, Berkeley and its contributors. 51170374Ssimokawa * 4. Neither the name of the University nor the names of its contributors 52127468Ssimokawa * may be used to endorse or promote products derived from this software 53117067Ssimokawa * without specific prior written permission. 54117067Ssimokawa * 55103285Sikob * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 56103285Sikob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 57113584Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 58103285Sikob * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 59127468Ssimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 60127468Ssimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 61127468Ssimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 62127468Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 63127468Ssimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 64127468Ssimokawa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 65127468Ssimokawa * SUCH DAMAGE. 66103285Sikob */ 67103285Sikob 68110072Ssimokawa#ifndef lint 69103285Sikobstatic char copyright[] = 70103285Sikob"@(#) Copyright (c) 1990, 1993\n\ 71127468Ssimokawa The Regents of the University of California. All rights reserved.\n"; 72103285Sikob#endif /* not lint */ 73116376Ssimokawa 74116376Ssimokawa#ifndef lint 75116376Ssimokawa#if 0 76116376Ssimokawastatic char sccsid[] = "@(#)traceroute.c 8.1 (Berkeley) 6/6/93"; 77116376Ssimokawa#endif 78116376Ssimokawastatic const char rcsid[] = 79116376Ssimokawa "$FreeBSD: head/usr.sbin/traceroute6/traceroute6.c 64276 2000-08-05 06:21:12Z kris $"; 80188704Ssbruno#endif /* not lint */ 81103285Sikob 82108281Ssimokawa/* 83109736Ssimokawa * traceroute host - trace the route ip packets follow going to "host". 84109736Ssimokawa * 85109736Ssimokawa * Attempt to trace the route an ip packet would follow to some 86120850Ssimokawa * internet host. We find out intermediate hops by launching probe 87120850Ssimokawa * packets with a small ttl (time to live) then listening for an 88103285Sikob * icmp "time exceeded" reply from a gateway. We start our probes 89110195Ssimokawa * with a ttl of one and increase by one until we get an icmp "port 90110269Ssimokawa * unreachable" (which means we got to "host") or hit a max (which 91110195Ssimokawa * defaults to 30 hops & can be changed with the -m flag). Three 92103285Sikob * probes (change with -q flag) are sent at each ttl setting and a 93103285Sikob * line is printed showing the ttl, address of the gateway and 94103285Sikob * round trip time of each probe. If the probe answers come from 95103285Sikob * different gateways, the address of each responding system will 96125238Ssimokawa * be printed. If there is no response within a 5 sec. timeout 97125238Ssimokawa * interval (changed with the -w flag), a "*" is printed for that 98124169Ssimokawa * probe. 99124169Ssimokawa * 100124169Ssimokawa * Probe packets are UDP format. We don't want the destination 101170374Ssimokawa * host to process them so the destination port is set to an 102103285Sikob * unlikely value (if some clod on the destination is using that 103124169Ssimokawa * value, it can be changed with the -p flag). 104103285Sikob * 105124169Ssimokawa * A sample use might be: 106124169Ssimokawa * 107124169Ssimokawa * [yak 71]% traceroute nis.nsf.net. 108124169Ssimokawa * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet 109124169Ssimokawa * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms 110124169Ssimokawa * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 111124169Ssimokawa * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms 112169806Ssimokawa * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms 113106543Ssimokawa * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms 114124169Ssimokawa * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms 115106543Ssimokawa * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms 116124169Ssimokawa * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms 117170374Ssimokawa * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms 118103285Sikob * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms 119103285Sikob * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms 120103285Sikob * 121125238Ssimokawa * Note that lines 2 & 3 are the same. This is due to a buggy 122125238Ssimokawa * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards 123103285Sikob * packets with a zero ttl. 124103285Sikob * 125108642Ssimokawa * A more interesting example is: 126116978Ssimokawa * 127103285Sikob * [yak 72]% traceroute allspice.lcs.mit.edu. 128103285Sikob * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max 129103285Sikob * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 130103285Sikob * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms 131103285Sikob * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms 132103285Sikob * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms 133103285Sikob * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms 134103285Sikob * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms 135124251Ssimokawa * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms 136124251Ssimokawa * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms 137124251Ssimokawa * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms 138124251Ssimokawa * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms 139103285Sikob * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms 140124251Ssimokawa * 12 * * * 141124251Ssimokawa * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms 142124251Ssimokawa * 14 * * * 143124251Ssimokawa * 15 * * * 144124251Ssimokawa * 16 * * * 145124251Ssimokawa * 17 * * * 146124251Ssimokawa * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms 147114909Ssimokawa * 148114909Ssimokawa * (I start to see why I'm having so much trouble with mail to 149114909Ssimokawa * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away 150114909Ssimokawa * either don't send ICMP "time exceeded" messages or send them 151106813Ssimokawa * with a ttl too small to reach us. 14 - 17 are running the 152103285Sikob * MIT C Gateway code that doesn't send "time exceeded"s. God 153103285Sikob * only knows what's going on with 12. 154103285Sikob * 155103285Sikob * The silent gateway 12 in the above may be the result of a bug in 156103285Sikob * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) 157103285Sikob * sends an unreachable message using whatever ttl remains in the 158103285Sikob * original datagram. Since, for gateways, the remaining ttl is 159110072Ssimokawa * zero, the icmp "time exceeded" is guaranteed to not make it back 160103285Sikob * to us. The behavior of this bug is slightly more interesting 161106810Ssimokawa * when it appears on the destination system: 162110072Ssimokawa * 163103285Sikob * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms 164103285Sikob * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms 165110072Ssimokawa * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms 166110072Ssimokawa * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms 167110072Ssimokawa * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms 168110193Ssimokawa * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms 169120660Ssimokawa * 7 * * * 170103285Sikob * 8 * * * 171110072Ssimokawa * 9 * * * 172110072Ssimokawa * 10 * * * 173106810Ssimokawa * 11 * * * 174103285Sikob * 12 * * * 175106813Ssimokawa * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! 176103285Sikob * 177110072Ssimokawa * Notice that there are 12 "gateways" (13 is the final 178110072Ssimokawa * destination) and exactly the last half of them are "missing". 179110072Ssimokawa * What's really happening is that rip (a Sun-3 running Sun OS3.5) 180110582Ssimokawa * is using the ttl from our arriving datagram as the ttl in its 181110072Ssimokawa * icmp reply. So, the reply will time out on the return path 182110072Ssimokawa * (with no notice sent to anyone since icmp's aren't sent for 183110072Ssimokawa * icmp's) until we probe with a ttl that's at least twice the path 184110072Ssimokawa * length. I.e., rip is really only 7 hops away. A reply that 185110072Ssimokawa * returns with a ttl of 1 is a clue this problem exists. 186170374Ssimokawa * Traceroute prints a "!" after the time if the ttl is <= 1. 187110193Ssimokawa * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or 188110582Ssimokawa * non-standard (HPUX) software, expect to see this problem 189110072Ssimokawa * frequently and/or take care picking the target host of your 190170374Ssimokawa * probes. 191110072Ssimokawa * 192110072Ssimokawa * Other possible annotations after the time are !H, !N, !P (got a host, 193110072Ssimokawa * network or protocol unreachable, respectively), !S or !F (source 194110072Ssimokawa * route failed or fragmentation needed -- neither of these should 195110072Ssimokawa * ever occur and the associated gateway is busted if you see one). If 196110072Ssimokawa * almost all the probes result in some kind of unreachable, traceroute 197110072Ssimokawa * will give up and exit. 198110072Ssimokawa * 199103285Sikob * Notes 200103285Sikob * ----- 201103285Sikob * This program must be run by root or be setuid. (I suggest that 202103285Sikob * you *don't* make it setuid -- casual use could result in a lot 203103285Sikob * of unnecessary traffic on our poor, congested nets.) 204103285Sikob * 205103285Sikob * This program requires a kernel mod that does not appear in any 206170374Ssimokawa * system available from Berkeley: A raw ip socket using proto 207103285Sikob * IPPROTO_RAW must interpret the data sent as an ip datagram (as 208103285Sikob * opposed to data to be wrapped in a ip datagram). See the README 209103285Sikob * file that came with the source to this program for a description 210103285Sikob * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may 211103285Sikob * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE 212167632Ssimokawa * MODIFIED TO RUN THIS PROGRAM. 213167632Ssimokawa * 214103285Sikob * The udp port usage may appear bizarre (well, ok, it is bizarre). 215103285Sikob * The problem is that an icmp message only contains 8 bytes of 216120660Ssimokawa * data from the original datagram. 8 bytes is the size of a udp 217103285Sikob * header so, if we want to associate replies with the original 218103285Sikob * datagram, the necessary information must be encoded into the 219103285Sikob * udp header (the ip id could be used but there's no way to 220103285Sikob * interlock with the kernel's assignment of ip id's and, anyway, 221124251Ssimokawa * it would have taken a lot more kernel hacking to allow this 222103285Sikob * code to set the ip id). So, to allow two or more users to 223103285Sikob * use traceroute simultaneously, we use this task's pid as the 224170425Ssimokawa * source port (the high bit is set to move the port number out 225170425Ssimokawa * of the "likely" range). To keep track of which probe is being 226170425Ssimokawa * replied to (so times and/or hop counts don't get confused by a 227170425Ssimokawa * reply that was delayed in transit), we increment the destination 228170425Ssimokawa * port number before each probe. 229170425Ssimokawa * 230170425Ssimokawa * Don't use this as a coding example. I was trying to find a 231170425Ssimokawa * routing problem and this code sort-of popped out after 48 hours 232170425Ssimokawa * without sleep. I was amazed it ever compiled, much less ran. 233170425Ssimokawa * 234170425Ssimokawa * I stole the idea for this program from Steve Deering. Since 235103285Sikob * the first release, I've learned that had I attended the right 236103285Sikob * IETF working group meetings, I also could have stolen it from Guy 237103285Sikob * Almes or Matt Mathis. I don't know (or care) who came up with 238103285Sikob * the idea first. I envy the originators' perspicacity and I'm 239103285Sikob * glad they didn't keep the idea a secret. 240120660Ssimokawa * 241120660Ssimokawa * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or 242120660Ssimokawa * enhancements to the original distribution. 243120660Ssimokawa * 244103285Sikob * I've hacked up a round-trip-route version of this that works by 245120660Ssimokawa * sending a loose-source-routed udp datagram through the destination 246103285Sikob * back to yourself. Unfortunately, SO many gateways botch source 247120660Ssimokawa * routing, the thing is almost worthless. Maybe one day... 248120660Ssimokawa * 249120660Ssimokawa * -- Van Jacobson (van@helios.ee.lbl.gov) 250120660Ssimokawa * Tue Dec 20 03:50:13 PST 1988 251124251Ssimokawa */ 252124251Ssimokawa 253103285Sikob#include <sys/param.h> 254103285Sikob#include <sys/time.h> 255106790Ssimokawa#include <sys/socket.h> 256103285Sikob#include <sys/uio.h> 257103285Sikob#include <sys/file.h> 258103285Sikob#include <sys/ioctl.h> 259103285Sikob 260103285Sikob#include <netinet/in.h> 261108655Ssimokawa 262108655Ssimokawa#include <arpa/inet.h> 263170374Ssimokawa 264103285Sikob#include <netdb.h> 265103285Sikob#include <stdio.h> 266170374Ssimokawa#include <err.h> 267103285Sikob#include <errno.h> 268170374Ssimokawa#include <stdlib.h> 269130460Sdfr#include <string.h> 270103285Sikob#include <unistd.h> 271103285Sikob 272103285Sikob#include <netinet/ip6.h> 273103285Sikob#include <netinet/icmp6.h> 274103285Sikob#include <netinet/udp.h> 275103285Sikob 276103285Sikob#ifdef IPSEC 277103285Sikob#include <net/route.h> 278103285Sikob#include <netinet6/ipsec.h> 279103285Sikob#endif 280103285Sikob 281103285Sikob#define DUMMY_PORT 10010 282103285Sikob 283170374Ssimokawa#define MAXPACKET 65535 /* max ip packet size */ 284170374Ssimokawa#ifndef MAXHOSTNAMELEN 285170374Ssimokawa#define MAXHOSTNAMELEN 64 286170374Ssimokawa#endif 287170374Ssimokawa 288170374Ssimokawa#ifndef FD_SET 289170374Ssimokawa#define NFDBITS (8*sizeof(fd_set)) 290170374Ssimokawa#define FD_SETSIZE NFDBITS 291103285Sikob#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 292103285Sikob#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 293103285Sikob#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 294103285Sikob#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 295170374Ssimokawa#endif 296170374Ssimokawa 297170374Ssimokawa#define Fprintf (void)fprintf 298170374Ssimokawa#define Sprintf (void)sprintf 299170374Ssimokawa#define Printf (void)printf 300170374Ssimokawa 301170374Ssimokawa#ifndef HAVE_GETIPNODEBYNAME 302170374Ssimokawa#define getipnodebyname(x, y, z, u) gethostbyname2((x), (y)) 303170374Ssimokawa#define freehostent(x) 304170374Ssimokawa#endif 305170374Ssimokawa 306170374Ssimokawa/* 307170374Ssimokawa * format of a (udp) probe packet. 308170374Ssimokawa */ 309103285Sikobstruct opacket { 310103285Sikob u_char seq; /* sequence number of this packet */ 311103285Sikob u_char hops; /* hop limit of the packet */ 312106790Ssimokawa struct timeval tv; /* time packet left */ 313106790Ssimokawa}; 314106790Ssimokawa 315103285Sikobu_char packet[512]; /* last inbound (icmp) packet */ 316103285Sikobstruct opacket *outpacket; /* last output (udp) packet */ 317170374Ssimokawa 318170374Ssimokawaint main __P((int, char *[])); 319170374Ssimokawaint wait_for_reply __P((int, struct msghdr *)); 320170374Ssimokawa#ifdef IPSEC 321103285Sikob#ifdef IPSEC_POLICY_IPSEC 322170374Ssimokawaint setpolicy __P((int so, char *policy)); 323103285Sikob#endif 324170374Ssimokawa#endif 325170374Ssimokawavoid send_probe __P((int, int)); 326103285Sikobstruct udphdr *get_udphdr __P((struct ip6_hdr *, u_char *)); 327103285Sikobint get_hoplim __P((struct msghdr *)); 328103285Sikobdouble deltaT __P((struct timeval *, struct timeval *)); 329103285Sikobchar *pr_type __P((int)); 330103285Sikobint packet_ok __P((struct msghdr *, int, int)); 331103285Sikobvoid print __P((struct msghdr *, int)); 332106790Ssimokawavoid tvsub __P((struct timeval *, struct timeval *)); 333125238Ssimokawaconst char *inetname __P((struct sockaddr *)); 334125238Ssimokawavoid usage __P((void)); 335125238Ssimokawa 336125238Ssimokawaint rcvsock; /* receive (icmp) socket file descriptor */ 337125238Ssimokawaint sndsock; /* send (udp) socket file descriptor */ 338125238Ssimokawastruct timezone tz; /* leftover */ 339103285Sikob 340125238Ssimokawastruct msghdr rcvmhdr; 341103285Sikobstruct iovec rcviov[2]; 342108281Ssimokawaint rcvhlim; 343125238Ssimokawastruct in6_pktinfo *rcvpktinfo; 344103285Sikob 345106790Ssimokawastruct sockaddr_in6 Src, Dst, Rcv; 346110577Ssimokawaint datalen; /* How much data */ 347170374Ssimokawa/* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */ 348110577Ssimokawachar rtbuf[2064]; 349170374Ssimokawa#ifdef USE_RFC2292BIS 350170374Ssimokawastruct ip6_rthdr *rth; 351110577Ssimokawa#endif 352110577Ssimokawastruct cmsghdr *cmsg; 353170374Ssimokawa 354111040Ssimokawachar *source = 0; 355110577Ssimokawachar *hostname; 356120660Ssimokawa 357120660Ssimokawaint nprobes = 3; 358110577Ssimokawaint first_hop = 1; 359110577Ssimokawaint max_hops = 30; 360110577Ssimokawau_short ident; 361170374Ssimokawau_short port = 32768+666; /* start udp dest port # for probe packets */ 362110577Ssimokawaint options; /* socket options */ 363111040Ssimokawaint verbose; 364171513Ssimokawaint waittime = 5; /* time to wait for response (in seconds) */ 365110577Ssimokawaint nflag; /* print addresses numerically */ 366169119Ssimokawaint lflag; /* print both numerical address & hostname */ 367170427Ssimokawa 368170427Ssimokawa#ifdef KAME_SCOPEID 369170427Ssimokawaconst int niflag = NI_WITHSCOPEID; 370110577Ssimokawa#else 371110577Ssimokawaconst int niflag = 0; 372110577Ssimokawa#endif 373110577Ssimokawa 374170374Ssimokawaint 375170374Ssimokawamain(argc, argv) 376170374Ssimokawa int argc; 377110577Ssimokawa char *argv[]; 378170374Ssimokawa{ 379170374Ssimokawa struct hostent *hp; 380110577Ssimokawa int error; 381110577Ssimokawa struct addrinfo hints, *res; 382171513Ssimokawa int ch, i, on, probe, seq, hops, rcvcmsglen; 383111040Ssimokawa static u_char *rcvcmsgbuf; 384170374Ssimokawa char hbuf[NI_MAXHOST], src0[NI_MAXHOST]; 385170374Ssimokawa 386170374Ssimokawa /* 387170374Ssimokawa * Receive ICMP 388110577Ssimokawa */ 389110577Ssimokawa if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { 390170374Ssimokawa perror("socket(ICMPv6)"); 391110577Ssimokawa exit(5); 392110577Ssimokawa } 393110577Ssimokawa 394110577Ssimokawa /* set a minimum set of socket options */ 395170374Ssimokawa on = 1; 396110577Ssimokawa /* specify to tell receiving interface */ 397110577Ssimokawa#ifdef IPV6_RECVPKTINFO 398121463Ssimokawa if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 399121463Ssimokawa sizeof(on)) < 0) 400121463Ssimokawa err(1, "setsockopt(IPV6_RECVPKTINFO)"); 401121463Ssimokawa#else /* old adv. API */ 402121463Ssimokawa if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_PKTINFO, &on, 403121463Ssimokawa sizeof(on)) < 0) 404170374Ssimokawa err(1, "setsockopt(IPV6_PKTINFO)"); 405170374Ssimokawa#endif 406170374Ssimokawa 407170374Ssimokawa /* specify to tell value of hoplimit field of received IP6 hdr */ 408121463Ssimokawa#ifdef IPV6_RECVHOPLIMIT 409170374Ssimokawa if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, 410110577Ssimokawa sizeof(on)) < 0) 411110577Ssimokawa err(1, "setsockopt(IPV6_RECVHOPLIMIT)"); 412110577Ssimokawa#else /* old adv. API */ 413103285Sikob if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, 414103285Sikob sizeof(on)) < 0) 415103285Sikob err(1, "setsockopt(IPV6_HOPLIMIT)"); 416103285Sikob#endif 417118455Ssimokawa 418103285Sikob /* revoke privs */ 419118455Ssimokawa seteuid(getuid()); 420103285Sikob setuid(getuid()); 421103285Sikob 422103285Sikob seq = 0; 423103285Sikob 424103285Sikob while ((ch = getopt(argc, argv, "df:g:lm:np:q:rs:w:v")) != EOF) 425103285Sikob switch(ch) { 426116978Ssimokawa case 'd': 427103285Sikob options |= SO_DEBUG; 428118455Ssimokawa break; 429118455Ssimokawa case 'f': 430103285Sikob first_hop = atoi(optarg); 431118455Ssimokawa if (first_hop > max_hops) { 432118455Ssimokawa Fprintf(stderr, 433187993Ssbruno "traceroute6: min hoplimit must be <= %d.\n", max_hops); 434187993Ssbruno exit(1); 435187993Ssbruno } 436187993Ssbruno break; 437187993Ssbruno case 'g': 438187993Ssbruno hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno); 439187993Ssbruno if (hp == NULL) { 440187993Ssbruno Fprintf(stderr, 441187993Ssbruno "traceroute6: unknown host %s\n", optarg); 442187993Ssbruno exit(1); 443187993Ssbruno } 444187993Ssbruno#ifdef USE_RFC2292BIS 445187993Ssbruno if (rth == NULL) { 446187993Ssbruno /* 447187993Ssbruno * XXX: We can't detect the number of 448187993Ssbruno * intermediate nodes yet. 449187993Ssbruno */ 450187993Ssbruno if ((rth = inet6_rth_init((void *)rtbuf, 451187993Ssbruno sizeof(rtbuf), 452187993Ssbruno IPV6_RTHDR_TYPE_0, 453187993Ssbruno 0)) == NULL) { 454187993Ssbruno Fprintf(stderr, 455187993Ssbruno "inet6_rth_init failed.\n"); 456187993Ssbruno exit(1); 457187993Ssbruno } 458170374Ssimokawa } 459171513Ssimokawa if (inet6_rth_add((void *)rth, 460170374Ssimokawa (struct in6_addr *)hp->h_addr)) { 461170374Ssimokawa Fprintf(stderr, 462170374Ssimokawa "inet6_rth_add failed for %s\n", 463170374Ssimokawa optarg); 464108853Ssimokawa exit(1); 465110577Ssimokawa } 466110577Ssimokawa#else /* old advanced API */ 467110193Ssimokawa if (cmsg == NULL) 468169806Ssimokawa cmsg = inet6_rthdr_init(rtbuf, IPV6_RTHDR_TYPE_0); 469172836Sjulian inet6_rthdr_add(cmsg, (struct in6_addr *)hp->h_addr, IPV6_RTHDR_LOOSE); 470169806Ssimokawa#endif 471169806Ssimokawa freehostent(hp); 472103285Sikob break; 473103285Sikob case 'l': 474103285Sikob lflag++; 475103285Sikob break; 476103285Sikob case 'm': 477103285Sikob max_hops = atoi(optarg); 478103285Sikob if (max_hops < first_hop) { 479187993Ssbruno Fprintf(stderr, 480169117Ssimokawa "traceroute6: max hoplimit must be >= %d.\n", first_hop); 481187993Ssbruno exit(1); 482103285Sikob } 483103285Sikob break; 484103285Sikob case 'n': 485103285Sikob nflag++; 486103285Sikob break; 487103285Sikob case 'p': 488103285Sikob port = atoi(optarg); 489103285Sikob if (port < 1) { 490103285Sikob Fprintf(stderr, 491103285Sikob "traceroute6: port must be >0.\n"); 492103285Sikob exit(1); 493103285Sikob } 494103285Sikob break; 495103285Sikob case 'q': 496103285Sikob nprobes = atoi(optarg); 497103285Sikob if (nprobes < 1) { 498103285Sikob Fprintf(stderr, 499103285Sikob "traceroute6: nprobes must be >0.\n"); 500103285Sikob exit(1); 501103285Sikob } 502103285Sikob break; 503103285Sikob case 'r': 504103285Sikob options |= SO_DONTROUTE; 505106790Ssimokawa break; 506116978Ssimokawa case 's': 507116978Ssimokawa /* 508116978Ssimokawa * set the ip source address of the outbound 509116978Ssimokawa * probe (e.g., on a multi-homed host). 510116978Ssimokawa */ 511116978Ssimokawa source = optarg; 512116978Ssimokawa break; 513116978Ssimokawa case 'v': 514116978Ssimokawa verbose++; 515116978Ssimokawa break; 516116978Ssimokawa case 'w': 517116978Ssimokawa waittime = atoi(optarg); 518116978Ssimokawa if (waittime <= 1) { 519103285Sikob Fprintf(stderr, 520103285Sikob "traceroute6: wait must be >1 sec.\n"); 521103285Sikob exit(1); 522103285Sikob } 523118455Ssimokawa break; 524103285Sikob default: 525103285Sikob usage(); 526169806Ssimokawa } 527111078Ssimokawa argc -= optind; 528118455Ssimokawa argv += optind; 529103285Sikob 530103285Sikob if (argc < 1) 531169806Ssimokawa usage(); 532170374Ssimokawa 533169806Ssimokawa#if 1 534170374Ssimokawa setvbuf(stdout, NULL, _IOLBF, BUFSIZ); 535170374Ssimokawa#else 536170374Ssimokawa setlinebuf (stdout); 537170374Ssimokawa#endif 538169806Ssimokawa 539178915Ssimokawa memset(&hints, 0, sizeof(hints)); 540178915Ssimokawa hints.ai_family = PF_INET6; 541178915Ssimokawa hints.ai_socktype = SOCK_RAW; 542118455Ssimokawa hints.ai_protocol = IPPROTO_ICMPV6; 543118455Ssimokawa hints.ai_flags = AI_CANONNAME; 544106790Ssimokawa error = getaddrinfo(*argv, NULL, &hints, &res); 545118455Ssimokawa if (error) { 546118455Ssimokawa (void)fprintf(stderr, 547111078Ssimokawa "traceroute6: %s\n", gai_strerror(error)); 548169806Ssimokawa exit(1); 549169806Ssimokawa } 550169806Ssimokawa if (res->ai_addrlen != sizeof(Dst)) { 551111078Ssimokawa (void)fprintf(stderr, 552178915Ssimokawa "traceroute6: size of sockaddr mismatch\n"); 553169806Ssimokawa exit(1); 554111078Ssimokawa } 555111078Ssimokawa memcpy(&Dst, res->ai_addr, res->ai_addrlen); 556111078Ssimokawa hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv; 557111078Ssimokawa 558169806Ssimokawa if (*++argv) 559169806Ssimokawa datalen = atoi(*argv); 560169806Ssimokawa if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) { 561169806Ssimokawa Fprintf(stderr, 562171513Ssimokawa "traceroute6: packet size must be 0 <= s < %ld.\n", 563170374Ssimokawa (long)(MAXPACKET - sizeof(struct opacket))); 564103285Sikob exit(1); 565103285Sikob } 566103285Sikob datalen += sizeof(struct opacket); 567103285Sikob outpacket = (struct opacket *)malloc((unsigned)datalen); 568103285Sikob if (! outpacket) { 569103285Sikob perror("malloc"); 570103285Sikob exit(1); 571103285Sikob } 572103285Sikob (void) bzero((char *)outpacket, datalen); 573106790Ssimokawa 574110577Ssimokawa /* initialize msghdr for receiving packets */ 575110577Ssimokawa rcviov[0].iov_base = (caddr_t)packet; 576110798Ssimokawa rcviov[0].iov_len = sizeof(packet); 577110577Ssimokawa rcvmhdr.msg_name = (caddr_t)&Rcv; 578110577Ssimokawa rcvmhdr.msg_namelen = sizeof(Rcv); 579110577Ssimokawa rcvmhdr.msg_iov = rcviov; 580110577Ssimokawa rcvmhdr.msg_iovlen = 1; 581110577Ssimokawa rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) 582170374Ssimokawa + CMSG_SPACE(sizeof(int)); 583111942Ssimokawa if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) { 584170374Ssimokawa Fprintf(stderr, "traceroute6: malloc failed\n"); 585110577Ssimokawa exit(1); 586170374Ssimokawa } 587113584Ssimokawa rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; 588110577Ssimokawa rcvmhdr.msg_controllen = rcvcmsglen; 589110577Ssimokawa 590110577Ssimokawa if (options & SO_DEBUG) 591110798Ssimokawa (void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, 592110798Ssimokawa (char *)&on, sizeof(on)); 593110798Ssimokawa if (options & SO_DONTROUTE) 594170374Ssimokawa (void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, 595170374Ssimokawa (char *)&on, sizeof(on)); 596110798Ssimokawa#ifdef IPSEC 597110798Ssimokawa#ifdef IPSEC_POLICY_IPSEC 598170374Ssimokawa /* 599170374Ssimokawa * do not raise error even if setsockopt fails, kernel may have ipsec 600170374Ssimokawa * turned off. 601110798Ssimokawa */ 602110798Ssimokawa if (setpolicy(rcvsock, "in bypass") < 0) 603110798Ssimokawa errx(1, "%s", ipsec_strerror()); 604110798Ssimokawa if (setpolicy(rcvsock, "out bypass") < 0) 605171513Ssimokawa errx(1, "%s", ipsec_strerror()); 606170374Ssimokawa#else 607171513Ssimokawa { 608170374Ssimokawa int level = IPSEC_LEVEL_NONE; 609170374Ssimokawa 610170374Ssimokawa (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, 611170374Ssimokawa sizeof(level)); 612170374Ssimokawa (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, 613170374Ssimokawa sizeof(level)); 614170374Ssimokawa#ifdef IP_AUTH_TRANS_LEVEL 615170374Ssimokawa (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, 616171513Ssimokawa sizeof(level)); 617170374Ssimokawa#else 618170374Ssimokawa (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, 619170374Ssimokawa sizeof(level)); 620110798Ssimokawa#endif 621110798Ssimokawa#ifdef IP_AUTH_NETWORK_LEVEL 622116376Ssimokawa (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, 623116376Ssimokawa sizeof(level)); 624103285Sikob#endif 625103285Sikob } 626103285Sikob#endif /*IPSEC_POLICY_IPSEC*/ 627103285Sikob#endif /*IPSEC*/ 628103285Sikob 629103285Sikob /* 630103285Sikob * Send UDP 631103285Sikob */ 632103285Sikob if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 633103285Sikob perror("socket(SOCK_DGRAM)"); 634103285Sikob exit(5); 635103285Sikob } 636103285Sikob#ifdef SO_SNDBUF 637103285Sikob if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, 638103285Sikob sizeof(datalen)) < 0) { 639103285Sikob perror("setsockopt(SO_SNDBUF)"); 640103285Sikob exit(6); 641103285Sikob } 642103285Sikob#endif /* SO_SNDBUF */ 643103285Sikob if (options & SO_DEBUG) 644103285Sikob (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, 645103285Sikob (char *)&on, sizeof(on)); 646103285Sikob if (options & SO_DONTROUTE) 647103285Sikob (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, 648103285Sikob (char *)&on, sizeof(on)); 649103285Sikob#ifdef USE_RFC2292BIS 650103285Sikob if (rth) {/* XXX: there is no library to finalize the header... */ 651103285Sikob rth->ip6r_len = rth->ip6r_segleft * 2; 652103285Sikob if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR, 653103285Sikob (void *)rth, (rth->ip6r_len + 1) << 3)) { 654103285Sikob Fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n", 655103285Sikob strerror(errno)); 656103285Sikob exit(1); 657103285Sikob } 658103285Sikob } 659103285Sikob#else /* old advanced API */ 660103285Sikob if (cmsg != NULL) { 661103285Sikob inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE); 662103285Sikob if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_PKTOPTIONS, 663103285Sikob rtbuf, cmsg->cmsg_len) < 0) { 664103285Sikob Fprintf(stderr, "setsockopt(IPV6_PKTOPTIONS): %s\n", 665116376Ssimokawa strerror(errno)); 666113584Ssimokawa exit(1); 667116376Ssimokawa } 668116376Ssimokawa } 669116376Ssimokawa#endif /* USE_RFC2292BIS */ 670116376Ssimokawa#ifdef IPSEC 671116376Ssimokawa#ifdef IPSEC_POLICY_IPSEC 672116376Ssimokawa /* 673116376Ssimokawa * do not raise error even if setsockopt fails, kernel may have ipsec 674116376Ssimokawa * turned off. 675116376Ssimokawa */ 676116376Ssimokawa if (setpolicy(sndsock, "in bypass") < 0) 677116376Ssimokawa errx(1, "%s", ipsec_strerror()); 678116376Ssimokawa if (setpolicy(sndsock, "out bypass") < 0) 679116376Ssimokawa errx(1, "%s", ipsec_strerror()); 680116376Ssimokawa#else 681116376Ssimokawa { 682116376Ssimokawa int level = IPSEC_LEVEL_BYPASS; 683116376Ssimokawa 684116376Ssimokawa (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, 685116376Ssimokawa sizeof(level)); 686116376Ssimokawa (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, 687116376Ssimokawa sizeof(level)); 688189928Ssbruno#ifdef IP_AUTH_TRANS_LEVEL 689189928Ssbruno (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, 690116376Ssimokawa sizeof(level)); 691116376Ssimokawa#else 692116376Ssimokawa (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, 693116376Ssimokawa sizeof(level)); 694116376Ssimokawa#endif 695116376Ssimokawa#ifdef IP_AUTH_NETWORK_LEVEL 696116376Ssimokawa (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, 697116376Ssimokawa sizeof(level)); 698116376Ssimokawa#endif 699116376Ssimokawa } 700116376Ssimokawa#endif /*IPSEC_POLICY_IPSEC*/ 701116376Ssimokawa#endif /*IPSEC*/ 702116376Ssimokawa 703116376Ssimokawa /* 704116376Ssimokawa * Source selection 705116376Ssimokawa */ 706116376Ssimokawa bzero(&Src, sizeof(Src)); 707116376Ssimokawa if (source) { 708116376Ssimokawa struct addrinfo hints, *res; 709116376Ssimokawa int error; 710116376Ssimokawa 711116376Ssimokawa memset(&hints, 0, sizeof(hints)); 712116376Ssimokawa hints.ai_family = AF_INET6; 713116376Ssimokawa hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 714116376Ssimokawa hints.ai_flags = AI_NUMERICHOST; 715116376Ssimokawa error = getaddrinfo(source, "0", &hints, &res); 716116376Ssimokawa if (error) { 717116376Ssimokawa Printf("traceroute6: %s: %s\n", source, 718116376Ssimokawa gai_strerror(error)); 719127468Ssimokawa exit(1); 720127468Ssimokawa } 721127468Ssimokawa if (res->ai_addrlen > sizeof(Src)) { 722127468Ssimokawa Printf("traceroute6: %s: %s\n", source, 723116376Ssimokawa gai_strerror(error)); 724116376Ssimokawa exit(1); 725127468Ssimokawa } 726193066Sjamie memcpy(&Src, res->ai_addr, res->ai_addrlen); 727193066Sjamie freeaddrinfo(res); 728193066Sjamie } else { 729116376Ssimokawa struct sockaddr_in6 Nxt; 730116376Ssimokawa int dummy, len; 731116376Ssimokawa 732116376Ssimokawa Nxt = Dst; 733116376Ssimokawa Nxt.sin6_port = htons(DUMMY_PORT); 734116376Ssimokawa if (cmsg != NULL) 735169117Ssimokawa bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr, 736116376Ssimokawa sizeof(Nxt.sin6_addr)); 737116376Ssimokawa if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 738117350Ssimokawa perror("socket"); 739116376Ssimokawa exit(1); 740189928Ssbruno } 741116376Ssimokawa if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) { 742116376Ssimokawa perror("connect"); 743187993Ssbruno exit(1); 744187993Ssbruno } 745116376Ssimokawa len = sizeof(Src); 746187993Ssbruno if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) { 747169117Ssimokawa perror("getsockname"); 748116376Ssimokawa exit(1); 749187993Ssbruno } 750187993Ssbruno if (getnameinfo((struct sockaddr *)&Src, Src.sin6_len, 751187993Ssbruno src0, sizeof(src0), NULL, 0, 752187993Ssbruno NI_NUMERICHOST | niflag)) { 753116376Ssimokawa Fprintf(stderr, "getnameinfo failed for source\n"); 754116376Ssimokawa exit(1); 755113584Ssimokawa } 756113584Ssimokawa source = src0; 757113584Ssimokawa close(dummy); 758113584Ssimokawa } 759113584Ssimokawa 760113584Ssimokawa#if 1 761113584Ssimokawa ident = (getpid() & 0xffff) | 0x8000; 762113584Ssimokawa#else 763113584Ssimokawa ident = 0; /*let the kernel pick one*/ 764116376Ssimokawa#endif 765117350Ssimokawa Src.sin6_port = htons(ident); 766189928Ssbruno if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) { 767189928Ssbruno perror("bind"); 768189928Ssbruno exit(1); 769189928Ssbruno } 770189928Ssbruno 771189928Ssbruno if (ident == 0) { 772189928Ssbruno int len; 773189928Ssbruno 774189928Ssbruno len = sizeof(Src); 775189928Ssbruno if (getsockname(sndsock, (struct sockaddr *)&Src, &i) < 0) { 776189928Ssbruno perror("getsockname"); 777189928Ssbruno exit(1); 778189928Ssbruno } 779189928Ssbruno ident = ntohs(Src.sin6_port); 780189928Ssbruno } 781189928Ssbruno 782189928Ssbruno /* 783189928Ssbruno * Message to users 784189928Ssbruno */ 785189928Ssbruno if (getnameinfo((struct sockaddr *)&Dst, Dst.sin6_len, hbuf, 786189928Ssbruno sizeof(hbuf), NULL, 0, NI_NUMERICHOST | niflag)) 787189928Ssbruno strcpy(hbuf, "(invalid)"); 788189928Ssbruno Fprintf(stderr, "traceroute6"); 789189928Ssbruno Fprintf(stderr, " to %s (%s)", hostname, hbuf); 790189928Ssbruno if (source) 791103285Sikob Fprintf(stderr, " from %s", source); 792106790Ssimokawa Fprintf(stderr, 793103285Sikob ", %d hops max, %d byte packets\n", 794106790Ssimokawa max_hops, datalen); 795103285Sikob (void) fflush(stderr); 796103285Sikob 797106543Ssimokawa if (first_hop > 1) 798103285Sikob Printf("Skipping %d intermediate hops\n", first_hop - 1); 799103285Sikob 800106543Ssimokawa /* 801103285Sikob * Main loop 802103285Sikob */ 803103285Sikob for (hops = first_hop; hops <= max_hops; ++hops) { 804103285Sikob struct in6_addr lastaddr; 805103285Sikob int got_there = 0; 806103285Sikob int unreachable = 0; 807103285Sikob 808103285Sikob Printf("%2d ", hops); 809103285Sikob bzero(&lastaddr, sizeof(lastaddr)); 810103285Sikob for (probe = 0; probe < nprobes; ++probe) { 811103285Sikob int cc; 812113584Ssimokawa struct timeval t1, t2; 813113584Ssimokawa struct timezone tz; 814113584Ssimokawa 815113584Ssimokawa (void) gettimeofday(&t1, &tz); 816103285Sikob send_probe(++seq, hops); 817103285Sikob while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) { 818103285Sikob (void) gettimeofday(&t2, &tz); 819103285Sikob if ((i = packet_ok(&rcvmhdr, cc, seq))) { 820103285Sikob if (! IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr, 821103285Sikob &lastaddr)) { 822103285Sikob print(&rcvmhdr, cc); 823103285Sikob lastaddr = Rcv.sin6_addr; 824103285Sikob } 825103285Sikob Printf(" %g ms", deltaT(&t1, &t2)); 826103285Sikob switch(i - 1) { 827103285Sikob case ICMP6_DST_UNREACH_NOROUTE: 828103285Sikob ++unreachable; 829103285Sikob Printf(" !N"); 830103285Sikob break; 831103285Sikob case ICMP6_DST_UNREACH_ADMIN: 832103285Sikob ++unreachable; 833103285Sikob Printf(" !P"); 834103285Sikob break; 835103285Sikob case ICMP6_DST_UNREACH_NOTNEIGHBOR: 836103285Sikob ++unreachable; 837103285Sikob Printf(" !S"); 838103285Sikob break; 839103285Sikob case ICMP6_DST_UNREACH_ADDR: 840103285Sikob ++unreachable; 841103285Sikob Printf(" !A"); 842103285Sikob break; 843103285Sikob case ICMP6_DST_UNREACH_NOPORT: 844103285Sikob if (rcvhlim >= 0 && 845103285Sikob rcvhlim <= 1) 846187993Ssbruno Printf(" !"); 847103285Sikob ++got_there; 848103285Sikob break; 849103285Sikob } 850103285Sikob break; 851103285Sikob } 852110193Ssimokawa } 853103285Sikob if (cc == 0) 854103285Sikob Printf(" *"); 855103285Sikob (void) fflush(stdout); 856103285Sikob } 857103285Sikob putchar('\n'); 858103285Sikob if (got_there || 859103285Sikob (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) { 860103285Sikob exit(0); 861103285Sikob } 862103285Sikob } 863103285Sikob 864103285Sikob exit(0); 865103285Sikob} 866103285Sikob 867103285Sikobint 868103285Sikobwait_for_reply(sock, mhdr) 869103285Sikob int sock; 870103285Sikob struct msghdr *mhdr; 871103285Sikob{ 872103285Sikob fd_set fds; 873103285Sikob struct timeval wait; 874103285Sikob int cc = 0; 875116376Ssimokawa 876103285Sikob FD_ZERO(&fds); 877106543Ssimokawa FD_SET(sock, &fds); 878103285Sikob wait.tv_sec = waittime; wait.tv_usec = 0; 879103285Sikob 880103285Sikob if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0) 881110195Ssimokawa cc = recvmsg(rcvsock, mhdr, 0); 882103285Sikob 883103285Sikob return(cc); 884139680Sjmg} 885103285Sikob 886167632Ssimokawa#ifdef IPSEC 887103285Sikob#ifdef IPSEC_POLICY_IPSEC 888103285Sikobint 889103285Sikobsetpolicy(so, policy) 890103285Sikob int so; 891103285Sikob char *policy; 892103285Sikob{ 893103285Sikob char *buf; 894103285Sikob 895106543Ssimokawa buf = ipsec_set_policy(policy, strlen(policy)); 896103285Sikob if (buf == NULL) { 897106790Ssimokawa warnx("%s", ipsec_strerror()); 898120660Ssimokawa return -1; 899120660Ssimokawa } 900120660Ssimokawa (void)setsockopt(so, IPPROTO_IPV6, IPV6_IPSEC_POLICY, 901103285Sikob buf, ipsec_get_policylen(buf)); 902129541Sdfr 903103285Sikob free(buf); 904106813Ssimokawa 905129585Sdfr return 0; 906103285Sikob} 907120660Ssimokawa#endif 908170374Ssimokawa#endif 909120660Ssimokawa 910120660Ssimokawavoid 911170374Ssimokawasend_probe(seq, hops) 912120660Ssimokawa int seq, hops; 913170374Ssimokawa{ 914170374Ssimokawa struct opacket *op = outpacket; 915170374Ssimokawa int i; 916170374Ssimokawa 917170374Ssimokawa if(setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 918170374Ssimokawa (char *)&hops, sizeof(hops)) < 0) { 919103285Sikob perror("setsockopt IPV6_UNICAST_HOPS"); 920106790Ssimokawa } 921103285Sikob 922103285Sikob Dst.sin6_port = htons(port + seq); 923103285Sikob 924106790Ssimokawa op->seq = seq; 925106790Ssimokawa op->hops = hops; 926103285Sikob (void) gettimeofday(&op->tv, &tz); 927120660Ssimokawa 928170374Ssimokawa i = sendto(sndsock, (char *)outpacket, datalen , 0, 929120660Ssimokawa (struct sockaddr *)&Dst, Dst.sin6_len); 930120660Ssimokawa if (i < 0 || i != datalen) { 931127468Ssimokawa if (i<0) 932120660Ssimokawa perror("sendto"); 933120660Ssimokawa Printf("traceroute6: wrote %s %d chars, ret=%d\n", hostname, 934120660Ssimokawa datalen, i); 935170374Ssimokawa (void) fflush(stdout); 936120660Ssimokawa } 937120660Ssimokawa} 938120660Ssimokawa 939120660Ssimokawaint 940120660Ssimokawaget_hoplim(mhdr) 941170374Ssimokawa struct msghdr *mhdr; 942103285Sikob{ 943170374Ssimokawa struct cmsghdr *cm; 944120660Ssimokawa 945170374Ssimokawa for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 946170374Ssimokawa cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 947170374Ssimokawa if (cm->cmsg_level == IPPROTO_IPV6 && 948103285Sikob cm->cmsg_type == IPV6_HOPLIMIT && 949170374Ssimokawa cm->cmsg_len == CMSG_LEN(sizeof(int))) 950170374Ssimokawa return(*(int *)CMSG_DATA(cm)); 951103285Sikob } 952103285Sikob 953103285Sikob return(-1); 954103285Sikob} 955103285Sikob 956106790Ssimokawadouble 957106790SsimokawadeltaT(t1p, t2p) 958103285Sikob struct timeval *t1p, *t2p; 959120660Ssimokawa{ 960120660Ssimokawa register double dt; 961120660Ssimokawa 962120660Ssimokawa dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + 963103285Sikob (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; 964103285Sikob return (dt); 965103285Sikob} 966170374Ssimokawa 967120660Ssimokawa 968120660Ssimokawa/* 969120660Ssimokawa * Convert an ICMP "type" field to a printable string. 970120660Ssimokawa */ 971120660Ssimokawachar * 972120660Ssimokawapr_type(t0) 973129541Sdfr int t0; 974170374Ssimokawa{ 975120660Ssimokawa u_char t = t0 & 0xff; 976120660Ssimokawa char *cp; 977120660Ssimokawa 978120660Ssimokawa switch (t) { 979113584Ssimokawa case ICMP6_DST_UNREACH: 980113584Ssimokawa cp = "Destination Unreachable"; 981113584Ssimokawa break; 982113584Ssimokawa case ICMP6_PACKET_TOO_BIG: 983113584Ssimokawa cp = "Pakcet Too Big"; 984113584Ssimokawa break; 985120660Ssimokawa case ICMP6_TIME_EXCEEDED: 986170374Ssimokawa cp = "Time Exceeded"; 987113584Ssimokawa break; 988103285Sikob case ICMP6_PARAM_PROB: 989103285Sikob cp = "Parameter Problem"; 990103285Sikob break; 991103285Sikob case ICMP6_ECHO_REQUEST: 992169130Ssimokawa cp = "Echo Request"; 993169130Ssimokawa break; 994169130Ssimokawa case ICMP6_ECHO_REPLY: 995169130Ssimokawa cp = "Echo Reply"; 996169130Ssimokawa break; 997169130Ssimokawa case ICMP6_MEMBERSHIP_QUERY: 998169130Ssimokawa cp = "Group Membership Query"; 999169130Ssimokawa break; 1000169130Ssimokawa case ICMP6_MEMBERSHIP_REPORT: 1001169130Ssimokawa cp = "Group Membership Report"; 1002169130Ssimokawa break; 1003169130Ssimokawa case ICMP6_MEMBERSHIP_REDUCTION: 1004169130Ssimokawa cp = "Group Membership Reduction"; 1005169130Ssimokawa break; 1006169130Ssimokawa case ND_ROUTER_SOLICIT: 1007169130Ssimokawa cp = "Router Solicitation"; 1008169130Ssimokawa break; 1009169130Ssimokawa case ND_ROUTER_ADVERT: 1010169130Ssimokawa cp = "Router Advertisement"; 1011169130Ssimokawa break; 1012169130Ssimokawa case ND_NEIGHBOR_SOLICIT: 1013169130Ssimokawa cp = "Neighbor Solicitation"; 1014169130Ssimokawa break; 1015169130Ssimokawa case ND_NEIGHBOR_ADVERT: 1016169130Ssimokawa cp = "Neighbor Advertisement"; 1017169130Ssimokawa break; 1018169130Ssimokawa case ND_REDIRECT: 1019169130Ssimokawa cp = "Redirect"; 1020169130Ssimokawa break; 1021169130Ssimokawa default: 1022169130Ssimokawa cp = "Unknown"; 1023169130Ssimokawa break; 1024169130Ssimokawa } 1025170374Ssimokawa return cp; 1026170374Ssimokawa} 1027170374Ssimokawa 1028170374Ssimokawa 1029170374Ssimokawaint 1030170374Ssimokawapacket_ok(mhdr, cc, seq) 1031170374Ssimokawa struct msghdr *mhdr; 1032170374Ssimokawa int cc; 1033170374Ssimokawa int seq; 1034170374Ssimokawa{ 1035170374Ssimokawa register struct icmp6_hdr *icp; 1036170374Ssimokawa struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; 1037170374Ssimokawa u_char type, code; 1038169130Ssimokawa char *buf = (char *)mhdr->msg_iov[0].iov_base; 1039103285Sikob struct cmsghdr *cm; 1040103285Sikob int *hlimp; 1041103285Sikob char hbuf[NI_MAXHOST]; 1042106790Ssimokawa 1043106790Ssimokawa#ifdef OLDRAWSOCKET 1044103285Sikob int hlen; 1045169119Ssimokawa struct ip6_hdr *ip; 1046169119Ssimokawa#endif 1047103285Sikob 1048169119Ssimokawa#ifdef OLDRAWSOCKET 1049169119Ssimokawa ip = (struct ip6_hdr *) buf; 1050169119Ssimokawa hlen = sizeof(struct ip6_hdr); 1051169119Ssimokawa if (cc < hlen + sizeof(struct icmp6_hdr)) { 1052171513Ssimokawa if (verbose) { 1053169119Ssimokawa if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1054169119Ssimokawa hbuf, sizeof(hbuf), NULL, 0, 1055169119Ssimokawa NI_NUMERICHOST | niflag) != 0) 1056169119Ssimokawa strcpy(hbuf, "invalid"); 1057169119Ssimokawa Printf("packet too short (%d bytes) from %s\n", cc, 1058170374Ssimokawa hbuf); 1059170374Ssimokawa } 1060170374Ssimokawa return (0); 1061170374Ssimokawa } 1062170374Ssimokawa cc -= hlen; 1063170374Ssimokawa icp = (struct icmp6_hdr *)(buf + hlen); 1064171513Ssimokawa#else 1065169119Ssimokawa if (cc < sizeof(struct icmp6_hdr)) { 1066169119Ssimokawa if (verbose) { 1067103285Sikob if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1068169119Ssimokawa hbuf, sizeof(hbuf), NULL, 0, 1069169119Ssimokawa NI_NUMERICHOST | niflag) != 0) 1070169119Ssimokawa strcpy(hbuf, "invalid"); 1071171513Ssimokawa Printf("data too short (%d bytes) from %s\n", cc, hbuf); 1072103285Sikob } 1073103285Sikob return(0); 1074103285Sikob } 1075106790Ssimokawa icp = (struct icmp6_hdr *)buf; 1076103285Sikob#endif 1077103285Sikob /* get optional information via advanced API */ 1078103285Sikob rcvpktinfo = NULL; 1079106790Ssimokawa hlimp = NULL; 1080170374Ssimokawa for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 1081103285Sikob cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 1082103285Sikob if (cm->cmsg_level == IPPROTO_IPV6 && 1083103285Sikob cm->cmsg_type == IPV6_PKTINFO && 1084170374Ssimokawa cm->cmsg_len == 1085103285Sikob CMSG_LEN(sizeof(struct in6_pktinfo))) 1086171513Ssimokawa rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm)); 1087169119Ssimokawa 1088169119Ssimokawa if (cm->cmsg_level == IPPROTO_IPV6 && 1089171513Ssimokawa cm->cmsg_type == IPV6_HOPLIMIT && 1090103285Sikob cm->cmsg_len == CMSG_LEN(sizeof(int))) 1091170374Ssimokawa hlimp = (int *)CMSG_DATA(cm); 1092170374Ssimokawa } 1093170374Ssimokawa if (rcvpktinfo == NULL || hlimp == NULL) { 1094170374Ssimokawa warnx("failed to get received hop limit or packet info"); 1095170374Ssimokawa#if 0 1096170374Ssimokawa return(0); 1097170374Ssimokawa#else 1098170374Ssimokawa rcvhlim = 0; /*XXX*/ 1099170374Ssimokawa#endif 1100170374Ssimokawa } 1101170374Ssimokawa else 1102110577Ssimokawa rcvhlim = *hlimp; 1103110577Ssimokawa 1104103285Sikob type = icp->icmp6_type; 1105103285Sikob code = icp->icmp6_code; 1106171513Ssimokawa if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) 1107110577Ssimokawa || type == ICMP6_DST_UNREACH) { 1108110577Ssimokawa struct ip6_hdr *hip; 1109103285Sikob struct udphdr *up; 1110103285Sikob 1111103285Sikob hip = (struct ip6_hdr *)(icp + 1); 1112106790Ssimokawa if ((up = get_udphdr(hip, (u_char *)(buf + cc))) == NULL) { 1113103285Sikob if (verbose) 1114103285Sikob warnx("failed to get upper layer header"); 1115103285Sikob return(0); 1116106790Ssimokawa } 1117110269Ssimokawa if (up->uh_sport == htons(ident) && 1118103285Sikob up->uh_dport == htons(port+seq)) 1119103285Sikob return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1); 1120106790Ssimokawa } 1121110269Ssimokawa if (verbose) { 1122106790Ssimokawa int i; 1123106790Ssimokawa u_int8_t *p; 1124106790Ssimokawa char sbuf[NI_MAXHOST+1], dbuf[INET6_ADDRSTRLEN]; 1125110269Ssimokawa 1126106790Ssimokawa if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1127103285Sikob sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST | niflag) != 0) 1128103285Sikob strcpy(sbuf, "invalid"); 1129106790Ssimokawa Printf("\n%d bytes from %s to %s", cc, sbuf, 1130113584Ssimokawa rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1131113584Ssimokawa dbuf, sizeof(dbuf)) 1132113584Ssimokawa : "?"); 1133113584Ssimokawa Printf(": icmp type %d (%s) code %d\n", type, pr_type(type), 1134113584Ssimokawa icp->icmp6_code); 1135113584Ssimokawa p = (u_int8_t *)(icp + 1); 1136126102Scperciva#define WIDTH 16 1137126102Scperciva for (i = 0; i < cc; i++) { 1138120660Ssimokawa if (i % WIDTH == 0) 1139120660Ssimokawa Printf("%04x:", i); 1140120660Ssimokawa if (i % 4 == 0) 1141120660Ssimokawa Printf(" "); 1142120660Ssimokawa Printf("%02x", p[i]); 1143113584Ssimokawa if (i % WIDTH == WIDTH - 1) 1144113584Ssimokawa Printf("\n"); 1145113584Ssimokawa } 1146113584Ssimokawa if (cc % WIDTH != 0) 1147120660Ssimokawa Printf("\n"); 1148120660Ssimokawa } 1149120660Ssimokawa return(0); 1150120660Ssimokawa} 1151120660Ssimokawa 1152113584Ssimokawa/* 1153113584Ssimokawa * Increment pointer until find the UDP header. 1154113584Ssimokawa */ 1155113584Ssimokawastruct udphdr * 1156113584Ssimokawaget_udphdr(ip6, lim) 1157113584Ssimokawa struct ip6_hdr *ip6; 1158113584Ssimokawa u_char *lim; 1159103285Sikob{ 1160103285Sikob u_char *cp = (u_char *)ip6, nh; 1161103285Sikob int hlen; 1162103285Sikob 1163103285Sikob if (cp + sizeof(*ip6) >= lim) 1164103285Sikob return(NULL); 1165167632Ssimokawa 1166167632Ssimokawa nh = ip6->ip6_nxt; 1167103285Sikob cp += sizeof(struct ip6_hdr); 1168117716Ssimokawa 1169103285Sikob while(lim - cp >= 8) { 1170121505Ssimokawa switch(nh) { 1171121505Ssimokawa case IPPROTO_ESP: 1172121505Ssimokawa case IPPROTO_TCP: 1173168051Ssimokawa case IPPROTO_ICMPV6: 1174167632Ssimokawa return(NULL); 1175103285Sikob case IPPROTO_UDP: 1176103285Sikob return((struct udphdr *)cp); 1177106790Ssimokawa case IPPROTO_FRAGMENT: 1178113584Ssimokawa hlen = sizeof(struct ip6_frag); 1179103285Sikob nh = ((struct ip6_frag *)cp)->ip6f_nxt; 1180103285Sikob break; 1181113584Ssimokawa case IPPROTO_AH: 1182103285Sikob hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2; 1183170374Ssimokawa nh = ((struct ip6_ext *)cp)->ip6e_nxt; 1184103285Sikob break; 1185103285Sikob default: 1186170374Ssimokawa hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3; 1187103285Sikob nh = ((struct ip6_ext *)cp)->ip6e_nxt; 1188170374Ssimokawa break; 1189103285Sikob } 1190170374Ssimokawa 1191170374Ssimokawa cp += hlen; 1192103285Sikob } 1193103285Sikob 1194113584Ssimokawa return(NULL); 1195114729Ssimokawa} 1196170374Ssimokawa 1197114729Ssimokawavoid 1198114729Ssimokawaprint(mhdr, cc) 1199114729Ssimokawa struct msghdr *mhdr; 1200114729Ssimokawa int cc; 1201114729Ssimokawa{ 1202114729Ssimokawa struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; 1203103285Sikob char hbuf[NI_MAXHOST]; 1204103285Sikob 1205170374Ssimokawa if (getnameinfo((struct sockaddr *)from, from->sin6_len, 1206113584Ssimokawa hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST | niflag) != 0) 1207113584Ssimokawa strcpy(hbuf, "invalid"); 1208113584Ssimokawa if (nflag) 1209113584Ssimokawa Printf(" %s", hbuf); 1210113584Ssimokawa else if (lflag) 1211113584Ssimokawa Printf(" %s (%s)", inetname((struct sockaddr *)from), hbuf); 1212120660Ssimokawa else 1213113584Ssimokawa Printf(" %s", inetname((struct sockaddr *)from)); 1214120660Ssimokawa 1215127468Ssimokawa if (verbose) { 1216120660Ssimokawa#ifdef OLDRAWSOCKET 1217120660Ssimokawa Printf(" %d bytes to %s", cc, 1218113584Ssimokawa rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1219120660Ssimokawa hbuf, sizeof(hbuf)) 1220120660Ssimokawa : "?"); 1221103285Sikob#else 1222120660Ssimokawa Printf(" %d bytes of data to %s", cc, 1223120660Ssimokawa rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, 1224103285Sikob hbuf, sizeof(hbuf)) 1225110269Ssimokawa : "?"); 1226103285Sikob#endif 1227103285Sikob } 1228120660Ssimokawa} 1229120660Ssimokawa 1230120660Ssimokawa/* 1231120660Ssimokawa * Subtract 2 timeval structs: out = out - in. 1232127468Ssimokawa * Out is assumed to be >= in. 1233120660Ssimokawa */ 1234120660Ssimokawavoid 1235120660Ssimokawatvsub(out, in) 1236120660Ssimokawa register struct timeval *out, *in; 1237120660Ssimokawa{ 1238120660Ssimokawa if ((out->tv_usec -= in->tv_usec) < 0) { 1239120660Ssimokawa out->tv_sec--; 1240110072Ssimokawa out->tv_usec += 1000000; 1241103285Sikob } 1242103285Sikob out->tv_sec -= in->tv_sec; 1243170374Ssimokawa} 1244170374Ssimokawa 1245103285Sikob 1246103285Sikob/* 1247103285Sikob * Construct an Internet address representation. 1248103285Sikob * If the nflag has been supplied, give 1249103285Sikob * numeric value, otherwise try for symbolic name. 1250103285Sikob */ 1251103285Sikobconst char * 1252103285Sikobinetname(sa) 1253103285Sikob struct sockaddr *sa; 1254103285Sikob{ 1255103285Sikob register char *cp; 1256103285Sikob static char line[NI_MAXHOST]; 1257103285Sikob static char domain[MAXHOSTNAMELEN + 1]; 1258103285Sikob static int first = 1; 1259103285Sikob 1260120660Ssimokawa if (first && !nflag) { 1261113584Ssimokawa first = 0; 1262113584Ssimokawa if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 1263103285Sikob (cp = index(domain, '.'))) 1264167632Ssimokawa (void) strcpy(domain, cp + 1); 1265103285Sikob else 1266120660Ssimokawa domain[0] = 0; 1267103285Sikob } 1268103285Sikob cp = NULL; 1269113584Ssimokawa if (!nflag) { 1270103285Sikob if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, 1271113584Ssimokawa NI_NAMEREQD) == 0) { 1272103285Sikob if ((cp = index(line, '.')) && 1273103285Sikob !strcmp(cp + 1, domain)) 1274103285Sikob *cp = 0; 1275103285Sikob cp = line; 1276107653Ssimokawa } 1277188722Ssbruno } 1278188722Ssbruno if (cp) 1279103285Sikob return cp; 1280103285Sikob 1281103285Sikob if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, 1282103285Sikob NI_NUMERICHOST | niflag) != 0) 1283103285Sikob strcpy(line, "invalid"); 1284103285Sikob return line; 1285103285Sikob} 1286129585Sdfr 1287103285Sikobvoid 1288103285Sikobusage() 1289103285Sikob{ 1290188726Ssbruno (void)fprintf(stderr, 1291188726Ssbruno"usage: traceroute6 [-dlnrv] [-f first_hop] [-m max_hops] [-p port#] \n" 1292188726Ssbruno" [-q nqueries] [-s src_addr] [-g gateway] [-w wait] host [data size]\n"); 1293188726Ssbruno exit(1); 1294188726Ssbruno} 1295188726Ssbruno