sync with latest libipsec and kernel.

This commit is contained in:
itojun 2000-01-31 14:24:23 +00:00
parent 6b2922d06b
commit 62e82d7e0c
3 changed files with 432 additions and 154 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ping.c,v 1.54 2000/01/20 01:04:41 mycroft Exp $ */
/* $NetBSD: ping.c,v 1.55 2000/01/31 14:24:23 itojun Exp $ */
/*
* Copyright (c) 1989, 1993
@ -62,7 +62,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: ping.c,v 1.54 2000/01/20 01:04:41 mycroft Exp $");
__RCSID("$NetBSD: ping.c,v 1.55 2000/01/31 14:24:23 itojun Exp $");
#endif
#include <stdio.h>
@ -255,7 +255,8 @@ main(int argc, char *argv[])
#endif
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
char *policy = NULL;
char *policy_in = NULL;
char *policy_out = NULL;
#endif
#endif
@ -377,7 +378,12 @@ main(int argc, char *argv[])
#ifdef IPSEC_POLICY_IPSEC
case 'E':
pingflags |= F_POLICY;
policy = strdup(optarg);
if (!strncmp("in", optarg, 2))
policy_in = strdup(optarg);
else if (!strncmp("out", optarg, 3))
policy_out = strdup(optarg);
else
errx(1, "invalid security policy");
break;
#else
case 'A':
@ -536,26 +542,34 @@ main(int argc, char *argv[])
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
{
int len;
char *buf;
if (pingflags & F_POLICY) {
if ((len = ipsec_get_policylen(policy)) < 0)
errx(1, ipsec_strerror());
if ((buf = malloc(len)) == NULL)
err(1, "malloc");
if ((len = ipsec_set_policy(buf, len, policy)) < 0)
errx(1, ipsec_strerror());
if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, buf, len) < 0)
err(1, "ipsec policy cannot be configured");
free(buf);
if (policy_in != NULL) {
buf = ipsec_set_policy(policy_in, strlen(policy_in));
if (buf == NULL)
errx(1, ipsec_strerror());
if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
buf, ipsec_get_policylen(buf)) < 0) {
err(1, "ipsec policy cannot be configured");
}
free(buf);
}
if (policy_out != NULL) {
buf = ipsec_set_policy(policy_out, strlen(policy_out));
if (buf == NULL)
errx(1, ipsec_strerror());
if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
buf, ipsec_get_policylen(buf)) < 0) {
err(1, "ipsec policy cannot be configured");
}
free(buf);
}
}
if ((len = ipsec_get_policylen("bypass")) < 0)
buf = ipsec_set_policy("out bypass", strlen("out bypass"));
if (buf == NULL)
errx(1, ipsec_strerror());
if ((buf = malloc(len)) == NULL)
err(1, "malloc");
if ((len = ipsec_set_policy(buf, len, "bypass")) < 0)
errx(1, ipsec_strerror());
if (setsockopt(sloop, IPPROTO_IP, IP_IPSEC_POLICY, buf, len) < 0) {
if (setsockopt(sloop, IPPROTO_IP, IP_IPSEC_POLICY,
buf, ipsec_get_policylen(buf)) < 0) {
#if 0
warnx("ipsec is not configured");
#else

View File

@ -25,8 +25,8 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $NetBSD: ping6.8,v 1.4 1999/12/15 05:02:39 itojun Exp $
.\" KAME Id: ping6.8,v 1.7 1999/12/15 04:59:13 itojun Exp
.\" $NetBSD: ping6.8,v 1.5 2000/01/31 14:24:24 itojun Exp $
.\" KAME Id: ping6.8,v 1.11 1999/12/23 17:39:45 itojun Exp
.\"
.Dd May 17, 1998
.Dt PING6 8
@ -39,9 +39,9 @@ packets to network hosts
.Sh SYNOPSIS
.Nm
.\" without ipsec, or new ipsec
.Op Fl dfnqRrvw
.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
@ -54,6 +54,7 @@ packets to network hosts
.Op Fl P Ar policy
.Op Fl S Ar sourceaddr
.Op Fl s Ar packetsize
.Op Ar hops...
.Ar host
.Sh DESCRIPTION
.Nm
@ -175,31 +176,19 @@ 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
Make the kernel believe that the target
.Ar host
.Po
e.g., after the interface was dropped by
.Xr routed 8
.Pc .
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
@ -238,6 +227,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

View File

@ -1,4 +1,4 @@
/* $NetBSD: ping6.c,v 1.10 2000/01/22 10:01:41 tron Exp $ */
/* $NetBSD: ping6.c,v 1.11 2000/01/31 14:24:25 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -80,7 +80,7 @@ static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93";
#else
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: ping6.c,v 1.10 2000/01/22 10:01:41 tron Exp $");
__RCSID("$NetBSD: ping6.c,v 1.11 2000/01/31 14:24:25 itojun Exp $");
#endif
#endif
@ -102,7 +102,7 @@ __RCSID("$NetBSD: ping6.c,v 1.10 2000/01/22 10:01:41 tron Exp $");
/*
* 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)
*/
@ -176,6 +176,9 @@ __RCSID("$NetBSD: ping6.c,v 1.10 2000/01/22 10:01:41 tron Exp $");
#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)
@ -233,6 +236,7 @@ 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));
@ -242,9 +246,13 @@ 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 *));
int setpolicy __P((int, char *));
void usage __P((void));
int
@ -266,8 +274,12 @@ 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 = NULL;
char *policy_in = NULL;
char *policy_out = NULL;
#endif
/* just to be sure */
@ -277,12 +289,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:qS: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:qS: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:qS:s:vwWAE")) != EOF)
#endif /*IPSEC_POLICY_IPSEC*/
#endif
switch(ch) {
@ -364,6 +376,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);
@ -378,9 +394,11 @@ main(argc, argv)
case 'q':
options |= F_QUIET;
break;
#ifdef IPV6_REACHCONF
case 'R':
options |= F_RROUTE;
options |= F_REACHCONF;
break;
#endif
case 'S':
/* XXX: use getaddrinfo? */
if (inet_pton(AF_INET6, optarg, (void *)&srcaddr) != 1)
@ -408,7 +426,12 @@ main(argc, argv)
#ifdef IPSEC_POLICY_IPSEC
case 'P':
options |= F_POLICY;
policy = strdup(optarg);
if (!strncmp("in", optarg, 2))
policy_in = strdup(optarg);
else if (!strncmp("out", optarg, 3))
policy_out = strdup(optarg);
else
errx(1, "invalid security policy");
break;
#else
case 'A':
@ -428,8 +451,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];
@ -470,9 +498,8 @@ main(argc, argv)
ident = getpid() & 0xFFFF;
if ((s = socket(res->ai_family, res->ai_socktype,
res->ai_protocol)) < 0)
err(1, "socket");
if ((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0)
err(1, "socket");
hold = 1;
@ -488,17 +515,10 @@ main(argc, argv)
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
if (options & F_POLICY) {
int len;
char *buf;
if ((len = ipsec_get_policylen(policy)) < 0)
if (setpolicy(s, policy_in) < 0)
errx(1, ipsec_strerror());
if ((buf = malloc(len)) == NULL)
err(1, "malloc");
if ((len = ipsec_set_policy(buf, len, policy)) < 0)
if (setpolicy(s, policy_out) < 0)
errx(1, ipsec_strerror());
if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf, len) < 0)
warnx("Unable to set IPSec policy");
free(buf);
}
#else
if (options & F_AUTHHDR) {
@ -540,6 +560,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 +606,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 +614,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 +659,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 +700,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 +734,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,9 +799,25 @@ 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)));
@ -715,7 +844,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 +885,7 @@ main(argc, argv)
* onalrm --
* This routine transmits another ping6.
*/
/* ARGSUSED */
void
onalrm(signo)
int signo;
@ -879,9 +1009,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,57 +1017,6 @@ 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,
@ -949,12 +1026,15 @@ pr_pack(buf, cc, mhdr)
}
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 +1073,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,10 +1176,145 @@ 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, (void *)in6->s6_addr,
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 */
@ -1137,6 +1362,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 +1399,7 @@ tvsub(out, in)
* oninfo --
* SIGINFO handler.
*/
/* ARGSUSED */
void
oninfo(notused)
int notused;
@ -1168,6 +1411,7 @@ oninfo(notused)
* onint --
* SIGINT handler.
*/
/* ARGSUSED */
void
onint(notused)
int notused;
@ -1268,6 +1512,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 +1550,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);
}
}
@ -1527,11 +1772,36 @@ fill(bp, patp)
}
}
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
int
setpolicy(so, policy)
int so;
char *policy;
{
char *buf;
if (policy == NULL)
return 0; /* ignore */
buf = ipsec_set_policy(policy, strlen(policy));
if (buf == NULL)
errx(1, ipsec_strerror());
if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY,
buf, ipsec_get_policylen(buf)) < 0)
warnx("Unable to set IPSec policy");
free(buf);
return 0;
}
#endif
#endif
void
usage()
{
(void)fprintf(stderr,
"usage: ping6 [-dfnqRrvwW"
"usage: ping6 [-dfnqvwW"
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
"] [-P policy"
@ -1541,6 +1811,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);
}