From 1501f61891a7a207cce1aa417e23eb96889384b2 Mon Sep 17 00:00:00 2001 From: itojun Date: Mon, 13 Dec 1999 14:18:31 +0000 Subject: bring in latest KAME get{addr,name}info(3). getnameinfo(3) globs ai_socktype and ai_protocol correctly. KAME scopeid extension is implemented. (draft-ietf-ipngwg-scopedaddr-format-00.txt) bump up shlib minor (may not be necessary, but rather big difference in behavior - especially ai_flags) --- lib/libc/net/getaddrinfo.3 | 104 +++- lib/libc/net/getaddrinfo.c | 1135 ++++++++++++++++++++++++++++---------------- lib/libc/net/getnameinfo.3 | 61 ++- lib/libc/net/getnameinfo.c | 100 +++- lib/libc/shlib_version | 4 +- 5 files changed, 933 insertions(+), 471 deletions(-) (limited to 'lib') diff --git a/lib/libc/net/getaddrinfo.3 b/lib/libc/net/getaddrinfo.3 index a8aeb4a3878..fb975ec7a4f 100644 --- a/lib/libc/net/getaddrinfo.3 +++ b/lib/libc/net/getaddrinfo.3 @@ -30,18 +30,21 @@ .\" SUCH DAMAGE. .\" .\" From: @(#)gethostbyname.3 8.4 (Berkeley) 5/25/95 -.\" $Id: getaddrinfo.3,v 1.2 1999/07/03 13:58:31 kleink Exp $ +.\" KAME Id: getaddrinfo.3,v 1.5 1999/12/10 04:04:30 itojun Exp .\" .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 +.\" .Sh LIBRARY .Lb libc +.\" .Sh SYNOPSIS .Fd #include .Fd #include @@ -52,6 +55,7 @@ .Fn freeaddrinfo "struct addrinfo *ai" .Ft "char *" .Fn gai_strerror "int ecode" +.\" .Sh DESCRIPTION The .Fn getaddrinfo @@ -62,8 +66,10 @@ and .Xr getservbyname 3 , in more sophisticated manner. .Pp -The addrinfo structure is defined as a result of including the -.Li +The +.Li addrinfo +structure is defined as a result of including the +.Aq Pa netdb.h header: .Bd -literal -offset struct addrinfo { * @@ -157,7 +163,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 @@ -220,7 +227,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 @@ -265,7 +273,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 @@ -294,43 +302,87 @@ If the argument is not one of the .Dv EAI_xxx values, the function still returns a pointer to a string whose contents indicate an unknown error. +.\" +.Sh EXTENSION +The implementation allows experimental numeric IPv6 address notation with +scope identifier. +By appending atmark and scope identifier to addresses, you can fill +.Li sin6_scope_id +field for addresses. +This would make management of scoped address easier, +and allows cut-and-paste input of scoped address. +.Pp +At this moment the code supports only link-local addresses with the format. +Scope identifier is hardcoded to name of hardware interface associated +with the link. +.Po +such as +.Li ne0 +.Pc . +Example would be like +.Dq Li fe80::1@ne0 , +which means +.Do +.Li fe80::1 +on the link associated with +.Li ne0 +interface +.Dc . +.Pp +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 FILES .Bl -tag -width /etc/resolv.conf -compact .It Pa /etc/hosts .It Pa /etc/host.conf .It Pa /etc/resolv.conf .El +.\" .Sh DIAGNOSTICS Error return status from .Fn getaddrinfo is zero on success and non-zero on errors. Non-zero error codes are defined in -.Li , +.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 .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 .It Dv EAI_FAMILY -ai_family not supported +.Fa ai_family +not supported .It Dv EAI_MEMORY 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, @@ -340,6 +392,7 @@ If the argument is not one of the .Dv EAI_xxx values, the function still returns a pointer to a string whose contents indicate an unknown error. +.\" .Sh SEE ALSO .Xr getnameinfo 3 , .Xr gethostbyname 3 , @@ -347,17 +400,28 @@ indicate an unknown error. .Xr hosts 5 , .Xr services 5 , .Xr hostname 7 , -.Xr named 8 +.Xr named 8 . .Pp -R. Gilligan, S. Thomson, J. Bound, and W. Stevens, -``Basic Socket Interface Extensions for IPv6,'' RFC2553, March 1999. +.Rs +.%A R. Gilligan +.%A S. Thomson +.%A J. Bound +.%A W. Stevens +.%T Basic Socket Interface Extensions for IPv6 +.%R RFC2553 +.%D March 1999 +.Re +.\" .Sh HISTORY The implementation first appeared in WIDE Hydrangea IPv6 protocol stack kit. +.\" .Sh STANDARDS The .Fn getaddrinfo function is defined IEEE POSIX 1003.1g draft specification, -and documented in ``Basic Socket Interface Extensions for IPv6'' +and documented in +.Dq Basic Socket Interface Extensions for IPv6 .Pq RFC2533 . +.\" .Sh BUGS The text was shamelessly copied from RFC2553. diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c index a2aa728fb77..8c6f706daba 100644 --- a/lib/libc/net/getaddrinfo.c +++ b/lib/libc/net/getaddrinfo.c @@ -1,4 +1,4 @@ -/* $NetBSD: getaddrinfo.c,v 1.13 1999/09/20 04:39:11 lukem Exp $ */ +/* $NetBSD: getaddrinfo.c,v 1.14 1999/12/13 14:18:32 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -35,31 +35,61 @@ * Issues to be discussed: * - Thread safe-ness must be checked. * - Return values. There are nonstandard return values defined and used - * in the source code. This is because RFC2133 is silent about which error + * in the source code. This is because RFC2553 is silent about which error * code must be returned for which situation. - * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag. + * Note: + * - We use getipnodebyname() just for thread-safeness. There's no intent + * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to + * getipnodebyname(). + * - The code filters out AFs that are not supported by the kernel, + * when resolving FQDNs and globbing NULL hostname. Is it the right + * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG + * in ai_flags? */ -#include "namespace.h" +#if 0 +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include #include +#if 0 #include +#endif #include - +#include #include #include #include - -#include -#include -#include #include #include -#include -#include #include +#include +#include +#include #include +#include +#include + +#if 0 +#ifndef HAVE_PORTABLE_PROTOTYPE +#include "cdecl_ext.h" +#endif + +#ifndef HAVE_U_INT32_T +#include "bittypes.h" +#endif + +#ifndef HAVE_SOCKADDR_STORAGE +#include "sockstorage.h" +#endif + +#ifndef HAVE_ADDRINFO +#include "addrinfo.h" +#endif -#if 0 /*quickhack*/ #if defined(__KAME__) && defined(INET6) # define FAITH #endif @@ -88,31 +118,55 @@ struct sockinet { u_char si_len; u_char si_family; u_short si_port; + u_int32_t si_scope_id; }; -static struct afd { +static const struct afd { int a_af; int a_addrlen; int a_socklen; int a_off; const char *a_addrany; const char *a_loopback; + int a_scoped; } afdl [] = { #ifdef INET6 -#define N_INET6 0 {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), offsetof(struct sockaddr_in6, sin6_addr), - in6_addrany, in6_loopback}, -#define N_INET 1 -#else -#define N_INET 0 + in6_addrany, in6_loopback, 1}, #endif {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), offsetof(struct sockaddr_in, sin_addr), - in_addrany, in_loopback}, - {0, 0, 0, 0, NULL, NULL}, + in_addrany, in_loopback, 0}, + {0, 0, 0, 0, NULL, NULL, 0}, +}; + +struct explore { + int e_af; + int e_socktype; + int e_protocol; + const char *e_protostr; + int e_wild; +#define WILD_AF(ex) ((ex)->e_wild & 0x01) +#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) +#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) +}; + +static const struct explore explore[] = { +#if 0 + { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, +#endif +#ifdef INET6 + { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, + { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, + { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, +#endif + { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, + { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, + { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, + { -1, 0, 0, NULL, 0 }, }; #ifdef INET6 @@ -122,15 +176,25 @@ static struct afd { #endif -static int get_name __P((const char *, struct afd *, - struct addrinfo **, char *, struct addrinfo *, - int)); -static int get_addr __P((const char *, int, struct addrinfo **, - struct addrinfo *, int)); -static int get_addr0 __P((const char *, int, struct addrinfo **, - struct addrinfo *, int)); static int str_isnumber __P((const char *)); - +static int explore_fqdn __P((const struct addrinfo *, const char *, + const char *, struct addrinfo **)); +static int explore_null __P((const struct addrinfo *, const char *, + const char *, struct addrinfo **)); +static int explore_numeric __P((const struct addrinfo *, const char *, + const char *, struct addrinfo **)); +static int explore_numeric_scope __P((const struct addrinfo *, const char *, + const char *, struct addrinfo **)); +static int get_name __P((const char *, const struct afd *, struct addrinfo **, + char *, const struct addrinfo *, const char *)); +static int get_canonname __P((const struct addrinfo *, + struct addrinfo *, const char *)); +static struct addrinfo *get_ai __P((const struct addrinfo *, + const struct afd *, const char *)); +static int get_portmatch __P((const struct addrinfo *, const char *)); +static int get_port __P((struct addrinfo *, const char *, int)); +static const struct afd *find_afd __P((int)); + static char *ai_errlist[] = { "Success", "Address family for hostname not supported", /* EAI_ADDRFAMILY */ @@ -140,7 +204,7 @@ static char *ai_errlist[] = { "ai_family not supported", /* EAI_FAMILY */ "Memory allocation failure", /* EAI_MEMORY */ "No address associated with hostname", /* EAI_NODATA */ - "hostname nor servname provided, or not known",/* EAI_NONAME */ + "hostname nor servname provided, or not known", /* EAI_NONAME */ "servname not supported for ai_socktype", /* EAI_SERVICE */ "ai_socktype not supported", /* EAI_SOCKTYPE */ "System error returned in errno", /* EAI_SYSTEM */ @@ -149,35 +213,45 @@ static char *ai_errlist[] = { "Unknown error", /* EAI_MAX */ }; +/* XXX macros that make external reference is BAD. */ + +#define GET_AI(ai, afd, addr) \ +do { \ + /* external reference: pai, error, and label free */ \ + (ai) = get_ai(pai, (afd), (addr)); \ + if ((ai) == NULL) { \ + error = EAI_MEMORY; \ + goto free; \ + } \ +} while (0) + +#define GET_PORT(ai, serv) \ +do { \ + /* external reference: error and label free */ \ + error = get_port((ai), (serv), 0); \ + if (error != 0) \ + goto free; \ +} while (0) + #define GET_CANONNAME(ai, str) \ -if (pai->ai_flags & AI_CANONNAME) {\ - if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\ - strcpy((ai)->ai_canonname, (str));\ - } else {\ - error = EAI_MEMORY;\ - goto free;\ - }\ -} +do { \ + /* external reference: pai, error and label free */ \ + error = get_canonname(pai, (ai), (str)); \ + if (error != 0) \ + goto free; \ +} while (0) -#define GET_AI(ai, afd, addr, port) {\ - char *p;\ - if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\ - ((afd)->a_socklen)))\ - == NULL) {\ - error = EAI_MEMORY;\ - goto free;\ - }\ - memcpy(ai, pai, sizeof(struct addrinfo));\ - (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\ - memset((ai)->ai_addr, 0, (afd)->a_socklen);\ - (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (afd)->a_socklen;\ - (ai)->ai_addr->sa_family = (ai)->ai_family = (afd)->a_af;\ - ((struct sockinet *)(ai)->ai_addr)->si_port = port;\ - p = (char *)((ai)->ai_addr);\ - memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);\ -} +#define ERR(err) \ +do { \ + /* external reference: error, and label bad */ \ + error = (err); \ + goto bad; \ +} while (0) -#define ERR(err) { error = (err); goto bad; } +#define MATCH_FAMILY(x, y, w) \ + ((x) == (y) || ((w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) +#define MATCH(x, y, w) \ + ((x) == (y) || ((w) && ((x) == ANY || (y) == ANY))) char * gai_strerror(ecode) @@ -194,8 +268,6 @@ freeaddrinfo(ai) { struct addrinfo *next; - _DIAGASSERT(ai != NULL); - do { next = ai->ai_next; if (ai->ai_canonname) @@ -210,9 +282,6 @@ str_isnumber(p) const char *p; { char *q = (char *)p; - - _DIAGASSERT(p != NULL); - while (*q) { if (! isdigit(*q)) return NO; @@ -228,34 +297,26 @@ getaddrinfo(hostname, servname, hints, res) struct addrinfo **res; { struct addrinfo sentinel; - struct addrinfo *top = NULL; struct addrinfo *cur; - int i, error = 0; - char pton[PTON_MAX]; + int error = 0; struct addrinfo ai; + struct addrinfo ai0; struct addrinfo *pai; - u_short port; + const struct afd *afd; + const struct explore *ex; #ifdef FAITH static int firsttime = 1; if (firsttime) { /* translator hack */ - { - char *q = getenv("GAI"); - if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1) - translate = YES; - } + char *q = getenv("GAI"); + if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1) + translate = YES; firsttime = 0; } #endif - /* hostname may be NULL */ - /* servname may be NULL */ - /* hints may be NULL */ - _DIAGASSERT(res != NULL); - - /* initialize file static vars */ sentinel.ai_next = NULL; cur = &sentinel; pai = &ai; @@ -267,7 +328,6 @@ getaddrinfo(hostname, servname, hints, res) pai->ai_canonname = NULL; pai->ai_addr = NULL; pai->ai_next = NULL; - port = ANY; if (hostname == NULL && servname == NULL) return EAI_NONAME; @@ -289,233 +349,536 @@ getaddrinfo(hostname, servname, hints, res) ERR(EAI_FAMILY); } memcpy(pai, hints, sizeof(*pai)); - switch (pai->ai_socktype) { - case ANY: - switch (pai->ai_protocol) { - case ANY: - break; - case IPPROTO_UDP: - pai->ai_socktype = SOCK_DGRAM; - break; - case IPPROTO_TCP: - pai->ai_socktype = SOCK_STREAM; - break; - default: - pai->ai_socktype = SOCK_RAW; - break; + + /* + * if both socktype/protocol are specified, check if they + * are meaningful combination. + */ + if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { + for (ex = explore; ex->e_af >= 0; ex++) { + if (pai->ai_family != ex->e_af) + continue; + if (ex->e_socktype == ANY) + continue; + if (ex->e_protocol == ANY) + continue; + if (pai->ai_socktype == ex->e_socktype + && pai->ai_protocol != ex->e_protocol) { + ERR(EAI_BADHINTS); + } } - break; - case SOCK_RAW: - break; - case SOCK_DGRAM: - if (pai->ai_protocol != IPPROTO_UDP && - pai->ai_protocol != ANY) - ERR(EAI_BADHINTS); /*xxx*/ - pai->ai_protocol = IPPROTO_UDP; - break; - case SOCK_STREAM: - if (pai->ai_protocol != IPPROTO_TCP && - pai->ai_protocol != ANY) - ERR(EAI_BADHINTS); /*xxx*/ - pai->ai_protocol = IPPROTO_TCP; - break; - default: - ERR(EAI_SOCKTYPE); - break; } } /* - * service port + * check for special cases. (1) numeric servname is disallowed if + * socktype/protocol are left unspecified. (2) servname is disallowed + * for raw and other inet{,6} sockets. */ - if (servname) { - if (str_isnumber(servname)) { - if (pai->ai_socktype == ANY) { - /* caller accept *ANY* socktype */ - pai->ai_socktype = SOCK_DGRAM; - pai->ai_protocol = IPPROTO_UDP; - } - port = htons(atoi(servname)); - } else { - struct servent *sp; - char *proto; + if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) + || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)) { + ai0 = *pai; - proto = NULL; - switch (pai->ai_socktype) { - case ANY: - proto = NULL; - break; - case SOCK_DGRAM: - proto = "udp"; - break; - case SOCK_STREAM: - proto = "tcp"; - break; - default: - fprintf(stderr, "panic!\n"); - break; + if (pai->ai_family == PF_UNSPEC) + pai->ai_family = PF_INET6; + error = get_portmatch(pai, servname); + if (error) + ERR(error); + + *pai = ai0; + } + + ai0 = *pai; + + /* NULL hostname, or numeric hostname */ + for (ex = explore; ex->e_af >= 0; ex++) { + *pai = ai0; + + if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) + continue; + if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) + continue; + if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) + continue; + + if (pai->ai_family == PF_UNSPEC) + pai->ai_family = ex->e_af; + if (pai->ai_socktype == ANY && ex->e_socktype != ANY) + pai->ai_socktype = ex->e_socktype; + if (pai->ai_protocol == ANY && ex->e_protocol != ANY) + pai->ai_protocol = ex->e_protocol; + + if (hostname == NULL) + error = explore_null(pai, hostname, servname, &cur->ai_next); + else + error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next); + + if (error) + goto free; + + while (cur && cur->ai_next) + cur = cur->ai_next; + } + + /* + * XXX + * If numreic representation of AF1 can be interpreted as FQDN + * representation of AF2, we need to think again about the code below. + */ + if (sentinel.ai_next) + goto good; + + if (pai->ai_flags & AI_NUMERICHOST) + ERR(EAI_NONAME); + if (hostname == NULL) + ERR(EAI_NONAME); + + /* + * hostname as alphabetical name. + * we would like to prefer AF_INET6 than AF_INET, so we'll make a + * outer loop by AFs. + */ + for (afd = afdl; afd->a_af; afd++) { + *pai = ai0; + + if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1)) + continue; + + for (ex = explore; ex->e_af >= 0; ex++) { + *pai = ai0; + + if (pai->ai_family == PF_UNSPEC) + pai->ai_family = afd->a_af; + + if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) + continue; + if (!MATCH(pai->ai_socktype, ex->e_socktype, + WILD_SOCKTYPE(ex))) { + continue; } - if ((sp = getservbyname(servname, proto)) == NULL) - ERR(EAI_SERVICE); - port = sp->s_port; - if (pai->ai_socktype == ANY) { - if (strcmp(sp->s_proto, "udp") == 0) { - pai->ai_socktype = SOCK_DGRAM; - pai->ai_protocol = IPPROTO_UDP; - } else if (strcmp(sp->s_proto, "tcp") == 0) { - pai->ai_socktype = SOCK_STREAM; - pai->ai_protocol = IPPROTO_TCP; - } else - ERR(EAI_PROTOCOL); /*xxx*/ + if (!MATCH(pai->ai_protocol, ex->e_protocol, + WILD_PROTOCOL(ex))) { + continue; } + + if (pai->ai_family == PF_UNSPEC) + pai->ai_family = ex->e_af; + if (pai->ai_socktype == ANY && ex->e_socktype != ANY) + pai->ai_socktype = ex->e_socktype; + if (pai->ai_protocol == ANY && ex->e_protocol != ANY) + pai->ai_protocol = ex->e_protocol; + + error = explore_fqdn(pai, hostname, servname, + &cur->ai_next); + + while (cur && cur->ai_next) + cur = cur->ai_next; } } - + + /* XXX */ + if (sentinel.ai_next) + error = 0; + + if (error) + goto free; + if (error == 0) { + if (sentinel.ai_next) { + good: + *res = sentinel.ai_next; + return SUCCESS; + } else + error = EAI_FAIL; + } + free: + bad: + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + *res = NULL; + return error; +} + +/* + * FQDN hostname, DNS lookup + */ +static int +explore_fqdn(pai, hostname, servname, res) + const struct addrinfo *pai; + const char *hostname; + const char *servname; + struct addrinfo **res; +{ + int s; + struct hostent *hp; + int h_error; + int af; + char *ap; + struct addrinfo sentinel, *cur; + int i; + const struct afd *afd; + int error; + + *res = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; + /* - * hostname == NULL. - * passive socket -> anyaddr (0.0.0.0 or ::) - * non-passive socket -> localhost (127.0.0.1 or ::1) + * filter out AFs that are not supported by the kernel + * XXX errno? */ - if (hostname == NULL) { - struct afd *afd; - int s; + s = socket(pai->ai_family, SOCK_DGRAM, 0); + if (s < 0) { + if (errno != EMFILE) + return 0; + } else + close(s); - for (afd = &afdl[0]; afd->a_af; afd++) { - if (!(pai->ai_family == PF_UNSPEC - || pai->ai_family == afd->a_af)) { - continue; - } + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + + /* + * post-RFC2553: should look at (pai->ai_flags & AI_ADDRCONFIG) + * rather than hardcoding it. we may need to add AI_ADDRCONFIG + * handling code by ourselves in case we don't have getipnodebyname(). + */ +#ifdef USE_GETIPNODEBY + hp = getipnodebyname(hostname, pai->ai_family, AI_ADDRCONFIG, &h_error); +#else + hp = gethostbyname2(hostname, pai->ai_family); + h_error = h_errno; +#endif + + if (hp == NULL) { + switch (h_error) { + case HOST_NOT_FOUND: + case NO_DATA: + error = EAI_NODATA; + break; + case TRY_AGAIN: + error = EAI_AGAIN; + break; + case NO_RECOVERY: + case NETDB_INTERNAL: + default: + error = EAI_FAIL; + break; + } + } else if ((hp->h_name == NULL) || (hp->h_name[0] == 0) + || (hp->h_addr_list[0] == NULL)) { +#ifdef USE_GETIPNODEBY + freehostent(hp); +#endif + hp = NULL; + error = EAI_FAIL; + } + + if (hp == NULL) + goto free; + + for (i = 0; hp->h_addr_list[i] != NULL; i++) { + af = hp->h_addrtype; + ap = hp->h_addr_list[i]; + if (af == AF_INET6 + && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { + af = AF_INET; + ap = ap + sizeof(struct in6_addr) + - sizeof(struct in_addr); + } + if (af != pai->ai_family) + continue; + + if ((pai->ai_flags & AI_CANONNAME) == 0) { + GET_AI(cur->ai_next, afd, ap); + GET_PORT(cur->ai_next, servname); + } else { /* - * filter out AFs that are not supported by the kernel - * XXX errno? + * if AI_CANONNAME and if reverse lookup + * fail, return ai anyway to pacify + * calling application. + * + * XXX getaddrinfo() is a name->address + * translation function, and it looks + * strange that we do addr->name + * translation here. */ - s = socket(afd->a_af, SOCK_DGRAM, 0); - if (s < 0) - continue; - close(s); + get_name(ap, afd, &cur->ai_next, + ap, pai, servname); + } - if (pai->ai_flags & AI_PASSIVE) { - GET_AI(cur->ai_next, afd, afd->a_addrany, port); - /* xxx meaningless? - * GET_CANONNAME(cur->ai_next, "anyaddr"); - */ - } else { - GET_AI(cur->ai_next, afd, afd->a_loopback, - port); - /* xxx meaningless? - * GET_CANONNAME(cur->ai_next, "localhost"); - */ - } + while (cur && cur->ai_next) cur = cur->ai_next; - } - top = sentinel.ai_next; - if (top) - goto good; - else - ERR(EAI_FAMILY); } - - /* hostname as numeric name */ - for (i = 0; afdl[i].a_af; i++) { - if (inet_pton(afdl[i].a_af, hostname, pton)) { - u_long v4a; - u_char pfx; - - switch (afdl[i].a_af) { - case AF_INET: - v4a = ntohl(((struct in_addr *)pton)->s_addr); - if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) - pai->ai_flags &= ~AI_CANONNAME; - v4a >>= IN_CLASSA_NSHIFT; - if (v4a == 0 || v4a == IN_LOOPBACKNET) - pai->ai_flags &= ~AI_CANONNAME; - break; + + *res = sentinel.ai_next; + return 0; + +free: +#ifdef USE_GETIPNODEBY + if (hp) + freehostent(hp); +#endif + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + return error; +} + +/* + * hostname == NULL. + * passive socket -> anyaddr (0.0.0.0 or ::) + * non-passive socket -> localhost (127.0.0.1 or ::1) + */ +static int +explore_null(pai, hostname, servname, res) + const struct addrinfo *pai; + const char *hostname; + const char *servname; + struct addrinfo **res; +{ + int s; + const struct afd *afd; + struct addrinfo *cur; + struct addrinfo sentinel; + int error; + + *res = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; + + /* + * filter out AFs that are not supported by the kernel + * XXX errno? + */ + s = socket(pai->ai_family, SOCK_DGRAM, 0); + if (s < 0) { + if (errno != EMFILE) + return 0; + } else + close(s); + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + + if (pai->ai_flags & AI_PASSIVE) { + GET_AI(cur->ai_next, afd, afd->a_addrany); + /* xxx meaningless? + * GET_CANONNAME(cur->ai_next, "anyaddr"); + */ + GET_PORT(cur->ai_next, servname); + } else { + GET_AI(cur->ai_next, afd, afd->a_loopback); + /* xxx meaningless? + * GET_CANONNAME(cur->ai_next, "localhost"); + */ + GET_PORT(cur->ai_next, servname); + } + cur = cur->ai_next; + + *res = sentinel.ai_next; + return 0; + +free: + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + return error; +} + +/* + * numeric hostname + */ +static int +explore_numeric(pai, hostname, servname, res) + const struct addrinfo *pai; + const char *hostname; + const char *servname; + struct addrinfo **res; +{ + const struct afd *afd; + struct addrinfo *cur; + struct addrinfo sentinel; + int error; + char pton[PTON_MAX]; + int flags; + + *res = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + flags = pai->ai_flags; + + if (inet_pton(afd->a_af, hostname, pton) == 1) { + u_int32_t v4a; #ifdef INET6 - case AF_INET6: - pfx = ((struct in6_addr *)pton)->s6_addr8[0]; - if (pfx == 0 || pfx == 0xfe || pfx == 0xff) - pai->ai_flags &= ~AI_CANONNAME; - break; + u_char pfx; #endif - } - - if (pai->ai_family == afdl[i].a_af || - pai->ai_family == PF_UNSPEC) { - if (! (pai->ai_flags & AI_CANONNAME)) { - GET_AI(top, &afdl[i], pton, port); - goto good; - } + + switch (afd->a_af) { + case AF_INET: + v4a = (u_int32_t)ntohl(((struct in_addr *)pton)->s_addr); + if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) + flags &= ~AI_CANONNAME; + v4a >>= IN_CLASSA_NSHIFT; + if (v4a == 0 || v4a == IN_LOOPBACKNET) + flags &= ~AI_CANONNAME; + break; +#ifdef INET6 + case AF_INET6: + pfx = ((struct in6_addr *)pton)->s6_addr[0]; + if (pfx == 0 || pfx == 0xfe || pfx == 0xff) + flags &= ~AI_CANONNAME; + break; +#endif + } + + if (pai->ai_family == afd->a_af || + pai->ai_family == PF_UNSPEC /*?*/) { + if ((flags & AI_CANONNAME) == 0) { + GET_AI(cur->ai_next, afd, pton); + GET_PORT(cur->ai_next, servname); + } else { /* * if AI_CANONNAME and if reverse lookup * fail, return ai anyway to pacify * calling application. * * XXX getaddrinfo() is a name->address - * translation function, and it looks strange - * that we do addr->name translation here. + * translation function, and it looks + * strange that we do addr->name + * translation here. */ - get_name(pton, &afdl[i], &top, pton, pai, port); - goto good; - } else - ERR(EAI_FAMILY); /*xxx*/ - } + get_name(pton, afd, &cur->ai_next, + pton, pai, servname); + } + while (cur && cur->ai_next) + cur = cur->ai_next; + } else + ERR(EAI_FAMILY); /*xxx*/ } - if (pai->ai_flags & AI_NUMERICHOST) - ERR(EAI_NONAME); + *res = sentinel.ai_next; + return 0; + +free: +bad: + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + return error; +} + +/* + * numeric hostname with scope + */ +static int +explore_numeric_scope(pai, hostname, servname, res) + const struct addrinfo *pai; + const char *hostname; + const char *servname; + struct addrinfo **res; +{ +#ifndef SCOPE_DELIMITER + return explore_numeric(pai, hostname, servname, res); +#else + const struct afd *afd; + struct addrinfo *cur; + int error; + char *cp, *hostname2 = NULL; + int scope; + struct sockaddr_in6 *sin6; + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + if (!afd->a_scoped) + return explore_numeric(pai, hostname, servname, res); + + cp = strchr(hostname, SCOPE_DELIMITER); + if (cp == NULL) + return explore_numeric(pai, hostname, servname, res); + + /* + * Handle special case of + */ + hostname2 = strdup(hostname); + if (hostname2 == NULL) + return EAI_MEMORY; + /* terminate at the delimiter */ + hostname2[cp - hostname] = '\0'; - /* hostname as alphabetical name */ - error = get_addr(hostname, pai->ai_family, &top, pai, port); + cp++; + switch (pai->ai_family) { +#ifdef INET6 + case AF_INET6: + scope = if_nametoindex(cp); + break; +#endif + } + + error = explore_numeric(pai, hostname2, servname, res); if (error == 0) { - if (top) { - good: - *res = top; - return SUCCESS; - } else - error = EAI_FAIL; + for (cur = *res; cur; cur = cur->ai_next) { + if (cur->ai_family != AF_INET6) + continue; + sin6 = (struct sockaddr_in6 *)cur->ai_addr; + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) + sin6->sin6_scope_id = scope; + } } - free: - if (top) - freeaddrinfo(top); - bad: - *res = NULL; + + free(hostname2); + return error; +#endif } static int -get_name(addr, afd, res, numaddr, pai, port0) +get_name(addr, afd, res, numaddr, pai, servname) const char *addr; - struct afd *afd; + const struct afd *afd; struct addrinfo **res; char *numaddr; - struct addrinfo *pai; - int port0; + const struct addrinfo *pai; + const char *servname; { - u_short port = port0 & 0xffff; struct hostent *hp; struct addrinfo *cur; int error = 0; #ifdef USE_GETIPNODEBY int h_error; -#endif - _DIAGASSERT(addr != NULL); - _DIAGASSERT(afd != NULL); - _DIAGASSERT(res != NULL); - _DIAGASSERT(numaddr != NULL); - _DIAGASSERT(pai != NULL); - -#ifdef USE_GETIPNODEBY hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); #else hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); #endif if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { - GET_AI(cur, afd, hp->h_addr_list[0], port); + GET_AI(cur, afd, hp->h_addr_list[0]); + GET_PORT(cur, servname); GET_CANONNAME(cur, hp->h_name); - } else - GET_AI(cur, afd, numaddr, port); + } else { + GET_AI(cur, afd, numaddr); + GET_PORT(cur, servname); + } #ifdef USE_GETIPNODEBY if (hp) @@ -536,196 +899,138 @@ get_name(addr, afd, res, numaddr, pai, port0) } static int -get_addr(hostname, af, res0, pai, port0) - const char *hostname; - int af; - struct addrinfo **res0; - struct addrinfo *pai; - int port0; +get_canonname(pai, ai, str) + const struct addrinfo *pai; + struct addrinfo *ai; + const char *str; { -#ifndef USE_GETIPNODEBY - int i, error, ekeep; - struct addrinfo *cur; - struct addrinfo **res; - int retry; - int s; -#endif - - _DIAGASSERT(hostname != NULL); - _DIAGASSERT(res != NULL); - _DIAGASSERT(pai != NULL); - -#ifdef USE_GETIPNODEBY - return get_addr0(hostname, af, res0, pai, port0); -#else - res = res0; - ekeep = 0; - error = 0; - for (i = 0; afdl[i].a_af; i++) { - retry = 0; - if (af == AF_UNSPEC) { - /* - * filter out AFs that are not supported by the kernel - * XXX errno? - */ - s = socket(afdl[i].a_af, SOCK_DGRAM, 0); - if (s < 0) - continue; - close(s); - } else { - if (af != afdl[i].a_af) - continue; - } - /* It is WRONG, we need getipnodebyname(). */ -again: - error = get_addr0(hostname, afdl[i].a_af, res, pai, port0); - switch (error) { - case EAI_AGAIN: - if (++retry < 3) - goto again; - /* FALL THROUGH*/ - default: - if (ekeep == 0) - ekeep = error; - break; - } - if (*res) { - /* make chain of addrs */ - for (cur = *res; - cur && cur->ai_next; - cur = cur->ai_next) - ; - if (!cur) - return EAI_FAIL; - res = &cur->ai_next; - } + if ((pai->ai_flags & AI_CANONNAME) != 0) { + ai->ai_canonname = (char *)malloc(strlen(str) + 1); + if (ai->ai_canonname == NULL) + return EAI_MEMORY; + strcpy(ai->ai_canonname, str); } + return 0; +} - /* if we got something, it's okay */ - if (*res0) - return 0; +static struct addrinfo * +get_ai(pai, afd, addr) + const struct addrinfo *pai; + const struct afd *afd; + const char *addr; +{ + char *p; + struct addrinfo *ai; + + ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + + (afd->a_socklen)); + if (ai == NULL) + return NULL; - return error ? error : ekeep; + memcpy(ai, pai, sizeof(struct addrinfo)); + ai->ai_addr = (struct sockaddr *)(ai + 1); + memset(ai->ai_addr, 0, afd->a_socklen); +#ifdef HAVE_SOCKADDR_SA_LEN + ai->ai_addr->sa_len = afd->a_socklen; #endif + ai->ai_addrlen = afd->a_socklen; + ai->ai_addr->sa_family = ai->ai_family = afd->a_af; + p = (char *)(ai->ai_addr); + memcpy(p + afd->a_off, addr, afd->a_addrlen); + return ai; } static int -get_addr0(hostname, af, res, pai, port0) - const char *hostname; - int af; - struct addrinfo **res; - struct addrinfo *pai; - int port0; +get_portmatch(ai, servname) + const struct addrinfo *ai; + const char *servname; { - u_short port = port0 & 0xffff; - struct addrinfo sentinel; - struct hostent *hp; - struct addrinfo *top, *cur; - struct afd *afd; - int i, error = 0, h_error; - char *ap; -#ifndef USE_GETIPNODEBY - extern int h_errno; -#endif - _DIAGASSERT(hostname != NULL); - _DIAGASSERT(res != NULL); - _DIAGASSERT(pai != NULL); + /* get_port does not touch first argument. when matchonly == 1. */ + return get_port((struct addrinfo *)ai, servname, 1); +} - top = NULL; - sentinel.ai_next = NULL; - cur = &sentinel; -#ifdef USE_GETIPNODEBY - if (af == AF_UNSPEC) { - hp = getipnodebyname(hostname, AF_INET6, - AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error); - } else - hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error); -#else - if (af == AF_UNSPEC) { - error = EAI_FAIL; - goto bad; +static int +get_port(ai, servname, matchonly) + struct addrinfo *ai; + const char *servname; + int matchonly; +{ + const char *proto; + struct servent *sp; + int port; + int allownumeric; + + if (servname == NULL) + return 0; + if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) + return 0; + + switch (ai->ai_socktype) { + case SOCK_RAW: + return EAI_SERVICE; + case SOCK_DGRAM: + case SOCK_STREAM: + allownumeric = 1; + break; + case ANY: + allownumeric = 0; + break; + default: + return EAI_SOCKTYPE; } - hp = gethostbyname2(hostname, af); - h_error = h_errno; -#endif - if (hp == NULL) { - switch (h_error) { - case HOST_NOT_FOUND: - case NO_DATA: - error = EAI_NODATA; + + if (str_isnumber(servname)) { + if (!allownumeric) + return EAI_SERVICE; + port = htons(atoi(servname)); + if (port < 0 || port > 65535) + return EAI_SERVICE; + } else { + switch (ai->ai_socktype) { + case SOCK_DGRAM: + proto = "udp"; break; - case TRY_AGAIN: - error = EAI_AGAIN; + case SOCK_STREAM: + proto = "tcp"; break; - case NO_RECOVERY: - case NETDB_INTERNAL: default: - error = EAI_FAIL; + proto = NULL; break; } - goto bad; + + if ((sp = getservbyname(servname, proto)) == NULL) + return EAI_SERVICE; + port = sp->s_port; } - if ((hp->h_name == NULL) || (hp->h_name[0] == 0) || - (hp->h_addr_list[0] == NULL)) - ERR(EAI_FAIL); - - for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) { - switch (af) { -#ifdef INET6 - case AF_INET6: - afd = &afdl[N_INET6]; - break; -#endif -#ifndef INET6 - default: /* AF_UNSPEC */ -#endif + if (!matchonly) { + switch (ai->ai_family) { case AF_INET: - afd = &afdl[N_INET]; + ((struct sockaddr_in *)ai->ai_addr)->sin_port = port; break; #ifdef INET6 - default: /* AF_UNSPEC */ - if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { - ap += sizeof(struct in6_addr) - - sizeof(struct in_addr); - afd = &afdl[N_INET]; - } else - afd = &afdl[N_INET6]; + case AF_INET6: + ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port; break; #endif } -#ifdef FAITH - if (translate && afd->a_af == AF_INET) { - struct in6_addr *in6; - - GET_AI(cur->ai_next, &afdl[N_INET6], ap, port); - in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr; - memcpy(&in6->s6_addr32[0], &faith_prefix, - sizeof(struct in6_addr) - sizeof(struct in_addr)); - memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr)); - } else -#endif /* FAITH */ - GET_AI(cur->ai_next, afd, ap, port); - if (cur == &sentinel) { - top = cur->ai_next; - GET_CANONNAME(top, hp->h_name); - } - cur = cur->ai_next; } -#ifdef USE_GETIPNODEBY - freehostent(hp); -#endif - *res = top; - return SUCCESS; - free: - if (top) - freeaddrinfo(top); -#ifdef USE_GETIPNODEBY - if (hp) - freehostent(hp); -#endif - bad: - *res = NULL; - return error; + + return 0; +} + +static const struct afd * +find_afd(af) + int af; +{ + const struct afd *afd; + + if (af == PF_UNSPEC) + return NULL; + for (afd = afdl; afd->a_af; afd++) { + if (afd->a_af == af) + return afd; + } + return NULL; } diff --git a/lib/libc/net/getnameinfo.3 b/lib/libc/net/getnameinfo.3 index 79288c83516..51088b8e3cf 100644 --- a/lib/libc/net/getnameinfo.3 +++ b/lib/libc/net/getnameinfo.3 @@ -30,22 +30,26 @@ .\" SUCH DAMAGE. .\" .\" From: @(#)gethostbyname.3 8.4 (Berkeley) 5/25/95 -.\" $Id: getnameinfo.3,v 1.2 1999/07/03 13:58:31 kleink Exp $ +.\" KAME Id: getnameinfo.3,v 1.4 1999/12/10 04:04:31 itojun Exp .\" .Dd May 25, 1995 .Dt GETNAMEINFO 3 .Os KAME +.\" .Sh NAME .Nm getnameinfo .Nd address-to-nodename translation in protocol-independent manner +.\" .Sh LIBRARY .Lb libc +.\" .Sh SYNOPSIS .Fd #include .Fd #include .Ft int .Fn getnameinfo "const struct sockaddr *sa" "socklen_t salen" \ "char *host" "size_t hostlen" "char *serv" "size_t servlen" "int flags" +.\" .Sh DESCRIPTION The .Fn getnameinfo @@ -66,16 +70,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 @@ -104,7 +108,7 @@ 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 : +.Aq Pa netdb.h : .Bd -literal -offset #define NI_MAXHOST 1025 #define NI_MAXSERV 32 @@ -113,7 +117,7 @@ returned strings the following constants are defined in The first value is actually defined as the constant .Dv MAXDNAME in recent versions of BIND's -.Li +.Aq Pa arpa/nameser.h header .Po older versions of BIND define this constant to be 256 @@ -156,30 +160,50 @@ 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 . +.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 , +if +.Dv NI_WITHSCOPEID +bit is enabled in +.Ar flags +argument. +Refer to +.Xr getaddrinfo 3 +for the notation. +.\" .Sh FILES .Bl -tag -width /etc/resolv.conf -compact .It Pa /etc/hosts .It Pa /etc/host.conf .It Pa /etc/resolv.conf .El +.\" .Sh DIAGNOSTICS The function indicates successful completion by a zero return value; a non-zero return value indicates failure. +.\" .Sh SEE ALSO .Xr getaddrinfo 3 , .Xr gethostbyaddr 3 , @@ -189,15 +213,26 @@ a non-zero return value indicates failure. .Xr hostname 7 , .Xr named 8 .Pp -R. Gilligan, S. Thomson, J. Bound, and W. Stevens, -``Basic Socket Interface Extensions for IPv6,'' RFC2553, March 1999. +.Rs +.%A R. Gilligan +.%A S. Thomson +.%A J. Bound +.%A W. Stevens +.%T Basic Socket Interface Extensions for IPv6 +.%R RFC2553 +.%D March 1999 +.Re +.\" .Sh HISTORY The implementation first appeared in WIDE Hydrangea IPv6 protocol stack kit. +.\" .Sh STANDARDS The .Fn getaddrinfo function is defined IEEE POSIX 1003.1g draft specification, -and documented in ``Basic Socket Interface Extensions for IPv6'' +and documented in +.Dq Basic Socket Interface Extensions for IPv6 .Pq RFC2533 . +.\" .Sh BUGS The text was shamelessly copied from RFC2553. diff --git a/lib/libc/net/getnameinfo.c b/lib/libc/net/getnameinfo.c index f3a46c30b28..3f3f6b1caa8 100644 --- a/lib/libc/net/getnameinfo.c +++ b/lib/libc/net/getnameinfo.c @@ -1,4 +1,4 @@ -/* $NetBSD: getnameinfo.c,v 1.4 1999/08/22 12:54:02 kleink Exp $ */ +/* $NetBSD: getnameinfo.c,v 1.5 1999/12/13 14:18:32 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -32,13 +32,22 @@ /* * Issues to be discussed: * - Thread safe-ness must be checked - * - Return values. There seems to be no standard for return value (RFC2133) + * - 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). */ -#include "namespace.h" +#if 0 +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + #include #include +#include #include #include #include @@ -47,6 +56,16 @@ #include #include +#if 0 +#ifndef HAVE_PORTABLE_PROTOTYPE +#include "cdecl_ext.h" +#endif + +#ifndef HAVE_ADDRINFO +#include "addrinfo.h" +#endif +#endif + #define SUCCESS 0 #define ANY 0 #define YES 1 @@ -95,9 +114,9 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) struct servent *sp; struct hostent *hp; u_short port; - int family, len, i; + int family, i; char *addr, *p; - u_long v4a; + u_int32_t v4a; int h_error; char numserv[512]; char numaddr[512]; @@ -105,8 +124,10 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) if (sa == NULL) return ENI_NOSOCKET; - len = sa->sa_len; - if (len != salen) return ENI_SALEN; +#ifdef HAVE_SA_LEN /*XXX*/ + if (sa->sa_len != salen) + return ENI_SALEN; +#endif family = sa->sa_family; for (i = 0; afdl[i].a_af; i++) @@ -117,31 +138,42 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) return ENI_FAMILY; found: - if (len != afd->a_socklen) return ENI_SALEN; + if (salen != afd->a_socklen) + return ENI_SALEN; port = ((struct sockinet *)sa)->si_port; /* network byte order */ addr = (char *)sa + afd->a_off; if (serv == NULL || servlen == 0) { - /* what we should do? */ - } else if (flags & NI_NUMERICSERV) { - snprintf(numserv, sizeof(numserv), "%d", ntohs(port)); - if (strlen(numserv) > servlen) - return ENI_MEMORY; - strcpy(serv, numserv); + /* + * 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 { - sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp"); + if (flags & NI_NUMERICSERV) + sp = NULL; + else { + sp = getservbyport(port, + (flags & NI_DGRAM) ? "udp" : "tcp"); + } if (sp) { if (strlen(sp->s_name) > servlen) return ENI_MEMORY; strcpy(serv, sp->s_name); - } else - return ENI_NOSERVNAME; + } else { + snprintf(numserv, sizeof(numserv), "%d", ntohs(port)); + if (strlen(numserv) > servlen) + return ENI_MEMORY; + strcpy(serv, numserv); + } } switch (sa->sa_family) { case AF_INET: - v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); + v4a = (u_int32_t) + ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) flags |= NI_NUMERICHOST; v4a >>= IN_CLASSA_NSHIFT; @@ -153,7 +185,7 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) { struct sockaddr_in6 *sin6; sin6 = (struct sockaddr_in6 *)sa; - switch (sin6->sin6_addr.s6_addr8[0]) { + switch (sin6->sin6_addr.s6_addr[0]) { case 0x00: if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) ; @@ -163,8 +195,9 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) flags |= NI_NUMERICHOST; break; default: - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { flags |= NI_NUMERICHOST; + } else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) flags |= NI_NUMERICHOST; break; @@ -174,7 +207,12 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) #endif } if (host == NULL || hostlen == 0) { - /* what should we do? */ + /* + * 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) { /* NUMERICHOST and NAMEREQD conflicts with each other */ if (flags & NI_NAMEREQD) @@ -185,6 +223,26 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) if (strlen(numaddr) > hostlen) return ENI_MEMORY; strcpy(host, numaddr); +#if defined(INET6) && defined(NI_WITHSCOPEID) + 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) { +#ifndef ALWAYS_WITHSCOPE + if (flags & NI_WITHSCOPEID) +#endif /* !ALWAYS_WITHSCOPE */ + { + char *ep = strchr(host, '\0'); + unsigned int ifindex = + ((struct sockaddr_in6 *)sa)->sin6_scope_id; + + *ep = SCOPE_DELIMITER; + if ((if_indextoname(ifindex, ep + 1)) == NULL) + /* XXX what should we do? */ + strncpy(ep + 1, "???", 3); + } + } +#endif /* INET6 */ } else { #ifdef USE_GETIPNODEBY hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); diff --git a/lib/libc/shlib_version b/lib/libc/shlib_version index b3a7a362f50..6c98ddb8851 100644 --- a/lib/libc/shlib_version +++ b/lib/libc/shlib_version @@ -1,5 +1,5 @@ -# $NetBSD: shlib_version,v 1.80 1999/12/01 18:35:15 thorpej Exp $ +# $NetBSD: shlib_version,v 1.81 1999/12/13 14:18:32 itojun Exp $ # Remember to update distrib/sets/lists/base/shl.* when changing # major=12 -minor=52 +minor=53 -- cgit