diff options
39 files changed, 3067 insertions, 1487 deletions
diff --git a/include/Makefile b/include/Makefile index e65d38e8c9e5..752d2d54564c 100644 --- a/include/Makefile +++ b/include/Makefile @@ -10,7 +10,7 @@ CLEANFILES= osreldate.h version vers.c SUBDIR= rpcsvc FILES= a.out.h ar.h assert.h bitstring.h ctype.h db.h dirent.h disktab.h \ dlfcn.h elf.h err.h fnmatch.h fstab.h \ - fts.h glob.h grp.h strhash.h histedit.h ieeefp.h iso646.h \ + fts.h glob.h grp.h strhash.h histedit.h ieeefp.h ifaddrs.h iso646.h \ limits.h link.h locale.h malloc.h memory.h mpool.h \ ndbm.h netdb.h nl_types.h nlist.h objformat.h \ paths.h pthread.h pthread_np.h pwd.h \ diff --git a/lib/libc/net/Makefile.inc b/lib/libc/net/Makefile.inc index 22c40109b8a2..1d3ab660da73 100644 --- a/lib/libc/net/Makefile.inc +++ b/lib/libc/net/Makefile.inc @@ -6,7 +6,7 @@ SRCS+= addr2ascii.c ascii2addr.c base64.c ether_addr.c getaddrinfo.c \ gethostbydns.c gethostbyht.c gethostbynis.c gethostnamadr.c \ - getnameinfo.c \ + getifaddrs.c getnameinfo.c \ getnetbydns.c getnetbyht.c getnetbynis.c getnetnamadr.c \ getproto.c getprotoent.c getprotoname.c getservbyname.c \ getservbyport.c getservent.c herror.c inet_addr.c ifname.c \ @@ -28,7 +28,7 @@ CFLAGS+=-DINET6 .if ${LIB} == "c" MAN3+= addr2ascii.3 byteorder.3 ethers.3 getaddrinfo.3 gethostbyname.3 \ - getipnodebyname.3 \ + getifaddrs.3 getipnodebyname.3 \ getnameinfo.3 getnetent.3 getprotoent.3 getservent.3 if_indextoname.3 \ inet.3 inet6_option_space.3 inet6_rthdr_space.3 linkaddr.3 \ rcmd.3 resolver.3 @@ -44,6 +44,7 @@ MLINKS+=gethostbyname.3 endhostent.3 gethostbyname.3 gethostbyaddr.3 \ gethostbyname.3 gethostbyname2.3 gethostbyname.3 gethostent.3 \ gethostbyname.3 herror.3 gethostbyname.3 hstrerror.3 \ gethostbyname.3 sethostent.3 +MLINKS+=getifaddrs.3 freeifaddrs.3 MLINKS+=getipnodebyname.3 getipnodebyaddr.3 getipnodebyname.3 freehostent.3 MLINKS+=getnetent.3 endnetent.3 getnetent.3 getnetbyaddr.3 \ getnetent.3 getnetbyname.3 getnetent.3 setnetent.3 diff --git a/lib/libc/net/getaddrinfo.3 b/lib/libc/net/getaddrinfo.3 index fd4b6d154b13..2e608cd18ae2 100644 --- a/lib/libc/net/getaddrinfo.3 +++ b/lib/libc/net/getaddrinfo.3 @@ -1,4 +1,7 @@ .\" Copyright (c) 1983, 1987, 1991, 1993 +.\" $FreeBSD$ +.\" $KAME: getaddrinfo.3,v 1.16 2000/07/05 08:18:42 itojun Exp $ +.\" .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -30,15 +33,13 @@ .\" SUCH DAMAGE. .\" .\" From: @(#)gethostbyname.3 8.4 (Berkeley) 5/25/95 -.\" $Id: getaddrinfo.3,v 1.3 1999/10/07 08:22:04 jinmei Exp $ -.\" $FreeBSD$ .\" .Dd May 25, 1995 .Dt GETADDRINFO 3 .Os KAME .\" .Sh NAME -.Nm getaddrinfo +.Nm getaddrinfo , .Nm freeaddrinfo , .Nm gai_strerror .Nd nodename-to-address translation in protocol-independent manner @@ -50,7 +51,8 @@ .Fd #include <sys/socket.h> .Fd #include <netdb.h> .Ft int -.Fn getaddrinfo "const char *nodename" "const char *servname" "const struct addrinfo *hints" "struct addrinfo **res" +.Fn getaddrinfo "const char *nodename" "const char *servname" \ +"const struct addrinfo *hints" "struct addrinfo **res" .Ft void .Fn freeaddrinfo "struct addrinfo *ai" .Ft "char *" @@ -60,14 +62,16 @@ The .Fn getaddrinfo function is defined for protocol-independent nodename-to-address translation. -It performs functionality of +It performs the functionality of .Xr gethostbyname 3 and .Xr getservbyname 3 , -in more sophisticated manner. +but in a more sophisticated manner. .Pp -The addrinfo structure is defined as a result of including the -.Li <netdb.h> +The +.Li addrinfo +structure is defined as a result of including the +.Aq Pa netdb.h header: .Bd -literal -offset struct addrinfo { * @@ -161,7 +165,8 @@ pointer, this is the same as if the caller had filled in an .Li addrinfo structure initialized to zero with .Fa ai_family -set to PF_UNSPEC. +set to +.Dv PF_UNSPEC . .Pp Upon successful return a pointer to a linked list of one or more .Li addrinfo @@ -224,7 +229,8 @@ call to .Pq for a connection-oriented protocol or either .Fn connect , -.Fn sendto , or +.Fn sendto , +or .Fn sendmsg .Pq for a connectionless protocol . In this case, if the @@ -269,7 +275,7 @@ All of the information returned by is dynamically allocated: the .Li addrinfo -structures, and the socket address structures and canonical node name +structures, the socket address structures, and canonical node name strings pointed to by the addrinfo structures. To return this information to the system the function .Fn freeaddrinfo @@ -316,7 +322,7 @@ such as .Li ne0 .Pc . Example would be like -.Dq Li fe80::1@ne0 , +.Dq Li fe80::1%ne0 , which means .Do .Li fe80::1 @@ -329,6 +335,105 @@ The implementation is still very experimental and non-standard. The current implementation assumes one-by-one relationship between interface and link, which is not necessarily true from the specification. .\" +.Sh EXAMPLES +The following code tries to connect to +.Dq Li www.kame.net +service +.Dq Li http . +via stream socket. +It loops through all the addresses available, regardless from address family. +If the destination resolves to IPv4 address, it will use +.Dv AF_INET +socket. +Similarly, if it resolves to IPv6, +.Dv AF_INET6 +socket is used. +Observe that there is no hardcoded reference to particular address family. +The code works even if +.Nm getaddrinfo +returns addresses that are not IPv4/v6. +.Bd -literal -offset indent +struct addrinfo hints, *res, *res0; +int error; +int s; +const char *cause = NULL; + +memset(&hints, 0, sizeof(hints)); +hints.ai_family = PF_UNSPEC; +hints.ai_socktype = SOCK_STREAM; +error = getaddrinfo("www.kame.net", "http", &hints, &res0); +if (error) { + err1(1, "%s", gai_strerror(error)); + /*NOTREACHED*/ +} +s = -1; +for (res = res0; res; res = res->ai_next) { + s = socket(res->ai_family, res->ai_socktype, + res->ai_protocol); + if (s < 0) { + cause = "socket"; + continue; + } + + if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { + cause = "connect"; + close(s); + s = -1; + continue; + } + + break; /* okay we got one */ +} +if (s < 0) { + err(1, cause); + /*NOTREACHED*/ +} +freeaddrinfo(res0); +.Ed +.Pp +The following example tries to open wildcard listening socket onto service +.Dq Li http , +for all the address families available. +.Bd -literal -offset indent +struct addrinfo hints, *res, *res0; +int error; +int s[MAXSOCK]; +int nsock; +const char *cause = NULL; + +memset(&hints, 0, sizeof(hints)); +hints.ai_family = PF_UNSPEC; +hints.ai_socktype = SOCK_STREAM; +hints.ai_flags = AI_PASSIVE; +error = getaddrinfo(NULL, "http", &hints, &res0); +if (error) { + err1(1, "%s", gai_strerror(error)); + /*NOTREACHED*/ +} +nsock = 0; +for (res = res0; res && nsock < MAXSOCK; res = res->ai_next) { + s[nsock] = socket(res->ai_family, res->ai_socktype, + res->ai_protocol); + if (s[nsock] < 0) { + cause = "socket"; + continue; + } + + if (connect(s[nsock], res->ai_addr, res->ai_addrlen) < 0) { + cause = "connect"; + close(s[nsock]); + continue; + } + + nsock++; +} +if (nsock == 0) { + err(1, cause); + /*NOTREACHED*/ +} +freeaddrinfo(res0); +.Ed +.\" .Sh FILES .Bl -tag -width /etc/resolv.conf -compact .It Pa /etc/hosts @@ -341,32 +446,44 @@ Error return status from .Fn getaddrinfo is zero on success and non-zero on errors. Non-zero error codes are defined in -.Li <netdb.h> , +.Aq Pa netdb.h , and as follows: .Pp .Bl -tag -width EAI_ADDRFAMILY -compact .It Dv EAI_ADDRFAMILY -address family for nodename not supported +Address family for +.Fa nodename +not supported. .It Dv EAI_AGAIN -temporary failure in name resolution +Temporary failure in name resolution. .It Dv EAI_BADFLAGS -invalid value for ai_flags +Invalid value for +.Fa ai_flags . .It Dv EAI_FAIL -non-recoverable failure in name resolution +Non-recoverable failure in name resolution. .It Dv EAI_FAMILY -ai_family not supported +.Fa ai_family +not supported. .It Dv EAI_MEMORY -memory allocation failure +Memory allocation failure. .It Dv EAI_NODATA -no address associated with nodename +No address associated with +.Fa nodename . .It Dv EAI_NONAME -nodename nor servname provided, or not known +.Fa nodename +nor +.Fa servname +provided, or not known. .It Dv EAI_SERVICE -servname not supported for ai_socktype +.Fa servname +not supported for +.Fa ai_socktype . .It Dv EAI_SOCKTYPE -ai_socktype not supported +.Fa ai_socktype +not supported. .It Dv EAI_SYSTEM -system error returned in errno +System error returned in +.Va errno . .El .Pp If called with proper argument, @@ -384,7 +501,7 @@ indicate an unknown error. .Xr hosts 5 , .Xr services 5 , .Xr hostname 7 , -.Xr named 8 . +.Xr named 8 .Pp .Rs .%A R. Gilligan @@ -395,6 +512,20 @@ indicate an unknown error. .%R RFC2553 .%D March 1999 .Re +.Rs +.%A Tatsuya Jinmei +.%A Atsushi Onoe +.%T "An Extension of Format for IPv6 Scoped Addresses" +.%R internet draft +.%N draft-ietf-ipngwg-scopedaddr-format-02.txt +.%O work in progress material +.Re +.Rs +.%A Craig Metz +.%T Protocol Independence Using the Sockets API +.%B "Proceedings of the freenix track: 2000 USENIX annual technical conference" +.%D June 2000 +.Re .\" .Sh HISTORY The implementation first appeared in WIDE Hydrangea IPv6 protocol stack kit. @@ -403,8 +534,9 @@ The implementation first appeared in WIDE Hydrangea IPv6 protocol stack kit. The .Fn getaddrinfo function is defined IEEE POSIX 1003.1g draft specification, -and documented in ``Basic Socket Interface Extensions for IPv6'' -.Pq RFC2533 . +and documented in +.Dq Basic Socket Interface Extensions for IPv6 +.Pq RFC2553 . .\" .Sh BUGS The text was shamelessly copied from RFC2553. diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c index af7964493bc2..f44a14d79919 100644 --- a/lib/libc/net/getaddrinfo.c +++ b/lib/libc/net/getaddrinfo.c @@ -1,3 +1,6 @@ +/* $FreeBSD$ */ +/* $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -25,8 +28,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ /* @@ -195,7 +196,7 @@ typedef union { struct res_target { struct res_target *next; const char *name; /* domain name */ - int class, type; /* class and type of query */ + int qclass, qtype; /* class and type of query */ u_char *answer; /* buffer to put answer */ int anslen; /* size of answer buffer */ int n; /* result length */ @@ -256,7 +257,9 @@ static char *ai_errlist[] = { "System error returned in errno", /* EAI_SYSTEM */ "Invalid value for hints", /* EAI_BADHINTS */ "Resolved protocol is unknown", /* EAI_PROTOCOL */ +#ifdef EAI_RESNULL "Argument res is NULL", /* EAI_RESNULL */ +#endif "Unknown error", /* EAI_MAX */ }; @@ -356,13 +359,16 @@ static int str_isnumber(p) const char *p; { - const char *q = (const char *)p; - while (*q) { - if (!isdigit(*q)) - return NO; - q++; - } - return YES; + char *ep; + + if (*p == '\0') + return NO; + ep = NULL; + (void)strtoul(p, &ep, 10); + if (ep && *ep == '\0') + return YES; + else + return NO; } int @@ -393,8 +399,10 @@ getaddrinfo(hostname, servname, hints, res) if (hostname == NULL && servname == NULL) return EAI_NONAME; +#ifdef EAI_RESNULL if (res == NULL) return EAI_RESNULL; /* xxx */ +#endif if (hints) { /* error check for hints */ if (hints->ai_addrlen || hints->ai_canonname || @@ -529,9 +537,9 @@ getaddrinfo(hostname, servname, hints, res) goto good; if (pai->ai_flags & AI_NUMERICHOST) - ERR(EAI_NONAME); + ERR(EAI_NODATA); if (hostname == NULL) - ERR(EAI_NONAME); + ERR(EAI_NODATA); #if 1 /* XXX: temporarily, behave as if AI_ADDRCONFIG is specified */ @@ -812,17 +820,33 @@ explore_numeric(pai, hostname, servname, res) if (afd == NULL) return 0; - if ((afd->a_af == AF_INET - ? inet_aton(hostname, (struct in_addr *)pton) - : inet_pton(afd->a_af, hostname, pton)) == 1) { - if (pai->ai_family == afd->a_af || - pai->ai_family == PF_UNSPEC /*?*/) { - GET_AI(cur->ai_next, afd, pton); - GET_PORT(cur->ai_next, servname); - while (cur && cur->ai_next) - cur = cur->ai_next; - } else - ERR(EAI_FAMILY); /*xxx*/ + switch (afd->a_af) { +#if 1 /*X/Open spec*/ + case AF_INET: + if (inet_aton(hostname, (struct in_addr *)pton) == 1) { + if (pai->ai_family == afd->a_af || + pai->ai_family == PF_UNSPEC /*?*/) { + GET_AI(cur->ai_next, afd, pton); + GET_PORT(cur->ai_next, servname); + while (cur && cur->ai_next) + cur = cur->ai_next; + } else + ERR(EAI_FAMILY); /*xxx*/ + } + break; +#endif + default: + if (inet_pton(afd->a_af, hostname, pton) == 1) { + if (pai->ai_family == afd->a_af || + pai->ai_family == PF_UNSPEC /*?*/) { + GET_AI(cur->ai_next, afd, pton); + GET_PORT(cur->ai_next, servname); + while (cur && cur->ai_next) + cur = cur->ai_next; + } else + ERR(EAI_FAMILY); /*xxx*/ + } + break; } *res = sentinel.ai_next; @@ -891,7 +915,7 @@ explore_numeric_scope(pai, hostname, servname, res) sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; if ((scopeid = ip6_str2scopeid(scope, sin6)) == -1) { free(hostname2); - return(EAI_NONAME); /* XXX: is return OK? */ + return(EAI_NODATA); /* XXX: is return OK? */ } sin6->sin6_scope_id = scopeid; } @@ -1150,6 +1174,10 @@ ip6_str2scopeid(scope, sin6) struct in6_addr *a6 = &sin6->sin6_addr; char *ep; + /* empty scopeid portion is invalid */ + if (*scope == '\0') + return -1; + if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { /* * We currently assume a one-to-one mapping between links @@ -1406,25 +1434,25 @@ _dns_getaddrinfo(pai, hostname, res) switch (pai->ai_family) { case AF_UNSPEC: /* prefer IPv6 */ - q.class = C_IN; - q.type = T_AAAA; + q.qclass = C_IN; + q.qtype = T_AAAA; q.answer = buf.buf; q.anslen = sizeof(buf); q.next = &q2; - q2.class = C_IN; - q2.type = T_A; + q2.qclass = C_IN; + q2.qtype = T_A; q2.answer = buf2.buf; q2.anslen = sizeof(buf2); break; case AF_INET: - q.class = C_IN; - q.type = T_A; + q.qclass = C_IN; + q.qtype = T_A; q.answer = buf.buf; q.anslen = sizeof(buf); break; case AF_INET6: - q.class = C_IN; - q.type = T_AAAA; + q.qclass = C_IN; + q.qtype = T_AAAA; q.answer = buf.buf; q.anslen = sizeof(buf); break; @@ -1433,14 +1461,14 @@ _dns_getaddrinfo(pai, hostname, res) } if (res_searchN(hostname, &q) < 0) return EAI_NODATA; - ai = getanswer(&buf, q.n, q.name, q.type, pai); + ai = getanswer(&buf, q.n, q.name, q.qtype, pai); if (ai) { cur->ai_next = ai; while (cur && cur->ai_next) cur = cur->ai_next; } if (q.next) { - ai = getanswer(&buf2, q2.n, q2.name, q2.type, pai); + ai = getanswer(&buf2, q2.n, q2.name, q2.qtype, pai); if (ai) cur->ai_next = ai; } @@ -1672,8 +1700,8 @@ res_queryN(name, target) hp->rcode = NOERROR; /* default */ /* make it easier... */ - class = t->class; - type = t->type; + class = t->qclass; + type = t->qtype; answer = t->answer; anslen = t->anslen; #ifdef DEBUG diff --git a/lib/libc/net/getnameinfo.3 b/lib/libc/net/getnameinfo.3 index 84b98cb025dd..0b4785724eb1 100644 --- a/lib/libc/net/getnameinfo.3 +++ b/lib/libc/net/getnameinfo.3 @@ -1,3 +1,6 @@ +.\" $FreeBSD$ +.\" $KAME: getnameinfo.3,v 1.16 2000/07/05 08:22:04 itojun Exp $ +.\" .\" Copyright (c) 1983, 1987, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" @@ -30,8 +33,6 @@ .\" SUCH DAMAGE. .\" .\" From: @(#)gethostbyname.3 8.4 (Berkeley) 5/25/95 -.\" $Id: getnameinfo.3,v 1.2 1999/10/07 04:46:27 itojun Exp $ -.\" $FreeBSD$ .\" .Dd May 25, 1995 .Dt GETNAMEINFO 3 @@ -48,7 +49,8 @@ .Fd #include <sys/socket.h> .Fd #include <netdb.h> .Ft int -.Fn getnameinfo "const struct sockaddr *sa" "socklen_t salen" "char *host" "size_t hostlen" "char *serv" "size_t servlen" "int flags" +.Fn getnameinfo "const struct sockaddr *sa" "socklen_t salen" \ +"char *host" "size_t hostlen" "char *serv" "size_t servlen" "int flags" .\" .Sh DESCRIPTION The @@ -70,16 +72,16 @@ a non-zero return value indicates failure. The first argument, .Fa sa , points to either a -.Fa sockaddr_in +.Li sockaddr_in structure (for IPv4) or a -.Fa sockaddr_in6 +.Li sockaddr_in6 structure (for IPv6) that holds the IP address and port number. The .Fa salen argument gives the length of the -.Fa sockaddr_in +.Li sockaddr_in or -.Fa sockaddr_in6 +.Li sockaddr_in6 structure. .Pp The function returns the nodename associated with the IP address in @@ -102,22 +104,22 @@ or .Fa servlen arguments. Otherwise, the caller must provide buffers large enough to hold the -nodename and the service name, including the terminating null characters. +nodename and the service name, including the terminating null characters. .Pp Unfortunately most systems do not provide constants that specify the maximum size of either a fully-qualified domain name or a service name. Therefore to aid the application in allocating buffers for these two returned strings the following constants are defined in -.Li <netdb.h> : +.Aq Pa netdb.h : .Bd -literal -offset -#define NI_MAXHOST 1025 -#define NI_MAXSERV 32 +#define NI_MAXHOST 1025 +#define NI_MAXSERV 32 .Ed .Pp The first value is actually defined as the constant .Dv MAXDNAME in recent versions of BIND's -.Li <arpa/nameser.h> +.Aq Pa arpa/nameser.h header .Po older versions of BIND define this constant to be 256 @@ -160,27 +162,30 @@ instead of its name. The two .Dv NI_NUMERICxxx flags are required to support the -.Li "-n" +.Fl n flag that many commands provide. .Pp A fifth flag bit, .Dv NI_DGRAM , specifies that the service is a datagram service, and causes .Fn getservbyport -to be called with a second argument of "udp" instead of its default of "tcp". +to be called with a second argument of +.Dq udp +instead of its default of +.Dq tcp . This is required for the few ports (512-514) that have different services for UDP and TCP. .Pp These .Dv NI_xxx flags are defined in -.Li <netdb.h> . +.Aq Pa netdb.h . .\" .Sh EXTENSION The implementation allows experimental numeric IPv6 address notation with scope identifier. IPv6 link-local address will appear as string like -.Dq Li fe80::1@ne0 , +.Dq Li fe80::1%ne0 , if .Dv NI_WITHSCOPEID bit is enabled in @@ -190,6 +195,35 @@ Refer to .Xr getaddrinfo 3 for the notation. .\" +.Sh EXAMPLES +The following code tries to get numeric hostname, and service name, +for given socket address. +Observe that there is no hardcoded reference to particular address family. +.Bd -literal -offset indent +struct sockaddr *sa; /* input */ +char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + +if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), sbuf, + sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)) { + errx(1, "could not get numeric hostname"); + /*NOTREACHED*/ +} +printf("host=%s, serv=%s\\n", hbuf, sbuf); +.Ed +.Pp +The following version checks if the socket address has reverse address mapping. +.Bd -literal -offset indent +struct sockaddr *sa; /* input */ +char hbuf[NI_MAXHOST]; + +if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, + NI_NAMEREQD)) { + errx(1, "could not resolve hostname"); + /*NOTREACHED*/ +} +printf("host=%s\\n", hbuf); +.Ed +.\" .Sh FILES .Bl -tag -width /etc/resolv.conf -compact .It Pa /etc/hosts @@ -200,6 +234,29 @@ for the notation. .Sh DIAGNOSTICS The function indicates successful completion by a zero return value; a non-zero return value indicates failure. +Error codes are as below: +.Bl -tag -width Er +.It Bq Er EAI_AGAIN +The name could not be resolved at this time. +Future attempts may succeed. +.It Bq Er EAI_BADFLAGS +The flags had an invalid value. +.It Bq Er EAI_FAIL +A non-recoverable error occurred. +.It Bq Er EAI_FAMILY +The address family was not recognized or the address length was invalid +for the specified family. +.It Bq Er EAI_MEMORY +There was a memory allocation failure. +.It Bq Er EAI_NONAME +The name does not resolve for the supplied parameters. +.Dv NI_NAMEREQD +is set and the host's name cannot be located, +or both nodename and servname were null. +.It Bq Er EAI_SYSTEM +A system error occurred. +The error code can be found in errno. +.El .\" .Sh SEE ALSO .Xr getaddrinfo 3 , @@ -219,6 +276,20 @@ a non-zero return value indicates failure. .%R RFC2553 .%D March 1999 .Re +.Rs +.%A Tatsuya Jinmei +.%A Atsushi Onoe +.%T "An Extension of Format for IPv6 Scoped Addresses" +.%R internet draft +.%N draft-ietf-ipngwg-scopedaddr-format-02.txt +.%O work in progress material +.Re +.Rs +.%A Craig Metz +.%T Protocol Independence Using the Sockets API +.%B "Proceedings of the freenix track: 2000 USENIX annual technical conference" +.%D June 2000 +.Re .\" .Sh HISTORY The implementation first appeared in WIDE Hydrangea IPv6 protocol stack kit. @@ -227,8 +298,14 @@ The implementation first appeared in WIDE Hydrangea IPv6 protocol stack kit. The .Fn getaddrinfo function is defined IEEE POSIX 1003.1g draft specification, -and documented in ``Basic Socket Interface Extensions for IPv6'' -.Pq RFC2533 . +and documented in +.Dq Basic Socket Interface Extensions for IPv6 +.Pq RFC2553 . .\" .Sh BUGS The text was shamelessly copied from RFC2553. +.Pp +The type of the 2nd argument should be +.Li socklen_t +for RFC2553 conformance. +The current code is based on pre-RFC2553 specification. diff --git a/lib/libc/net/getnameinfo.c b/lib/libc/net/getnameinfo.c index 5edcffb9498c..2dbd81fe2d52 100644 --- a/lib/libc/net/getnameinfo.c +++ b/lib/libc/net/getnameinfo.c @@ -1,3 +1,6 @@ +/* $FreeBSD$ */ +/* $KAME: getnameinfo.c,v 1.43 2000/06/12 04:27:03 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -25,8 +28,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ /* @@ -34,6 +35,13 @@ * - Thread safe-ness must be checked * - Return values. There seems to be no standard for return value (RFC2553) * but INRIA implementation returns EAI_xxx defined for getaddrinfo(). + * - RFC2553 says that we should raise error on short buffer. X/Open says + * we need to truncate the result. We obey RFC2553 (and X/Open should be + * modified). + * - What is "local" in NI_FQDN? + * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other. + * - (KAME extension) NI_WITHSCOPEID when called with global address, + * and sin6_scope_id filled */ #include <sys/types.h> @@ -46,11 +54,12 @@ #include <resolv.h> #include <string.h> #include <stddef.h> +#include <errno.h> -#define SUCCESS 0 -#define ANY 0 -#define YES 1 -#define NO 0 +#define SUCCESS 0 +#define ANY 0 +#define YES 1 +#define NO 0 static struct afd { int a_af; @@ -73,13 +82,19 @@ struct sockinet { u_short si_port; }; -#define ENI_NOSOCKET 0 -#define ENI_NOSERVHOST 1 -#define ENI_NOHOSTNAME 2 -#define ENI_MEMORY 3 -#define ENI_SYSTEM 4 -#define ENI_FAMILY 5 -#define ENI_SALEN 6 +#ifdef INET6 +static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *, + size_t, int)); +static int ip6_sa2str __P((const struct sockaddr_in6 *, char *, size_t, int)); +#endif + +#define ENI_NOSOCKET EAI_FAIL /*XXX*/ +#define ENI_NOSERVNAME EAI_NONAME +#define ENI_NOHOSTNAME EAI_NONAME +#define ENI_MEMORY EAI_MEMORY +#define ENI_SYSTEM EAI_SYSTEM +#define ENI_FAMILY EAI_FAMILY +#define ENI_SALEN EAI_FAMILY int getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) @@ -96,19 +111,18 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) struct hostent *hp; u_short port; int family, i; - char *addr, *p; - u_long v4a; + const char *addr; + u_int32_t v4a; int h_error; char numserv[512]; char numaddr[512]; - int noserv = 0; if (sa == NULL) return ENI_NOSOCKET; if (sa->sa_len != salen) return ENI_SALEN; - + family = sa->sa_family; for (i = 0; afdl[i].a_af; i++) if (afdl[i].a_af == family) { @@ -116,16 +130,22 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) goto found; } return ENI_FAMILY; - + found: if (salen != afd->a_socklen) return ENI_SALEN; - - port = ((struct sockinet *)sa)->si_port; /* network byte order */ - addr = (char *)sa + afd->a_off; + + /* network byte order */ + port = ((const struct sockinet *)sa)->si_port; + addr = (const char *)sa + afd->a_off; if (serv == NULL || servlen == 0) { - noserv = 1; + /* + * do nothing in this case. + * in case you are wondering if "&&" is more correct than + * "||" here: RFC2553 says that serv == NULL OR servlen == 0 + * means that the caller does not want the result. + */ } else { if (flags & NI_NUMERICSERV) sp = NULL; @@ -147,73 +167,92 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) switch (sa->sa_family) { case AF_INET: - v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); + v4a = (u_int32_t) + ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr); if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) flags |= NI_NUMERICHOST; v4a >>= IN_CLASSA_NSHIFT; if (v4a == 0) - flags |= NI_NUMERICHOST; + flags |= NI_NUMERICHOST; break; #ifdef INET6 case AF_INET6: { - struct sockaddr_in6 *sin6; - sin6 = (struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || - IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) - flags |= NI_NUMERICHOST; + const struct sockaddr_in6 *sin6; + sin6 = (const struct sockaddr_in6 *)sa; + switch (sin6->sin6_addr.s6_addr[0]) { + case 0x00: + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) + ; + else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) + ; + else + flags |= NI_NUMERICHOST; + break; + default: + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + flags |= NI_NUMERICHOST; + } + else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) + flags |= NI_NUMERICHOST; + break; + } } break; #endif } if (host == NULL || hostlen == 0) { - if (noserv == 1) - return ENI_NOSERVHOST; + /* + * do nothing in this case. + * in case you are wondering if "&&" is more correct than + * "||" here: RFC2553 says that host == NULL OR hostlen == 0 + * means that the caller does not want the result. + */ } else if (flags & NI_NUMERICHOST) { + int numaddrlen; + /* NUMERICHOST and NAMEREQD conflicts with each other */ if (flags & NI_NAMEREQD) return ENI_NOHOSTNAME; - if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) - == NULL) - return ENI_SYSTEM; - if (strlen(numaddr) > hostlen) - return ENI_MEMORY; - strcpy(host, numaddr); + + switch(afd->a_af) { #ifdef INET6 - if (afd->a_af == AF_INET6 && - (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) || - IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) && - ((struct sockaddr_in6 *)sa)->sin6_scope_id) { - if (flags & NI_WITHSCOPEID) { - char *ep = strchr(host, '\0'); - unsigned int ifindex = - ((struct sockaddr_in6 *)sa)->sin6_scope_id; - char ifname[IF_NAMESIZE * 2 /* for safety */]; - int scopelen, numaddrlen; - - if ((if_indextoname(ifindex, ifname)) == NULL) - return ENI_SYSTEM; - scopelen = strlen(ifname); - numaddrlen = strlen(host); - if (numaddrlen + 1 /* SCOPE_DELIMITER */ - + scopelen > hostlen) - return ENI_MEMORY; - /* - * Construct <numeric-addr><delim><scopeid> - */ - memcpy(host + numaddrlen + 1, ifname, scopelen); - host[numaddrlen] = SCOPE_DELIMITER; - host[numaddrlen + 1 + scopelen] = '\0'; - } + case AF_INET6: + { + int error; + + if ((error = ip6_parsenumeric(sa, addr, host, + hostlen, flags)) != 0) + return(error); + break; + } +#endif + default: + if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) + == NULL) + return ENI_SYSTEM; + numaddrlen = strlen(numaddr); + if (numaddrlen + 1 > hostlen) /* don't forget terminator */ + return ENI_MEMORY; + strcpy(host, numaddr); + break; } -#endif /* INET6 */ } else { hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); + if (hp) { +#if 0 + /* + * commented out, since "for local host" is not + * implemented here - see RFC2553 p30 + */ if (flags & NI_NOFQDN) { + char *p; p = strchr(hp->h_name, '.'); - if (p) *p = '\0'; + if (p) + *p = '\0'; } +#endif if (strlen(hp->h_name) > hostlen) { freehostent(hp); return ENI_MEMORY; @@ -223,13 +262,112 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) } else { if (flags & NI_NAMEREQD) return ENI_NOHOSTNAME; - if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) - == NULL) - return ENI_NOHOSTNAME; - if (strlen(numaddr) > hostlen) - return ENI_MEMORY; - strcpy(host, numaddr); + switch(afd->a_af) { +#ifdef INET6 + case AF_INET6: + { + int error; + + if ((error = ip6_parsenumeric(sa, addr, host, + hostlen, + flags)) != 0) + return(error); + break; + } +#endif + default: + if (inet_ntop(afd->a_af, addr, host, + hostlen) == NULL) + return ENI_SYSTEM; + break; + } } } return SUCCESS; } + +#ifdef INET6 +static int +ip6_parsenumeric(sa, addr, host, hostlen, flags) + const struct sockaddr *sa; + const char *addr; + char *host; + size_t hostlen; + int flags; +{ + int numaddrlen; + char numaddr[512]; + + if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) + == NULL) + return ENI_SYSTEM; + + numaddrlen = strlen(numaddr); + if (numaddrlen + 1 > hostlen) /* don't forget terminator */ + return ENI_MEMORY; + strcpy(host, numaddr); + +#ifdef NI_WITHSCOPEID + if ( +#ifdef DONT_OPAQUE_SCOPEID + (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) || + IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) && +#endif + ((const struct sockaddr_in6 *)sa)->sin6_scope_id) { +#ifndef ALWAYS_WITHSCOPE + if (flags & NI_WITHSCOPEID) +#endif /* !ALWAYS_WITHSCOPE */ + { + char scopebuf[MAXHOSTNAMELEN]; + int scopelen; + + /* ip6_sa2str never fails */ + scopelen = ip6_sa2str((const struct sockaddr_in6 *)sa, + scopebuf, sizeof(scopebuf), + flags); + if (scopelen + 1 + numaddrlen + 1 > hostlen) + return ENI_MEMORY; + /* + * construct <numeric-addr><delim><scopeid> + */ + memcpy(host + numaddrlen + 1, scopebuf, + scopelen); + host[numaddrlen] = SCOPE_DELIMITER; + host[numaddrlen + 1 + scopelen] = '\0'; + } + } +#endif /* NI_WITHSCOPEID */ + + return 0; +} + +/* ARGSUSED */ +static int +ip6_sa2str(sa6, buf, bufsiz, flags) + const struct sockaddr_in6 *sa6; + char *buf; + size_t bufsiz; + int flags; +{ + unsigned int ifindex = (unsigned int)sa6->sin6_scope_id; + const struct in6_addr *a6 = &sa6->sin6_addr; + +#ifdef NI_NUMERICSCOPE + if (flags & NI_NUMERICSCOPE) { + return(snprintf(buf, bufsiz, "%d", sa6->sin6_scope_id)); + } +#endif + + /* if_indextoname() does not take buffer size. not a good api... */ + if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) && + bufsiz >= IF_NAMESIZE) { + char *p = if_indextoname(ifindex, buf); + if (p) { + return(strlen(p)); + } + } + + /* last resort */ + return(snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id)); +} +#endif /* INET6 */ diff --git a/lib/libc/net/rcmd.c b/lib/libc/net/rcmd.c index 5bbef4bb4a85..70a18d449f3f 100644 --- a/lib/libc/net/rcmd.c +++ b/lib/libc/net/rcmd.c @@ -182,8 +182,8 @@ rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af) refused = 0; continue; } - freeaddrinfo(res); (void)fprintf(stderr, "%s: %s\n", *ahost, strerror(errno)); + freeaddrinfo(res); sigsetmask(oldmask); return (-1); } diff --git a/lib/libftpio/Makefile b/lib/libftpio/Makefile index 7709dead85ea..8652bc7ce539 100644 --- a/lib/libftpio/Makefile +++ b/lib/libftpio/Makefile @@ -7,6 +7,7 @@ SHLIB_MINOR= 0 SRCS= ftpio.c ftperr.c INCS= ftpio.h CFLAGS+= -I${.CURDIR} -Wall +CFLAGS+= -DINET6 MAN3= ftpio.3 CLEANFILES= ftperr.c diff --git a/lib/libftpio/ftp.errors b/lib/libftpio/ftp.errors index 7ae444515e78..c03eeacae329 100644 --- a/lib/libftpio/ftp.errors +++ b/lib/libftpio/ftp.errors @@ -18,7 +18,8 @@ 221 Service closing control connection 225 Data connection open; no transfer in progress 226 Requested file action successful -227 Entering Passive Mode +227 Entering Passive Mode +229 Entering Extended Passive Mode 230 User logged in, proceed 250 Requested file action okay, completed 257 File/directory created diff --git a/lib/libftpio/ftpio.3 b/lib/libftpio/ftpio.3 index b20b8f5d91db..510324df724d 100644 --- a/lib/libftpio/ftpio.3 +++ b/lib/libftpio/ftpio.3 @@ -39,7 +39,10 @@ .Nm ftpPassive , .Nm ftpVerbose , .Nm ftpGetURL , -.Nm ftpPutURL +.Nm ftpPutURL , +.Nm ftpLoginAf , +.Nm ftpGetURLAf , +.Nm ftpPutURLAf .Nd FTPIO User library .Sh SYNOPSIS .Fd #include <ftpio.h> @@ -71,6 +74,12 @@ .Fn ftpGetURL "char *url, char *user, char *passwd, int *retcode" .Ft FILE * .Fn ftpPutURL "char *url, char *user, char *passwd, int *retcode" +.Ft int +.Fn ftpLoginAf "char *host" "int af" "char *user" "char *passwd" "int ftp_port" "int verbose" "int *retcode" +.Ft FILE * +.Fn ftpGetURLAf "char *url" "int af" "char *user" "char *passwd" "int *retcode" +.Ft FILE * +.Fn ftpPutURLAf "char *url" "int af" "char *user" "char *passwd" "int *retcode" .Sh DESCRIPTION These functions implement a high-level library for managing FTP connections. @@ -186,6 +195,16 @@ operations except that no server stream is ever returned - the connection to the server closes when the file has been completely written. Use the lower-level routines if multiple puts are required as it will be far more efficient. +.Pp +.Fn ftpLoginAf , +.Fn ftpGetURLAf , +.Fn ftpPutURLAf +are same as +.Fn ftpLogin , +.Fn ftpGetURL , +.Fn ftpPutURL +except that they are able to specify address family +.Fa af . .Sh ENVIRONMENT .Bl -tag -width FTP_PASSIVE_MODE -offset 123 .It Ev FTP_TIMEOUT diff --git a/lib/libftpio/ftpio.c b/lib/libftpio/ftpio.c index 35f2b15a6030..3cee32dbfeec 100644 --- a/lib/libftpio/ftpio.c +++ b/lib/libftpio/ftpio.c @@ -58,13 +58,14 @@ static __inline char *get_a_line(FTP_t ftp); static int get_a_number(FTP_t ftp, char **q); static int botch(char *func, char *botch_state); static int cmd(FTP_t ftp, const char *fmt, ...); -static int ftp_login_session(FTP_t ftp, char *host, char *user, char *passwd, int port, int verbose); +static int ftp_login_session(FTP_t ftp, char *host, int af, char *user, char *passwd, int port, int verbose); static int ftp_file_op(FTP_t ftp, char *operation, char *file, FILE **fp, char *mode, off_t *seekto); static int ftp_close(FTP_t ftp); static int get_url_info(char *url_in, char *host_ret, int *port_ret, char *name_ret); static void ftp_timeout(int sig); static void ftp_set_timeout(void); static void ftp_clear_timeout(void); +static void ai_unmapped(struct addrinfo *); /* Global status variable - ick */ @@ -79,6 +80,8 @@ int FtpTimedOut; #define FTP_QUIT_HAPPY 221 #define FTP_TRANSFER_HAPPY 226 #define FTP_PASSIVE_HAPPY 227 +#define FTP_LPASSIVE_HAPPY 228 +#define FTP_EPASSIVE_HAPPY 229 #define FTP_CHDIR_HAPPY 250 /* FTP unhappy status codes */ @@ -267,6 +270,16 @@ ftpGet(FILE *fp, char *file, off_t *seekto) FILE * ftpLogin(char *host, char *user, char *passwd, int port, int verbose, int *retcode) { +#ifdef INET6 + return ftpLoginAf(host, AF_UNSPEC, user, passwd, port, verbose, retcode); +#else + return ftpLoginAf(host, AF_INET, user, passwd, port, verbose, retcode); +#endif +} + +FILE * +ftpLoginAf(char *host, int af, char *user, char *passwd, int port, int verbose, int *retcode) +{ FTP_t n; FILE *fp; @@ -277,7 +290,7 @@ ftpLogin(char *host, char *user, char *passwd, int port, int verbose, int *retco n = ftp_new(); fp = NULL; - if (n && ftp_login_session(n, host, user, passwd, port, verbose) == SUCCESS) { + if (n && ftp_login_session(n, host, af, user, passwd, port, verbose) == SUCCESS) { fp = funopen(n, ftp_read_method, ftp_write_method, NULL, ftp_close_method); /* BSD 4.4 function! */ fp->_file = n->fd_ctrl; } @@ -323,11 +336,27 @@ ftpPassive(FILE *fp, int st) if (ftp->is_passive == st) return SUCCESS; - i = cmd(ftp, "PASV"); - if (i < 0) - return i; - if (i != FTP_PASSIVE_HAPPY) - return FAILURE; + switch (ftp->addrtype) { + case AF_INET: + i = cmd(ftp, "PASV"); + if (i < 0) + return i; + if (i != FTP_PASSIVE_HAPPY) + return FAILURE; + break; + case AF_INET6: + i = cmd(ftp, "EPSV"); + if (i < 0) + return i; + if (i != FTP_EPASSIVE_HAPPY) { + i = cmd(ftp, "LPSV"); + if (i < 0) + return i; + if (i != FTP_LPASSIVE_HAPPY) + return FAILURE; + } + break; + } ftp->is_passive = !ftp->is_passive; return SUCCESS; } @@ -335,6 +364,16 @@ ftpPassive(FILE *fp, int st) FILE * ftpGetURL(char *url, char *user, char *passwd, int *retcode) { +#ifdef INET6 + return ftpGetURLAf(url, AF_UNSPEC, user, passwd, retcode); +#else + return ftpGetURLAf(url, AF_INET, user, passwd, retcode); +#endif +} + +FILE * +ftpGetURLAf(char *url, int af, char *user, char *passwd, int *retcode) +{ char host[255], name[255]; int port; FILE *fp2; @@ -364,7 +403,7 @@ ftpGetURL(char *url, char *user, char *passwd, int *retcode) prev_host = NULL; } } - fp = ftpLogin(host, user, passwd, port, 0, retcode); + fp = ftpLoginAf(host, af, user, passwd, port, 0, retcode); if (fp) { fp2 = ftpGet(fp, name, NULL); if (!fp2) { @@ -385,6 +424,17 @@ ftpGetURL(char *url, char *user, char *passwd, int *retcode) FILE * ftpPutURL(char *url, char *user, char *passwd, int *retcode) { +#ifdef INET6 + return ftpPutURLAf(url, AF_UNSPEC, user, passwd, retcode); +#else + return ftpPutURLAf(url, AF_INET, user, passwd, retcode); +#endif + +} + +FILE * +ftpPutURLAf(char *url, int af, char *user, char *passwd, int *retcode) +{ char host[255], name[255]; int port; static FILE *fp = NULL; @@ -397,7 +447,7 @@ ftpPutURL(char *url, char *user, char *passwd, int *retcode) fp = NULL; } if (get_url_info(url, host, &port, name) == SUCCESS) { - fp = ftpLogin(host, user, passwd, port, 0, retcode); + fp = ftpLoginAf(host, af, user, passwd, port, 0, retcode); if (fp) { fp2 = ftpPut(fp, name); if (!fp2) { @@ -671,12 +721,13 @@ cmd(FTP_t ftp, const char *fmt, ...) } static int -ftp_login_session(FTP_t ftp, char *host, char *user, char *passwd, int port, int verbose) +ftp_login_session(FTP_t ftp, char *host, int af, + char *user, char *passwd, int port, int verbose) { - struct hostent *he = NULL; - struct sockaddr_in sin; + char pbuf[10]; + struct addrinfo hints, *res, *res0; + int err; int s; - unsigned long temp; int i; if (networkInit() != SUCCESS) @@ -697,30 +748,36 @@ ftp_login_session(FTP_t ftp, char *host, char *user, char *passwd, int port, int if (!port) port = 21; - temp = inet_addr(host); - if (temp != INADDR_NONE) { - ftp->addrtype = sin.sin_family = AF_INET; - sin.sin_addr.s_addr = temp; - } - else { - he = gethostbyname(host); - if (!he) { - ftp->error = 0; - return FAILURE; - } - ftp->addrtype = sin.sin_family = he->h_addrtype; - bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length); + snprintf(pbuf, sizeof(pbuf), "%d", port); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + err = getaddrinfo(host, pbuf, &hints, &res0); + if (err) { + ftp->error = 0; + return FAILURE; } - sin.sin_port = htons(port); + s = -1; + for (res = res0; res; res = res->ai_next) { + ai_unmapped(res); + ftp->addrtype = res->ai_family; - if ((s = socket(ftp->addrtype, SOCK_STREAM, 0)) < 0) { - ftp->error = -1; - return FAILURE; - } + if ((s = socket(res->ai_family, res->ai_socktype, + res->ai_protocol)) < 0) + continue; + + if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { + (void)close(s); + s = -1; + continue; + } - if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { - (void)close(s); + break; + } + freeaddrinfo(res0); + if (s < 0) { ftp->error = errno; return FAILURE; } @@ -744,11 +801,14 @@ ftp_login_session(FTP_t ftp, char *host, char *user, char *passwd, int port, int static int ftp_file_op(FTP_t ftp, char *operation, char *file, FILE **fp, char *mode, off_t *seekto) { - int i,s; + int i,l,s; char *q; unsigned char addr[64]; - struct sockaddr_in sin; - u_long a; + union sockaddr_cmn { + struct sockaddr_in sin4; + struct sockaddr_in6 sin6; + } sin; + char *cmdstr; if (!fp) return FAILURE; @@ -763,35 +823,101 @@ ftp_file_op(FTP_t ftp, char *operation, char *file, FILE **fp, char *mode, off_t } if (ftp->is_passive) { - if (ftp->is_verbose) - fprintf(stderr, "Sending PASV\n"); - if (writes(ftp->fd_ctrl, "PASV\r\n")) { - ftp_close(ftp); - if (FtpTimedOut) - ftp->error = FTP_TIMED_OUT; - return FTP_TIMED_OUT; - } - i = get_a_number(ftp, &q); - if (check_code(ftp, i, FTP_PASSIVE_HAPPY)) { - ftp_close(ftp); - return i; + if (ftp->addrtype == AF_INET) { + if (ftp->is_verbose) + fprintf(stderr, "Sending PASV\n"); + if (writes(ftp->fd_ctrl, "PASV\r\n")) { + ftp_close(ftp); + if (FtpTimedOut) + ftp->error = FTP_TIMED_OUT; + return FTP_TIMED_OUT; + } + i = get_a_number(ftp, &q); + if (check_code(ftp, i, FTP_PASSIVE_HAPPY)) { + ftp_close(ftp); + return i; + } + cmdstr = "PASV"; + } else { + if (ftp->is_verbose) + fprintf(stderr, "Sending EPSV\n"); + if (writes(ftp->fd_ctrl, "EPSV\r\n")) { + ftp_close(ftp); + if (FtpTimedOut) + ftp->error = FTP_TIMED_OUT; + return FTP_TIMED_OUT; + } + i = get_a_number(ftp, &q); + if (check_code(ftp, i, FTP_EPASSIVE_HAPPY)) { + if (ftp->is_verbose) + fprintf(stderr, "Sending LPSV\n"); + if (writes(ftp->fd_ctrl, "LPSV\r\n")) { + ftp_close(ftp); + if (FtpTimedOut) + ftp->error = FTP_TIMED_OUT; + return FTP_TIMED_OUT; + } + i = get_a_number(ftp, &q); + if (check_code(ftp, i, FTP_LPASSIVE_HAPPY)) { + ftp_close(ftp); + return i; + } + cmdstr = "LPSV"; + } else + cmdstr = "EPSV"; } - while (*q && !isdigit(*q)) + while (*q && *q != '(') /* ) */ q++; if (!*q) { ftp_close(ftp); return FAILURE; } - q--; - for (i = 0; i < 6; i++) { + if (strcmp(cmdstr, "PASV") == 0 || strcmp(cmdstr, "LPSV") == 0) { + l = (ftp->addrtype == AF_INET ? 6 : 21); + for (i = 0; i < l; i++) { + q++; + addr[i] = strtol(q, &q, 10); + } + + sin.sin4.sin_family = ftp->addrtype; + if (ftp->addrtype == AF_INET6) { + sin.sin6.sin6_len = sizeof(struct sockaddr_in6); + bcopy(addr + 2, (char *)&sin.sin6.sin6_addr, 16); + bcopy(addr + 19, (char *)&sin.sin6.sin6_port, 2); + } else { + sin.sin4.sin_len = sizeof(struct sockaddr_in); + bcopy(addr, (char *)&sin.sin4.sin_addr, 4); + bcopy(addr + 4, (char *)&sin.sin4.sin_port, 2); + } + } else if (strcmp(cmdstr, "EPSV") == 0) { + int port; + int sinlen; q++; - addr[i] = strtol(q, &q, 10); + if (sscanf(q, "%c%c%c%d%c", &addr[0], &addr[1], &addr[2], + &port, &addr[3]) != 5 + || addr[0] != addr[1] || addr[0] != addr[2] || addr[0] != addr[3]) { + ftp_close(ftp); + return FAILURE; + } + sinlen = sizeof(sin); + if (getpeername(ftp->fd_ctrl, (struct sockaddr *)&sin, &sinlen) < 0) { + ftp_close(ftp); + return FAILURE; + } + switch (sin.sin4.sin_family) { + case AF_INET: + sin.sin4.sin_port = htons(port); + break; + case AF_INET6: + sin.sin6.sin6_port = htons(port); + break; + default: + ftp_close(ftp); + return FAILURE; + } } - sin.sin_family = ftp->addrtype; - bcopy(addr, (char *)&sin.sin_addr, 4); - bcopy(addr + 4, (char *)&sin.sin_port, 2); - if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + if (connect(s, (struct sockaddr *)&sin, sin.sin4.sin_len) < 0) { (void)close(s); return FAILURE; } @@ -816,39 +942,85 @@ ftp_file_op(FTP_t ftp, char *operation, char *file, FILE **fp, char *mode, off_t else { int fd,portrange; +#ifdef IPV6_PORTRANGE + if (ftp->addrtype == AF_INET6) { + portrange = IPV6_PORTRANGE_HIGH; + if (setsockopt(s, IPPROTO_IPV6, IPV6_PORTRANGE, (char *) + &portrange, sizeof(portrange)) < 0) { + close(s); + return FAILURE; + } + } +#endif #ifdef IP_PORTRANGE - portrange = IP_PORTRANGE_HIGH; - if (setsockopt(s, IPPROTO_IP, IP_PORTRANGE, (char *) - &portrange, sizeof(portrange)) < 0) { - close(s); - return FAILURE; - }; + if (ftp->addrtype == AF_INET) { + portrange = IP_PORTRANGE_HIGH; + if (setsockopt(s, IPPROTO_IP, IP_PORTRANGE, (char *) + &portrange, sizeof(portrange)) < 0) { + close(s); + return FAILURE; + } + } #endif i = sizeof sin; getsockname(ftp->fd_ctrl, (struct sockaddr *)&sin, &i); - sin.sin_port = 0; - i = sizeof sin; + sin.sin4.sin_port = 0; + i = ((struct sockaddr *)&sin)->sa_len; if (bind(s, (struct sockaddr *)&sin, i) < 0) { close(s); return FAILURE; } + i = sizeof sin; getsockname(s,(struct sockaddr *)&sin,&i); if (listen(s, 1) < 0) { close(s); return FAILURE; } - a = ntohl(sin.sin_addr.s_addr); - i = cmd(ftp, "PORT %d,%d,%d,%d,%d,%d", - (a >> 24) & 0xff, - (a >> 16) & 0xff, - (a >> 8) & 0xff, - a & 0xff, - (ntohs(sin.sin_port) >> 8) & 0xff, - ntohs(sin.sin_port) & 0xff); - if (check_code(ftp, i, FTP_PORT_HAPPY)) { - close(s); - return i; + if (sin.sin4.sin_family == AF_INET) { + u_long a; + a = ntohl(sin.sin4.sin_addr.s_addr); + i = cmd(ftp, "PORT %d,%d,%d,%d,%d,%d", + (a >> 24) & 0xff, + (a >> 16) & 0xff, + (a >> 8) & 0xff, + a & 0xff, + (ntohs(sin.sin4.sin_port) >> 8) & 0xff, + ntohs(sin.sin4.sin_port) & 0xff); + if (check_code(ftp, i, FTP_PORT_HAPPY)) { + close(s); + return i; + } + } else { +#define UC(b) (((int)b)&0xff) + char *a; + char hname[INET6_ADDRSTRLEN]; + + if (getnameinfo((struct sockaddr *)&sin, sin.sin6.sin6_len, + hname, sizeof(hname), + NULL, 0, NI_NUMERICHOST) != 0) { + goto try_lprt; + } + i = cmd(ftp, "EPRT |%d|%s|%d|", 2, hname, + htons(sin.sin6.sin6_port)); + if (check_code(ftp, i, FTP_PORT_HAPPY)) { +try_lprt: + a = (char *)&sin.sin6.sin6_addr; + i = cmd(ftp, +"LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", + 6, 16, + UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]), + UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]), + UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]), + UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]), + 2, + (ntohs(sin.sin4.sin_port) >> 8) & 0xff, + ntohs(sin.sin4.sin_port) & 0xff); + if (check_code(ftp, i, FTP_PORT_HAPPY)) { + close(s); + return i; + } + } } if (seekto && *seekto) { i = cmd(ftp, "REST %d", *seekto); @@ -880,3 +1052,30 @@ ftp_file_op(FTP_t ftp, char *operation, char *file, FILE **fp, char *mode, off_t else return FAILURE; } + +static void +ai_unmapped(struct addrinfo *ai) +{ + struct sockaddr_in6 *sin6; + struct sockaddr_in sin; + + if (ai->ai_family != AF_INET6) + return; + if (ai->ai_addrlen != sizeof(struct sockaddr_in6) || + sizeof(sin) > ai->ai_addrlen) + return; + sin6 = (struct sockaddr_in6 *)ai->ai_addr; + if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) + return; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_len = sizeof(struct sockaddr_in); + memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12], + sizeof(sin.sin_addr)); + sin.sin_port = sin6->sin6_port; + + ai->ai_family = AF_INET; + memcpy(ai->ai_addr, &sin, sin.sin_len); + ai->ai_addrlen = sin.sin_len; +} diff --git a/lib/libftpio/ftpio.h b/lib/libftpio/ftpio.h index 26d4f90cd422..ed6fd820d719 100644 --- a/lib/libftpio/ftpio.h +++ b/lib/libftpio/ftpio.h @@ -63,6 +63,9 @@ extern FILE *ftpGetURL(char *url, char *user, char *passwd, int *retcode); extern FILE *ftpPutURL(char *url, char *user, char *passwd, int *retcode); extern time_t ftpGetModtime(FILE *fp, char *s); extern const char *ftpErrString(int error); +extern FILE *ftpLoginAf(char *host, int af, char *user, char *passwd, int port, int verbose, int *retcode); +extern FILE *ftpGetURLAf(char *url, int af, char *user, char *passwd, int *retcode); +extern FILE *ftpPutURLAf(char *url, int af, char *user, char *passwd, int *retcode); __END_DECLS #endif /* _FTP_H_INCLUDE */ diff --git a/lib/libipsec/Makefile b/lib/libipsec/Makefile index d29fbb5554ae..52510f787fc8 100644 --- a/lib/libipsec/Makefile +++ b/lib/libipsec/Makefile @@ -27,20 +27,22 @@ # $FreeBSD$ LIB= ipsec -SHLIB_MAJOR= 0 +SHLIB_MAJOR= 1 SHLIB_MINOR= 0 CFLAGS+=-I${.OBJDIR} -CFLAGS+=-DIPSEC_DEBUG -DIPSEC -DINET6 +CFLAGS+=-DIPSEC_DEBUG -DIPSEC +.if !defined(NOINET6) +CFLAGS+=-DINET6 +.endif -.PATH: ${.CURDIR}/../../sys/netkey -SRCS= pfkey.c pfkey_dump.c +#.PATH: ${.CURDIR}/../../sys/netkey +#SRCS= pfkey.c pfkey_dump.c SRCS+= ipsec_strerror.c policy_parse.y policy_token.l SRCS+= ipsec_dump_policy.c ipsec_get_policylen.c -SRCS+= key_debug.c -LDADD+= -ll -ly +#SRCS+= key_debug.c CLEANFILES+= y.tab.c y.tab.h -YFLAGS+=-d -p __libyy -LFLAGS+=-P__libyy +YFLAGS+=-d -p __libipsecyy +LFLAGS+=-P__libipsecyy MAN3= ipsec_set_policy.3 ipsec_strerror.3 MLINKS+=ipsec_set_policy.3 ipsec_get_policylen.3 \ diff --git a/lib/libipsec/ipsec_dump_policy.c b/lib/libipsec/ipsec_dump_policy.c index a9ef2f5a7aa0..35b8586dc300 100644 --- a/lib/libipsec/ipsec_dump_policy.c +++ b/lib/libipsec/ipsec_dump_policy.c @@ -1,3 +1,6 @@ +/* $FreeBSD$ */ +/* $KAME: ipsec_dump_policy.c,v 1.11 2000/05/07 05:29:47 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. @@ -25,8 +28,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <sys/types.h> @@ -39,6 +40,7 @@ #include <arpa/inet.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <netdb.h> @@ -53,7 +55,11 @@ static const char *ipsp_policy_strs[] = { "discard", "none", "ipsec", "entrust", "bypass", }; -static int set_addresses __P((char *buf, caddr_t ptr)); +static char *ipsec_dump_ipsecrequest __P((char *, size_t, + struct sadb_x_ipsecrequest *, size_t)); +static int set_addresses __P((char *, size_t, struct sockaddr *, + struct sockaddr *)); +static char *set_address __P((char *, size_t, struct sockaddr *)); /* * policy is sadb_x_policy buffer. @@ -67,15 +73,16 @@ ipsec_dump_policy(policy, delimiter) { struct sadb_x_policy *xpl = (struct sadb_x_policy *)policy; struct sadb_x_ipsecrequest *xisr; - int xtlen, buflen; + size_t off, buflen; char *buf; - int error; + char isrbuf[1024]; + char *newbuf; /* sanity check */ if (policy == NULL) return NULL; if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) { - ipsec_errcode = EIPSEC_INVAL_EXTTYPE; + __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; return NULL; } @@ -89,7 +96,7 @@ ipsec_dump_policy(policy, delimiter) case IPSEC_DIR_OUTBOUND: break; default: - ipsec_errcode = EIPSEC_INVAL_DIR; + __ipsec_errcode = EIPSEC_INVAL_DIR; return NULL; } @@ -101,7 +108,7 @@ ipsec_dump_policy(policy, delimiter) case IPSEC_POLICY_ENTRUST: break; default: - ipsec_errcode = EIPSEC_INVAL_POLICY; + __ipsec_errcode = EIPSEC_INVAL_POLICY; return NULL; } @@ -111,143 +118,190 @@ ipsec_dump_policy(policy, delimiter) + 1; /* NUL */ if ((buf = malloc(buflen)) == NULL) { - ipsec_errcode = EIPSEC_NO_BUFS; + __ipsec_errcode = EIPSEC_NO_BUFS; return NULL; } - strcpy(buf, ipsp_dir_strs[xpl->sadb_x_policy_dir]); - strcat(buf, " "); - strcat(buf, ipsp_policy_strs[xpl->sadb_x_policy_type]); + snprintf(buf, buflen, "%s %s", ipsp_dir_strs[xpl->sadb_x_policy_dir], + ipsp_policy_strs[xpl->sadb_x_policy_type]); if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) { - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return buf; } - xtlen = PFKEY_EXTLEN(xpl) - sizeof(*xpl); - xisr = (struct sadb_x_ipsecrequest *)(xpl + 1); - /* count length of buffer for use */ - /* XXX non-seriously */ - while (xtlen > 0) { - buflen += 20; - if (xisr->sadb_x_ipsecrequest_mode ==IPSEC_MODE_TUNNEL) - buflen += 50; - xtlen -= xisr->sadb_x_ipsecrequest_len; - xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr - + xisr->sadb_x_ipsecrequest_len); + off = sizeof(*xpl); + while (off < PFKEY_EXTLEN(xpl)) { + xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off); + off += xisr->sadb_x_ipsecrequest_len; } /* validity check */ - if (xtlen < 0) { - ipsec_errcode = EIPSEC_INVAL_SADBMSG; + if (off != PFKEY_EXTLEN(xpl)) { + __ipsec_errcode = EIPSEC_INVAL_SADBMSG; free(buf); return NULL; } - if ((buf = realloc(buf, buflen)) == NULL) { - ipsec_errcode = EIPSEC_NO_BUFS; - return NULL; - } + off = sizeof(*xpl); + while (off < PFKEY_EXTLEN(xpl)) { + xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off); - xtlen = PFKEY_EXTLEN(xpl) - sizeof(*xpl); - xisr = (struct sadb_x_ipsecrequest *)(xpl + 1); - - while (xtlen > 0) { - strcat(buf, delimiter); - - switch (xisr->sadb_x_ipsecrequest_proto) { - case IPPROTO_ESP: - strcat(buf, "esp"); - break; - case IPPROTO_AH: - strcat(buf, "ah"); - break; - case IPPROTO_IPCOMP: - strcat(buf, "ipcomp"); - break; - default: - ipsec_errcode = EIPSEC_INVAL_PROTO; + if (ipsec_dump_ipsecrequest(isrbuf, sizeof(isrbuf), xisr, + PFKEY_EXTLEN(xpl) - off) == NULL) { free(buf); return NULL; } - strcat(buf, "/"); - - switch (xisr->sadb_x_ipsecrequest_mode) { - case IPSEC_MODE_ANY: - strcat(buf, "any"); - break; - case IPSEC_MODE_TRANSPORT: - strcat(buf, "transport"); - break; - case IPSEC_MODE_TUNNEL: - strcat(buf, "tunnel"); - break; - default: - ipsec_errcode = EIPSEC_INVAL_MODE; + buflen = strlen(buf) + strlen(delimiter) + strlen(isrbuf) + 1; + newbuf = (char *)realloc(buf, buflen); + if (newbuf == NULL) { + __ipsec_errcode = EIPSEC_NO_BUFS; free(buf); return NULL; } + buf = newbuf; + snprintf(buf, buflen, "%s%s%s", buf, delimiter, isrbuf); - strcat(buf, "/"); + off += xisr->sadb_x_ipsecrequest_len; + } - if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { - error = set_addresses(buf, (caddr_t)(xisr + 1)); - if (error) { - ipsec_errcode = EIPSEC_INVAL_MODE; - free(buf); - return NULL; - } - } + __ipsec_errcode = EIPSEC_NO_ERROR; + return buf; +} - switch (xisr->sadb_x_ipsecrequest_level) { - case IPSEC_LEVEL_DEFAULT: - strcat(buf, "/default"); - break; - case IPSEC_LEVEL_USE: - strcat(buf, "/use"); - break; - case IPSEC_LEVEL_REQUIRE: - strcat(buf, "/require"); - break; - case IPSEC_LEVEL_UNIQUE: - strcat(buf, "/unique"); - break; - default: - ipsec_errcode = EIPSEC_INVAL_LEVEL; - free(buf); +static char * +ipsec_dump_ipsecrequest(buf, len, xisr, bound) + char *buf; + size_t len; + struct sadb_x_ipsecrequest *xisr; + size_t bound; /* boundary */ +{ + const char *proto, *mode, *level; + char abuf[NI_MAXHOST * 2 + 2]; + + if (xisr->sadb_x_ipsecrequest_len > bound) { + __ipsec_errcode = EIPSEC_INVAL_PROTO; + return NULL; + } + + switch (xisr->sadb_x_ipsecrequest_proto) { + case IPPROTO_ESP: + proto = "esp"; + break; + case IPPROTO_AH: + proto = "ah"; + break; + case IPPROTO_IPCOMP: + proto = "ipcomp"; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_PROTO; + return NULL; + } + + switch (xisr->sadb_x_ipsecrequest_mode) { + case IPSEC_MODE_ANY: + mode = "any"; + break; + case IPSEC_MODE_TRANSPORT: + mode = "transport"; + break; + case IPSEC_MODE_TUNNEL: + mode = "tunnel"; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_MODE; + return NULL; + } + + abuf[0] = '\0'; + if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { + struct sockaddr *sa1, *sa2; + caddr_t p; + + p = (caddr_t)(xisr + 1); + sa1 = (struct sockaddr *)p; + sa2 = (struct sockaddr *)(p + sa1->sa_len); + if (sizeof(*xisr) + sa1->sa_len + sa2->sa_len != + xisr->sadb_x_ipsecrequest_len) { + __ipsec_errcode = EIPSEC_INVAL_ADDRESS; return NULL; } + if (set_addresses(abuf, sizeof(abuf), sa1, sa2) != 0) { + __ipsec_errcode = EIPSEC_INVAL_ADDRESS; + return NULL; + } + } - xtlen -= xisr->sadb_x_ipsecrequest_len; - xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr - + xisr->sadb_x_ipsecrequest_len); + switch (xisr->sadb_x_ipsecrequest_level) { + case IPSEC_LEVEL_DEFAULT: + level = "default"; + break; + case IPSEC_LEVEL_USE: + level = "use"; + break; + case IPSEC_LEVEL_REQUIRE: + level = "require"; + break; + case IPSEC_LEVEL_UNIQUE: + level = "unique"; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_LEVEL; + return NULL; + } + + if (xisr->sadb_x_ipsecrequest_reqid == 0) + snprintf(buf, len, "%s/%s/%s/%s", proto, mode, abuf, level); + else { + int ch; + + if (xisr->sadb_x_ipsecrequest_reqid > IPSEC_MANUAL_REQID_MAX) + ch = '#'; + else + ch = ':'; + snprintf(buf, len, "%s/%s/%s/%s%c%d", proto, mode, abuf, level, + ch, xisr->sadb_x_ipsecrequest_reqid); } - ipsec_errcode = EIPSEC_NO_ERROR; return buf; } static int -set_addresses(buf, ptr) +set_addresses(buf, len, sa1, sa2) char *buf; - caddr_t ptr; + size_t len; + struct sockaddr *sa1; + struct sockaddr *sa2; { - char tmp[100]; /* XXX */ - struct sockaddr *saddr = (struct sockaddr *)ptr; - - getnameinfo(saddr, saddr->sa_len, tmp, sizeof(tmp), - NULL, 0, NI_NUMERICHOST); - - strcat(buf, tmp); - - strcat(buf, "-"); - - saddr = (struct sockaddr *)((caddr_t)saddr + saddr->sa_len); - getnameinfo(saddr, saddr->sa_len, tmp, sizeof(tmp), - NULL, 0, NI_NUMERICHOST); + char tmp1[NI_MAXHOST], tmp2[NI_MAXHOST]; + + if (set_address(tmp1, sizeof(tmp1), sa1) == NULL || + set_address(tmp2, sizeof(tmp2), sa2) == NULL) + return -1; + if (strlen(tmp1) + 1 + strlen(tmp2) + 1 > len) + return -1; + snprintf(buf, len, "%s-%s", tmp1, tmp2); + return 0; +} - strcat(buf, tmp); +static char * +set_address(buf, len, sa) + char *buf; + size_t len; + struct sockaddr *sa; +{ +#ifdef NI_WITHSCOPEID + const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; +#else + const int niflags = NI_NUMERICHOST; +#endif - return 0; + if (len < 1) + return NULL; + buf[0] = '\0'; + if (getnameinfo(sa, sa->sa_len, buf, len, NULL, 0, niflags) != 0) + return NULL; + return buf; } diff --git a/lib/libipsec/ipsec_get_policylen.c b/lib/libipsec/ipsec_get_policylen.c index a8a3e5d05b70..9986de0e5d0a 100644 --- a/lib/libipsec/ipsec_get_policylen.c +++ b/lib/libipsec/ipsec_get_policylen.c @@ -1,3 +1,6 @@ +/* $FreeBSD$ */ +/* $KAME: ipsec_get_policylen.c,v 1.5 2000/05/07 05:25:03 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. @@ -25,13 +28,13 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <sys/types.h> #include <sys/param.h> +#include <netinet6/ipsec.h> + #include <net/pfkeyv2.h> #include "ipsec_strerror.h" diff --git a/lib/libipsec/ipsec_set_policy.3 b/lib/libipsec/ipsec_set_policy.3 index e8a61ebb74f1..d5d05038cfac 100644 --- a/lib/libipsec/ipsec_set_policy.3 +++ b/lib/libipsec/ipsec_set_policy.3 @@ -1,4 +1,7 @@ .\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. +.\" $FreeBSD$ +.\" $KAME: ipsec_set_policy.3,v 1.10 2000/05/07 05:25:03 itojun Exp $ +.\" .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -25,9 +28,6 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: ipsec_set_policy.3,v 1.5 1999/10/20 00:21:06 sakane Exp $ -.\" $FreeBSD$ -.\" .Dd May 5, 1998 .Dt IPSEC_SET_POLICY 3 .Os @@ -36,10 +36,10 @@ .Nm ipsec_get_policylen , .Nm ipsec_dump_policy .Nd manipulate IPsec policy specification structure from readable string +.\" .Sh LIBRARY .Lb libipsec .Sh SYNOPSIS -.Fd #include <sys/types.h> .Fd #include <netinet6/ipsec.h> .Ft "char *" .Fn ipsec_set_policy "char *policy" "int len" @@ -167,9 +167,9 @@ is the other node .Pp .Ar level must be set to one of the following: -.Li default , use +.Li default , use , require or -.Li require . +.Li unique . .Li default means that the kernel should consult the system default policy defined by @@ -189,6 +189,19 @@ or encrypted .Li require means that a relevant SA is required, since the kernel must perform IPsec operation against packets. +.Li unique +is the same as +.Li require , +but adds the restriction that the SA for outbound traffic is used +only for this policy. +You may need the identifier in order to relate the policy and the SA +when you define the SA by manual keying. +You can put the decimal number as the identifier after +.Li unique +like +.Li unique : number . +.Li number +must be between 1 and 32767 . If the .Ar request string is kept unambiguous, @@ -219,8 +232,8 @@ Here are several examples in discard out ipsec esp/transport/10.1.1.1-10.1.1.2/require in ipsec ah/transport/10.1.1.2-10.1.1.1/require -in ipsec esp/transport/10.1.1.2-10.1.1.1/use - ah/tunnel/10.1.1.2-10.1.1.1/require +out ipsec esp/transport/10.1.1.2-10.1.1.1/use + ah/tunnel/10.1.1.2-10.1.1.1/unique:1000 in ipsec ipcomp/transport/10.1.1.2-10.1.1.1/use esp/transport/10.1.1.2-10.1.1.1/use .Ed @@ -238,11 +251,7 @@ and on errors. .Sh SEE ALSO .Xr ipsec_strerror 3 , -.Xr ipsec 4 , +.Xr ispec 4 , .Xr setkey 8 .Sh HISTORY The functions first appeared in WIDE/KAME IPv6 protocol stack kit. -.Pp -IPv6 and IPsec support based on the KAME Project (http://www.kame.net/) stack -was initially integrated into -.Fx 4.0 diff --git a/lib/libipsec/ipsec_strerror.3 b/lib/libipsec/ipsec_strerror.3 index d1f3c584cb03..d0d39774d364 100644 --- a/lib/libipsec/ipsec_strerror.3 +++ b/lib/libipsec/ipsec_strerror.3 @@ -1,4 +1,7 @@ .\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. +.\" $FreeBSD$ +.\" $KAME: ipsec_strerror.3,v 1.6 2000/05/07 05:25:03 itojun Exp $ +.\" .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -25,22 +28,19 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: ipsec_strerror.3,v 1.2 1999/09/21 03:49:19 itojun Exp $ -.\" $FreeBSD$ -.\" .Dd May 6, 1998 .Dt IPSEC_STRERROR 3 .Os +.\" .Sh NAME .Nm ipsec_strerror .Nd error code for IPsec policy manipulation library -.Sh LIBRARY -.Lb libipsec +.\" .Sh SYNOPSIS -.Fd #include <sys/types.h> .Fd #include <netinet6/ipsec.h> .Ft "char *" -.Fn ipsec_strerror void +.Fn ipsec_strerror +.\" .Sh DESCRIPTION .Pa netinet6/ipsec.h declares @@ -51,16 +51,30 @@ which is used to pass error code from IPsec policy manipulation library to user program. .Fn ipsec_strerror can be used to obtain error message string for the error code. +.Pp +The array pointed to is not to be modified by the program. +Since +.Fn ipsec_strerror +uses +.Xr strerror 3 +as underlying function, calling +.Xr strerror 3 +after +.Fn ipsec_strerror +would make the return value from +.Fn ipsec_strerror +invalid, or overwritten. +.\" .Sh RETURN VALUES .Fn ipsec_strerror always return a pointer to C string. The C string must not be overwritten by user programs. .\" -.\" .Sh SEE ALSO +.Sh SEE ALSO +.Xr ipsec_set_policy 3 .\" .Sh HISTORY The functions first appeared in WIDE/KAME IPv6 protocol stack kit. -.Pp -IPv6 and IPsec support based on the KAME Project (http://www.kame.net/) stack -was initially integrated into -.Fx 4.0 +.\" +.\" .Sh BUGS +.\" (to be written) diff --git a/lib/libipsec/ipsec_strerror.c b/lib/libipsec/ipsec_strerror.c index 601b1d7023f3..1cf4e4c4bd54 100644 --- a/lib/libipsec/ipsec_strerror.c +++ b/lib/libipsec/ipsec_strerror.c @@ -1,3 +1,6 @@ +/* $FreeBSD$ */ +/* $KAME: ipsec_strerror.c,v 1.6 2000/05/07 05:25:03 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. @@ -25,8 +28,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <sys/types.h> @@ -37,7 +38,7 @@ #include "ipsec_strerror.h" -int ipsec_errcode; +int __ipsec_errcode; static char *ipsec_errlist[] = { "Success", /*EIPSEC_NO_ERROR*/ @@ -72,15 +73,15 @@ NULL, /*EIPSEC_SYSTEM_ERROR*/ char *ipsec_strerror(void) { - if (ipsec_errcode < 0 || ipsec_errcode > EIPSEC_MAX) - ipsec_errcode = EIPSEC_MAX; + if (__ipsec_errcode < 0 || __ipsec_errcode > EIPSEC_MAX) + __ipsec_errcode = EIPSEC_MAX; - return ipsec_errlist[ipsec_errcode]; + return ipsec_errlist[__ipsec_errcode]; } -void ipsec_set_strerror(char *str) +void __ipsec_set_strerror(char *str) { - ipsec_errcode = EIPSEC_SYSTEM_ERROR; + __ipsec_errcode = EIPSEC_SYSTEM_ERROR; ipsec_errlist[EIPSEC_SYSTEM_ERROR] = str; return; diff --git a/lib/libipsec/ipsec_strerror.h b/lib/libipsec/ipsec_strerror.h index 752ba75ba2ab..02448cd630a4 100644 --- a/lib/libipsec/ipsec_strerror.h +++ b/lib/libipsec/ipsec_strerror.h @@ -1,3 +1,6 @@ +/* $FreeBSD$ */ +/* $KAME: ipsec_strerror.h,v 1.7 2000/05/07 05:25:03 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. @@ -25,38 +28,36 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ -extern int ipsec_errcode; -extern void ipsec_set_strerror(char *str); +extern int __ipsec_errcode; +extern void __ipsec_set_strerror __P((char *)); -#define EIPSEC_NO_ERROR 0 /*success*/ -#define EIPSEC_NOT_SUPPORTED 1 /*not supported*/ -#define EIPSEC_INVAL_ARGUMENT 2 /*invalid argument*/ -#define EIPSEC_INVAL_SADBMSG 3 /*invalid sadb message*/ -#define EIPSEC_INVAL_VERSION 4 /*invalid version*/ -#define EIPSEC_INVAL_POLICY 5 /*invalid security policy*/ -#define EIPSEC_INVAL_ADDRESS 6 /*invalid address specification*/ -#define EIPSEC_INVAL_PROTO 7 /*invalid ipsec protocol*/ -#define EIPSEC_INVAL_MODE 8 /*Invalid ipsec mode*/ -#define EIPSEC_INVAL_LEVEL 9 /*invalid ipsec level*/ -#define EIPSEC_INVAL_SATYPE 10 /*invalid SA type*/ -#define EIPSEC_INVAL_MSGTYPE 11 /*invalid message type*/ -#define EIPSEC_INVAL_EXTTYPE 12 /*invalid extension type*/ -#define EIPSEC_INVAL_ALGS 13 /*Invalid algorithm type*/ -#define EIPSEC_INVAL_KEYLEN 14 /*invalid key length*/ -#define EIPSEC_INVAL_FAMILY 15 /*invalid address family*/ -#define EIPSEC_INVAL_PREFIXLEN 16 /*SPI range violation*/ -#define EIPSEC_INVAL_DIR 17 /*Invalid direciton*/ -#define EIPSEC_INVAL_SPI 18 /*invalid prefixlen*/ -#define EIPSEC_NO_PROTO 19 /*no protocol specified*/ -#define EIPSEC_NO_ALGS 20 /*No algorithm specified*/ -#define EIPSEC_NO_BUFS 21 /*no buffers available*/ -#define EIPSEC_DO_GET_SUPP_LIST 22 /*must get supported algorithm first*/ -#define EIPSEC_PROTO_MISMATCH 23 /*protocol mismatch*/ -#define EIPSEC_FAMILY_MISMATCH 24 /*family mismatch*/ -#define EIPSEC_FEW_ARGUMENTS 25 /*Too few arguments*/ -#define EIPSEC_SYSTEM_ERROR 26 /*system error*/ -#define EIPSEC_MAX 27 /*unknown error*/ +#define EIPSEC_NO_ERROR 0 /*success*/ +#define EIPSEC_NOT_SUPPORTED 1 /*not supported*/ +#define EIPSEC_INVAL_ARGUMENT 2 /*invalid argument*/ +#define EIPSEC_INVAL_SADBMSG 3 /*invalid sadb message*/ +#define EIPSEC_INVAL_VERSION 4 /*invalid version*/ +#define EIPSEC_INVAL_POLICY 5 /*invalid security policy*/ +#define EIPSEC_INVAL_ADDRESS 6 /*invalid address specification*/ +#define EIPSEC_INVAL_PROTO 7 /*invalid ipsec protocol*/ +#define EIPSEC_INVAL_MODE 8 /*Invalid ipsec mode*/ +#define EIPSEC_INVAL_LEVEL 9 /*invalid ipsec level*/ +#define EIPSEC_INVAL_SATYPE 10 /*invalid SA type*/ +#define EIPSEC_INVAL_MSGTYPE 11 /*invalid message type*/ +#define EIPSEC_INVAL_EXTTYPE 12 /*invalid extension type*/ +#define EIPSEC_INVAL_ALGS 13 /*Invalid algorithm type*/ +#define EIPSEC_INVAL_KEYLEN 14 /*invalid key length*/ +#define EIPSEC_INVAL_FAMILY 15 /*invalid address family*/ +#define EIPSEC_INVAL_PREFIXLEN 16 /*SPI range violation*/ +#define EIPSEC_INVAL_DIR 17 /*Invalid direciton*/ +#define EIPSEC_INVAL_SPI 18 /*invalid prefixlen*/ +#define EIPSEC_NO_PROTO 19 /*no protocol specified*/ +#define EIPSEC_NO_ALGS 20 /*No algorithm specified*/ +#define EIPSEC_NO_BUFS 21 /*no buffers available*/ +#define EIPSEC_DO_GET_SUPP_LIST 22 /*must get supported algorithm first*/ +#define EIPSEC_PROTO_MISMATCH 23 /*protocol mismatch*/ +#define EIPSEC_FAMILY_MISMATCH 24 /*family mismatch*/ +#define EIPSEC_FEW_ARGUMENTS 25 /*Too few arguments*/ +#define EIPSEC_SYSTEM_ERROR 26 /*system error*/ +#define EIPSEC_MAX 27 /*unknown error*/ diff --git a/lib/libipsec/pfkey.c b/lib/libipsec/pfkey.c index 318be331a9cf..11b67228bc8c 100644 --- a/lib/libipsec/pfkey.c +++ b/lib/libipsec/pfkey.c @@ -1,3 +1,6 @@ +/* $FreeBSD$ */ +/* $KAME: pfkey.c,v 1.31 2000/06/10 14:17:43 sakane Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. @@ -25,21 +28,14 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ -#ifndef lint -static char *rcsid = "@(#) pfkey.c $Revision: 1.10 $"; -#endif - #include <sys/types.h> #include <sys/param.h> #include <sys/socket.h> #include <net/pfkeyv2.h> #include <netkey/key_var.h> #include <netinet/in.h> -#include <netinet6/in6.h> #include <netinet6/ipsec.h> #include <stdlib.h> @@ -48,31 +44,31 @@ static char *rcsid = "@(#) pfkey.c $Revision: 1.10 $"; #include <errno.h> #include "ipsec_strerror.h" - -#define CALLOC(size, cast) (cast)calloc(1, (size)) - -static int pfkey_send_x1 __P((int so, u_int type, u_int satype, u_int mode, - struct sockaddr *src, struct sockaddr *dst, u_int32_t spi, u_int wsize, - caddr_t keymat, - u_int e_type, u_int e_keylen, u_int a_type, u_int a_keylen, - u_int flags, - u_int32_t l_alloc, u_int32_t l_bytes, - u_int32_t l_addtime, u_int32_t l_usetime, u_int32_t seq)); -static int pfkey_send_x2 __P((int so, u_int type, u_int satype, u_int mode, - struct sockaddr *src, struct sockaddr *dst, u_int32_t spi)); -static int pfkey_send_x3 __P((int so, u_int type, u_int satype)); - -static caddr_t pfkey_setsadbmsg __P((caddr_t buf, u_int type, u_int tlen, - u_int satype, u_int mode, u_int32_t seq, pid_t pid)); -static caddr_t pfkey_setsadbsa __P((caddr_t buf, u_int32_t spi, u_int wsize, - u_int auth, u_int enc, u_int32_t flags)); -static caddr_t pfkey_setsadbaddr __P((caddr_t buf, u_int exttype, - struct sockaddr *saddr, u_int prefixlen, u_int ul_proto)); -static caddr_t pfkey_setsadbkey(caddr_t buf, u_int type, - caddr_t key, u_int keylen); -static caddr_t pfkey_setsadblifetime(caddr_t buf, u_int type, - u_int32_t l_alloc, u_int32_t l_bytes, - u_int32_t l_addtime, u_int32_t l_usetime); +#include "libpfkey.h" + +#define CALLOC(size, cast) (cast)calloc(1, (size)) + +static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t, + u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t, + u_int32_t, u_int32_t, u_int32_t)); +static int pfkey_send_x2 __P((int, u_int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +static int pfkey_send_x3 __P((int, u_int, u_int)); +static int pfkey_send_x4 __P((int, u_int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, char *, int, u_int32_t)); +static int pfkey_send_x5 __P((int, u_int, u_int32_t)); + +static caddr_t pfkey_setsadbmsg __P((caddr_t, u_int, u_int, + u_int, u_int32_t, pid_t)); +static caddr_t pfkey_setsadbsa __P((caddr_t, u_int32_t, u_int, + u_int, u_int, u_int32_t)); +static caddr_t pfkey_setsadbaddr __P((caddr_t, u_int, + struct sockaddr *, u_int, u_int)); +static caddr_t pfkey_setsadbkey __P((caddr_t, u_int, caddr_t, u_int)); +static caddr_t pfkey_setsadblifetime __P((caddr_t, u_int, u_int32_t, u_int32_t, + u_int32_t, u_int32_t)); +static caddr_t pfkey_setsadbxsa2 __P((caddr_t, u_int32_t, u_int32_t)); /* * check key length against algorithm specified. @@ -98,7 +94,7 @@ ipsec_check_keylen(supported, alg_id, keylen) /* validity check */ if (ipsec_supported == NULL) { - ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST; + __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST; return -1; } switch (supported) { @@ -106,7 +102,7 @@ ipsec_check_keylen(supported, alg_id, keylen) case SADB_EXT_SUPPORTED_ENCRYPT: break; default: - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } @@ -137,18 +133,18 @@ ipsec_check_keylen(supported, alg_id, keylen) } } - ipsec_errcode = EIPSEC_NOT_SUPPORTED; + __ipsec_errcode = EIPSEC_NOT_SUPPORTED; return -1; /* NOTREACHED */ found: if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) { - ipsec_errcode = EIPSEC_INVAL_KEYLEN; + __ipsec_errcode = EIPSEC_INVAL_KEYLEN; return -1; } - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return 0; } @@ -165,7 +161,7 @@ u_int pfkey_set_softrate(type, rate) u_int type, rate; { - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; if (rate > 100 || rate == 0) rate = 100; @@ -185,7 +181,7 @@ pfkey_set_softrate(type, rate) return 0; } - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return 1; } @@ -218,33 +214,46 @@ pfkey_get_softrate(type) * -1 : error occured, and set errno. */ int -pfkey_send_getspi(so, satype, mode, src, dst, min, max, seq) +pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq) int so; u_int satype, mode; struct sockaddr *src, *dst; - u_int32_t min, max, seq; + u_int32_t min, max, reqid, seq; { struct sadb_msg *newmsg; int len; int need_spirange = 0; caddr_t p; + int plen; /* validity check */ if (src == NULL || dst == NULL) { - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } if (src->sa_family != dst->sa_family) { - ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; return -1; } if (min > max || (min > 0 && min <= 255)) { - ipsec_errcode = EIPSEC_INVAL_SPI; + __ipsec_errcode = EIPSEC_INVAL_SPI; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; return -1; } /* create new sadb_msg to send. */ len = sizeof(struct sadb_msg) + + sizeof(struct sadb_x_sa2) + sizeof(struct sadb_address) + PFKEY_ALIGN8(src->sa_len) + sizeof(struct sadb_address) @@ -256,32 +265,28 @@ pfkey_send_getspi(so, satype, mode, src, dst, min, max, seq) } if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { - ipsec_set_strerror(strerror(errno)); + __ipsec_set_strerror(strerror(errno)); return -1; } p = pfkey_setsadbmsg((caddr_t)newmsg, SADB_GETSPI, - len, satype, mode, seq, getpid()); + len, satype, seq, getpid()); + + p = pfkey_setsadbxsa2(p, mode, reqid); /* set sadb_address for source */ - p = pfkey_setsadbaddr(p, - SADB_EXT_ADDRESS_SRC, - src, - _INALENBYAF(src->sa_family) << 3, - IPSEC_ULPROTO_ANY); + p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); /* set sadb_address for destination */ - p = pfkey_setsadbaddr(p, - SADB_EXT_ADDRESS_DST, - dst, - _INALENBYAF(dst->sa_family) << 3, - IPSEC_ULPROTO_ANY); + p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); /* proccessing spi range */ if (need_spirange) { int _len = sizeof(struct sadb_spirange); -#define _SADB_SPIRANGE(p) ((struct sadb_spirange *)(p)) +#define _SADB_SPIRANGE(p) ((struct sadb_spirange *)(p)) _SADB_SPIRANGE(p)->sadb_spirange_len = PFKEY_UNIT64(_len); _SADB_SPIRANGE(p)->sadb_spirange_exttype = SADB_EXT_SPIRANGE; _SADB_SPIRANGE(p)->sadb_spirange_min = min; @@ -297,7 +302,7 @@ pfkey_send_getspi(so, satype, mode, src, dst, min, max, seq) if (len < 0) return -1; - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return len; } @@ -309,13 +314,13 @@ pfkey_send_getspi(so, satype, mode, src, dst, min, max, seq) * -1 : error occured, and set errno. */ int -pfkey_send_update(so, satype, mode, src, dst, spi, wsize, +pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize, keymat, e_type, e_keylen, a_type, a_keylen, flags, l_alloc, l_bytes, l_addtime, l_usetime, seq) int so; u_int satype, mode, wsize; struct sockaddr *src, *dst; - u_int32_t spi; + u_int32_t spi, reqid; caddr_t keymat; u_int e_type, e_keylen, a_type, a_keylen, flags; u_int32_t l_alloc; @@ -324,7 +329,8 @@ pfkey_send_update(so, satype, mode, src, dst, spi, wsize, { int len; if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi, - wsize, keymat, e_type, e_keylen, a_type, a_keylen, flags, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) return -1; @@ -339,13 +345,13 @@ pfkey_send_update(so, satype, mode, src, dst, spi, wsize, * -1 : error occured, and set errno. */ int -pfkey_send_add(so, satype, mode, src, dst, spi, wsize, +pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize, keymat, e_type, e_keylen, a_type, a_keylen, flags, l_alloc, l_bytes, l_addtime, l_usetime, seq) int so; u_int satype, mode, wsize; struct sockaddr *src, *dst; - u_int32_t spi; + u_int32_t spi, reqid; caddr_t keymat; u_int e_type, e_keylen, a_type, a_keylen, flags; u_int32_t l_alloc; @@ -354,7 +360,8 @@ pfkey_send_add(so, satype, mode, src, dst, spi, wsize, { int len; if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi, - wsize, keymat, e_type, e_keylen, a_type, a_keylen, flags, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) return -1; @@ -458,7 +465,7 @@ pfkey_recv_register(so) sup->sadb_supported_len = PFKEY_EXTLEN(sup); break; default: - ipsec_errcode = EIPSEC_INVAL_SATYPE; + __ipsec_errcode = EIPSEC_INVAL_SATYPE; free(newmsg); return -1; } @@ -468,7 +475,7 @@ pfkey_recv_register(so) } if (tlen < 0) { - ipsec_errcode = EIPSEC_INVAL_SATYPE; + __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } @@ -477,7 +484,7 @@ pfkey_recv_register(so) ipsec_supported = newmsg; - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return 0; } @@ -546,7 +553,6 @@ pfkey_send_promisc_toggle(so, flag) /* * sending SADB_X_SPDADD message to the kernel. - * The length of key material is a_keylen + e_keylen. * OUT: * positive: success and return length sent. * -1 : error occured, and set errno. @@ -556,133 +562,140 @@ pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq) int so; struct sockaddr *src, *dst; u_int prefs, prefd, proto; - char *policy; + caddr_t policy; int policylen; u_int32_t seq; { - struct sadb_msg *newmsg; int len; - caddr_t p; - - /* validity check */ - if (src == NULL || dst == NULL) { - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; - return -1; - } - if (src->sa_family != dst->sa_family) { - ipsec_errcode = EIPSEC_FAMILY_MISMATCH; - return -1; - } - if (prefs > (_INALENBYAF(src->sa_family) << 3) - || prefd > (_INALENBYAF(dst->sa_family) << 3)) { - ipsec_errcode = EIPSEC_INVAL_PREFIXLEN; - return -1; - } - - /* create new sadb_msg to reply. */ - len = sizeof(struct sadb_msg) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(src->sa_family)) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(src->sa_family)) - + policylen; - if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { - ipsec_set_strerror(strerror(errno)); + if ((len = pfkey_send_x4(so, SADB_X_SPDADD, + src, prefs, dst, prefd, proto, + policy, policylen, seq)) < 0) return -1; - } - p = pfkey_setsadbmsg((caddr_t)newmsg, SADB_X_SPDADD, len, - SADB_SATYPE_UNSPEC, IPSEC_MODE_ANY, seq, getpid()); - p = pfkey_setsadbaddr(p, - SADB_EXT_ADDRESS_SRC, - src, - prefs, - proto); - p = pfkey_setsadbaddr(p, - SADB_EXT_ADDRESS_DST, - dst, - prefd, - proto); - memcpy(p, policy, policylen); + return len; +} - /* send message */ - len = pfkey_send(so, newmsg, len); - free(newmsg); +/* + * sending SADB_X_SPDUPDATE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; - if (len < 0) + if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, + src, prefs, dst, prefd, proto, + policy, policylen, seq)) < 0) return -1; - ipsec_errcode = EIPSEC_NO_ERROR; return len; } /* * sending SADB_X_SPDDELETE message to the kernel. - * The length of key material is a_keylen + e_keylen. * OUT: * positive: success and return length sent. * -1 : error occured, and set errno. */ int -pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, seq) +pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq) int so; struct sockaddr *src, *dst; u_int prefs, prefd, proto; + caddr_t policy; + int policylen; u_int32_t seq; { - struct sadb_msg *newmsg; int len; - caddr_t p; - /* validity check */ - if (src == NULL || dst == NULL) { - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + if (policylen != sizeof(struct sadb_x_policy)) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } - if (src->sa_family != dst->sa_family) { - ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + + if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE, + src, prefs, dst, prefd, proto, + policy, policylen, seq)) < 0) return -1; - } - if (prefs > (_INALENBYAF(src->sa_family) << 3) - || prefd > (_INALENBYAF(dst->sa_family) << 3)) { - ipsec_errcode = EIPSEC_INVAL_PREFIXLEN; + + return len; +} + +/* + * sending SADB_X_SPDDELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddelete2(so, spid) + int so; + u_int32_t spid; +{ + int len; + + if ((len = pfkey_send_x5(so, SADB_X_SPDDELETE2, spid)) < 0) return -1; - } - /* create new sadb_msg to reply. */ - len = sizeof(struct sadb_msg) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(src->sa_family)) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(src->sa_family)); + return len; +} - if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { - ipsec_set_strerror(strerror(errno)); +/* + * sending SADB_X_SPDGET message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdget(so, spid) + int so; + u_int32_t spid; +{ + int len; + + if ((len = pfkey_send_x5(so, SADB_X_SPDGET, spid)) < 0) return -1; - } - p = pfkey_setsadbmsg((caddr_t)newmsg, SADB_X_SPDDELETE, len, - SADB_SATYPE_UNSPEC, IPSEC_MODE_ANY, seq, getpid()); - p = pfkey_setsadbaddr(p, - SADB_EXT_ADDRESS_SRC, - src, - prefs, - proto); - p = pfkey_setsadbaddr(p, - SADB_EXT_ADDRESS_DST, - dst, - prefd, - proto); + return len; +} - /* send message */ - len = pfkey_send(so, newmsg, len); - free(newmsg); +/* + * sending SADB_X_SPDSETIDX message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; - if (len < 0) + if (policylen != sizeof(struct sadb_x_policy)) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX, + src, prefs, dst, prefd, proto, + policy, policylen, seq)) < 0) return -1; - ipsec_errcode = EIPSEC_NO_ERROR; return len; } @@ -724,13 +737,13 @@ pfkey_send_spddump(so) /* sending SADB_ADD or SADB_UPDATE message to the kernel */ static int -pfkey_send_x1(so, type, satype, mode, src, dst, spi, wsize, +pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize, keymat, e_type, e_keylen, a_type, a_keylen, flags, l_alloc, l_bytes, l_addtime, l_usetime, seq) int so; u_int type, satype, mode; struct sockaddr *src, *dst; - u_int32_t spi; + u_int32_t spi, reqid; u_int wsize; caddr_t keymat; u_int e_type, e_keylen, a_type, a_keylen, flags; @@ -739,44 +752,57 @@ pfkey_send_x1(so, type, satype, mode, src, dst, spi, wsize, struct sadb_msg *newmsg; int len; caddr_t p; + int plen; /* validity check */ if (src == NULL || dst == NULL) { - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } if (src->sa_family != dst->sa_family) { - ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; return -1; } switch (satype) { case SADB_SATYPE_ESP: if (e_type == SADB_EALG_NONE) { - ipsec_errcode = EIPSEC_NO_ALGS; + __ipsec_errcode = EIPSEC_NO_ALGS; return -1; } break; case SADB_SATYPE_AH: if (e_type != SADB_EALG_NONE) { - ipsec_errcode = EIPSEC_INVAL_ALGS; + __ipsec_errcode = EIPSEC_INVAL_ALGS; return -1; } if (a_type == SADB_AALG_NONE) { - ipsec_errcode = EIPSEC_NO_ALGS; + __ipsec_errcode = EIPSEC_NO_ALGS; return -1; } break; case SADB_X_SATYPE_IPCOMP: break; default: - ipsec_errcode = EIPSEC_INVAL_SATYPE; + __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } /* create new sadb_msg to reply. */ len = sizeof(struct sadb_msg) + sizeof(struct sadb_sa) + + sizeof(struct sadb_x_sa2) + sizeof(struct sadb_address) + PFKEY_ALIGN8(src->sa_len) + sizeof(struct sadb_address) @@ -790,23 +816,18 @@ pfkey_send_x1(so, type, satype, mode, src, dst, spi, wsize, len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen)); if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { - ipsec_set_strerror(strerror(errno)); + __ipsec_set_strerror(strerror(errno)); return -1; } p = pfkey_setsadbmsg((caddr_t)newmsg, type, len, - satype, mode, seq, getpid()); + satype, seq, getpid()); p = pfkey_setsadbsa(p, spi, wsize, a_type, e_type, flags); - p = pfkey_setsadbaddr(p, - SADB_EXT_ADDRESS_SRC, - src, - _INALENBYAF(src->sa_family) << 3, - IPSEC_ULPROTO_ANY); - p = pfkey_setsadbaddr(p, - SADB_EXT_ADDRESS_DST, - dst, - _INALENBYAF(dst->sa_family) << 3, - IPSEC_ULPROTO_ANY); + p = pfkey_setsadbxsa2(p, mode, reqid); + p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); if (e_type != SADB_EALG_NONE) p = pfkey_setsadbkey(p, SADB_EXT_KEY_ENCRYPT, @@ -828,7 +849,7 @@ pfkey_send_x1(so, type, satype, mode, src, dst, spi, wsize, if (len < 0) return -1; - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return len; } @@ -843,14 +864,26 @@ pfkey_send_x2(so, type, satype, mode, src, dst, spi) struct sadb_msg *newmsg; int len; caddr_t p; + int plen; /* validity check */ if (src == NULL || dst == NULL) { - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } if (src->sa_family != dst->sa_family) { - ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; return -1; } @@ -863,22 +896,16 @@ pfkey_send_x2(so, type, satype, mode, src, dst, spi) + PFKEY_ALIGN8(dst->sa_len); if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { - ipsec_set_strerror(strerror(errno)); + __ipsec_set_strerror(strerror(errno)); return -1; } - p = pfkey_setsadbmsg((caddr_t)newmsg, type, len, satype, mode, 0, getpid()); + p = pfkey_setsadbmsg((caddr_t)newmsg, type, len, satype, 0, getpid()); p = pfkey_setsadbsa(p, spi, 0, 0, 0, 0); - p = pfkey_setsadbaddr(p, - SADB_EXT_ADDRESS_SRC, - src, - _INALENBYAF(src->sa_family) << 3, - IPSEC_ULPROTO_ANY); - p = pfkey_setsadbaddr(p, - SADB_EXT_ADDRESS_DST, - dst, - _INALENBYAF(dst->sa_family) << 3, - IPSEC_ULPROTO_ANY); + p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); /* send message */ len = pfkey_send(so, newmsg, len); @@ -887,7 +914,7 @@ pfkey_send_x2(so, type, satype, mode, src, dst, spi) if (len < 0) return -1; - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return len; } @@ -907,7 +934,7 @@ pfkey_send_x3(so, type, satype) switch (type) { case SADB_X_PROMISC: if (satype != 0 && satype != 1) { - ipsec_errcode = EIPSEC_INVAL_SATYPE; + __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } break; @@ -919,7 +946,7 @@ pfkey_send_x3(so, type, satype) case SADB_X_SATYPE_IPCOMP: break; default: - ipsec_errcode = EIPSEC_INVAL_SATYPE; + __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } } @@ -928,11 +955,11 @@ pfkey_send_x3(so, type, satype) len = sizeof(struct sadb_msg); if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { - ipsec_set_strerror(strerror(errno)); + __ipsec_set_strerror(strerror(errno)); return -1; } - (void)pfkey_setsadbmsg((caddr_t)newmsg, type, len, satype, 0, 0, getpid()); + (void)pfkey_setsadbmsg((caddr_t)newmsg, type, len, satype, 0, getpid()); /* send message */ len = pfkey_send(so, newmsg, len); @@ -941,7 +968,128 @@ pfkey_send_x3(so, type, satype) if (len < 0) return -1; - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_X_SPDADD message to the kernel */ +static int +pfkey_send_x4(so, type, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int type, prefs, prefd, proto; + char *policy; + int policylen; + u_int32_t seq; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + if (prefs > plen || prefd > plen) { + __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + policylen; + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + + p = pfkey_setsadbmsg((caddr_t)newmsg, type, len, + SADB_SATYPE_UNSPEC, seq, getpid()); + p = pfkey_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + src, + prefs, + proto); + p = pfkey_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + dst, + prefd, + proto); + memcpy(p, policy, policylen); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */ +static int +pfkey_send_x5(so, type, spid) + int so; + u_int type; + u_int32_t spid; +{ + struct sadb_msg *newmsg; + struct sadb_x_policy xpl; + int len; + caddr_t p; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(xpl); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + + p = pfkey_setsadbmsg((caddr_t)newmsg, type, len, + SADB_SATYPE_UNSPEC, 0, getpid()); + + memset(&xpl, 0, sizeof(xpl)); + xpl.sadb_x_policy_len = PFKEY_UNUNIT64(sizeof(xpl)); + xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + xpl.sadb_x_policy_id = spid; + + memcpy(p, &xpl, sizeof(xpl)); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; return len; } @@ -958,7 +1106,7 @@ pfkey_open() const int bufsiz = 128 * 1024; /*is 128K enough?*/ if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { - ipsec_set_strerror(strerror(errno)); + __ipsec_set_strerror(strerror(errno)); return -1; } @@ -969,7 +1117,7 @@ pfkey_open() (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz)); (void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz)); - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return so; } @@ -985,7 +1133,7 @@ pfkey_close(so) { (void)close(so); - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return; } @@ -1005,37 +1153,37 @@ pfkey_recv(so) while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) { if (errno == EINTR) continue; - ipsec_set_strerror(strerror(errno)); + __ipsec_set_strerror(strerror(errno)); return NULL; } if (len < sizeof(buf)) { recv(so, (caddr_t)&buf, sizeof(buf), 0); - ipsec_errcode = EIPSEC_MAX; + __ipsec_errcode = EIPSEC_MAX; return NULL; } /* read real message */ reallen = PFKEY_UNUNIT64(buf.sadb_msg_len); if ((newmsg = CALLOC(reallen, struct sadb_msg *)) == 0) { - ipsec_set_strerror(strerror(errno)); + __ipsec_set_strerror(strerror(errno)); return NULL; } while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) { if (errno == EINTR) continue; - ipsec_set_strerror(strerror(errno)); + __ipsec_set_strerror(strerror(errno)); free(newmsg); return NULL; } if (len != reallen) { - ipsec_errcode = EIPSEC_SYSTEM_ERROR; + __ipsec_errcode = EIPSEC_SYSTEM_ERROR; free(newmsg); return NULL; } - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return newmsg; } @@ -1052,11 +1200,11 @@ pfkey_send(so, msg, len) int len; { if ((len = send(so, (caddr_t)msg, len, 0)) < 0) { - ipsec_set_strerror(strerror(errno)); + __ipsec_set_strerror(strerror(errno)); return -1; } - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return len; } @@ -1083,7 +1231,7 @@ pfkey_align(msg, mhp) /* validity check */ if (msg == NULL || mhp == NULL) { - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } @@ -1100,7 +1248,7 @@ pfkey_align(msg, mhp) /* duplicate check */ /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/ if (mhp[ext->sadb_ext_type] != NULL) { - ipsec_errcode = EIPSEC_INVAL_EXTTYPE; + __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; return -1; } @@ -1125,10 +1273,11 @@ pfkey_align(msg, mhp) case SADB_EXT_SUPPORTED_ENCRYPT: case SADB_EXT_SPIRANGE: case SADB_X_EXT_POLICY: + case SADB_X_EXT_SA2: mhp[ext->sadb_ext_type] = (caddr_t)ext; break; default: - ipsec_errcode = EIPSEC_INVAL_EXTTYPE; + __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; return -1; } @@ -1137,7 +1286,7 @@ pfkey_align(msg, mhp) ext = (struct sadb_ext *)((caddr_t)ext + extlen); } - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return 0; } @@ -1160,7 +1309,7 @@ pfkey_check(mhp) /* validity check */ if (mhp == NULL || mhp[0] == NULL) { - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return -1; } @@ -1168,13 +1317,13 @@ pfkey_check(mhp) /* check version */ if (msg->sadb_msg_version != PF_KEY_V2) { - ipsec_errcode = EIPSEC_INVAL_VERSION; + __ipsec_errcode = EIPSEC_INVAL_VERSION; return -1; } /* check type */ if (msg->sadb_msg_type > SADB_MAX) { - ipsec_errcode = EIPSEC_INVAL_MSGTYPE; + __ipsec_errcode = EIPSEC_INVAL_MSGTYPE; return -1; } @@ -1189,7 +1338,7 @@ pfkey_check(mhp) case SADB_GET: case SADB_ACQUIRE: case SADB_EXPIRE: - ipsec_errcode = EIPSEC_INVAL_SATYPE; + __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } break; @@ -1202,7 +1351,7 @@ pfkey_check(mhp) case SADB_X_SPDGET: case SADB_X_SPDDUMP: case SADB_X_SPDFLUSH: - ipsec_errcode = EIPSEC_INVAL_SATYPE; + __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } break; @@ -1210,14 +1359,14 @@ pfkey_check(mhp) case SADB_SATYPE_OSPFV2: case SADB_SATYPE_RIPV2: case SADB_SATYPE_MIP: - ipsec_errcode = EIPSEC_NOT_SUPPORTED; + __ipsec_errcode = EIPSEC_NOT_SUPPORTED; return -1; case 1: /* XXX: What does it do ? */ if (msg->sadb_msg_type == SADB_X_PROMISC) break; /*FALLTHROUGH*/ default: - ipsec_errcode = EIPSEC_INVAL_SATYPE; + __ipsec_errcode = EIPSEC_INVAL_SATYPE; return -1; } @@ -1230,13 +1379,13 @@ pfkey_check(mhp) dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); if (src0->sadb_address_proto != dst0->sadb_address_proto) { - ipsec_errcode = EIPSEC_PROTO_MISMATCH; + __ipsec_errcode = EIPSEC_PROTO_MISMATCH; return -1; } if (PFKEY_ADDR_SADDR(src0)->sa_family != PFKEY_ADDR_SADDR(dst0)->sa_family) { - ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; return -1; } @@ -1245,7 +1394,7 @@ pfkey_check(mhp) case AF_INET6: break; default: - ipsec_errcode = EIPSEC_INVAL_FAMILY; + __ipsec_errcode = EIPSEC_INVAL_FAMILY; return -1; } @@ -1255,7 +1404,7 @@ pfkey_check(mhp) */ } - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return 0; } @@ -1264,9 +1413,9 @@ pfkey_check(mhp) * `buf' must has been allocated sufficiently. */ static caddr_t -pfkey_setsadbmsg(buf, type, tlen, satype, mode, seq, pid) +pfkey_setsadbmsg(buf, type, tlen, satype, seq, pid) caddr_t buf; - u_int type, satype, mode; + u_int type, satype; u_int tlen; u_int32_t seq; pid_t pid; @@ -1275,7 +1424,7 @@ pfkey_setsadbmsg(buf, type, tlen, satype, mode, seq, pid) u_int len; p = (struct sadb_msg *)buf; - len = sizeof(struct sadb_sa); + len = sizeof(struct sadb_msg); memset(p, 0, len); p->sadb_msg_version = PF_KEY_V2; @@ -1283,7 +1432,6 @@ pfkey_setsadbmsg(buf, type, tlen, satype, mode, seq, pid) p->sadb_msg_errno = 0; p->sadb_msg_satype = satype; p->sadb_msg_len = PFKEY_UNIT64(tlen); - p->sadb_msg_mode = mode; p->sadb_msg_reserved = 0; p->sadb_msg_seq = seq; p->sadb_msg_pid = (u_int32_t)pid; @@ -1402,7 +1550,7 @@ pfkey_setsadblifetime(buf, type, l_alloc, l_bytes, l_addtime, l_usetime) p->sadb_lifetime_allocations = (l_alloc * soft_lifetime_allocations_rate) /100; p->sadb_lifetime_bytes - = ((l_bytes * soft_lifetime_bytes_rate) /100) << 10; + = (l_bytes * soft_lifetime_bytes_rate) /100; p->sadb_lifetime_addtime = (l_addtime * soft_lifetime_addtime_rate) /100; p->sadb_lifetime_usetime @@ -1410,7 +1558,7 @@ pfkey_setsadblifetime(buf, type, l_alloc, l_bytes, l_addtime, l_usetime) break; case SADB_EXT_LIFETIME_HARD: p->sadb_lifetime_allocations = l_alloc; - p->sadb_lifetime_bytes = l_bytes << 10; + p->sadb_lifetime_bytes = l_bytes; p->sadb_lifetime_addtime = l_addtime; p->sadb_lifetime_usetime = l_usetime; break; @@ -1419,3 +1567,29 @@ pfkey_setsadblifetime(buf, type, l_alloc, l_bytes, l_addtime, l_usetime) return buf + len; } +/* + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbxsa2(buf, mode0, reqid) + caddr_t buf; + u_int32_t mode0; + u_int32_t reqid; +{ + struct sadb_x_sa2 *p; + u_int8_t mode = mode0 & 0xff; + u_int len; + + p = (struct sadb_x_sa2 *)buf; + len = sizeof(struct sadb_x_sa2); + + memset(p, 0, len); + p->sadb_x_sa2_len = PFKEY_UNIT64(len); + p->sadb_x_sa2_exttype = SADB_X_EXT_SA2; + p->sadb_x_sa2_mode = mode; + p->sadb_x_sa2_reqid = reqid; + + return(buf + len); +} + diff --git a/lib/libipsec/pfkey_dump.c b/lib/libipsec/pfkey_dump.c index b7def246f683..6408651470f6 100644 --- a/lib/libipsec/pfkey_dump.c +++ b/lib/libipsec/pfkey_dump.c @@ -1,3 +1,6 @@ +/* $FreeBSD$ */ +/* $KAME: pfkey_dump.c,v 1.19 2000/06/10 06:47:11 sakane Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. @@ -25,8 +28,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <sys/types.h> @@ -39,9 +40,6 @@ #include <netinet/in.h> #include <netinet6/ipsec.h> -#ifdef INET6 -#include <netinet6/in6.h> -#endif #include <arpa/inet.h> #include <stdlib.h> @@ -49,11 +47,13 @@ #include <stdio.h> #include <string.h> #include <time.h> +#include <netdb.h> #include "ipsec_strerror.h" +#include "libpfkey.h" -#define GETMSGSTR(str, num) \ -{ \ +#define GETMSGSTR(str, num) \ +do { \ if (sizeof((str)[0]) == 0 \ || num >= sizeof(str)/sizeof((str)[0])) \ printf("%d ", (num)); \ @@ -61,15 +61,12 @@ printf("%d ", (num)); \ else \ printf("%s ", (str)[(num)]); \ -} - -#define GETAF(p) \ - (((struct sockaddr *)(p))->sa_family) +} while (0) -static char *_str_ipaddr __P((u_int family, caddr_t addr)); -static char *_str_prefport __P((u_int family, u_int pref, u_int port)); -static char *_str_time __P((time_t t)); -static void _str_lifetime_byte __P((struct sadb_lifetime *x, char *str)); +static char *str_ipaddr __P((struct sockaddr *)); +static char *str_prefport __P((u_int, u_int, u_int)); +static char *str_time __P((time_t)); +static void str_lifetime_byte __P((struct sadb_lifetime *, char *)); /* * Must to be re-written about following strings. @@ -151,6 +148,7 @@ pfkey_sadump(m) { caddr_t mhp[SADB_EXT_MAX + 1]; struct sadb_sa *m_sa; + struct sadb_x_sa2 *m_sa2; struct sadb_lifetime *m_lftc, *m_lfth, *m_lfts; struct sadb_address *m_saddr, *m_daddr, *m_paddr; struct sadb_key *m_auth, *m_enc; @@ -168,6 +166,7 @@ pfkey_sadump(m) } m_sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + m_sa2 = (struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2]; m_lftc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; m_lfth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; m_lfts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; @@ -177,7 +176,7 @@ pfkey_sadump(m) m_auth = (struct sadb_key *)mhp[SADB_EXT_KEY_AUTH]; m_enc = (struct sadb_key *)mhp[SADB_EXT_KEY_ENCRYPT]; m_sid = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_SRC]; - m_did = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_SRC]; + m_did = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_DST]; m_sens = (struct sadb_sens *)mhp[SADB_EXT_SENSITIVITY]; /* source address */ @@ -185,34 +184,36 @@ pfkey_sadump(m) printf("no ADDRESS_SRC extension.\n"); return; } - printf("%s ", - _str_ipaddr(GETAF(m_saddr + 1), _INADDRBYSA(m_saddr + 1))); + printf("%s ", str_ipaddr((struct sockaddr *)(m_saddr + 1))); /* destination address */ if (m_daddr == NULL) { printf("no ADDRESS_DST extension.\n"); return; } - printf("%s ", - _str_ipaddr(GETAF(m_daddr + 1), _INADDRBYSA(m_daddr + 1))); + printf("%s ", str_ipaddr((struct sockaddr *)(m_daddr + 1))); /* SA type */ if (m_sa == NULL) { printf("no SA extension.\n"); return; } + if (m_sa2 == NULL) { + printf("no SA2 extension.\n"); + return; + } printf("\n\t"); GETMSGSTR(_str_satype, m->sadb_msg_satype); printf("mode="); - GETMSGSTR(_str_mode, m->sadb_msg_mode); + GETMSGSTR(_str_mode, m_sa2->sadb_x_sa2_mode); - printf("spi=%u(0x%08x) replay=%u flags=0x%08x\n", + printf("spi=%u(0x%08x) reqid=%u(0x%08x)\n", (u_int32_t)ntohl(m_sa->sadb_sa_spi), (u_int32_t)ntohl(m_sa->sadb_sa_spi), - m_sa->sadb_sa_replay, - m_sa->sadb_sa_flags); + (u_int32_t)m_sa2->sadb_x_sa2_reqid, + (u_int32_t)m_sa2->sadb_x_sa2_reqid); /* encryption key */ if (m->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) { @@ -237,8 +238,13 @@ pfkey_sadump(m) printf("\n"); } + /* replay windoe size & flags */ + printf("\treplay=%u flags=0x%08x ", + m_sa->sadb_sa_replay, + m_sa->sadb_sa_flags); + /* state */ - printf("\tstate="); + printf("state="); GETMSGSTR(_str_state, m_sa->sadb_sa_state); printf("seq=%lu pid=%lu\n", @@ -250,8 +256,8 @@ pfkey_sadump(m) time_t tmp_time = time(0); printf("\tcreated: %s", - _str_time(m_lftc->sadb_lifetime_addtime)); - printf("\tcurrent: %s\n", _str_time(tmp_time)); + str_time(m_lftc->sadb_lifetime_addtime)); + printf("\tcurrent: %s\n", str_time(tmp_time)); printf("\tdiff: %lu(s)", (u_long)(m_lftc->sadb_lifetime_addtime == 0 ? 0 : (tmp_time - m_lftc->sadb_lifetime_addtime))); @@ -264,7 +270,7 @@ pfkey_sadump(m) 0 : m_lfts->sadb_lifetime_addtime)); printf("\tlast: %s", - _str_time(m_lftc->sadb_lifetime_usetime)); + str_time(m_lftc->sadb_lifetime_usetime)); printf("\thard: %lu(s)", (u_long)(m_lfth == NULL ? 0 : m_lfth->sadb_lifetime_usetime)); @@ -272,9 +278,9 @@ pfkey_sadump(m) (u_long)(m_lfts == NULL ? 0 : m_lfts->sadb_lifetime_usetime)); - _str_lifetime_byte(m_lftc, "current"); - _str_lifetime_byte(m_lfth, "hard"); - _str_lifetime_byte(m_lfts, "soft"); + str_lifetime_byte(m_lftc, "current"); + str_lifetime_byte(m_lfth, "hard"); + str_lifetime_byte(m_lfts, "soft"); printf("\n"); printf("\tallocated: %lu", @@ -288,7 +294,7 @@ pfkey_sadump(m) } /* XXX DEBUG */ - printf("\trefcnt=%d\n", m->sadb_msg_reserved); + printf("\trefcnt=%u\n", m->sadb_msg_reserved); return; } @@ -297,9 +303,12 @@ void pfkey_spdump(m) struct sadb_msg *m; { + char pbuf[NI_MAXSERV]; caddr_t mhp[SADB_EXT_MAX + 1]; struct sadb_address *m_saddr, *m_daddr; struct sadb_x_policy *m_xpl; + struct sockaddr *sa; + u_int16_t port; /* check pfkey message. */ if (pfkey_align(m, mhp)) { @@ -320,25 +329,49 @@ pfkey_spdump(m) printf("no ADDRESS_SRC extension.\n"); return; } - printf("%s%s ", - _str_ipaddr(GETAF(m_saddr + 1), _INADDRBYSA(m_saddr + 1)), - _str_prefport(GETAF(m_saddr + 1), - m_saddr->sadb_address_prefixlen, - _INPORTBYSA(m_saddr + 1))); + sa = (struct sockaddr *)(m_saddr + 1); + switch (sa->sa_family) { + case AF_INET: + case AF_INET6: + if (getnameinfo(sa, sa->sa_len, NULL, 0, pbuf, sizeof(pbuf), + NI_NUMERICSERV) != 0) + port = 0; /*XXX*/ + else + port = atoi(pbuf); + printf("%s%s ", str_ipaddr(sa), + str_prefport(sa->sa_family, + m_saddr->sadb_address_prefixlen, port)); + break; + default: + printf("unknown-af "); + break; + } /* destination address */ if (m_daddr == NULL) { printf("no ADDRESS_DST extension.\n"); return; } - printf("%s%s ", - _str_ipaddr(GETAF(m_daddr + 1), _INADDRBYSA(m_daddr + 1)), - _str_prefport(GETAF(m_daddr + 1), - m_daddr->sadb_address_prefixlen, - _INPORTBYSA(m_daddr + 1))); + sa = (struct sockaddr *)(m_daddr + 1); + switch (sa->sa_family) { + case AF_INET: + case AF_INET6: + if (getnameinfo(sa, sa->sa_len, NULL, 0, pbuf, sizeof(pbuf), + NI_NUMERICSERV) != 0) + port = 0; /*XXX*/ + else + port = atoi(pbuf); + printf("%s%s ", str_ipaddr(sa), + str_prefport(sa->sa_family, + m_daddr->sadb_address_prefixlen, port)); + break; + default: + printf("unknown-af "); + break; + } /* upper layer protocol */ - if (m_saddr->sadb_address_proto != m_saddr->sadb_address_proto) { + if (m_saddr->sadb_address_proto != m_daddr->sadb_address_proto) { printf("upper layer protocol mismatched.\n"); return; } @@ -362,12 +395,13 @@ pfkey_spdump(m) free(d_xpl); } - printf("\tseq=%ld pid=%ld\n", + printf("\tspid=%ld seq=%ld pid=%ld\n", + (u_long)m_xpl->sadb_x_policy_id, (u_long)m->sadb_msg_seq, (u_long)m->sadb_msg_pid); /* XXX TEST */ - printf("\trefcnt=%d\n", m->sadb_msg_reserved); + printf("\trefcnt=%u\n", m->sadb_msg_reserved); return; } @@ -376,35 +410,48 @@ pfkey_spdump(m) * set "ipaddress" to buffer. */ static char * -_str_ipaddr(family, addr) - u_int family; - caddr_t addr; +str_ipaddr(sa) + struct sockaddr *sa; { - static char buf[128]; - char addrbuf[128]; + static char buf[NI_MAXHOST]; +#ifdef NI_WITHSCOPEID + const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; +#else + const int niflag = NI_NUMERICHOST; +#endif - if (addr == NULL) + if (sa == NULL) return ""; - inet_ntop(family, addr, addrbuf, sizeof(addrbuf)); - - snprintf(buf, sizeof(buf), "%s", addrbuf); - - return buf; + if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0, niflag) == 0) + return buf; + return NULL; } /* * set "/prefix[port number]" to buffer. */ static char * -_str_prefport(family, pref, port) +str_prefport(family, pref, port) u_int family, pref, port; { static char buf[128]; char prefbuf[10]; char portbuf[10]; + int plen; + + switch (family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + return "?"; + } - if (pref == (_INALENBYAF(family) << 3)) + if (pref == plen) prefbuf[0] = '\0'; else snprintf(prefbuf, sizeof(prefbuf), "/%u", pref); @@ -412,7 +459,7 @@ _str_prefport(family, pref, port) if (port == IPSEC_PORT_ANY) snprintf(portbuf, sizeof(portbuf), "[%s]", "any"); else - snprintf(portbuf, sizeof(portbuf), "[%u]", ntohs(port)); + snprintf(portbuf, sizeof(portbuf), "[%u]", port); snprintf(buf, sizeof(buf), "%s%s", prefbuf, portbuf); @@ -423,7 +470,7 @@ _str_prefport(family, pref, port) * set "Mon Day Time Year" to buffer */ static char * -_str_time(t) +str_time(t) time_t t; { static char buf[128]; @@ -443,7 +490,7 @@ _str_time(t) } static void -_str_lifetime_byte(x, str) +str_lifetime_byte(x, str) struct sadb_lifetime *x; char *str; { @@ -456,8 +503,24 @@ _str_lifetime_byte(x, str) return; } +#if 0 + if ((x->sadb_lifetime_bytes) / 1024 / 1024) { + y = (x->sadb_lifetime_bytes) * 1.0 / 1024 / 1024; + unit = "M"; + w = 1; + } else if ((x->sadb_lifetime_bytes) / 1024) { + y = (x->sadb_lifetime_bytes) * 1.0 / 1024; + unit = "K"; + w = 1; + } else { + y = (x->sadb_lifetime_bytes) * 1.0; + unit = ""; + w = 0; + } +#else y = (x->sadb_lifetime_bytes) * 1.0; unit = ""; w = 0; +#endif printf("\t%s: %.*f(%sbytes)", str, w, y, unit); } diff --git a/lib/libipsec/policy_parse.y b/lib/libipsec/policy_parse.y index ffa1a6f8ae8d..e36d7b70ee5a 100644 --- a/lib/libipsec/policy_parse.y +++ b/lib/libipsec/policy_parse.y @@ -1,3 +1,6 @@ +/* $FreeBSD$ */ +/* $KAME: policy_parse.y,v 1.10 2000/05/07 05:25:03 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. @@ -25,10 +28,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ -/* KAME $Id: policy_parse.y,v 1.1 1999/10/20 01:26:41 sakane Exp $ */ /* * IN/OUT bound policy configuration take place such below: @@ -59,24 +59,24 @@ #include <stdlib.h> #include <stdio.h> -#include <errno.h> #include <string.h> #include <netdb.h> #include "ipsec_strerror.h" -#define ATOX(c) \ +#define ATOX(c) \ (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) )) static caddr_t pbuf = NULL; /* sadb_x_policy buffer */ static int tlen = 0; /* total length of pbuf */ static int offset = 0; /* offset of pbuf */ -static int p_dir, p_type, p_protocol, p_mode, p_level; +static int p_dir, p_type, p_protocol, p_mode, p_level, p_reqid; static struct sockaddr *p_src = NULL; static struct sockaddr *p_dst = NULL; +struct _val; extern void yyerror __P((char *msg)); -static struct sockaddr *parse_sockaddr __P((/*struct _val *buf*/)); +static struct sockaddr *parse_sockaddr __P((struct _val *buf)); static int rule_check __P((void)); static int init_x_policy __P((void)); static int set_x_request __P((struct sockaddr *src, struct sockaddr *dst)); @@ -85,8 +85,8 @@ static void policy_parse_request_init __P((void)); static caddr_t policy_parse __P((char *msg, int msglen)); extern void __policy__strbuffer__init__ __P((char *msg)); -extern int yyparse(); -extern int yylex(); +extern int yyparse __P((void)); +extern int yylex __P((void)); %} @@ -98,12 +98,12 @@ extern int yylex(); } val; } -%token DIR ACTION PROTOCOL MODE LEVEL +%token DIR ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY %token IPADDRESS %token ME ANY %token SLASH HYPHEN %type <num> DIR ACTION PROTOCOL MODE LEVEL -%type <val> IPADDRESS +%type <val> IPADDRESS LEVEL_SPECIFY %% policy_spec @@ -116,6 +116,14 @@ policy_spec return -1; } rules + | DIR + { + p_dir = $1; + p_type = 0; /* ignored it by kernel */ + + if (init_x_policy()) + return -1; + } ; rules @@ -139,11 +147,11 @@ rule | protocol SLASH mode SLASH SLASH level | protocol SLASH mode | protocol SLASH { - ipsec_errcode = EIPSEC_FEW_ARGUMENTS; + __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; return -1; } | protocol { - ipsec_errcode = EIPSEC_FEW_ARGUMENTS; + __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; return -1; } ; @@ -157,7 +165,14 @@ mode ; level - : LEVEL { p_level = $1; } + : LEVEL { + p_level = $1; + p_reqid = 0; + } + | LEVEL_SPECIFY { + p_level = IPSEC_LEVEL_UNIQUE; + p_reqid = atol($1.buf); /* atol() is good. */ + } ; addresses @@ -174,13 +189,13 @@ addresses } | ME HYPHEN ANY { if (p_dir != IPSEC_DIR_OUTBOUND) { - ipsec_errcode = EIPSEC_INVAL_DIR; + __ipsec_errcode = EIPSEC_INVAL_DIR; return -1; } } | ANY HYPHEN ME { if (p_dir != IPSEC_DIR_INBOUND) { - ipsec_errcode = EIPSEC_INVAL_DIR; + __ipsec_errcode = EIPSEC_INVAL_DIR; return -1; } } @@ -195,7 +210,10 @@ void yyerror(msg) char *msg; { - fprintf(stderr, "%s\n", msg); + extern char *__libipsecyytext; /*XXX*/ + + fprintf(stderr, "libipsec: %s while parsing \"%s\"\n", + msg, __libipsecyytext); return; } @@ -213,43 +231,29 @@ parse_sockaddr(buf) hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_NUMERICHOST; error = getaddrinfo(buf->buf, serv, &hints, &res); - if (error != 0 || res->ai_addr == NULL) { - ipsec_set_strerror(error == EAI_SYSTEM ? - gai_strerror(error) : strerror(errno)); + if (error != 0) { + yyerror("invalid IP address"); + __ipsec_set_strerror(gai_strerror(error)); return NULL; } if (res->ai_addr == NULL) { - ipsec_set_strerror(gai_strerror(error)); + yyerror("invalid IP address"); + __ipsec_set_strerror(gai_strerror(error)); return NULL; } newaddr = malloc(res->ai_addr->sa_len); if (newaddr == NULL) { - ipsec_errcode = EIPSEC_NO_BUFS; + __ipsec_errcode = EIPSEC_NO_BUFS; freeaddrinfo(res); return NULL; } memcpy(newaddr, res->ai_addr, res->ai_addr->sa_len); - /* - * XXX: If the scope of the destination is link-local, - * embed the scope-id(in this case, interface index) - * into the address. - */ - if (newaddr->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)newaddr; - if(IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && - sin6->sin6_scope_id != 0) - *(u_short *)&sin6->sin6_addr.s6_addr[2] = - htons(sin6->sin6_scope_id & 0xffff); - } - freeaddrinfo(res); - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return newaddr; } @@ -258,29 +262,29 @@ rule_check() { if (p_type == IPSEC_POLICY_IPSEC) { if (p_protocol == IPPROTO_IP) { - ipsec_errcode = EIPSEC_NO_PROTO; + __ipsec_errcode = EIPSEC_NO_PROTO; return -1; } if (p_mode != IPSEC_MODE_TRANSPORT && p_mode != IPSEC_MODE_TUNNEL) { - ipsec_errcode = EIPSEC_INVAL_MODE; + __ipsec_errcode = EIPSEC_INVAL_MODE; return -1; } if (p_src == NULL && p_dst == NULL) { if (p_mode != IPSEC_MODE_TRANSPORT) { - ipsec_errcode = EIPSEC_INVAL_ADDRESS; + __ipsec_errcode = EIPSEC_INVAL_ADDRESS; return -1; } } else if (p_src->sa_family != p_dst->sa_family) { - ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; return -1; } } - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return 0; } @@ -293,7 +297,7 @@ init_x_policy() pbuf = malloc(tlen); if (pbuf == NULL) { - ipsec_errcode = EIPSEC_NO_BUFS; + __ipsec_errcode = EIPSEC_NO_BUFS; return -1; } p = (struct sadb_x_policy *)pbuf; @@ -304,7 +308,7 @@ init_x_policy() p->sadb_x_policy_reserved = 0; offset = tlen; - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return 0; } @@ -322,7 +326,7 @@ set_x_request(src, dst) pbuf = realloc(pbuf, tlen); if (pbuf == NULL) { - ipsec_errcode = EIPSEC_NO_BUFS; + __ipsec_errcode = EIPSEC_NO_BUFS; return -1; } p = (struct sadb_x_ipsecrequest *)&pbuf[offset]; @@ -330,12 +334,13 @@ set_x_request(src, dst) p->sadb_x_ipsecrequest_proto = p_protocol; p->sadb_x_ipsecrequest_mode = p_mode; p->sadb_x_ipsecrequest_level = p_level; + p->sadb_x_ipsecrequest_reqid = p_reqid; offset += sizeof(*p); if (set_sockaddr(src) || set_sockaddr(dst)) return -1; - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return 0; } @@ -344,7 +349,7 @@ set_sockaddr(addr) struct sockaddr *addr; { if (addr == NULL) { - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return 0; } @@ -354,7 +359,7 @@ set_sockaddr(addr) offset += addr->sa_len; - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return 0; } @@ -364,6 +369,7 @@ policy_parse_request_init() p_protocol = IPPROTO_IP; p_mode = IPSEC_MODE_ANY; p_level = IPSEC_LEVEL_DEFAULT; + p_reqid = 0; if (p_src != NULL) { free(p_src); p_src = NULL; @@ -401,7 +407,7 @@ policy_parse(msg, msglen) /* update total length */ ((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen); - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return pbuf; } @@ -415,12 +421,12 @@ ipsec_set_policy(msg, msglen) policy = policy_parse(msg, msglen); if (policy == NULL) { - if (ipsec_errcode == EIPSEC_NO_ERROR) - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + if (__ipsec_errcode == EIPSEC_NO_ERROR) + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; return NULL; } - ipsec_errcode = EIPSEC_NO_ERROR; + __ipsec_errcode = EIPSEC_NO_ERROR; return policy; } diff --git a/lib/libipsec/policy_token.l b/lib/libipsec/policy_token.l index c9737cb83435..81d632b41cfa 100644 --- a/lib/libipsec/policy_token.l +++ b/lib/libipsec/policy_token.l @@ -1,3 +1,6 @@ +/* $FreeBSD$ */ +/* $KAME: policy_token.l,v 1.9 2000/05/07 05:25:03 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. @@ -25,8 +28,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ %{ @@ -46,8 +47,14 @@ #include <unistd.h> #include <errno.h> +#ifndef __NetBSD__ #include "y.tab.h" -#define yylval __libyylval /* XXX */ +#else +#include "policy_parse.h" +#endif +#define yylval __libipsecyylval /* XXX */ + +int yylex __P((void)); %} %option noyywrap @@ -56,7 +63,6 @@ nl \n ws [ \t]+ digit [0-9] -letter [0-9A-Za-z] hexdigit [0-9A-Fa-f] special [()+\|\?\*,] dot \. @@ -79,9 +85,7 @@ decstring {digit}+ hexpair {hexdigit}{hexdigit} hexstring 0[xX]{hexdigit}+ octetstring {octet}({dot}{octet})+ -ipaddress [a-zA-Z0-9:\._][a-zA-Z0-9:\._]*(%{letter}{letter}+)? -name {letter}(({letter}|{digit}|{hyphen})*({letter}|{digit}))* -hostname {name}(({dot}{name})+{dot}?)? +ipaddress [a-zA-Z0-9:\._][a-zA-Z0-9:\._]*(%[a-zA-Z0-9]+)? %% @@ -107,12 +111,17 @@ any { return(ANY); } default { yylval.num = IPSEC_LEVEL_DEFAULT; return(LEVEL); } use { yylval.num = IPSEC_LEVEL_USE; return(LEVEL); } require { yylval.num = IPSEC_LEVEL_REQUIRE; return(LEVEL); } +unique{colon}{decstring} { + yylval.val.len = strlen(yytext + 7); + yylval.val.buf = yytext + 7; + return(LEVEL_SPECIFY); + } unique { yylval.num = IPSEC_LEVEL_UNIQUE; return(LEVEL); } {slash} { return(SLASH); } {ipaddress} { yylval.val.len = strlen(yytext); - yylval.val.buf = strdup(yytext); + yylval.val.buf = yytext; return(IPADDRESS); } @@ -123,6 +132,8 @@ unique { yylval.num = IPSEC_LEVEL_UNIQUE; return(LEVEL); } %% +void __policy__strbuffer__init__ __P((char *)); + void __policy__strbuffer__init__(msg) char *msg; diff --git a/lib/libipsec/test-policy.c b/lib/libipsec/test-policy.c index c8fd72732836..5a4faf5731bc 100644 --- a/lib/libipsec/test-policy.c +++ b/lib/libipsec/test-policy.c @@ -1,3 +1,6 @@ +/* $FreeBSD$ */ +/* $KAME: test-policy.c,v 1.13 2000/05/07 05:25:03 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. @@ -25,8 +28,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <sys/types.h> @@ -34,7 +35,6 @@ #include <sys/socket.h> #include <netinet/in.h> -#include <netinet6/in6.h> #include <net/pfkeyv2.h> #include <netkey/key_debug.h> #include <netinet6/ipsec.h> @@ -43,90 +43,115 @@ #include <stdlib.h> #include <unistd.h> #include <string.h> +#include <errno.h> #include <err.h> -char *requests[] = { -"must_error", /* error */ -"in ipsec must_error", /* error */ -"out ipsec esp/must_error", /* error */ -"out discard", -"out none", -"in entrust", -"out entrust", -"in bypass", /* may be error */ -"out ipsec esp", /* error */ -"in ipsec ah/transport", -"in ipsec ah/tunnel", /* error */ -"out ipsec ah/transport/", -"out ipsec ah/tunnel/", /* error */ -"in ipsec esp / transport / 10.0.0.1-10.0.0.2", -"in ipsec esp/tunnel/::1-::2", -"in ipsec esp/tunnel/10.0.0.1-::2", /* error */ -"in ipsec esp/tunnel/::1-::2/require", -"out ipsec ah/transport//use", -"out ipsec ah/transport esp/use", -"in ipsec ah/transport esp/tunnel", /* error */ -"in ipsec +struct req_t { + int result; /* expected result; 0:ok 1:ng */ + char *str; +} reqs[] = { +{ 0, "out ipsec" }, +{ 1, "must_error" }, +{ 1, "in ipsec must_error" }, +{ 1, "out ipsec esp/must_error" }, +{ 1, "out discard" }, +{ 1, "out none" }, +{ 0, "in entrust" }, +{ 0, "out entrust" }, +{ 1, "out ipsec esp" }, +{ 0, "in ipsec ah/transport" }, +{ 1, "in ipsec ah/tunnel" }, +{ 0, "out ipsec ah/transport/" }, +{ 1, "out ipsec ah/tunnel/" }, +{ 0, "in ipsec esp / transport / 10.0.0.1-10.0.0.2" }, +{ 0, "in ipsec esp/tunnel/::1-::2" }, +{ 1, "in ipsec esp/tunnel/10.0.0.1-::2" }, +{ 0, "in ipsec esp/tunnel/::1-::2/require" }, +{ 0, "out ipsec ah/transport//use" }, +{ 1, "out ipsec ah/transport esp/use" }, +{ 1, "in ipsec ah/transport esp/tunnel" }, +{ 0, "in ipsec ah/transport esp/tunnel/::1-::1" }, +{ 0, "in ipsec ah / transport - esp / tunnel / ::1-::2", -" -out ipsec -ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require -ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require -ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require -", -"out ipsec esp/transport/fec0::10-fec0::11/use", + esp / tunnel / ::1-::2" }, +{ 0, "out ipsec + ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require + ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require + ah/transport/::1-::2 esp/tunnel/::3-::4/use ah/transport/::5-::6/require + " }, +{ 0, "out ipsec esp/transport/fec0::10-fec0::11/use" }, }; -int test(char *buf, int family); +int test1 __P((void)); +int test1sub1 __P((struct req_t *)); +int test1sub2 __P((char *, int)); +int test2 __P((void)); +int test2sub __P((int)); int main(ac, av) int ac; char **av; { - int do_setsockopt; - char *buf; - int i; + test1(); + test2(); - if (ac != 1) - do_setsockopt = 1; - else - do_setsockopt = 0; + exit(0); +} - for (i = 0; i < sizeof(requests)/sizeof(requests[0]); i++) { - printf("*** requests ***\n"); - printf("\t[%s]\n", requests[i]); +int +test1() +{ + int i; + int result; + + printf("TEST1\n"); + for (i = 0; i < sizeof(reqs)/sizeof(reqs[0]); i++) { + printf("#%d [%s]\n", i + 1, reqs[i].str); - buf = ipsec_set_policy(requests[i], strlen(requests[i])); - if (buf == NULL) { - printf("ipsec_set_policy: %s\n", ipsec_strerror()); - continue; + result = test1sub1(&reqs[i]); + if (result == 0 && reqs[i].result == 1) { + errx(1, "ERROR: expecting failure.\n"); + } else if (result == 1 && reqs[i].result == 0) { + errx(1, "ERROR: expecting success.\n"); } + } + + return 0; +} - printf("\tsetlen:%d\n", ipsec_get_policylen(buf)); +int +test1sub1(req) + struct req_t *req; +{ + char *buf; - if (do_setsockopt) { - printf("\tPF_INET:\n"); - test(buf, PF_INET); + buf = ipsec_set_policy(req->str, strlen(req->str)); + if (buf == NULL) { + printf("ipsec_set_policy: %s\n", ipsec_strerror()); + return 1; + } - printf("\tPF_INET6:\n"); - test(buf, PF_INET6); - } else { - kdebug_sadb_x_policy((struct sadb_ext *)buf); - } + if (test1sub2(buf, PF_INET) != 0 + || test1sub2(buf, PF_INET6) != 0) { free(buf); + return 1; } +#if 0 + kdebug_sadb_x_policy((struct sadb_ext *)buf); +#endif + free(buf); return 0; } int -test(policy, family) +test1sub2(policy, family) char *policy; int family; { - int so, proto, optname; + int so; + int proto = 0, optname = 0; int len; char getbuf[1024]; @@ -145,35 +170,148 @@ test(policy, family) err(1, "socket"); len = ipsec_get_policylen(policy); +#if 0 + printf("\tsetlen:%d\n", len); +#endif + if (setsockopt(so, proto, optname, policy, len) < 0) { - printf("error on setsockopt"); - goto end; + printf("fail to set sockopt; %s\n", strerror(errno)); + close(so); + return 1; } - len = sizeof(getbuf); memset(getbuf, 0, sizeof(getbuf)); + memcpy(getbuf, policy, sizeof(struct sadb_x_policy)); if (getsockopt(so, proto, optname, getbuf, &len) < 0) { - printf("error on getsockopt"); - goto end; + printf("fail to get sockopt; %s\n", strerror(errno)); + close(so); + return 1; } { char *buf = NULL; +#if 0 printf("\tgetlen:%d\n", len); +#endif if ((buf = ipsec_dump_policy(getbuf, NULL)) == NULL) { printf("%s\n", ipsec_strerror()); - goto end; - } else { - printf("\t[%s]\n", buf); - free(buf); + close(so); + return 1; } +#if 0 + printf("\t[%s]\n", buf); +#endif + free(buf); } - end: close (so); + return 0; +} + +char addr[] = { + 28, 28, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, +}; + +int +test2() +{ + int so; + char *pol1 = "out ipsec"; + char *pol2 = "out ipsec ah/transport//use"; + char *sp1, *sp2; + int splen1, splen2; + int spid; + struct sadb_msg *m; + + printf("TEST2\n"); + if (getuid() != 0) + errx(1, "root privilege required.\n"); + + sp1 = ipsec_set_policy(pol1, strlen(pol1)); + splen1 = ipsec_get_policylen(sp1); + sp2 = ipsec_set_policy(pol2, strlen(pol2)); + splen2 = ipsec_get_policylen(sp2); + + if ((so = pfkey_open()) < 0) + errx(1, "ERROR: %s\n", ipsec_strerror()); + + printf("spdflush()\n"); + if (pfkey_send_spdflush(so) < 0) + errx(1, "ERROR: %s\n", ipsec_strerror()); + m = pfkey_recv(so); + free(m); + + printf("spdsetidx()\n"); + if (pfkey_send_spdsetidx(so, (struct sockaddr *)addr, 128, + (struct sockaddr *)addr, 128, + 255, sp1, splen1, 0) < 0) + errx(1, "ERROR: %s\n", ipsec_strerror()); + m = pfkey_recv(so); + free(m); + + printf("spdupdate()\n"); + if (pfkey_send_spdupdate(so, (struct sockaddr *)addr, 128, + (struct sockaddr *)addr, 128, + 255, sp2, splen2, 0) < 0) + errx(1, "ERROR: %s\n", ipsec_strerror()); + m = pfkey_recv(so); + free(m); + + printf("spddelete()\n"); + if (pfkey_send_spddelete(so, (struct sockaddr *)addr, 128, + (struct sockaddr *)addr, 128, + 255, sp1, splen1, 0) < 0) + errx(1, "ERROR: %s\n", ipsec_strerror()); + m = pfkey_recv(so); + free(m); + + printf("spdadd()\n"); + if (pfkey_send_spdadd(so, (struct sockaddr *)addr, 128, + (struct sockaddr *)addr, 128, + 255, sp2, splen2, 0) < 0) + errx(1, "ERROR: %s\n", ipsec_strerror()); + spid = test2sub(so); + + printf("spdget(%u)\n", spid); + if (pfkey_send_spdget(so, spid) < 0) + errx(1, "ERROR: %s\n", ipsec_strerror()); + m = pfkey_recv(so); + free(m); + + printf("spddelete2()\n"); + if (pfkey_send_spddelete2(so, spid) < 0) + errx(1, "ERROR: %s\n", ipsec_strerror()); + m = pfkey_recv(so); + free(m); + + /* expecting failure */ + printf("spdupdate()\n"); + if (pfkey_send_spdupdate(so, (struct sockaddr *)addr, 128, + (struct sockaddr *)addr, 128, + 255, sp2, splen2, 0) == 0) { + errx(1, "ERROR: expecting failure.\n"); + } return 0; } +int +test2sub(so) + int so; +{ + struct sadb_msg *msg; + caddr_t mhp[SADB_EXT_MAX + 1]; + + if ((msg = pfkey_recv(so)) == NULL) + errx(1, "ERROR: pfkey_recv failure.\n"); + if (pfkey_align(msg, mhp) < 0) + errx(1, "ERROR: pfkey_align failure.\n"); + + return ((struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY])->sadb_x_policy_id; +} + diff --git a/sbin/ping6/Makefile b/sbin/ping6/Makefile index 0cac4c084490..3f671d7330b5 100644 --- a/sbin/ping6/Makefile +++ b/sbin/ping6/Makefile @@ -1,25 +1,19 @@ -# Copyright (c) 1996 WIDE Project. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modifications, are permitted provided that the above copyright notice -# and this paragraph are duplicated in all such forms and that any -# documentation, advertising materials, and other materials related to -# such distribution and use acknowledge that the software was developed -# by the WIDE Project, Japan. The name of the Project may not be used to -# endorse or promote products derived from this software without -# specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' -# AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT -# LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE. # $FreeBSD$ PROG= ping6 MAN8= ping6.8 -BINMODE = 4555 -COPTS+= -Wall -Wmissing-prototypes -.if ${MACHINE_ARCH} == "alpha" -COPTS+= -fno-builtin # GCC's builtin memcpy doesn't do unaligned copies -.endif -CFLAGS+= -DINET6 +SRCS= ping6.c + +CFLAGS+=-DINET6 -DIPSEC + +BINOWN= root +BINGRP= bin +BINMODE=4555 + +LDADD= -lipsec -lmd +DPADD= ${LIBIPSEC} ${LIBMD} + +# kame scopeid hack +CFLAGS+=-DKAME_SCOPEID .include <bsd.prog.mk> diff --git a/sbin/ping6/ping6.8 b/sbin/ping6/ping6.8 index 06350b398605..f2e81f151e94 100644 --- a/sbin/ping6/ping6.8 +++ b/sbin/ping6/ping6.8 @@ -1,3 +1,5 @@ +.\" $KAME: ping6.8,v 1.22 2000/05/31 17:00:07 itojun Exp $ +.\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. .\" @@ -25,7 +27,6 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: ping6.8,v 1.4 1999/10/07 05:29:03 itojun Exp $ .\" $FreeBSD$ .\" .Dd May 17, 1998 @@ -37,45 +38,93 @@ .Tn ICMPv6 ECHO_REQUEST packets to network hosts .Sh SYNOPSIS -.Nm -.Op Fl AdEfnqRrvw +.Nm ping6 +.\" without ipsec, or new ipsec +.Op Fl dfHnNqRvw +.\" old ipsec +.\" .Op Fl AdEfnNqRvw +.Bk -words .Op Fl a Ar addrtype +.Ek +.Bk -words .Op Fl b Ar bufsiz +.Ek +.Bk -words .Op Fl c Ar count +.Ek +.Bk -words .Op Fl h Ar hoplimit +.Ek +.Bk -words .Op Fl I Ar interface +.Ek +.Bk -words .Op Fl i Ar wait +.Ek +.Bk -words .Op Fl l Ar preload +.Ek +.Bk -words .Op Fl p Ar pattern +.Ek +.Bk -words +.\" new ipsec +.Op Fl P Ar policy +.Ek +.Bk -words +.Op Fl S Ar sourceaddr +.Ek +.Bk -words .Op Fl s Ar packetsize +.Ek +.Bk -words +.Op Ar hops... +.Ek +.Bk -words .Ar host +.Ek .Sh DESCRIPTION +.Nm +uses the +.Tn ICMPv6 +protocol's mandatory +.Tn ICMP6_ECHO_REQUEST +datagram to elicit an +.Tn ICMP6_ECHO_REPLY +from a host or gateway. +.Tn ICMP6_ECHO_REQUEST +datagrams (``pings'') have an IPv6 header, +and +.Tn ICMPv6 +header formatted as documented in RFC2463. +The options are as follows: .Bl -tag -width Ds -.It Fl A -Enables transport-mode IPsec authentication header. -(experimental) +.\" old ipsec +.\" .It Fl A +.\" Enables transport-mode IPsec authentication header +.\" .Pq experimental . .It Fl a Ar addrtype Generate ICMPv6 Node Information Node Addresses query, rather than echo-request. .Ar addrtype -must be a string constructed of the following charaters. +must be a string constructed of the following characters. .Bl -tag -width Ds -compact .It Ic a -requires all the responder's unicast addresses. +requests all the responder's unicast addresses. If the charater is ommited, only those addresses which belong to the interface which has the -responder's address are required. +responder's address are requests. +.It Ic c +requests responder's IPv4-compatible and IPv4-mapped addresses. .It Ic g -requires responder's global-scope addresses. +requests responder's global-scope addresses. .It Ic s -requires responder's site-local addresses. +requests responder's site-local addresses. .It Ic l -requires responder's link-local addresses. +requests responder's link-local addresses. .It Ic A -requires responder's anycast addresses. -Without this character, the responder -will return unicast addresses only. -With this character, the responder -will return anycast addresses only. +requests responder's anycast addresses. +Without this character, the responder will return unicast addresses only. +With this character, the responder will return anycast addresses only. Note that the specification does not specify how to get responder's anycast addresses. This is an experimental option. @@ -92,9 +141,9 @@ packets. Set the .Dv SO_DEBUG option on the socket being used. -.It Fl E -Enables transport-mode IPsec encapsulated security payload. -(experimental) +.\" .It Fl E +.\" Enables transport-mode IPsec encapsulated security payload +.\" .Pq experimental . .It Fl f Flood ping. Outputs packets as fast as they come back or one hundred times per second, @@ -111,6 +160,11 @@ Only the super-user may use this option. .Bf -emphasis This can be very hard on a network and should be used with caution. .Ef +.It Fl H +Specifies to try reverse-lookup of IPv6 addresses. +The +.Nm +command does not try reverse-lookup unless the option is specified. .It Fl h Ar hoplimit Set the IPv6 hoplimit. .It Fl I Ar interface @@ -137,6 +191,19 @@ 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. +.It Fl N +Probe node information multicast group +.Pq Li ff02::2:xxxx:xxxx . +.Ar host +must be string hostname of the target +.Pq must not be a numeric IPv6 address . +Node information multicast group will be computed based on given +.Ar host , +and will be used as the final destination. +Since node information multicast group is a link-local multicast group, +destination link needs to be specified by +.Fl I +option. .It Fl p Ar pattern You may specify up to 16 .Dq pad @@ -151,36 +218,36 @@ flag, .Nm prints out any ICMP error messages caused by its own ECHO_REQUEST messages. +.\" new ipsec +.It Fl P Ar policy +.Ar policy +specifies IPsec policy to be used for the probe. .It Fl q Quiet output. Nothing is displayed except the summary lines at startup time and when finished. .It Fl R -Record route. -Includes the -.Tn RECORD_ROUTE -option in the -.Tn ECHO_REQUEST -packet and displays -the route buffer on returned packets. -Note that the IP header is only large enough for nine such routes; -the -.Xr traceroute 8 -command is usually better at determining the route packets take to a -particular destination. -Many hosts ignore or discard the -.Tn RECORD_ROUTE -option. -.It Fl r -Bypass the normal routing tables and send directly to a host on an attached -network. -If the host is not on a directly-attached network, an error is returned. -This option can be used to ping a local host through an interface -that has no route through it +Make the kernel believe that the target +.Ar host .Po -e.g., after the interface was dropped by -.Xr routed 8 -.Pc . +or the first +.Ar hop +if you specify +.Ar hops +.Pc +is reachable, by injecting upper-layer reachability confirmation hint. +The option is meaningful only if the target +.Ar host +.Pq or the first hop +is a neighbor. +.It Fl S Ar sourceaddr +Specifies the source address of request packets. +The source address must be one of the unicast addresses of the sending node. +If the outgoing interface is specified by the +.Fl I +option as well, +.Ar sourceaddr +needs to be an address assigned to the specified interface. .It Fl s Ar packetsize Specifies the number of data bytes to be sent. The default is 56, which translates into 64 @@ -206,12 +273,18 @@ has no effect if is specified. .It Fl W Same as -.Fl w . -This option was remained for backward compatibility. +.Fl w , +but with old packet format based on 03 draft. +This option is present for backward compatibility. .Fl s has no effect if .Fl w is specified. +.It Ar hops +IPv6 addresses for intermediate nodes, +which will be put into type 0 routing header. +.It Ar host +IPv6 adddress of the final destination node. .El .Pp When using @@ -310,15 +383,9 @@ using the option of .Nm Ns . .Sh RETURN VALUES -The .Nm -command returns an exit status of zero if at least one response was -heard from the specified -.Ar host ; -a status of two if the transmission was successful but no responses -were received; or another value -.Pq from Aq Pa sysexits.h -if an error occurred. +returns 0 on success (the host is alive), +and non-zero if the arguments are incorrect or the host is not responding. .Sh SEE ALSO .Xr netstat 1 , .Xr ifconfig 8 , @@ -326,6 +393,20 @@ if an error occurred. .Xr routed 8 , .Xr traceroute 8 , .Xr traceroute6 8 +.Rs +.%A A. Conta +.%A S. Deering +.%T "Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification" +.%N RFC2463 +.%D December 1998 +.Re +.Rs +.%A Matt Crawford +.%T "IPv6 Node Information Queries" +.%N draft-ietf-ipngwg-icmp-name-lookups-05.txt +.%D October 22, 1999 +.%O work in progress material +.Re .Sh HISTORY The .Nm ping diff --git a/sbin/ping6/ping6.c b/sbin/ping6/ping6.c index da6bd38dfdf0..06e68398f149 100644 --- a/sbin/ping6/ping6.c +++ b/sbin/ping6/ping6.c @@ -1,3 +1,5 @@ +/* $KAME: ping6.c,v 1.54 2000/06/12 16:16:44 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -63,12 +65,10 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #ifndef lint -static const char copyright[] = +static char copyright[] = "@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ @@ -77,6 +77,8 @@ static const char copyright[] = #if 0 static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93"; #endif +static const char rcsid[] = + "$FreeBSD$"; #endif /* not lint */ /* @@ -97,7 +99,7 @@ static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93"; /* * NOTE: * USE_SIN6_SCOPE_ID assumes that sin6_scope_id has the same semantics - * as IPV6_PKTINFO. Some objects it (sin6_scope_id specifies *link* while + * as IPV6_PKTINFO. Some people object it (sin6_scope_id specifies *link* while * IPV6_PKTINFO specifies *interface*. Link is defined as collection of * network attached to 1 or more interfaces) */ @@ -134,15 +136,21 @@ static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93"; #include <netinet6/ipsec.h> #endif -#define MAXPACKETLEN 131072 +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +#include <md5.h> +#else +#include "md5.h" +#endif + +#define MAXPACKETLEN 131072 #define IP6LEN 40 -#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 */ +#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 */ #define EXTRA 256 /* for AH and various other headers. weird. */ #define DEFDATALEN ICMP6ECHOTMLEN -#define MAXDATALEN MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN +#define MAXDATALEN MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN #define NROUTES 9 /* number of record route slots */ #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ @@ -161,22 +169,29 @@ static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93"; #define F_VERBOSE 0x0100 #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC -#define F_POLICY 0x4000 +#define F_POLICY 0x0400 #else -#define F_AUTHHDR 0x0200 -#define F_ENCRYPT 0x0400 +#define F_AUTHHDR 0x0200 +#define F_ENCRYPT 0x0400 #endif /*IPSEC_POLICY_IPSEC*/ #endif /*IPSEC*/ -#define F_NODEADDR 0x0800 -#define F_FQDN 0x1000 -#define F_INTERFACE 0x2000 +#define F_NODEADDR 0x0800 +#define F_FQDN 0x1000 +#define F_INTERFACE 0x2000 +#define F_SRCADDR 0x4000 +#ifdef IPV6_REACHCONF +#define F_REACHCONF 0x8000 +#endif +#define F_HOSTNAME 0x10000 +#define F_FQDNOLD 0x20000 +#define F_NIGROUP 0x40000 u_int options; -#define IN6LEN sizeof(struct in6_addr) -#define SA6LEN sizeof(struct sockaddr_in6) -#define DUMMY_PORT 10101 +#define IN6LEN sizeof(struct in6_addr) +#define SA6LEN sizeof(struct sockaddr_in6) +#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 @@ -187,7 +202,7 @@ u_int options; int mx_dup_ck = MAX_DUP_CHK; char rcvd_tbl[MAX_DUP_CHK / 8]; -struct addrinfo *res; +struct addrinfo *res; struct sockaddr_in6 dst; /* who to ping6 */ struct sockaddr_in6 src; /* src addr of this packet */ int datalen = DEFDATALEN; @@ -197,6 +212,7 @@ char BSPACE = '\b'; /* characters written for flood */ char DOT = '.'; char *hostname; int ident; /* process id to identify our packets */ +struct in6_addr srcaddr; /* counters */ long npackets; /* max packets to transmit */ @@ -212,9 +228,6 @@ double tmin = 999999999.0; /* minimum round trip time */ double tmax = 0.0; /* maximum round trip time */ double tsum = 0.0; /* sum of all times, for doing average */ -/* for inet_ntop() */ -char ntop_buf[INET6_ADDRSTRLEN]; - /* for node addresses */ u_short naflags; @@ -226,19 +239,24 @@ char *scmsg = 0; int main __P((int, char *[])); void fill __P((char *, char *)); int get_hoplim __P((struct msghdr *)); +struct in6_pktinfo *get_rcvpktinfo __P((struct msghdr *)); void onalrm __P((int)); void oninfo __P((int)); void onint __P((int)); void pinger __P((void)); -char *pr_addr __P((struct sockaddr_in6 *)); +const char *pr_addr __P((struct sockaddr_in6 *)); void pr_icmph __P((struct icmp6_hdr *, u_char *)); void pr_iph __P((struct ip6_hdr *)); void pr_nodeaddr __P((struct icmp6_nodeinfo *, int)); void pr_pack __P((u_char *, int, struct msghdr *)); +void pr_exthdrs __P((struct msghdr *)); +void pr_ip6opt __P((void *)); +void pr_rthdr __P((void *)); void pr_retip __P((struct ip6_hdr *, u_char *)); void summary __P((void)); void tvsub __P((struct timeval *, struct timeval *)); int setpolicy __P((int, char *)); +char *nigroup __P((char *)); void usage __P((void)); int @@ -246,8 +264,6 @@ main(argc, argv) int argc; char *argv[]; { - extern int errno, optind; - extern char *optarg; struct itimerval itimer; struct sockaddr_in6 from; struct timeval timeout; @@ -260,6 +276,11 @@ main(argc, argv) int ip6optlen = 0; struct cmsghdr *scmsgp = NULL; int sockbufsize = 0; + int usepktinfo = 0; + struct in6_pktinfo *pktinfo = NULL; +#ifdef USE_RFC2292BIS + struct ip6_rthdr *rthdr = NULL; +#endif #ifdef IPSEC_POLICY_IPSEC char *policy_in = NULL; char *policy_out = NULL; @@ -269,21 +290,18 @@ main(argc, argv) memset(&smsghdr, 0, sizeof(&smsghdr)); memset(&smsgiov, 0, sizeof(&smsgiov)); - if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) - err(1, "socket"); - setuid(getuid()); - preload = 0; datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN]; #ifndef IPSEC - while ((ch = getopt(argc, argv, "a:b:c:dfh:I:i:l:np:qRrs:vwW")) != EOF) + while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:vwW")) != EOF) #else #ifdef IPSEC_POLICY_IPSEC - while ((ch = getopt(argc, argv, "a:b:c:dfh:I:i:l:np:qRrs:vwWP:")) != EOF) + while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:vwWP:")) != EOF) #else - while ((ch = getopt(argc, argv, "a:b:c:dfh:I:i:l:np:qRrs:vwWAE")) != EOF) + while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:vwWAE")) != EOF) #endif /*IPSEC_POLICY_IPSEC*/ #endif + { switch(ch) { case 'a': { @@ -317,6 +335,7 @@ main(argc, argv) break; default: usage(); + /*NOTREACHED*/ } } break; @@ -346,6 +365,9 @@ main(argc, argv) options |= F_FLOOD; setbuf(stdout, (char *)NULL); break; + case 'H': + options |= F_HOSTNAME; + break; case 'h': /* hoplimit */ hoplimit = strtol(optarg, &e, 10); if (255 < hoplimit || hoplimit < -1) @@ -355,6 +377,9 @@ main(argc, argv) case 'I': ifname = optarg; options |= F_INTERFACE; +#ifndef USE_SIN6_SCOPE_ID + usepktinfo++; +#endif break; case 'i': /* wait between sending packets */ interval = strtol(optarg, &e, 10); @@ -375,6 +400,9 @@ main(argc, argv) case 'n': options |= F_NUMERIC; break; + case 'N': + options |= F_NIGROUP; + break; case 'p': /* fill buffer with user pattern */ options |= F_PINGFILLED; fill((char *)datap, optarg); @@ -383,7 +411,18 @@ main(argc, argv) options |= F_QUIET; break; case 'R': - options |= F_RROUTE; +#ifdef IPV6_REACHCONF + options |= F_REACHCONF; + break; +#else + errx(1, "-R is not supported in this configuration"); +#endif + case 'S': + /* XXX: use getaddrinfo? */ + if (inet_pton(AF_INET6, optarg, (void *)&srcaddr) != 1) + errx(1, "invalid IPv6 address: %s", optarg); + options |= F_SRCADDR; + usepktinfo++; break; case 's': /* size of packet to send */ datalen = strtol(optarg, &e, 10); @@ -398,9 +437,11 @@ main(argc, argv) options |= F_VERBOSE; break; case 'w': - case 'W': options |= F_FQDN; break; + case 'W': + options |= F_FQDNOLD; + break; #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC case 'P': @@ -423,21 +464,37 @@ main(argc, argv) #endif /*IPSEC*/ default: usage(); + /*NOTREACHED*/ } + } argc -= optind; argv += optind; - if (argc < 1) + if (argc < 1) { usage(); + /*NOTREACHED*/ + } - if (argc > 1) + if (argc > 1) { +#ifdef USE_SIN6_SCOPE_ID + ip6optlen += CMSG_SPACE(inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1)); +#else /* old advanced API */ ip6optlen += inet6_rthdr_space(IPV6_RTHDR_TYPE_0, argc - 1); +#endif + } - target = argv[argc - 1]; + if (options & F_NIGROUP) { + target = nigroup(argv[argc - 1]); + if (target == NULL) { + usage(); + /*NOTREACHED*/ + } + } else + target = argv[argc - 1]; /* getaddrinfo */ bzero(&hints, sizeof(struct addrinfo)); - if ((options & F_NUMERIC) == 0) + if ((options & F_NUMERIC) != 0) hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_RAW; @@ -446,15 +503,13 @@ main(argc, argv) ret_ga = getaddrinfo(target, NULL, &hints, &res); if (ret_ga) { fprintf(stderr, "ping6: %s\n", gai_strerror(ret_ga)); - if (ret_ga == EAI_SYSTEM) - errx(1, "%s", strerror(errno)); exit(1); } if (res->ai_canonname) hostname = res->ai_canonname; else hostname = target; - + if (!res->ai_addr) errx(1, "getaddrinfo failed"); @@ -474,6 +529,9 @@ main(argc, argv) ident = getpid() & 0xFFFF; + if ((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) + err(1, "socket"); + hold = 1; if (options & F_SO_DEBUG) @@ -520,7 +578,8 @@ main(argc, argv) struct icmp6_filter filt; if (!(options & F_VERBOSE)) { ICMP6_FILTER_SETBLOCKALL(&filt); - if ((options & F_FQDN) || (options & F_NODEADDR)) + if ((options & F_FQDN) || (options & F_FQDNOLD) || + (options & F_NODEADDR)) ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filt); else ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt); @@ -533,6 +592,45 @@ main(argc, argv) } #endif /*ICMP6_FILTER*/ + /* let the kerel pass extension headers of incoming packets */ + /* TODO: implement parsing routine */ + if ((options & F_VERBOSE) != 0) { + int opton = 1; + +#ifdef IPV6_RECVRTHDR + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_RECVRTHDR)"); +#else /* old adv. API */ + if (setsockopt(s, IPPROTO_IPV6, IPV6_RTHDR, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_RTHDR)"); +#endif +#ifdef IPV6_RECVHOPOPTS + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_RECVHOPOPTS)"); +#else /* old adv. API */ + if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_HOPOPTS)"); +#endif +#ifdef IPV6_RECVDSTOPTS + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_RECVDSTOPTS)"); +#else /* olad adv. API */ + if (setsockopt(s, IPPROTO_IPV6, IPV6_DSTOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_DSTOPTS)"); +#endif +#ifdef IPV6_RECVRTHDRDSTOPTS + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_RECVRTHDRDSTOPTS)"); +#endif + } + /* optval = 1; if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) @@ -540,19 +638,19 @@ main(argc, argv) &optval, sizeof(optval)) == -1) err(1, "IPV6_MULTICAST_LOOP"); */ - /* record route option */ - if (options & F_RROUTE) - errx(1, "record route not available in this implementation"); - /* Outgoing interface */ -#ifndef USE_SIN6_SCOPE_ID - if (options & F_INTERFACE) + /* Specify the outgoing interface and/or the source address */ + if (usepktinfo) ip6optlen += CMSG_SPACE(sizeof(struct in6_pktinfo)); -#endif if (hoplimit != -1) ip6optlen += CMSG_SPACE(sizeof(int)); +#ifdef IPV6_REACHCONF + if (options & F_REACHCONF) + ip6optlen += CMSG_SPACE(0); +#endif + /* set IP6 packet options */ if (ip6optlen) { if ((scmsg = (char *)malloc(ip6optlen)) == 0) @@ -561,24 +659,30 @@ main(argc, argv) smsghdr.msg_controllen = ip6optlen; scmsgp = (struct cmsghdr *)scmsg; } - if (options & F_INTERFACE) { -#ifndef USE_SIN6_SCOPE_ID - struct in6_pktinfo *pktinfo = - (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); - - if ((pktinfo->ipi6_ifindex = if_nametoindex(ifname)) == 0) - errx(1, "%s: invalid interface name", ifname); - bzero(&pktinfo->ipi6_addr, sizeof(struct in6_addr)); + if (usepktinfo) { + pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); + memset(pktinfo, 0, sizeof(*pktinfo)); scmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); scmsgp->cmsg_level = IPPROTO_IPV6; scmsgp->cmsg_type = IPV6_PKTINFO; - scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); + } + + /* set the outgoing interface */ + if (ifname) { +#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); #else if ((dst.sin6_scope_id = if_nametoindex(ifname)) == 0) errx(1, "%s: invalid interface name", ifname); #endif } + /* set the source address */ + if (options & F_SRCADDR)/* pktinfo must be valid */ + pktinfo->ipi6_addr = srcaddr; + if (hoplimit != -1) { scmsgp->cmsg_len = CMSG_LEN(sizeof(int)); scmsgp->cmsg_level = IPPROTO_IPV6; @@ -587,34 +691,63 @@ main(argc, argv) scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); } +#ifdef IPV6_REACHCONF + if (options & F_REACHCONF) { + scmsgp->cmsg_len = CMSG_LEN(0); + scmsgp->cmsg_level = IPPROTO_IPV6; + scmsgp->cmsg_type = IPV6_REACHCONF; + + scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); + } +#endif + if (argc > 1) { /* some intermediate addrs are specified */ int hops, error; +#ifdef USE_RFC2292BIS + int rthdrlen; +#endif +#ifdef USE_RFC2292BIS + rthdrlen = inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1); + scmsgp->cmsg_len = CMSG_LEN(rthdrlen); + scmsgp->cmsg_level = IPPROTO_IPV6; + scmsgp->cmsg_type = IPV6_RTHDR; + rthdr = (struct ip6_rthdr *)CMSG_DATA(scmsgp); + rthdr = inet6_rth_init((void *)rthdr, rthdrlen, + IPV6_RTHDR_TYPE_0, argc - 1); + if (rthdr == NULL) + errx(1, "can't initialize rthdr"); +#else /* old advanced API */ if ((scmsgp = (struct cmsghdr *)inet6_rthdr_init(scmsgp, IPV6_RTHDR_TYPE_0)) == 0) errx(1, "can't initialize rthdr"); +#endif /* USE_RFC2292BIS */ for (hops = 0; hops < argc - 1; hops++) { struct addrinfo *iaip; - if ((error = getaddrinfo(argv[hops], NULL, &hints, &iaip))) { - fprintf(stderr, "ping6: %s\n", gai_strerror(error)); - if (error == EAI_SYSTEM) - errx(1, strerror(errno)); - exit(1); - } + if ((error = getaddrinfo(argv[hops], NULL, &hints, &iaip))) + errx(1, gai_strerror(error)); if (SIN6(res->ai_addr)->sin6_family != AF_INET6) errx(1, "bad addr family of an intermediate addr"); +#ifdef USE_RFC2292BIS + if (inet6_rth_add(rthdr, + &(SIN6(iaip->ai_addr))->sin6_addr)) + errx(1, "can't add an intermediate node"); +#else /* old advanced API */ if (inet6_rthdr_add(scmsgp, &(SIN6(iaip->ai_addr))->sin6_addr, IPV6_RTHDR_LOOSE)) errx(1, "can't add an intermediate node"); +#endif /* USE_RFC2292BIS */ } +#ifndef USE_RFC2292BIS if (inet6_rthdr_lasthop(scmsgp, IPV6_RTHDR_LOOSE)) errx(1, "can't set the last flag"); +#endif scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); } @@ -624,7 +757,7 @@ main(argc, argv) * source selection */ int dummy, len = sizeof(src); - + if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) err(1, "UDP socket"); @@ -633,19 +766,38 @@ main(argc, argv) src.sin6_port = ntohs(DUMMY_PORT); src.sin6_scope_id = dst.sin6_scope_id; -#ifndef USE_SIN6_SCOPE_ID - if (setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTOPTIONS, + +#ifdef USE_SIN6_SCOPE_ID + src.sin6_scope_id = dst.sin6_scope_id; +#endif + +#ifdef USE_RFC2292BIS + if (pktinfo && + setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTINFO, + (void *)pktinfo, sizeof(*pktinfo))) + err(1, "UDP setsockopt(IPV6_PKTINFO)"); + + if (hoplimit != -1 && + setsockopt(dummy, IPPROTO_IPV6, IPV6_HOPLIMIT, + (void *)&hoplimit, sizeof(hoplimit))) + err(1, "UDP setsockopt(IPV6_HOPLIMIT)"); + + if (rthdr && + setsockopt(dummy, IPPROTO_IPV6, IPV6_RTHDR, + (void *)rthdr, (rthdr->ip6r_len + 1) << 3)) + err(1, "UDP setsockopt(IPV6_RTHDR)"); +#else /* old advanced API */ + if (smsghdr.msg_control && + setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTOPTIONS, (void *)smsghdr.msg_control, smsghdr.msg_controllen)) { - err(1, "UDP setsockopt"); + err(1, "UDP setsockopt(IPV6_PKTOPTIONS)"); } -#else - src.sin6_scope_id = dst.sin6_scope_id; #endif - + if (connect(dummy, (struct sockaddr *)&src, len) < 0) err(1, "UDP connect"); - + if (getsockname(dummy, (struct sockaddr *)&src, &len) < 0) err(1, "getsockname"); @@ -655,7 +807,7 @@ main(argc, argv) #if defined(SO_SNDBUF) && defined(SO_RCVBUF) if (sockbufsize) { if (datalen > sockbufsize) - warnx("you need -b to increae socket buffer size"); + warnx("you need -b to increase socket buffer size"); if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize, sizeof(sockbufsize)) < 0) err(1, "setsockopt(SO_SNDBUF)"); @@ -679,13 +831,29 @@ main(argc, argv) optval = 1; #ifndef USE_SIN6_SCOPE_ID - setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &optval, sizeof(optval)); +#ifdef IPV6_RECVPKTINFO + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval, + sizeof(optval)) < 0) + warn("setsockopt(IPV6_RECVPKTINFO)"); /* XXX err? */ +#else /* old adv. API */ + if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &optval, + sizeof(optval)) < 0) + warn("setsockopt(IPV6_PKTINFO)"); /* XXX err? */ +#endif +#endif /* USE_SIN6_SCOPE_ID */ +#ifdef IPV6_RECVHOPLIMIT + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval, + sizeof(optval)) < 0) + warn("setsockopt(IPV6_RECVHOPLIMIT)"); /* XXX err? */ +#else /* old adv. API */ + if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval, + sizeof(optval)) < 0) + warn("setsockopt(IPV6_HOPLIMIT)"); /* XXX err? */ #endif - setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval, sizeof(optval)); printf("PING6(%d=40+8+%d bytes) ", datalen + 48, datalen); - printf("%s --> ", inet_ntop(AF_INET6, &src.sin6_addr, ntop_buf, sizeof(ntop_buf))); - printf("%s\n", inet_ntop(AF_INET6, &dst.sin6_addr, ntop_buf, sizeof(ntop_buf))); + printf("%s --> ", pr_addr(&src)); + printf("%s\n", pr_addr(&dst)); while (preload--) /* Fire off them quickies. */ pinger(); @@ -708,7 +876,7 @@ main(argc, argv) for (;;) { struct msghdr m; struct cmsghdr *cm; - u_char buf[256]; + u_char buf[1024]; struct iovec iov[2]; if (options & F_FLOOD) { @@ -749,6 +917,7 @@ main(argc, argv) * onalrm -- * This routine transmits another ping6. */ +/* ARGSUSED */ void onalrm(signo) int signo; @@ -796,6 +965,7 @@ pinger() int i, cc; icp = (struct icmp6_hdr *)outpack; + memset(icp, 0, sizeof(*icp)); icp->icmp6_code = 0; icp->icmp6_cksum = 0; icp->icmp6_seq = ntransmitted++; /* htons later */ @@ -806,9 +976,24 @@ pinger() 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); + memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr, + sizeof(dst.sin6_addr)); + cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr); + datalen = 0; + } 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 */ - icp->icmp6_data16[0] = htons(NI_QTYPE_FQDN); + ((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); @@ -816,13 +1001,17 @@ pinger() datalen = 0; } else if (options & F_NODEADDR) { icp->icmp6_type = ICMP6_NI_QUERY; - /* code field is always 0 */ + icp->icmp6_code = ICMP6_NI_SUBJ_IPV6; /* XXX: overwrite icmp6_id */ - icp->icmp6_data16[0] = htons(NI_QTYPE_NODEADDR); + ((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); - cc = ICMP6_NIQLEN; + 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; } @@ -867,87 +1056,38 @@ pr_pack(buf, cc, mhdr) int cc; struct msghdr *mhdr; { +#define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c) struct icmp6_hdr *icp; int i; int hoplim; struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; u_char *cp = NULL, *dp, *end = buf + cc; -#ifdef OLD_RAWSOCKET - struct ip6_hdr *ip; -#endif + struct in6_pktinfo *pktinfo = NULL; struct timeval tv, *tp; double triptime = 0; int dupflag; size_t off; + int oldfqdn; (void)gettimeofday(&tv, NULL); -#ifdef OLD_RAWSOCKET - /* Check the IP header */ - ip = (struct ip6_hdr *)buf; - if (cc < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) { - if (options & F_VERBOSE) - warnx("packet too short (%d bytes) from %s\n", cc, - inet_ntop(AF_INET6, (void *)&from->sin6_addr, - ntop_buf, sizeof(ntop_buf))); - return; - } - - /* chase nexthdr link */ - { - u_int8_t nh; - struct ah *ah; - struct ip6_ext *ip6e; - - off = IP6LEN; - nh = ip->ip6_nxt; - while (nh != IPPROTO_ICMPV6) { - if (options & F_VERBOSE) - fprintf(stderr, "header chain: type=0x%x\n", nh); - - switch (nh) { -#ifdef IPSEC - case IPPROTO_AH: - ah = (struct ah *)(buf + off); - off += sizeof(struct ah); - off += (ah->ah_len << 2); - nh = ah->ah_nxt; - break; -#endif - - case IPPROTO_HOPOPTS: - ip6e = (struct ip6_ext *)(buf + off); - off += (ip6e->ip6e_len + 1) << 3; - nh = ip6e->ip6e_nxt; - break; - default: - if (options & F_VERBOSE) { - fprintf(stderr, - "unknown header type=0x%x: drop it\n", - nh); - } - return; - } - } - } - /* Now the ICMP part */ - icp = (struct icmp6_hdr *)(buf + off); -#else if (cc < sizeof(struct icmp6_hdr)) { if (options & F_VERBOSE) warnx("packet too short (%d bytes) from %s\n", cc, - inet_ntop(AF_INET6, (void *)&from->sin6_addr, - ntop_buf, sizeof(ntop_buf))); + pr_addr(from)); return; } icp = (struct icmp6_hdr *)buf; off = 0; -#endif if ((hoplim = get_hoplim(mhdr)) == -1) { warnx("failed to get receiving hop limit"); return; } + if ((pktinfo = get_rcvpktinfo(mhdr)) == NULL) { + warnx("failed to get receiving pakcet information"); + return; + } if (icp->icmp6_type == ICMP6_ECHO_REPLY) { /* XXX the following line overwrites the original packet */ @@ -983,10 +1123,19 @@ pr_pack(buf, cc, mhdr) (void)write(STDOUT_FILENO, &BSPACE, 1); else { (void)printf("%d bytes from %s, icmp_seq=%u", cc, - inet_ntop(AF_INET6, &from->sin6_addr, - ntop_buf, sizeof(ntop_buf)), + pr_addr(from), icp->icmp6_seq); (void)printf(" hlim=%d", hoplim); + if ((options & F_VERBOSE) != 0) { + struct sockaddr_in6 dstsa; + + memset(&dstsa, 0, sizeof(dstsa)); + dstsa.sin6_family = AF_INET6; + dstsa.sin6_len = sizeof(dstsa); + dstsa.sin6_scope_id = pktinfo->ipi6_ifindex; + dstsa.sin6_addr = pktinfo->ipi6_addr; + (void)printf(" dst=%s", pr_addr(&dstsa)); + } if (timing) (void)printf(" time=%g ms", triptime); if (dupflag) @@ -1019,55 +1168,112 @@ pr_pack(buf, cc, mhdr) break; case NI_QTYPE_FQDN: default: /* XXX: for backward compatibility */ - cp = (u_char *)ni + ICMP6_NIRLEN + 1; - while (cp < end) { - if (isprint(*cp)) - putchar(*cp); - else - printf("\\%03o", *cp & 0xff); - cp++; - } - if (options & F_VERBOSE) { - long ttl; - - (void)printf(" ("); - - switch(ni->ni_code) { - case ICMP6_NI_REFUSED: - (void)printf("refused,"); - break; - case ICMP6_NI_UNKNOWN: - (void)printf("unknwon qtype,"); - break; - } + cp = (u_char *)ni + ICMP6_NIRLEN; + if (buf[off + ICMP6_NIRLEN] == + cc - off - ICMP6_NIRLEN - 1) + oldfqdn = 1; + else + oldfqdn = 0; + if (oldfqdn) { + cp++; + while (cp < end) { + safeputc(*cp & 0xff); + cp++; + } + } else { + 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("???"); + } + break; + } + } + } + if (options & F_VERBOSE) { + int32_t ttl; + int comma = 0; - if ((end - (u_char *)ni) < ICMP6_NIRLEN) { - /* case of refusion, unkown */ - goto fqdnend; - } - ttl = ntohl(*(u_long *)&buf[off+ICMP6ECHOLEN+8]); - if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) - (void)printf("TTL=%d:meaningless", - (int)ttl); - else { - if (ttl < 0) - (void)printf("TTL=%d:invalid", - (int)ttl); - else - (void)printf("TTL=%d", - (int)ttl); - } + (void)printf(" ("); /*)*/ - if (buf[off + ICMP6_NIRLEN] != - cc - off - ICMP6_NIRLEN - 1) { - (void)printf(",invalid namelen:%d/%lu", - buf[off + ICMP6_NIRLEN], - (u_long)cc - off - ICMP6_NIRLEN - 1); - } - putchar(')'); - } - fqdnend: - ; + switch(ni->ni_code) { + case ICMP6_NI_REFUSED: + (void)printf("refused"); + comma++; + break; + case ICMP6_NI_UNKNOWN: + (void)printf("unknwon qtype"); + comma++; + break; + } + + if ((end - (u_char *)ni) < ICMP6_NIRLEN) { + /* case of refusion, unkown */ + goto fqdnend; + } + ttl = (int32_t)ntohl(*(u_long *)&buf[off+ICMP6ECHOLEN+8]); + if (comma) + printf(","); + if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) + (void)printf("TTL=%d:meaningless", + (int)ttl); + else { + if (ttl < 0) { + (void)printf("TTL=%d:invalid", + ttl); + } else + (void)printf("TTL=%d", ttl); + } + comma++; + + if (oldfqdn) { + if (comma) + printf(","); + printf("03 draft"); + comma++; + } else { + cp = (u_char *)ni + ICMP6_NIRLEN; + if (cp == end) { + if (comma) + printf(","); + printf("no name"); + comma++; + } + } + + if (buf[off + ICMP6_NIRLEN] != + cc - off - ICMP6_NIRLEN - 1 && oldfqdn) { + if (comma) + printf(","); + (void)printf("invalid namelen:%d/%lu", + buf[off + ICMP6_NIRLEN], + (u_long)cc - off - ICMP6_NIRLEN - 1); + comma++; + } + /*(*/ + putchar(')'); + } + fqdnend: + ; } } else { /* We've got something other than an ECHOREPLY */ @@ -1080,16 +1286,153 @@ pr_pack(buf, cc, mhdr) if (!(options & F_FLOOD)) { (void)putchar('\n'); + if (options & F_VERBOSE) + pr_exthdrs(mhdr); (void)fflush(stdout); } +#undef safeputc +} + +void +pr_exthdrs(mhdr) + struct msghdr *mhdr; +{ + struct cmsghdr *cm; + + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { + if (cm->cmsg_level != IPPROTO_IPV6) + continue; + + switch(cm->cmsg_type) { + case IPV6_HOPOPTS: + printf(" HbH Options: "); + pr_ip6opt(CMSG_DATA(cm)); + break; + case IPV6_DSTOPTS: +#ifdef IPV6_RTHDRDSTOPTS + case IPV6_RTHDRDSTOPTS: +#endif + printf(" Dst Options: "); + pr_ip6opt(CMSG_DATA(cm)); + break; + case IPV6_RTHDR: + printf(" Routing: "); + pr_rthdr(CMSG_DATA(cm)); + break; + } + } } +#ifdef USE_RFC2292BIS +void +pr_ip6opt(void *extbuf) +{ + struct ip6_hbh *ext; + int currentlen; + u_int8_t type; + size_t extlen, len; + void *databuf; + size_t offset; + u_int16_t value2; + u_int32_t value4; + + ext = (struct ip6_hbh *)extbuf; + extlen = (ext->ip6h_len + 1) * 8; + printf("nxt %u, len %u (%d bytes)\n", ext->ip6h_nxt, + ext->ip6h_len, extlen); + + currentlen = 0; + while (1) { + currentlen = inet6_opt_next(extbuf, extlen, currentlen, + &type, &len, &databuf); + if (currentlen == -1) + break; + switch (type) { + /* + * Note that inet6_opt_next automatically skips any padding + * optins. + */ + case IP6OPT_JUMBO: + offset = 0; + offset = inet6_opt_get_val(databuf, offset, + &value4, sizeof(value4)); + printf(" Jumbo Payload Opt: Length %u\n", + (unsigned int)ntohl(value4)); + break; + case IP6OPT_ROUTER_ALERT: + offset = 0; + offset = inet6_opt_get_val(databuf, offset, + &value2, sizeof(value2)); + printf(" Router Alert Opt: Type %u\n", + ntohs(value2)); + break; + default: + printf(" Received Opt %u len %u\n", type, len); + break; + } + } + return; +} +#else /* !USE_RFC2292BIS */ +/* ARGSUSED */ +void +pr_ip6opt(void *extbuf) +{ + putchar('\n'); + return; +} +#endif /* USE_RFC2292BIS */ + +#ifdef USE_RFC2292BIS +void +pr_rthdr(void *extbuf) +{ + struct in6_addr *in6; + char ntopbuf[INET6_ADDRSTRLEN]; + struct ip6_rthdr *rh = (struct ip6_rthdr *)extbuf; + int i, segments; + + /* print fixed part of the header */ + printf("nxt %u, len %u (%d bytes), type %u, ", rh->ip6r_nxt, + rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type); + if ((segments = inet6_rth_segments(extbuf)) >= 0) + printf("%d segments, ", segments); + else + printf("segments unknown, "); + printf("%d left\n", rh->ip6r_segleft); + + for (i = 0; i < segments; i++) { + in6 = inet6_rth_getaddr(extbuf, i); + if (in6 == NULL) + printf(" [%d]<NULL>\n", i); + else + printf(" [%d]%s\n", i, + inet_ntop(AF_INET6, in6, + ntopbuf, sizeof(ntopbuf))); + } + + return; + +} +#else /* !USE_RFC2292BIS */ +/* ARGSUSED */ +void +pr_rthdr(void *extbuf) +{ + putchar('\n'); + return; +} +#endif /* USE_RFC2292BIS */ + + void pr_nodeaddr(ni, nilen) struct icmp6_nodeinfo *ni; /* ni->qtype must be NODEADDR */ int nilen; { struct in6_addr *ia6 = (struct in6_addr *)(ni + 1); + char ntop_buf[INET6_ADDRSTRLEN]; nilen -= sizeof(struct icmp6_nodeinfo); @@ -1131,6 +1474,23 @@ get_hoplim(mhdr) return(-1); } +struct in6_pktinfo * +get_rcvpktinfo(mhdr) + struct msghdr *mhdr; +{ + struct cmsghdr *cm; + + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_PKTINFO && + cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) + return((struct in6_pktinfo *)CMSG_DATA(cm)); + } + + return(NULL); +} + /* * tvsub -- * Subtract 2 timeval structs: out = out - in. Out is assumed to @@ -1151,6 +1511,7 @@ tvsub(out, in) * oninfo -- * SIGINFO handler. */ +/* ARGSUSED */ void oninfo(notused) int notused; @@ -1162,6 +1523,7 @@ oninfo(notused) * onint -- * SIGINT handler. */ +/* ARGSUSED */ void onint(notused) int notused; @@ -1232,6 +1594,8 @@ pr_icmph(icp, end) struct icmp6_hdr *icp; u_char *end; { + char ntop_buf[INET6_ADDRSTRLEN]; + switch(icp->icmp6_type) { case ICMP6_DST_UNREACH: switch(icp->icmp6_code) { @@ -1262,6 +1626,7 @@ pr_icmph(icp, end) case ICMP6_PACKET_TOO_BIG: (void)printf("Packet too big mtu = %d\n", (int)ntohl(icp->icmp6_mtu)); + pr_retip((struct ip6_hdr *)(icp + 1), end); break; case ICMP6_TIME_EXCEEDED: switch(icp->icmp6_code) { @@ -1299,57 +1664,57 @@ pr_icmph(icp, end) pr_retip((struct ip6_hdr *)(icp + 1), end); break; case ICMP6_ECHO_REQUEST: - (void)printf("Echo Request\n"); + (void)printf("Echo Request"); /* XXX ID + Seq + Data */ break; case ICMP6_ECHO_REPLY: - (void)printf("Echo Reply\n"); + (void)printf("Echo Reply"); /* XXX ID + Seq + Data */ break; case ICMP6_MEMBERSHIP_QUERY: - (void)printf("Membership Query\n"); + (void)printf("Listener Query"); break; case ICMP6_MEMBERSHIP_REPORT: - (void)printf("Membership Report\n"); + (void)printf("Listener Report"); break; case ICMP6_MEMBERSHIP_REDUCTION: - (void)printf("Membership Reduction\n"); + (void)printf("Listener Done"); break; case ND_ROUTER_SOLICIT: - (void)printf("Router Solicitation\n"); + (void)printf("Router Solicitation"); break; case ND_ROUTER_ADVERT: - (void)printf("Router Advertisement\n"); + (void)printf("Router Advertisement"); break; case ND_NEIGHBOR_SOLICIT: - (void)printf("Neighbor Solicitation\n"); + (void)printf("Neighbor Solicitation"); break; case ND_NEIGHBOR_ADVERT: - (void)printf("Neighbor Advertisement\n"); + (void)printf("Neighbor Advertisement"); break; case ND_REDIRECT: { struct nd_redirect *red = (struct nd_redirect *)icp; (void)printf("Redirect\n"); - (void)printf("Destination: %s\n", + (void)printf("Destination: %s", inet_ntop(AF_INET6, &red->nd_rd_dst, ntop_buf, sizeof(ntop_buf))); - (void)printf("New Target: %s\n", + (void)printf("New Target: %s", inet_ntop(AF_INET6, &red->nd_rd_target, ntop_buf, sizeof(ntop_buf))); break; } case ICMP6_NI_QUERY: - (void)printf("Node Information Query\n"); + (void)printf("Node Information Query"); /* XXX ID + Seq + Data */ break; case ICMP6_NI_REPLY: - (void)printf("Node Information Reply\n"); + (void)printf("Node Information Reply"); /* XXX ID + Seq + Data */ break; default: - (void)printf("Bad ICMP type: %d\n", icp->icmp6_type); + (void)printf("Bad ICMP type: %d", icp->icmp6_type); } } @@ -1363,6 +1728,7 @@ pr_iph(ip6) { u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; u_int8_t tc; + char ntop_buf[INET6_ADDRSTRLEN]; tc = *(&ip6->ip6_vfc + 1); /* XXX */ tc = (tc >> 4) & 0x0f; @@ -1374,9 +1740,9 @@ pr_iph(ip6) ntohs(ip6->ip6_plen), ip6->ip6_nxt, ip6->ip6_hlim); printf("%s->", inet_ntop(AF_INET6, &ip6->ip6_src, - ntop_buf, INET6_ADDRSTRLEN)); + ntop_buf, sizeof(ntop_buf))); printf("%s\n", inet_ntop(AF_INET6, &ip6->ip6_dst, - ntop_buf, INET6_ADDRSTRLEN)); + ntop_buf, sizeof(ntop_buf))); } /* @@ -1384,17 +1750,18 @@ pr_iph(ip6) * Return an ascii host address as a dotted quad and optionally with * a hostname. */ -char * +const char * pr_addr(addr) struct sockaddr_in6 *addr; { static char buf[MAXHOSTNAMELEN]; int flag = 0; - if (options & F_NUMERIC) + 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); @@ -1505,7 +1872,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); @@ -1545,20 +1912,60 @@ setpolicy(so, policy) #endif #endif +char * +nigroup(name) + char *name; +{ + char *p; + MD5_CTX ctxt; + u_int8_t digest[16]; + char 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*/ + l = p - name; + + /* generate 8 bytes of pseudo-random value. */ + bzero(&ctxt, sizeof(ctxt)); + MD5Init(&ctxt); + MD5Update(&ctxt, &l, sizeof(l)); + MD5Update(&ctxt, name, p - name); + MD5Final(digest, &ctxt); + + bzero(&in6, sizeof(in6)); + in6.s6_addr[0] = 0xff; + in6.s6_addr[1] = 0x02; + in6.s6_addr[11] = 0x02; + bcopy(digest, &in6.s6_addr[12], 4); + + if (inet_ntop(AF_INET6, &in6, hbuf, sizeof(hbuf)) == NULL) + return NULL; + + return strdup(hbuf); +} + void usage() { (void)fprintf(stderr, -"usage: ping6 [-dfnqRrvwW" +"usage: ping6 [-dfHnNqvwW" +#ifdef IPV6_REACHCONF + "R" +#endif #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC "] [-P policy" #else "AE" #endif -#endif - "] [-a [aclsg]] [-b sockbufsiz] [-c count] [-I interface]\n\ - [-i wait] [-l preload] [-p pattern] [-s packetsize]\n\ - [-h hoplimit] host [hosts...]\n"); +#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"); exit(1); } diff --git a/sbin/rtsol/Makefile b/sbin/rtsol/Makefile index d373d6cbcd0c..4926191fd5ee 100644 --- a/sbin/rtsol/Makefile +++ b/sbin/rtsol/Makefile @@ -18,9 +18,9 @@ SRCDIR= ${.CURDIR}/../../usr.sbin/rtsold PROG= rtsol SRCS= rtsold.c rtsol.c if.c probe.c dump.c -CFLAGS+=-DINET6 -LDADD+= -lkvm -DPADD+= ${LIBKVM} +CFLAGS+=-DINET6 -DHAVE_GETIFADDRS +LDADD= -lkvm +DPADD= ${LIBKVM} NOMAN= yes diff --git a/usr.bin/kdump/mkioctls b/usr.bin/kdump/mkioctls index a295a591f449..fbce2a929ad2 100644 --- a/usr.bin/kdump/mkioctls +++ b/usr.bin/kdump/mkioctls @@ -53,6 +53,9 @@ BEGIN { print "#include <netinet/ip_frag.h>" print "#include <netinet/ip_state.h>" print "#include <netinet/ip_mroute.h>" + print "#include <netinet6/in6_var.h>" + print "#include <netinet6/nd6.h>" + print "#include <netinet6/ip6_mroute.h>" print "#include <cam/cam.h>" print "#include <stdio.h>" print "" diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile index f52e79269815..7f88c3bfef64 100644 --- a/usr.bin/netstat/Makefile +++ b/usr.bin/netstat/Makefile @@ -3,8 +3,9 @@ PROG= netstat SRCS= if.c inet.c inet6.c main.c mbuf.c mroute.c ipx.c route.c \ - unix.c atalk.c netgraph.c mroute6.c # iso.c ns.c tp_astring.c + unix.c atalk.c netgraph.c mroute6.c ipsec.c # iso.c ns.c tp_astring.c CFLAGS+=-Wall +CFLAGS+=-DIPSEC #CFLAGS+=-g #.PATH: ${.CURDIR}/../../sys/netiso diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c index ac09c4b66a37..c14c7a202ad6 100644 --- a/usr.bin/netstat/inet.c +++ b/usr.bin/netstat/inet.c @@ -68,9 +68,6 @@ static const char rcsid[] = #include <netinet/tcp_debug.h> #include <netinet/udp.h> #include <netinet/udp_var.h> -#ifdef IPSEC -#include <netinet6/ipsec.h> -#endif #include <arpa/inet.h> #include <err.h> @@ -682,109 +679,6 @@ igmp_stats(off, name) #undef py } -#ifdef IPSEC -static char *ipsec_ahnames[] = { - "none", - "hmac MD5", - "hmac SHA1", - "keyed MD5", - "keyed SHA1", - "null", -}; - -static char *ipsec_espnames[] = { - "none", - "DES CBC", - "3DES CBC", - "simple", - "blowfish CBC", - "CAST128 CBC", - "RC5 CBC", -}; - -/* - * Dump IPSEC statistics structure. - */ -void -ipsec_stats(off, name) - u_long off; - char *name; -{ - struct ipsecstat ipsecstat; - int first, proto; - - if (off == 0) - return; - printf ("%s:\n", name); - kread(off, (char *)&ipsecstat, sizeof (ipsecstat)); - -#define p(f, m) if (ipsecstat.f || sflag <= 1) \ - printf(m, ipsecstat.f, plural(ipsecstat.f)) - - p(in_success, "\t%lu inbound packet%s processed successfully\n"); - p(in_polvio, "\t%lu inbound packet%s violated process security " - "policy\n"); - p(in_nosa, "\t%lu inbound packet%s with no SA available\n"); - p(in_inval, "\t%lu inbound packet%s failed processing due to EINVAL\n"); - p(in_badspi, "\t%lu inbound packet%s failed getting SPI\n"); - p(in_ahreplay, "\t%lu inbound packet%s failed on AH replay check\n"); - p(in_espreplay, "\t%lu inbound packet%s failed on ESP replay check\n"); - p(in_ahauthsucc, "\t%lu inbound AH packet%s considered authentic\n"); - p(in_ahauthfail, "\t%lu inbound AH packet%s failed on authentication\n"); - p(in_espauthsucc, "\t%lu inbound ESP packet%s considered authentic\n"); - p(in_espauthfail, "\t%lu inbound ESP packet%s failed on authentication\n"); - for (first = 1, proto = 0; proto < SADB_AALG_MAX; proto++) { - if (ipsecstat.in_ahhist[proto] <= 0) - continue; - if (first) { - printf("\tAH input histogram:\n"); - first = 0; - } - printf("\t\t%s: %lu\n", ipsec_ahnames[proto], - ipsecstat.in_ahhist[proto]); - } - for (first = 1, proto = 0; proto < SADB_EALG_MAX; proto++) { - if (ipsecstat.in_esphist[proto] <= 0) - continue; - if (first) { - printf("\tESP input histogram:\n"); - first = 0; - } - printf("\t\t%s: %lu\n", ipsec_espnames[proto], - ipsecstat.in_esphist[proto]); - } - - p(out_success, "\t%lu outbound packet%s processed successfully\n"); - p(out_polvio, "\t%lu outbound packet%s violated process security " - "policy\n"); - p(out_nosa, "\t%lu outbound packet%s with no SA available\n"); - p(out_inval, "\t%lu outbound packet%s failed processing due to " - "EINVAL\n"); - p(out_noroute, "\t%lu outbound packet%s with no route\n"); - for (first = 1, proto = 0; proto < SADB_AALG_MAX; proto++) { - if (ipsecstat.out_ahhist[proto] <= 0) - continue; - if (first) { - printf("\tAH output histogram:\n"); - first = 0; - } - printf("\t\t%s: %lu\n", ipsec_ahnames[proto], - ipsecstat.out_ahhist[proto]); - } - for (first = 1, proto = 0; proto < SADB_EALG_MAX; proto++) { - if (ipsecstat.out_esphist[proto] <= 0) - continue; - if (first) { - printf("\tESP output histogram:\n"); - first = 0; - } - printf("\t\t%s: %lu\n", ipsec_espnames[proto], - ipsecstat.out_esphist[proto]); - } -#undef p -} -#endif /*IPSEC*/ - /* * Pretty print an Internet address (net address + port). */ diff --git a/usr.bin/netstat/inet6.c b/usr.bin/netstat/inet6.c index c1c65f289b1f..c078b33053d7 100644 --- a/usr.bin/netstat/inet6.c +++ b/usr.bin/netstat/inet6.c @@ -164,7 +164,7 @@ static char *ip6nh[] = { "#86", "#87", "#88", - "#89", + "OSPF", "#80", "#91", "#92", @@ -351,44 +351,44 @@ ip6_stats(off, name) printf("%s:\n", name); #define p(f, m) if (ip6stat.f || sflag <= 1) \ - printf(m, ip6stat.f, plural(ip6stat.f)) + printf(m, (unsigned long long)ip6stat.f, plural(ip6stat.f)) #define p1a(f, m) if (ip6stat.f || sflag <= 1) \ - printf(m, ip6stat.f) - - p(ip6s_total, "\t%lu total packet%s received\n"); - p1a(ip6s_toosmall, "\t%lu with size smaller than minimum\n"); - p1a(ip6s_tooshort, "\t%lu with data size < data length\n"); - p1a(ip6s_badoptions, "\t%lu with bad options\n"); - p1a(ip6s_badvers, "\t%lu with incorrect version number\n"); - p(ip6s_fragments, "\t%lu fragment%s received\n"); - p(ip6s_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n"); - p(ip6s_fragtimeout, "\t%lu fragment%s dropped after timeout\n"); - p(ip6s_fragoverflow, "\t%lu fragment%s that exceeded limit\n"); - p(ip6s_reassembled, "\t%lu packet%s reassembled ok\n"); - p(ip6s_delivered, "\t%lu packet%s for this host\n"); - p(ip6s_forward, "\t%lu packet%s forwarded\n"); - p(ip6s_cantforward, "\t%lu packet%s not forwardable\n"); - p(ip6s_redirectsent, "\t%lu redirect%s sent\n"); - p(ip6s_localout, "\t%lu packet%s sent from this host\n"); - p(ip6s_rawout, "\t%lu packet%s sent with fabricated ip header\n"); - p(ip6s_odropped, "\t%lu output packet%s dropped due to no bufs, etc.\n"); - p(ip6s_noroute, "\t%lu output packet%s discarded due to no route\n"); - p(ip6s_fragmented, "\t%lu output datagram%s fragmented\n"); - p(ip6s_ofragments, "\t%lu fragment%s created\n"); - p(ip6s_cantfrag, "\t%lu datagram%s that can't be fragmented\n"); - p(ip6s_badscope, "\t%lu packet%s that violated scope rules\n"); - p(ip6s_notmember, "\t%lu multicast packet%s which we don't join\n"); + printf(m, (unsigned long long)ip6stat.f) + + p(ip6s_total, "\t%llu total packet%s received\n"); + p1a(ip6s_toosmall, "\t%llu with size smaller than minimum\n"); + p1a(ip6s_tooshort, "\t%llu with data size < data length\n"); + p1a(ip6s_badoptions, "\t%llu with bad options\n"); + p1a(ip6s_badvers, "\t%llu with incorrect version number\n"); + p(ip6s_fragments, "\t%llu fragment%s received\n"); + p(ip6s_fragdropped, "\t%llu fragment%s dropped (dup or out of space)\n"); + p(ip6s_fragtimeout, "\t%llu fragment%s dropped after timeout\n"); + p(ip6s_fragoverflow, "\t%llu fragment%s that exceeded limit\n"); + p(ip6s_reassembled, "\t%llu packet%s reassembled ok\n"); + p(ip6s_delivered, "\t%llu packet%s for this host\n"); + p(ip6s_forward, "\t%llu packet%s forwarded\n"); + p(ip6s_cantforward, "\t%llu packet%s not forwardable\n"); + p(ip6s_redirectsent, "\t%llu redirect%s sent\n"); + p(ip6s_localout, "\t%llu packet%s sent from this host\n"); + p(ip6s_rawout, "\t%llu packet%s sent with fabricated ip header\n"); + p(ip6s_odropped, "\t%llu output packet%s dropped due to no bufs, etc.\n"); + p(ip6s_noroute, "\t%llu output packet%s discarded due to no route\n"); + p(ip6s_fragmented, "\t%llu output datagram%s fragmented\n"); + p(ip6s_ofragments, "\t%llu fragment%s created\n"); + p(ip6s_cantfrag, "\t%llu datagram%s that can't be fragmented\n"); + p(ip6s_badscope, "\t%llu packet%s that violated scope rules\n"); + p(ip6s_notmember, "\t%llu multicast packet%s which we don't join\n"); for (first = 1, i = 0; i < 256; i++) if (ip6stat.ip6s_nxthist[i] != 0) { if (first) { printf("\tInput histogram:\n"); first = 0; } - printf("\t\t%s: %lu\n", ip6nh[i], - ip6stat.ip6s_nxthist[i]); + printf("\t\t%s: %llu\n", ip6nh[i], + (unsigned long long)ip6stat.ip6s_nxthist[i]); } printf("\tMbuf statistics:\n"); - printf("\t\t%lu one mbuf\n", ip6stat.ip6s_m1); + printf("\t\t%llu one mbuf\n", (unsigned long long)ip6stat.ip6s_m1); for (first = 1, i = 0; i < 32; i++) { char ifbuf[IFNAMSIZ]; if (ip6stat.ip6s_m2m[i] != 0) { @@ -396,17 +396,94 @@ ip6_stats(off, name) printf("\t\ttwo or more mbuf:\n"); first = 0; } - printf("\t\t\t%s= %ld\n", - if_indextoname(i, ifbuf), - ip6stat.ip6s_m2m[i]); + printf("\t\t\t%s= %llu\n", + if_indextoname(i, ifbuf), + (unsigned long long)ip6stat.ip6s_m2m[i]); + } + } + printf("\t\t%llu one ext mbuf\n", + (unsigned long long)ip6stat.ip6s_mext1); + printf("\t\t%llu two or more ext mbuf\n", + (unsigned long long)ip6stat.ip6s_mext2m); + p(ip6s_exthdrtoolong, + "\t%llu packet%s whose headers are not continuous\n"); + p(ip6s_nogif, "\t%llu tunneling packet%s that can't find gif\n"); + p(ip6s_toomanyhdr, + "\t%llu packet%s discarded due to too may headers\n"); + + /* for debugging source address selection */ +#define PRINT_SCOPESTAT(s,i) do {\ + switch(i) { /* XXX hardcoding in each case */\ + case 1:\ + p(s, "\t\t%llu node-local%s\n");\ + break;\ + case 2:\ + p(s,"\t\t%llu link-local%s\n");\ + break;\ + case 5:\ + p(s,"\t\t%llu site-local%s\n");\ + break;\ + case 14:\ + p(s,"\t\t%llu global%s\n");\ + break;\ + default:\ + printf("\t\t%llu addresses scope=%x\n",\ + (unsigned long long)ip6stat.s, i);\ + }\ + } while (0); + + p(ip6s_sources_none, + "\t%llu failure%s of source address selection\n"); + for (first = 1, i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_sameif[i]) { + if (first) { + printf("\tsource addresses on an outgoing I/F\n"); + first = 0; + } + PRINT_SCOPESTAT(ip6s_sources_sameif[i], i); + } + } + for (first = 1, i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_otherif[i]) { + if (first) { + printf("\tsource addresses on a non-outgoing I/F\n"); + first = 0; + } + PRINT_SCOPESTAT(ip6s_sources_otherif[i], i); + } + } + for (first = 1, i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_samescope[i]) { + if (first) { + printf("\tsource addresses of same scope\n"); + first = 0; + } + PRINT_SCOPESTAT(ip6s_sources_samescope[i], i); + } + } + for (first = 1, i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_otherscope[i]) { + if (first) { + printf("\tsource addresses of a different scope\n"); + first = 0; + } + PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i); } } - printf("\t\t%lu one ext mbuf\n", ip6stat.ip6s_mext1); - printf("\t\t%lu two or more ext mbuf\n", ip6stat.ip6s_mext2m); - p(ip6s_exthdrtoolong, "\t%lu packet%s whose headers are not continuous\n"); - p(ip6s_nogif, "\t%lu tunneling packet%s that can't find gif\n"); - p(ip6s_toomanyhdr, "\t%lu packet%s discarded due to too may headers\n"); + for (first = 1, i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_deprecated[i]) { + if (first) { + printf("\tdeprecated source addresses\n"); + first = 0; + } + PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i); + } + } + + p1a(ip6s_forward_cachehit, "\t%llu forward cache hit\n"); + p1a(ip6s_forward_cachemiss, "\t%llu forward cache miss\n"); #undef p +#undef p1a } /* @@ -419,9 +496,9 @@ ip6_ifstats(ifname) struct in6_ifreq ifr; int s; #define p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \ - printf(m, ifr.ifr_ifru.ifru_stat.f, plural(ifr.ifr_ifru.ifru_stat.f)) + printf(m, (unsigned long long)ifr.ifr_ifru.ifru_stat.f, plural(ifr.ifr_ifru.ifru_stat.f)) #define p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \ - printf(m, ip6stat.f) + printf(m, (unsigned long long)ip6stat.f) if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { perror("Warning: socket(AF_INET6)"); @@ -436,28 +513,28 @@ ip6_ifstats(ifname) goto end; } - p(ifs6_in_receive, "\t%qu total input datagram%s\n"); - p(ifs6_in_hdrerr, "\t%qu datagram%s with invalid header received\n"); - p(ifs6_in_toobig, "\t%qu datagram%s exceeded MTU received\n"); - p(ifs6_in_noroute, "\t%qu datagram%s with no route received\n"); - p(ifs6_in_addrerr, "\t%qu datagram%s with invalid dst received\n"); - p(ifs6_in_protounknown, "\t%qu datagram%s with unknown proto received\n"); - p(ifs6_in_truncated, "\t%qu truncated datagram%s received\n"); - p(ifs6_in_discard, "\t%qu input datagram%s discarded\n"); + p(ifs6_in_receive, "\t%llu total input datagram%s\n"); + p(ifs6_in_hdrerr, "\t%llu datagram%s with invalid header received\n"); + p(ifs6_in_toobig, "\t%llu datagram%s exceeded MTU received\n"); + p(ifs6_in_noroute, "\t%llu datagram%s with no route received\n"); + p(ifs6_in_addrerr, "\t%llu datagram%s with invalid dst received\n"); + p(ifs6_in_protounknown, "\t%llu datagram%s with unknown proto received\n"); + p(ifs6_in_truncated, "\t%llu truncated datagram%s received\n"); + p(ifs6_in_discard, "\t%llu input datagram%s discarded\n"); p(ifs6_in_deliver, - "\t%qu datagram%s delivered to an upper layer protocol\n"); - p(ifs6_out_forward, "\t%qu datagram%s forwarded to this interface\n"); + "\t%llu datagram%s delivered to an upper layer protocol\n"); + p(ifs6_out_forward, "\t%llu datagram%s forwarded to this interface\n"); p(ifs6_out_request, - "\t%qu datagram%s sent from an upper layer protocol\n"); - p(ifs6_out_discard, "\t%qu total discarded output datagram%s\n"); - p(ifs6_out_fragok, "\t%qu output datagram%s fragmented\n"); - p(ifs6_out_fragfail, "\t%qu output datagram%s failed on fragment\n"); - p(ifs6_out_fragcreat, "\t%qu output datagram%s succeeded on fragment\n"); - p(ifs6_reass_reqd, "\t%qu incoming datagram%s fragmented\n"); - p(ifs6_reass_ok, "\t%qu datagram%s reassembled\n"); - p(ifs6_reass_fail, "\t%qu datagram%s failed on reassembling\n"); - p(ifs6_in_mcast, "\t%qu multicast datagram%s received\n"); - p(ifs6_out_mcast, "\t%qu multicast datagram%s sent\n"); + "\t%llu datagram%s sent from an upper layer protocol\n"); + p(ifs6_out_discard, "\t%llu total discarded output datagram%s\n"); + p(ifs6_out_fragok, "\t%llu output datagram%s fragmented\n"); + p(ifs6_out_fragfail, "\t%llu output datagram%s failed on fragment\n"); + p(ifs6_out_fragcreat, "\t%llu output datagram%s succeeded on fragment\n"); + p(ifs6_reass_reqd, "\t%llu incoming datagram%s fragmented\n"); + p(ifs6_reass_ok, "\t%llu datagram%s reassembled\n"); + p(ifs6_reass_fail, "\t%llu datagram%s failed on reassembling\n"); + p(ifs6_in_mcast, "\t%llu multicast datagram%s received\n"); + p(ifs6_out_mcast, "\t%llu multicast datagram%s sent\n"); end: close(s); @@ -742,36 +819,53 @@ icmp6_stats(off, name) printf("%s:\n", name); #define p(f, m) if (icmp6stat.f || sflag <= 1) \ - printf(m, icmp6stat.f, plural(icmp6stat.f)) + printf(m, (unsigned long long)icmp6stat.f, plural(icmp6stat.f)) +#define p_5(f, m) printf(m, (unsigned long long)icmp6stat.f) - p(icp6s_error, "\t%lu call%s to icmp_error\n"); + p(icp6s_error, "\t%llu call%s to icmp_error\n"); p(icp6s_canterror, - "\t%lu error%s not generated because old message was icmp error or so\n"); + "\t%llu error%s not generated because old message was icmp error or so\n"); p(icp6s_toofreq, - "\t%lu error%s not generated because rate limitation\n"); + "\t%llu error%s not generated because rate limitation\n"); for (first = 1, i = 0; i < 256; i++) if (icmp6stat.icp6s_outhist[i] != 0) { if (first) { printf("\tOutput histogram:\n"); first = 0; } - printf("\t\t%s: %lu\n", icmp6names[i], - icmp6stat.icp6s_outhist[i]); + printf("\t\t%s: %llu\n", icmp6names[i], + (unsigned long long)icmp6stat.icp6s_outhist[i]); } - p(icp6s_badcode, "\t%lu message%s with bad code fields\n"); - p(icp6s_tooshort, "\t%lu message%s < minimum length\n"); - p(icp6s_checksum, "\t%lu bad checksum%s\n"); - p(icp6s_badlen, "\t%lu message%s with bad length\n"); + p(icp6s_badcode, "\t%llu message%s with bad code fields\n"); + p(icp6s_tooshort, "\t%llu message%s < minimum length\n"); + p(icp6s_checksum, "\t%llu bad checksum%s\n"); + p(icp6s_badlen, "\t%llu message%s with bad length\n"); for (first = 1, i = 0; i < ICMP6_MAXTYPE; i++) if (icmp6stat.icp6s_inhist[i] != 0) { if (first) { printf("\tInput histogram:\n"); first = 0; } - printf("\t\t%s: %lu\n", icmp6names[i], - icmp6stat.icp6s_inhist[i]); + printf("\t\t%s: %llu\n", icmp6names[i], + (unsigned long long)icmp6stat.icp6s_inhist[i]); } - p(icp6s_reflect, "\t%lu message response%s generated\n"); + printf("\tHistgram of error messages to be generated:\n"); + p_5(icp6s_odst_unreach_noroute, "\t\t%llu no route\n"); + p_5(icp6s_odst_unreach_admin, "\t\t%llu administratively prohibited\n"); + p_5(icp6s_odst_unreach_beyondscope, "\t\t%llu beyond scope\n"); + p_5(icp6s_odst_unreach_addr, "\t\t%llu address unreachable\n"); + p_5(icp6s_odst_unreach_noport, "\t\t%llu port unreachable\n"); + p_5(icp6s_opacket_too_big, "\t\t%llu packet too big\n"); + p_5(icp6s_otime_exceed_transit, "\t\t%llu time exceed transit\n"); + p_5(icp6s_otime_exceed_reassembly, "\t\t%llu time exceed reassembly\n"); + p_5(icp6s_oparamprob_header, "\t\t%llu erroneous header field\n"); + p_5(icp6s_oparamprob_nextheader, "\t\t%llu unrecognized next header\n"); + p_5(icp6s_oparamprob_option, "\t\t%llu unrecognized option\n"); + p_5(icp6s_oredirect, "\t\t%llu redirect\n"); + p_5(icp6s_ounknown, "\t\t%llu unknown\n"); + + p(icp6s_reflect, "\t%llu message response%s generated\n"); + p(icp6s_nd_toomanyopt, "\t%llu message%s with too many ND options\n"); #undef p #undef p_5 } @@ -786,7 +880,7 @@ icmp6_ifstats(ifname) struct in6_ifreq ifr; int s; #define p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \ - printf(m, (u_quad_t)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f)) + printf(m, (unsigned long long)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f)) if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { perror("Warning: socket(AF_INET6)"); @@ -801,41 +895,41 @@ icmp6_ifstats(ifname) goto end; } - p(ifs6_in_msg, "\t%qu total input message%s\n"); - p(ifs6_in_error, "\t%qu total input error message%s\n"); - p(ifs6_in_dstunreach, "\t%qu input destination unreachable error%s\n"); - p(ifs6_in_adminprohib, "\t%qu input administratively prohibited error%s\n"); - p(ifs6_in_timeexceed, "\t%qu input time exceeded error%s\n"); - p(ifs6_in_paramprob, "\t%qu input parameter problem error%s\n"); - p(ifs6_in_pkttoobig, "\t%qu input packet too big error%s\n"); - p(ifs6_in_echo, "\t%qu input echo request%s\n"); - p(ifs6_in_echoreply, "\t%qu input echo reply%s\n"); - p(ifs6_in_routersolicit, "\t%qu input router solicitation%s\n"); - p(ifs6_in_routeradvert, "\t%qu input router advertisement%s\n"); - p(ifs6_in_neighborsolicit, "\t%qu input neighbor solicitation%s\n"); - p(ifs6_in_neighboradvert, "\t%qu input neighbor advertisement%s\n"); - p(ifs6_in_redirect, "\t%qu input redirect%s\n"); - p(ifs6_in_mldquery, "\t%qu input MLD query%s\n"); - p(ifs6_in_mldreport, "\t%qu input MLD report%s\n"); - p(ifs6_in_mlddone, "\t%qu input MLD done%s\n"); - - p(ifs6_out_msg, "\t%qu total output message%s\n"); - p(ifs6_out_error, "\t%qu total output error message%s\n"); - p(ifs6_out_dstunreach, "\t%qu output destination unreachable error%s\n"); - p(ifs6_out_adminprohib, "\t%qu output administratively prohibited error%s\n"); - p(ifs6_out_timeexceed, "\t%qu output time exceeded error%s\n"); - p(ifs6_out_paramprob, "\t%qu output parameter problem error%s\n"); - p(ifs6_out_pkttoobig, "\t%qu output packet too big error%s\n"); - p(ifs6_out_echo, "\t%qu output echo request%s\n"); - p(ifs6_out_echoreply, "\t%qu output echo reply%s\n"); - p(ifs6_out_routersolicit, "\t%qu output router solicitation%s\n"); - p(ifs6_out_routeradvert, "\t%qu output router advertisement%s\n"); - p(ifs6_out_neighborsolicit, "\t%qu output neighbor solicitation%s\n"); - p(ifs6_out_neighboradvert, "\t%qu output neighbor advertisement%s\n"); - p(ifs6_out_redirect, "\t%qu output redirect%s\n"); - p(ifs6_out_mldquery, "\t%qu output MLD query%s\n"); - p(ifs6_out_mldreport, "\t%qu output MLD report%s\n"); - p(ifs6_out_mlddone, "\t%qu output MLD done%s\n"); + p(ifs6_in_msg, "\t%llu total input message%s\n"); + p(ifs6_in_error, "\t%llu total input error message%s\n"); + p(ifs6_in_dstunreach, "\t%llu input destination unreachable error%s\n"); + p(ifs6_in_adminprohib, "\t%llu input administratively prohibited error%s\n"); + p(ifs6_in_timeexceed, "\t%llu input time exceeded error%s\n"); + p(ifs6_in_paramprob, "\t%llu input parameter problem error%s\n"); + p(ifs6_in_pkttoobig, "\t%llu input packet too big error%s\n"); + p(ifs6_in_echo, "\t%llu input echo request%s\n"); + p(ifs6_in_echoreply, "\t%llu input echo reply%s\n"); + p(ifs6_in_routersolicit, "\t%llu input router solicitation%s\n"); + p(ifs6_in_routeradvert, "\t%llu input router advertisement%s\n"); + p(ifs6_in_neighborsolicit, "\t%llu input neighbor solicitation%s\n"); + p(ifs6_in_neighboradvert, "\t%llu input neighbor advertisement%s\n"); + p(ifs6_in_redirect, "\t%llu input redirect%s\n"); + p(ifs6_in_mldquery, "\t%llu input MLD query%s\n"); + p(ifs6_in_mldreport, "\t%llu input MLD report%s\n"); + p(ifs6_in_mlddone, "\t%llu input MLD done%s\n"); + + p(ifs6_out_msg, "\t%llu total output message%s\n"); + p(ifs6_out_error, "\t%llu total output error message%s\n"); + p(ifs6_out_dstunreach, "\t%llu output destination unreachable error%s\n"); + p(ifs6_out_adminprohib, "\t%llu output administratively prohibited error%s\n"); + p(ifs6_out_timeexceed, "\t%llu output time exceeded error%s\n"); + p(ifs6_out_paramprob, "\t%llu output parameter problem error%s\n"); + p(ifs6_out_pkttoobig, "\t%llu output packet too big error%s\n"); + p(ifs6_out_echo, "\t%llu output echo request%s\n"); + p(ifs6_out_echoreply, "\t%llu output echo reply%s\n"); + p(ifs6_out_routersolicit, "\t%llu output router solicitation%s\n"); + p(ifs6_out_routeradvert, "\t%llu output router advertisement%s\n"); + p(ifs6_out_neighborsolicit, "\t%llu output neighbor solicitation%s\n"); + p(ifs6_out_neighboradvert, "\t%llu output neighbor advertisement%s\n"); + p(ifs6_out_redirect, "\t%llu output redirect%s\n"); + p(ifs6_out_mldquery, "\t%llu output MLD query%s\n"); + p(ifs6_out_mldreport, "\t%llu output MLD report%s\n"); + p(ifs6_out_mlddone, "\t%llu output MLD done%s\n"); end: close(s); @@ -858,14 +952,14 @@ pim6_stats(off, name) printf("%s:\n", name); #define p(f, m) if (pim6stat.f || sflag <= 1) \ - printf(m, pim6stat.f, plural(pim6stat.f)) - p(pim6s_rcv_total, "\t%u message%s received\n"); - p(pim6s_rcv_tooshort, "\t%u message%s received with too few bytes\n"); - p(pim6s_rcv_badsum, "\t%u message%s received with bad checksum\n"); - p(pim6s_rcv_badversion, "\t%u message%s received with bad version\n"); - p(pim6s_rcv_registers, "\t%u register%s received\n"); - p(pim6s_rcv_badregisters, "\t%u bad register%s received\n"); - p(pim6s_snd_registers, "\t%u register%s sent\n"); + printf(m, (unsigned long long)pim6stat.f, plural(pim6stat.f)) + p(pim6s_rcv_total, "\t%llu message%s received\n"); + p(pim6s_rcv_tooshort, "\t%llu message%s received with too few bytes\n"); + p(pim6s_rcv_badsum, "\t%llu message%s received with bad checksum\n"); + p(pim6s_rcv_badversion, "\t%llu message%s received with bad version\n"); + p(pim6s_rcv_registers, "\t%llu register%s received\n"); + p(pim6s_rcv_badregisters, "\t%llu bad register%s received\n"); + p(pim6s_snd_registers, "\t%llu register%s sent\n"); #undef p } diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c index 87c3a73f930d..453eb791c905 100644 --- a/usr.bin/netstat/main.c +++ b/usr.bin/netstat/main.c @@ -143,6 +143,8 @@ static struct nlist nl[] = { { "_mf6ctable" }, #define N_MIF6TABLE 36 { "_mif6table" }, +#define N_PFKEYSTAT 37 + { "_pfkeystat" }, { "" }, }; @@ -203,6 +205,15 @@ struct protox ip6protox[] = { }; #endif /*INET6*/ +#ifdef IPSEC +struct protox pfkeyprotox[] = { + { -1, N_PFKEYSTAT, 1, 0, + pfkey_stats, NULL, "pfkey", 0 }, + { -1, -1, 0, 0, + 0, NULL, 0, 0 } +}; +#endif + struct protox atalkprotox[] = { { N_DDPCB, N_DDPSTAT, 1, atalkprotopr, ddp_stats, NULL, "ddp" }, @@ -261,6 +272,9 @@ struct protox *protoprotox[] = { #ifdef INET6 ip6protox, #endif +#ifdef IPSEC + pfkeyprotox, +#endif ipxprotox, atalkprotox, #ifdef NS nsprotox, @@ -316,6 +330,10 @@ main(argc, argv) else if (strcmp(optarg, "inet6") == 0) af = AF_INET6; #endif /*INET6*/ +#ifdef INET6 + else if (strcmp(optarg, "pfkey") == 0) + af = PF_KEY; +#endif /*INET6*/ else if (strcmp(optarg, "unix") == 0) af = AF_UNIX; else if (strcmp(optarg, "atalk") == 0) @@ -505,6 +523,11 @@ main(argc, argv) for (tp = ip6protox; tp->pr_name; tp++) printproto(tp, tp->pr_name); #endif /*INET6*/ +#ifdef IPSEC + if (af == PF_KEY || af == AF_UNSPEC) + for (tp = pfkeyprotox; tp->pr_name; tp++) + printproto(tp, tp->pr_name); +#endif /*IPSEC*/ if (af == AF_IPX || af == AF_UNSPEC) { kread(0, 0, 0); for (tp = ipxprotox; tp->pr_name; tp++) diff --git a/usr.bin/netstat/mroute.c b/usr.bin/netstat/mroute.c index 74706c7eb0fe..46e0dfe68be6 100644 --- a/usr.bin/netstat/mroute.c +++ b/usr.bin/netstat/mroute.c @@ -48,7 +48,6 @@ static const char rcsid[] = * MROUTING 1.0 */ - #include <sys/param.h> #include <sys/queue.h> #include <sys/socket.h> @@ -123,7 +122,7 @@ mroutepr(mfcaddr, vifaddr) kread((u_long)m, (char *)&mfc, sizeof mfc); if (!banner_printed) { - printf("\nMulticast Forwarding Cache\n" + printf("\nIPv4 Multicast Forwarding Cache\n" " Origin Group " " Packets In-Vif Out-Vifs:Ttls\n"); banner_printed = 1; @@ -157,12 +156,12 @@ mrt_stats(mstaddr) struct mrtstat mrtstat; if (mstaddr == 0) { - printf("No multicast routing compiled into this system.\n"); + printf("No IPv4 multicast routing compiled into this system.\n"); return; } kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat)); - printf("multicast forwarding:\n"); + printf("IPv4 multicast forwarding:\n"); printf(" %10lu multicast forwarding cache lookup%s\n", mrtstat.mrts_mfc_lookups, plural(mrtstat.mrts_mfc_lookups)); printf(" %10lu multicast forwarding cache miss%s\n", diff --git a/usr.bin/netstat/mroute6.c b/usr.bin/netstat/mroute6.c index 3730a9e49ee9..f605a039ac40 100644 --- a/usr.bin/netstat/mroute6.c +++ b/usr.bin/netstat/mroute6.c @@ -139,7 +139,8 @@ mroute6pr(mfcaddr, mifaddr) printf(" %5s", (mifp->m6_flags & MIFF_REGISTER) ? "reg0" : if_indextoname(ifnet.if_index, ifname)); - printf(" %9qu %9qu\n", mifp->m6_pkt_in, mifp->m6_pkt_out); + printf(" %9llu %9llu\n", (unsigned long long)mifp->m6_pkt_in, + (unsigned long long)mifp->m6_pkt_out); } if (!banner_printed) printf("\nIPv6 Multicast Interface Table is empty\n"); @@ -163,7 +164,7 @@ mroute6pr(mfcaddr, mifaddr) routename6(&mfc.mf6c_origin)); printf(" %-*.*s", WID_GRP, WID_GRP, routename6(&mfc.mf6c_mcastgrp)); - printf(" %9qu", mfc.mf6c_pkt_cnt); + printf(" %9llu", (unsigned long long)mfc.mf6c_pkt_cnt); for (waitings = 0, rtep = mfc.mf6c_stall; rtep; ) { waitings++; @@ -206,30 +207,43 @@ mrt6_stats(mstaddr) kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat)); printf("IPv6 multicast forwarding:\n"); - printf(" %10qu multicast forwarding cache lookup%s\n", - mrtstat.mrt6s_mfc_lookups, plural(mrtstat.mrt6s_mfc_lookups)); - printf(" %10qu multicast forwarding cache miss%s\n", - mrtstat.mrt6s_mfc_misses, plurales(mrtstat.mrt6s_mfc_misses)); - printf(" %10qu upcall%s to mrouted\n", - mrtstat.mrt6s_upcalls, plural(mrtstat.mrt6s_upcalls)); - printf(" %10qu upcall queue overflow%s\n", - mrtstat.mrt6s_upq_ovflw, plural(mrtstat.mrt6s_upq_ovflw)); - printf(" %10qu upcall%s dropped due to full socket buffer\n", - mrtstat.mrt6s_upq_sockfull, plural(mrtstat.mrt6s_upq_sockfull)); - printf(" %10qu cache cleanup%s\n", - mrtstat.mrt6s_cache_cleanups, plural(mrtstat.mrt6s_cache_cleanups)); - printf(" %10qu datagram%s with no route for origin\n", - mrtstat.mrt6s_no_route, plural(mrtstat.mrt6s_no_route)); - printf(" %10qu datagram%s arrived with bad tunneling\n", - mrtstat.mrt6s_bad_tunnel, plural(mrtstat.mrt6s_bad_tunnel)); - printf(" %10qu datagram%s could not be tunneled\n", - mrtstat.mrt6s_cant_tunnel, plural(mrtstat.mrt6s_cant_tunnel)); - printf(" %10qu datagram%s arrived on wrong interface\n", - mrtstat.mrt6s_wrong_if, plural(mrtstat.mrt6s_wrong_if)); - printf(" %10qu datagram%s selectively dropped\n", - mrtstat.mrt6s_drop_sel, plural(mrtstat.mrt6s_drop_sel)); - printf(" %10qu datagram%s dropped due to queue overflow\n", - mrtstat.mrt6s_q_overflow, plural(mrtstat.mrt6s_q_overflow)); - printf(" %10qu datagram%s dropped for being too large\n", - mrtstat.mrt6s_pkt2large, plural(mrtstat.mrt6s_pkt2large)); + printf(" %10llu multicast forwarding cache lookup%s\n", + (unsigned long long)mrtstat.mrt6s_mfc_lookups, + plural(mrtstat.mrt6s_mfc_lookups)); + printf(" %10llu multicast forwarding cache miss%s\n", + (unsigned long long)mrtstat.mrt6s_mfc_misses, + plurales(mrtstat.mrt6s_mfc_misses)); + printf(" %10llu upcall%s to mrouted\n", + (unsigned long long)mrtstat.mrt6s_upcalls, + plural(mrtstat.mrt6s_upcalls)); + printf(" %10llu upcall llueue overflow%s\n", + (unsigned long long)mrtstat.mrt6s_upq_ovflw, + plural(mrtstat.mrt6s_upq_ovflw)); + printf(" %10llu upcall%s dropped due to full socket buffer\n", + (unsigned long long)mrtstat.mrt6s_upq_sockfull, + plural(mrtstat.mrt6s_upq_sockfull)); + printf(" %10llu cache cleanup%s\n", + (unsigned long long)mrtstat.mrt6s_cache_cleanups, + plural(mrtstat.mrt6s_cache_cleanups)); + printf(" %10llu datagram%s with no route for origin\n", + (unsigned long long)mrtstat.mrt6s_no_route, + plural(mrtstat.mrt6s_no_route)); + printf(" %10llu datagram%s arrived with bad tunneling\n", + (unsigned long long)mrtstat.mrt6s_bad_tunnel, + plural(mrtstat.mrt6s_bad_tunnel)); + printf(" %10llu datagram%s could not be tunneled\n", + (unsigned long long)mrtstat.mrt6s_cant_tunnel, + plural(mrtstat.mrt6s_cant_tunnel)); + printf(" %10llu datagram%s arrived on wrong interface\n", + (unsigned long long)mrtstat.mrt6s_wrong_if, + plural(mrtstat.mrt6s_wrong_if)); + printf(" %10llu datagram%s selectively dropped\n", + (unsigned long long)mrtstat.mrt6s_drop_sel, + plural(mrtstat.mrt6s_drop_sel)); + printf(" %10llu datagram%s dropped due to llueue overflow\n", + (unsigned long long)mrtstat.mrt6s_q_overflow, + plural(mrtstat.mrt6s_q_overflow)); + printf(" %10llu datagram%s dropped for being too large\n", + (unsigned long long)mrtstat.mrt6s_pkt2large, + plural(mrtstat.mrt6s_pkt2large)); } diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h index 3b435c2f6ae6..70bfbf0c6471 100644 --- a/usr.bin/netstat/netstat.h +++ b/usr.bin/netstat/netstat.h @@ -81,8 +81,17 @@ void icmp6_ifstats __P((char *)); void pim6_stats __P((u_long, char *)); void mroute6pr __P((u_long, u_long)); void mrt6_stats __P((u_long)); + +struct sockaddr_in6; +struct in6_addr; +char *routename6 __P((struct sockaddr_in6 *)); +char *netname6 __P((struct sockaddr_in6 *, struct in6_addr *)); #endif /*INET6*/ +#ifdef IPSEC +void pfkey_stats __P((u_long, char *)); +#endif + void bdg_stats __P((u_long, char *)); void mbpr __P((void)); diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c index 9d43a8188ed5..b6b638215a7d 100644 --- a/usr.bin/netstat/route.c +++ b/usr.bin/netstat/route.c @@ -73,6 +73,12 @@ static const char rcsid[] = #define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d))) + +/* alignment constraint for routing socket */ +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) +#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) + /* * Definitions for showing gateway flags. */ @@ -222,44 +228,35 @@ pr_family(af) } /* column widths; each followed by one space */ -#define WID_DST 18 /* width of destination column */ -#define WID_GW 18 /* width of gateway column */ -#ifdef INET6 -#define WID_DST6 (lflag ? 39 : (nflag ? 33: 18)) /* width of dest column */ -#define WID_GW6 (lflag ? 31 : (nflag ? 29 : 18)) /* width of gateway column */ +#ifndef INET6 +#define WID_DST(af) 18 /* width of destination column */ +#define WID_GW(af) 18 /* width of gateway column */ +#else +#define WID_DST(af) \ + ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 33: 18)) : 18) +#define WID_GW(af) \ + ((af) == AF_INET6 ? (lflag ? 31 : (nflag ? 29 : 18)) : 18) #endif /*INET6*/ /* * Print header for routing table columns. */ void -pr_rthdr(wid_af) - int wid_af; +pr_rthdr(af) + int af; { - int wid_dst, wid_gw; - - wid_dst = -#ifdef INET6 - wid_af == AF_INET6 ? WID_DST6 : -#endif - WID_DST; - wid_gw = -#ifdef INET6 - wid_af == AF_INET6 ? WID_GW6 : -#endif - WID_GW; if (Aflag) printf("%-8.8s ","Address"); - if (wid_af == AF_INET || lflag) + if (lflag) printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %8.8s %6s\n", - wid_dst, wid_dst, "Destination", - wid_gw, wid_gw, "Gateway", + WID_DST(af), WID_DST(af), "Destination", + WID_GW(af), WID_GW(af), "Gateway", "Flags", "Refs", "Use", "Netif", "Expire"); else printf("%-*.*s %-*.*s %-6.6s %8.8s %6s\n", - wid_dst, wid_dst, "Destination", - wid_gw, wid_gw, "Gateway", + WID_DST(af), WID_DST(af), "Destination", + WID_GW(af), WID_GW(af), "Gateway", "Flags", "Netif", "Expire"); } @@ -414,7 +411,7 @@ np_rtentry(rtm) p_sockaddr(sa, NULL, 0, 36); else { p_sockaddr(sa, NULL, rtm->rtm_flags, 16); - sa = (struct sockaddr *)(sa->sa_len + (char *)sa); + sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa); p_sockaddr(sa, NULL, 0, 18); } p_flags(rtm->rtm_flags & interesting, "%-6.6s "); @@ -602,15 +599,9 @@ p_rtentry(rt) if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt)))) bcopy(sa, &mask, sa->sa_len); p_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags, -#ifdef INET6 - addr.u_sa.sa_family == AF_INET6 ? WID_DST6 : -#endif - WID_DST); + WID_DST(addr.u_sa.sa_family)); p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, -#ifdef INET6 - addr.u_sa.sa_family == AF_INET6 ? WID_GW6 : -#endif - WID_GW); + WID_GW(addr.u_sa.sa_family)); p_flags(rt->rt_flags, "%-6.6s "); if (addr.u_sa.sa_family == AF_INET || lflag) printf("%6ld %8ld ", rt->rt_refcnt, rt->rt_use); @@ -765,18 +756,14 @@ netname6(sa6, mask) static char line[MAXHOSTNAMELEN + 1]; u_char *p = (u_char *)mask; u_char *lim; - int masklen, illegal = 0; - int flag = NI_WITHSCOPEID; + int masklen, illegal = 0, flag = NI_WITHSCOPEID; if (mask) { for (masklen = 0, lim = p + 16; p < lim; p++) { - if (*p == 0xff) - masklen += 8; - else - break; - } - if (p < lim) { switch (*p) { + case 0xff: + masklen += 8; + break; case 0xfe: masklen += 7; break; @@ -831,12 +818,17 @@ routename6(sa6) { static char line[MAXHOSTNAMELEN + 1]; int flag = NI_WITHSCOPEID; + /* use local variable for safety */ + struct sockaddr_in6 sa6_local = {AF_INET6, sizeof(sa6_local),}; + + sa6_local.sin6_addr = sa6->sin6_addr; + sa6_local.sin6_scope_id = sa6->sin6_scope_id; if (nflag) flag |= NI_NUMERICHOST; - getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line), - NULL, 0, flag); + getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len, + line, sizeof(line), NULL, 0, flag); return line; } diff --git a/usr.bin/telnet/commands.c b/usr.bin/telnet/commands.c index c0c6b2cb4a53..12904b833c8e 100644 --- a/usr.bin/telnet/commands.c +++ b/usr.bin/telnet/commands.c @@ -2254,7 +2254,7 @@ tn(argc, argv) hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(src_addr, 0, &hints, &src_res); - if (error == EAI_NONAME) { + if (error == EAI_NODATA) { hints.ai_flags = 0; error = getaddrinfo(src_addr, 0, &hints, &src_res); } @@ -2292,7 +2292,19 @@ tn(argc, argv) hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(hostname, portp, &hints, &res); - if (error == 0) { + if (error) { + hints.ai_flags = AI_CANONNAME; + error = getaddrinfo(hostname, portp, &hints, &res); + } + if (error != 0) { + fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error)); + if (error == EAI_SYSTEM) + fprintf(stderr, "%s: %s\n", hostname, strerror(errno)); + setuid(getuid()); + goto fail; + } + if (hints.ai_flags == AI_NUMERICHOST) { + /* hostname has numeric */ int gni_err = 1; if (doaddrlookup) @@ -2300,19 +2312,11 @@ tn(argc, argv) _hostname, sizeof(_hostname) - 1, NULL, 0, NI_NAMEREQD); if (gni_err != 0) - (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1); + (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1); _hostname[sizeof(_hostname)-1] = '\0'; hostname = _hostname; - } else if (error == EAI_NONAME) { - hints.ai_flags = AI_CANONNAME; - error = getaddrinfo(hostname, portp, &hints, &res); - if (error != 0) { - fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error)); - if (error == EAI_SYSTEM) - fprintf(stderr, "%s: %s\n", hostname, strerror(errno)); - setuid(getuid()); - goto fail; - } + } else { + /* hostname has FQDN */ if (srcroute != 0) (void) strncpy(_hostname, hostname, sizeof(_hostname) - 1); else if (res->ai_canonname != NULL) @@ -2321,12 +2325,6 @@ tn(argc, argv) (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1); _hostname[sizeof(_hostname)-1] = '\0'; hostname = _hostname; - } else if (error != 0) { - fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error)); - if (error == EAI_SYSTEM) - fprintf(stderr, "%s: %s\n", hostname, strerror(errno)); - setuid(getuid()); - goto fail; } res0 = res; af_again: @@ -2982,7 +2980,7 @@ sourceroute(ai, arg, cpp, lenp, protop, optp) hints.ai_flags = AI_NUMERICHOST; error = getaddrinfo(cp, NULL, &hints, &res); - if (error == EAI_NONAME) { + if (error == EAI_NODATA) { hints.ai_flags = 0; error = getaddrinfo(cp, NULL, &hints, &res); } diff --git a/usr.bin/whois/whois.c b/usr.bin/whois/whois.c index 0ef3d4b5c30f..af03a1235b27 100644 --- a/usr.bin/whois/whois.c +++ b/usr.bin/whois/whois.c @@ -75,20 +75,18 @@ static const char rcsid[] = #define WHOIS_QUICK 0x04 static void usage __P((void)); -static void whois __P((char *, struct sockaddr_in *, int)); +static void whois __P((char *, struct addrinfo *, int)); int main(argc, argv) int argc; char **argv; { - int ch, i, j; + int ch, i, j, error; int use_qnichost, flags; char *host; char *qnichost; - struct servent *sp; - struct hostent *hp; - struct sockaddr_in sin; + struct addrinfo hints, *res; #ifdef SOCKS SOCKSinit(argv[0]); @@ -145,16 +143,6 @@ main(argc, argv) usage(); } - memset(&sin, 0, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - sp = getservbyname("whois", "tcp"); - if (sp == NULL) { - sin.sin_port = htons(WHOIS_PORT); - } else { - sin.sin_port = sp->s_port; - } - /* * If no nic host is specified, use whois-servers.net * if there is a '.' in the name, else fall back to NICHOST. @@ -186,36 +174,38 @@ main(argc, argv) strcpy(qnichost, *argv + j + 1); strcat(qnichost, QNICHOST_TAIL); - if (inet_aton(qnichost, &sin.sin_addr) == 0) { - hp = gethostbyname2(qnichost, AF_INET); - if (hp == NULL) { - free(qnichost); - qnichost = NULL; - } else { - sin.sin_addr = *(struct in_addr *)hp->h_addr_list[0]; - } - } + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = 0; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(qnichost, "whois", + &hints, &res); + if (error != 0) + errx(EX_NOHOST, "%s: %s", qnichost, + gai_strerror(error)); } } - if (!qnichost && inet_aton(host, &sin.sin_addr) == 0) { - hp = gethostbyname2(host, AF_INET); - if (hp == NULL) { + if (!qnichost) { + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = 0; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(host, "whois", &hints, &res); + if (error != 0) errx(EX_NOHOST, "%s: %s", host, - hstrerror(h_errno)); - } - host = hp->h_name; - sin.sin_addr = *(struct in_addr *)hp->h_addr_list[0]; + gai_strerror(error)); } - whois(*argv++, &sin, flags); + whois(*argv++, res, flags); + freeaddrinfo(res); } exit(0); } static void -whois(name, sinp, flags) +whois(name, res, flags) char *name; - struct sockaddr_in *sinp; + struct addrinfo *res; int flags; { FILE *sfi, *sfo; @@ -223,12 +213,12 @@ whois(name, sinp, flags) size_t len; int s, nomatch; - s = socket(PF_INET, SOCK_STREAM, 0); + s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) { err(EX_OSERR, "socket"); } - if (connect(s, (struct sockaddr *)sinp, sizeof(*sinp)) < 0) { + if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { err(EX_OSERR, "connect"); } @@ -278,17 +268,23 @@ whois(name, sinp, flags) nhost = INICHOST; } if (nhost) { - if (inet_aton(nhost, &sinp->sin_addr) == 0) { - struct hostent *hp = gethostbyname2(nhost, AF_INET); - if (hp == NULL) { - return; - } - sinp->sin_addr = *(struct in_addr *)hp->h_addr_list[0]; + struct addrinfo hints, *res2; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = 0; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(nhost, "whois", &hints, &res2); + if (error != 0) { + warnx("%s: %s", nhost, gai_strerror(error)); + return; } if (!nomatch) { free(nhost); } - whois(name, sinp, 0); + whois(name, res2, 0); + freeaddrinfo(res2); } } |
