summaryrefslogtreecommitdiff
path: root/lib/libc
diff options
context:
space:
mode:
authorKris Kennaway <kris@FreeBSD.org>2000-07-15 07:29:31 +0000
committerKris Kennaway <kris@FreeBSD.org>2000-07-15 07:29:31 +0000
commite6d0854e13b64e40140480e08569e93f3c6b93cb (patch)
tree4ad1df1e542a1f3513ccb842e719aa03ea938119 /lib/libc
parent8b0561f1900283a280aa406a12c2db7e4c7eaea0 (diff)
Notes
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/net/Makefile.inc5
-rw-r--r--lib/libc/net/getaddrinfo.3186
-rw-r--r--lib/libc/net/getaddrinfo.c100
-rw-r--r--lib/libc/net/getnameinfo.3113
-rw-r--r--lib/libc/net/getnameinfo.c278
-rw-r--r--lib/libc/net/rcmd.c2
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);
}