diff options
author | ume <ume@FreeBSD.org> | 2001-06-11 12:39:29 +0000 |
---|---|---|
committer | ume <ume@FreeBSD.org> | 2001-06-11 12:39:29 +0000 |
commit | 832f8d224926758a9ae0b23a6b45353e44fbc87a (patch) | |
tree | a79fc7ad2b97862c4a404f352f0211ad93a7b5f1 /sbin | |
parent | 2693854b01a52b0395a91322aa3edf926bddff38 (diff) | |
download | FreeBSD-src-832f8d224926758a9ae0b23a6b45353e44fbc87a.zip FreeBSD-src-832f8d224926758a9ae0b23a6b45353e44fbc87a.tar.gz |
Sync with recent KAME.
This work was based on kame-20010528-freebsd43-snap.tgz and some
critical problem after the snap was out were fixed.
There are many many changes since last KAME merge.
TODO:
- The definitions of SADB_* in sys/net/pfkeyv2.h are still different
from RFC2407/IANA assignment because of binary compatibility
issue. It should be fixed under 5-CURRENT.
- ip6po_m member of struct ip6_pktopts is no longer used. But, it
is still there because of binary compatibility issue. It should
be removed under 5-CURRENT.
Reviewed by: itojun
Obtained from: KAME
MFC after: 3 weeks
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/ifconfig/ifconfig.8 | 13 | ||||
-rw-r--r-- | sbin/ifconfig/ifconfig.c | 231 | ||||
-rw-r--r-- | sbin/ping6/ping6.8 | 65 | ||||
-rw-r--r-- | sbin/ping6/ping6.c | 1601 | ||||
-rw-r--r-- | sbin/route/route.c | 234 | ||||
-rw-r--r-- | sbin/rtsol/Makefile | 4 | ||||
-rw-r--r-- | sbin/setkey/parse.y | 85 | ||||
-rw-r--r-- | sbin/setkey/scriptdump.pl | 4 | ||||
-rw-r--r-- | sbin/setkey/setkey.8 | 161 | ||||
-rw-r--r-- | sbin/setkey/setkey.c | 78 | ||||
-rw-r--r-- | sbin/setkey/token.l | 36 |
11 files changed, 1833 insertions, 679 deletions
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 index 176af6a..e4ef0f4 100644 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -256,6 +256,19 @@ list of available options. .It Fl mediaopt Ar opts If the driver supports the media selection system, disable the specified media options on the interface. +.It Cm tunnel Ar src_addr Ar dest_addr +(IP tunnel devices only) +Configure the physical source and destination address for IP tunnel +interfaces (gif). The arguments +.Ar src_addr +and +.Ar dest_addr +are interpreted as the outer source/destination for the encapsulating +IPv4/IPv6 header. +.It Cm deletetunnel +Unconfigure the physical source and destination address for IP tunnel +interfaces previously configured with +.Cm tunnel . .It Cm vlan Ar vlan_tag If the interface is a vlan pseudo interface, set the vlan tag value to diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c index f865af24..72c0f16 100644 --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -149,35 +149,43 @@ void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); void status __P((const struct afswtch *afp, int addrcount, struct sockaddr_dl *sdl, struct if_msghdr *ifm, struct ifa_msghdr *ifam)); +void tunnel_status __P((int s)); void usage __P((void)); void ifmaybeload __P((char *name)); #ifdef INET6 +void in6_fillscopeid __P((struct sockaddr_in6 *sin6)); int prefix __P((void *, int)); static char *sec2str __P((time_t)); int explicit_prefix = 0; #endif typedef void c_func __P((const char *cmd, int arg, int s, const struct afswtch *afp)); +typedef void c_func2 __P((const char *arg, const char *arg2, int s, const struct afswtch *afp)); c_func setatphase, setatrange; c_func setifaddr, setifbroadaddr, setifdstaddr, setifnetmask; +c_func2 settunnel; +c_func deletetunnel; #ifdef INET6 c_func setifprefixlen; c_func setip6flags; -c_func setip6vltime; c_func setip6pltime; +c_func setip6vltime; +c_func2 setip6lifetime; #endif c_func setifipdst; c_func setifflags, setifmetric, setifmtu, setiflladdr; #define NEXTARG 0xffffff +#define NEXTARG2 0xfffffe const struct cmd { const char *c_name; int c_parameter; /* NEXTARG means next argv */ void (*c_func) __P((const char *, int, int, const struct afswtch *afp)); + void (*c_func2) __P((const char *, const char *, int, const struct afswtch *afp)); } cmds[] = { { "up", IFF_UP, setifflags } , { "down", -IFF_UP, setifflags }, @@ -201,14 +209,20 @@ struct cmd { { "anycast", IN6_IFF_ANYCAST, setip6flags }, { "tentative", IN6_IFF_TENTATIVE, setip6flags }, { "-tentative", -IN6_IFF_TENTATIVE, setip6flags }, - { "vltime", NEXTARG, setip6vltime }, + { "deprecated", IN6_IFF_DEPRECATED, setip6flags }, + { "-deprecated", -IN6_IFF_DEPRECATED, setip6flags }, + { "autoconf", IN6_IFF_AUTOCONF, setip6flags }, + { "-autoconf", -IN6_IFF_AUTOCONF, setip6flags }, { "pltime", NEXTARG, setip6pltime }, + { "vltime", NEXTARG, setip6vltime }, #endif { "range", NEXTARG, setatrange }, { "phase", NEXTARG, setatphase }, { "metric", NEXTARG, setifmetric }, { "broadcast", NEXTARG, setifbroadaddr }, { "ipdst", NEXTARG, setifipdst }, + { "tunnel", NEXTARG2, NULL, settunnel }, + { "deletetunnel", 0, deletetunnel }, { "link0", IFF_LINK0, setifflags }, { "-link0", -IFF_LINK0, setifflags }, { "link1", IFF_LINK1, setifflags }, @@ -600,13 +614,19 @@ ifconfig(argc, argv, afp) break; if (p->c_name == 0 && setaddr) p++; /* got src, do dst */ - if (p->c_func) { + if (p->c_func || p->c_func2) { if (p->c_parameter == NEXTARG) { if (argv[1] == NULL) errx(1, "'%s' requires argument", p->c_name); (*p->c_func)(argv[1], 0, s, afp); argc--, argv++; + } else if (p->c_parameter == NEXTARG2) { + if (argc < 3) + errx(1, "'%s' requires 2 arguments", + p->c_name); + (*p->c_func2)(argv[1], argv[2], s, afp); + argc -= 2, argv += 2; } else (*p->c_func)(*argv, p->c_parameter, s, afp); } @@ -704,6 +724,82 @@ setifaddr(addr, param, s, afp) } void +settunnel(src, dst, s, afp) + const char *src, *dst; + int s; + const struct afswtch *afp; +{ + struct addrinfo hints, *srcres, *dstres; + struct ifaliasreq addreq; + int ecode; +#ifdef INET6 + struct in6_aliasreq in6_addreq; +#endif + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = afp->af_af; + + if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0) + errx(1, "error in parsing address string: %s", + gai_strerror(ecode)); + + if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0) + errx(1, "error in parsing address string: %s", + gai_strerror(ecode)); + + if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family) + errx(1, + "source and destination address families do not match"); + + switch (srcres->ai_addr->sa_family) { + case AF_INET: + memset(&addreq, 0, sizeof(addreq)); + strncpy(addreq.ifra_name, name, IFNAMSIZ); + memcpy(&addreq.ifra_addr, srcres->ai_addr, + srcres->ai_addr->sa_len); + memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, + dstres->ai_addr->sa_len); + + if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0) + warn("SIOCSIFPHYADDR"); + break; + +#ifdef INET6 + case AF_INET6: + memset(&in6_addreq, 0, sizeof(in6_addreq)); + strncpy(in6_addreq.ifra_name, name, IFNAMSIZ); + memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, + srcres->ai_addr->sa_len); + memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr, + dstres->ai_addr->sa_len); + + if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0) + warn("SIOCSIFPHYADDR_IN6"); + break; +#endif /* INET6 */ + + default: + warn("address family not supported"); + } + + freeaddrinfo(srcres); + freeaddrinfo(dstres); +} + +/* ARGSUSED */ +void +deletetunnel(vname, param, s, afp) + const char *vname; + int param; + int s; + const struct afswtch *afp; +{ + + if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0) + err(1, "SIOCDIFPHYADDR"); +} + +void setifnetmask(addr, dummy, s, afp) const char *addr; int dummy __unused; @@ -745,23 +841,48 @@ setip6flags(dummyaddr, flag, dummysoc, afp) } void -setip6vltime(seconds, dummy, s, afp) +setip6pltime(seconds, dummy, s, afp) const char *seconds; int dummy __unused; int s; const struct afswtch *afp; { - in6_addreq.ifra_lifetime.ia6t_vltime = atoi(seconds); + setip6lifetime("pltime", seconds, s, afp); } void -setip6pltime(seconds, dummy, s, afp) +setip6vltime(seconds, dummy, s, afp) const char *seconds; int dummy __unused; int s; const struct afswtch *afp; { - in6_addreq.ifra_lifetime.ia6t_pltime = atoi(seconds); + setip6lifetime("vltime", seconds, s, afp); +} + +void +setip6lifetime(cmd, val, s, afp) + const char *cmd; + const char *val; + int s; + const struct afswtch *afp; +{ + time_t newval, t; + char *ep; + + t = time(NULL); + newval = (time_t)strtoul(val, &ep, 0); + if (val == ep) + errx(1, "invalid %s", cmd); + if (afp->af_af != AF_INET6) + errx(1, "%s not allowed for the AF", cmd); + if (strcmp(cmd, "vltime") == 0) { + in6_addreq.ifra_lifetime.ia6t_expire = t + newval; + in6_addreq.ifra_lifetime.ia6t_vltime = newval; + } else if (strcmp(cmd, "pltime") == 0) { + in6_addreq.ifra_lifetime.ia6t_preferred = t + newval; + in6_addreq.ifra_lifetime.ia6t_pltime = newval; + } } #endif @@ -964,6 +1085,8 @@ status(afp, addrcount, sdl, ifm, ifam) printf(" mtu %d", mtu); putchar('\n'); + tunnel_status(s); + while (addrcount > 0) { info.rti_addrs = ifam->ifam_addrs; @@ -1015,6 +1138,73 @@ status(afp, addrcount, sdl, ifm, ifam) } void +tunnel_status(s) + int s; +{ + char psrcaddr[NI_MAXHOST]; + char pdstaddr[NI_MAXHOST]; + u_long srccmd, dstcmd; + struct ifreq *ifrp; + const char *ver = ""; +#ifdef NI_WITHSCOPEID + const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; +#else + const int niflag = NI_NUMERICHOST; +#endif +#ifdef INET6 + struct in6_ifreq in6_ifr; + int s6; +#endif /* INET6 */ + + psrcaddr[0] = pdstaddr[0] = '\0'; + +#ifdef INET6 + memset(&in6_ifr, 0, sizeof(in6_ifr)); + strncpy(in6_ifr.ifr_name, name, IFNAMSIZ); + s6 = socket(AF_INET6, SOCK_DGRAM, 0); + if (s6 < 0) { + srccmd = SIOCGIFPSRCADDR; + dstcmd = SIOCGIFPDSTADDR; + ifrp = 𝔦 + } else { + close(s6); + srccmd = SIOCGIFPSRCADDR_IN6; + dstcmd = SIOCGIFPDSTADDR_IN6; + ifrp = (struct ifreq *)&in6_ifr; + } +#else /* INET6 */ + srccmd = SIOCGIFPSRCADDR; + dstcmd = SIOCGIFPDSTADDR; + ifrp = 𝔦 +#endif /* INET6 */ + + if (ioctl(s, srccmd, (caddr_t)ifrp) < 0) + return; +#ifdef INET6 + if (ifrp->ifr_addr.sa_family == AF_INET6) + in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr); +#endif + getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, + psrcaddr, sizeof(psrcaddr), 0, 0, niflag); +#ifdef INET6 + if (ifrp->ifr_addr.sa_family == AF_INET6) + ver = "6"; +#endif + + if (ioctl(s, dstcmd, (caddr_t)ifrp) < 0) + return; +#ifdef INET6 + if (ifrp->ifr_addr.sa_family == AF_INET6) + in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr); +#endif + getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, + pdstaddr, sizeof(pdstaddr), 0, 0, niflag); + + printf("\ttunnel inet%s %s --> %s\n", ver, + psrcaddr, pdstaddr); +} + +void in_status(s, info) int s __unused; struct rt_addrinfo * info; @@ -1050,6 +1240,19 @@ in_status(s, info) #ifdef INET6 void +in6_fillscopeid(sin6) + struct sockaddr_in6 *sin6; +{ +#if defined(__KAME__) && defined(KAME_SCOPEID) + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + sin6->sin6_scope_id = + ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); + sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; + } +#endif +} + +void in6_status(s, info) int s __unused; struct rt_addrinfo * info; @@ -1146,16 +1349,20 @@ in6_status(s, info) printf("prefixlen %d ", prefix(&sin->sin6_addr, sizeof(struct in6_addr))); - if (flags6 & IN6_IFF_ANYCAST) + if ((flags6 & IN6_IFF_ANYCAST) != 0) printf("anycast "); - if (flags6 & IN6_IFF_TENTATIVE) + if ((flags6 & IN6_IFF_TENTATIVE) != 0) printf("tentative "); - if (flags6 & IN6_IFF_DUPLICATED) + if ((flags6 & IN6_IFF_DUPLICATED) != 0) printf("duplicated "); - if (flags6 & IN6_IFF_DETACHED) + if ((flags6 & IN6_IFF_DETACHED) != 0) printf("detached "); - if (flags6 & IN6_IFF_DEPRECATED) + if ((flags6 & IN6_IFF_DEPRECATED) != 0) printf("deprecated "); + if ((flags6 & IN6_IFF_AUTOCONF) != 0) + printf("autoconf "); + if ((flags6 & IN6_IFF_TEMPORARY) != 0) + printf("temporary "); if (scopeid) printf("scopeid 0x%x ", scopeid); diff --git a/sbin/ping6/ping6.8 b/sbin/ping6/ping6.8 index 6f8855d..eb3251c 100644 --- a/sbin/ping6/ping6.8 +++ b/sbin/ping6/ping6.8 @@ -1,4 +1,4 @@ -.\" $KAME: ping6.8,v 1.22 2000/05/31 17:00:07 itojun Exp $ +.\" $KAME: ping6.8,v 1.39 2001/04/04 00:08:34 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -40,9 +40,9 @@ packets to network hosts .Sh SYNOPSIS .Nm .\" without ipsec, or new ipsec -.Op Fl dfHnNqRvw +.Op Fl dfHnNqRtvw .\" old ipsec -.\" .Op Fl AdEfnNqRvw +.\" .Op Fl AdEfnNqRtvw .Bk -words .Op Fl a Ar addrtype .Ek @@ -184,13 +184,13 @@ option. If .Ar preload is specified, -.Nm ping +.Nm sends that many packets as fast as possible before falling into its normal mode of behavior. Only the super-user may use this option. .It Fl n Numeric output only. -No attempt will be made to lookup symbolic names for host addresses. +No attempt will be made to lookup symbolic names from addresses in the reply. .It Fl N Probe node information multicast group .Pq Li ff02::2:xxxx:xxxx . @@ -213,11 +213,6 @@ For example, .Dq Li \-p ff will cause the sent packet to be filled with all ones. -.Fl Q -flag, -.Nm -prints out any ICMP error messages caused by its own ECHO_REQUEST -messages. .\" new ipsec .It Fl P Ar policy .Ar policy @@ -259,6 +254,13 @@ header data. You may need to specify .Fl b as well to extend socket buffer size. +.It Fl t +Generate ICMPv6 Node Information supported query types query, +rather than echo-request. +.Fl s +has no effect if +.Fl t +is specified. .It Fl v Verbose output. .Tn ICMP @@ -266,7 +268,7 @@ packets other than .Tn ECHO_RESPONSE that are received are listed. .It Fl w -Generate ICMPv6 Node Information FQDN query, rather than echo-request. +Generate ICMPv6 Node Information DNS Name query, rather than echo-request. .Fl s has no effect if .Fl w @@ -335,7 +337,7 @@ during normal operations or from automated scripts. .\" If less than eight bytes of pad are specified, no round trip times are .\" given. .Sh DUPLICATE AND DAMAGED PACKETS -.Nm Ping6 +.Nm will report duplicate and damaged packets. Duplicate packets should never occur when pinging a unicast address, and seem to be caused by @@ -350,7 +352,7 @@ to the same request. .Pp Damaged packets are obviously serious cause for alarm and often indicate broken hardware somewhere in the -.Nm ping +.Nm packet's path .Pq in the network or in the hosts . .Sh TRYING DIFFERENT DATA PATTERNS @@ -386,8 +388,39 @@ option of .Nm returns 0 on success (the host is alive), and non-zero if the arguments are incorrect or the host is not responding. +.Sh EXAMPLES +Normally, +.Xr ping6 8 +works just like +.Xr ping 8 +would work; the following will send ICMPv6 echo request to +.Li dst.foo.com . +.Bd -literal -offset indent +ping6 -n dst.foo.com +.Ed +.Pp +The following will probe hostnames for all nodes on the network link attached to +.Li wi0 +interface. +The address +.Li ff02::1 +is named the link-local all-node multicast address, and the packet would +reach every node on the network link. +.Bd -literal -offset indent +ping6 -w ff02::1%wi0 +.Ed +.Pp +The following will probe addresses assigned to the destination node, +.Li dst.foo.com . +.Bd -literal -offset indent +ping6 -a agl dst.foo.com +.Ed +.Pp .Sh SEE ALSO .Xr netstat 1 , +.Xr icmp6 4 , +.Xr inet6 4 , +.Xr ip6 4 , .Xr ifconfig 8 , .Xr ping 8 , .Xr routed 8 , @@ -403,8 +436,8 @@ and non-zero if the arguments are incorrect or the host is not responding. .Rs .%A Matt Crawford .%T "IPv6 Node Information Queries" -.%N draft-ietf-ipngwg-icmp-name-lookups-05.txt -.%D October 22, 1999 +.%N draft-ietf-ipngwg-icmp-name-lookups-07.txt +.%D August 2000 .%O work in progress material .Re .Sh BUGS @@ -438,7 +471,7 @@ option (or something like those) to specify the particular address family. This essentially means that we have two different commands. .Sh HISTORY The -.Nm ping +.Xr ping 8 command appeared in .Bx 4.3 . The diff --git a/sbin/ping6/ping6.c b/sbin/ping6/ping6.c index 3d529b6..e7079a3 100644 --- a/sbin/ping6/ping6.c +++ b/sbin/ping6/ping6.c @@ -1,4 +1,4 @@ -/* $KAME: ping6.c,v 1.54 2000/06/12 16:16:44 itojun Exp $ */ +/* $KAME: ping6.c,v 1.126 2001/05/17 03:39:08 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -99,8 +99,8 @@ static const char rcsid[] = /* * NOTE: * USE_SIN6_SCOPE_ID assumes that sin6_scope_id has the same semantics - * as IPV6_PKTINFO. Some people object it (sin6_scope_id specifies *link* while - * IPV6_PKTINFO specifies *interface*. Link is defined as collection of + * 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) */ @@ -116,12 +116,16 @@ static const char rcsid[] = #include <netinet/ip6.h> #include <netinet/icmp6.h> #include <arpa/inet.h> +#include <arpa/nameser.h> #include <netdb.h> #include <ctype.h> #include <err.h> #include <errno.h> #include <fcntl.h> +#if defined(__OpenBSD__) || defined(__NetBSD__) +#include <math.h> +#endif #include <signal.h> #include <stdio.h> #include <stdlib.h> @@ -144,7 +148,8 @@ static const char rcsid[] = #define ICMP6ECHOLEN 8 /* icmp echo header len excluding time */ #define ICMP6ECHOTMLEN sizeof(struct timeval) #define ICMP6_NIQLEN (ICMP6ECHOLEN + 8) -#define ICMP6_NIRLEN (ICMP6ECHOLEN + 12) /* 64 bits of nonce + 32 bits ttl */ +/* FQDN case, 64 bits of nonce + 32 bits ttl */ +#define ICMP6_NIRLEN (ICMP6ECHOLEN + 12) #define EXTRA 256 /* for AH and various other headers. weird. */ #define DEFDATALEN ICMP6ECHOTMLEN #define MAXDATALEN MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN @@ -158,7 +163,6 @@ static const char rcsid[] = #define F_FLOOD 0x0001 #define F_INTERVAL 0x0002 -#define F_NUMERIC 0x0004 #define F_PINGFILLED 0x0008 #define F_QUIET 0x0010 #define F_RROUTE 0x0020 @@ -182,13 +186,16 @@ static const char rcsid[] = #define F_HOSTNAME 0x10000 #define F_FQDNOLD 0x20000 #define F_NIGROUP 0x40000 +#define F_SUPTYPES 0x80000 +#define F_NOMINMTU 0x100000 +#define F_NOUSERDATA (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES) u_int options; #define IN6LEN sizeof(struct in6_addr) #define SA6LEN sizeof(struct sockaddr_in6) -#define DUMMY_PORT 10101 +#define DUMMY_PORT 10101 -#define SIN6(s) ((struct sockaddr_in6 *)(s)) +#define SIN6(s) ((struct sockaddr_in6 *)(s)) /* * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum @@ -199,9 +206,9 @@ u_int options; int mx_dup_ck = MAX_DUP_CHK; char rcvd_tbl[MAX_DUP_CHK / 8]; -struct addrinfo *res; -struct sockaddr_in6 dst; /* who to ping6 */ -struct sockaddr_in6 src; /* src addr of this packet */ +struct addrinfo *res; +struct sockaddr_in6 dst; /* who to ping6 */ +struct sockaddr_in6 src; /* src addr of this packet */ int datalen = DEFDATALEN; int s; /* socket file descriptor */ u_char outpack[MAXPACKETLEN]; @@ -209,21 +216,26 @@ char BSPACE = '\b'; /* characters written for flood */ char DOT = '.'; char *hostname; int ident; /* process id to identify our packets */ +u_int8_t nonce[8]; /* nonce field for node information */ struct in6_addr srcaddr; +int hoplimit = -1; /* hoplimit */ +int pathmtu = 0; /* path MTU for the destination. 0 = unspec. */ /* counters */ long npackets; /* max packets to transmit */ long nreceived; /* # of packets we got back */ long nrepeats; /* number of duplicates */ long ntransmitted; /* sequence # for outbound packets = #sent */ -int interval = 1; /* interval between packets */ -int hoplimit = -1; /* hoplimit */ +struct timeval interval = {1, 0}; /* interval between packets */ /* timing */ int timing; /* flag to do timing */ 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 */ +#if defined(__OpenBSD__) || defined(__NetBSD__) +double tsumsq = 0.0; /* sum of all times squared, for std. dev. */ +#endif /* for node addresses */ u_short naflags; @@ -233,22 +245,38 @@ struct msghdr smsghdr; struct iovec smsgiov; char *scmsg = 0; +volatile int signo; +volatile sig_atomic_t seenalrm; +volatile sig_atomic_t seenint; +#ifdef SIGINFO +volatile sig_atomic_t seeninfo; +#endif + int main __P((int, char *[])); void fill __P((char *, char *)); int get_hoplim __P((struct msghdr *)); +int get_pathmtu __P((struct msghdr *)); +void set_pathmtu __P((int)); struct in6_pktinfo *get_rcvpktinfo __P((struct msghdr *)); -void onalrm __P((int)); -void oninfo __P((int)); +void onsignal __P((int)); +void retransmit __P((void)); void onint __P((int)); +size_t pingerlen __P((void)); void pinger __P((void)); -const char *pr_addr __P((struct sockaddr_in6 *)); +const char *pr_addr __P((struct sockaddr *, int)); void pr_icmph __P((struct icmp6_hdr *, u_char *)); void pr_iph __P((struct ip6_hdr *)); +void pr_suptypes __P((struct icmp6_nodeinfo *, size_t)); void pr_nodeaddr __P((struct icmp6_nodeinfo *, int)); +int myechoreply __P((const struct icmp6_hdr *)); +int mynireply __P((const struct icmp6_nodeinfo *)); +char *dnsdecode __P((const u_char **, const u_char *, const u_char *, + u_char *, size_t)); 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 *)); +int pr_bitrange __P((u_int32_t, int, int)); void pr_retip __P((struct ip6_hdr *, u_char *)); void summary __P((void)); void tvsub __P((struct timeval *, struct timeval *)); @@ -263,7 +291,7 @@ main(argc, argv) { struct itimerval itimer; struct sockaddr_in6 from; - struct timeval timeout; + struct timeval timeout, *tv; struct addrinfo hints; fd_set *fdmaskp; int fdmasks; @@ -283,6 +311,8 @@ main(argc, argv) char *policy_in = NULL; char *policy_out = NULL; #endif + double intval; + size_t rthlen; /* just to be sure */ memset(&smsghdr, 0, sizeof(&smsghdr)); @@ -291,54 +321,62 @@ main(argc, argv) preload = 0; datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN]; #ifndef IPSEC - while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:vwW")) != EOF) +#define ADDOPTS #else #ifdef IPSEC_POLICY_IPSEC - while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:vwWP:")) != EOF) +#define ADDOPTS "P:" #else - while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:vwWAE")) != EOF) +#define ADDOPTS "AE" #endif /*IPSEC_POLICY_IPSEC*/ #endif - { - switch(ch) { - case 'a': - { - char *cp; - - options |= F_NODEADDR; - datalen = 2048; /* XXX: enough? */ - for (cp = optarg; *cp != '\0'; cp++) { - switch(*cp) { - case 'a': - naflags |= NI_NODEADDR_FLAG_ALL; - break; - case 'c': - case 'C': - naflags |= NI_NODEADDR_FLAG_COMPAT; - break; - case 'l': - case 'L': - naflags |= NI_NODEADDR_FLAG_LINKLOCAL; - break; - case 's': - case 'S': - naflags |= NI_NODEADDR_FLAG_SITELOCAL; - break; - case 'g': - case 'G': - naflags |= NI_NODEADDR_FLAG_GLOBAL; - break; - case 'A': /* experimental. not in the spec */ - naflags |= NI_NODEADDR_FLAG_ANYCAST; - break; - default: - usage(); - /*NOTREACHED*/ - } - } - break; - } - case 'b': + while ((ch = getopt(argc, argv, + "a:b:c:dfHh:I:i:l:mnNp:qRS:s:tvwW" ADDOPTS)) != -1) { +#undef ADDOPTS + switch (ch) { + case 'a': + { + char *cp; + + options &= ~F_NOUSERDATA; + options |= F_NODEADDR; + for (cp = optarg; *cp != '\0'; cp++) { + switch (*cp) { + case 'a': + naflags |= NI_NODEADDR_FLAG_ALL; + break; + case 'c': + case 'C': + naflags |= NI_NODEADDR_FLAG_COMPAT; + break; + case 'l': + case 'L': + naflags |= NI_NODEADDR_FLAG_LINKLOCAL; + break; + case 's': + case 'S': + naflags |= NI_NODEADDR_FLAG_SITELOCAL; + break; + case 'g': + case 'G': + naflags |= NI_NODEADDR_FLAG_GLOBAL; + break; + case 'A': /* experimental. not in the spec */ +#ifdef NI_NODEADDR_FLAG_ANYCAST + naflags |= NI_NODEADDR_FLAG_ANYCAST; + break; +#else + errx(1, +"-a A is not supported on the platform"); + /*NOTREACHED*/ +#endif + default: + usage(); + /*NOTREACHED*/ + } + } + break; + } + case 'b': #if defined(SO_SNDBUF) && defined(SO_RCVBUF) sockbufsize = atoi(optarg); #else @@ -380,10 +418,23 @@ main(argc, argv) #endif break; case 'i': /* wait between sending packets */ - interval = strtol(optarg, &e, 10); - if (interval <= 0 || *optarg == '\0' || *e != '\0') - errx(1, - "illegal timing interval -- %s", optarg); + intval = strtod(optarg, &e); + if (*optarg == '\0' || *e != '\0') + errx(1, "illegal timing interval %s", optarg); + if (intval < 1 && getuid()) { + errx(1, "%s: only root may use interval < 1s", + strerror(EPERM)); + } + interval.tv_sec = (long)intval; + interval.tv_usec = + (long)((intval - interval.tv_sec) * 1000000); + if (interval.tv_sec < 0) + errx(1, "illegal timing interval %s", optarg); + /* less than 1/hz does not make sense */ + if (interval.tv_sec == 0 && interval.tv_usec < 10000) { + warnx("too small interval, raised to 0.01"); + interval.tv_usec = 10000; + } options |= F_INTERVAL; break; case 'l': @@ -395,8 +446,16 @@ main(argc, argv) if (preload < 0 || *optarg == '\0' || *e != '\0') errx(1, "illegal preload value -- %s", optarg); break; + case 'm': +#ifdef IPV6_USE_MIN_MTU + options |= F_NOMINMTU; + break; +#else + errx(1, "-%c is not supported on this platform", ch); + /*NOTREACHED*/ +#endif case 'n': - options |= F_NUMERIC; + options &= ~F_HOSTNAME; break; case 'N': options |= F_NIGROUP; @@ -426,18 +485,25 @@ main(argc, argv) datalen = strtol(optarg, &e, 10); if (datalen <= 0 || *optarg == '\0' || *e != '\0') errx(1, "illegal datalen value -- %s", optarg); - if (datalen > MAXDATALEN) + if (datalen > MAXDATALEN) { errx(1, "datalen value too large, maximum is %d", MAXDATALEN); + } + break; + case 't': + options &= ~F_NOUSERDATA; + options |= F_SUPTYPES; break; case 'v': options |= F_VERBOSE; break; case 'w': + options &= ~F_NOUSERDATA; options |= F_FQDN; break; case 'W': + options &= ~F_NOUSERDATA; options |= F_FQDNOLD; break; #ifdef IPSEC @@ -476,11 +542,17 @@ main(argc, argv) } 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); +#ifdef IPV6_RECVRTHDR /* 2292bis */ + rthlen = CMSG_SPACE(inet6_rth_space(IPV6_RTHDR_TYPE_0, + argc - 1)); +#else /* RFC2292 */ + rthlen = inet6_rthdr_space(IPV6_RTHDR_TYPE_0, argc - 1); #endif + if (rthlen == 0) { + errx(1, "too many intermediate hops"); + /*NOTREACHED*/ + } + ip6optlen += rthlen; } if (options & F_NIGROUP) { @@ -494,8 +566,7 @@ main(argc, argv) /* getaddrinfo */ bzero(&hints, sizeof(struct addrinfo)); - if ((options & F_NUMERIC) != 0) - hints.ai_flags = AI_CANONNAME; + hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_RAW; hints.ai_protocol = IPPROTO_ICMPV6; @@ -509,28 +580,91 @@ main(argc, argv) hostname = res->ai_canonname; else hostname = target; - + if (!res->ai_addr) errx(1, "getaddrinfo failed"); (void)memcpy(&dst, res->ai_addr, res->ai_addrlen); + if ((s = socket(res->ai_family, res->ai_socktype, + res->ai_protocol)) < 0) + err(1, "socket"); + + /* + * let the kerel pass extension headers of incoming packets, + * for privileged socket options + */ + if ((options & F_VERBOSE) != 0) { + int opton = 1; + +#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 /* old 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 + } + + /* revoke root privilege */ + seteuid(getuid()); + setuid(getuid()); + if (options & F_FLOOD && options & F_INTERVAL) errx(1, "-f and -i incompatible options"); - if (datalen >= sizeof(struct timeval)) /* can we time transfer */ - timing = 1; - packlen = datalen + IP6LEN + ICMP6ECHOLEN + EXTRA; + if ((options & F_NOUSERDATA) == 0) { + if (datalen >= sizeof(struct timeval)) { + /* we can time transfer */ + timing = 1; + } else + timing = 0; + /* in F_VERBOSE case, we may get non-echoreply packets*/ + if (options & F_VERBOSE) + packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA; + else + packlen = datalen + IP6LEN + ICMP6ECHOLEN + EXTRA; + } else { + /* suppress timing for node information query */ + timing = 0; + datalen = 2048; + packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA; + } + if (!(packet = (u_char *)malloc((u_int)packlen))) err(1, "Unable to allocate packet"); if (!(options & F_PINGFILLED)) - for (i = 8; i < datalen; ++i) + for (i = ICMP6ECHOLEN; i < packlen; ++i) *datap++ = i; ident = getpid() & 0xFFFF; - - if ((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) - err(1, "socket"); +#ifndef __OpenBSD__ + gettimeofday(&timeout, NULL); + srand((unsigned int)(timeout.tv_sec ^ timeout.tv_usec ^ (long)ident)); + memset(nonce, 0, sizeof(nonce)); + for (i = 0; i < sizeof(nonce); i += sizeof(int)) + *((int *)&nonce[i]) = rand(); +#else + memset(nonce, 0, sizeof(nonce)); + for (i = 0; i < sizeof(nonce); i += sizeof(u_int32_t)) + *((u_int32_t *)&nonce[i]) = arc4random(); +#endif hold = 1; @@ -540,8 +674,24 @@ main(argc, argv) optval = IPV6_DEFHLIM; if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, - &optval, sizeof(optval)) == -1) + &optval, sizeof(optval)) == -1) err(1, "IPV6_MULTICAST_HOPS"); +#ifdef IPV6_USE_MIN_MTU + if ((options & F_NOMINMTU) == 0) { + optval = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, + &optval, sizeof(optval)) == -1) + err(1, "setsockopt(IPV6_USE_MIN_MTU)"); + } +#ifdef IPV6_RECVPATHMTU + else { + optval = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPATHMTU, + &optval, sizeof(optval)) == -1) + err(1, "setsockopt(IPV6_RECVPATHMTU)"); + } +#endif /* IPV6_RECVPATHMTU */ +#endif /* IPV6_USE_MIN_MTU */ #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC @@ -556,18 +706,18 @@ main(argc, argv) optval = IPSEC_LEVEL_REQUIRE; #ifdef IPV6_AUTH_TRANS_LEVEL if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, - &optval, sizeof(optval)) == -1) + &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_AUTH_TRANS_LEVEL)"); #else /* old def */ if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_LEVEL, - &optval, sizeof(optval)) == -1) + &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_AUTH_LEVEL)"); #endif } if (options & F_ENCRYPT) { optval = IPSEC_LEVEL_REQUIRE; if (setsockopt(s, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, - &optval, sizeof(optval)) == -1) + &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_ESP_TRANS_LEVEL)"); } #endif /*IPSEC_POLICY_IPSEC*/ @@ -579,7 +729,7 @@ main(argc, argv) if (!(options & F_VERBOSE)) { ICMP6_FILTER_SETBLOCKALL(&filt); if ((options & F_FQDN) || (options & F_FQDNOLD) || - (options & F_NODEADDR)) + (options & F_NODEADDR) || (options & F_SUPTYPES)) ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filt); else ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt); @@ -587,55 +737,31 @@ main(argc, argv) ICMP6_FILTER_SETPASSALL(&filt); } if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, - sizeof(filt)) < 0) + sizeof(filt)) < 0) err(1, "setsockopt(ICMP6_FILTER)"); } #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))) + sizeof(opton))) err(1, "setsockopt(IPV6_RECVRTHDR)"); #else /* old adv. API */ if (setsockopt(s, IPPROTO_IPV6, IPV6_RTHDR, &opton, - sizeof(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)) if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, - &optval, sizeof(optval)) == -1) + &optval, sizeof(optval)) == -1) err(1, "IPV6_MULTICAST_LOOP"); */ @@ -673,7 +799,7 @@ main(argc, argv) #ifndef USE_SIN6_SCOPE_ID /* pktinfo must have already been allocated */ if ((pktinfo->ipi6_ifindex = if_nametoindex(ifname)) == 0) - errx(1, "%s: invalid interface name", ifname); + errx(1, "%s: invalid interface name", ifname); #else if ((dst.sin6_scope_id = if_nametoindex(ifname)) == 0) errx(1, "%s: invalid interface name", ifname); @@ -714,34 +840,36 @@ main(argc, argv) 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); + 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) + IPV6_RTHDR_TYPE_0)) == 0) errx(1, "can't initialize rthdr"); #endif /* USE_RFC2292BIS */ for (hops = 0; hops < argc - 1; hops++) { struct addrinfo *iaip; - if ((error = getaddrinfo(argv[hops], NULL, &hints, &iaip))) + if ((error = getaddrinfo(argv[hops], NULL, &hints, + &iaip))) errx(1, "%s", gai_strerror(error)); - if (SIN6(res->ai_addr)->sin6_family != AF_INET6) + if (SIN6(iaip->ai_addr)->sin6_family != AF_INET6) errx(1, - "bad addr family of an intermediate addr"); + "bad addr family of an intermediate addr"); #ifdef USE_RFC2292BIS if (inet6_rth_add(rthdr, - &(SIN6(iaip->ai_addr))->sin6_addr)) + &(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)) + &(SIN6(iaip->ai_addr))->sin6_addr, + IPV6_RTHDR_LOOSE)) errx(1, "can't add an intermediate node"); #endif /* USE_RFC2292BIS */ + freeaddrinfo(iaip); } #ifndef USE_RFC2292BIS @@ -757,7 +885,7 @@ main(argc, argv) * source selection */ int dummy, len = sizeof(src); - + if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) err(1, "UDP socket"); @@ -766,38 +894,31 @@ main(argc, argv) src.sin6_port = ntohs(DUMMY_PORT); src.sin6_scope_id = dst.sin6_scope_id; - -#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))) + (void *)pktinfo, sizeof(*pktinfo))) err(1, "UDP setsockopt(IPV6_PKTINFO)"); if (hoplimit != -1 && setsockopt(dummy, IPPROTO_IPV6, IPV6_HOPLIMIT, - (void *)&hoplimit, sizeof(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)) + (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)) { + (void *)smsghdr.msg_control, smsghdr.msg_controllen)) err(1, "UDP setsockopt(IPV6_PKTOPTIONS)"); - } #endif - + if (connect(dummy, (struct sockaddr *)&src, len) < 0) err(1, "UDP connect"); - + if (getsockname(dummy, (struct sockaddr *)&src, &len) < 0) err(1, "getsockname"); @@ -809,10 +930,10 @@ main(argc, argv) if (datalen > sockbufsize) warnx("you need -b to increase socket buffer size"); if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize, - sizeof(sockbufsize)) < 0) + sizeof(sockbufsize)) < 0) err(1, "setsockopt(SO_SNDBUF)"); if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &sockbufsize, - sizeof(sockbufsize)) < 0) + sizeof(sockbufsize)) < 0) err(1, "setsockopt(SO_RCVBUF)"); } else { @@ -825,7 +946,8 @@ main(argc, argv) * to get some stuff for /etc/ethers. */ hold = 48 * 1024; - setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold)); + setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, + sizeof(hold)); } #endif @@ -833,64 +955,99 @@ main(argc, argv) #ifndef USE_SIN6_SCOPE_ID #ifdef IPV6_RECVPKTINFO if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval, - sizeof(optval)) < 0) + sizeof(optval)) < 0) warn("setsockopt(IPV6_RECVPKTINFO)"); /* XXX err? */ #else /* old adv. API */ if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &optval, - sizeof(optval)) < 0) + 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) + sizeof(optval)) < 0) warn("setsockopt(IPV6_RECVHOPLIMIT)"); /* XXX err? */ #else /* old adv. API */ if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval, - sizeof(optval)) < 0) + sizeof(optval)) < 0) warn("setsockopt(IPV6_HOPLIMIT)"); /* XXX err? */ #endif - printf("PING6(%d=40+8+%d bytes) ", datalen + 48, datalen); - printf("%s --> ", pr_addr(&src)); - printf("%s\n", pr_addr(&dst)); + printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()), + (unsigned long)(pingerlen() - 8)); + printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src))); + printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst))); while (preload--) /* Fire off them quickies. */ pinger(); - (void)signal(SIGINT, onint); - (void)signal(SIGINFO, oninfo); + (void)signal(SIGINT, onsignal); +#ifdef SIGINFO + (void)signal(SIGINFO, onsignal); +#endif if ((options & F_FLOOD) == 0) { - (void)signal(SIGALRM, onalrm); - itimer.it_interval.tv_sec = interval; - itimer.it_interval.tv_usec = 0; - itimer.it_value.tv_sec = 0; - itimer.it_value.tv_usec = 1; + (void)signal(SIGALRM, onsignal); + itimer.it_interval = interval; + itimer.it_value = interval; (void)setitimer(ITIMER_REAL, &itimer, NULL); + retransmit(); } - fdmasks = howmany(s+1, NFDBITS); + fdmasks = howmany(s + 1, NFDBITS) * sizeof(fd_mask); if ((fdmaskp = malloc(fdmasks)) == NULL) err(1, "malloc"); + signo = seenalrm = seenint = 0; +#ifdef SIGINFO + seeninfo = 0; +#endif + for (;;) { struct msghdr m; struct cmsghdr *cm; u_char buf[1024]; struct iovec iov[2]; + /* signal handling */ + if (seenalrm) { + retransmit(); + seenalrm = 0; + continue; + } + if (seenint) { + onint(SIGINT); + seenint = 0; + continue; + } +#ifdef SIGINFO + if (seeninfo) { + summary(); + seeninfo = 0; + continue; + } +#endif + if (options & F_FLOOD) { pinger(); timeout.tv_sec = 0; timeout.tv_usec = 10000; - memset(fdmaskp, 0, fdmasks); - FD_SET(s, fdmaskp); - if (select(s + 1, fdmaskp, NULL, NULL, &timeout) < 1) - continue; - } - fromlen = sizeof(from); + tv = &timeout; + } else + tv = NULL; + memset(fdmaskp, 0, fdmasks); + FD_SET(s, fdmaskp); + cc = select(s + 1, fdmaskp, NULL, NULL, tv); + if (cc < 0) { + if (errno != EINTR) { + warn("select"); + sleep(1); + } + continue; + } else if (cc == 0) + continue; + fromlen = sizeof(from); m.msg_name = (caddr_t)&from; m.msg_namelen = sizeof(from); memset(&iov, 0, sizeof(iov)); @@ -902,14 +1059,35 @@ main(argc, argv) m.msg_control = (caddr_t)buf; m.msg_controllen = sizeof(buf); - if ((cc = recvmsg(s, &m, 0)) < 0) { - if (errno == EINTR) - continue; - warn("recvfrom"); + cc = recvmsg(s, &m, 0); + if (cc < 0) { + if (errno != EINTR) { + warn("recvmsg"); + sleep(1); + } + continue; + } else if (cc == 0) { + int mtu; + + /* + * receive control messages only. Process the + * exceptions (currently the only possiblity is + * a path MTU notification.) + */ + if ((mtu = get_pathmtu(&m)) > 0) { + if ((options & F_VERBOSE) != 0) { + printf("new path MTU (%d) is " + "notified\n", mtu); + } + set_pathmtu(mtu); + } continue; + } else { + /* + * an ICMPv6 message (probably an echoreply) arrived. + */ + pr_pack(packet, cc, &m); } - - pr_pack(packet, cc, &m); if (npackets && nreceived >= npackets) break; } @@ -917,14 +1095,32 @@ main(argc, argv) exit(nreceived == 0); } +void +onsignal(sig) + int sig; +{ + signo = sig; + switch (sig) { + case SIGALRM: + seenalrm++; + break; + case SIGINT: + seenint++; + break; +#ifdef SIGINFO + case SIGINFO: + seeninfo++; + break; +#endif + } +} + /* - * onalrm -- + * retransmit -- * This routine transmits another ping6. */ -/* ARGSUSED */ void -onalrm(signo) - int signo; +retransmit() { struct itimerval itimer; @@ -961,32 +1157,51 @@ onalrm(signo) * of the data portion are used to hold a UNIX "timeval" struct in VAX * byte-order, to compute the round-trip time. */ +size_t +pingerlen() +{ + size_t l; + + if (options & F_FQDN) + l = ICMP6_NIQLEN + sizeof(dst.sin6_addr); + else if (options & F_FQDNOLD) + l = ICMP6_NIQLEN; + else if (options & F_NODEADDR) + l = ICMP6_NIQLEN + sizeof(dst.sin6_addr); + else if (options & F_SUPTYPES) + l = ICMP6_NIQLEN; + else + l = ICMP6ECHOLEN + datalen; + + return l; +} + void pinger() { struct icmp6_hdr *icp; struct iovec iov[2]; int i, cc; + struct icmp6_nodeinfo *nip; + int seq; icp = (struct icmp6_hdr *)outpack; + nip = (struct icmp6_nodeinfo *)outpack; memset(icp, 0, sizeof(*icp)); - icp->icmp6_code = 0; icp->icmp6_cksum = 0; - icp->icmp6_seq = ntransmitted++; /* htons later */ - icp->icmp6_id = htons(ident); /* ID */ - - CLR(icp->icmp6_seq % mx_dup_ck); - icp->icmp6_seq = htons(icp->icmp6_seq); + seq = ntransmitted++; + CLR(seq % mx_dup_ck); if (options & F_FQDN) { icp->icmp6_type = ICMP6_NI_QUERY; icp->icmp6_code = ICMP6_NI_SUBJ_IPV6; - /* XXX: overwrite icmp6_id */ - ((struct icmp6_nodeinfo *)icp)->ni_qtype = htons(NI_QTYPE_FQDN); - ((struct icmp6_nodeinfo *)icp)->ni_flags = htons(0); - if (timing) - (void)gettimeofday((struct timeval *) - &outpack[ICMP6ECHOLEN], NULL); + nip->ni_qtype = htons(NI_QTYPE_FQDN); + nip->ni_flags = htons(0); + + memcpy(nip->icmp6_ni_nonce, nonce, + sizeof(nip->icmp6_ni_nonce)); + *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr, sizeof(dst.sin6_addr)); cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr); @@ -994,39 +1209,58 @@ pinger() } else if (options & F_FQDNOLD) { /* packet format in 03 draft - no Subject data on queries */ icp->icmp6_type = ICMP6_NI_QUERY; - /* code field is always 0 */ - /* XXX: overwrite icmp6_id */ - ((struct icmp6_nodeinfo *)icp)->ni_qtype = htons(NI_QTYPE_FQDN); - ((struct icmp6_nodeinfo *)icp)->ni_flags = htons(0); - if (timing) - (void)gettimeofday((struct timeval *) - &outpack[ICMP6ECHOLEN], NULL); + icp->icmp6_code = 0; /* code field is always 0 */ + nip->ni_qtype = htons(NI_QTYPE_FQDN); + nip->ni_flags = htons(0); + + memcpy(nip->icmp6_ni_nonce, nonce, + sizeof(nip->icmp6_ni_nonce)); + *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + cc = ICMP6_NIQLEN; datalen = 0; } else if (options & F_NODEADDR) { icp->icmp6_type = ICMP6_NI_QUERY; icp->icmp6_code = ICMP6_NI_SUBJ_IPV6; - /* XXX: overwrite icmp6_id */ - ((struct icmp6_nodeinfo *)icp)->ni_qtype = - htons(NI_QTYPE_NODEADDR); - ((struct icmp6_nodeinfo *)icp)->ni_flags = htons(0); - if (timing) - (void)gettimeofday((struct timeval *) - &outpack[ICMP6ECHOLEN], NULL); + nip->ni_qtype = htons(NI_QTYPE_NODEADDR); + nip->ni_flags = naflags; + + memcpy(nip->icmp6_ni_nonce, nonce, + sizeof(nip->icmp6_ni_nonce)); + *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr, sizeof(dst.sin6_addr)); cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr); datalen = 0; - ((struct icmp6_nodeinfo *)icp)->ni_flags = naflags; - } - else { + } else if (options & F_SUPTYPES) { + icp->icmp6_type = ICMP6_NI_QUERY; + icp->icmp6_code = ICMP6_NI_SUBJ_FQDN; /*empty*/ + nip->ni_qtype = htons(NI_QTYPE_SUPTYPES); + /* we support compressed bitmap */ + nip->ni_flags = NI_SUPTYPE_FLAG_COMPRESS; + + memcpy(nip->icmp6_ni_nonce, nonce, + sizeof(nip->icmp6_ni_nonce)); + *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + cc = ICMP6_NIQLEN; + datalen = 0; + } else { icp->icmp6_type = ICMP6_ECHO_REQUEST; + icp->icmp6_code = 0; + icp->icmp6_id = htons(ident); + icp->icmp6_seq = ntohs(seq); if (timing) (void)gettimeofday((struct timeval *) &outpack[ICMP6ECHOLEN], NULL); cc = ICMP6ECHOLEN + datalen; } +#ifdef DIAGNOSTIC + if (pingerlen() != cc) + errx(1, "internal error; length mismatch"); +#endif + smsghdr.msg_name = (caddr_t)&dst; smsghdr.msg_namelen = sizeof(dst); memset(&iov, 0, sizeof(iov)); @@ -1047,6 +1281,91 @@ pinger() (void)write(STDOUT_FILENO, &DOT, 1); } +int +myechoreply(icp) + const struct icmp6_hdr *icp; +{ + if (ntohs(icp->icmp6_id) == ident) + return 1; + else + return 0; +} + +int +mynireply(nip) + const struct icmp6_nodeinfo *nip; +{ + if (memcmp(nip->icmp6_ni_nonce + sizeof(u_int16_t), + nonce + sizeof(u_int16_t), + sizeof(nonce) - sizeof(u_int16_t)) == 0) + return 1; + else + return 0; +} + +char * +dnsdecode(sp, ep, base, buf, bufsiz) + const u_char **sp; + const u_char *ep; + const u_char *base; /*base for compressed name*/ + u_char *buf; + size_t bufsiz; +{ + int i; + const u_char *cp; + char cresult[MAXDNAME + 1]; + const u_char *comp; + int l; + + cp = *sp; + *buf = '\0'; + + if (cp >= ep) + return NULL; + while (cp < ep) { + i = *cp; + if (i == 0 || cp != *sp) { + if (strlcat(buf, ".", bufsiz) >= bufsiz) + return NULL; /*result overrun*/ + } + if (i == 0) + break; + cp++; + + if ((i & 0xc0) == 0xc0 && cp - base > (i & 0x3f)) { + /* DNS compression */ + if (!base) + return NULL; + + comp = base + (i & 0x3f); + if (dnsdecode(&comp, cp, base, cresult, + sizeof(cresult)) == NULL) + return NULL; + if (strlcat(buf, cresult, bufsiz) >= bufsiz) + return NULL; /*result overrun*/ + break; + } else if ((i & 0x3f) == i) { + if (i > ep - cp) + return NULL; /*source overrun*/ + while (i-- > 0 && cp < ep) { + l = snprintf(cresult, sizeof(cresult), + isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff); + if (l >= sizeof(cresult)) + return NULL; + if (strlcat(buf, cresult, bufsiz) >= bufsiz) + return NULL; /*result overrun*/ + cp++; + } + } else + return NULL; /*invalid label*/ + } + if (i != 0) + return NULL; /*not terminated*/ + cp++; + *sp = cp; + return buf; +} + /* * pr_pack -- * Print out the packet, if it came from us. This logic is necessary @@ -1062,9 +1381,11 @@ pr_pack(buf, cc, mhdr) { #define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c) struct icmp6_hdr *icp; + struct icmp6_nodeinfo *ni; int i; int hoplim; - struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; + struct sockaddr *from; + int fromlen; u_char *cp = NULL, *dp, *end = buf + cc; struct in6_pktinfo *pktinfo = NULL; struct timeval tv, *tp; @@ -1072,16 +1393,28 @@ pr_pack(buf, cc, mhdr) int dupflag; size_t off; int oldfqdn; + u_int16_t seq; + char dnsname[MAXDNAME + 1]; (void)gettimeofday(&tv, NULL); + if (!mhdr || !mhdr->msg_name || + mhdr->msg_namelen != sizeof(struct sockaddr_in6) || + ((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET6) { + if (options & F_VERBOSE) + warnx("invalid peername\n"); + return; + } + from = (struct sockaddr *)mhdr->msg_name; + fromlen = mhdr->msg_namelen; if (cc < sizeof(struct icmp6_hdr)) { if (options & F_VERBOSE) warnx("packet too short (%d bytes) from %s\n", cc, - pr_addr(from)); + pr_addr(from, fromlen)); return; } icp = (struct icmp6_hdr *)buf; + ni = (struct icmp6_nodeinfo *)buf; off = 0; if ((hoplim = get_hoplim(mhdr)) == -1) { @@ -1093,11 +1426,8 @@ pr_pack(buf, cc, mhdr) return; } - if (icp->icmp6_type == ICMP6_ECHO_REPLY) { - /* XXX the following line overwrites the original packet */ - icp->icmp6_seq = ntohs(icp->icmp6_seq); - if (ntohs(icp->icmp6_id) != ident) - return; /* It was not our ECHO */ + if (icp->icmp6_type == ICMP6_ECHO_REPLY && myechoreply(icp)) { + seq = ntohs(icp->icmp6_seq); ++nreceived; if (timing) { tp = (struct timeval *)(icp + 1); @@ -1105,18 +1435,21 @@ pr_pack(buf, cc, mhdr) triptime = ((double)tv.tv_sec) * 1000.0 + ((double)tv.tv_usec) / 1000.0; tsum += triptime; +#if defined(__OpenBSD__) || defined(__NetBSD__) + tsumsq += triptime * triptime; +#endif if (triptime < tmin) tmin = triptime; if (triptime > tmax) tmax = triptime; } - if (TST(icp->icmp6_seq % mx_dup_ck)) { + if (TST(seq % mx_dup_ck)) { ++nrepeats; --nreceived; dupflag = 1; } else { - SET(icp->icmp6_seq % mx_dup_ck); + SET(seq % mx_dup_ck); dupflag = 0; } @@ -1127,18 +1460,21 @@ pr_pack(buf, cc, mhdr) (void)write(STDOUT_FILENO, &BSPACE, 1); else { (void)printf("%d bytes from %s, icmp_seq=%u", cc, - pr_addr(from), - icp->icmp6_seq); + pr_addr(from, fromlen), 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; +#ifdef SIN6_LEN dstsa.sin6_len = sizeof(dstsa); +#endif dstsa.sin6_scope_id = pktinfo->ipi6_ifindex; dstsa.sin6_addr = pktinfo->ipi6_addr; - (void)printf(" dst=%s", pr_addr(&dstsa)); + (void)printf(" dst=%s", + pr_addr((struct sockaddr *)&dstsa, + sizeof(dstsa))); } if (timing) (void)printf(" time=%g ms", triptime); @@ -1154,24 +1490,50 @@ pr_pack(buf, cc, mhdr) } } } - } else if (icp->icmp6_type == ICMP6_NI_REPLY) { /* ICMP6_NI_REPLY */ - struct icmp6_nodeinfo *ni = (struct icmp6_nodeinfo *)(buf + off); - - (void)printf("%d bytes from %s: ", cc, - pr_addr(from)); - - switch(ntohs(ni->ni_qtype)) { - case NI_QTYPE_NOOP: - printf("NodeInfo NOOP"); - break; - case NI_QTYPE_SUPTYPES: - printf("NodeInfo Supported Qtypes"); - break; - case NI_QTYPE_NODEADDR: - pr_nodeaddr(ni, end - (u_char *)ni); - break; - case NI_QTYPE_FQDN: - default: /* XXX: for backward compatibility */ + } else if (icp->icmp6_type == ICMP6_NI_REPLY && mynireply(ni)) { + seq = ntohs(*(u_int16_t *)ni->icmp6_ni_nonce); + ++nreceived; + if (TST(seq % mx_dup_ck)) { + ++nrepeats; + --nreceived; + dupflag = 1; + } else { + SET(seq % mx_dup_ck); + dupflag = 0; + } + + if (options & F_QUIET) + return; + + (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen)); + + switch (ntohs(ni->ni_code)) { + case ICMP6_NI_SUCCESS: + break; + case ICMP6_NI_REFUSED: + printf("refused, type 0x%x", ntohs(ni->ni_type)); + goto fqdnend; + case ICMP6_NI_UNKNOWN: + printf("unknown, type 0x%x", ntohs(ni->ni_type)); + goto fqdnend; + default: + printf("unknown code 0x%x, type 0x%x", + ntohs(ni->ni_code), ntohs(ni->ni_type)); + goto fqdnend; + } + + switch (ntohs(ni->ni_qtype)) { + case NI_QTYPE_NOOP: + printf("NodeInfo NOOP"); + break; + case NI_QTYPE_SUPTYPES: + pr_suptypes(ni, end - (u_char *)ni); + break; + case NI_QTYPE_NODEADDR: + pr_nodeaddr(ni, end - (u_char *)ni); + break; + case NI_QTYPE_FQDN: + default: /* XXX: for backward compatibility */ cp = (u_char *)ni + ICMP6_NIRLEN; if (buf[off + ICMP6_NIRLEN] == cc - off - ICMP6_NIRLEN - 1) @@ -1179,38 +1541,31 @@ pr_pack(buf, cc, mhdr) else oldfqdn = 0; if (oldfqdn) { - cp++; + cp++; /* skip length */ while (cp < end) { safeputc(*cp & 0xff); cp++; } } else { + i = 0; while (cp < end) { - i = *cp++; - if (i) { - if (i > end - cp) { - printf("???"); - break; - } - while (i-- && cp < end) { - safeputc(*cp & 0xff); - cp++; - } - if (cp + 1 < end && *cp) - printf("."); - } else { - if (cp == end) { - /* FQDN */ - printf("."); - } else if (cp + 1 == end && - *cp == '\0') { - /* truncated */ - } else { - /* invalid */ - printf("???"); - } + if (dnsdecode((const u_char **)&cp, end, + (const u_char *)(ni + 1), dnsname, + sizeof(dnsname)) == NULL) { + printf("???"); break; } + /* + * name-lookup special handling for + * truncated name + */ + if (cp + 1 <= end && !*cp && + strlen(dnsname) > 0) { + dnsname[strlen(dnsname) - 1] = '\0'; + cp++; + } + printf("%s%s", i > 0 ? "," : "", + dnsname); } } if (options & F_VERBOSE) { @@ -1219,7 +1574,7 @@ pr_pack(buf, cc, mhdr) (void)printf(" ("); /*)*/ - switch(ni->ni_code) { + switch (ni->ni_code) { case ICMP6_NI_REFUSED: (void)printf("refused"); comma++; @@ -1231,19 +1586,21 @@ pr_pack(buf, cc, mhdr) } if ((end - (u_char *)ni) < ICMP6_NIRLEN) { - /* case of refusion, unkown */ + /* case of refusion, unknown */ + /*(*/ + putchar(')'); goto fqdnend; } ttl = (int32_t)ntohl(*(u_long *)&buf[off+ICMP6ECHOLEN+8]); if (comma) printf(","); - if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) + if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) { (void)printf("TTL=%d:meaningless", - (int)ttl); - else { + (int)ttl); + } else { if (ttl < 0) { (void)printf("TTL=%d:invalid", - ttl); + ttl); } else (void)printf("TTL=%d", ttl); } @@ -1269,22 +1626,21 @@ pr_pack(buf, cc, mhdr) if (comma) printf(","); (void)printf("invalid namelen:%d/%lu", - buf[off + ICMP6_NIRLEN], - (u_long)cc - off - ICMP6_NIRLEN - 1); + buf[off + ICMP6_NIRLEN], + (u_long)cc - off - ICMP6_NIRLEN - 1); comma++; } /*(*/ putchar(')'); } - fqdnend: + fqdnend: ; } } else { /* We've got something other than an ECHOREPLY */ if (!(options & F_VERBOSE)) return; - (void)printf("%d bytes from %s: ", cc, - pr_addr(from)); + (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen)); pr_icmph(icp, end); } @@ -1308,7 +1664,7 @@ pr_exthdrs(mhdr) if (cm->cmsg_level != IPPROTO_IPV6) continue; - switch(cm->cmsg_type) { + switch (cm->cmsg_type) { case IPV6_HOPOPTS: printf(" HbH Options: "); pr_ip6opt(CMSG_DATA(cm)); @@ -1343,13 +1699,13 @@ pr_ip6opt(void *extbuf) 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); + printf("nxt %u, len %u (%lu bytes)\n", ext->ip6h_nxt, + (unsigned int)ext->ip6h_len, (unsigned long)extlen); currentlen = 0; while (1) { currentlen = inet6_opt_next(extbuf, extlen, currentlen, - &type, &len, &databuf); + &type, &len, &databuf); if (currentlen == -1) break; switch (type) { @@ -1360,19 +1716,20 @@ pr_ip6opt(void *extbuf) case IP6OPT_JUMBO: offset = 0; offset = inet6_opt_get_val(databuf, offset, - &value4, sizeof(value4)); + &value4, sizeof(value4)); printf(" Jumbo Payload Opt: Length %u\n", - (unsigned int)ntohl(value4)); + (u_int32_t)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)); + ntohs(value2)); break; default: - printf(" Received Opt %u len %u\n", type, len); + printf(" Received Opt %u len %lu\n", + type, (unsigned long)len); break; } } @@ -1399,7 +1756,7 @@ pr_rthdr(void *extbuf) /* 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); + rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type); if ((segments = inet6_rth_segments(extbuf)) >= 0) printf("%d segments, ", segments); else @@ -1410,15 +1767,18 @@ pr_rthdr(void *extbuf) 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))); + else { + if (!inet_ntop(AF_INET6, in6, ntopbuf, + sizeof(ntopbuf))) + strncpy(ntopbuf, "?", sizeof(ntopbuf)); + printf(" [%d]%s\n", i, ntopbuf); + } } return; - + } + #else /* !USE_RFC2292BIS */ /* ARGSUSED */ void @@ -1429,35 +1789,186 @@ pr_rthdr(void *extbuf) } #endif /* USE_RFC2292BIS */ +int +pr_bitrange(v, s, ii) + u_int32_t v; + int s; + int ii; +{ + int off; + int i; + + off = 0; + while (off < 32) { + /* shift till we have 0x01 */ + if ((v & 0x01) == 0) { + if (ii > 1) + printf("-%u", s + off - 1); + ii = 0; + switch (v & 0x0f) { + case 0x00: + v >>= 4; + off += 4; + continue; + case 0x08: + v >>= 3; + off += 3; + continue; + case 0x04: case 0x0c: + v >>= 2; + off += 2; + continue; + default: + v >>= 1; + off += 1; + continue; + } + } + + /* we have 0x01 with us */ + for (i = 0; i < 32 - off; i++) { + if ((v & (0x01 << i)) == 0) + break; + } + if (!ii) + printf(" %u", s + off); + ii += i; + v >>= i; off += i; + } + return ii; +} + +void +pr_suptypes(ni, nilen) + struct icmp6_nodeinfo *ni; /* ni->qtype must be SUPTYPES */ + size_t nilen; +{ + size_t clen; + u_int32_t v; + const u_char *cp, *end; + u_int16_t cur; + struct cbit { + u_int16_t words; /*32bit count*/ + u_int16_t skip; + } cbit; +#define MAXQTYPES (1 << 16) + size_t off; + int b; + + cp = (u_char *)(ni + 1); + end = ((u_char *)ni) + nilen; + cur = 0; + b = 0; + + printf("NodeInfo Supported Qtypes"); + if (options & F_VERBOSE) { + if (ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) + printf(", compressed bitmap"); + else + printf(", raw bitmap"); + } + + while (cp < end) { + clen = (size_t)(end - cp); + if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) == 0) { + if (clen == 0 || clen > MAXQTYPES / 8 || + clen % sizeof(v)) { + printf("???"); + return; + } + } else { + if (clen < sizeof(cbit) || clen % sizeof(v)) + return; + memcpy(&cbit, cp, sizeof(cbit)); + if (sizeof(cbit) + ntohs(cbit.words) * sizeof(v) > + clen) + return; + cp += sizeof(cbit); + clen = ntohs(cbit.words) * sizeof(v); + if (cur + clen * 8 + (u_long)ntohs(cbit.skip) * 32 > + MAXQTYPES) + return; + } + + for (off = 0; off < clen; off += sizeof(v)) { + memcpy(&v, cp + off, sizeof(v)); + v = (u_int32_t)ntohl(v); + b = pr_bitrange(v, (int)(cur + off * 8), b); + } + /* flush the remaining bits */ + b = pr_bitrange(0, (int)(cur + off * 8), b); + + cp += clen; + cur += clen * 8; + if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) != 0) + cur += ntohs(cbit.skip) * 32; + } +} 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); + u_char *cp = (u_char *)(ni + 1); char ntop_buf[INET6_ADDRSTRLEN]; + int withttl = 0; nilen -= sizeof(struct icmp6_nodeinfo); if (options & F_VERBOSE) { - switch(ni->ni_code) { - case ICMP6_NI_REFUSED: - (void)printf("refused"); - break; - case ICMP6_NI_UNKNOWN: - (void)printf("unknown qtype"); - break; + switch (ni->ni_code) { + case ICMP6_NI_REFUSED: + (void)printf("refused"); + break; + case ICMP6_NI_UNKNOWN: + (void)printf("unknown qtype"); + break; } - if (ni->ni_flags & NI_NODEADDR_FLAG_ALL) + if (ni->ni_flags & NI_NODEADDR_FLAG_TRUNCATE) (void)printf(" truncated"); } putchar('\n'); if (nilen <= 0) printf(" no address\n"); - for (; nilen > 0; nilen -= sizeof(*ia6), ia6 += 1) { - printf(" %s\n", - inet_ntop(AF_INET6, ia6, ntop_buf, sizeof(ntop_buf))); + + /* + * In icmp-name-lookups 05 and later, TTL of each returned address + * is contained in the resposne. We try to detect the version + * by the length of the data, but note that the detection algorithm + * is incomplete. We assume the latest draft by default. + */ + if (nilen % (sizeof(u_int32_t) + sizeof(struct in6_addr)) == 0) + withttl = 1; + while (nilen > 0) { + u_int32_t ttl; + + if (withttl) { + /* XXX: alignment? */ + ttl = (u_int32_t)ntohl(*(u_int32_t *)cp); + cp += sizeof(u_int32_t); + nilen -= sizeof(u_int32_t); + } + + if (inet_ntop(AF_INET6, cp, ntop_buf, sizeof(ntop_buf)) == + NULL) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + printf(" %s", ntop_buf); + if (withttl) { + if (ttl == 0xffffffff) { + /* + * XXX: can this convention be applied to all + * type of TTL (i.e. non-ND TTL)? + */ + printf("(TTL=infty)"); + } + else + printf("(TTL=%u)", ttl); + } + putchar('\n'); + + nilen -= sizeof(struct in6_addr); + cp += sizeof(struct in6_addr); } } @@ -1469,6 +1980,9 @@ get_hoplim(mhdr) for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { + if (cm->cmsg_len == 0) + return(-1); + if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_HOPLIMIT && cm->cmsg_len == CMSG_LEN(sizeof(int))) @@ -1486,6 +2000,9 @@ get_rcvpktinfo(mhdr) for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { + if (cm->cmsg_len == 0) + return(NULL); + if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO && cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) @@ -1495,6 +2012,116 @@ get_rcvpktinfo(mhdr) return(NULL); } +int +get_pathmtu(mhdr) + struct msghdr *mhdr; +{ +#ifdef IPV6_RECVPATHMTU + struct cmsghdr *cm; + struct ip6_mtuinfo *mtuctl = NULL; + + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { + if (cm->cmsg_len == 0) + return(0); + + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_PATHMTU && + cm->cmsg_len == CMSG_LEN(sizeof(struct ip6_mtuinfo))) { + mtuctl = (struct ip6_mtuinfo *)CMSG_DATA(cm); + + /* + * If the notified destination is different from + * the one we are pinging, just ignore the info. + * We check the scope ID only when both notified value + * and our own value have non-0 values, because we may + * have used the default scope zone ID for sending, + * in which case the scope ID value is 0. + */ + if (!IN6_ARE_ADDR_EQUAL(&mtuctl->ip6m_addr.sin6_addr, + &dst.sin6_addr) || + (mtuctl->ip6m_addr.sin6_scope_id && + dst.sin6_scope_id && + mtuctl->ip6m_addr.sin6_scope_id != + dst.sin6_scope_id)) { + if ((options & F_VERBOSE) != 0) { + printf("path MTU for %s is notified. " + "(ignored)\n", + pr_addr((struct sockaddr *)&mtuctl->ip6m_addr, + sizeof(mtuctl->ip6m_addr))); + } + return(0); + } + + /* + * Ignore an invalid MTU. XXX: can we just believe + * the kernel check? + */ + if (mtuctl->ip6m_mtu < IPV6_MMTU) + return(0); + + /* notification for our destination. return the MTU. */ + return((int)mtuctl->ip6m_mtu); + } + } +#endif + return(0); +} + +void +set_pathmtu(mtu) + int mtu; +{ +#ifdef IPV6_USE_MTU + static int firsttime = 1; + struct cmsghdr *cm; + + if (firsttime) { + int oldlen = smsghdr.msg_controllen; + char *oldbuf = smsghdr.msg_control; + + /* XXX: We need to enlarge control message buffer */ + firsttime = 0; /* prevent further enlargement */ + + smsghdr.msg_controllen = oldlen + CMSG_SPACE(sizeof(int)); + if ((smsghdr.msg_control = + (char *)malloc(smsghdr.msg_controllen)) == NULL) + err(1, "set_pathmtu: malloc"); + cm = (struct cmsghdr *)CMSG_FIRSTHDR(&smsghdr); + cm->cmsg_len = CMSG_LEN(sizeof(int)); + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_USE_MTU; + + cm = (struct cmsghdr *)CMSG_NXTHDR(&smsghdr, cm); + if (oldlen) + memcpy((void *)cm, (void *)oldbuf, oldlen); + + free(oldbuf); + } + + /* + * look for a cmsgptr that points MTU structure. + * XXX: this procedure seems redundant at this moment, but we'd better + * keep the code generic enough for future extensions. + */ + for (cm = CMSG_FIRSTHDR(&smsghdr); cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(&smsghdr, cm)) { + if (cm->cmsg_len == 0) /* XXX: paranoid check */ + errx(1, "set_pathmtu: internal error"); + + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_USE_MTU && + cm->cmsg_len == CMSG_LEN(sizeof(int))) + break; + } + + if (cm == NULL) + errx(1, "set_pathmtu: internal error: no space for path MTU"); + + *(int *)CMSG_DATA(cm) = mtu; +#endif +} + /* * tvsub -- * Subtract 2 timeval structs: out = out - in. Out is assumed to @@ -1512,18 +2139,6 @@ tvsub(out, in) } /* - * oninfo -- - * SIGINFO handler. - */ -/* ARGSUSED */ -void -oninfo(notused) - int notused; -{ - summary(); -} - -/* * onint -- * SIGINT handler. */ @@ -1548,7 +2163,6 @@ onint(notused) void summary() { - register int i; (void)printf("\n--- %s ping6 statistics ---\n", hostname); (void)printf("%ld packets transmitted, ", ntransmitted); @@ -1566,28 +2180,35 @@ summary() (void)putchar('\n'); if (nreceived && timing) { /* Only display average to microseconds */ - i = 1000.0 * tsum / (nreceived + nrepeats); - (void)printf("round-trip min/avg/max = %g/%g/%g ms\n", - tmin, ((double)i) / 1000.0, tmax); + double num = nreceived + nrepeats; + double avg = tsum / num; +#if defined(__OpenBSD__) || defined(__NetBSD__) + double dev = sqrt(tsumsq / num - avg * avg); + (void)printf( + "round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n", + tmin, avg, tmax, dev); +#else + (void)printf( + "round-trip min/avg/max = %.3f/%.3f/%.3f ms\n", + tmin, avg, tmax); +#endif (void)fflush(stdout); } + (void)fflush(stdout); } -#ifdef notdef -static char *ttab[] = { - "Echo Reply", /* ip + seq + udata */ - "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */ - "Source Quench", /* IP */ - "Redirect", /* redirect type, gateway, + IP */ - "Echo", - "Time Exceeded", /* transit, frag reassem + IP */ - "Parameter Problem", /* pointer + IP */ - "Timestamp", /* id + seq + three timestamps */ - "Timestamp Reply", /* " */ - "Info Request", /* id + sq */ - "Info Reply" /* " */ +/*subject type*/ +static char *niqcode[] = { + "IPv6 address", + "DNS label", /*or empty*/ + "IPv4 address", }; -#endif + +/*result code*/ +static char *nircode[] = { + "Success", "Refused", "Unknown", +}; + /* * pr_icmph -- @@ -1599,16 +2220,21 @@ pr_icmph(icp, end) u_char *end; { char ntop_buf[INET6_ADDRSTRLEN]; + struct nd_redirect *red; + struct icmp6_nodeinfo *ni; + char dnsname[MAXDNAME + 1]; + const u_char *cp; + size_t l; - switch(icp->icmp6_type) { + switch (icp->icmp6_type) { case ICMP6_DST_UNREACH: - switch(icp->icmp6_code) { + switch (icp->icmp6_code) { case ICMP6_DST_UNREACH_NOROUTE: (void)printf("No Route to Destination\n"); break; case ICMP6_DST_UNREACH_ADMIN: (void)printf("Destination Administratively " - "Unreachable\n"); + "Unreachable\n"); break; case ICMP6_DST_UNREACH_BEYONDSCOPE: (void)printf("Destination Unreachable Beyond Scope\n"); @@ -1629,11 +2255,11 @@ pr_icmph(icp, end) break; case ICMP6_PACKET_TOO_BIG: (void)printf("Packet too big mtu = %d\n", - (int)ntohl(icp->icmp6_mtu)); + (int)ntohl(icp->icmp6_mtu)); pr_retip((struct ip6_hdr *)(icp + 1), end); break; case ICMP6_TIME_EXCEEDED: - switch(icp->icmp6_code) { + switch (icp->icmp6_code) { case ICMP6_TIME_EXCEED_TRANSIT: (void)printf("Time to live exceeded\n"); break; @@ -1649,22 +2275,22 @@ pr_icmph(icp, end) break; case ICMP6_PARAM_PROB: (void)printf("Parameter problem: "); - switch(icp->icmp6_code) { - case ICMP6_PARAMPROB_HEADER: - (void)printf("Erroneous Header "); - break; - case ICMP6_PARAMPROB_NEXTHEADER: - (void)printf("Unknown Nextheader "); - break; - case ICMP6_PARAMPROB_OPTION: - (void)printf("Unrecognized Option "); - break; - default: - (void)printf("Bad code(%d) ", icp->icmp6_code); - break; + switch (icp->icmp6_code) { + case ICMP6_PARAMPROB_HEADER: + (void)printf("Erroneous Header "); + break; + case ICMP6_PARAMPROB_NEXTHEADER: + (void)printf("Unknown Nextheader "); + break; + case ICMP6_PARAMPROB_OPTION: + (void)printf("Unrecognized Option "); + break; + default: + (void)printf("Bad code(%d) ", icp->icmp6_code); + break; } (void)printf("pointer = 0x%02x\n", - (int)ntohl(icp->icmp6_pptr)); + (u_int32_t)ntohl(icp->icmp6_pptr)); pr_retip((struct ip6_hdr *)(icp + 1), end); break; case ICMP6_ECHO_REQUEST: @@ -1697,25 +2323,119 @@ pr_icmph(icp, end) (void)printf("Neighbor Advertisement"); break; case ND_REDIRECT: - { - struct nd_redirect *red = (struct nd_redirect *)icp; - + red = (struct nd_redirect *)icp; (void)printf("Redirect\n"); - (void)printf("Destination: %s", - inet_ntop(AF_INET6, &red->nd_rd_dst, - ntop_buf, sizeof(ntop_buf))); - (void)printf("New Target: %s", - inet_ntop(AF_INET6, &red->nd_rd_target, - ntop_buf, sizeof(ntop_buf))); + if (!inet_ntop(AF_INET6, &red->nd_rd_dst, ntop_buf, + sizeof(ntop_buf))) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + (void)printf("Destination: %s", ntop_buf); + if (!inet_ntop(AF_INET6, &red->nd_rd_target, ntop_buf, + sizeof(ntop_buf))) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + (void)printf(" New Target: %s", ntop_buf); break; - } case ICMP6_NI_QUERY: (void)printf("Node Information Query"); /* XXX ID + Seq + Data */ + ni = (struct icmp6_nodeinfo *)icp; + l = end - (u_char *)(ni + 1); + printf(", "); + switch (ntohs(ni->ni_qtype)) { + case NI_QTYPE_NOOP: + (void)printf("NOOP"); + break; + case NI_QTYPE_SUPTYPES: + (void)printf("Supported qtypes"); + break; + case NI_QTYPE_FQDN: + (void)printf("DNS name"); + break; + case NI_QTYPE_NODEADDR: + (void)printf("nodeaddr"); + break; + case NI_QTYPE_IPV4ADDR: + (void)printf("IPv4 nodeaddr"); + break; + default: + (void)printf("unknown qtype"); + break; + } + if (options & F_VERBOSE) { + switch (ni->ni_code) { + case ICMP6_NI_SUBJ_IPV6: + if (l == sizeof(struct in6_addr) && + inet_ntop(AF_INET6, ni + 1, ntop_buf, + sizeof(ntop_buf)) != NULL) { + (void)printf(", subject=%s(%s)", + niqcode[ni->ni_code], ntop_buf); + } else { +#if 1 + /* backward compat to -W */ + (void)printf(", oldfqdn"); +#else + (void)printf(", invalid"); +#endif + } + break; + case ICMP6_NI_SUBJ_FQDN: + if (end == (u_char *)(ni + 1)) { + (void)printf(", no subject"); + break; + } + printf(", subject=%s", niqcode[ni->ni_code]); + cp = (const u_char *)(ni + 1); + if (dnsdecode(&cp, end, NULL, dnsname, + sizeof(dnsname)) != NULL) + printf("(%s)", dnsname); + else + printf("(invalid)"); + break; + case ICMP6_NI_SUBJ_IPV4: + if (l == sizeof(struct in_addr) && + inet_ntop(AF_INET, ni + 1, ntop_buf, + sizeof(ntop_buf)) != NULL) { + (void)printf(", subject=%s(%s)", + niqcode[ni->ni_code], ntop_buf); + } else + (void)printf(", invalid"); + break; + default: + (void)printf(", invalid"); + break; + } + } break; case ICMP6_NI_REPLY: (void)printf("Node Information Reply"); /* XXX ID + Seq + Data */ + ni = (struct icmp6_nodeinfo *)icp; + printf(", "); + switch (ntohs(ni->ni_qtype)) { + case NI_QTYPE_NOOP: + (void)printf("NOOP"); + break; + case NI_QTYPE_SUPTYPES: + (void)printf("Supported qtypes"); + break; + case NI_QTYPE_FQDN: + (void)printf("DNS name"); + break; + case NI_QTYPE_NODEADDR: + (void)printf("nodeaddr"); + break; + case NI_QTYPE_IPV4ADDR: + (void)printf("IPv4 nodeaddr"); + break; + default: + (void)printf("unknown qtype"); + break; + } + if (options & F_VERBOSE) { + if (ni->ni_code > sizeof(nircode) / sizeof(nircode[0])) + printf(", invalid"); + else + printf(", %s", nircode[ni->ni_code]); + } break; default: (void)printf("Bad ICMP type: %d", icp->icmp6_type); @@ -1740,13 +2460,14 @@ pr_iph(ip6) printf("Vr TC Flow Plen Nxt Hlim\n"); printf(" %1x %02x %05x %04x %02x %02x\n", - (ip6->ip6_vfc & IPV6_VERSION_MASK) >> 4, tc, (int)ntohl(flow), - ntohs(ip6->ip6_plen), - ip6->ip6_nxt, ip6->ip6_hlim); - printf("%s->", inet_ntop(AF_INET6, &ip6->ip6_src, - ntop_buf, sizeof(ntop_buf))); - printf("%s\n", inet_ntop(AF_INET6, &ip6->ip6_dst, - ntop_buf, sizeof(ntop_buf))); + (ip6->ip6_vfc & IPV6_VERSION_MASK) >> 4, tc, (u_int32_t)ntohl(flow), + ntohs(ip6->ip6_plen), ip6->ip6_nxt, ip6->ip6_hlim); + if (!inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, sizeof(ntop_buf))) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + printf("%s->", ntop_buf); + if (!inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, sizeof(ntop_buf))) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + printf("%s\n", ntop_buf); } /* @@ -1755,22 +2476,25 @@ pr_iph(ip6) * a hostname. */ const char * -pr_addr(addr) - struct sockaddr_in6 *addr; +pr_addr(addr, addrlen) + struct sockaddr *addr; + int addrlen; { - static char buf[MAXHOSTNAMELEN]; - int flag = 0; + static char buf[NI_MAXHOST]; + int flag; +#ifdef NI_WITHSCOPEID + flag = NI_WITHSCOPEID; +#else + flag = 0; +#endif if ((options & F_HOSTNAME) == 0) flag |= NI_NUMERICHOST; -#ifdef KAME_SCOPEID - flag |= NI_WITHSCOPEID; -#endif - - getnameinfo((struct sockaddr *)addr, addr->sin6_len, buf, sizeof(buf), - NULL, 0, flag); - return (buf); + if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, flag) == 0) + return (buf); + else + return "?"; } /* @@ -1796,53 +2520,53 @@ pr_retip(ip6, end) cp += hlen; while (end - cp >= 8) { switch (nh) { - case IPPROTO_HOPOPTS: - printf("HBH "); - hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3; - nh = ((struct ip6_hbh *)cp)->ip6h_nxt; - break; - case IPPROTO_DSTOPTS: - printf("DSTOPT "); - hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3; - nh = ((struct ip6_dest *)cp)->ip6d_nxt; - break; - case IPPROTO_FRAGMENT: - printf("FRAG "); - hlen = sizeof(struct ip6_frag); - nh = ((struct ip6_frag *)cp)->ip6f_nxt; - break; - case IPPROTO_ROUTING: - printf("RTHDR "); - hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3; - nh = ((struct ip6_rthdr *)cp)->ip6r_nxt; - break; + case IPPROTO_HOPOPTS: + printf("HBH "); + hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3; + nh = ((struct ip6_hbh *)cp)->ip6h_nxt; + break; + case IPPROTO_DSTOPTS: + printf("DSTOPT "); + hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3; + nh = ((struct ip6_dest *)cp)->ip6d_nxt; + break; + case IPPROTO_FRAGMENT: + printf("FRAG "); + hlen = sizeof(struct ip6_frag); + nh = ((struct ip6_frag *)cp)->ip6f_nxt; + break; + case IPPROTO_ROUTING: + printf("RTHDR "); + hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3; + nh = ((struct ip6_rthdr *)cp)->ip6r_nxt; + break; #ifdef IPSEC - case IPPROTO_AH: - printf("AH "); - hlen = (((struct ah *)cp)->ah_len+2) << 2; - nh = ((struct ah *)cp)->ah_nxt; - break; + case IPPROTO_AH: + printf("AH "); + hlen = (((struct ah *)cp)->ah_len+2) << 2; + nh = ((struct ah *)cp)->ah_nxt; + break; #endif - case IPPROTO_ICMPV6: - printf("ICMP6: type = %d, code = %d\n", - *cp, *(cp + 1)); - return; - case IPPROTO_ESP: - printf("ESP\n"); - return; - case IPPROTO_TCP: - printf("TCP: from port %u, to port %u (decimal)\n", - (*cp * 256 + *(cp + 1)), - (*(cp + 2) * 256 + *(cp + 3))); - return; - case IPPROTO_UDP: - printf("UDP: from port %u, to port %u (decimal)\n", - (*cp * 256 + *(cp + 1)), - (*(cp + 2) * 256 + *(cp + 3))); - return; - default: - printf("Unknown Header(%d)\n", nh); - return; + case IPPROTO_ICMPV6: + printf("ICMP6: type = %d, code = %d\n", + *cp, *(cp + 1)); + return; + case IPPROTO_ESP: + printf("ESP\n"); + return; + case IPPROTO_TCP: + printf("TCP: from port %u, to port %u (decimal)\n", + (*cp * 256 + *(cp + 1)), + (*(cp + 2) * 256 + *(cp + 3))); + return; + case IPPROTO_UDP: + printf("UDP: from port %u, to port %u (decimal)\n", + (*cp * 256 + *(cp + 1)), + (*(cp + 2) * 256 + *(cp + 3))); + return; + default: + printf("Unknown Header(%d)\n", nh); + return; } if ((cp += hlen) >= end) @@ -1876,7 +2600,7 @@ fill(bp, patp) &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], &pat[13], &pat[14], &pat[15]); -/* xxx */ +/* xxx */ if (ii > 0) for (kk = 0; kk <= MAXDATALEN - (8 + sizeof(struct timeval) + ii); @@ -1906,8 +2630,8 @@ setpolicy(so, policy) buf = ipsec_set_policy(policy, strlen(policy)); if (buf == NULL) errx(1, "%s", ipsec_strerror()); - if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, - buf, ipsec_get_policylen(buf)) < 0) + if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf, + ipsec_get_policylen(buf)) < 0) warnx("Unable to set IPSec policy"); free(buf); @@ -1921,30 +2645,38 @@ nigroup(name) char *name; { char *p; + unsigned char *q; MD5_CTX ctxt; u_int8_t digest[16]; - char l; + u_int8_t c; + size_t l; char hbuf[NI_MAXHOST]; struct in6_addr in6; - p = name; - while (p && *p && *p != '.') - p++; - if (p - name > 63) - return NULL; /*label too long*/ + p = strchr(name, '.'); + if (!p) + p = name + strlen(name); l = p - name; + if (l > 63 || l > sizeof(hbuf) - 1) + return NULL; /*label too long*/ + strncpy(hbuf, name, l); + hbuf[(int)l] = '\0'; + + for (q = name; *q; q++) { + if (isupper(*q)) + *q = tolower(*q); + } /* generate 8 bytes of pseudo-random value. */ bzero(&ctxt, sizeof(ctxt)); MD5Init(&ctxt); - MD5Update(&ctxt, &l, sizeof(l)); - MD5Update(&ctxt, name, p - name); + c = l & 0xff; + MD5Update(&ctxt, &c, sizeof(c)); + MD5Update(&ctxt, name, l); MD5Final(digest, &ctxt); - bzero(&in6, sizeof(in6)); - in6.s6_addr[0] = 0xff; - in6.s6_addr[1] = 0x02; - in6.s6_addr[11] = 0x02; + if (inet_pton(AF_INET6, "ff02::2:0000:0000", &in6) != 1) + return NULL; /*XXX*/ bcopy(digest, &in6.s6_addr[12], 4); if (inet_ntop(AF_INET6, &in6, hbuf, sizeof(hbuf)) == NULL) @@ -1957,19 +2689,20 @@ void usage() { (void)fprintf(stderr, -"usage: ping6 [-dfHnNqvwW" + "usage: ping6 [-dfHmnNqvwW" #ifdef IPV6_REACHCONF - "R" + "R" #endif #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC - "] [-P policy" + "] [-P policy" #else - "AE" + "AE" +#endif #endif -#endif - "] [-a [aAclsg]] [-b sockbufsiz] [-c count] \n\ - [-I interface] [-i wait] [-l preload] [-p pattern] [-S sourceaddr]\n\ - [-s packetsize] [-h hoplimit] [hops...] host\n"); + "] [-a [aAclsg]] [-b sockbufsiz] [-c count] \n" + "\t[-I interface] [-i wait] [-l preload] [-p pattern] " + "[-S sourceaddr]\n" + "\t[-s packetsize] [-h hoplimit] [hops...] host\n"); exit(1); } diff --git a/sbin/route/route.c b/sbin/route/route.c index 2b7d246..46d61c2 100644 --- a/sbin/route/route.c +++ b/sbin/route/route.c @@ -72,11 +72,7 @@ static const char rcsid[] = #include <string.h> #include <sysexits.h> #include <unistd.h> - -/* wrapper for KAME-special getnameinfo() */ -#ifndef NI_WITHSCOPEID -#define NI_WITHSCOPEID 0 -#endif +#include <ifaddrs.h> struct keytab { char *kt_cp; @@ -98,6 +94,7 @@ union sockunion { struct sockaddr_ns sns; #endif struct sockaddr_dl sdl; + struct sockaddr_storage ss; /* added to avoid memory overrun */ } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp; typedef union sockunion *sup; @@ -110,10 +107,7 @@ struct rt_metrics rt_metrics; u_long rtm_inits; int atalk_aton __P((const char *, struct at_addr *)); char *atalk_ntoa __P((struct at_addr)); -#ifdef INET6 -char *inet6_ntoa __P((struct sockaddr *sa)); -#endif -char *routename(), *netname(); +const char *routename(), *netname(); void flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf(); void print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr(); int getaddr(), rtmsg(), x25_makemask(); @@ -122,10 +116,6 @@ extern char *iso_ntoa(); void usage __P((const char *)) __dead2; -#ifdef INET6 -char name_buf[MAXHOSTNAMELEN * 2 + 1]; /*for getnameinfo()*/ -#endif - void usage(cp) const char *cp; @@ -303,14 +293,14 @@ bad: usage(*argv); struct sockaddr *sa = (struct sockaddr *)(rtm + 1); (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? routename(sa) : netname(sa)); - sa = (struct sockaddr *)(sa->sa_len + (char *)sa); + sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa); (void) printf("%-20.20s ", routename(sa)); (void) printf("done\n"); } } } -char * +const char * routename(sa) struct sockaddr *sa; { @@ -364,8 +354,36 @@ routename(sa) #ifdef INET6 case AF_INET6: - (void) snprintf(line, sizeof(line), "%s", inet6_ntoa(sa)); - break; + { + struct sockaddr_in6 sin6; /* use static var for safety */ + int niflags = 0; +#ifdef NI_WITHSCOPEID + niflags = NI_WITHSCOPEID; +#endif + + memset(&sin6, 0, sizeof(sin6)); + memcpy(&sin6, sa, sa->sa_len); + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_family = AF_INET6; +#ifdef __KAME__ + if (sa->sa_len == sizeof(struct sockaddr_in6) && + (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) && + sin6.sin6_scope_id == 0) { + sin6.sin6_scope_id = + ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); + sin6.sin6_addr.s6_addr[2] = 0; + sin6.sin6_addr.s6_addr[3] = 0; + } +#endif + if (nflag) + niflags |= NI_NUMERICHOST; + if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, + line, sizeof(line), NULL, 0, niflags) != 0) + strncpy(line, "invalid", sizeof(line)); + + return(line); + } #endif case AF_APPLETALK: @@ -399,7 +417,7 @@ routename(sa) * Return the name of the network whose address is given. * The address is assumed to be that of a net or subnet, not a host. */ -char * +const char * netname(sa) struct sockaddr *sa; { @@ -469,8 +487,36 @@ netname(sa) #ifdef INET6 case AF_INET6: - (void) snprintf(line, sizeof(line), "%s", inet6_ntoa(sa)); - break; + { + struct sockaddr_in6 sin6; /* use static var for safety */ + int niflags = 0; +#ifdef NI_WITHSCOPEID + niflags = NI_WITHSCOPEID; +#endif + + memset(&sin6, 0, sizeof(sin6)); + memcpy(&sin6, sa, sa->sa_len); + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_family = AF_INET6; +#ifdef __KAME__ + if (sa->sa_len == sizeof(struct sockaddr_in6) && + (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) && + sin6.sin6_scope_id == 0) { + sin6.sin6_scope_id = + ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); + sin6.sin6_addr.s6_addr[2] = 0; + sin6.sin6_addr.s6_addr[3] = 0; + } +#endif + if (nflag) + niflags |= NI_NUMERICHOST; + if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, + line, sizeof(line), NULL, 0, niflags) != 0) + strncpy(line, "invalid", sizeof(line)); + + return(line); + } #endif case AF_APPLETALK: @@ -827,47 +873,35 @@ getaddr(which, s, hpp) case RTA_GATEWAY: su = &so_gate; if (iflag) { - #define MAX_IFACES 400 - int sock; - struct ifreq iflist[MAX_IFACES]; - struct ifconf ifconf; - struct ifreq *ifr, *ifr_end; - struct sockaddr_dl *dl, *sdl = NULL; - - /* Get socket */ - if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) - err(1, "socket"); - - /* Get interface list */ - ifconf.ifc_req = iflist; - ifconf.ifc_len = sizeof(iflist); - if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0) - err(1, "ioctl(SIOCGIFCONF)"); - close(sock); - - /* Look for this interface in the list */ - for (ifr = ifconf.ifc_req, - ifr_end = (struct ifreq *) - (ifconf.ifc_buf + ifconf.ifc_len); - ifr < ifr_end; - ifr = (struct ifreq *) ((char *) &ifr->ifr_addr - + MAX(ifr->ifr_addr.sa_len, - sizeof(ifr->ifr_addr)))) { - dl = (struct sockaddr_dl *)&ifr->ifr_addr; - if (ifr->ifr_addr.sa_family == AF_LINK - && (ifr->ifr_flags & IFF_POINTOPOINT) - && !strncmp(s, dl->sdl_data, dl->sdl_nlen) - && s[dl->sdl_nlen] == 0) { - sdl = dl; - break; - } - } + struct ifaddrs *ifap, *ifa; + struct sockaddr_dl *sdl = NULL; + + if (getifaddrs(&ifap)) + err(1, "getifaddrs"); + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family != AF_LINK) + continue; + + if (strcmp(s, ifa->ifa_name) || + (ifa->ifa_flags & IFF_POINTOPOINT) == 0) + continue; + sdl = (struct sockaddr_dl *)ifa->ifa_addr; + } /* If we found it, then use it */ if (sdl) { - su->sdl = *sdl; - return(1); + /* + * Copy is safe since we have a + * sockaddr_storage member in sockunion{}. + * Note that we need to copy before calling + * freeifaddrs(). + */ + memcpy(&su->sdl, sdl, sdl->sdl_len); } + freeifaddrs(ifap); + if (sdl) + return(1); } break; case RTA_NETMASK: @@ -908,31 +942,33 @@ getaddr(which, s, hpp) switch (afamily) { #ifdef INET6 case AF_INET6: - { + { struct addrinfo hints, *res; - int error; - - bzero(&hints, sizeof(struct addrinfo)); - hints.ai_family = AF_INET6; - - error = getaddrinfo(s, NULL, &hints, &res); - if (error != 0) { - (void) fprintf(stderr, "%s: bad value\n", - gai_strerror(error)); - if (error == EAI_SYSTEM) - (void) fprintf(stderr, "%s\n", - strerror(errno)); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = afamily; /*AF_INET6*/ + hints.ai_flags = AI_NUMERICHOST; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + if (getaddrinfo(s, "0", &hints, &res) != 0 || + res->ai_family != AF_INET6 || + res->ai_addrlen != sizeof(su->sin6)) { + (void) fprintf(stderr, "%s: bad value\n", s); exit(1); } - bcopy(res->ai_addr, &su->sa, res->ai_addrlen); - /* XXX: embedded link local addr check */ - if (IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr)) - *(u_short *)&su->sin6.sin6_addr.s6_addr[2] = - ntohs(su->sin6.sin6_scope_id); - su->sin6.sin6_scope_id = 0; - return 0; - } + memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); +#ifdef __KAME__ + if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) || + IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr)) && + su->sin6.sin6_scope_id) { + *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] = + htons(su->sin6.sin6_scope_id); + su->sin6.sin6_scope_id = 0; + } #endif + freeaddrinfo(res); + return (0); + } +#endif /* INET6 */ #ifdef NS case AF_NS: @@ -1624,45 +1660,3 @@ atalk_ntoa(struct at_addr at) (void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node); return(buf); } - -#ifdef INET6 -char * -inet6_ntoa(struct sockaddr *sa) -{ - char *cp; - struct sockaddr_in6 *sin6; - int error = -1, gap; - - cp = NULL; - sin6 = (struct sockaddr_in6 *)sa; - gap = sizeof(struct sockaddr_in6) - sin6->sin6_len; - if (gap > 0) - bzero((char *)(sin6) + sin6->sin6_len, gap); - - /* XXX: embedded link local addr check */ - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && - *(u_short *)&sin6->sin6_addr.s6_addr[2] != 0) { - u_short index; - - index = *(u_short *)&sin6->sin6_addr.s6_addr[2]; - *(u_short *)&sin6->sin6_addr.s6_addr[2] = 0; - if (sin6->sin6_scope_id == 0) - sin6->sin6_scope_id = ntohs(index); - } - - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || sa->sa_len < 4) - cp = "default"; - if (cp == 0 && !nflag) - error = getnameinfo(sa, sa->sa_len, name_buf, sizeof(name_buf), - NULL, 0, NI_NAMEREQD); - if (error != 0) - error = getnameinfo(sa, sa->sa_len, name_buf, - sizeof(name_buf), NULL, 0, - NI_NUMERICHOST|NI_WITHSCOPEID); - if (error != 0) - inet_ntop(AF_INET6, &sin6->sin6_addr, name_buf, - sizeof(name_buf)); - - return (cp != NULL) ? cp : name_buf; -} -#endif diff --git a/sbin/rtsol/Makefile b/sbin/rtsol/Makefile index 4926191..f533ed8 100644 --- a/sbin/rtsol/Makefile +++ b/sbin/rtsol/Makefile @@ -16,11 +16,9 @@ SRCDIR= ${.CURDIR}/../../usr.sbin/rtsold PROG= rtsol -SRCS= rtsold.c rtsol.c if.c probe.c dump.c +SRCS= rtsold.c rtsol.c if.c probe.c dump.c rtsock.c CFLAGS+=-DINET6 -DHAVE_GETIFADDRS -LDADD= -lkvm -DPADD= ${LIBKVM} NOMAN= yes diff --git a/sbin/setkey/parse.y b/sbin/setkey/parse.y index 0eea4c1..1d43dc4 100644 --- a/sbin/setkey/parse.y +++ b/sbin/setkey/parse.y @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: parse.y,v 1.29 2000/06/10 14:17:44 sakane Exp $ */ +/* $KAME: kame/kame/kame/setkey/parse.y,v 1.36 2001/06/07 15:53:12 sakane Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -57,6 +57,7 @@ u_int p_type; u_int32_t p_spi; +int p_no_spi; struct sockaddr *p_src, *p_dst; u_int p_prefs, p_prefd, p_upper; u_int p_satype, p_ext, p_alg_enc, p_alg_auth, p_replay, p_mode; @@ -79,7 +80,6 @@ extern int m_len; extern char cmdarg[8192]; extern int f_debug; -int setkeymsg __P((void)); static struct addrinfo *parse_addr __P((char *, char *, int)); static int setvarbuf __P((int *, struct sadb_ext *, int, caddr_t, int)); void parse_init __P((void)); @@ -107,7 +107,7 @@ extern void yyerror __P((const char *)); %token F_EXT EXTENSION NOCYCLICSEQ %token ALG_AUTH ALG_ENC ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_COMP %token F_LIFETIME_HARD F_LIFETIME_SOFT -%token DECSTRING QUOTEDSTRING HEXSTRING ANY +%token DECSTRING QUOTEDSTRING HEXSTRING STRING ANY /* SPD management */ %token SPDADD SPDDELETE SPDDUMP SPDFLUSH %token F_POLICY PL_REQUESTS @@ -118,7 +118,7 @@ extern void yyerror __P((const char *)); %type <num> DECSTRING %type <val> ADDRESS PL_REQUESTS %type <val> key_string policy_requests -%type <val> QUOTEDSTRING HEXSTRING +%type <val> QUOTEDSTRING HEXSTRING STRING %% commands @@ -140,6 +140,7 @@ command : add_command | get_command | delete_command + | deleteall_command | flush_command | dump_command | spdadd_command @@ -166,6 +167,16 @@ delete_command EOT ; + /* deleteall command */ +deleteall_command + : DELETEALL { p_type = SADB_DELETE; } + ipaddress { p_src = pp_addr; } + ipaddress { p_dst = pp_addr; } + protocol_spec + { p_no_spi = 1; } + EOT + ; + /* get command */ get_command : GET { p_type = SADB_GET; } @@ -327,7 +338,7 @@ auth_alg auth_key : /*NOTHING*/ { - if (p_alg_auth != SADB_AALG_NULL) { + if (p_alg_auth != SADB_X_AALG_NULL) { yyerror("no key found."); return -1; } @@ -541,10 +552,27 @@ port upper_spec : DECSTRING { p_upper = $1; } | UP_PROTO { p_upper = $1; } - | PR_ESP { p_upper = IPPROTO_ESP; }; - | PR_AH { p_upper = IPPROTO_AH; }; - | PR_IPCOMP { p_upper = IPPROTO_IPCOMP; }; | ANY { p_upper = IPSEC_ULPROTO_ANY; } + | STRING + { + struct protoent *ent; + + ent = getprotobyname($1.buf); + if (ent) + p_upper = ent->p_proto; + else { + if (strcmp("icmp6", $1.buf) == 0) { + p_upper = IPPROTO_ICMPV6; + } else if(strcmp("ip4", $1.buf) == 0) { + p_upper = IPPROTO_IPV4; + } else { + yyerror("invalid upper layer protocol"); + free($1.buf); + return -1; + } + } + free($1.buf); + } ; policy_spec @@ -665,27 +693,29 @@ setkeymsg() struct sadb_address m_addr; u_int len; - len = sizeof(struct sadb_sa); - m_sa.sadb_sa_len = PFKEY_UNIT64(len); - m_sa.sadb_sa_exttype = SADB_EXT_SA; - m_sa.sadb_sa_spi = htonl(p_spi); - m_sa.sadb_sa_replay = p_replay; - m_sa.sadb_sa_state = 0; - m_sa.sadb_sa_auth = p_alg_auth; - m_sa.sadb_sa_encrypt = p_alg_enc; - m_sa.sadb_sa_flags = p_ext; - - memcpy(m_buf + m_len, &m_sa, len); - m_len += len; + if (p_no_spi == 0) { + len = sizeof(struct sadb_sa); + m_sa.sadb_sa_len = PFKEY_UNIT64(len); + m_sa.sadb_sa_exttype = SADB_EXT_SA; + m_sa.sadb_sa_spi = htonl(p_spi); + m_sa.sadb_sa_replay = p_replay; + m_sa.sadb_sa_state = 0; + m_sa.sadb_sa_auth = p_alg_auth; + m_sa.sadb_sa_encrypt = p_alg_enc; + m_sa.sadb_sa_flags = p_ext; + + memcpy(m_buf + m_len, &m_sa, len); + m_len += len; - len = sizeof(struct sadb_x_sa2); - m_sa2.sadb_x_sa2_len = PFKEY_UNIT64(len); - m_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - m_sa2.sadb_x_sa2_mode = p_mode; - m_sa2.sadb_x_sa2_reqid = p_reqid; + len = sizeof(struct sadb_x_sa2); + m_sa2.sadb_x_sa2_len = PFKEY_UNIT64(len); + m_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + m_sa2.sadb_x_sa2_mode = p_mode; + m_sa2.sadb_x_sa2_reqid = p_reqid; - memcpy(m_buf + m_len, &m_sa2, len); - m_len += len; + memcpy(m_buf + m_len, &m_sa2, len); + m_len += len; + } /* set src */ m_addr.sadb_address_len = @@ -864,6 +894,7 @@ parse_init() { p_type = 0; p_spi = 0; + p_no_spi = 0; p_src = 0, p_dst = 0; pp_prefix = p_prefs = p_prefd = ~0; diff --git a/sbin/setkey/scriptdump.pl b/sbin/setkey/scriptdump.pl index aa36544..33907dc 100644 --- a/sbin/setkey/scriptdump.pl +++ b/sbin/setkey/scriptdump.pl @@ -33,11 +33,11 @@ foreach $_ (<IN>) { $akey =~ s/\s//g; $akey =~ s/^/0x/g; } elsif (/^\treplay=(\d+) flags=(0x\d+) state=/) { - print "$mode $src $dst $proto $spi -m $ipsecmode"; + print "$mode $src $dst $proto $spi"; $replay = $1; print " -u $reqid" if $reqid; if ($mode eq 'add') { - print " -r $replay" if $replay; + print " -m $ipsecmode -r $replay" if $replay; if ($proto eq 'esp') { print " -E $ealgo $ekey" if $ealgo; print " -A $aalgo $akey" if $aalgo; diff --git a/sbin/setkey/setkey.8 b/sbin/setkey/setkey.8 index 7921800..368fc5d 100644 --- a/sbin/setkey/setkey.8 +++ b/sbin/setkey/setkey.8 @@ -1,5 +1,5 @@ -.\" $FreeBSD$ -.\" $KAME: setkey.8,v 1.28 2000/06/16 12:03:46 sakane Exp $ +.\" $KAME: setkey.8,v 1.49 2001/05/18 05:49:51 sakane Exp $ +.\" $FreeBSD$ .\" .\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. .\" All rights reserved. @@ -28,9 +28,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd May 17, 1998 +.Dd November 20, 2000 .Dt SETKEY 8 -.Os KAME +.Os .\" .Sh NAME .Nm setkey @@ -55,7 +55,7 @@ .\" .Sh DESCRIPTION .Nm -addes, updates, dumpes, or flushes +adds, updates, dumps, or flushes Security Association Database (SAD) entries as well as Security Policy Database (SPD) entries in the kernel. .Pp @@ -94,11 +94,14 @@ it has been expired but remains because it is referenced by SPD entries. .It Fl d Enable to print debugging messages for command parser, -without talking to kernel. It is not used usually. +without talking to kernel. +It is not used usually. .It Fl x Loop forever and dump all the messages transmitted to .Dv PF_KEY socket. +.Fl xx +makes each timestamps unformatted. .It Fl h Add hexadecimal dump on .Fl x @@ -108,14 +111,13 @@ Loop forever with short output on .Fl D . .It Fl v Be verbose. +The program will dump messages exchanged on .Dv PF_KEY -socket -.Po -including messages sent from other processes -.Pc . +socket, including messages sent from other processes to the kernel. .El .Pp -Operations have the following grammar. Note that lines starting with +Operations have the following grammar. +Note that lines starting with hashmarks ('#') are treated as comment lines. .Bl -tag -width Ds .It Xo @@ -142,6 +144,13 @@ Show an SAD entry. Remove an SAD entry. .\" .It Xo +.Li deleteall +.Ar src Ar dst Ar protocol +.Li ; +.Xc +Remove all SAD entries that match the specification. +.\" +.It Xo .Li flush .Op Ar protocol .Li ; @@ -227,7 +236,7 @@ attached .\" .Pp .It Ar extensions -take some of the following: +takes some of the following: .Bl -tag -width Fl -compact .\" .It Fl m Ar mode @@ -243,39 +252,49 @@ The default value is .It Fl r Ar size Specify window size of bytes for replay prevention. .Ar size -must be decimal number in 32-bit word. If +must be decimal number in 32-bit word. +If .Ar size is zero or not specified, replay check don't take place. .\" .It Fl u Ar id -Specify the identifier of policy. See also -.Xr ipsec_set_policy 3 . +Specify the identifier of the policy entry in SPD. +See +.Ar policy . .\" .It Fl f Ar pad_option +defines the content of the ESP padding. .Ar pad_option is one of following: -.Li zero-pad , random-pad -or -.Li seq-pad +.Bl -tag -width random-pad -compact +.It Li zero-pad +All of the padding are zero. +.It Li random-pad +A series of randomized values are set. +.It Li seq-pad +A series of sequential increasing numbers started from 1 are set. +.El .\" .It Fl f Li nocyclic-seq Don't allow cyclic sequence number. .\" .It Fl lh Ar time .It Fl ls Ar time -Specify hard/soft lifetime. +Specify hard/soft life time duration of the SA. .El .\" .Pp .It Ar algorithm .Bl -tag -width Fl -compact .It Fl E Ar ealgo Ar key -Specify encryption algorithm. +Specify a encryption algorithm. .It Fl A Ar aalgo Ar key -Specify authentication algorithm. +Specify a authentication algorithm. If .Fl A -is used for esp, it will be treated as ESP payload authentication algorithm. +is used with +.Ar protocol Li esp , +it will be treated as ESP payload authentication algorithm. .It Fl C Ar calgo Op Fl R Specify compression algorithm. If @@ -302,23 +321,23 @@ field needs to be smaller than in this case. .El .Pp -.Li esp -SAs accept +.Ar protocol Li esp +accepts .Fl E and .Fl A . -.Li esp-old -SAs accept +.Ar protocol Li esp-old +accepts .Fl E only. -.Li ah +.Ar protocol Li ah and .Li ah-old -SAs accept +accept .Fl A only. -.Li ipcomp -SAs accept +.Ar protocol Li ipcomp +accepts .Fl C only. .Pp @@ -365,45 +384,57 @@ They must be in numeric form. .Pp .It Ar upperspec Upper-layer protocol to be used. -Currently -.Li icmp , +You can use one of words in +.Pa /etc/protocols +as +.Ar upperspec . +Or .Li icmp6 , .Li ip4 , -.Li tcp , -.Li udp and .Li any can be specified. .Li any stands for .Dq any protocol . +Also you can use the protocol number. .Pp NOTE: .Ar upperspec does not work against forwarding case at this moment, as it requires extra reassembly at forwarding node .Pq not implemented at this moment . +We have many protocols in +.Pa /etc/protocols , +but protocols except of TCP, UDP and ICMP may not be suitable to use with IPSec. +You have to consider and be careful to use them. +.Li icmp +.Li tcp +.Li udp +all protocols .\" .Pp .It Ar policy .Ar policy is the one of following: -.Pp -.Bl -item -compact -.It +.Bd -literal -offset +.Xo .Fl P .Ar direction .Li discard -.It +.Xc +.Xo .Fl P .Ar direction .Li none -.It +.Xc +.Xo .Fl P .Ar direction .Li ipsec .Ar protocol/mode/src-dst/level -.El +.Xc +.Ed .Pp You must specify the direction of its policy as .Ar direction . @@ -430,18 +461,33 @@ is either .Li transport or .Li tunnel . -You must specify the end-points addresses of the SA as +If +.Ar mode +is +.Li tunnel , +you must specify the end-points addresses of the SA as .Ar src and .Ar dst with .Sq - between these addresses which is used to specify the SA to use. +If +.Ar mode +is +.Li transport , +both +.Ar src +and +.Ar dst +can be omited. .Ar level is to be one of the following: -.Li default , use +.Li default , use , require or -.Li require . +.Li unique . +If the SA is not available in every level, the kernel will request +getting SA to the key exchange daemon. .Li default means the kernel consults to the system wide default against protocol you specified, e.g. @@ -451,7 +497,23 @@ sysctl variable, when the kernel processes the packet. means that the kernel use a SA if it's available, otherwise the kernel keeps normal operation. .Li require -means SA is required whenever the kernel deals with the packet. +means SA is required whenever the kernel sends a packet matched +with the policy. +.Li unique +is the same to require. +In addition, it allows the policy to bind with the unique out-bound SA. +If you use the SA by manual keying, +you can put the decimal number as the policy identifier after +.Li unique +separated by colon +.Sq \: +like the following; +.Li unique:number . +.Li number +must be between 1 and 32767. +It corresponds to +.Ar extensions Fl u . +.Pp Note that .Dq Li discard and @@ -491,6 +553,12 @@ keyed-md5 128 ah: 96bit ICV (no document) keyed-sha1 160 ah: 96bit ICV (no document) 160 ah-old: 128bit ICV (no document) null 0 to 2048 for debugging +hmac-sha2-256 256 ah: 96bit ICV (no document) + 256 ah-old: 128bit ICV (no document) +hmac-sha2-384 384 ah: 96bit ICV (no document) + 384 ah-old: 128bit ICV (no document) +hmac-sha2-512 512 ah: 96bit ICV (no document) + 512 ah-old: 128bit ICV (no document) .Ed .Pp Followings are the list of encryption algorithms that can be used as @@ -508,9 +576,9 @@ des-cbc 64 esp-old: rfc1829, esp: rfc2405 simple 0 to 2048 rfc2410 blowfish-cbc 40 to 448 rfc2451 cast128-cbc 40 to 128 rfc2451 -rc5-cbc 40 to 2040 rfc2451 des-deriv 64 ipsec-ciph-des-derived-01 (expired) 3des-deriv 192 no document +rijndael-cbc 128/192/256 draft-ietf-ipsec-ciph-aes-cbc-00 .Ed .Pp Followings are the list of compression algorithms that can be used as @@ -555,7 +623,8 @@ The command exits with 0 on success, and non-zero on errors. .\" .Sh SEE ALSO .Xr ipsec_set_policy 3 , -.Xr sysctl 8 +.Xr sysctl 8 , +.Xr racoon 8 .\" .Sh HISTORY The diff --git a/sbin/setkey/setkey.c b/sbin/setkey/setkey.c index b1e1c1e..e729e7d 100644 --- a/sbin/setkey/setkey.c +++ b/sbin/setkey/setkey.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: setkey.c,v 1.14 2000/06/10 06:47:09 sakane Exp $ */ +/* $KAME: setkey.c,v 1.18 2001/05/08 04:36:39 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -63,6 +63,8 @@ int postproc __P((struct sadb_msg *, int)); const char *numstr __P((int)); void shortdump_hdr __P((void)); void shortdump __P((struct sadb_msg *)); +static void printdate __P((void)); +static int32_t gmt2local __P((time_t)); #define MODE_SCRIPT 1 #define MODE_CMDDUMP 2 @@ -79,11 +81,14 @@ int f_mode = 0; int f_cmddump = 0; int f_policy = 0; int f_hexdump = 0; +int f_tflag = 0; char *pname; u_char m_buf[BUFSIZ]; u_int m_len; +static time_t thiszone; + extern int lineno; extern int parse __P((FILE **)); @@ -112,7 +117,9 @@ main(ac, av) if (ac == 1) Usage(); - while ((c = getopt(ac, av, "acdf:hlvxDFP")) != EOF) { + thiszone = gmt2local(0); + + while ((c = getopt(ac, av, "acdf:hlvxDFP")) != -1) { switch (c) { case 'c': f_mode = MODE_SCRIPT; @@ -142,6 +149,7 @@ main(ac, av) break; case 'x': f_mode = MODE_PROMISC; + f_tflag++; break; case 'P': f_policy = 1; @@ -199,7 +207,7 @@ get_supported() if (f_debug) return 0; - if (pfkey_send_register(so, PF_UNSPEC) < 0) + if (pfkey_send_register(so, SADB_SATYPE_UNSPEC) < 0) return -1; if (pfkey_recv_register(so) < 0) @@ -275,6 +283,7 @@ promisc() err(1, "recv"); /*NOTREACHED*/ } + printdate(); if (f_hexdump) { int i; for (i = 0; i < len; i++) { @@ -541,7 +550,7 @@ shortdump(msg) snprintf(buf, sizeof(buf), "%-3lu", (u_long)t); printf("%s", buf); } else - printf(" ???/???"); + printf(" ??\?/???"); /* backslash to avoid trigraph ??/ */ printf(" "); @@ -576,3 +585,64 @@ shortdump(msg) printf("\n"); } + +/* From: tcpdump(1):gmt2local.c and util.c */ +/* + * Print the timestamp + */ +static void +printdate() +{ + struct timeval tp; + int s; + + if (gettimeofday(&tp, NULL) == -1) { + perror("gettimeofday"); + return; + } + + if (f_tflag == 1) { + /* Default */ + s = (tp.tv_sec + thiszone ) % 86400; + (void)printf("%02d:%02d:%02d.%06u ", + s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tp.tv_usec); + } else if (f_tflag > 1) { + /* Unix timeval style */ + (void)printf("%u.%06u ", + (u_int32_t)tp.tv_sec, (u_int32_t)tp.tv_usec); + } + + printf("\n"); +} + +/* + * Returns the difference between gmt and local time in seconds. + * Use gmtime() and localtime() to keep things simple. + */ +int32_t +gmt2local(time_t t) +{ + register int dt, dir; + register struct tm *gmt, *loc; + struct tm sgmt; + + if (t == 0) + t = time(NULL); + gmt = &sgmt; + *gmt = *gmtime(&t); + loc = localtime(&t); + dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + + (loc->tm_min - gmt->tm_min) * 60; + + /* + * If the year or julian day is different, we span 00:00 GMT + * and must add or subtract a day. Check the year first to + * avoid problems when the julian day wraps. + */ + dir = loc->tm_year - gmt->tm_year; + if (dir == 0) + dir = loc->tm_yday - gmt->tm_yday; + dt += dir * 24 * 60 * 60; + + return (dt); +} diff --git a/sbin/setkey/token.l b/sbin/setkey/token.l index c2eaad5..208196e 100644 --- a/sbin/setkey/token.l +++ b/sbin/setkey/token.l @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: token.l,v 1.13 2000/06/07 00:29:14 itojun Exp $ */ +/* $KAME: token.l,v 1.21 2001/05/18 05:35:01 sakane Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -47,7 +47,11 @@ #include <unistd.h> #include <errno.h> #include "vchar.h" +#ifdef __NetBSD__ +#include "parse.h" +#else #include "y.tab.h" +#endif #define DECHO \ if (f_debug) {printf("<%d>", yy_start); ECHO ; printf("\n"); } @@ -121,6 +125,7 @@ hostname {name}(({dot}{name})+{dot}?)? add { PREPROC; return(ADD); } delete { PREPROC; return(DELETE); } +deleteall { PREPROC; return(DELETEALL); } get { PREPROC; return(GET); } flush { PREPROC; return(FLUSH); } dump { PREPROC; return(DUMP); } @@ -160,20 +165,23 @@ ipcomp { PREPROC; yylval.num = 0; return(PR_IPCOMP); } {hyphen}A { PREPROC; return(F_AUTH); } hmac-md5 { PREPROC; yylval.num = SADB_AALG_MD5HMAC; return(ALG_AUTH); } hmac-sha1 { PREPROC; yylval.num = SADB_AALG_SHA1HMAC; return(ALG_AUTH); } -keyed-md5 { PREPROC; yylval.num = SADB_AALG_MD5; return(ALG_AUTH); } -keyed-sha1 { PREPROC; yylval.num = SADB_AALG_SHA; return(ALG_AUTH); } -null { PREPROC; yylval.num = SADB_AALG_NULL; return(ALG_AUTH); } +keyed-md5 { PREPROC; yylval.num = SADB_X_AALG_MD5; return(ALG_AUTH); } +keyed-sha1 { PREPROC; yylval.num = SADB_X_AALG_SHA; return(ALG_AUTH); } +hmac-sha2-256 { PREPROC; yylval.num = SADB_X_AALG_SHA2_256; return(ALG_AUTH); } +hmac-sha2-384 { PREPROC; yylval.num = SADB_X_AALG_SHA2_384; return(ALG_AUTH); } +hmac-sha2-512 { PREPROC; yylval.num = SADB_X_AALG_SHA2_512; return(ALG_AUTH); } +null { PREPROC; yylval.num = SADB_X_AALG_NULL; return(ALG_AUTH); } /* encryption alogorithm */ {hyphen}E { PREPROC; return(F_ENC); } des-cbc { PREPROC; yylval.num = SADB_EALG_DESCBC; return(ALG_ENC); } 3des-cbc { PREPROC; yylval.num = SADB_EALG_3DESCBC; return(ALG_ENC); } simple { PREPROC; yylval.num = SADB_EALG_NULL; return(ALG_ENC); } -blowfish-cbc { PREPROC; yylval.num = SADB_EALG_BLOWFISHCBC; return(ALG_ENC); } -cast128-cbc { PREPROC; yylval.num = SADB_EALG_CAST128CBC; return(ALG_ENC); } -rc5-cbc { PREPROC; yylval.num = SADB_EALG_RC5CBC; return(ALG_ENC); } +blowfish-cbc { PREPROC; yylval.num = SADB_X_EALG_BLOWFISHCBC; return(ALG_ENC); } +cast128-cbc { PREPROC; yylval.num = SADB_X_EALG_CAST128CBC; return(ALG_ENC); } des-deriv { PREPROC; yylval.num = SADB_EALG_DESCBC; return(ALG_ENC_DESDERIV); } des-32iv { PREPROC; yylval.num = SADB_EALG_DESCBC; return(ALG_ENC_DES32IV); } +rijndael-cbc { PREPROC; yylval.num = SADB_X_EALG_RIJNDAELCBC; return(ALG_ENC); } /* compression algorithms */ {hyphen}C { PREPROC; return(F_COMP); } @@ -196,14 +204,6 @@ nocyclic-seq { PREPROC; return(NOCYCLICSEQ); } {hyphen}lh { PREPROC; return(F_LIFETIME_HARD); } {hyphen}ls { PREPROC; return(F_LIFETIME_SOFT); } - - /* upper layer protocols */ -icmp { PREPROC; yylval.num = IPPROTO_ICMP; return(UP_PROTO); } -icmp6 { PREPROC; yylval.num = IPPROTO_ICMPV6; return(UP_PROTO); } -ip4 { PREPROC; yylval.num = IPPROTO_IPV4; return(UP_PROTO); } -tcp { PREPROC; yylval.num = IPPROTO_TCP; return(UP_PROTO); } -udp { PREPROC; yylval.num = IPPROTO_UDP; return(UP_PROTO); } - /* ... */ any { PREPROC; return(ANY); } {ws} { PREPROC; } @@ -277,6 +277,12 @@ any { PREPROC; return(ANY); } return(QUOTEDSTRING); } +[a-z0-9.\-]* { + yylval.val.len = yyleng; + yylval.val.buf = strdup(yytext); + return(STRING); + } + . { yyfatal("Syntax error"); /*NOTREACHED*/ |