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