diff options
| author | Kris Kennaway <kris@FreeBSD.org> | 2000-07-15 07:29:31 +0000 |
|---|---|---|
| committer | Kris Kennaway <kris@FreeBSD.org> | 2000-07-15 07:29:31 +0000 |
| commit | e6d0854e13b64e40140480e08569e93f3c6b93cb (patch) | |
| tree | 4ad1df1e542a1f3513ccb842e719aa03ea938119 /lib/libc | |
| parent | 8b0561f1900283a280aa406a12c2db7e4c7eaea0 (diff) | |
Notes
Diffstat (limited to 'lib/libc')
| -rw-r--r-- | lib/libc/net/Makefile.inc | 5 | ||||
| -rw-r--r-- | lib/libc/net/getaddrinfo.3 | 186 | ||||
| -rw-r--r-- | lib/libc/net/getaddrinfo.c | 100 | ||||
| -rw-r--r-- | lib/libc/net/getnameinfo.3 | 113 | ||||
| -rw-r--r-- | lib/libc/net/getnameinfo.c | 278 | ||||
| -rw-r--r-- | lib/libc/net/rcmd.c | 2 |
6 files changed, 530 insertions, 154 deletions
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); } |
