diff options
author | ume <ume@FreeBSD.org> | 2005-04-25 17:36:28 +0000 |
---|---|---|
committer | ume <ume@FreeBSD.org> | 2005-04-25 17:36:28 +0000 |
commit | c5b4993c85e0d43326c139c8546a7620e37a6a41 (patch) | |
tree | 7354a3ee865b61c107c10dbbe961ea7801f8f5f8 /lib/libc/net/gethostnamadr.c | |
parent | 1c27d898b4c751a3eaf3754898bbfefa174dec6a (diff) | |
download | FreeBSD-src-c5b4993c85e0d43326c139c8546a7620e37a6a41.zip FreeBSD-src-c5b4993c85e0d43326c139c8546a7620e37a6a41.tar.gz |
ensure parsing numeric address before any host query.
Inspired by: NetBSD
Diffstat (limited to 'lib/libc/net/gethostnamadr.c')
-rw-r--r-- | lib/libc/net/gethostnamadr.c | 139 |
1 files changed, 126 insertions, 13 deletions
diff --git a/lib/libc/net/gethostnamadr.c b/lib/libc/net/gethostnamadr.c index f5c3382..2409502 100644 --- a/lib/libc/net/gethostnamadr.c +++ b/lib/libc/net/gethostnamadr.c @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include <netdb.h> #include <stdio.h> #include <ctype.h> +#include <errno.h> #include <string.h> #include <stdarg.h> #include <nsswitch.h> @@ -47,9 +48,12 @@ extern int _nis_gethostbyname(void *, void *, va_list); extern int _ht_gethostbyaddr(void *, void *, va_list); extern int _dns_gethostbyaddr(void *, void *, va_list); extern int _nis_gethostbyaddr(void *, void *, va_list); +extern const char *_res_hostalias(const char *, char *, size_t); + +static struct hostent *gethostbyname_internal(const char *, int); /* Host lookup order if nsswitch.conf is broken or nonexistant */ -static const ns_src default_src[] = { +static const ns_src default_src[] = { { NSSRC_FILES, NS_SUCCESS }, { NSSRC_DNS, NS_SUCCESS }, { 0 } @@ -62,31 +66,140 @@ gethostbyname(const char *name) if ((_res.options & RES_INIT) == 0 && res_init() == -1) { h_errno = NETDB_INTERNAL; - return (NULL); + return NULL; + } + if (_res.options & RES_USE_INET6) { + hp = gethostbyname_internal(name, AF_INET6); + if (hp) + return hp; } - if (_res.options & RES_USE_INET6) { /* XXX */ - hp = gethostbyname2(name, AF_INET6); /* XXX */ - if (hp) /* XXX */ - return (hp); /* XXX */ - } /* XXX */ - return (gethostbyname2(name, AF_INET)); + return gethostbyname_internal(name, AF_INET); } struct hostent * -gethostbyname2(const char *name, int type) +gethostbyname2(const char *name, int af) +{ + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; + return NULL; + } + return gethostbyname_internal(name, af); +} + +static struct hostent * +gethostbyname_internal(const char *name, int af) { + const char *cp; + char *bp, *ep; struct hostent *hp = 0; - int rval; + int size, rval; + char abuf[MAXDNAME]; + static struct hostent host; + static char *h_addr_ptrs[2]; + static char *host_aliases[1]; + static char hostbuf[MAXDNAME + IN6ADDRSZ + sizeof(uint32_t)]; + static uint32_t host_addr[4]; /* IPv4 or IPv6 */ static const ns_dtab dtab[] = { NS_FILES_CB(_ht_gethostbyname, NULL) { NSSRC_DNS, _dns_gethostbyname, NULL }, NS_NIS_CB(_nis_gethostbyname, NULL) /* force -DHESIOD */ { 0 } - }; - + }; + + switch (af) { + case AF_INET: + size = INADDRSZ; + break; + case AF_INET6: + size = IN6ADDRSZ; + break; + default: + h_errno = NETDB_INTERNAL; + errno = EAFNOSUPPORT; + return NULL; + } + + host.h_addrtype = af; + host.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(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, host_addr) <= 0) { + h_errno = HOST_NOT_FOUND; + return NULL; + } + strncpy(hostbuf, name, MAXDNAME); + hostbuf[MAXDNAME] = '\0'; + bp = hostbuf + MAXDNAME; + ep = hostbuf + sizeof hostbuf; + host.h_name = hostbuf; + host.h_aliases = host_aliases; + host_aliases[0] = NULL; + h_addr_ptrs[0] = (char *)host_addr; + h_addr_ptrs[1] = NULL; + host.h_addr_list = h_addr_ptrs; + if (_res.options & RES_USE_INET6) + _map_v4v6_hostent(&host, &bp, &ep); + h_errno = NETDB_SUCCESS; + return &host; + } + 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, host_addr) <= 0) { + h_errno = HOST_NOT_FOUND; + return NULL; + } + strncpy(hostbuf, name, MAXDNAME); + hostbuf[MAXDNAME] = '\0'; + host.h_name = hostbuf; + host.h_aliases = host_aliases; + host_aliases[0] = NULL; + h_addr_ptrs[0] = (char *)host_addr; + h_addr_ptrs[1] = NULL; + host.h_addr_list = h_addr_ptrs; + h_errno = NETDB_SUCCESS; + return &host; + } + if (!isxdigit((u_char)*cp) && *cp != ':' && *cp != '.') + break; + } + rval = _nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "gethostbyname", - default_src, name, type); + default_src, name, af); if (rval != NS_SUCCESS) return NULL; |