diff options
author | ume <ume@FreeBSD.org> | 2006-04-15 16:20:27 +0000 |
---|---|---|
committer | ume <ume@FreeBSD.org> | 2006-04-15 16:20:27 +0000 |
commit | b6bb84cf9e6c9d871a17bcf962cf63180af70e95 (patch) | |
tree | 7f8977d8ba3a31812862992c940fc48d67e9a71c /lib/libc/net/gethostnamadr.c | |
parent | 65a640e4f05dfa0b6ed9cf426628b7a1106b767b (diff) | |
download | FreeBSD-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.c | 411 |
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(); } |