From 62e82d7e0ce266ff2b5571568bd2e3cd7f859942 Mon Sep 17 00:00:00 2001 From: itojun Date: Mon, 31 Jan 2000 14:24:23 +0000 Subject: [PATCH] sync with latest libipsec and kernel. --- sbin/ping/ping.c | 54 +++-- sbin/ping6/ping6.8 | 50 +++-- sbin/ping6/ping6.c | 482 +++++++++++++++++++++++++++++++++++---------- 3 files changed, 432 insertions(+), 154 deletions(-) diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c index 52cb61de2e5c..8e929cbb2a74 100644 --- a/sbin/ping/ping.c +++ b/sbin/ping/ping.c @@ -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 #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 @@ -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 diff --git a/sbin/ping6/ping6.8 b/sbin/ping6/ping6.8 index 13e4925a18c9..5703be3e4241 100644 --- a/sbin/ping6/ping6.8 +++ b/sbin/ping6/ping6.8 @@ -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 diff --git a/sbin/ping6/ping6.c b/sbin/ping6/ping6.c index 309a9ab5797d..c6cc76b45821 100644 --- a/sbin/ping6/ping6.c +++ b/sbin/ping6/ping6.c @@ -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 #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]\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); }