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