summaryrefslogtreecommitdiffstats
path: root/lib/libc/net/gethostnamadr.c
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2006-04-15 16:20:27 +0000
committerume <ume@FreeBSD.org>2006-04-15 16:20:27 +0000
commitb6bb84cf9e6c9d871a17bcf962cf63180af70e95 (patch)
tree7f8977d8ba3a31812862992c940fc48d67e9a71c /lib/libc/net/gethostnamadr.c
parent65a640e4f05dfa0b6ed9cf426628b7a1106b767b (diff)
downloadFreeBSD-src-b6bb84cf9e6c9d871a17bcf962cf63180af70e95.zip
FreeBSD-src-b6bb84cf9e6c9d871a17bcf962cf63180af70e95.tar.gz
- make reentrant version of netdb functions glibc style API, and
expose them to outside of libc. - make netdb functions NSS friendly. Reviewed by: arch@ and current@ (no objection)
Diffstat (limited to 'lib/libc/net/gethostnamadr.c')
-rw-r--r--lib/libc/net/gethostnamadr.c411
1 files changed, 225 insertions, 186 deletions
diff --git a/lib/libc/net/gethostnamadr.c b/lib/libc/net/gethostnamadr.c
index b641f73..c8867e5 100644
--- a/lib/libc/net/gethostnamadr.c
+++ b/lib/libc/net/gethostnamadr.c
@@ -52,8 +52,8 @@ extern int _ht_gethostbyaddr(void *, void *, va_list);
extern int _dns_gethostbyaddr(void *, void *, va_list);
extern int _nis_gethostbyaddr(void *, void *, va_list);
-static int gethostbyname_internal(const char *, int, struct hostent *,
- struct hostent_data *);
+static int gethostbyname_internal(const char *, int, struct hostent *, char *,
+ size_t, struct hostent **, int *, res_state);
/* Host lookup order if nsswitch.conf is broken or nonexistant */
static const ns_src default_src[] = {
@@ -62,87 +62,190 @@ static const ns_src default_src[] = {
{ 0 }
};
-static struct hostdata hostdata;
-static thread_key_t hostdata_key;
-static once_t hostdata_init_once = ONCE_INITIALIZER;
-static int hostdata_thr_keycreated = 0;
+NETDB_THREAD_ALLOC(hostent)
+NETDB_THREAD_ALLOC(hostent_data)
+NETDB_THREAD_ALLOC(hostdata)
static void
-hostdata_free(void *ptr)
+hostent_free(void *ptr)
+{
+ free(ptr);
+}
+
+static void
+hostent_data_free(void *ptr)
{
- struct hostdata *hd = ptr;
+ struct hostent_data *hed = ptr;
- if (hd == NULL)
+ if (hed == NULL)
return;
- hd->data.stayopen = 0;
- _endhosthtent(&hd->data);
- free(hd);
+ hed->stayopen = 0;
+ _endhosthtent(hed);
+ free(hed);
}
static void
-hostdata_keycreate(void)
+hostdata_free(void *ptr)
{
- hostdata_thr_keycreated =
- (thr_keycreate(&hostdata_key, hostdata_free) == 0);
+ free(ptr);
}
-struct hostdata *
-__hostdata_init(void)
+int
+__copy_hostent(struct hostent *he, struct hostent *hptr, char *buf,
+ size_t buflen)
{
- struct hostdata *hd;
+ char *cp;
+ char **ptr;
+ int i, n;
+ int nptr, len;
+
+ /* Find out the amount of space required to store the answer. */
+ nptr = 2; /* NULL ptrs */
+ len = (char *)ALIGN(buf) - buf;
+ for (i = 0; he->h_addr_list[i]; i++, nptr++) {
+ len += he->h_length;
+ }
+ for (i = 0; he->h_aliases[i]; i++, nptr++) {
+ len += strlen(he->h_aliases[i]) + 1;
+ }
+ len += strlen(he->h_name) + 1;
+ len += nptr * sizeof(char*);
+
+ if (len > buflen) {
+ errno = ERANGE;
+ return (-1);
+ }
- if (thr_main() != 0)
- return &hostdata;
- if (thr_once(&hostdata_init_once, hostdata_keycreate) != 0 ||
- !hostdata_thr_keycreated)
- return NULL;
- if ((hd = thr_getspecific(hostdata_key)) != NULL)
- return hd;
- if ((hd = calloc(1, sizeof(*hd))) == NULL)
- return NULL;
- if (thr_setspecific(hostdata_key, hd) == 0)
- return hd;
- free(hd);
- return NULL;
+ /* copy address size and type */
+ hptr->h_addrtype = he->h_addrtype;
+ n = hptr->h_length = he->h_length;
+
+ ptr = (char **)ALIGN(buf);
+ cp = (char *)ALIGN(buf) + nptr * sizeof(char *);
+
+ /* copy address list */
+ hptr->h_addr_list = ptr;
+ for (i = 0; he->h_addr_list[i]; i++ , ptr++) {
+ memcpy(cp, he->h_addr_list[i], n);
+ hptr->h_addr_list[i] = cp;
+ cp += n;
+ }
+ hptr->h_addr_list[i] = NULL;
+ ptr++;
+
+ /* copy official name */
+ n = strlen(he->h_name) + 1;
+ strcpy(cp, he->h_name);
+ hptr->h_name = cp;
+ cp += n;
+
+ /* copy aliases */
+ hptr->h_aliases = ptr;
+ for (i = 0 ; he->h_aliases[i]; i++) {
+ n = strlen(he->h_aliases[i]) + 1;
+ strcpy(cp, he->h_aliases[i]);
+ hptr->h_aliases[i] = cp;
+ cp += n;
+ }
+ hptr->h_aliases[i] = NULL;
+
+ return (0);
+}
+
+static int
+fakeaddr(const char *name, int af, struct hostent *hp, char *buf,
+size_t buflen, res_state statp)
+{
+ struct hostent_data *hed;
+ struct hostent he;
+
+ if ((hed = __hostent_data_init()) == NULL) {
+ errno = ENOMEM;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ if ((af != AF_INET ||
+ inet_aton(name, (struct in_addr *)hed->host_addr) != 1) &&
+ inet_pton(af, name, hed->host_addr) != 1) {
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+ return (-1);
+ }
+ strncpy(hed->hostbuf, name, MAXDNAME);
+ hed->hostbuf[MAXDNAME] = '\0';
+ if (af == AF_INET && (statp->options & RES_USE_INET6) != 0U) {
+ _map_v4v6_address((char *)hed->host_addr,
+ (char *)hed->host_addr);
+ af = AF_INET6;
+ }
+ he.h_addrtype = af;
+ switch(af) {
+ case AF_INET:
+ he.h_length = NS_INADDRSZ;
+ break;
+ case AF_INET6:
+ he.h_length = NS_IN6ADDRSZ;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
+ }
+ he.h_name = hed->hostbuf;
+ he.h_aliases = hed->host_aliases;
+ hed->host_aliases[0] = NULL;
+ hed->h_addr_ptrs[0] = (char *)hed->host_addr;
+ hed->h_addr_ptrs[1] = NULL;
+ he.h_addr_list = hed->h_addr_ptrs;
+ RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
+ return (__copy_hostent(&he, hp, buf, buflen));
}
int
-gethostbyname_r(const char *name, struct hostent *he, struct hostent_data *hed)
+gethostbyname_r(const char *name, struct hostent *he, char *buffer,
+ size_t buflen, struct hostent **result, int *h_errnop)
{
- int error;
+ res_state statp;
- hed->res = __res_state();
- if ((hed->res->options & RES_INIT) == 0 && res_ninit(hed->res) == -1) {
- RES_SET_H_ERRNO(hed->res, NETDB_INTERNAL);
- return -1;
+ statp = __res_state();
+ if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
}
- if (hed->res->options & RES_USE_INET6) {
- error = gethostbyname_internal(name, AF_INET6, he, hed);
- if (error == 0)
- return 0;
+ if (statp->options & RES_USE_INET6) {
+ if (fakeaddr(name, AF_INET, he, buffer, buflen, statp) == 0) {
+ *result = he;
+ return (0);
+ }
+ if (gethostbyname_internal(name, AF_INET6, he, buffer, buflen,
+ result, h_errnop, statp) == 0)
+ return (0);
}
- return gethostbyname_internal(name, AF_INET, he, hed);
+ return (gethostbyname_internal(name, AF_INET, he, buffer, buflen,
+ result, h_errnop, statp));
}
int
-gethostbyname2_r(const char *name, int af, struct hostent *he,
- struct hostent_data *hed)
+gethostbyname2_r(const char *name, int af, struct hostent *he, char *buffer,
+ size_t buflen, struct hostent **result, int *h_errnop)
{
- hed->res = __res_state();
- if ((hed->res->options & RES_INIT) == 0 && res_ninit(hed->res) == -1) {
- RES_SET_H_ERRNO(hed->res, NETDB_INTERNAL);
- return -1;
+ res_state statp;
+
+ statp = __res_state();
+ if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ return (-1);
}
- return gethostbyname_internal(name, af, he, hed);
+ return (gethostbyname_internal(name, af, he, buffer, buflen, result,
+ h_errnop, statp));
}
-static int
-gethostbyname_internal(const char *name, int af, struct hostent *he,
- struct hostent_data *hed)
+int
+gethostbyname_internal(const char *name, int af, struct hostent *hp, char *buf,
+ size_t buflen, struct hostent **result, int *h_errnop, res_state statp)
{
const char *cp;
- char *bp, *ep;
- int size, rval;
+ int rval, ret_errno;
char abuf[MAXDNAME];
static const ns_dtab dtab[] = {
@@ -154,111 +257,45 @@ gethostbyname_internal(const char *name, int af, struct hostent *he,
switch (af) {
case AF_INET:
- size = INADDRSZ;
- break;
case AF_INET6:
- size = IN6ADDRSZ;
break;
default:
- RES_SET_H_ERRNO(hed->res, NETDB_INTERNAL);
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
errno = EAFNOSUPPORT;
- return -1;
+ return (-1);
}
- he->h_addrtype = af;
- he->h_length = size;
-
/*
* if there aren't any dots, it could be a user-level alias.
* this is also done in res_query() since we are not the only
* function that looks up host names.
*/
if (!strchr(name, '.') &&
- (cp = res_hostalias(hed->res, name, abuf, sizeof abuf)))
+ (cp = res_hostalias(statp, name, abuf, sizeof abuf)))
name = cp;
- /*
- * disallow names consisting only of digits/dots, unless
- * they end in a dot.
- */
- if (isdigit((u_char)name[0]))
- for (cp = name;; ++cp) {
- if (!*cp) {
- if (*--cp == '.')
- break;
- /*
- * All-numeric, no dot at the end.
- * Fake up a hostent as if we'd actually
- * done a lookup.
- */
- if (inet_pton(af, name, hed->host_addr) <= 0) {
- RES_SET_H_ERRNO(hed->res,
- HOST_NOT_FOUND);
- return -1;
- }
- strncpy(hed->hostbuf, name, MAXDNAME);
- hed->hostbuf[MAXDNAME] = '\0';
- bp = hed->hostbuf + MAXDNAME + 1;
- ep = hed->hostbuf + sizeof hed->hostbuf;
- he->h_name = hed->hostbuf;
- he->h_aliases = hed->host_aliases;
- hed->host_aliases[0] = NULL;
- hed->h_addr_ptrs[0] = (char *)hed->host_addr;
- hed->h_addr_ptrs[1] = NULL;
- he->h_addr_list = hed->h_addr_ptrs;
- if (hed->res->options & RES_USE_INET6)
- _map_v4v6_hostent(he, &bp, ep);
- RES_SET_H_ERRNO(hed->res, NETDB_SUCCESS);
- return 0;
- }
- if (!isdigit((u_char)*cp) && *cp != '.')
- break;
- }
- if ((isxdigit((u_char)name[0]) && strchr(name, ':') != NULL) ||
- name[0] == ':')
- for (cp = name;; ++cp) {
- if (!*cp) {
- if (*--cp == '.')
- break;
- /*
- * All-IPv6-legal, no dot at the end.
- * Fake up a hostent as if we'd actually
- * done a lookup.
- */
- if (inet_pton(af, name, hed->host_addr) <= 0) {
- RES_SET_H_ERRNO(hed->res,
- HOST_NOT_FOUND);
- return -1;
- }
- strncpy(hed->hostbuf, name, MAXDNAME);
- hed->hostbuf[MAXDNAME] = '\0';
- he->h_name = hed->hostbuf;
- he->h_aliases = hed->host_aliases;
- hed->host_aliases[0] = NULL;
- hed->h_addr_ptrs[0] = (char *)hed->host_addr;
- hed->h_addr_ptrs[1] = NULL;
- he->h_addr_list = hed->h_addr_ptrs;
- RES_SET_H_ERRNO(hed->res, NETDB_SUCCESS);
- return 0;
- }
- if (!isxdigit((u_char)*cp) && *cp != ':' && *cp != '.')
- break;
- }
+ if (fakeaddr(name, af, hp, buf, buflen, statp) == 0) {
+ *result = hp;
+ return (0);
+ }
- rval = _nsdispatch(NULL, dtab, NSDB_HOSTS, "gethostbyname",
- default_src, name, af, he, hed);
+ rval = _nsdispatch((void *)result, dtab, NSDB_HOSTS,
+ "gethostbyname2_r", default_src, name, af, hp, buf, buflen,
+ &ret_errno, h_errnop);
- return (rval == NS_SUCCESS) ? 0 : -1;
+ return ((rval == NS_SUCCESS) ? 0 : -1);
}
int
-gethostbyaddr_r(const char *addr, int len, int af, struct hostent *he,
- struct hostent_data *hed)
+gethostbyaddr_r(const char *addr, int len, int af, struct hostent *hp,
+ char *buf, size_t buflen, struct hostent **result, int *h_errnop)
{
const u_char *uaddr = (const u_char *)addr;
const struct in6_addr *addr6;
socklen_t size;
- int rval;
+ int rval, ret_errno;
+ res_state statp;
static const ns_dtab dtab[] = {
NS_FILES_CB(_ht_gethostbyaddr, NULL)
@@ -267,116 +304,118 @@ gethostbyaddr_r(const char *addr, int len, int af, struct hostent *he,
{ 0 }
};
- hed->res = __res_state();
- if ((hed->res->options & RES_INIT) == 0 && res_ninit(hed->res) == -1) {
- RES_SET_H_ERRNO(hed->res, NETDB_INTERNAL);
- return -1;
+ statp = __res_state();
+ if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (-1);
}
- if (af == AF_INET6 && len == IN6ADDRSZ) {
+ if (af == AF_INET6 && len == NS_IN6ADDRSZ) {
addr6 = (const struct in6_addr *)(const void *)uaddr;
if (IN6_IS_ADDR_LINKLOCAL(addr6)) {
- RES_SET_H_ERRNO(hed->res, HOST_NOT_FOUND);
- return -1;
+ RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+ *h_errnop = statp->res_h_errno;
+ return (-1);
}
if (IN6_IS_ADDR_V4MAPPED(addr6) ||
IN6_IS_ADDR_V4COMPAT(addr6)) {
/* Unmap. */
- uaddr += IN6ADDRSZ - INADDRSZ;
+ uaddr += NS_IN6ADDRSZ - NS_INADDRSZ;
af = AF_INET;
- len = INADDRSZ;
+ len = NS_INADDRSZ;
}
}
switch (af) {
case AF_INET:
- size = INADDRSZ;
+ size = NS_INADDRSZ;
break;
case AF_INET6:
- size = IN6ADDRSZ;
+ size = NS_IN6ADDRSZ;
break;
default:
errno = EAFNOSUPPORT;
- RES_SET_H_ERRNO(hed->res, NETDB_INTERNAL);
- return -1;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (-1);
}
if (size != len) {
errno = EINVAL;
- RES_SET_H_ERRNO(hed->res, NETDB_INTERNAL);
- return -1;
+ RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
+ *h_errnop = statp->res_h_errno;
+ return (-1);
}
- rval = _nsdispatch(NULL, dtab, NSDB_HOSTS, "gethostbyaddr",
- default_src, uaddr, len, af, he, hed);
-
- return (rval == NS_SUCCESS) ? 0 : -1;
-}
-
-void
-sethostent_r(int stayopen, struct hostent_data *hed)
-{
- _sethosthtent(stayopen, hed);
- _sethostdnsent(stayopen);
-}
+ rval = _nsdispatch((void *)result, dtab, NSDB_HOSTS,
+ "gethostbyaddr_r", default_src, uaddr, len, af, hp, buf, buflen,
+ &ret_errno, h_errnop);
-void
-endhostent_r(struct hostent_data *hed)
-{
- _endhosthtent(hed);
- _endhostdnsent();
+ return ((rval == NS_SUCCESS) ? 0 : -1);
}
struct hostent *
gethostbyname(const char *name)
{
struct hostdata *hd;
+ struct hostent *rval;
+ int ret_h_errno;
if ((hd = __hostdata_init()) == NULL)
- return NULL;
- if (gethostbyname_r(name, &hd->host, &hd->data) != 0)
- return NULL;
- return &hd->host;
+ return (NULL);
+ if (gethostbyname_r(name, &hd->host, hd->data, sizeof(hd->data), &rval,
+ &ret_h_errno) != 0)
+ return (NULL);
+ return (rval);
}
struct hostent *
gethostbyname2(const char *name, int af)
{
struct hostdata *hd;
+ struct hostent *rval;
+ int ret_h_errno;
if ((hd = __hostdata_init()) == NULL)
- return NULL;
- if (gethostbyname2_r(name, af, &hd->host, &hd->data) != 0)
- return NULL;
- return &hd->host;
+ return (NULL);
+ if (gethostbyname2_r(name, af, &hd->host, hd->data, sizeof(hd->data),
+ &rval, &ret_h_errno) != 0)
+ return (NULL);
+ return (rval);
}
struct hostent *
gethostbyaddr(const char *addr, int len, int af)
{
struct hostdata *hd;
+ struct hostent *rval;
+ int ret_h_errno;
if ((hd = __hostdata_init()) == NULL)
- return NULL;
- if (gethostbyaddr_r(addr, len, af, &hd->host, &hd->data) != 0)
- return NULL;
- return &hd->host;
+ return (NULL);
+ if (gethostbyaddr_r(addr, len, af, &hd->host, hd->data,
+ sizeof(hd->data), &rval, &ret_h_errno) != 0)
+ return (NULL);
+ return (rval);
}
void
sethostent(int stayopen)
{
- struct hostdata *hd;
+ struct hostent_data *hed;
- if ((hd = __hostdata_init()) == NULL)
+ if ((hed = __hostent_data_init()) == NULL)
return;
- sethostent_r(stayopen, &hd->data);
+ _sethosthtent(stayopen, hed);
+ _sethostdnsent(stayopen);
}
void
endhostent(void)
{
- struct hostdata *hd;
+ struct hostent_data *hed;
- if ((hd = __hostdata_init()) == NULL)
+ if ((hed = __hostent_data_init()) == NULL)
return;
- endhostent_r(&hd->data);
+ _endhosthtent(hed);
+ _endhostdnsent();
}
OpenPOWER on IntegriCloud