summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2000-02-16 05:59:21 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2000-02-16 05:59:21 +0000
commit25f5c880785d1675aa8341d93da42f1b434febee (patch)
tree91f80ad5d0d2ea08761dd26c6a7904c4cf413679
parentc440f13861867629f9802ee49df9d77652faf4df (diff)
sync with more recent kame. uses getnameinfo(3) as much as possible.
-rw-r--r--sbin/ping6/ping6.863
-rw-r--r--sbin/ping6/ping6.c464
2 files changed, 383 insertions, 144 deletions
diff --git a/sbin/ping6/ping6.8 b/sbin/ping6/ping6.8
index cffebf82d7a..167b885fe24 100644
--- a/sbin/ping6/ping6.8
+++ b/sbin/ping6/ping6.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ping6.8,v 1.3 1999/12/15 05:05:58 itojun Exp $
+.\" $OpenBSD: ping6.8,v 1.4 2000/02/16 05:59:20 itojun Exp $
.\"
.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
.\" All rights reserved.
@@ -27,7 +27,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" KAME Id: ping6.8,v 1.7 1999/12/15 04:59:13 itojun Exp
+.\" KAME Id: ping6.8,v 1.11 1999/12/23 17:39:45 itojun Exp
.\"
.Dd May 17, 1998
.Dt PING6 8
@@ -40,9 +40,10 @@ packets to network hosts
.Sh SYNOPSIS
.Nm
.\" without ipsec, or new ipsec
-.Op Fl dfnqRrvw
+.Op Fl dfnqvw
+.\".Op Fl dfnqRvw
.\" old ipsec
-.\" .Op Fl AdEfnqRrvw
+.\" .Op Fl AdEfnqRvw
.Op Fl a Ar addrtype
.Op Fl b Ar bufsiz
.Op Fl c Ar count
@@ -52,9 +53,10 @@ packets to network hosts
.Op Fl l Ar preload
.Op Fl p Ar pattern
.\" new ipsec
-.\" .Op Fl P Ar policy
+.Op Fl P Ar policy
.Op Fl S Ar sourceaddr
.Op Fl s Ar packetsize
+.Op Ar hops...
.Ar host
.Sh DESCRIPTION
.Nm
@@ -168,39 +170,27 @@ flag,
prints out any ICMP error messages caused by its own ECHO_REQUEST
messages.
.\" new ipsec
-.\" .It Fl P Ar policy
-.\" .Ar policy
-.\" specifies IPsec policy to be used for the probe.
+.\".It Fl P Ar policy
+.\".Ar policy
+.\"specifies IPsec policy to be used for the probe.
.It Fl q
Quiet output.
Nothing is displayed except the summary lines at startup time and
when finished.
-.It Fl R
-Record route.
-Includes the
-.Tn RECORD_ROUTE
-option in the
-.Tn ECHO_REQUEST
-packet and displays
-the route buffer on returned packets.
-Note that the IP header is only large enough for nine such routes;
-the
-.Xr traceroute 8
-command is usually better at determining the route packets take to a
-particular destination.
-Many hosts ignore or discard the
-.Tn RECORD_ROUTE
-option.
-.It Fl r
-Bypass the normal routing tables and send directly to a host on an attached
-network.
-If the host is not on a directly-attached network, an error is returned.
-This option can be used to ping a local host through an interface
-that has no route through it
-.Po
-e.g., after the interface was dropped by
-.Xr routed 8
-.Pc .
+.\".It Fl R
+.\"Make the kernel believe that the target
+.\".Ar host
+.\".Po
+.\"or the first
+.\".Ar hop
+.\"if you specify
+.\".Ar hops
+.\".Pc
+.\"is reachable, by injecting upper-layer reachability confirmation hint.
+.\"The option is meaningful only if the target
+.\".Ar host
+.\".Pq or the first hop
+.\"is a neighbor.
.It Fl S Ar sourceaddr
Specifies the source address of request packets.
The source address must be one of the unicast addresses of the sending
@@ -239,6 +229,11 @@ This option was remained for backward compatibility.
has no effect if
.Fl w
is specified.
+.It Ar hops
+IPv6 addresses for intermediate nodes,
+which will be put into type 0 routing header.
+.It Ar host
+IPv6 adddress of the final destination node.
.El
.Pp
When using
diff --git a/sbin/ping6/ping6.c b/sbin/ping6/ping6.c
index 5f26066c92e..a8072b51923 100644
--- a/sbin/ping6/ping6.c
+++ b/sbin/ping6/ping6.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ping6.c,v 1.2 2000/01/22 20:25:05 deraadt Exp $ */
+/* $OpenBSD: ping6.c,v 1.3 2000/02/16 05:59:20 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -95,7 +95,7 @@ static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93";
/*
* NOTE:
* USE_SIN6_SCOPE_ID assumes that sin6_scope_id has the same semantics
- * as IPV6_PKTINFO. Some objects it (sin6_scope_id specifies *link* while
+ * as IPV6_PKTINFO. Some people object it (sin6_scope_id specifies *link* while
* IPV6_PKTINFO specifies *interface*. Link is defined as collection of
* network attached to 1 or more interfaces)
*/
@@ -169,6 +169,9 @@ static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93";
#define F_FQDN 0x1000
#define F_INTERFACE 0x2000
#define F_SRCADDR 0x4000
+#ifdef IPV6_REACHCONF
+#define F_REACHCONF 0x8000
+#endif
u_int options;
#define IN6LEN sizeof(struct in6_addr)
@@ -212,9 +215,6 @@ double tmin = 999999999.0; /* minimum round trip time */
double tmax = 0.0; /* maximum round trip time */
double tsum = 0.0; /* sum of all times, for doing average */
-/* for inet_ntop() */
-char ntop_buf[INET6_ADDRSTRLEN];
-
/* for node addresses */
u_short naflags;
@@ -226,15 +226,19 @@ char *scmsg = 0;
int main __P((int, char *[]));
void fill __P((char *, char *));
int get_hoplim __P((struct msghdr *));
+struct in6_pktinfo *get_rcvpktinfo __P((struct msghdr *));
void onalrm __P((int));
void oninfo __P((int));
void onint __P((int));
void pinger __P((void));
-char *pr_addr __P((struct sockaddr_in6 *));
+const char *pr_addr __P((struct sockaddr_in6 *));
void pr_icmph __P((struct icmp6_hdr *, u_char *));
void pr_iph __P((struct ip6_hdr *));
void pr_nodeaddr __P((struct icmp6_nodeinfo *, int));
void pr_pack __P((u_char *, int, struct msghdr *));
+void pr_exthdrs __P((struct msghdr *));
+void pr_ip6opt __P((void *));
+void pr_rthdr __P((void *));
void pr_retip __P((struct ip6_hdr *, u_char *));
void summary __P((void));
void tvsub __P((struct timeval *, struct timeval *));
@@ -246,6 +250,10 @@ main(argc, argv)
int argc;
char *argv[];
{
+#if defined(__FreeBSD__) && __FreeBSD__ < 3
+ extern int optind;
+ extern char *optarg;
+#endif
struct itimerval itimer;
struct sockaddr_in6 from;
struct timeval timeout;
@@ -260,6 +268,9 @@ main(argc, argv)
int sockbufsize = 0;
int usepktinfo = 0;
struct in6_pktinfo *pktinfo = NULL;
+#ifdef USE_RFC2292BIS
+ struct ip6_rthdr *rthdr = NULL;
+#endif
#ifdef IPSEC_POLICY_IPSEC
char *policy_in = NULL;
char *policy_out = NULL;
@@ -272,12 +283,12 @@ main(argc, argv)
preload = 0;
datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN];
#ifndef IPSEC
- while ((ch = getopt(argc, argv, "a:b:c:dfh:I:i:l:np:qRrS:s:vwW")) != EOF)
+ while ((ch = getopt(argc, argv, "a:b:c:dfh:I:i:l:np:qRS:s:vwW")) != EOF)
#else
#ifdef IPSEC_POLICY_IPSEC
- while ((ch = getopt(argc, argv, "a:b:c:dfh:I:i:l:np:qRrS:s:vwWP:")) != EOF)
+ while ((ch = getopt(argc, argv, "a:b:c:dfh:I:i:l:np:qRS:s:vwWP:")) != EOF)
#else
- while ((ch = getopt(argc, argv, "a:b:c:dfh:I:i:l:np:qRrS:s:vwWAE")) != EOF)
+ while ((ch = getopt(argc, argv, "a:b:c:dfh:I:i:l:np:qRS:s:vwWAE")) != EOF)
#endif /*IPSEC_POLICY_IPSEC*/
#endif
switch(ch) {
@@ -359,6 +370,10 @@ main(argc, argv)
options |= F_INTERVAL;
break;
case 'l':
+ if (getuid()) {
+ errno = EPERM;
+ errx(1, "Must be superuser to preload");
+ }
preload = strtol(optarg, &e, 10);
if (preload < 0 || *optarg == '\0' || *e != '\0')
errx(1, "illegal preload value -- %s", optarg);
@@ -374,8 +389,12 @@ main(argc, argv)
options |= F_QUIET;
break;
case 'R':
- options |= F_RROUTE;
+#ifdef IPV6_REACHCONF
+ options |= F_REACHCONF;
break;
+#else
+ errx(1, "-R is not supported in this configuration");
+#endif
case 'S':
/* XXX: use getaddrinfo? */
if (inet_pton(AF_INET6, optarg, (void *)&srcaddr) != 1)
@@ -428,8 +447,13 @@ main(argc, argv)
if (argc < 1)
usage();
- if (argc > 1)
+ if (argc > 1) {
+#ifdef USE_SIN6_SCOPE_ID
+ ip6optlen += CMSG_SPACE(inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1));
+#else /* old advanced API */
ip6optlen += inet6_rthdr_space(IPV6_RTHDR_TYPE_0, argc - 1);
+#endif
+ }
target = argv[argc - 1];
@@ -438,12 +462,8 @@ main(argc, argv)
if ((options & F_NUMERIC) == 0)
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_INET6;
-#ifdef NRL_GETADDRINFO
- hints.ai_socktype = SOCK_DGRAM;
-#else
hints.ai_socktype = SOCK_RAW;
hints.ai_protocol = IPPROTO_ICMPV6;
-#endif
ret_ga = getaddrinfo(target, NULL, &hints, &res);
if (ret_ga) {
@@ -458,10 +478,6 @@ main(argc, argv)
if (!res->ai_addr)
errx(1, "getaddrinfo failed");
-#ifdef NRL_GETADDRINFO
- res->ai_socktype = SOCK_RAW;
- res->ai_protocol = IPPROTO_ICMPV6;
-#endif
(void)memcpy(&dst, res->ai_addr, res->ai_addrlen);
if (options & F_FLOOD && options & F_INTERVAL)
@@ -540,6 +556,45 @@ main(argc, argv)
}
#endif /*ICMP6_FILTER*/
+ /* let the kerel pass extension headers of incoming packets */
+ /* TODO: implement parsing routine */
+ if ((options & F_VERBOSE) != 0) {
+ int opton = 1;
+
+#ifdef IPV6_RECVRTHDR
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_RECVRTHDR)");
+#else /* old adv. API */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RTHDR, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_RTHDR)");
+#endif
+#ifdef IPV6_RECVHOPOPTS
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_RECVHOPOPTS)");
+#else /* old adv. API */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPOPTS, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_HOPOPTS)");
+#endif
+#ifdef IPV6_RECVDSTOPTS
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_RECVDSTOPTS)");
+#else /* olad adv. API */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_DSTOPTS, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_DSTOPTS)");
+#endif
+#ifdef IPV6_RECVRTHDRDSTOPTS
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_RECVRTHDRDSTOPTS)");
+#endif
+ }
+
/*
optval = 1;
if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr))
@@ -547,9 +602,6 @@ main(argc, argv)
&optval, sizeof(optval)) == -1)
err(1, "IPV6_MULTICAST_LOOP");
*/
- /* record route option */
- if (options & F_RROUTE)
- errx(1, "record route not available in this implementation");
/* Specify the outgoing interface and/or the source address */
if (usepktinfo)
@@ -558,6 +610,11 @@ main(argc, argv)
if (hoplimit != -1)
ip6optlen += CMSG_SPACE(sizeof(int));
+#ifdef IPV6_REACHCONF
+ if (options & F_REACHCONF)
+ ip6optlen += CMSG_SPACE(0);
+#endif
+
/* set IP6 packet options */
if (ip6optlen) {
if ((scmsg = (char *)malloc(ip6optlen)) == 0)
@@ -598,12 +655,37 @@ main(argc, argv)
scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
}
+#ifdef IPV6_REACHCONF
+ if (options & F_REACHCONF) {
+ scmsgp->cmsg_len = CMSG_LEN(0);
+ scmsgp->cmsg_level = IPPROTO_IPV6;
+ scmsgp->cmsg_type = IPV6_REACHCONF;
+
+ scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ }
+#endif
+
if (argc > 1) { /* some intermediate addrs are specified */
int hops, error;
-
+#ifdef USE_RFC2292BIS
+ int rthdrlen;
+#endif
+
+#ifdef USE_RFC2292BIS
+ rthdrlen = inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1);
+ scmsgp->cmsg_len = CMSG_LEN(rthdrlen);
+ scmsgp->cmsg_level = IPPROTO_IPV6;
+ scmsgp->cmsg_type = IPV6_RTHDR;
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(scmsgp);
+ rthdr = inet6_rth_init((void *)rthdr, rthdrlen,
+ IPV6_RTHDR_TYPE_0, argc - 1);
+ if (rthdr == NULL)
+ errx(1, "can't initialize rthdr");
+#else /* old advanced API */
if ((scmsgp = (struct cmsghdr *)inet6_rthdr_init(scmsgp,
IPV6_RTHDR_TYPE_0)) == 0)
errx(1, "can't initialize rthdr");
+#endif /* USE_RFC2292BIS */
for (hops = 0; hops < argc - 1; hops++) {
struct addrinfo *iaip;
@@ -614,14 +696,22 @@ main(argc, argv)
errx(1,
"bad addr family of an intermediate addr");
+#ifdef USE_RFC2292BIS
+ if (inet6_rth_add(rthdr,
+ &(SIN6(iaip->ai_addr))->sin6_addr))
+ errx(1, "can't add an intermediate node");
+#else /* old advanced API */
if (inet6_rthdr_add(scmsgp,
&(SIN6(iaip->ai_addr))->sin6_addr,
IPV6_RTHDR_LOOSE))
errx(1, "can't add an intermediate node");
+#endif /* USE_RFC2292BIS */
}
+#ifndef USE_RFC2292BIS
if (inet6_rthdr_lasthop(scmsgp, IPV6_RTHDR_LOOSE))
errx(1, "can't set the last flag");
+#endif
scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
}
@@ -640,15 +730,34 @@ main(argc, argv)
src.sin6_port = ntohs(DUMMY_PORT);
src.sin6_scope_id = dst.sin6_scope_id;
-#ifndef USE_SIN6_SCOPE_ID
- if (setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTOPTIONS,
+
+#ifdef USE_SIN6_SCOPE_ID
+ src.sin6_scope_id = dst.sin6_scope_id;
+#endif
+
+#ifdef USE_RFC2292BIS
+ if (pktinfo &&
+ setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTINFO,
+ (void *)pktinfo, sizeof(*pktinfo)))
+ err(1, "UDP setsockopt(IPV6_PKTINFO)");
+
+ if (hoplimit != -1 &&
+ setsockopt(dummy, IPPROTO_IPV6, IPV6_HOPLIMIT,
+ (void *)&hoplimit, sizeof(hoplimit)))
+ err(1, "UDP setsockopt(IPV6_HOPLIMIT)");
+
+ if (rthdr &&
+ setsockopt(dummy, IPPROTO_IPV6, IPV6_RTHDR,
+ (void *)rthdr, (rthdr->ip6r_len + 1) << 3))
+ err(1, "UDP setsockopt(IPV6_RTHDR)");
+#else /* old advanced API */
+ if (smsghdr.msg_control &&
+ setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTOPTIONS,
(void *)smsghdr.msg_control,
smsghdr.msg_controllen)) {
err(1, "UDP setsockopt(IPV6_PKTOPTIONS)");
}
-#else
- src.sin6_scope_id = dst.sin6_scope_id;
-#endif
+#endif
if (connect(dummy, (struct sockaddr *)&src, len) < 0)
err(1, "UDP connect");
@@ -686,13 +795,29 @@ main(argc, argv)
optval = 1;
#ifndef USE_SIN6_SCOPE_ID
- setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &optval, sizeof(optval));
-#endif
- setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval, sizeof(optval));
+#ifdef IPV6_RECVPKTINFO
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval,
+ sizeof(optval)) < 0)
+ warn("setsockopt(IPV6_RECVPKTINFO)"); /* XXX err? */
+#else /* old adv. API */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &optval,
+ sizeof(optval)) < 0)
+ warn("setsockopt(IPV6_PKTINFO)"); /* XXX err? */
+#endif
+#endif /* USE_SIN6_SCOPE_ID */
+#ifdef IPV6_RECVHOPLIMIT
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval,
+ sizeof(optval)) < 0)
+ warn("setsockopt(IPV6_RECVHOPLIMIT)"); /* XXX err? */
+#else /* old adv. API */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval,
+ sizeof(optval)) < 0)
+ warn("setsockopt(IPV6_HOPLIMIT)"); /* XXX err? */
+#endif
printf("PING6(%d=40+8+%d bytes) ", datalen + 48, datalen);
- printf("%s --> ", inet_ntop(AF_INET6, &src.sin6_addr, ntop_buf, sizeof(ntop_buf)));
- printf("%s\n", inet_ntop(AF_INET6, &dst.sin6_addr, ntop_buf, sizeof(ntop_buf)));
+ printf("%s --> ", pr_addr(&src));
+ printf("%s\n", pr_addr(&dst));
while (preload--) /* Fire off them quickies. */
pinger();
@@ -715,7 +840,7 @@ main(argc, argv)
for (;;) {
struct msghdr m;
struct cmsghdr *cm;
- u_char buf[256];
+ u_char buf[1024];
struct iovec iov[2];
if (options & F_FLOOD) {
@@ -756,6 +881,7 @@ main(argc, argv)
* onalrm --
* This routine transmits another ping6.
*/
+/* ARGSUSED */
void
onalrm(signo)
int signo;
@@ -879,9 +1005,7 @@ pr_pack(buf, cc, mhdr)
int hoplim;
struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
u_char *cp = NULL, *dp, *end = buf + cc;
-#ifdef OLD_RAWSOCKET
- struct ip6_hdr *ip;
-#endif
+ struct in6_pktinfo *pktinfo = NULL;
struct timeval tv, *tp;
double triptime = 0;
int dupflag;
@@ -889,72 +1013,23 @@ pr_pack(buf, cc, mhdr)
(void)gettimeofday(&tv, NULL);
-#ifdef OLD_RAWSOCKET
- /* Check the IP header */
- ip = (struct ip6_hdr *)buf;
- if (cc < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
- if (options & F_VERBOSE)
- warnx("packet too short (%d bytes) from %s\n", cc,
- inet_ntop(AF_INET6, (void *)&from->sin6_addr,
- ntop_buf, sizeof(ntop_buf)));
- return;
- }
-
- /* chase nexthdr link */
- {
- u_int8_t nh;
- struct ah *ah;
- struct ip6_ext *ip6e;
-
- off = IP6LEN;
- nh = ip->ip6_nxt;
- while (nh != IPPROTO_ICMPV6) {
- if (options & F_VERBOSE)
- fprintf(stderr, "header chain: type=0x%x\n", nh);
-
- switch (nh) {
-#ifdef IPSEC
- case IPPROTO_AH:
- ah = (struct ah *)(buf + off);
- off += sizeof(struct ah);
- off += (ah->ah_len << 2);
- nh = ah->ah_nxt;
- break;
-#endif
-
- case IPPROTO_HOPOPTS:
- ip6e = (struct ip6_ext *)(buf + off);
- off += (ip6e->ip6e_len + 1) << 3;
- nh = ip6e->ip6e_nxt;
- break;
- default:
- if (options & F_VERBOSE) {
- fprintf(stderr,
- "unknown header type=0x%x: drop it\n",
- nh);
- }
- return;
- }
- }
- }
- /* Now the ICMP part */
- icp = (struct icmp6_hdr *)(buf + off);
-#else
if (cc < sizeof(struct icmp6_hdr)) {
if (options & F_VERBOSE)
warnx("packet too short (%d bytes) from %s\n", cc,
- inet_ntop(AF_INET6, (void *)&from->sin6_addr,
- ntop_buf, sizeof(ntop_buf)));
+ pr_addr(from));
return;
}
icp = (struct icmp6_hdr *)buf;
off = 0;
-#endif
if ((hoplim = get_hoplim(mhdr)) == -1) {
warnx("failed to get receiving hop limit");
return;
}
+ if ((pktinfo = get_rcvpktinfo(mhdr)) == NULL) {
+ warnx("failed to get receiving pakcet information");
+ return;
+ }
if (icp->icmp6_type == ICMP6_ECHO_REPLY) {
/* XXX the following line overwrites the original packet */
@@ -993,6 +1068,16 @@ pr_pack(buf, cc, mhdr)
pr_addr(from),
icp->icmp6_seq);
(void)printf(" hlim=%d", hoplim);
+ if ((options & F_VERBOSE) != 0) {
+ struct sockaddr_in6 dstsa;
+
+ memset(&dstsa, 0, sizeof(dstsa));
+ dstsa.sin6_family = AF_INET6;
+ dstsa.sin6_len = sizeof(dstsa);
+ dstsa.sin6_scope_id = pktinfo->ipi6_ifindex;
+ dstsa.sin6_addr = pktinfo->ipi6_addr;
+ (void)printf(" dst=%s", pr_addr(&dstsa));
+ }
if (timing)
(void)printf(" time=%g ms", triptime);
if (dupflag)
@@ -1086,16 +1171,152 @@ pr_pack(buf, cc, mhdr)
if (!(options & F_FLOOD)) {
(void)putchar('\n');
+ if (options & F_VERBOSE)
+ pr_exthdrs(mhdr);
(void)fflush(stdout);
}
}
void
+pr_exthdrs(mhdr)
+ struct msghdr *mhdr;
+{
+ struct cmsghdr *cm;
+
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_level != IPPROTO_IPV6)
+ continue;
+
+ switch(cm->cmsg_type) {
+ case IPV6_HOPOPTS:
+ printf(" HbH Options: ");
+ pr_ip6opt(CMSG_DATA(cm));
+ break;
+ case IPV6_DSTOPTS:
+#ifdef IPV6_RTHDRDSTOPTS
+ case IPV6_RTHDRDSTOPTS:
+#endif
+ printf(" Dst Options: ");
+ pr_ip6opt(CMSG_DATA(cm));
+ break;
+ case IPV6_RTHDR:
+ printf(" Routing: ");
+ pr_rthdr(CMSG_DATA(cm));
+ break;
+ }
+ }
+}
+
+#ifdef USE_RFC2292BIS
+void
+pr_ip6opt(void *extbuf)
+{
+ struct ip6_hbh *ext;
+ int currentlen;
+ u_int8_t type;
+ size_t extlen, len;
+ void *databuf;
+ size_t offset;
+ u_int16_t value2;
+ u_int32_t value4;
+
+ ext = (struct ip6_hbh *)extbuf;
+ extlen = (ext->ip6h_len + 1) * 8;
+ printf("nxt %u, len %u (%d bytes)\n", ext->ip6h_nxt,
+ ext->ip6h_len, extlen);
+
+ currentlen = 0;
+ while (1) {
+ currentlen = inet6_opt_next(extbuf, extlen, currentlen,
+ &type, &len, &databuf);
+ if (currentlen == -1)
+ break;
+ switch (type) {
+ /*
+ * Note that inet6_opt_next automatically skips any padding
+ * optins.
+ */
+ case IP6OPT_JUMBO:
+ offset = 0;
+ offset = inet6_opt_get_val(databuf, offset,
+ &value4, sizeof(value4));
+ printf(" Jumbo Payload Opt: Length %u\n",
+ (unsigned int)ntohl(value4));
+ break;
+ case IP6OPT_ROUTER_ALERT:
+ offset = 0;
+ offset = inet6_opt_get_val(databuf, offset,
+ &value2, sizeof(value2));
+ printf(" Router Alert Opt: Type %u\n",
+ ntohs(value2));
+ break;
+ default:
+ printf(" Received Opt %u len %u\n", type, len);
+ break;
+ }
+ }
+ return;
+}
+#else /* !USE_RFC2292BIS */
+/* ARGSUSED */
+void
+pr_ip6opt(void *extbuf)
+{
+ putchar('\n');
+ return;
+}
+#endif /* USE_RFC2292BIS */
+
+#ifdef USE_RFC2292BIS
+void
+pr_rthdr(void *extbuf)
+{
+ struct in6_addr *in6;
+ char ntopbuf[INET6_ADDRSTRLEN];
+ struct ip6_rthdr *rh = (struct ip6_rthdr *)extbuf;
+ int i, segments;
+
+ /* print fixed part of the header */
+ printf("nxt %u, len %u (%d bytes), type %u, ", rh->ip6r_nxt,
+ rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type);
+ if ((segments = inet6_rth_segments(extbuf)) >= 0)
+ printf("%d segments, ", segments);
+ else
+ printf("segments unknown, ");
+ printf("%d left\n", rh->ip6r_segleft);
+
+ for (i = 0; i < segments; i++) {
+ in6 = inet6_rth_getaddr(extbuf, i);
+ if (in6 == NULL)
+ printf(" [%d]<NULL>\n", i);
+ else
+ printf(" [%d]%s\n", i,
+ inet_ntop(AF_INET6, in6,
+ ntopbuf, sizeof(ntopbuf)));
+ }
+
+ return;
+
+}
+#else /* !USE_RFC2292BIS */
+/* ARGSUSED */
+void
+pr_rthdr(void *extbuf)
+{
+ putchar('\n');
+ return;
+}
+#endif /* USE_RFC2292BIS */
+
+
+void
pr_nodeaddr(ni, nilen)
struct icmp6_nodeinfo *ni; /* ni->qtype must be NODEADDR */
int nilen;
{
struct in6_addr *ia6 = (struct in6_addr *)(ni + 1);
+ char ntop_buf[INET6_ADDRSTRLEN];
nilen -= sizeof(struct icmp6_nodeinfo);
@@ -1137,6 +1358,23 @@ get_hoplim(mhdr)
return(-1);
}
+struct in6_pktinfo *
+get_rcvpktinfo(mhdr)
+ struct msghdr *mhdr;
+{
+ struct cmsghdr *cm;
+
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_PKTINFO &&
+ cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo)))
+ return((struct in6_pktinfo *)CMSG_DATA(cm));
+ }
+
+ return(NULL);
+}
+
/*
* tvsub --
* Subtract 2 timeval structs: out = out - in. Out is assumed to
@@ -1157,6 +1395,7 @@ tvsub(out, in)
* oninfo --
* SIGINFO handler.
*/
+/* ARGSUSED */
void
oninfo(notused)
int notused;
@@ -1168,6 +1407,7 @@ oninfo(notused)
* onint --
* SIGINT handler.
*/
+/* ARGSUSED */
void
onint(notused)
int notused;
@@ -1238,6 +1478,8 @@ pr_icmph(icp, end)
struct icmp6_hdr *icp;
u_char *end;
{
+ char ntop_buf[INET6_ADDRSTRLEN];
+
switch(icp->icmp6_type) {
case ICMP6_DST_UNREACH:
switch(icp->icmp6_code) {
@@ -1268,6 +1510,7 @@ pr_icmph(icp, end)
case ICMP6_PACKET_TOO_BIG:
(void)printf("Packet too big mtu = %d\n",
(int)ntohl(icp->icmp6_mtu));
+ pr_retip((struct ip6_hdr *)(icp + 1), end);
break;
case ICMP6_TIME_EXCEEDED:
switch(icp->icmp6_code) {
@@ -1305,57 +1548,57 @@ pr_icmph(icp, end)
pr_retip((struct ip6_hdr *)(icp + 1), end);
break;
case ICMP6_ECHO_REQUEST:
- (void)printf("Echo Request\n");
+ (void)printf("Echo Request");
/* XXX ID + Seq + Data */
break;
case ICMP6_ECHO_REPLY:
- (void)printf("Echo Reply\n");
+ (void)printf("Echo Reply");
/* XXX ID + Seq + Data */
break;
case ICMP6_MEMBERSHIP_QUERY:
- (void)printf("Membership Query\n");
+ (void)printf("Listener Query");
break;
case ICMP6_MEMBERSHIP_REPORT:
- (void)printf("Membership Report\n");
+ (void)printf("Listener Report");
break;
case ICMP6_MEMBERSHIP_REDUCTION:
- (void)printf("Membership Reduction\n");
+ (void)printf("Listener Done");
break;
case ND_ROUTER_SOLICIT:
- (void)printf("Router Solicitation\n");
+ (void)printf("Router Solicitation");
break;
case ND_ROUTER_ADVERT:
- (void)printf("Router Advertisement\n");
+ (void)printf("Router Advertisement");
break;
case ND_NEIGHBOR_SOLICIT:
- (void)printf("Neighbor Solicitation\n");
+ (void)printf("Neighbor Solicitation");
break;
case ND_NEIGHBOR_ADVERT:
- (void)printf("Neighbor Advertisement\n");
+ (void)printf("Neighbor Advertisement");
break;
case ND_REDIRECT:
{
struct nd_redirect *red = (struct nd_redirect *)icp;
(void)printf("Redirect\n");
- (void)printf("Destination: %s\n",
+ (void)printf("Destination: %s",
inet_ntop(AF_INET6, &red->nd_rd_dst,
ntop_buf, sizeof(ntop_buf)));
- (void)printf("New Target: %s\n",
+ (void)printf("New Target: %s",
inet_ntop(AF_INET6, &red->nd_rd_target,
ntop_buf, sizeof(ntop_buf)));
break;
}
case ICMP6_NI_QUERY:
- (void)printf("Node Information Query\n");
+ (void)printf("Node Information Query");
/* XXX ID + Seq + Data */
break;
case ICMP6_NI_REPLY:
- (void)printf("Node Information Reply\n");
+ (void)printf("Node Information Reply");
/* XXX ID + Seq + Data */
break;
default:
- (void)printf("Bad ICMP type: %d\n", icp->icmp6_type);
+ (void)printf("Bad ICMP type: %d", icp->icmp6_type);
}
}
@@ -1369,6 +1612,7 @@ pr_iph(ip6)
{
u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK;
u_int8_t tc;
+ char ntop_buf[INET6_ADDRSTRLEN];
tc = *(&ip6->ip6_vfc + 1); /* XXX */
tc = (tc >> 4) & 0x0f;
@@ -1380,9 +1624,9 @@ pr_iph(ip6)
ntohs(ip6->ip6_plen),
ip6->ip6_nxt, ip6->ip6_hlim);
printf("%s->", inet_ntop(AF_INET6, &ip6->ip6_src,
- ntop_buf, INET6_ADDRSTRLEN));
+ ntop_buf, sizeof(ntop_buf)));
printf("%s\n", inet_ntop(AF_INET6, &ip6->ip6_dst,
- ntop_buf, INET6_ADDRSTRLEN));
+ ntop_buf, sizeof(ntop_buf)));
}
/*
@@ -1390,7 +1634,7 @@ pr_iph(ip6)
* Return an ascii host address as a dotted quad and optionally with
* a hostname.
*/
-char *
+const char *
pr_addr(addr)
struct sockaddr_in6 *addr;
{
@@ -1556,7 +1800,7 @@ void
usage()
{
(void)fprintf(stderr,
-"usage: ping6 [-dfnqRrvwW"
+"usage: ping6 [-dfnqvwW"
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
"] [-P policy"
@@ -1566,6 +1810,6 @@ usage()
#endif
"] [-a [alsg]] [-b sockbufsiz] [-c count] [-I interface]\n\
[-i wait] [-l preload] [-p pattern] [-S sourceaddr]\n\
- [-s packetsize] [-h hoplimit] host [hosts...]\n");
+ [-s packetsize] [-h hoplimit] [hops...] host\n");
exit(1);
}