summaryrefslogtreecommitdiff
path: root/lib/libc/net/getaddrinfo.c
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2000-02-09 12:22:10 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2000-02-09 12:22:10 +0000
commitf1dd7c2f67784cc38698446bb1dfbf5018879596 (patch)
treefc8f5835a1dda89568432ac6b143afa4646fea20 /lib/libc/net/getaddrinfo.c
parentd3591852121f70dd41edd8defab790c140791be0 (diff)
revise extended scoped address format support. delimiter and the order
is changed, based on discussion in ipngwg scoped address cabal. past code: fe80::1@de0 now: de0%fe80::1 this will be in sync with next extended address format proposal (which should be final - I don't want to make this kind of change again).
Diffstat (limited to 'lib/libc/net/getaddrinfo.c')
-rw-r--r--lib/libc/net/getaddrinfo.c255
1 files changed, 162 insertions, 93 deletions
diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c
index 47b298f9c5a..ff3131388ee 100644
--- a/lib/libc/net/getaddrinfo.c
+++ b/lib/libc/net/getaddrinfo.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: getaddrinfo.c,v 1.9 2000/01/26 06:51:26 itojun Exp $ */
+/* $OpenBSD: getaddrinfo.c,v 1.10 2000/02/09 12:22:09 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -30,13 +30,18 @@
*/
/*
- * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
- *
* 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 RFC2553 is silent about which error
* code must be returned for which situation.
+ * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2
+ * says to use inet_aton() to convert IPv4 numeric to binary (alows
+ * classful form as a result).
+ * current code - disallow classful form for IPv4 (due to use of inet_pton).
+ * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is
+ * invalid.
+ * current code - SEGV on freeaddrinfo(NULL)
* 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
@@ -71,11 +76,6 @@
#define YES 1
#define NO 0
-#ifdef FAITH
-static int translate = NO;
-static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT;
-#endif
-
static const char in_addrany[] = { 0, 0, 0, 0 };
static const char in6_addrany[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
@@ -150,7 +150,7 @@ static const struct explore explore[] = {
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 *,
+static int explore_null __P((const struct addrinfo *,
const char *, struct addrinfo **));
static int explore_numeric __P((const struct addrinfo *, const char *,
const char *, struct addrinfo **));
@@ -163,6 +163,12 @@ static struct addrinfo *get_ai __P((const struct addrinfo *,
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));
+#ifdef AI_ADDRCONFIG
+static int addrconfig __P((const struct addrinfo *));
+#endif
+#ifdef INET6
+static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *));
+#endif
/* XXX macros that make external reference is BAD. */
@@ -174,7 +180,7 @@ do { \
error = EAI_MEMORY; \
goto free; \
} \
-} while (0)
+} while (/*CONSTCOND*/0)
#define GET_PORT(ai, serv) \
do { \
@@ -182,7 +188,7 @@ do { \
error = get_port((ai), (serv), 0); \
if (error != 0) \
goto free; \
-} while (0)
+} while (/*CONSTCOND*/0)
#define GET_CANONNAME(ai, str) \
do { \
@@ -190,27 +196,27 @@ do { \
error = get_canonname(pai, (ai), (str)); \
if (error != 0) \
goto free; \
-} while (0)
+} while (/*CONSTCOND*/0)
#define ERR(err) \
do { \
/* external reference: error, and label bad */ \
error = (err); \
goto bad; \
-} while (0)
+} while (/*CONSTCOND*/0)
#define MATCH_FAMILY(x, y, w) \
- ((x) == (y) || ((w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
+ ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
#define MATCH(x, y, w) \
- ((x) == (y) || ((w) && ((x) == ANY || (y) == ANY)))
+ ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
static int
str_isnumber(p)
const char *p;
{
- char *q = (char *)p;
+ const char *q = (const char *)p;
while (*q) {
- if (! isdigit(*q))
+ if (!isdigit(*q))
return NO;
q++;
}
@@ -231,21 +237,6 @@ getaddrinfo(hostname, servname, hints, res)
struct addrinfo *pai;
const struct afd *afd;
const struct explore *ex;
-#ifndef AI_MASK
-#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST)
-#endif
-
-#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;
- firsttime = 0;
- }
-#endif
sentinel.ai_next = NULL;
cur = &sentinel;
@@ -306,11 +297,19 @@ getaddrinfo(hostname, servname, hints, res)
* for raw and other inet{,6} sockets.
*/
if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
- || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)) {
- ai0 = *pai;
+#ifdef PF_INET6
+ || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
+#endif
+ ) {
+ ai0 = *pai; /* backup *pai */
- if (pai->ai_family == PF_UNSPEC)
+ if (pai->ai_family == PF_UNSPEC) {
+#ifdef PF_INET6
pai->ai_family = PF_INET6;
+#else
+ pai->ai_family = PF_INET;
+#endif
+ }
error = get_portmatch(pai, servname);
if (error)
ERR(error);
@@ -339,7 +338,7 @@ getaddrinfo(hostname, servname, hints, res)
pai->ai_protocol = ex->e_protocol;
if (hostname == NULL)
- error = explore_null(pai, hostname, servname, &cur->ai_next);
+ error = explore_null(pai, servname, &cur->ai_next);
else
error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
@@ -445,21 +444,22 @@ explore_fqdn(pai, hostname, servname, res)
char *ap;
struct addrinfo sentinel, *cur;
int i;
-#ifndef USE_GETIPNODEBY
int naddrs;
-#endif
const struct afd *afd;
- int error;
+ int error = 0;
*res = NULL;
sentinel.ai_next = NULL;
cur = &sentinel;
+#ifdef AI_ADDRCONFIG
/*
- * Do not filter unsupported AFs here. We need to honor content of
- * databases (/etc/hosts, DNS and others). Otherwise we cannot
- * replace gethostbyname() by getaddrinfo().
+ * If AI_ADDRCONFIG is specified, check if we are expected to
+ * return the address family or not.
*/
+ if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(pai))
+ return 0;
+#endif
/*
* if the servname does not match socktype/protocol, ignore it.
@@ -469,17 +469,8 @@ explore_fqdn(pai, hostname, servname, res)
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) {
@@ -498,9 +489,6 @@ explore_fqdn(pai, hostname, servname, res)
}
} 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;
}
@@ -508,9 +496,6 @@ explore_fqdn(pai, hostname, servname, res)
if (hp == NULL)
goto free;
-#ifdef USE_GETIPNODEBY
- aplist = hp->h_addr_list;
-#else
/*
* hp will be overwritten if we use gethostbyname2().
* always deep copy for simplification.
@@ -519,7 +504,7 @@ explore_fqdn(pai, hostname, servname, res)
;
naddrs++;
aplist = (char **)malloc(sizeof(aplist[0]) * naddrs);
- apbuf = (char *)malloc(hp->h_length * naddrs);
+ apbuf = (char *)malloc((size_t)hp->h_length * naddrs);
if (aplist == NULL || apbuf == NULL) {
error = EAI_MEMORY;
goto free;
@@ -531,20 +516,21 @@ explore_fqdn(pai, hostname, servname, res)
continue;
}
memcpy(&apbuf[i * hp->h_length], hp->h_addr_list[i],
- hp->h_length);
+ (size_t)hp->h_length);
aplist[i] = &apbuf[i * hp->h_length];
}
-#endif
for (i = 0; aplist[i] != NULL; i++) {
af = hp->h_addrtype;
ap = aplist[i];
+#ifdef AF_INET6
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);
}
+#endif
if (af != pai->ai_family)
continue;
@@ -587,9 +573,8 @@ free:
* non-passive socket -> localhost (127.0.0.1 or ::1)
*/
static int
-explore_null(pai, hostname, servname, res)
+explore_null(pai, servname, res)
const struct addrinfo *pai;
- const char *hostname;
const char *servname;
struct addrinfo **res;
{
@@ -676,15 +661,33 @@ explore_numeric(pai, hostname, servname, res)
afd = find_afd(pai->ai_family);
flags = pai->ai_flags;
- 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*/
+ switch (afd->a_af) {
+#if 0 /*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;
@@ -713,8 +716,7 @@ explore_numeric_scope(pai, hostname, servname, res)
const struct afd *afd;
struct addrinfo *cur;
int error;
- char *cp, *hostname2 = NULL;
- int scope;
+ char *cp, *hostname2 = NULL, *scope;
struct sockaddr_in6 *sin6;
/*
@@ -732,36 +734,29 @@ explore_numeric_scope(pai, hostname, servname, res)
return explore_numeric(pai, hostname, servname, res);
/*
- * Handle special case of <scoped_address><delimiter><scope id>
+ * Handle special case of <scope id><delimiter><scoped_address>
*/
hostname2 = strdup(hostname);
if (hostname2 == NULL)
return EAI_MEMORY;
/* terminate at the delimiter */
hostname2[cp - hostname] = '\0';
-
+ scope = hostname2;
cp++;
- switch (pai->ai_family) {
-#ifdef INET6
- case AF_INET6:
- scope = if_nametoindex(cp);
- if (scope == 0) {
- free(hostname2);
- return (EAI_NONAME);
- }
- break;
-#endif
- }
- error = explore_numeric(pai, hostname2, servname, res);
+ error = explore_numeric(pai, cp, servname, res);
if (error == 0) {
+ int scopeid;
+
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;
+ if ((scopeid = ip6_str2scopeid(scope, sin6)) == -1) {
+ free(hostname2);
+ return(EAI_NONAME); /* XXX: is return OK? */
+ }
+ sin6->sin6_scope_id = scopeid;
}
}
@@ -802,12 +797,12 @@ get_ai(pai, afd, addr)
memcpy(ai, pai, sizeof(struct addrinfo));
ai->ai_addr = (struct sockaddr *)(ai + 1);
- memset(ai->ai_addr, 0, afd->a_socklen);
+ memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
ai->ai_addr->sa_len = afd->a_socklen;
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);
+ memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
return ai;
}
@@ -834,8 +829,15 @@ get_port(ai, servname, matchonly)
if (servname == NULL)
return 0;
- if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+ switch (ai->ai_family) {
+ case AF_INET:
+#ifdef AF_INET6
+ case AF_INET6:
+#endif
+ break;
+ default:
return 0;
+ }
switch (ai->ai_socktype) {
case SOCK_RAW:
@@ -905,3 +907,70 @@ find_afd(af)
}
return NULL;
}
+
+#ifdef AI_ADDRCONFIG
+/*
+ * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend
+ * will take care of it.
+ * the semantics of AI_ADDRCONFIG is not defined well. we are not sure
+ * if the code is right or not.
+ */
+static int
+addrconfig(pai)
+ const struct addrinfo *pai;
+{
+#ifdef USE_GETIPNODEBY
+ return 1;
+#else
+ int s;
+
+ /* XXX errno */
+ s = socket(pai->ai_family, SOCK_DGRAM, 0);
+ if (s < 0)
+ return 0;
+ close(s);
+ return 1;
+#endif
+}
+#endif
+
+#ifdef INET6
+/* convert a string to a scope identifier. XXX: IPv6 specific */
+static int
+ip6_str2scopeid(scope, sin6)
+ char *scope;
+ struct sockaddr_in6 *sin6;
+{
+ int scopeid;
+ struct in6_addr *a6 = &sin6->sin6_addr;
+ char *ep;
+
+ if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) {
+ /*
+ * We currently assume a one-to-one mapping between links
+ * and interfaces, so we simply use interface indices for
+ * like-local scopes.
+ */
+ scopeid = if_nametoindex(scope);
+ if (scopeid == 0)
+ goto trynumeric;
+ return(scopeid);
+ }
+
+ /* still unclear about literal, allow numeric only - placeholder */
+ if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
+ goto trynumeric;
+ if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
+ goto trynumeric;
+ else
+ goto trynumeric; /* global */
+
+ /* try to convert to a numeric id as a last resort */
+ trynumeric:
+ scopeid = (int)strtoul(scope, &ep, 10);
+ if (*ep == '\0')
+ return scopeid;
+ else
+ return -1;
+}
+#endif