diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | a27d2baa0c1a2ec70f47ea9199b1dd6762c8a349 (patch) | |
tree | defd1cc07d16ad2f3b21154114e092d11c94c5bb /libc/netbsd | |
download | bionic-a27d2baa0c1a2ec70f47ea9199b1dd6762c8a349.zip bionic-a27d2baa0c1a2ec70f47ea9199b1dd6762c8a349.tar.gz bionic-a27d2baa0c1a2ec70f47ea9199b1dd6762c8a349.tar.bz2 |
Initial Contributionandroid-1.0
Diffstat (limited to 'libc/netbsd')
41 files changed, 14893 insertions, 0 deletions
diff --git a/libc/netbsd/gethnamaddr.c b/libc/netbsd/gethnamaddr.c new file mode 100644 index 0000000..e6f919e --- /dev/null +++ b/libc/netbsd/gethnamaddr.c @@ -0,0 +1,1235 @@ +/* $NetBSD: gethnamaddr.c,v 1.70 2006/03/22 00:03:51 christos Exp $ */ + +/* + * ++Copyright++ 1985, 1988, 1993 + * - + * Copyright (c) 1985, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#include <sys/cdefs.h> +#include <sys/types.h> + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "arpa_nameser.h" +#include "resolv_private.h" +#include "resolv_cache.h" +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include <stdarg.h> +#include <stdio.h> +#include <syslog.h> + +#ifndef LOG_AUTH +# define LOG_AUTH 0 +#endif + +#define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */ + +#include "nsswitch.h" +#include <stdlib.h> +#include <string.h> + +static const char const AskedForGot[] = + "gethostby*.getanswer: asked for \"%s\", got \"%s\""; + +#define MAXPACKET (64*1024) + +typedef union { + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf; + +typedef union { + int32_t al; + char ac; +} align; + +#ifdef DEBUG +static void dprintf(const char *, res_state, ...) + __attribute__((__format__(__printf__, 1, 3))); +#endif +static struct hostent *getanswer(const querybuf *, int, const char *, int, + res_state); +static void map_v4v6_address(const char *, char *); +static void map_v4v6_hostent(struct hostent *, char **, char *); +static void addrsort(char **, int, res_state); + +void _sethtent(int); +void _endhtent(void); +struct hostent *_gethtent(void); +void ht_sethostent(int); +void ht_endhostent(void); +struct hostent *ht_gethostbyname(char *); +struct hostent *ht_gethostbyaddr(const char *, int, int); +void dns_service(void); +#undef dn_skipname +int dn_skipname(const u_char *, const u_char *); +int _gethtbyaddr(void *, void *, va_list); +int _gethtbyname(void *, void *, va_list); +struct hostent *_gethtbyname2(const char *, int); +int _dns_gethtbyaddr(void *, void *, va_list); +int _dns_gethtbyname(void *, void *, va_list); + +static struct hostent *gethostbyname_internal(const char *, int, res_state); + +static const ns_src default_dns_files[] = { + { NSSRC_FILES, NS_SUCCESS }, + { NSSRC_DNS, NS_SUCCESS }, + { 0, 0 } +}; + + +#ifdef DEBUG +static void +dprintf(const char *msg, res_state res, ...) +{ + assert(msg != NULL); + + if (res->options & RES_DEBUG) { + int save = errno; + va_list ap; + + va_start (ap, res); + vprintf(msg, ap); + va_end (ap); + + errno = save; + } +} +#else +# define dprintf(msg, res, num) ((void)0) /*nada*/ +#endif + +#define BOUNDED_INCR(x) \ + do { \ + cp += (x); \ + if (cp > eom) { \ + h_errno = NO_RECOVERY; \ + return NULL; \ + } \ + } while (/*CONSTCOND*/0) + +#define BOUNDS_CHECK(ptr, count) \ + do { \ + if ((ptr) + (count) > eom) { \ + h_errno = NO_RECOVERY; \ + return NULL; \ + } \ + } while (/*CONSTCOND*/0) + +static struct hostent * +getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, + res_state res) +{ + const HEADER *hp; + const u_char *cp; + int n; + const u_char *eom, *erdata; + char *bp, **ap, **hap, *ep; + int type, class, ancount, qdcount; + int haveanswer, had_error; + int toobig = 0; + char tbuf[MAXDNAME]; + const char *tname; + int (*name_ok)(const char *); + res_static rs = __res_get_static(); + + assert(answer != NULL); + assert(qname != NULL); + + tname = qname; + rs->host.h_name = NULL; + eom = answer->buf + anslen; + switch (qtype) { + case T_A: + case T_AAAA: + name_ok = res_hnok; + break; + case T_PTR: + name_ok = res_dnok; + break; + default: + return NULL; /* XXX should be abort(); */ + } + /* + * find first satisfactory answer + */ + hp = &answer->hdr; + ancount = ntohs(hp->ancount); + qdcount = ntohs(hp->qdcount); + bp = rs->hostbuf; + ep = rs->hostbuf + sizeof rs->hostbuf; + cp = answer->buf; + BOUNDED_INCR(HFIXEDSZ); + if (qdcount != 1) { + h_errno = NO_RECOVERY; + return NULL; + } + n = dn_expand(answer->buf, eom, cp, bp, ep - bp); + if ((n < 0) || !(*name_ok)(bp)) { + h_errno = NO_RECOVERY; + return NULL; + } + BOUNDED_INCR(n + QFIXEDSZ); + if (qtype == T_A || qtype == T_AAAA) { + /* res_send() has already verified that the query name is the + * same as the one we sent; this just gets the expanded name + * (i.e., with the succeeding search-domain tacked on). + */ + n = strlen(bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) { + h_errno = NO_RECOVERY; + return NULL; + } + rs->host.h_name = bp; + bp += n; + /* The qname can be abbreviated, but h_name is now absolute. */ + qname = rs->host.h_name; + } + ap = rs->host_aliases; + *ap = NULL; + rs->host.h_aliases = rs->host_aliases; + hap = rs->h_addr_ptrs; + *hap = NULL; + rs->host.h_addr_list = rs->h_addr_ptrs; + haveanswer = 0; + had_error = 0; + while (ancount-- > 0 && cp < eom && !had_error) { + n = dn_expand(answer->buf, eom, cp, bp, ep - bp); + if ((n < 0) || !(*name_ok)(bp)) { + had_error++; + continue; + } + cp += n; /* name */ + BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); + type = _getshort(cp); + cp += INT16SZ; /* type */ + class = _getshort(cp); + cp += INT16SZ + INT32SZ; /* class, TTL */ + n = _getshort(cp); + cp += INT16SZ; /* len */ + BOUNDS_CHECK(cp, n); + erdata = cp + n; + if (class != C_IN) { + /* XXX - debug? syslog? */ + cp += n; + continue; /* XXX - had_error++ ? */ + } + if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { + if (ap >= &rs->host_aliases[MAXALIASES-1]) + continue; + n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); + if ((n < 0) || !(*name_ok)(tbuf)) { + had_error++; + continue; + } + cp += n; + if (cp != erdata) { + h_errno = NO_RECOVERY; + return NULL; + } + /* Store alias. */ + *ap++ = bp; + n = strlen(bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) { + had_error++; + continue; + } + bp += n; + /* Get canonical name. */ + n = strlen(tbuf) + 1; /* for the \0 */ + if (n > ep - bp || n >= MAXHOSTNAMELEN) { + had_error++; + continue; + } + strlcpy(bp, tbuf, (size_t)(ep - bp)); + rs->host.h_name = bp; + bp += n; + continue; + } + if (qtype == T_PTR && type == T_CNAME) { + n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); + if (n < 0 || !res_dnok(tbuf)) { + had_error++; + continue; + } + cp += n; + if (cp != erdata) { + h_errno = NO_RECOVERY; + return NULL; + } + /* Get canonical name. */ + n = strlen(tbuf) + 1; /* for the \0 */ + if (n > ep - bp || n >= MAXHOSTNAMELEN) { + had_error++; + continue; + } + strlcpy(bp, tbuf, (size_t)(ep - bp)); + tname = bp; + bp += n; + continue; + } + if (type != qtype) { + if (type != T_KEY && type != T_SIG) + syslog(LOG_NOTICE|LOG_AUTH, + "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", + qname, p_class(C_IN), p_type(qtype), + p_type(type)); + cp += n; + continue; /* XXX - had_error++ ? */ + } + switch (type) { + case T_PTR: + if (strcasecmp(tname, bp) != 0) { + syslog(LOG_NOTICE|LOG_AUTH, + AskedForGot, qname, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } + n = dn_expand(answer->buf, eom, cp, bp, ep - bp); + if ((n < 0) || !res_hnok(bp)) { + had_error++; + break; + } +#if MULTI_PTRS_ARE_ALIASES + cp += n; + if (cp != erdata) { + h_errno = NO_RECOVERY; + return NULL; + } + if (!haveanswer) + rs->host.h_name = bp; + else if (ap < &rs->host_aliases[MAXALIASES-1]) + *ap++ = bp; + else + n = -1; + if (n != -1) { + n = strlen(bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) { + had_error++; + break; + } + bp += n; + } + break; +#else + rs->host.h_name = bp; + if (res->options & RES_USE_INET6) { + n = strlen(bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) { + had_error++; + break; + } + bp += n; + map_v4v6_hostent(&rs->host, &bp, ep); + } + h_errno = NETDB_SUCCESS; + return &rs->host; +#endif + case T_A: + case T_AAAA: + if (strcasecmp(rs->host.h_name, bp) != 0) { + syslog(LOG_NOTICE|LOG_AUTH, + AskedForGot, rs->host.h_name, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } + if (n != rs->host.h_length) { + cp += n; + continue; + } + if (type == T_AAAA) { + struct in6_addr in6; + memcpy(&in6, cp, IN6ADDRSZ); + if (IN6_IS_ADDR_V4MAPPED(&in6)) { + cp += n; + continue; + } + } + if (!haveanswer) { + int nn; + + rs->host.h_name = bp; + nn = strlen(bp) + 1; /* for the \0 */ + bp += nn; + } + + bp += sizeof(align) - + (size_t)((u_long)bp % sizeof(align)); + + if (bp + n >= &rs->hostbuf[sizeof rs->hostbuf]) { + dprintf("size (%d) too big\n", res, n); + had_error++; + continue; + } + if (hap >= &rs->h_addr_ptrs[MAXADDRS-1]) { + if (!toobig++) + dprintf("Too many addresses (%d)\n", + res, MAXADDRS); + cp += n; + continue; + } + (void)memcpy(*hap++ = bp, cp, (size_t)n); + bp += n; + cp += n; + if (cp != erdata) { + h_errno = NO_RECOVERY; + return NULL; + } + break; + default: + abort(); + } + if (!had_error) + haveanswer++; + } + if (haveanswer) { + *ap = NULL; + *hap = NULL; + /* + * Note: we sort even if host can take only one address + * in its return structures - should give it the "best" + * address in that case, not some random one + */ + if (res->nsort && haveanswer > 1 && qtype == T_A) + addrsort(rs->h_addr_ptrs, haveanswer, res); + if (!rs->host.h_name) { + n = strlen(qname) + 1; /* for the \0 */ + if (n > ep - bp || n >= MAXHOSTNAMELEN) + goto no_recovery; + strlcpy(bp, qname, (size_t)(ep - bp)); + rs->host.h_name = bp; + bp += n; + } + if (res->options & RES_USE_INET6) + map_v4v6_hostent(&rs->host, &bp, ep); + h_errno = NETDB_SUCCESS; + return &rs->host; + } + no_recovery: + h_errno = NO_RECOVERY; + return NULL; +} + +int +gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen, + struct hostent**result, int *errorp) +{ + struct hostent *res; + + res = gethostbyname(name); + *errorp = h_errno; + if (res == NULL) { + *result = NULL; + return -1; + } + memcpy(hp, res, sizeof *hp); + *result = hp; + return 0; +} + +struct hostent * +gethostbyname(const char *name) +{ + struct hostent *hp; + res_state res = __res_get_state(); + + if (res == NULL) + return NULL; + + assert(name != NULL); + + if (res->options & RES_USE_INET6) { + hp = gethostbyname_internal(name, AF_INET6, res); + if (hp) { + __res_put_state(res); + return hp; + } + } + hp = gethostbyname_internal(name, AF_INET, res); + __res_put_state(res); + return hp; +} + +struct hostent * +gethostbyname2(const char *name, int af) +{ + struct hostent *hp; + res_state res = __res_get_state(); + + if (res == NULL) + return NULL; + hp = gethostbyname_internal(name, af, res); + __res_put_state(res); + return hp; +} + +static struct hostent * +gethostbyname_internal(const char *name, int af, res_state res) +{ + const char *cp; + char *bp, *ep; + int size; + struct hostent *hp; + struct resolv_cache* cache; + res_static rs = __res_get_static(); + + static const ns_dtab dtab[] = { + NS_FILES_CB(_gethtbyname, NULL) + { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */ + { 0, 0, 0 } + }; + + assert(name != NULL); + + switch (af) { + case AF_INET: + size = INADDRSZ; + break; + case AF_INET6: + size = IN6ADDRSZ; + break; + default: + h_errno = NETDB_INTERNAL; + errno = EAFNOSUPPORT; + return NULL; + } + + rs->host.h_addrtype = af; + rs->host.h_length = size; + + /* + * if there aren't any dots, it could be a user-level alias. + * this is also done in res_nquery() since we are not the only + * function that looks up host names. + */ + if (!strchr(name, '.') && (cp = __hostalias(name))) + 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, + (char *)(void *)rs->host_addr) <= 0) { + h_errno = HOST_NOT_FOUND; + return NULL; + } + strncpy(rs->hostbuf, name, MAXDNAME); + rs->hostbuf[MAXDNAME] = '\0'; + bp = rs->hostbuf + MAXDNAME; + ep = rs->hostbuf + sizeof rs->hostbuf; + rs->host.h_name = rs->hostbuf; + rs->host.h_aliases = rs->host_aliases; + rs->host_aliases[0] = NULL; + rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr; + rs->h_addr_ptrs[1] = NULL; + rs->host.h_addr_list = rs->h_addr_ptrs; + if (res->options & RES_USE_INET6) + map_v4v6_hostent(&rs->host, &bp, ep); + h_errno = NETDB_SUCCESS; + return &rs->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, + (char *)(void *)rs->host_addr) <= 0) { + h_errno = HOST_NOT_FOUND; + return NULL; + } + strncpy(rs->hostbuf, name, MAXDNAME); + rs->hostbuf[MAXDNAME] = '\0'; + bp = rs->hostbuf + MAXDNAME; + ep = rs->hostbuf + sizeof rs->hostbuf; + rs->host.h_name = rs->hostbuf; + rs->host.h_aliases = rs->host_aliases; + rs->host_aliases[0] = NULL; + rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr; + rs->h_addr_ptrs[1] = NULL; + rs->host.h_addr_list = rs->h_addr_ptrs; + h_errno = NETDB_SUCCESS; + return &rs->host; + } + if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.') + break; + } + +#ifdef ANDROID_CHANGES + cache = __get_res_cache(); + if (cache != NULL) { + hp = _resolv_cache_lookup( cache, name, af ); + if (hp == _RESOLV_HOSTENT_NONE) { + h_errno = HOST_NOT_FOUND; + return NULL; + } + if (hp != NULL) { + h_errno = NETDB_SUCCESS; + return hp; + } + } +#endif + + hp = NULL; + h_errno = NETDB_INTERNAL; + if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname", + default_dns_files, name, strlen(name), af) != NS_SUCCESS) { +#ifdef ANDROID_CHANGES + /* cache negative DNS entry */ + if (h_errno == HOST_NOT_FOUND && cache != NULL) + _resolv_cache_add( cache, name, af, _RESOLV_HOSTENT_NONE ); +#endif + return NULL; + } +#ifdef ANDROID_CHANGES + if (cache != NULL) { + _resolv_cache_add( cache, name, af, hp ); + } +#endif + h_errno = NETDB_SUCCESS; + return hp; +} + +struct hostent * +gethostbyaddr(const char *addr, /* XXX should have been def'd as u_char! */ + socklen_t len, int af) +{ + const u_char *uaddr = (const u_char *)addr; + socklen_t size; + struct hostent *hp; + static const ns_dtab dtab[] = { + NS_FILES_CB(_gethtbyaddr, NULL) + { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */ + { 0, 0, 0 } + }; + + assert(addr != NULL); + + if (af == AF_INET6 && len == IN6ADDRSZ && + (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)(const void *)uaddr) || + IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)(const void *)uaddr))) { + h_errno = HOST_NOT_FOUND; + return NULL; + } + if (af == AF_INET6 && len == IN6ADDRSZ && + (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)(const void *)uaddr) || + IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)(const void *)uaddr))) { + /* Unmap. */ + addr += IN6ADDRSZ - INADDRSZ; + uaddr += IN6ADDRSZ - INADDRSZ; + af = AF_INET; + len = INADDRSZ; + } + switch (af) { + case AF_INET: + size = INADDRSZ; + break; + case AF_INET6: + size = IN6ADDRSZ; + break; + default: + errno = EAFNOSUPPORT; + h_errno = NETDB_INTERNAL; + return NULL; + } + if (size != len) { + errno = EINVAL; + h_errno = NETDB_INTERNAL; + return NULL; + } + hp = NULL; + h_errno = NETDB_INTERNAL; + if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr", + default_dns_files, uaddr, len, af) != NS_SUCCESS) + return NULL; + h_errno = NETDB_SUCCESS; + return hp; +} + +void +_sethtent(int f) +{ + res_static rs = __res_get_static(); + if (rs == NULL) return; + if (!rs->hostf) + rs->hostf = fopen(_PATH_HOSTS, "r" ); + else + rewind(rs->hostf); + rs->stayopen = f; +} + +void +_endhtent(void) +{ + res_static rs = __res_get_static(); + if (rs == NULL) return; + + if (rs->hostf && !rs->stayopen) { + (void) fclose(rs->hostf); + rs->hostf = NULL; + } +} + +struct hostent * +_gethtent(void) +{ + char *p; + char *cp, **q; + int af, len; + res_static rs = __res_get_static(); + + if (!rs->hostf && !(rs->hostf = fopen(_PATH_HOSTS, "r" ))) { + h_errno = NETDB_INTERNAL; + return NULL; + } + again: + if (!(p = fgets(rs->hostbuf, sizeof rs->hostbuf, rs->hostf))) { + h_errno = HOST_NOT_FOUND; + return NULL; + } + if (*p == '#') + goto again; + if (!(cp = strpbrk(p, "#\n"))) + goto again; + *cp = '\0'; + if (!(cp = strpbrk(p, " \t"))) + goto again; + *cp++ = '\0'; + if (inet_pton(AF_INET6, p, (char *)(void *)rs->host_addr) > 0) { + af = AF_INET6; + len = IN6ADDRSZ; + } else if (inet_pton(AF_INET, p, (char *)(void *)rs->host_addr) > 0) { + res_state res = __res_get_state(); + if (res == NULL) + return NULL; + if (res->options & RES_USE_INET6) { + map_v4v6_address((char *)(void *)rs->host_addr, + (char *)(void *)rs->host_addr); + af = AF_INET6; + len = IN6ADDRSZ; + } else { + af = AF_INET; + len = INADDRSZ; + } + __res_put_state(res); + } else { + goto again; + } + /* if this is not something we're looking for, skip it. */ + if (rs->host.h_addrtype != 0 && rs->host.h_addrtype != af) + goto again; + if (rs->host.h_length != 0 && rs->host.h_length != len) + goto again; + rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr; + rs->h_addr_ptrs[1] = NULL; + rs->host.h_addr_list = rs->h_addr_ptrs; + rs->host.h_length = len; + rs->host.h_addrtype = af; + while (*cp == ' ' || *cp == '\t') + cp++; + rs->host.h_name = cp; + q = rs->host.h_aliases = rs->host_aliases; + if ((cp = strpbrk(cp, " \t")) != NULL) + *cp++ = '\0'; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &rs->host_aliases[MAXALIASES - 1]) + *q++ = cp; + if ((cp = strpbrk(cp, " \t")) != NULL) + *cp++ = '\0'; + } + *q = NULL; + h_errno = NETDB_SUCCESS; + return &rs->host; +} + +/*ARGSUSED*/ +int +_gethtbyname(void *rv, void *cb_data, va_list ap) +{ + struct hostent *hp; + const char *name; + int af; + + assert(rv != NULL); + + name = va_arg(ap, char *); + /* NOSTRICT skip len */(void)va_arg(ap, int); + af = va_arg(ap, int); + + hp = NULL; +#if 0 + { + res_state res = __res_get_state(); + if (res == NULL) + return NS_NOTFOUND; + if (res->options & RES_USE_INET6) + hp = _gethtbyname2(name, AF_INET6); + if (hp==NULL) + hp = _gethtbyname2(name, AF_INET); + __res_put_state(res); + } +#else + hp = _gethtbyname2(name, af); +#endif + *((struct hostent **)rv) = hp; + if (hp == NULL) { + h_errno = HOST_NOT_FOUND; + return NS_NOTFOUND; + } + return NS_SUCCESS; +} + +struct hostent * +_gethtbyname2(const char *name, int af) +{ + struct hostent *p; + char *tmpbuf, *ptr, **cp; + int num; + size_t len; + res_static rs = __res_get_static(); + + assert(name != NULL); + + _sethtent(rs->stayopen); + ptr = tmpbuf = NULL; + num = 0; + while ((p = _gethtent()) != NULL && num < MAXADDRS) { + if (p->h_addrtype != af) + continue; + if (strcasecmp(p->h_name, name) != 0) { + for (cp = p->h_aliases; *cp != NULL; cp++) + if (strcasecmp(*cp, name) == 0) + break; + if (*cp == NULL) continue; + } + + if (num == 0) { + size_t bufsize; + char *src; + + bufsize = strlen(p->h_name) + 2 + + MAXADDRS * p->h_length + + ALIGNBYTES; + for (cp = p->h_aliases; *cp != NULL; cp++) + bufsize += strlen(*cp) + 1; + + if ((tmpbuf = malloc(bufsize)) == NULL) { + h_errno = NETDB_INTERNAL; + return NULL; + } + + ptr = tmpbuf; + src = p->h_name; + while ((*ptr++ = *src++) != '\0'); + for (cp = p->h_aliases; *cp != NULL; cp++) { + src = *cp; + while ((*ptr++ = *src++) != '\0'); + } + *ptr++ = '\0'; + + ptr = (char *)(void *)ALIGN(ptr); + } + + (void)memcpy(ptr, p->h_addr_list[0], (size_t)p->h_length); + ptr += p->h_length; + num++; + } + _endhtent(); + if (num == 0) return NULL; + + len = ptr - tmpbuf; + if (len > (sizeof(rs->hostbuf) - ALIGNBYTES)) { + free(tmpbuf); + errno = ENOSPC; + h_errno = NETDB_INTERNAL; + return NULL; + } + ptr = memcpy((void *)ALIGN(rs->hostbuf), tmpbuf, len); + free(tmpbuf); + + rs->host.h_name = ptr; + while (*ptr++); + + cp = rs->host_aliases; + while (*ptr) { + *cp++ = ptr; + while (*ptr++); + } + ptr++; + *cp = NULL; + + ptr = (char *)(void *)ALIGN(ptr); + cp = rs->h_addr_ptrs; + while (num--) { + *cp++ = ptr; + ptr += rs->host.h_length; + } + *cp = NULL; + + return &rs->host; +} + +/*ARGSUSED*/ +int +_gethtbyaddr(void *rv, void *cb_data, va_list ap) +{ + struct hostent *p; + const unsigned char *addr; + int len, af; + res_static rs = __res_get_static(); + + assert(rv != NULL); + + addr = va_arg(ap, unsigned char *); + len = va_arg(ap, int); + af = va_arg(ap, int); + + rs->host.h_length = len; + rs->host.h_addrtype = af; + + _sethtent(rs->stayopen); + while ((p = _gethtent()) != NULL) + if (p->h_addrtype == af && !memcmp(p->h_addr, addr, + (size_t)len)) + break; + _endhtent(); + *((struct hostent **)rv) = p; + if (p==NULL) { + h_errno = HOST_NOT_FOUND; + return NS_NOTFOUND; + } + return NS_SUCCESS; +} + +static void +map_v4v6_address(const char *src, char *dst) +{ + u_char *p = (u_char *)dst; + char tmp[INADDRSZ]; + int i; + + assert(src != NULL); + assert(dst != NULL); + + /* Stash a temporary copy so our caller can update in place. */ + (void)memcpy(tmp, src, INADDRSZ); + /* Mark this ipv6 addr as a mapped ipv4. */ + for (i = 0; i < 10; i++) + *p++ = 0x00; + *p++ = 0xff; + *p++ = 0xff; + /* Retrieve the saved copy and we're done. */ + (void)memcpy((void *)p, tmp, INADDRSZ); +} + +static void +map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep) +{ + char **ap; + + assert(hp != NULL); + assert(bpp != NULL); + assert(ep != NULL); + + if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ) + return; + hp->h_addrtype = AF_INET6; + hp->h_length = IN6ADDRSZ; + for (ap = hp->h_addr_list; *ap; ap++) { + int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align)); + + if (ep - *bpp < (i + IN6ADDRSZ)) { + /* Out of memory. Truncate address list here. XXX */ + *ap = NULL; + return; + } + *bpp += i; + map_v4v6_address(*ap, *bpp); + *ap = *bpp; + *bpp += IN6ADDRSZ; + } +} + +static void +addrsort(char **ap, int num, res_state res) +{ + int i, j; + char **p; + short aval[MAXADDRS]; + int needsort = 0; + + assert(ap != NULL); + + p = ap; + for (i = 0; i < num; i++, p++) { + for (j = 0 ; (unsigned)j < res->nsort; j++) + if (res->sort_list[j].addr.s_addr == + (((struct in_addr *)(void *)(*p))->s_addr & + res->sort_list[j].mask)) + break; + aval[i] = j; + if (needsort == 0 && i > 0 && j < aval[i-1]) + needsort = i; + } + if (!needsort) + return; + + while (needsort < num) { + for (j = needsort - 1; j >= 0; j--) { + if (aval[j] > aval[j+1]) { + char *hp; + + i = aval[j]; + aval[j] = aval[j+1]; + aval[j+1] = i; + + hp = ap[j]; + ap[j] = ap[j+1]; + ap[j+1] = hp; + } else + break; + } + needsort++; + } +} + +struct hostent * +gethostent(void) +{ + res_static rs = __res_get_static(); + rs->host.h_addrtype = 0; + rs->host.h_length = 0; + return _gethtent(); +} + +/*ARGSUSED*/ +int +_dns_gethtbyname(void *rv, void *cb_data, va_list ap) +{ + querybuf *buf; + int n, type; + struct hostent *hp; + const char *name; + int af; + res_state res; + + assert(rv != NULL); + + name = va_arg(ap, char *); + /* NOSTRICT skip len */(void)va_arg(ap, int); + af = va_arg(ap, int); + + switch (af) { + case AF_INET: + type = T_A; + break; + case AF_INET6: + type = T_AAAA; + break; + default: + return NS_UNAVAIL; + } + buf = malloc(sizeof(*buf)); + if (buf == NULL) { + h_errno = NETDB_INTERNAL; + return NS_NOTFOUND; + } + res = __res_get_state(); + if (res == NULL) { + free(buf); + return NS_NOTFOUND; + } + n = res_nsearch(res, name, C_IN, type, buf->buf, sizeof(buf->buf)); + if (n < 0) { + free(buf); + dprintf("res_nsearch failed (%d)\n", res, n); + __res_put_state(res); + return NS_NOTFOUND; + } + hp = getanswer(buf, n, name, type, res); + free(buf); + __res_put_state(res); + if (hp == NULL) + switch (h_errno) { + case HOST_NOT_FOUND: + return NS_NOTFOUND; + case TRY_AGAIN: + return NS_TRYAGAIN; + default: + return NS_UNAVAIL; + } + *((struct hostent **)rv) = hp; + return NS_SUCCESS; +} + +/*ARGSUSED*/ +int +_dns_gethtbyaddr(void *rv, void *cb_data, va_list ap) +{ + char qbuf[MAXDNAME + 1], *qp, *ep; + int n; + querybuf *buf; + struct hostent *hp; + const unsigned char *uaddr; + int len, af, advance; + res_state res; + res_static rs = __res_get_static(); + + assert(rv != NULL); + + uaddr = va_arg(ap, unsigned char *); + len = va_arg(ap, int); + af = va_arg(ap, int); + + switch (af) { + case AF_INET: + (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa", + (uaddr[3] & 0xff), (uaddr[2] & 0xff), + (uaddr[1] & 0xff), (uaddr[0] & 0xff)); + break; + + case AF_INET6: + qp = qbuf; + ep = qbuf + sizeof(qbuf) - 1; + for (n = IN6ADDRSZ - 1; n >= 0; n--) { + advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.", + uaddr[n] & 0xf, + ((unsigned int)uaddr[n] >> 4) & 0xf); + if (advance > 0 && qp + advance < ep) + qp += advance; + else { + h_errno = NETDB_INTERNAL; + return NS_NOTFOUND; + } + } + if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) { + h_errno = NETDB_INTERNAL; + return NS_NOTFOUND; + } + break; + default: + abort(); + } + + buf = malloc(sizeof(*buf)); + if (buf == NULL) { + h_errno = NETDB_INTERNAL; + return NS_NOTFOUND; + } + res = __res_get_state(); + if (res == NULL) { + free(buf); + return NS_NOTFOUND; + } + n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf)); + if (n < 0) { + free(buf); + dprintf("res_nquery failed (%d)\n", res, n); + __res_put_state(res); + return NS_NOTFOUND; + } + hp = getanswer(buf, n, qbuf, T_PTR, res); + free(buf); + if (hp == NULL) { + __res_put_state(res); + switch (h_errno) { + case HOST_NOT_FOUND: + return NS_NOTFOUND; + case TRY_AGAIN: + return NS_TRYAGAIN; + default: + return NS_UNAVAIL; + } + } + hp->h_addrtype = af; + hp->h_length = len; + (void)memcpy(rs->host_addr, uaddr, (size_t)len); + rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr; + rs->h_addr_ptrs[1] = NULL; + if (af == AF_INET && (res->options & RES_USE_INET6)) { + map_v4v6_address((char *)(void *)rs->host_addr, + (char *)(void *)rs->host_addr); + hp->h_addrtype = AF_INET6; + hp->h_length = IN6ADDRSZ; + } + + __res_put_state(res); + *((struct hostent **)rv) = hp; + h_errno = NETDB_SUCCESS; + return NS_SUCCESS; +} diff --git a/libc/netbsd/inet/nsap_addr.c b/libc/netbsd/inet/nsap_addr.c new file mode 100644 index 0000000..e18bd33 --- /dev/null +++ b/libc/netbsd/inet/nsap_addr.c @@ -0,0 +1,121 @@ +/* $NetBSD: nsap_addr.c,v 1.2 2004/05/20 23:12:33 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static const char rcsid[] = "Id: nsap_addr.c,v 1.2.206.1 2004/03/09 08:33:33 marka Exp"; +#else +__RCSID("$NetBSD: nsap_addr.c,v 1.2 2004/05/20 23:12:33 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include "arpa_nameser.h" + +#include <assert.h> +#include <ctype.h> +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include <resolv.h> +#endif + +static char +xtob(int c) { + return (c - (((c >= '0') && (c <= '9')) ? '0' : '7')); +} + +u_int +inet_nsap_addr(const char *ascii, u_char *binary, int maxlen) { + u_char c, nib; + u_int len = 0; + + assert(ascii != NULL); + assert(binary != NULL); + + if (ascii[0] != '0' || (ascii[1] != 'x' && ascii[1] != 'X')) + return (0); + ascii += 2; + + while ((c = *ascii++) != '\0' && len < (u_int)maxlen) { + if (c == '.' || c == '+' || c == '/') + continue; + if (!isascii(c)) + return (0); + if (islower(c)) + c = toupper(c); + if (isxdigit(c)) { + nib = xtob(c); + c = *ascii++; + if (c != '\0') { + c = toupper(c); + if (isxdigit(c)) { + *binary++ = (nib << 4) | xtob(c); + len++; + } else + return (0); + } + else + return (0); + } + else + return (0); + } + return (len); +} + +char * +inet_nsap_ntoa(int binlen, const u_char *binary, char *ascii) { + int nib; + int i; + static char tmpbuf[2+255*3]; + char *start; + + assert(binary != NULL); + + if (ascii) + start = ascii; + else { + ascii = tmpbuf; + start = tmpbuf; + } + + *ascii++ = '0'; + *ascii++ = 'x'; + + if (binlen > 255) + binlen = 255; + + for (i = 0; i < binlen; i++) { + nib = (u_int32_t)*binary >> 4; + *ascii++ = nib + (nib < 10 ? '0' : '7'); + nib = *binary++ & 0x0f; + *ascii++ = nib + (nib < 10 ? '0' : '7'); + if (((i % 2) == 0 && (i + 1) < binlen)) + *ascii++ = '.'; + } + *ascii = '\0'; + return (start); +} diff --git a/libc/netbsd/isc/ev_streams.c b/libc/netbsd/isc/ev_streams.c new file mode 100644 index 0000000..aeecc3e --- /dev/null +++ b/libc/netbsd/isc/ev_streams.c @@ -0,0 +1,311 @@ +/* $NetBSD: ev_streams.c,v 1.2 2004/05/20 19:52:31 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* ev_streams.c - implement asynch stream file IO for the eventlib + * vix 04mar96 [initial] + */ + +#include <sys/cdefs.h> +#if !defined(LINT) && !defined(CODECENTER) && !defined(lint) +#ifdef notdef +static const char rcsid[] = "Id: ev_streams.c,v 1.2.206.2 2004/03/17 00:29:51 marka Exp"; +#else +__RCSID("$NetBSD: ev_streams.c,v 1.2 2004/05/20 19:52:31 christos Exp $"); +#endif +#endif + +#include <sys/types.h> +#include <sys/uio.h> + +#include <errno.h> + +#include <isc/eventlib.h> +#include "eventlib_p.h" + +#ifndef _LIBC +static int copyvec(evStream *str, const struct iovec *iov, int iocnt); +static void consume(evStream *str, size_t bytes); +static void done(evContext opaqueCtx, evStream *str); +static void writable(evContext opaqueCtx, void *uap, int fd, int evmask); +static void readable(evContext opaqueCtx, void *uap, int fd, int evmask); +#endif + +struct iovec +evConsIovec(void *buf, size_t cnt) { + struct iovec ret; + + memset(&ret, 0xf5, sizeof ret); + ret.iov_base = buf; + ret.iov_len = cnt; + return (ret); +} + +#ifndef _LIBC +int +evWrite(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt, + evStreamFunc func, void *uap, evStreamID *id) +{ + evContext_p *ctx = opaqueCtx.opaque; + evStream *new; + int save; + + OKNEW(new); + new->func = func; + new->uap = uap; + new->fd = fd; + new->flags = 0; + if (evSelectFD(opaqueCtx, fd, EV_WRITE, writable, new, &new->file) < 0) + goto free; + if (copyvec(new, iov, iocnt) < 0) + goto free; + new->prevDone = NULL; + new->nextDone = NULL; + if (ctx->streams != NULL) + ctx->streams->prev = new; + new->prev = NULL; + new->next = ctx->streams; + ctx->streams = new; + if (id != NULL) + id->opaque = new; + return (0); + free: + save = errno; + FREE(new); + errno = save; + return (-1); +} + +int +evRead(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt, + evStreamFunc func, void *uap, evStreamID *id) +{ + evContext_p *ctx = opaqueCtx.opaque; + evStream *new; + int save; + + OKNEW(new); + new->func = func; + new->uap = uap; + new->fd = fd; + new->flags = 0; + if (evSelectFD(opaqueCtx, fd, EV_READ, readable, new, &new->file) < 0) + goto free; + if (copyvec(new, iov, iocnt) < 0) + goto free; + new->prevDone = NULL; + new->nextDone = NULL; + if (ctx->streams != NULL) + ctx->streams->prev = new; + new->prev = NULL; + new->next = ctx->streams; + ctx->streams = new; + if (id) + id->opaque = new; + return (0); + free: + save = errno; + FREE(new); + errno = save; + return (-1); +} + +int +evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer) /*ARGSUSED*/ { + evStream *str = id.opaque; + + UNUSED(opaqueCtx); + + str->timer = timer; + str->flags |= EV_STR_TIMEROK; + return (0); +} + +int +evUntimeRW(evContext opaqueCtx, evStreamID id) /*ARGSUSED*/ { + evStream *str = id.opaque; + + UNUSED(opaqueCtx); + + str->flags &= ~EV_STR_TIMEROK; + return (0); +} + +int +evCancelRW(evContext opaqueCtx, evStreamID id) { + evContext_p *ctx = opaqueCtx.opaque; + evStream *old = id.opaque; + + /* + * The streams list is doubly threaded. First, there's ctx->streams + * that's used by evDestroy() to find and cancel all streams. Second, + * there's ctx->strDone (head) and ctx->strLast (tail) which thread + * through the potentially smaller number of "IO completed" streams, + * used in evGetNext() to avoid scanning the entire list. + */ + + /* Unlink from ctx->streams. */ + if (old->prev != NULL) + old->prev->next = old->next; + else + ctx->streams = old->next; + if (old->next != NULL) + old->next->prev = old->prev; + + /* + * If 'old' is on the ctx->strDone list, remove it. Update + * ctx->strLast if necessary. + */ + if (old->prevDone == NULL && old->nextDone == NULL) { + /* + * Either 'old' is the only item on the done list, or it's + * not on the done list. If the former, then we unlink it + * from the list. If the latter, we leave the list alone. + */ + if (ctx->strDone == old) { + ctx->strDone = NULL; + ctx->strLast = NULL; + } + } else { + if (old->prevDone != NULL) + old->prevDone->nextDone = old->nextDone; + else + ctx->strDone = old->nextDone; + if (old->nextDone != NULL) + old->nextDone->prevDone = old->prevDone; + else + ctx->strLast = old->prevDone; + } + + /* Deallocate the stream. */ + if (old->file.opaque) + evDeselectFD(opaqueCtx, old->file); + memput(old->iovOrig, sizeof (struct iovec) * old->iovOrigCount); + FREE(old); + return (0); +} + +/* Copy a scatter/gather vector and initialize a stream handler's IO. */ +static int +copyvec(evStream *str, const struct iovec *iov, int iocnt) { + int i; + + str->iovOrig = (struct iovec *)memget(sizeof(struct iovec) * iocnt); + if (str->iovOrig == NULL) { + errno = ENOMEM; + return (-1); + } + str->ioTotal = 0; + for (i = 0; i < iocnt; i++) { + str->iovOrig[i] = iov[i]; + str->ioTotal += iov[i].iov_len; + } + str->iovOrigCount = iocnt; + str->iovCur = str->iovOrig; + str->iovCurCount = str->iovOrigCount; + str->ioDone = 0; + return (0); +} + +/* Pull off or truncate lead iovec(s). */ +static void +consume(evStream *str, size_t bytes) { + while (bytes > 0U) { + if (bytes < (size_t)str->iovCur->iov_len) { + str->iovCur->iov_len -= bytes; + str->iovCur->iov_base = (void *) + ((u_char *)str->iovCur->iov_base + bytes); + str->ioDone += bytes; + bytes = 0; + } else { + bytes -= str->iovCur->iov_len; + str->ioDone += str->iovCur->iov_len; + str->iovCur++; + str->iovCurCount--; + } + } +} + +/* Add a stream to Done list and deselect the FD. */ +static void +done(evContext opaqueCtx, evStream *str) { + evContext_p *ctx = opaqueCtx.opaque; + + if (ctx->strLast != NULL) { + str->prevDone = ctx->strLast; + ctx->strLast->nextDone = str; + ctx->strLast = str; + } else { + INSIST(ctx->strDone == NULL); + ctx->strDone = ctx->strLast = str; + } + evDeselectFD(opaqueCtx, str->file); + str->file.opaque = NULL; + /* evDrop() will call evCancelRW() on us. */ +} + +/* Dribble out some bytes on the stream. (Called by evDispatch().) */ +static void +writable(evContext opaqueCtx, void *uap, int fd, int evmask) { + evStream *str = uap; + int bytes; + + UNUSED(evmask); + + bytes = writev(fd, str->iovCur, str->iovCurCount); + if (bytes > 0) { + if ((str->flags & EV_STR_TIMEROK) != 0) + evTouchIdleTimer(opaqueCtx, str->timer); + consume(str, bytes); + } else { + if (bytes < 0 && errno != EINTR) { + str->ioDone = -1; + str->ioErrno = errno; + } + } + if (str->ioDone == -1 || str->ioDone == str->ioTotal) + done(opaqueCtx, str); +} + +/* Scoop up some bytes from the stream. (Called by evDispatch().) */ +static void +readable(evContext opaqueCtx, void *uap, int fd, int evmask) { + evStream *str = uap; + int bytes; + + UNUSED(evmask); + + bytes = readv(fd, str->iovCur, str->iovCurCount); + if (bytes > 0) { + if ((str->flags & EV_STR_TIMEROK) != 0) + evTouchIdleTimer(opaqueCtx, str->timer); + consume(str, bytes); + } else { + if (bytes == 0) + str->ioDone = 0; + else { + if (errno != EINTR) { + str->ioDone = -1; + str->ioErrno = errno; + } + } + } + if (str->ioDone <= 0 || str->ioDone == str->ioTotal) + done(opaqueCtx, str); +} +#endif diff --git a/libc/netbsd/isc/ev_timers.c b/libc/netbsd/isc/ev_timers.c new file mode 100644 index 0000000..9674687 --- /dev/null +++ b/libc/netbsd/isc/ev_timers.c @@ -0,0 +1,504 @@ +/* $NetBSD: ev_timers.c,v 1.2 2004/05/20 19:52:31 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1995-1999 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* ev_timers.c - implement timers for the eventlib + * vix 09sep95 [initial] + */ + +#include <sys/cdefs.h> +#if !defined(LINT) && !defined(CODECENTER) && !defined(lint) +#ifdef notdef +static const char rcsid[] = "Id: ev_timers.c,v 1.2.2.1.4.5 2004/03/17 02:39:13 marka Exp"; +#else +__RCSID("$NetBSD: ev_timers.c,v 1.2 2004/05/20 19:52:31 christos Exp $"); +#endif +#endif + +/* Import. */ + +#include <errno.h> + +#include <isc/assertions.h> +#include <isc/eventlib.h> +#include "eventlib_p.h" + +/* Constants. */ + +#define MILLION 1000000 +#define BILLION 1000000000 + +/* Forward. */ + +#ifndef _LIBC +static int due_sooner(void *, void *); +static void set_index(void *, int); +static void free_timer(void *, void *); +static void print_timer(void *, void *); +static void idle_timeout(evContext, void *, struct timespec, struct timespec); + +/* Private type. */ + +typedef struct { + evTimerFunc func; + void * uap; + struct timespec lastTouched; + struct timespec max_idle; + evTimer * timer; +} idle_timer; +#endif + +/* Public. */ + +struct timespec +evConsTime(time_t sec, long nsec) { + struct timespec x; + + x.tv_sec = sec; + x.tv_nsec = nsec; + return (x); +} + +struct timespec +evAddTime(struct timespec addend1, struct timespec addend2) { + struct timespec x; + + x.tv_sec = addend1.tv_sec + addend2.tv_sec; + x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec; + if (x.tv_nsec >= BILLION) { + x.tv_sec++; + x.tv_nsec -= BILLION; + } + return (x); +} + +struct timespec +evSubTime(struct timespec minuend, struct timespec subtrahend) { + struct timespec x; + + x.tv_sec = minuend.tv_sec - subtrahend.tv_sec; + if (minuend.tv_nsec >= subtrahend.tv_nsec) + x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec; + else { + x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec; + x.tv_sec--; + } + return (x); +} + +int +evCmpTime(struct timespec a, struct timespec b) { + long x = a.tv_sec - b.tv_sec; + + if (x == 0L) + x = a.tv_nsec - b.tv_nsec; + return (x < 0L ? (-1) : x > 0L ? (1) : (0)); +} + +struct timespec +evNowTime() { + struct timeval now; +#ifdef CLOCK_REALTIME + struct timespec tsnow; + int m = CLOCK_REALTIME; + +#ifdef CLOCK_MONOTONIC + if (__evOptMonoTime) + m = CLOCK_MONOTONIC; +#endif + if (clock_gettime(m, &tsnow) == 0) + return (tsnow); +#endif + if (gettimeofday(&now, NULL) < 0) + return (evConsTime(0L, 0L)); + return (evTimeSpec(now)); +} + +struct timespec +evUTCTime(void) { + struct timeval now; +#ifdef CLOCK_REALTIME + struct timespec tsnow; + if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0) + return (tsnow); +#endif + if (gettimeofday(&now, NULL) < 0) + return (evConsTime(0L, 0L)); + return (evTimeSpec(now)); +} + +#ifndef _LIBC +struct timespec +evLastEventTime(evContext opaqueCtx) { + evContext_p *ctx = opaqueCtx.opaque; + + return (ctx->lastEventTime); +} +#endif + +struct timespec +evTimeSpec(struct timeval tv) { + struct timespec ts; + + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; + return (ts); +} + +struct timeval +evTimeVal(struct timespec ts) { + struct timeval tv; + + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; + return (tv); +} + +#ifndef _LIBC +int +evSetTimer(evContext opaqueCtx, + evTimerFunc func, + void *uap, + struct timespec due, + struct timespec inter, + evTimerID *opaqueID +) { + evContext_p *ctx = opaqueCtx.opaque; + evTimer *id; + + printf("evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n", + ctx, func, uap, + (long)due.tv_sec, due.tv_nsec, + (long)inter.tv_sec, inter.tv_nsec); + +#ifdef __hpux + /* + * tv_sec and tv_nsec are unsigned. + */ + if (due.tv_nsec >= BILLION) + EV_ERR(EINVAL); + + if (inter.tv_nsec >= BILLION) + EV_ERR(EINVAL); +#else + if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION) + EV_ERR(EINVAL); + + if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION) + EV_ERR(EINVAL); +#endif + + /* due={0,0} is a magic cookie meaning "now." */ + if (due.tv_sec == (time_t)0 && due.tv_nsec == 0L) + due = evNowTime(); + + /* Allocate and fill. */ + OKNEW(id); + id->func = func; + id->uap = uap; + id->due = due; + id->inter = inter; + + if (heap_insert(ctx->timers, id) < 0) + return (-1); + + /* Remember the ID if the caller provided us a place for it. */ + if (opaqueID) + opaqueID->opaque = id; + + if (ctx->debug > 7) { + printf("timers after evSetTimer:\n"); + (void) heap_for_each(ctx->timers, print_timer, (void *)ctx); + } + + return (0); +} + +int +evClearTimer(evContext opaqueCtx, evTimerID id) { + evContext_p *ctx = opaqueCtx.opaque; + evTimer *del = id.opaque; + + if (ctx->cur != NULL && + ctx->cur->type == Timer && + ctx->cur->u.timer.this == del) { + printf("deferring delete of timer (executing)\n"); + /* + * Setting the interval to zero ensures that evDrop() will + * clean up the timer. + */ + del->inter = evConsTime(0, 0); + return (0); + } + + if (heap_element(ctx->timers, del->index) != del) + EV_ERR(ENOENT); + + if (heap_delete(ctx->timers, del->index) < 0) + return (-1); + FREE(del); + + if (ctx->debug > 7) { + printf("timers after evClearTimer:\n"); + (void) heap_for_each(ctx->timers, print_timer, (void *)ctx); + } + + return (0); +} + +int +evConfigTimer(evContext opaqueCtx, + evTimerID id, + const char *param, + int value +) { + evContext_p *ctx = opaqueCtx.opaque; + evTimer *timer = id.opaque; + int result=0; + + UNUSED(value); + + if (heap_element(ctx->timers, timer->index) != timer) + EV_ERR(ENOENT); + + if (strcmp(param, "rate") == 0) + timer->mode |= EV_TMR_RATE; + else if (strcmp(param, "interval") == 0) + timer->mode &= ~EV_TMR_RATE; + else + EV_ERR(EINVAL); + + return (result); +} + +int +evResetTimer(evContext opaqueCtx, + evTimerID id, + evTimerFunc func, + void *uap, + struct timespec due, + struct timespec inter +) { + evContext_p *ctx = opaqueCtx.opaque; + evTimer *timer = id.opaque; + struct timespec old_due; + int result=0; + + if (heap_element(ctx->timers, timer->index) != timer) + EV_ERR(ENOENT); + +#ifdef __hpux + /* + * tv_sec and tv_nsec are unsigned. + */ + if (due.tv_nsec >= BILLION) + EV_ERR(EINVAL); + + if (inter.tv_nsec >= BILLION) + EV_ERR(EINVAL); +#else + if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION) + EV_ERR(EINVAL); + + if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION) + EV_ERR(EINVAL); +#endif + + old_due = timer->due; + + timer->func = func; + timer->uap = uap; + timer->due = due; + timer->inter = inter; + + switch (evCmpTime(due, old_due)) { + case -1: + result = heap_increased(ctx->timers, timer->index); + break; + case 0: + result = 0; + break; + case 1: + result = heap_decreased(ctx->timers, timer->index); + break; + } + + if (ctx->debug > 7) { + printf("timers after evResetTimer:\n"); + (void) heap_for_each(ctx->timers, print_timer, (void *)ctx); + } + + return (result); +} + +int +evSetIdleTimer(evContext opaqueCtx, + evTimerFunc func, + void *uap, + struct timespec max_idle, + evTimerID *opaqueID +) { + evContext_p *ctx = opaqueCtx.opaque; + idle_timer *tt; + + /* Allocate and fill. */ + OKNEW(tt); + tt->func = func; + tt->uap = uap; + tt->lastTouched = ctx->lastEventTime; + tt->max_idle = max_idle; + + if (evSetTimer(opaqueCtx, idle_timeout, tt, + evAddTime(ctx->lastEventTime, max_idle), + max_idle, opaqueID) < 0) { + FREE(tt); + return (-1); + } + + tt->timer = opaqueID->opaque; + + return (0); +} + +int +evClearIdleTimer(evContext opaqueCtx, evTimerID id) { + evTimer *del = id.opaque; + idle_timer *tt = del->uap; + + FREE(tt); + return (evClearTimer(opaqueCtx, id)); +} + +int +evResetIdleTimer(evContext opaqueCtx, + evTimerID opaqueID, + evTimerFunc func, + void *uap, + struct timespec max_idle +) { + evContext_p *ctx = opaqueCtx.opaque; + evTimer *timer = opaqueID.opaque; + idle_timer *tt = timer->uap; + + tt->func = func; + tt->uap = uap; + tt->lastTouched = ctx->lastEventTime; + tt->max_idle = max_idle; + + return (evResetTimer(opaqueCtx, opaqueID, idle_timeout, tt, + evAddTime(ctx->lastEventTime, max_idle), + max_idle)); +} + +int +evTouchIdleTimer(evContext opaqueCtx, evTimerID id) { + evContext_p *ctx = opaqueCtx.opaque; + evTimer *t = id.opaque; + idle_timer *tt = t->uap; + + tt->lastTouched = ctx->lastEventTime; + + return (0); +} + +/* Public to the rest of eventlib. */ + +heap_context +evCreateTimers(const evContext_p *ctx) { + + UNUSED(ctx); + + return (heap_new(due_sooner, set_index, 2048)); +} + +void +evDestroyTimers(const evContext_p *ctx) { + (void) heap_for_each(ctx->timers, free_timer, NULL); + (void) heap_free(ctx->timers); +} + +/* Private. */ + +static int +due_sooner(void *a, void *b) { + evTimer *a_timer, *b_timer; + + a_timer = a; + b_timer = b; + return (evCmpTime(a_timer->due, b_timer->due) < 0); +} + +static void +set_index(void *what, int idx) { + evTimer *timer; + + timer = what; + timer->index = idx; +} + +static void +free_timer(void *what, void *uap) { + evTimer *t = what; + + UNUSED(uap); + + FREE(t); +} + +static void +print_timer(void *what, void *uap) { + evTimer *cur = what; + evContext_p *ctx = uap; + + cur = what; + evPrintf(ctx, 7, + " func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n", + cur->func, cur->uap, + (long)cur->due.tv_sec, cur->due.tv_nsec, + (long)cur->inter.tv_sec, cur->inter.tv_nsec); +} + +static void +idle_timeout(evContext opaqueCtx, + void *uap, + struct timespec due, + struct timespec inter +) { + evContext_p *ctx = opaqueCtx.opaque; + idle_timer *this = uap; + struct timespec idle; + + UNUSED(due); + UNUSED(inter); + + idle = evSubTime(ctx->lastEventTime, this->lastTouched); + if (evCmpTime(idle, this->max_idle) >= 0) { + (this->func)(opaqueCtx, this->uap, this->timer->due, + this->max_idle); + /* + * Setting the interval to zero will cause the timer to + * be cleaned up in evDrop(). + */ + this->timer->inter = evConsTime(0L, 0L); + FREE(this); + } else { + /* evDrop() will reschedule the timer. */ + this->timer->inter = evSubTime(this->max_idle, idle); + } +} +#endif diff --git a/libc/netbsd/isc/eventlib_p.h b/libc/netbsd/isc/eventlib_p.h new file mode 100644 index 0000000..7edc5a0 --- /dev/null +++ b/libc/netbsd/isc/eventlib_p.h @@ -0,0 +1,233 @@ +/* $NetBSD: eventlib_p.h,v 1.1.1.1 2004/05/20 19:34:32 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1995-1999 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* eventlib_p.h - private interfaces for eventlib + * vix 09sep95 [initial] + * + * Id: eventlib_p.h,v 1.3.2.1.4.1 2004/03/09 08:33:43 marka Exp + */ + +#ifndef _EVENTLIB_P_H +#define _EVENTLIB_P_H + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/un.h> + +#define EVENTLIB_DEBUG 1 + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <isc/heap.h> +#include <isc/list.h> +#include <isc/memcluster.h> + + +#define EV_MASK_ALL (EV_READ | EV_WRITE | EV_EXCEPT) +#define EV_ERR(e) return (errno = (e), -1) +#define OK(x) if ((x) < 0) EV_ERR(errno); else (void)NULL + + +#if HAVE_MEM_GET_SET +#define NEW(p) if (((p) = memget(sizeof *(p))) != NULL) \ + FILL(p); \ + else \ + (void)NULL; +#define OKNEW(p) if (!((p) = memget(sizeof *(p)))) { \ + errno = ENOMEM; \ + return (-1); \ + } else \ + FILL(p) +#define FREE(p) memput((p), sizeof *(p)) + +#if EVENTLIB_DEBUG +#define FILL(p) memset((p), 0xF5, sizeof *(p)) +#else +#define FILL(p) +#endif + +#else + +#define NEW(p) p = malloc(sizeof *(p)); +#define OKNEW(p) if (!((p) = malloc(sizeof *(p)))) { errno = ENOMEM; return (-1); } +#define FREE(p) free(p) +#define FILL(p) + +#endif + + +typedef struct evConn { + evConnFunc func; + void * uap; + int fd; + int flags; +#define EV_CONN_LISTEN 0x0001 /* Connection is a listener. */ +#define EV_CONN_SELECTED 0x0002 /* evSelectFD(conn->file). */ +#define EV_CONN_BLOCK 0x0004 /* Listener fd was blocking. */ + evFileID file; + struct evConn * prev; + struct evConn * next; +} evConn; + +typedef struct evAccept { + int fd; + union { + struct sockaddr sa; + struct sockaddr_in in; +#ifndef NO_SOCKADDR_UN + struct sockaddr_un un; +#endif + } la; + socklen_t lalen; + union { + struct sockaddr sa; + struct sockaddr_in in; +#ifndef NO_SOCKADDR_UN + struct sockaddr_un un; +#endif + } ra; + socklen_t ralen; + int ioErrno; + evConn * conn; + LINK(struct evAccept) link; +} evAccept; + +typedef struct evFile { + evFileFunc func; + void * uap; + int fd; + int eventmask; + int preemptive; + struct evFile * prev; + struct evFile * next; + struct evFile * fdprev; + struct evFile * fdnext; +} evFile; + +typedef struct evStream { + evStreamFunc func; + void * uap; + evFileID file; + evTimerID timer; + int flags; +#define EV_STR_TIMEROK 0x0001 /* IFF timer valid. */ + int fd; + struct iovec * iovOrig; + int iovOrigCount; + struct iovec * iovCur; + int iovCurCount; + int ioTotal; + int ioDone; + int ioErrno; + struct evStream *prevDone, *nextDone; + struct evStream *prev, *next; +} evStream; + +typedef struct evTimer { + evTimerFunc func; + void * uap; + struct timespec due, inter; + int index; + int mode; +#define EV_TMR_RATE 1 +} evTimer; + +typedef struct evWait { + evWaitFunc func; + void * uap; + const void * tag; + struct evWait * next; +} evWait; + +typedef struct evWaitList { + evWait * first; + evWait * last; + struct evWaitList * prev; + struct evWaitList * next; +} evWaitList; + +typedef struct evEvent_p { + enum { Accept, File, Stream, Timer, Wait, Free, Null } type; + union { + struct { evAccept *this; } accept; + struct { evFile *this; int eventmask; } file; + struct { evStream *this; } stream; + struct { evTimer *this; } timer; + struct { evWait *this; } wait; + struct { struct evEvent_p *next; } free; + struct { const void *placeholder; } null; + } u; +} evEvent_p; + +typedef struct { + /* Global. */ + const evEvent_p *cur; + /* Debugging. */ + int debug; + FILE *output; + /* Connections. */ + evConn *conns; + LIST(evAccept) accepts; + /* Files. */ + evFile *files, *fdNext; + fd_set rdLast, rdNext; + fd_set wrLast, wrNext; + fd_set exLast, exNext; + fd_set nonblockBefore; + int fdMax, fdCount, highestFD; + evFile *fdTable[FD_SETSIZE]; +#ifdef EVENTLIB_TIME_CHECKS + struct timespec lastSelectTime; + int lastFdCount; +#endif + /* Streams. */ + evStream *streams; + evStream *strDone, *strLast; + /* Timers. */ + struct timespec lastEventTime; + heap_context timers; + /* Waits. */ + evWaitList *waitLists; + evWaitList waitDone; +} evContext_p; + +/* eventlib.c */ +#define evPrintf __evPrintf +void evPrintf(const evContext_p *ctx, int level, const char *fmt, ...); + +/* ev_timers.c */ +#define evCreateTimers __evCreateTimers +heap_context evCreateTimers(const evContext_p *); +#define evDestroyTimers __evDestroyTimers +void evDestroyTimers(const evContext_p *); + +/* ev_waits.c */ +#define evFreeWait __evFreeWait +evWait *evFreeWait(evContext_p *ctx, evWait *old); + +/* Global options */ +int __evOptMonoTime; + +#endif /*_EVENTLIB_P_H*/ diff --git a/libc/netbsd/nameser/ns_name.c b/libc/netbsd/nameser/ns_name.c new file mode 100644 index 0000000..85d2f60 --- /dev/null +++ b/libc/netbsd/nameser/ns_name.c @@ -0,0 +1,970 @@ +/* $NetBSD: ns_name.c,v 1.3 2004/11/07 02:19:49 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +#ifndef lint +#ifdef notdef +static const char rcsid[] = "Id: ns_name.c,v 1.3.2.4.4.2 2004/05/04 03:27:47 marka Exp"; +#else +__RCSID("$NetBSD: ns_name.c,v 1.3 2004/11/07 02:19:49 christos Exp $"); +#endif +#endif + +#include <sys/types.h> + +#include <netinet/in.h> +#include "arpa_nameser.h" + +#include <errno.h> +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include <resolv.h> +#endif +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include <limits.h> + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +#define NS_TYPE_ELT 0x40 /* EDNS0 extended label type */ +#define DNS_LABELTYPE_BITSTRING 0x41 + +/* Data. */ + +static const char digits[] = "0123456789"; + +static const char digitvalue[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/ + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/ +}; + +/* Forward. */ + +static int special(int); +static int printable(int); +static int dn_find(const u_char *, const u_char *, + const u_char * const *, + const u_char * const *); +static int encode_bitsring(const char **, const char *, + unsigned char **, unsigned char **, + unsigned const char *); +static int labellen(const u_char *); +static int decode_bitstring(const unsigned char **, + char *, const char *); + +/* Public. */ + +/* + * ns_name_ntop(src, dst, dstsiz) + * Convert an encoded domain name to printable ascii as per RFC1035. + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * notes: + * The root is returned as "." + * All other domains are returned in non absolute form + */ +int +ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) +{ + const u_char *cp; + char *dn, *eom; + u_char c; + u_int n; + int l; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + if (dn != dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if ((l = labellen(cp - 1)) < 0) { + errno = EMSGSIZE; /* XXX */ + return(-1); + } + if (dn + l >= eom) { + errno = EMSGSIZE; + return (-1); + } + if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) { + int m; + + if (n != DNS_LABELTYPE_BITSTRING) { + /* XXX: labellen should reject this case */ + errno = EINVAL; + return(-1); + } + if ((m = decode_bitstring(&cp, dn, eom)) < 0) + { + errno = EMSGSIZE; + return(-1); + } + dn += m; + continue; + } + for (; l > 0; l--) { + c = *cp++; + if (special(c)) { + if (dn + 1 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = (char)c; + } else if (!printable(c)) { + if (dn + 3 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = digits[c / 100]; + *dn++ = digits[(c % 100) / 10]; + *dn++ = digits[c % 10]; + } else { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = (char)c; + } + } + } + if (dn == dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\0'; + return (dn - dst); +} + +/* + * ns_name_pton(src, dst, dstsiz) + * Convert a ascii string into an encoded domain name as per RFC1035. + * return: + * -1 if it fails + * 1 if string was fully qualified + * 0 is string was not fully qualified + * notes: + * Enforces label and domain length limits. + */ + +int +ns_name_pton(const char *src, u_char *dst, size_t dstsiz) +{ + u_char *label, *bp, *eom; + int c, n, escaped, e = 0; + char *cp; + + escaped = 0; + bp = dst; + eom = dst + dstsiz; + label = bp++; + + while ((c = *src++) != 0) { + if (escaped) { + if (c == '[') { /* start a bit string label */ + if ((cp = strchr(src, ']')) == NULL) { + errno = EINVAL; /* ??? */ + return(-1); + } + if ((e = encode_bitsring(&src, cp + 2, + &label, &bp, eom)) + != 0) { + errno = e; + return(-1); + } + escaped = 0; + label = bp++; + if ((c = *src++) == 0) + goto done; + else if (c != '.') { + errno = EINVAL; + return(-1); + } + continue; + } + else if ((cp = strchr(digits, c)) != NULL) { + n = (cp - digits) * 100; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (cp - digits) * 10; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (cp - digits); + if (n > 255) { + errno = EMSGSIZE; + return (-1); + } + c = n; + } + escaped = 0; + } else if (c == '\\') { + escaped = 1; + continue; + } else if (c == '.') { + c = (bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + errno = EMSGSIZE; + return (-1); + } + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + /* Fully qualified ? */ + if (*src == '\0') { + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = '\0'; + } + if ((bp - dst) > MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + return (1); + } + if (c == 0 || *src == '.') { + errno = EMSGSIZE; + return (-1); + } + label = bp++; + continue; + } + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = (u_char)c; + } + c = (bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + errno = EMSGSIZE; + return (-1); + } + done: + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = 0; + } + if ((bp - dst) > MAXCDNAME) { /* src too big */ + errno = EMSGSIZE; + return (-1); + } + return (0); +} + +/* + * ns_name_ntol(src, dst, dstsiz) + * Convert a network strings labels into all lowercase. + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * notes: + * Enforces label and domain length limits. + */ + +int +ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) +{ + const u_char *cp; + u_char *dn, *eom; + u_char c; + u_int n; + int l; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + *dn++ = n; + if ((l = labellen(cp - 1)) < 0) { + errno = EMSGSIZE; + return (-1); + } + if (dn + l >= eom) { + errno = EMSGSIZE; + return (-1); + } + for (; l > 0; l--) { + c = *cp++; + if (isupper(c)) + *dn++ = tolower(c); + else + *dn++ = c; + } + } + *dn++ = '\0'; + return (dn - dst); +} + +/* + * ns_name_unpack(msg, eom, src, dst, dstsiz) + * Unpack a domain name from a message, source may be compressed. + * return: + * -1 if it fails, or consumed octets if it succeeds. + */ +int +ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src, + u_char *dst, size_t dstsiz) +{ + const u_char *srcp, *dstlim; + u_char *dstp; + int n, len, checked, l; + + len = -1; + checked = 0; + dstp = dst; + srcp = src; + dstlim = dst + dstsiz; + if (srcp < msg || srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + /* Fetch next label in domain name. */ + while ((n = *srcp++) != 0) { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) { + case 0: + case NS_TYPE_ELT: + /* Limit checks. */ + if ((l = labellen(srcp - 1)) < 0) { + errno = EMSGSIZE; + return(-1); + } + if (dstp + l + 1 >= dstlim || srcp + l >= eom) { + errno = EMSGSIZE; + return (-1); + } + checked += l + 1; + *dstp++ = n; + memcpy(dstp, srcp, (size_t)l); + dstp += l; + srcp += l; + break; + + case NS_CMPRSFLGS: + if (srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + if (len < 0) + len = srcp - src + 1; + srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); + if (srcp < msg || srcp >= eom) { /* Out of range. */ + errno = EMSGSIZE; + return (-1); + } + checked += 2; + /* + * Check for loops in the compressed name; + * if we've looked at the whole message, + * there must be a loop. + */ + if (checked >= eom - msg) { + errno = EMSGSIZE; + return (-1); + } + break; + + default: + errno = EMSGSIZE; + return (-1); /* flag error */ + } + } + *dstp = '\0'; + if (len < 0) + len = srcp - src; + return (len); +} + +/* + * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) + * Pack domain name 'domain' into 'comp_dn'. + * return: + * Size of the compressed name, or -1. + * notes: + * 'dnptrs' is an array of pointers to previous compressed names. + * dnptrs[0] is a pointer to the beginning of the message. The array + * ends with NULL. + * 'lastdnptr' is a pointer to the end of the array pointed to + * by 'dnptrs'. + * Side effects: + * The list of pointers in dnptrs is updated for labels inserted into + * the message as we compress the name. If 'dnptr' is NULL, we don't + * try to compress names. If 'lastdnptr' is NULL, we don't update the + * list. + */ +int +ns_name_pack(const u_char *src, u_char *dst, int dstsiz, + const u_char **dnptrs, const u_char **lastdnptr) +{ + u_char *dstp; + const u_char **cpp, **lpp, *eob, *msg; + const u_char *srcp; + int n, l, first = 1; + + srcp = src; + dstp = dst; + eob = dstp + dstsiz; + lpp = cpp = NULL; + if (dnptrs != NULL) { + if ((msg = *dnptrs++) != NULL) { + for (cpp = dnptrs; *cpp != NULL; cpp++) + ; + lpp = cpp; /* end of list to search */ + } + } else + msg = NULL; + + /* make sure the domain we are about to add is legal */ + l = 0; + do { + int l0; + + n = *srcp; + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + errno = EMSGSIZE; + return (-1); + } + if ((l0 = labellen(srcp)) < 0) { + errno = EINVAL; + return(-1); + } + l += l0 + 1; + if (l > MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + srcp += l0 + 1; + } while (n != 0); + + /* from here on we need to reset compression pointer array on error */ + srcp = src; + do { + /* Look to see if we can use pointers. */ + n = *srcp; + if (n != 0 && msg != NULL) { + l = dn_find(srcp, msg, (const u_char * const *)dnptrs, + (const u_char * const *)lpp); + if (l >= 0) { + if (dstp + 1 >= eob) { + goto cleanup; + } + *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS; + *dstp++ = l % 256; + return (dstp - dst); + } + /* Not found, save it. */ + if (lastdnptr != NULL && cpp < lastdnptr - 1 && + (dstp - msg) < 0x4000 && first) { + *cpp++ = dstp; + *cpp = NULL; + first = 0; + } + } + /* copy label to buffer */ + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* Should not happen. */ + goto cleanup; + } + n = labellen(srcp); + if (dstp + 1 + n >= eob) { + goto cleanup; + } + memcpy(dstp, srcp, (size_t)(n + 1)); + srcp += n + 1; + dstp += n + 1; + } while (n != 0); + + if (dstp > eob) { +cleanup: + if (msg != NULL) + *lpp = NULL; + errno = EMSGSIZE; + return (-1); + } + return (dstp - dst); +} + +/* + * ns_name_uncompress(msg, eom, src, dst, dstsiz) + * Expand compressed domain name to presentation format. + * return: + * Number of bytes read out of `src', or -1 (with errno set). + * note: + * Root domain returns as "." not "". + */ +int +ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src, + char *dst, size_t dstsiz) +{ + u_char tmp[NS_MAXCDNAME]; + int n; + + if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) + return (-1); + if (ns_name_ntop(tmp, dst, dstsiz) == -1) + return (-1); + return (n); +} + +/* + * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr) + * Compress a domain name into wire format, using compression pointers. + * return: + * Number of bytes consumed in `dst' or -1 (with errno set). + * notes: + * 'dnptrs' is an array of pointers to previous compressed names. + * dnptrs[0] is a pointer to the beginning of the message. + * The list ends with NULL. 'lastdnptr' is a pointer to the end of the + * array pointed to by 'dnptrs'. Side effect is to update the list of + * pointers for labels inserted into the message as we compress the name. + * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr' + * is NULL, we don't update the list. + */ +int +ns_name_compress(const char *src, u_char *dst, size_t dstsiz, + const u_char **dnptrs, const u_char **lastdnptr) +{ + u_char tmp[NS_MAXCDNAME]; + + if (ns_name_pton(src, tmp, sizeof tmp) == -1) + return (-1); + return (ns_name_pack(tmp, dst, (int)dstsiz, dnptrs, lastdnptr)); +} + +/* + * Reset dnptrs so that there are no active references to pointers at or + * after src. + */ +void +ns_name_rollback(const u_char *src, const u_char **dnptrs, + const u_char **lastdnptr) +{ + while (dnptrs < lastdnptr && *dnptrs != NULL) { + if (*dnptrs >= src) { + *dnptrs = NULL; + break; + } + dnptrs++; + } +} + +/* + * ns_name_skip(ptrptr, eom) + * Advance *ptrptr to skip over the compressed name it points at. + * return: + * 0 on success, -1 (with errno set) on failure. + */ +int +ns_name_skip(const u_char **ptrptr, const u_char *eom) +{ + const u_char *cp; + u_int n; + int l; + + cp = *ptrptr; + while (cp < eom && (n = *cp++) != 0) { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) { + case 0: /* normal case, n == len */ + cp += n; + continue; + case NS_TYPE_ELT: /* EDNS0 extended label */ + if ((l = labellen(cp - 1)) < 0) { + errno = EMSGSIZE; /* XXX */ + return(-1); + } + cp += l; + continue; + case NS_CMPRSFLGS: /* indirection */ + cp++; + break; + default: /* illegal type */ + errno = EMSGSIZE; + return (-1); + } + break; + } + if (cp > eom) { + errno = EMSGSIZE; + return (-1); + } + *ptrptr = cp; + return (0); +} + +/* Private. */ + +/* + * special(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this characted special ("in need of quoting") ? + * return: + * boolean. + */ +static int +special(int ch) { + switch (ch) { + case 0x22: /* '"' */ + case 0x2E: /* '.' */ + case 0x3B: /* ';' */ + case 0x5C: /* '\\' */ + case 0x28: /* '(' */ + case 0x29: /* ')' */ + /* Special modifiers in zone files. */ + case 0x40: /* '@' */ + case 0x24: /* '$' */ + return (1); + default: + return (0); + } +} + +/* + * printable(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this character visible and not a space when printed ? + * return: + * boolean. + */ +static int +printable(int ch) { + return (ch > 0x20 && ch < 0x7f); +} + +/* + * Thinking in noninternationalized USASCII (per the DNS spec), + * convert this character to lower case if it's upper case. + */ +static int +mklower(int ch) { + if (ch >= 0x41 && ch <= 0x5A) + return (ch + 0x20); + return (ch); +} + +/* + * dn_find(domain, msg, dnptrs, lastdnptr) + * Search for the counted-label name in an array of compressed names. + * return: + * offset from msg if found, or -1. + * notes: + * dnptrs is the pointer to the first name on the list, + * not the pointer to the start of the message. + */ +static int +dn_find(const u_char *domain, const u_char *msg, + const u_char * const *dnptrs, + const u_char * const *lastdnptr) +{ + const u_char *dn, *cp, *sp; + const u_char * const *cpp; + u_int n; + + for (cpp = dnptrs; cpp < lastdnptr; cpp++) { + sp = *cpp; + /* + * terminate search on: + * root label + * compression pointer + * unusable offset + */ + while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 && + (sp - msg) < 0x4000) { + dn = domain; + cp = sp; + while ((n = *cp++) != 0) { + /* + * check for indirection + */ + switch (n & NS_CMPRSFLGS) { + case 0: /* normal case, n == len */ + n = labellen(cp - 1); /* XXX */ + + if (n != *dn++) + goto next; + + for (; n > 0; n--) + if (mklower(*dn++) != + mklower(*cp++)) + goto next; + /* Is next root for both ? */ + if (*dn == '\0' && *cp == '\0') + return (sp - msg); + if (*dn) + continue; + goto next; + case NS_CMPRSFLGS: /* indirection */ + cp = msg + (((n & 0x3f) << 8) | *cp); + break; + + default: /* illegal type */ + errno = EMSGSIZE; + return (-1); + } + } + next: ; + sp += *sp + 1; + } + } + errno = ENOENT; + return (-1); +} + +static int +decode_bitstring(const unsigned char **cpp, char *dn, const char *eom) +{ + const unsigned char *cp = *cpp; + char *beg = dn, tc; + int b, blen, plen, i; + + if ((blen = (*cp & 0xff)) == 0) + blen = 256; + plen = (blen + 3) / 4; + plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); + if (dn + plen >= eom) + return(-1); + + cp++; + i = SPRINTF((dn, "\\[x")); + if (i < 0) + return (-1); + dn += i; + for (b = blen; b > 7; b -= 8, cp++) { + i = SPRINTF((dn, "%02x", *cp & 0xff)); + if (i < 0) + return (-1); + dn += i; + } + if (b > 4) { + tc = *cp++; + i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b)))); + if (i < 0) + return (-1); + dn += i; + } else if (b > 0) { + tc = *cp++; + i = SPRINTF((dn, "%1x", + (((u_int32_t)tc >> 4) & 0x0f) & (0x0f << (4 - b)))); + if (i < 0) + return (-1); + dn += i; + } + i = SPRINTF((dn, "/%d]", blen)); + if (i < 0) + return (-1); + dn += i; + + *cpp = cp; + return(dn - beg); +} + +static int +encode_bitsring(const char **bp, const char *end, unsigned char **labelp, + unsigned char ** dst, unsigned const char *eom) +{ + int afterslash = 0; + const char *cp = *bp; + unsigned char *tp; + char c; + const char *beg_blen; + char *end_blen = NULL; + int value = 0, count = 0, tbcount = 0, blen = 0; + + beg_blen = end_blen = NULL; + + /* a bitstring must contain at least 2 characters */ + if (end - cp < 2) + return(EINVAL); + + /* XXX: currently, only hex strings are supported */ + if (*cp++ != 'x') + return(EINVAL); + if (!isxdigit((*cp) & 0xff)) /* reject '\[x/BLEN]' */ + return(EINVAL); + + for (tp = *dst + 1; cp < end && tp < eom; cp++) { + switch((c = *cp)) { + case ']': /* end of the bitstring */ + if (afterslash) { + if (beg_blen == NULL) + return(EINVAL); + blen = (int)strtol(beg_blen, &end_blen, 10); + if (*end_blen != ']') + return(EINVAL); + } + if (count) + *tp++ = ((value << 4) & 0xff); + cp++; /* skip ']' */ + goto done; + case '/': + afterslash = 1; + break; + default: + if (afterslash) { + if (!isdigit(c&0xff)) + return(EINVAL); + if (beg_blen == NULL) { + + if (c == '0') { + /* blen never begings with 0 */ + return(EINVAL); + } + beg_blen = cp; + } + } else { + if (!isxdigit(c&0xff)) + return(EINVAL); + value <<= 4; + value += digitvalue[(int)c]; + count += 4; + tbcount += 4; + if (tbcount > 256) + return(EINVAL); + if (count == 8) { + *tp++ = value; + count = 0; + } + } + break; + } + } + done: + if (cp >= end || tp >= eom) + return(EMSGSIZE); + + /* + * bit length validation: + * If a <length> is present, the number of digits in the <bit-data> + * MUST be just sufficient to contain the number of bits specified + * by the <length>. If there are insignificant bits in a final + * hexadecimal or octal digit, they MUST be zero. + * RFC 2673, Section 3.2. + */ + if (blen > 0) { + int traillen; + + if (((blen + 3) & ~3) != tbcount) + return(EINVAL); + traillen = tbcount - blen; /* between 0 and 3 */ + if (((value << (8 - traillen)) & 0xff) != 0) + return(EINVAL); + } + else + blen = tbcount; + if (blen == 256) + blen = 0; + + /* encode the type and the significant bit fields */ + **labelp = DNS_LABELTYPE_BITSTRING; + **dst = blen; + + *bp = cp; + *dst = tp; + + return(0); +} + +static int +labellen(const u_char *lp) +{ + int bitlen; + u_char l = *lp; + + if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* should be avoided by the caller */ + return(-1); + } + + if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) { + if (l == DNS_LABELTYPE_BITSTRING) { + if ((bitlen = *(lp + 1)) == 0) + bitlen = 256; + return((bitlen + 7 ) / 8 + 1); + } + return(-1); /* unknwon ELT */ + } + return(l); +} diff --git a/libc/netbsd/nameser/ns_netint.c b/libc/netbsd/nameser/ns_netint.c new file mode 100644 index 0000000..1b2964f --- /dev/null +++ b/libc/netbsd/nameser/ns_netint.c @@ -0,0 +1,59 @@ +/* $NetBSD: ns_netint.c,v 1.2 2004/05/20 20:19:00 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +#ifndef lint +#ifdef notdef +static const char rcsid[] = "Id: ns_netint.c,v 1.1.206.1 2004/03/09 08:33:44 marka Exp"; +#else +__RCSID("$NetBSD: ns_netint.c,v 1.2 2004/05/20 20:19:00 christos Exp $"); +#endif +#endif + +/* Import. */ + +#include "arpa_nameser.h" + +/* Public. */ + +u_int16_t +ns_get16(const u_char *src) { + u_int dst; + + NS_GET16(dst, src); + return (dst); +} + +u_int32_t +ns_get32(const u_char *src) { + u_long dst; + + NS_GET32(dst, src); + return (dst); +} + +void +ns_put16(u_int16_t src, u_char *dst) { + NS_PUT16(src, dst); +} + +void +ns_put32(u_int32_t src, u_char *dst) { + NS_PUT32(src, dst); +} diff --git a/libc/netbsd/nameser/ns_parse.c b/libc/netbsd/nameser/ns_parse.c new file mode 100644 index 0000000..fd94860 --- /dev/null +++ b/libc/netbsd/nameser/ns_parse.c @@ -0,0 +1,209 @@ +/* $NetBSD: ns_parse.c,v 1.2 2004/05/20 20:35:05 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +#ifndef lint +#ifdef notdef +static const char rcsid[] = "Id: ns_parse.c,v 1.3.2.1.4.1 2004/03/09 08:33:44 marka Exp"; +#else +__RCSID("$NetBSD: ns_parse.c,v 1.2 2004/05/20 20:35:05 christos Exp $"); +#endif +#endif + +/* Import. */ + +#include <sys/types.h> + +#include <netinet/in.h> +#include "arpa_nameser.h" + +#include <errno.h> +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include <resolv.h> +#endif +#include <string.h> + +/* Forward. */ + +static void setsection(ns_msg *msg, ns_sect sect); + +/* Macros. */ + +#define RETERR(err) do { errno = (err); return (-1); } while (/*NOTREACHED*//*CONSTCOND*/0) + +/* Public. */ + +/* These need to be in the same order as the nres.h:ns_flag enum. */ +const struct _ns_flagdata _ns_flagdata[16] = { + { 0x8000, 15 }, /* qr. */ + { 0x7800, 11 }, /* opcode. */ + { 0x0400, 10 }, /* aa. */ + { 0x0200, 9 }, /* tc. */ + { 0x0100, 8 }, /* rd. */ + { 0x0080, 7 }, /* ra. */ + { 0x0040, 6 }, /* z. */ + { 0x0020, 5 }, /* ad. */ + { 0x0010, 4 }, /* cd. */ + { 0x000f, 0 }, /* rcode. */ + { 0x0000, 0 }, /* expansion (1/6). */ + { 0x0000, 0 }, /* expansion (2/6). */ + { 0x0000, 0 }, /* expansion (3/6). */ + { 0x0000, 0 }, /* expansion (4/6). */ + { 0x0000, 0 }, /* expansion (5/6). */ + { 0x0000, 0 }, /* expansion (6/6). */ +}; + +int ns_msg_getflag(ns_msg handle, int flag) { + return((u_int32_t)((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift); +} + +int +ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { + const u_char *optr = ptr; + + for (; count > 0; count--) { + int b, rdlength; + + b = dn_skipname(ptr, eom); + if (b < 0) + RETERR(EMSGSIZE); + ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/; + if (section != ns_s_qd) { + if (ptr + NS_INT32SZ + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + ptr += NS_INT32SZ/*TTL*/; + NS_GET16(rdlength, ptr); + ptr += rdlength/*RData*/; + } + } + if (ptr > eom) + RETERR(EMSGSIZE); + return (ptr - optr); +} + +int +ns_initparse(const u_char *msg, int msglen, ns_msg *handle) { + const u_char *eom = msg + msglen; + int i; + + memset(handle, 0x5e, sizeof *handle); + handle->_msg = msg; + handle->_eom = eom; + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + NS_GET16(handle->_id, msg); + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + NS_GET16(handle->_flags, msg); + for (i = 0; i < ns_s_max; i++) { + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + NS_GET16(handle->_counts[i], msg); + } + for (i = 0; i < ns_s_max; i++) + if (handle->_counts[i] == 0) + handle->_sections[i] = NULL; + else { + int b = ns_skiprr(msg, eom, (ns_sect)i, + handle->_counts[i]); + + if (b < 0) + return (-1); + handle->_sections[i] = msg; + msg += b; + } + if (msg != eom) + RETERR(EMSGSIZE); + setsection(handle, ns_s_max); + return (0); +} + +int +ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) { + int b; + + /* Make section right. */ + if ((unsigned)section >= (unsigned)ns_s_max) + RETERR(ENODEV); + if (section != handle->_sect) + setsection(handle, section); + + /* Make rrnum right. */ + if (rrnum == -1) + rrnum = handle->_rrnum; + if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) + RETERR(ENODEV); + if (rrnum < handle->_rrnum) + setsection(handle, section); + if (rrnum > handle->_rrnum) { + b = ns_skiprr(handle->_msg_ptr, handle->_eom, section, + rrnum - handle->_rrnum); + + if (b < 0) + return (-1); + handle->_msg_ptr += b; + handle->_rrnum = rrnum; + } + + /* Do the parse. */ + b = dn_expand(handle->_msg, handle->_eom, + handle->_msg_ptr, rr->name, NS_MAXDNAME); + if (b < 0) + return (-1); + handle->_msg_ptr += b; + if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); + NS_GET16(rr->type, handle->_msg_ptr); + NS_GET16(rr->rr_class, handle->_msg_ptr); + if (section == ns_s_qd) { + rr->ttl = 0; + rr->rdlength = 0; + rr->rdata = NULL; + } else { + if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); + NS_GET32(rr->ttl, handle->_msg_ptr); + NS_GET16(rr->rdlength, handle->_msg_ptr); + if (handle->_msg_ptr + rr->rdlength > handle->_eom) + RETERR(EMSGSIZE); + rr->rdata = handle->_msg_ptr; + handle->_msg_ptr += rr->rdlength; + } + if (++handle->_rrnum > handle->_counts[(int)section]) + setsection(handle, (ns_sect)((int)section + 1)); + + /* All done. */ + return (0); +} + +/* Private. */ + +static void +setsection(ns_msg *msg, ns_sect sect) { + msg->_sect = sect; + if (sect == ns_s_max) { + msg->_rrnum = -1; + msg->_msg_ptr = NULL; + } else { + msg->_rrnum = 0; + msg->_msg_ptr = msg->_sections[(int)sect]; + } +} diff --git a/libc/netbsd/nameser/ns_print.c b/libc/netbsd/nameser/ns_print.c new file mode 100644 index 0000000..7465e62 --- /dev/null +++ b/libc/netbsd/nameser/ns_print.c @@ -0,0 +1,915 @@ +/* $NetBSD: ns_print.c,v 1.5 2004/11/07 02:19:49 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +#ifndef lint +#ifdef notdef +static const char rcsid[] = "Id: ns_print.c,v 1.3.2.1.4.5 2004/07/28 20:16:45 marka Exp"; +#else +__RCSID("$NetBSD: ns_print.c,v 1.5 2004/11/07 02:19:49 christos Exp $"); +#endif +#endif + +/* Import. */ + +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include "arpa_nameser.h" +#include <arpa/inet.h> + +#include <isc/assertions.h> +#include <isc/dst.h> +#include <errno.h> +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include <resolv.h> +#endif +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +#ifndef MIN +#define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + +/* Forward. */ + +static size_t prune_origin(const char *name, const char *origin); +static int charstr(const u_char *rdata, const u_char *edata, + char **buf, size_t *buflen); +static int addname(const u_char *msg, size_t msglen, + const u_char **p, const char *origin, + char **buf, size_t *buflen); +static void addlen(size_t len, char **buf, size_t *buflen); +static int addstr(const char *src, size_t len, + char **buf, size_t *buflen); +static int addtab(size_t len, size_t target, int spaced, + char **buf, size_t *buflen); + +/* Macros. */ + +#define T(x) \ + do { \ + if ((x) < 0) \ + return (-1); \ + } while (/*CONSTCOND*/0) + +/* Public. */ + +/* + * int + * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen) + * Convert an RR to presentation format. + * return: + * Number of characters written to buf, or -1 (check errno). + */ +int +ns_sprintrr(const ns_msg *handle, const ns_rr *rr, + const char *name_ctx, const char *origin, + char *buf, size_t buflen) +{ + int n; + + n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle), + ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr), + ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr), + name_ctx, origin, buf, buflen); + return (n); +} + +/* + * int + * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen, + * name_ctx, origin, buf, buflen) + * Convert the fields of an RR into presentation format. + * return: + * Number of characters written to buf, or -1 (check errno). + */ +int +ns_sprintrrf(const u_char *msg, size_t msglen, + const char *name, ns_class class, ns_type type, + u_long ttl, const u_char *rdata, size_t rdlen, + const char *name_ctx, const char *origin, + char *buf, size_t buflen) +{ + const char *obuf = buf; + const u_char *edata = rdata + rdlen; + int spaced = 0; + + const char *comment; + char tmp[100]; + int len, x; + + /* + * Owner. + */ + if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) { + T(addstr("\t\t\t", (size_t)3, &buf, &buflen)); + } else { + len = prune_origin(name, origin); + if (*name == '\0') { + goto root; + } else if (len == 0) { + T(addstr("@\t\t\t", (size_t)4, &buf, &buflen)); + } else { + T(addstr(name, (size_t)len, &buf, &buflen)); + /* Origin not used or not root, and no trailing dot? */ + if (((origin == NULL || origin[0] == '\0') || + (origin[0] != '.' && origin[1] != '\0' && + name[len] == '\0')) && name[len - 1] != '.') { + root: + T(addstr(".", (size_t)1, &buf, &buflen)); + len++; + } + T(spaced = addtab((size_t)len, 24, spaced, &buf, &buflen)); + } + } + + /* + * TTL, Class, Type. + */ + T(x = ns_format_ttl(ttl, buf, buflen)); + addlen((size_t)x, &buf, &buflen); + len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type))); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + T(spaced = addtab((size_t)(x + len), (size_t)16, spaced, &buf, &buflen)); + + /* + * RData. + */ + switch (type) { + case ns_t_a: + if (rdlen != (size_t)NS_INADDRSZ) + goto formerr; + (void) inet_ntop(AF_INET, rdata, buf, buflen); + addlen(strlen(buf), &buf, &buflen); + break; + + case ns_t_cname: + case ns_t_mb: + case ns_t_mg: + case ns_t_mr: + case ns_t_ns: + case ns_t_ptr: + case ns_t_dname: + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + break; + + case ns_t_hinfo: + case ns_t_isdn: + /* First word. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", (size_t)1, &buf, &buflen)); + + + /* Second word, optional in ISDN records. */ + if (type == ns_t_isdn && rdata == edata) + break; + + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + break; + + case ns_t_soa: { + u_long t; + + /* Server name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", (size_t)1, &buf, &buflen)); + + /* Administrator name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" (\n", (size_t)3, &buf, &buflen)); + spaced = 0; + + if ((edata - rdata) != 5*NS_INT32SZ) + goto formerr; + + /* Serial number. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); + len = SPRINTF((tmp, "%lu", t)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); + T(addstr("; serial\n", (size_t)9, &buf, &buflen)); + spaced = 0; + + /* Refresh interval. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen((size_t)len, &buf, &buflen); + T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); + T(addstr("; refresh\n", (size_t)10, &buf, &buflen)); + spaced = 0; + + /* Retry interval. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen((size_t)len, &buf, &buflen); + T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); + T(addstr("; retry\n", (size_t)8, &buf, &buflen)); + spaced = 0; + + /* Expiry. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen((size_t)len, &buf, &buflen); + T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); + T(addstr("; expiry\n", (size_t)9, &buf, &buflen)); + spaced = 0; + + /* Minimum TTL. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen)); + T(len = ns_format_ttl(t, buf, buflen)); + addlen((size_t)len, &buf, &buflen); + T(addstr(" )", (size_t)2, &buf, &buflen)); + T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); + T(addstr("; minimum\n", (size_t)10, &buf, &buflen)); + + break; + } + + case ns_t_mx: + case ns_t_afsdb: + case ns_t_rt: { + u_int t; + + if (rdlen < (size_t)NS_INT16SZ) + goto formerr; + + /* Priority. */ + t = ns_get16(rdata); + rdata += NS_INT16SZ; + len = SPRINTF((tmp, "%u ", t)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Target. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + break; + } + + case ns_t_px: { + u_int t; + + if (rdlen < (size_t)NS_INT16SZ) + goto formerr; + + /* Priority. */ + t = ns_get16(rdata); + rdata += NS_INT16SZ; + len = SPRINTF((tmp, "%u ", t)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Name1. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", (size_t)1, &buf, &buflen)); + + /* Name2. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + break; + } + + case ns_t_x25: + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + break; + + case ns_t_txt: + while (rdata < edata) { + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + if (rdata < edata) + T(addstr(" ", (size_t)1, &buf, &buflen)); + } + break; + + case ns_t_nsap: { + char t[2+255*3]; + + (void) inet_nsap_ntoa((int)rdlen, rdata, t); + T(addstr(t, strlen(t), &buf, &buflen)); + break; + } + + case ns_t_aaaa: + if (rdlen != (size_t)NS_IN6ADDRSZ) + goto formerr; + (void) inet_ntop(AF_INET6, rdata, buf, buflen); + addlen(strlen(buf), &buf, &buflen); + break; + + case ns_t_loc: { + char t[255]; + + /* XXX protocol format checking? */ + (void) loc_ntoa(rdata, t); + T(addstr(t, strlen(t), &buf, &buflen)); + break; + } + + case ns_t_naptr: { + u_int order, preference; + char t[50]; + + if (rdlen < 2U*NS_INT16SZ) + goto formerr; + + /* Order, Precedence. */ + order = ns_get16(rdata); rdata += NS_INT16SZ; + preference = ns_get16(rdata); rdata += NS_INT16SZ; + len = SPRINTF((t, "%u %u ", order, preference)); + T(addstr(t, (size_t)len, &buf, &buflen)); + + /* Flags. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", (size_t)1, &buf, &buflen)); + + /* Service. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", (size_t)1, &buf, &buflen)); + + /* Regexp. */ + T(len = charstr(rdata, edata, &buf, &buflen)); + if (len < 0) + return (-1); + if (len == 0) + goto formerr; + rdata += len; + T(addstr(" ", (size_t)1, &buf, &buflen)); + + /* Server. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + break; + } + + case ns_t_srv: { + u_int priority, weight, port; + char t[50]; + + if (rdlen < 3U*NS_INT16SZ) + goto formerr; + + /* Priority, Weight, Port. */ + priority = ns_get16(rdata); rdata += NS_INT16SZ; + weight = ns_get16(rdata); rdata += NS_INT16SZ; + port = ns_get16(rdata); rdata += NS_INT16SZ; + len = SPRINTF((t, "%u %u %u ", priority, weight, port)); + T(addstr(t, (size_t)len, &buf, &buflen)); + + /* Server. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + break; + } + + case ns_t_minfo: + case ns_t_rp: + /* Name1. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", (size_t)1, &buf, &buflen)); + + /* Name2. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + break; + + case ns_t_wks: { + int n, lcnt; + + if (rdlen < 1U + NS_INT32SZ) + goto formerr; + + /* Address. */ + (void) inet_ntop(AF_INET, rdata, buf, buflen); + addlen(strlen(buf), &buf, &buflen); + rdata += NS_INADDRSZ; + + /* Protocol. */ + len = SPRINTF((tmp, " %u ( ", *rdata)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + rdata += NS_INT8SZ; + + /* Bit map. */ + n = 0; + lcnt = 0; + while (rdata < edata) { + u_int c = *rdata++; + do { + if (c & 0200) { + if (lcnt == 0) { + T(addstr("\n\t\t\t\t", (size_t)5, + &buf, &buflen)); + lcnt = 10; + spaced = 0; + } + len = SPRINTF((tmp, "%d ", n)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + lcnt--; + } + c <<= 1; + } while (++n & 07); + } + T(addstr(")", (size_t)1, &buf, &buflen)); + + break; + } + + case ns_t_key: { + char base64_key[NS_MD5RSA_MAX_BASE64]; + u_int keyflags, protocol, algorithm, key_id; + const char *leader; + int n; + + if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ) + goto formerr; + + /* Key flags, Protocol, Algorithm. */ +#ifndef _LIBC + key_id = dst_s_dns_key_id(rdata, edata-rdata); +#else + key_id = 0; +#endif + keyflags = ns_get16(rdata); rdata += NS_INT16SZ; + protocol = *rdata++; + algorithm = *rdata++; + len = SPRINTF((tmp, "0x%04x %u %u", + keyflags, protocol, algorithm)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Public key data. */ + len = b64_ntop(rdata, (size_t)(edata - rdata), + base64_key, sizeof base64_key); + if (len < 0) + goto formerr; + if (len > 15) { + T(addstr(" (", (size_t)2, &buf, &buflen)); + leader = "\n\t\t"; + spaced = 0; + } else + leader = " "; + for (n = 0; n < len; n += 48) { + T(addstr(leader, strlen(leader), &buf, &buflen)); + T(addstr(base64_key + n, (size_t)MIN(len - n, 48), + &buf, &buflen)); + } + if (len > 15) + T(addstr(" )", (size_t)2, &buf, &buflen)); + n = SPRINTF((tmp, " ; key_tag= %u", key_id)); + T(addstr(tmp, (size_t)n, &buf, &buflen)); + + break; + } + + case ns_t_sig: { + char base64_key[NS_MD5RSA_MAX_BASE64]; + u_int typ, algorithm, labels, footprint; + const char *leader; + u_long t; + int n; + + if (rdlen < 22U) + goto formerr; + + /* Type covered, Algorithm, Label count, Original TTL. */ + typ = ns_get16(rdata); rdata += NS_INT16SZ; + algorithm = *rdata++; + labels = *rdata++; + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = SPRINTF((tmp, "%s %d %d %lu ", + p_type((int)typ), algorithm, labels, t)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + if (labels > (u_int)dn_count_labels(name)) + goto formerr; + + /* Signature expiry. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = SPRINTF((tmp, "%s ", p_secstodate(t))); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Time signed. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = SPRINTF((tmp, "%s ", p_secstodate(t))); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Signature Footprint. */ + footprint = ns_get16(rdata); rdata += NS_INT16SZ; + len = SPRINTF((tmp, "%u ", footprint)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Signer's name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + /* Signature. */ + len = b64_ntop(rdata, (size_t)(edata - rdata), + base64_key, sizeof base64_key); + if (len > 15) { + T(addstr(" (", (size_t)2, &buf, &buflen)); + leader = "\n\t\t"; + spaced = 0; + } else + leader = " "; + if (len < 0) + goto formerr; + for (n = 0; n < len; n += 48) { + T(addstr(leader, strlen(leader), &buf, &buflen)); + T(addstr(base64_key + n, (size_t)MIN(len - n, 48), + &buf, &buflen)); + } + if (len > 15) + T(addstr(" )", (size_t)2, &buf, &buflen)); + break; + } + + case ns_t_nxt: { + int n, c; + + /* Next domain name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + /* Type bit map. */ + n = edata - rdata; + for (c = 0; c < n*8; c++) + if (NS_NXT_BIT_ISSET(c, rdata)) { + len = SPRINTF((tmp, " %s", p_type(c))); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + } + break; + } + + case ns_t_cert: { + u_int c_type, key_tag, alg; + int n; + unsigned int siz; + char base64_cert[8192], tmp1[40]; + const char *leader; + + c_type = ns_get16(rdata); rdata += NS_INT16SZ; + key_tag = ns_get16(rdata); rdata += NS_INT16SZ; + alg = (u_int) *rdata++; + + len = SPRINTF((tmp1, "%d %d %d ", c_type, key_tag, alg)); + T(addstr(tmp1, (size_t)len, &buf, &buflen)); + siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */ + if (siz > sizeof(base64_cert) * 3/4) { + const char *str = "record too long to print"; + T(addstr(str, strlen(str), &buf, &buflen)); + } + else { + len = b64_ntop(rdata, (size_t)(edata-rdata), + base64_cert, siz); + + if (len < 0) + goto formerr; + else if (len > 15) { + T(addstr(" (", (size_t)2, &buf, &buflen)); + leader = "\n\t\t"; + spaced = 0; + } + else + leader = " "; + + for (n = 0; n < len; n += 48) { + T(addstr(leader, strlen(leader), + &buf, &buflen)); + T(addstr(base64_cert + n, (size_t)MIN(len - n, 48), + &buf, &buflen)); + } + if (len > 15) + T(addstr(" )", (size_t)2, &buf, &buflen)); + } + break; + } + + case ns_t_tkey: { + /* KJD - need to complete this */ + u_long t; + int mode, err, keysize; + + /* Algorithm name. */ + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", (size_t)1, &buf, &buflen)); + + /* Inception. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = SPRINTF((tmp, "%s ", p_secstodate(t))); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Experation. */ + t = ns_get32(rdata); rdata += NS_INT32SZ; + len = SPRINTF((tmp, "%s ", p_secstodate(t))); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* Mode , Error, Key Size. */ + /* Priority, Weight, Port. */ + mode = ns_get16(rdata); rdata += NS_INT16SZ; + err = ns_get16(rdata); rdata += NS_INT16SZ; + keysize = ns_get16(rdata); rdata += NS_INT16SZ; + len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + + /* XXX need to dump key, print otherdata length & other data */ + break; + } + + case ns_t_tsig: { + /* BEW - need to complete this */ + int n; + + T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen)); + T(addstr(" ", (size_t)1, &buf, &buflen)); + rdata += 8; /* time */ + n = ns_get16(rdata); rdata += INT16SZ; + rdata += n; /* sig */ + n = ns_get16(rdata); rdata += INT16SZ; /* original id */ + sprintf(buf, "%d", ns_get16(rdata)); + rdata += INT16SZ; + addlen(strlen(buf), &buf, &buflen); + break; + } + + case ns_t_a6: { + struct in6_addr a; + int pbyte, pbit; + + /* prefix length */ + if (rdlen == 0U) goto formerr; + len = SPRINTF((tmp, "%d ", *rdata)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + pbit = *rdata; + if (pbit > 128) goto formerr; + pbyte = (pbit & ~7) / 8; + rdata++; + + /* address suffix: provided only when prefix len != 128 */ + if (pbit < 128) { + if (rdata + pbyte >= edata) goto formerr; + memset(&a, 0, sizeof(a)); + memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte); + (void) inet_ntop(AF_INET6, &a, buf, buflen); + addlen(strlen(buf), &buf, &buflen); + rdata += sizeof(a) - pbyte; + } + + /* prefix name: provided only when prefix len > 0 */ + if (pbit == 0) + break; + if (rdata >= edata) goto formerr; + T(addstr(" ", (size_t)1, &buf, &buflen)); + T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); + + break; + } + + case ns_t_opt: { + len = SPRINTF((tmp, "%u bytes", class)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + break; + } + + default: + comment = "unknown RR type"; + goto hexify; + } + return (buf - obuf); + formerr: + comment = "RR format error"; + hexify: { + int n, m; + char *p; + + len = SPRINTF((tmp, "\\# %tu%s\t; %s", edata - rdata, + rdlen != 0 ? " (" : "", comment)); + T(addstr(tmp, (size_t)len, &buf, &buflen)); + while (rdata < edata) { + p = tmp; + p += SPRINTF((p, "\n\t")); + spaced = 0; + n = MIN(16, edata - rdata); + for (m = 0; m < n; m++) + p += SPRINTF((p, "%02x ", rdata[m])); + T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen)); + if (n < 16) { + T(addstr(")", (size_t)1, &buf, &buflen)); + T(addtab((size_t)(p - tmp + 1), (size_t)48, spaced, &buf, &buflen)); + } + p = tmp; + p += SPRINTF((p, "; ")); + for (m = 0; m < n; m++) + *p++ = (isascii(rdata[m]) && isprint(rdata[m])) + ? rdata[m] + : '.'; + T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen)); + rdata += n; + } + return (buf - obuf); + } +} + +/* Private. */ + +/* + * size_t + * prune_origin(name, origin) + * Find out if the name is at or under the current origin. + * return: + * Number of characters in name before start of origin, + * or length of name if origin does not match. + * notes: + * This function should share code with samedomain(). + */ +static size_t +prune_origin(const char *name, const char *origin) { + const char *oname = name; + + while (*name != '\0') { + if (origin != NULL && ns_samename(name, origin) == 1) + return (name - oname - (name > oname)); + while (*name != '\0') { + if (*name == '\\') { + name++; + /* XXX need to handle \nnn form. */ + if (*name == '\0') + break; + } else if (*name == '.') { + name++; + break; + } + name++; + } + } + return (name - oname); +} + +/* + * int + * charstr(rdata, edata, buf, buflen) + * Format a <character-string> into the presentation buffer. + * return: + * Number of rdata octets consumed + * 0 for protocol format error + * -1 for output buffer error + * side effects: + * buffer is advanced on success. + */ +static int +charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) { + const u_char *odata = rdata; + size_t save_buflen = *buflen; + char *save_buf = *buf; + + if (addstr("\"", (size_t)1, buf, buflen) < 0) + goto enospc; + if (rdata < edata) { + int n = *rdata; + + if (rdata + 1 + n <= edata) { + rdata++; + while (n-- > 0) { + if (strchr("\n\"\\", *rdata) != NULL) + if (addstr("\\", (size_t)1, buf, buflen) < 0) + goto enospc; + if (addstr((const char *)rdata, (size_t)1, + buf, buflen) < 0) + goto enospc; + rdata++; + } + } + } + if (addstr("\"", (size_t)1, buf, buflen) < 0) + goto enospc; + return (rdata - odata); + enospc: + errno = ENOSPC; + *buf = save_buf; + *buflen = save_buflen; + return (-1); +} + +static int +addname(const u_char *msg, size_t msglen, + const u_char **pp, const char *origin, + char **buf, size_t *buflen) +{ + size_t newlen, save_buflen = *buflen; + char *save_buf = *buf; + int n; + + n = dn_expand(msg, msg + msglen, *pp, *buf, (int)*buflen); + if (n < 0) + goto enospc; /* Guess. */ + newlen = prune_origin(*buf, origin); + if (**buf == '\0') { + goto root; + } else if (newlen == 0U) { + /* Use "@" instead of name. */ + if (newlen + 2 > *buflen) + goto enospc; /* No room for "@\0". */ + (*buf)[newlen++] = '@'; + (*buf)[newlen] = '\0'; + } else { + if (((origin == NULL || origin[0] == '\0') || + (origin[0] != '.' && origin[1] != '\0' && + (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') { + /* No trailing dot. */ + root: + if (newlen + 2 > *buflen) + goto enospc; /* No room for ".\0". */ + (*buf)[newlen++] = '.'; + (*buf)[newlen] = '\0'; + } + } + *pp += n; + addlen(newlen, buf, buflen); + **buf = '\0'; + return (newlen); + enospc: + errno = ENOSPC; + *buf = save_buf; + *buflen = save_buflen; + return (-1); +} + +static void +addlen(size_t len, char **buf, size_t *buflen) { + assert(len <= *buflen); + *buf += len; + *buflen -= len; +} + +static int +addstr(const char *src, size_t len, char **buf, size_t *buflen) { + if (len >= *buflen) { + errno = ENOSPC; + return (-1); + } + memcpy(*buf, src, len); + addlen(len, buf, buflen); + **buf = '\0'; + return (0); +} + +static int +addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) { + size_t save_buflen = *buflen; + char *save_buf = *buf; + int t; + + if (spaced || len >= target - 1) { + T(addstr(" ", (size_t)2, buf, buflen)); + spaced = 1; + } else { + for (t = (target - len - 1) / 8; t >= 0; t--) + if (addstr("\t", (size_t)1, buf, buflen) < 0) { + *buflen = save_buflen; + *buf = save_buf; + return (-1); + } + spaced = 0; + } + return (spaced); +} diff --git a/libc/netbsd/nameser/ns_samedomain.c b/libc/netbsd/nameser/ns_samedomain.c new file mode 100644 index 0000000..04fdb61 --- /dev/null +++ b/libc/netbsd/nameser/ns_samedomain.c @@ -0,0 +1,211 @@ +/* $NetBSD: ns_samedomain.c,v 1.2 2004/05/20 20:35:05 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1995,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +#ifndef lint +#ifdef notdef +static const char rcsid[] = "Id: ns_samedomain.c,v 1.1.2.2.4.2 2004/03/16 12:34:17 marka Exp"; +#else +__RCSID("$NetBSD: ns_samedomain.c,v 1.2 2004/05/20 20:35:05 christos Exp $"); +#endif +#endif + +#include <sys/types.h> +#include "arpa_nameser.h" +#include <errno.h> +#include <string.h> + +#ifndef _LIBC +/* + * int + * ns_samedomain(a, b) + * Check whether a name belongs to a domain. + * Inputs: + * a - the domain whose ancestory is being verified + * b - the potential ancestor we're checking against + * Return: + * boolean - is a at or below b? + * Notes: + * Trailing dots are first removed from name and domain. + * Always compare complete subdomains, not only whether the + * domain name is the trailing string of the given name. + * + * "host.foobar.top" lies in "foobar.top" and in "top" and in "" + * but NOT in "bar.top" + */ + +int +ns_samedomain(const char *a, const char *b) { + size_t la, lb; + int diff, i, escaped; + const char *cp; + + la = strlen(a); + lb = strlen(b); + + /* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */ + if (la != 0U && a[la - 1] == '.') { + escaped = 0; + /* Note this loop doesn't get executed if la==1. */ + for (i = la - 2; i >= 0; i--) + if (a[i] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else + break; + if (!escaped) + la--; + } + + /* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */ + if (lb != 0U && b[lb - 1] == '.') { + escaped = 0; + /* note this loop doesn't get executed if lb==1 */ + for (i = lb - 2; i >= 0; i--) + if (b[i] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else + break; + if (!escaped) + lb--; + } + + /* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */ + if (lb == 0U) + return (1); + + /* 'b' longer than 'a' means 'a' can't be in 'b'. */ + if (lb > la) + return (0); + + /* 'a' and 'b' being equal at this point indicates sameness. */ + if (lb == la) + return (strncasecmp(a, b, lb) == 0); + + /* Ok, we know la > lb. */ + + diff = la - lb; + + /* + * If 'a' is only 1 character longer than 'b', then it can't be + * a subdomain of 'b' (because of the need for the '.' label + * separator). + */ + if (diff < 2) + return (0); + + /* + * If the character before the last 'lb' characters of 'b' + * isn't '.', then it can't be a match (this lets us avoid + * having "foobar.com" match "bar.com"). + */ + if (a[diff - 1] != '.') + return (0); + + /* + * We're not sure about that '.', however. It could be escaped + * and thus not a really a label separator. + */ + escaped = 0; + for (i = diff - 2; i >= 0; i--) + if (a[i] == '\\') { + if (escaped) + escaped = 0; + else + escaped = 1; + } else + break; + if (escaped) + return (0); + + /* Now compare aligned trailing substring. */ + cp = a + diff; + return (strncasecmp(cp, b, lb) == 0); +} + +/* + * int + * ns_subdomain(a, b) + * is "a" a subdomain of "b"? + */ +int +ns_subdomain(const char *a, const char *b) { + return (ns_samename(a, b) != 1 && ns_samedomain(a, b)); +} +#endif + +/* + * int + * ns_makecanon(src, dst, dstsize) + * make a canonical copy of domain name "src" + * notes: + * foo -> foo. + * foo. -> foo. + * foo.. -> foo. + * foo\. -> foo\.. + * foo\\. -> foo\\. + */ + +int +ns_makecanon(const char *src, char *dst, size_t dstsize) { + size_t n = strlen(src); + + if (n + sizeof "." > dstsize) { /* Note: sizeof == 2 */ + errno = EMSGSIZE; + return (-1); + } + strcpy(dst, src); + while (n >= 1U && dst[n - 1] == '.') /* Ends in "." */ + if (n >= 2U && dst[n - 2] == '\\' && /* Ends in "\." */ + (n < 3U || dst[n - 3] != '\\')) /* But not "\\." */ + break; + else + dst[--n] = '\0'; + dst[n++] = '.'; + dst[n] = '\0'; + return (0); +} + +/* + * int + * ns_samename(a, b) + * determine whether domain name "a" is the same as domain name "b" + * return: + * -1 on error + * 0 if names differ + * 1 if names are the same + */ + +int +ns_samename(const char *a, const char *b) { + char ta[NS_MAXDNAME], tb[NS_MAXDNAME]; + + if (ns_makecanon(a, ta, sizeof ta) < 0 || + ns_makecanon(b, tb, sizeof tb) < 0) + return (-1); + if (strcasecmp(ta, tb) == 0) + return (1); + else + return (0); +} diff --git a/libc/netbsd/nameser/ns_ttl.c b/libc/netbsd/nameser/ns_ttl.c new file mode 100644 index 0000000..0878194 --- /dev/null +++ b/libc/netbsd/nameser/ns_ttl.c @@ -0,0 +1,164 @@ +/* $NetBSD: ns_ttl.c,v 1.2 2004/05/20 20:35:05 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +#ifndef lint +#ifdef notdef +static const char rcsid[] = "Id: ns_ttl.c,v 1.1.206.1 2004/03/09 08:33:45 marka Exp"; +#else +__RCSID("$NetBSD: ns_ttl.c,v 1.2 2004/05/20 20:35:05 christos Exp $"); +#endif +#endif + +/* Import. */ + +#include "arpa_nameser.h" + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +/* Forward. */ + +static int fmt1(int t, char s, char **buf, size_t *buflen); + +/* Macros. */ + +#define T(x) if ((x) < 0) return (-1); else + +/* Public. */ + +int +ns_format_ttl(u_long src, char *dst, size_t dstlen) { + char *odst = dst; + int secs, mins, hours, days, weeks, x; + char *p; + + secs = src % 60; src /= 60; + mins = src % 60; src /= 60; + hours = src % 24; src /= 24; + days = src % 7; src /= 7; + weeks = src; src = 0; + + x = 0; + if (weeks) { + T(fmt1(weeks, 'W', &dst, &dstlen)); + x++; + } + if (days) { + T(fmt1(days, 'D', &dst, &dstlen)); + x++; + } + if (hours) { + T(fmt1(hours, 'H', &dst, &dstlen)); + x++; + } + if (mins) { + T(fmt1(mins, 'M', &dst, &dstlen)); + x++; + } + if (secs || !(weeks || days || hours || mins)) { + T(fmt1(secs, 'S', &dst, &dstlen)); + x++; + } + + if (x > 1) { + int ch; + + for (p = odst; (ch = *p) != '\0'; p++) + if (isascii(ch) && isupper(ch)) + *p = tolower(ch); + } + + return (dst - odst); +} + +#ifndef _LIBC +int +ns_parse_ttl(const char *src, u_long *dst) { + u_long ttl, tmp; + int ch, digits, dirty; + + ttl = 0; + tmp = 0; + digits = 0; + dirty = 0; + while ((ch = *src++) != '\0') { + if (!isascii(ch) || !isprint(ch)) + goto einval; + if (isdigit(ch)) { + tmp *= 10; + tmp += (ch - '0'); + digits++; + continue; + } + if (digits == 0) + goto einval; + if (islower(ch)) + ch = toupper(ch); + switch (ch) { + case 'W': tmp *= 7; /*FALLTHROUGH*/ + case 'D': tmp *= 24; /*FALLTHROUGH*/ + case 'H': tmp *= 60; /*FALLTHROUGH*/ + case 'M': tmp *= 60; /*FALLTHROUGH*/ + case 'S': break; + default: goto einval; + } + ttl += tmp; + tmp = 0; + digits = 0; + dirty = 1; + } + if (digits > 0) { + if (dirty) + goto einval; + else + ttl += tmp; + } + *dst = ttl; + return (0); + + einval: + errno = EINVAL; + return (-1); +} +#endif + +/* Private. */ + +static int +fmt1(int t, char s, char **buf, size_t *buflen) { + char tmp[50]; + size_t len; + + len = SPRINTF((tmp, "%d%c", t, s)); + if (len + 1 > *buflen) + return (-1); + strcpy(*buf, tmp); + *buf += len; + *buflen -= len; + return (0); +} diff --git a/libc/netbsd/net/base64.c b/libc/netbsd/net/base64.c new file mode 100644 index 0000000..70caaf7 --- /dev/null +++ b/libc/netbsd/net/base64.c @@ -0,0 +1,340 @@ +/* $NetBSD: base64.c,v 1.8 2002/11/11 01:15:17 thorpej Exp $ */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: base64.c,v 1.8 2002/11/11 01:15:17 thorpej Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "arpa_nameser.h" + +#include <assert.h> +#include <ctype.h> +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include <resolv.h> +#endif +#include <stdio.h> + +#include <stdlib.h> +#include <string.h> + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +int +b64_ntop(src, srclength, target, targsize) + u_char const *src; + size_t srclength; + char *target; + size_t targsize; +{ + size_t datalength = 0; + u_char input[3]; + u_char output[4]; + size_t i; + + assert(src != NULL); + assert(target != NULL); + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = (u_int32_t)input[0] >> 2; + output[1] = ((u_int32_t)(input[0] & 0x03) << 4) + + ((u_int32_t)input[1] >> 4); + output[2] = ((u_int32_t)(input[1] & 0x0f) << 2) + + ((u_int32_t)input[2] >> 6); + output[3] = input[2] & 0x3f; + assert(output[0] < 64); + assert(output[1] < 64); + assert(output[2] < 64); + assert(output[3] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = (u_int32_t)input[0] >> 2; + output[1] = ((u_int32_t)(input[0] & 0x03) << 4) + + ((u_int32_t)input[1] >> 4); + output[2] = ((u_int32_t)(input[1] & 0x0f) << 2) + + ((u_int32_t)input[2] >> 6); + assert(output[0] < 64); + assert(output[1] < 64); + assert(output[2] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (datalength); +} + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +b64_pton(src, target, targsize) + char const *src; + u_char *target; + size_t targsize; +{ + size_t tarindex; + int state, ch; + char *pos; + + assert(src != NULL); + assert(target != NULL); + + state = 0; + tarindex = 0; + + while ((ch = (u_char) *src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= + (u_int32_t)(pos - Base64) >> 4; + target[tarindex+1] = ((pos - Base64) & 0x0f) + << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= + (u_int32_t)(pos - Base64) >> 2; + target[tarindex+1] = ((pos - Base64) & 0x03) + << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + default: + abort(); + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for (; ch != '\0'; ch = (u_char) *src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for (; ch != '\0'; ch = (u_char) *src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} diff --git a/libc/netbsd/net/getaddrinfo.c b/libc/netbsd/net/getaddrinfo.c new file mode 100644 index 0000000..2dd3d97 --- /dev/null +++ b/libc/netbsd/net/getaddrinfo.c @@ -0,0 +1,1792 @@ +/* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ +/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * 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 + * getipnodebyname(). + * - The code filters out AFs that are not supported by the kernel, + * when globbing NULL hostname (to loopback, or wildcard). Is it the right + * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG + * in ai_flags? + * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. + * (1) what should we do against numeric hostname (2) what should we do + * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? + * non-loopback address configured? global address configured? + * - To avoid search order issue, we have a big amount of code duplicate + * from gethnamaddr.c and some other places. The issues that there's no + * lower layer function to lookup "IPv4 or IPv6" record. Calling + * gethostbyname2 from getaddrinfo will end up in wrong search order, as + * follows: + * - The code makes use of following calls when asked to resolver with + * ai_family = PF_UNSPEC: + * getipnodebyname(host, AF_INET6); + * getipnodebyname(host, AF_INET); + * This will result in the following queries if the node is configure to + * prefer /etc/hosts than DNS: + * lookup /etc/hosts for IPv6 address + * lookup DNS for IPv6 address + * lookup /etc/hosts for IPv4 address + * lookup DNS for IPv4 address + * which may not meet people's requirement. + * The right thing to happen is to have underlying layer which does + * PF_UNSPEC lookup (lookup both) and return chain of addrinfos. + * This would result in a bit of code duplicate with _dns_ghbyname() and + * friends. + */ + +#include <sys/cdefs.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "arpa_nameser.h" +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include "resolv_private.h" +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <syslog.h> +#include <stdarg.h> +#include "nsswitch.h" + +#define SUCCESS 0 +#define ANY 0 +#define YES 1 +#define NO 0 + +static const char in_addrany[] = { 0, 0, 0, 0 }; +static const char in_loopback[] = { 127, 0, 0, 1 }; +#ifdef INET6 +static const char in6_addrany[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +static const char in6_loopback[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 +}; +#endif + +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 + {PF_INET6, sizeof(struct in6_addr), + sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr), + 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, 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 }, + { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, + { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, + { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, + { -1, 0, 0, NULL, 0 }, +}; + +#ifdef INET6 +#define PTON_MAX 16 +#else +#define PTON_MAX 4 +#endif + +static const ns_src default_dns_files[] = { + { NSSRC_FILES, NS_SUCCESS }, + { NSSRC_DNS, NS_SUCCESS }, + { 0, 0 } +}; + +#define MAXPACKET (64*1024) + +typedef union { + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf; + +struct res_target { + struct res_target *next; + const char *name; /* domain name */ + int qclass, qtype; /* class and type of query */ + u_char *answer; /* buffer to put answer */ + int anslen; /* size of answer buffer */ + int n; /* result length */ +}; + +static int str2number(const char *); +static int explore_fqdn(const struct addrinfo *, const char *, + const char *, struct addrinfo **); +static int explore_null(const struct addrinfo *, + const char *, struct addrinfo **); +static int explore_numeric(const struct addrinfo *, const char *, + const char *, struct addrinfo **, const char *); +static int explore_numeric_scope(const struct addrinfo *, const char *, + const char *, struct addrinfo **); +static int get_canonname(const struct addrinfo *, + struct addrinfo *, const char *); +static struct addrinfo *get_ai(const struct addrinfo *, + const struct afd *, const char *); +static int get_portmatch(const struct addrinfo *, const char *); +static int get_port(const struct addrinfo *, const char *, int); +static const struct afd *find_afd(int); +#ifdef INET6 +static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *); +#endif + +static struct addrinfo *getanswer(const querybuf *, int, const char *, int, + const struct addrinfo *); +static void aisort(struct addrinfo *s, res_state res); +static int _dns_getaddrinfo(void *, void *, va_list); +static void _sethtent(FILE **); +static void _endhtent(FILE **); +static struct addrinfo *_gethtent(FILE **, const char *, + const struct addrinfo *); +static int _files_getaddrinfo(void *, void *, va_list); + +static int res_queryN(const char *, struct res_target *, res_state); +static int res_searchN(const char *, struct res_target *, res_state); +static int res_querydomainN(const char *, const char *, + struct res_target *, res_state); + +static const char * const ai_errlist[] = { + "Success", + "Address family for hostname not supported", /* EAI_ADDRFAMILY */ + "Temporary failure in name resolution", /* EAI_AGAIN */ + "Invalid value for ai_flags", /* EAI_BADFLAGS */ + "Non-recoverable failure in name resolution", /* EAI_FAIL */ + "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 */ + "servname not supported for ai_socktype", /* EAI_SERVICE */ + "ai_socktype not supported", /* EAI_SOCKTYPE */ + "System error returned in errno", /* EAI_SYSTEM */ + "Invalid value for hints", /* EAI_BADHINTS */ + "Resolved protocol is unknown", /* EAI_PROTOCOL */ + "Argument buffer overflow", /* EAI_OVERFLOW */ + "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 (/*CONSTCOND*/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 (/*CONSTCOND*/0) + +#define GET_CANONNAME(ai, str) \ +do { \ + /* external reference: pai, error and label free */ \ + error = get_canonname(pai, (ai), (str)); \ + if (error != 0) \ + goto free; \ +} while (/*CONSTCOND*/0) + +#define ERR(err) \ +do { \ + /* external reference: error, and label bad */ \ + error = (err); \ + goto bad; \ + /*NOTREACHED*/ \ +} while (/*CONSTCOND*/0) + +#define MATCH_FAMILY(x, y, w) \ + ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || \ + (y) == PF_UNSPEC))) +#define MATCH(x, y, w) \ + ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) + +const char * +gai_strerror(int ecode) +{ + if (ecode < 0 || ecode > EAI_MAX) + ecode = EAI_MAX; + return ai_errlist[ecode]; +} + +void +freeaddrinfo(struct addrinfo *ai) +{ + struct addrinfo *next; + + assert(ai != NULL); + + do { + next = ai->ai_next; + if (ai->ai_canonname) + free(ai->ai_canonname); + /* no need to free(ai->ai_addr) */ + free(ai); + ai = next; + } while (ai); +} + +static int +str2number(const char *p) +{ + char *ep; + unsigned long v; + + assert(p != NULL); + + if (*p == '\0') + return -1; + ep = NULL; + errno = 0; + v = strtoul(p, &ep, 10); + if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) + return v; + else + return -1; +} + +int +getaddrinfo(const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + struct addrinfo sentinel; + struct addrinfo *cur; + int error = 0; + struct addrinfo ai; + struct addrinfo ai0; + struct addrinfo *pai; + const struct explore *ex; + + /* hostname is allowed to be NULL */ + /* servname is allowed to be NULL */ + /* hints is allowed to be NULL */ + assert(res != NULL); + + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + pai = &ai; + pai->ai_flags = 0; + pai->ai_family = PF_UNSPEC; + pai->ai_socktype = ANY; + pai->ai_protocol = ANY; + pai->ai_addrlen = 0; + pai->ai_canonname = NULL; + pai->ai_addr = NULL; + pai->ai_next = NULL; + + if (hostname == NULL && servname == NULL) + return EAI_NONAME; + if (hints) { + /* error check for hints */ + if (hints->ai_addrlen || hints->ai_canonname || + hints->ai_addr || hints->ai_next) + ERR(EAI_BADHINTS); /* xxx */ + if (hints->ai_flags & ~AI_MASK) + ERR(EAI_BADFLAGS); + switch (hints->ai_family) { + case PF_UNSPEC: + case PF_INET: +#ifdef INET6 + case PF_INET6: +#endif + break; + default: + ERR(EAI_FAMILY); + } + memcpy(pai, hints, sizeof(*pai)); + + /* + * 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); + } + } + } + } + + /* + * 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 (MATCH_FAMILY(pai->ai_family, PF_INET, 1) +#ifdef PF_INET6 + || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) +#endif + ) { + ai0 = *pai; /* backup *pai */ + + 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); + + *pai = ai0; + } + + ai0 = *pai; + + /* NULL hostname, or numeric hostname */ + for (ex = explore; ex->e_af >= 0; ex++) { + *pai = ai0; + + /* PF_UNSPEC entries are prepared for DNS queries only */ + if (ex->e_af == PF_UNSPEC) + continue; + + 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, servname, &cur->ai_next); + else + error = explore_numeric_scope(pai, hostname, servname, + &cur->ai_next); + + if (error) + goto free; + + while (cur->ai_next) + cur = cur->ai_next; + } + + /* + * XXX + * If numeric 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 (hostname == NULL) + ERR(EAI_NODATA); + if (pai->ai_flags & AI_NUMERICHOST) + 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 (ex = explore; ex->e_af >= 0; ex++) { + *pai = ai0; + + /* require exact match for family field */ + if (pai->ai_family != ex->e_af) + 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_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(const struct addrinfo *pai, const char *hostname, + const char *servname, struct addrinfo **res) +{ + struct addrinfo *result; + struct addrinfo *cur; + int error = 0; + static const ns_dtab dtab[] = { + NS_FILES_CB(_files_getaddrinfo, NULL) + { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ + NS_NIS_CB(_yp_getaddrinfo, NULL) + { 0, 0, 0 } + }; + + assert(pai != NULL); + /* hostname may be NULL */ + /* servname may be NULL */ + assert(res != NULL); + + result = NULL; + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", + default_dns_files, hostname, pai)) { + case NS_TRYAGAIN: + error = EAI_AGAIN; + goto free; + case NS_UNAVAIL: + error = EAI_FAIL; + goto free; + case NS_NOTFOUND: + error = EAI_NODATA; + goto free; + case NS_SUCCESS: + error = 0; + for (cur = result; cur; cur = cur->ai_next) { + GET_PORT(cur, servname); + /* canonname should be filled already */ + } + break; + } + + *res = result; + + return 0; + +free: + if (result) + freeaddrinfo(result); + 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(const struct addrinfo *pai, const char *servname, + struct addrinfo **res) +{ + int s; + const struct afd *afd; + struct addrinfo *cur; + struct addrinfo sentinel; + int error; + + assert(pai != NULL); + /* servname may be NULL */ + assert(res != NULL); + + *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 (afd == NULL) + return 0; + + 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(const struct addrinfo *pai, const char *hostname, + const char *servname, struct addrinfo **res, const char *canonname) +{ + const struct afd *afd; + struct addrinfo *cur; + struct addrinfo sentinel; + int error; + char pton[PTON_MAX]; + + assert(pai != NULL); + /* hostname may be NULL */ + /* servname may be NULL */ + assert(res != NULL); + + *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); + if (afd == NULL) + return 0; + + 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); + if ((pai->ai_flags & AI_CANONNAME)) { + /* + * Set the numeric address itself as + * the canonical name, based on a + * clarification in rfc2553bis-03. + */ + GET_CANONNAME(cur->ai_next, canonname); + } + 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); + if ((pai->ai_flags & AI_CANONNAME)) { + /* + * Set the numeric address itself as + * the canonical name, based on a + * clarification in rfc2553bis-03. + */ + GET_CANONNAME(cur->ai_next, canonname); + } + while (cur->ai_next) + cur = cur->ai_next; + } else + ERR(EAI_FAMILY); /*xxx*/ + } + break; + } + + *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(const struct addrinfo *pai, const char *hostname, + const char *servname, struct addrinfo **res) +{ +#if !defined(SCOPE_DELIMITER) || !defined(INET6) + return explore_numeric(pai, hostname, servname, res, hostname); +#else + const struct afd *afd; + struct addrinfo *cur; + int error; + char *cp, *hostname2 = NULL, *scope, *addr; + struct sockaddr_in6 *sin6; + + assert(pai != NULL); + /* hostname may be NULL */ + /* servname may be NULL */ + assert(res != NULL); + + /* + * 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 == NULL) + return 0; + + if (!afd->a_scoped) + return explore_numeric(pai, hostname, servname, res, hostname); + + cp = strchr(hostname, SCOPE_DELIMITER); + if (cp == NULL) + return explore_numeric(pai, hostname, servname, res, hostname); + + /* + * Handle special case of <scoped_address><delimiter><scope id> + */ + hostname2 = strdup(hostname); + if (hostname2 == NULL) + return EAI_MEMORY; + /* terminate at the delimiter */ + hostname2[cp - hostname] = '\0'; + addr = hostname2; + scope = cp + 1; + + error = explore_numeric(pai, addr, servname, res, hostname); + if (error == 0) { + u_int32_t scopeid; + + for (cur = *res; cur; cur = cur->ai_next) { + if (cur->ai_family != AF_INET6) + continue; + sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; + if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { + free(hostname2); + return(EAI_NODATA); /* XXX: is return OK? */ + } + sin6->sin6_scope_id = scopeid; + } + } + + free(hostname2); + + return error; +#endif +} + +static int +get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str) +{ + + assert(pai != NULL); + assert(ai != NULL); + assert(str != NULL); + + if ((pai->ai_flags & AI_CANONNAME) != 0) { + ai->ai_canonname = strdup(str); + if (ai->ai_canonname == NULL) + return EAI_MEMORY; + } + return 0; +} + +static struct addrinfo * +get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr) +{ + char *p; + struct addrinfo *ai; + + assert(pai != NULL); + assert(afd != NULL); + assert(addr != NULL); + + ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + + (afd->a_socklen)); + if (ai == NULL) + return NULL; + + memcpy(ai, pai, sizeof(struct addrinfo)); + ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); + memset(ai->ai_addr, 0, (size_t)afd->a_socklen); + +#ifdef HAVE_SA_LEN + ai->ai_addr->sa_len = afd->a_socklen; +#endif + + ai->ai_addrlen = afd->a_socklen; +#if defined (__alpha__) || (defined(__i386__) && defined(_LP64)) || defined(__sparc64__) + ai->__ai_pad0 = 0; +#endif + ai->ai_addr->sa_family = ai->ai_family = afd->a_af; + p = (char *)(void *)(ai->ai_addr); + memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); + return ai; +} + +static int +get_portmatch(const struct addrinfo *ai, const char *servname) +{ + + assert(ai != NULL); + /* servname may be NULL */ + + return get_port(ai, servname, 1); +} + +static int +get_port(const struct addrinfo *ai, const char *servname, int matchonly) +{ + const char *proto; + struct servent *sp; + int port; + int allownumeric; + + assert(ai != NULL); + /* servname may be NULL */ + + if (servname == NULL) + return 0; + 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: + return EAI_SERVICE; + case SOCK_DGRAM: + case SOCK_STREAM: + allownumeric = 1; + break; + case ANY: + allownumeric = 0; + break; + default: + return EAI_SOCKTYPE; + } + + port = str2number(servname); + if (port >= 0) { + if (!allownumeric) + return EAI_SERVICE; + if (port < 0 || port > 65535) + return EAI_SERVICE; + port = htons(port); + } else { + if (ai->ai_flags & AI_NUMERICSERV) + return EAI_NONAME; + + switch (ai->ai_socktype) { + case SOCK_DGRAM: + proto = "udp"; + break; + case SOCK_STREAM: + proto = "tcp"; + break; + default: + proto = NULL; + break; + } + + if ((sp = getservbyname(servname, proto)) == NULL) + return EAI_SERVICE; + port = sp->s_port; + } + + if (!matchonly) { + switch (ai->ai_family) { + case AF_INET: + ((struct sockaddr_in *)(void *) + ai->ai_addr)->sin_port = port; + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)(void *) + ai->ai_addr)->sin6_port = port; + break; +#endif + } + } + + return 0; +} + +static const struct afd * +find_afd(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; +} + +#ifdef INET6 +/* convert a string to a scope identifier. XXX: IPv6 specific */ +static int +ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid) +{ + u_long lscopeid; + struct in6_addr *a6; + char *ep; + + assert(scope != NULL); + assert(sin6 != NULL); + assert(scopeid != NULL); + + a6 = &sin6->sin6_addr; + + /* empty scopeid portion is invalid */ + if (*scope == '\0') + return -1; + + 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 0; + } + + /* 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: + errno = 0; + lscopeid = strtoul(scope, &ep, 10); + *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); + if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) + return 0; + else + return -1; +} +#endif + +/* code duplicate with gethnamaddr.c */ + +static const char AskedForGot[] = + "gethostby*.getanswer: asked for \"%s\", got \"%s\""; + +static struct addrinfo * +getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, + const struct addrinfo *pai) +{ + struct addrinfo sentinel, *cur; + struct addrinfo ai; + const struct afd *afd; + char *canonname; + const HEADER *hp; + const u_char *cp; + int n; + const u_char *eom; + char *bp, *ep; + int type, class, ancount, qdcount; + int haveanswer, had_error; + char tbuf[MAXDNAME]; + int (*name_ok) (const char *); + char hostbuf[8*1024]; + + assert(answer != NULL); + assert(qname != NULL); + assert(pai != NULL); + + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + + canonname = NULL; + eom = answer->buf + anslen; + switch (qtype) { + case T_A: + case T_AAAA: + case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ + name_ok = res_hnok; + break; + default: + return NULL; /* XXX should be abort(); */ + } + /* + * find first satisfactory answer + */ + hp = &answer->hdr; + ancount = ntohs(hp->ancount); + qdcount = ntohs(hp->qdcount); + bp = hostbuf; + ep = hostbuf + sizeof hostbuf; + cp = answer->buf + HFIXEDSZ; + if (qdcount != 1) { + h_errno = NO_RECOVERY; + return (NULL); + } + n = dn_expand(answer->buf, eom, cp, bp, ep - bp); + if ((n < 0) || !(*name_ok)(bp)) { + h_errno = NO_RECOVERY; + return (NULL); + } + cp += n + QFIXEDSZ; + if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { + /* res_send() has already verified that the query name is the + * same as the one we sent; this just gets the expanded name + * (i.e., with the succeeding search-domain tacked on). + */ + n = strlen(bp) + 1; /* for the \0 */ + if (n >= MAXHOSTNAMELEN) { + h_errno = NO_RECOVERY; + return (NULL); + } + canonname = bp; + bp += n; + /* The qname can be abbreviated, but h_name is now absolute. */ + qname = canonname; + } + haveanswer = 0; + had_error = 0; + while (ancount-- > 0 && cp < eom && !had_error) { + n = dn_expand(answer->buf, eom, cp, bp, ep - bp); + if ((n < 0) || !(*name_ok)(bp)) { + had_error++; + continue; + } + cp += n; /* name */ + type = _getshort(cp); + cp += INT16SZ; /* type */ + class = _getshort(cp); + cp += INT16SZ + INT32SZ; /* class, TTL */ + n = _getshort(cp); + cp += INT16SZ; /* len */ + if (class != C_IN) { + /* XXX - debug? syslog? */ + cp += n; + continue; /* XXX - had_error++ ? */ + } + if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && + type == T_CNAME) { + n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); + if ((n < 0) || !(*name_ok)(tbuf)) { + had_error++; + continue; + } + cp += n; + /* Get canonical name. */ + n = strlen(tbuf) + 1; /* for the \0 */ + if (n > ep - bp || n >= MAXHOSTNAMELEN) { + had_error++; + continue; + } + strlcpy(bp, tbuf, (size_t)(ep - bp)); + canonname = bp; + bp += n; + continue; + } + if (qtype == T_ANY) { + if (!(type == T_A || type == T_AAAA)) { + cp += n; + continue; + } + } else if (type != qtype) { + if (type != T_KEY && type != T_SIG) + syslog(LOG_NOTICE|LOG_AUTH, + "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", + qname, p_class(C_IN), p_type(qtype), + p_type(type)); + cp += n; + continue; /* XXX - had_error++ ? */ + } + switch (type) { + case T_A: + case T_AAAA: + if (strcasecmp(canonname, bp) != 0) { + syslog(LOG_NOTICE|LOG_AUTH, + AskedForGot, canonname, bp); + cp += n; + continue; /* XXX - had_error++ ? */ + } + if (type == T_A && n != INADDRSZ) { + cp += n; + continue; + } + if (type == T_AAAA && n != IN6ADDRSZ) { + cp += n; + continue; + } + if (type == T_AAAA) { + struct in6_addr in6; + memcpy(&in6, cp, IN6ADDRSZ); + if (IN6_IS_ADDR_V4MAPPED(&in6)) { + cp += n; + continue; + } + } + if (!haveanswer) { + int nn; + + canonname = bp; + nn = strlen(bp) + 1; /* for the \0 */ + bp += nn; + } + + /* don't overwrite pai */ + ai = *pai; + ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; + afd = find_afd(ai.ai_family); + if (afd == NULL) { + cp += n; + continue; + } + cur->ai_next = get_ai(&ai, afd, (const char *)cp); + if (cur->ai_next == NULL) + had_error++; + while (cur && cur->ai_next) + cur = cur->ai_next; + cp += n; + break; + default: + abort(); + } + if (!had_error) + haveanswer++; + } + if (haveanswer) { + if (!canonname) + (void)get_canonname(pai, sentinel.ai_next, qname); + else + (void)get_canonname(pai, sentinel.ai_next, canonname); + h_errno = NETDB_SUCCESS; + return sentinel.ai_next; + } + + h_errno = NO_RECOVERY; + return NULL; +} + +#define SORTEDADDR(p) (((struct sockaddr_in *)(void *)(p->ai_next->ai_addr))->sin_addr.s_addr) +#define SORTMATCH(p, s) ((SORTEDADDR(p) & (s).mask) == (s).addr.s_addr) + +static void +aisort(struct addrinfo *s, res_state res) +{ + struct addrinfo head, *t, *p; + int i; + + head.ai_next = NULL; + t = &head; + + for (i = 0; i < res->nsort; i++) { + p = s; + while (p->ai_next) { + if ((p->ai_next->ai_family != AF_INET) + || SORTMATCH(p, res->sort_list[i])) { + t->ai_next = p->ai_next; + t = t->ai_next; + p->ai_next = p->ai_next->ai_next; + } else { + p = p->ai_next; + } + } + } + + /* add rest of list and reset s to the new list*/ + t->ai_next = s->ai_next; + s->ai_next = head.ai_next; +} + +/*ARGSUSED*/ +static int +_dns_getaddrinfo(void *rv, void *cb_data, va_list ap) +{ + struct addrinfo *ai; + querybuf *buf, *buf2; + const char *name; + const struct addrinfo *pai; + struct addrinfo sentinel, *cur; + struct res_target q, q2; + res_state res; + + name = va_arg(ap, char *); + pai = va_arg(ap, const struct addrinfo *); + + fprintf(stderr, "_dns_getaddrinfo() name = '%s'\n", name); + + memset(&q, 0, sizeof(q)); + memset(&q2, 0, sizeof(q2)); + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + + buf = malloc(sizeof(*buf)); + if (buf == NULL) { + h_errno = NETDB_INTERNAL; + return NS_NOTFOUND; + } + buf2 = malloc(sizeof(*buf2)); + if (buf2 == NULL) { + free(buf); + h_errno = NETDB_INTERNAL; + return NS_NOTFOUND; + } + + switch (pai->ai_family) { + case AF_UNSPEC: + /* prefer IPv6 */ + q.name = name; + q.qclass = C_IN; + q.qtype = T_AAAA; + q.answer = buf->buf; + q.anslen = sizeof(buf->buf); + q.next = &q2; + q2.name = name; + q2.qclass = C_IN; + q2.qtype = T_A; + q2.answer = buf2->buf; + q2.anslen = sizeof(buf2->buf); + break; + case AF_INET: + q.name = name; + q.qclass = C_IN; + q.qtype = T_A; + q.answer = buf->buf; + q.anslen = sizeof(buf->buf); + break; + case AF_INET6: + q.name = name; + q.qclass = C_IN; + q.qtype = T_AAAA; + q.answer = buf->buf; + q.anslen = sizeof(buf->buf); + break; + default: + free(buf); + free(buf2); + return NS_UNAVAIL; + } + + res = __res_get_state(); + if (res == NULL) { + free(buf); + free(buf2); + return NS_NOTFOUND; + } + + if (res_searchN(name, &q, res) < 0) { + __res_put_state(res); + free(buf); + free(buf2); + return NS_NOTFOUND; + } + ai = getanswer(buf, q.n, q.name, q.qtype, pai); + if (ai) { + cur->ai_next = ai; + while (cur && cur->ai_next) + cur = cur->ai_next; + } + if (q.next) { + ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai); + if (ai) + cur->ai_next = ai; + } + free(buf); + free(buf2); + if (sentinel.ai_next == NULL) { + __res_put_state(res); + switch (h_errno) { + case HOST_NOT_FOUND: + return NS_NOTFOUND; + case TRY_AGAIN: + return NS_TRYAGAIN; + default: + return NS_UNAVAIL; + } + } + + if (res->nsort) + aisort(&sentinel, res); + + __res_put_state(res); + + *((struct addrinfo **)rv) = sentinel.ai_next; + return NS_SUCCESS; +} + +static void +_sethtent(FILE **hostf) +{ + + if (!*hostf) + *hostf = fopen(_PATH_HOSTS, "r" ); + else + rewind(*hostf); +} + +static void +_endhtent(FILE **hostf) +{ + + if (*hostf) { + (void) fclose(*hostf); + *hostf = NULL; + } +} + +static struct addrinfo * +_gethtent(FILE **hostf, const char *name, const struct addrinfo *pai) +{ + char *p; + char *cp, *tname, *cname; + struct addrinfo hints, *res0, *res; + int error; + const char *addr; + char hostbuf[8*1024]; + +// fprintf(stderr, "_gethtent() name = '%s'\n", name); + assert(name != NULL); + assert(pai != NULL); + + if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "r" ))) + return (NULL); + again: + if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf))) + return (NULL); + if (*p == '#') + goto again; + if (!(cp = strpbrk(p, "#\n"))) + goto again; + *cp = '\0'; + if (!(cp = strpbrk(p, " \t"))) + goto again; + *cp++ = '\0'; + addr = p; + /* if this is not something we're looking for, skip it. */ + cname = NULL; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (!cname) + cname = cp; + tname = cp; + if ((cp = strpbrk(cp, " \t")) != NULL) + *cp++ = '\0'; +// fprintf(stderr, "\ttname = '%s'", tname); + if (strcasecmp(name, tname) == 0) + goto found; + } + goto again; + +found: + hints = *pai; + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(addr, NULL, &hints, &res0); + if (error) + goto again; + for (res = res0; res; res = res->ai_next) { + /* cover it up */ + res->ai_flags = pai->ai_flags; + + if (pai->ai_flags & AI_CANONNAME) { + if (get_canonname(pai, res, cname) != 0) { + freeaddrinfo(res0); + goto again; + } + } + } + return res0; +} + +/*ARGSUSED*/ +static int +_files_getaddrinfo(void *rv, void *cb_data, va_list ap) +{ + const char *name; + const struct addrinfo *pai; + struct addrinfo sentinel, *cur; + struct addrinfo *p; + FILE *hostf = NULL; + + name = va_arg(ap, char *); + pai = va_arg(ap, struct addrinfo *); + +// fprintf(stderr, "_files_getaddrinfo() name = '%s'\n", name); + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + + _sethtent(&hostf); + while ((p = _gethtent(&hostf, name, pai)) != NULL) { + cur->ai_next = p; + while (cur && cur->ai_next) + cur = cur->ai_next; + } + _endhtent(&hostf); + + *((struct addrinfo **)rv) = sentinel.ai_next; + if (sentinel.ai_next == NULL) + return NS_NOTFOUND; + return NS_SUCCESS; +} + +/* resolver logic */ + +/* + * Formulate a normal query, send, and await answer. + * Returned answer is placed in supplied buffer "answer". + * Perform preliminary check of answer, returning success only + * if no error is indicated and the answer count is nonzero. + * Return the size of the response on success, -1 on error. + * Error number is left in h_errno. + * + * Caller must parse answer and determine whether it answers the question. + */ +static int +res_queryN(const char *name, /* domain name */ struct res_target *target, + res_state res) +{ + u_char buf[MAXPACKET]; + HEADER *hp; + int n; + struct res_target *t; + int rcode; + int ancount; + + assert(name != NULL); + /* XXX: target may be NULL??? */ + + rcode = NOERROR; + ancount = 0; + + for (t = target; t; t = t->next) { + int class, type; + u_char *answer; + int anslen; + + hp = (HEADER *)(void *)t->answer; + hp->rcode = NOERROR; /* default */ + + /* make it easier... */ + class = t->qclass; + type = t->qtype; + answer = t->answer; + anslen = t->anslen; +#ifdef DEBUG + if (res->options & RES_DEBUG) + printf(";; res_nquery(%s, %d, %d)\n", name, class, type); +#endif + + n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL, + buf, sizeof(buf)); +#ifdef RES_USE_EDNS0 + if (n > 0 && (res->options & RES_USE_EDNS0) != 0) + n = res_nopt(res, n, buf, sizeof(buf), anslen); +#endif + if (n <= 0) { +#ifdef DEBUG + if (res->options & RES_DEBUG) + printf(";; res_nquery: mkquery failed\n"); +#endif + h_errno = NO_RECOVERY; + return n; + } + n = res_nsend(res, buf, n, answer, anslen); +#if 0 + if (n < 0) { +#ifdef DEBUG + if (res->options & RES_DEBUG) + printf(";; res_query: send error\n"); +#endif + h_errno = TRY_AGAIN; + return n; + } +#endif + + if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { + rcode = hp->rcode; /* record most recent error */ +#ifdef DEBUG + if (res->options & RES_DEBUG) + printf(";; rcode = %u, ancount=%u\n", hp->rcode, + ntohs(hp->ancount)); +#endif + continue; + } + + ancount += ntohs(hp->ancount); + + t->n = n; + } + + if (ancount == 0) { + switch (rcode) { + case NXDOMAIN: + h_errno = HOST_NOT_FOUND; + break; + case SERVFAIL: + h_errno = TRY_AGAIN; + break; + case NOERROR: + h_errno = NO_DATA; + break; + case FORMERR: + case NOTIMP: + case REFUSED: + default: + h_errno = NO_RECOVERY; + break; + } + return -1; + } + return ancount; +} + +/* + * Formulate a normal query, send, and retrieve answer in supplied buffer. + * Return the size of the response on success, -1 on error. + * If enabled, implement search rules until answer or unrecoverable failure + * is detected. Error code, if any, is left in h_errno. + */ +static int +res_searchN(const char *name, struct res_target *target, res_state res) +{ + const char *cp, * const *domain; + HEADER *hp; + u_int dots; + int trailing_dot, ret, saved_herrno; + int got_nodata = 0, got_servfail = 0, tried_as_is = 0; + + assert(name != NULL); + assert(target != NULL); + + hp = (HEADER *)(void *)target->answer; /*XXX*/ + + errno = 0; + h_errno = HOST_NOT_FOUND; /* default, if we never query */ + dots = 0; + for (cp = name; *cp; cp++) + dots += (*cp == '.'); + trailing_dot = 0; + if (cp > name && *--cp == '.') + trailing_dot++; + + +fprintf(stderr, "res_searchN() name = '%s'\n", name); + + /* + * if there aren't any dots, it could be a user-level alias + */ + if (!dots && (cp = __hostalias(name)) != NULL) { + ret = res_queryN(cp, target, res); + return ret; + } + + /* + * If there are dots in the name already, let's just give it a try + * 'as is'. The threshold can be set with the "ndots" option. + */ + saved_herrno = -1; + if (dots >= res->ndots) { + ret = res_querydomainN(name, NULL, target, res); + if (ret > 0) + return (ret); + saved_herrno = h_errno; + tried_as_is++; + } + + /* + * We do at least one level of search if + * - there is no dot and RES_DEFNAME is set, or + * - there is at least one dot, there is no trailing dot, + * and RES_DNSRCH is set. + */ + if ((!dots && (res->options & RES_DEFNAMES)) || + (dots && !trailing_dot && (res->options & RES_DNSRCH))) { + int done = 0; + + for (domain = (const char * const *)res->dnsrch; + *domain && !done; + domain++) { + + ret = res_querydomainN(name, *domain, target, res); + if (ret > 0) + return ret; + + /* + * If no server present, give up. + * If name isn't found in this domain, + * keep trying higher domains in the search list + * (if that's enabled). + * On a NO_DATA error, keep trying, otherwise + * a wildcard entry of another type could keep us + * from finding this entry higher in the domain. + * If we get some other error (negative answer or + * server failure), then stop searching up, + * but try the input name below in case it's + * fully-qualified. + */ + if (errno == ECONNREFUSED) { + h_errno = TRY_AGAIN; + return -1; + } + + switch (h_errno) { + case NO_DATA: + got_nodata++; + /* FALLTHROUGH */ + case HOST_NOT_FOUND: + /* keep trying */ + break; + case TRY_AGAIN: + if (hp->rcode == SERVFAIL) { + /* try next search element, if any */ + got_servfail++; + break; + } + /* FALLTHROUGH */ + default: + /* anything else implies that we're done */ + done++; + } + /* + * if we got here for some reason other than DNSRCH, + * we only wanted one iteration of the loop, so stop. + */ + if (!(res->options & RES_DNSRCH)) + done++; + } + } + + /* + * if we have not already tried the name "as is", do that now. + * note that we do this regardless of how many dots were in the + * name or whether it ends with a dot. + */ + if (!tried_as_is) { + ret = res_querydomainN(name, NULL, target, res); + if (ret > 0) + return ret; + } + + /* + * if we got here, we didn't satisfy the search. + * if we did an initial full query, return that query's h_errno + * (note that we wouldn't be here if that query had succeeded). + * else if we ever got a nodata, send that back as the reason. + * else send back meaningless h_errno, that being the one from + * the last DNSRCH we did. + */ + if (saved_herrno != -1) + h_errno = saved_herrno; + else if (got_nodata) + h_errno = NO_DATA; + else if (got_servfail) + h_errno = TRY_AGAIN; + return -1; +} + +/* + * Perform a call on res_query on the concatenation of name and domain, + * removing a trailing dot from name if domain is NULL. + */ +static int +res_querydomainN(const char *name, const char *domain, + struct res_target *target, res_state res) +{ + char nbuf[MAXDNAME]; + const char *longname = nbuf; + size_t n, d; + + assert(name != NULL); + /* XXX: target may be NULL??? */ + +#ifdef DEBUG + if (res->options & RES_DEBUG) + printf(";; res_querydomain(%s, %s)\n", + name, domain?domain:"<Nil>"); +#endif + if (domain == NULL) { + /* + * Check for trailing '.'; + * copy without '.' if present. + */ + n = strlen(name); + if (n + 1 > sizeof(nbuf)) { + h_errno = NO_RECOVERY; + return -1; + } + if (n > 0 && name[--n] == '.') { + strncpy(nbuf, name, n); + nbuf[n] = '\0'; + } else + longname = name; + } else { + n = strlen(name); + d = strlen(domain); + if (n + 1 + d + 1 > sizeof(nbuf)) { + h_errno = NO_RECOVERY; + return -1; + } + snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); + } + return res_queryN(longname, target, res); +} diff --git a/libc/netbsd/net/getnameinfo.c b/libc/netbsd/net/getnameinfo.c new file mode 100644 index 0000000..5effa63 --- /dev/null +++ b/libc/netbsd/net/getnameinfo.c @@ -0,0 +1,519 @@ +/* $NetBSD: getnameinfo.c,v 1.43 2006/02/17 15:58:26 ginsbach Exp $ */ +/* $KAME: getnameinfo.c,v 1.45 2000/09/25 22:43:56 itojun Exp $ */ + +/* + * Copyright (c) 2000 Ben Harris. + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Issues to be discussed: + * - Thread safe-ness must be checked + * - 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). ipngwg rough consensus seems to follow RFC2553. + * - What is "local" in NI_FQDN? + * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other. + * - (KAME extension) always attach textual scopeid (fe80::1%lo0), if + * sin6_scope_id is filled - standardization status? + * XXX breaks backward compat for code that expects no scopeid. + * beware on merge. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: getnameinfo.c,v 1.43 2006/02/17 15:58:26 ginsbach Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_ieee1394.h> +#include <net/if_types.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "arpa_nameser.h" +#include <assert.h> +#include <limits.h> +#include <netdb.h> +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include <resolv.h> +#endif +#include <stddef.h> +#include <string.h> + +static const struct afd { + int a_af; + socklen_t a_addrlen; + socklen_t a_socklen; + int a_off; +} afdl [] = { +#ifdef INET6 + {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr)}, +#endif + {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr)}, + {0, 0, 0, 0}, +}; + +struct sockinet { + u_char si_len; + u_char si_family; + u_short si_port; +}; + +static int getnameinfo_inet __P((const struct sockaddr *, socklen_t, char *, + socklen_t, char *, socklen_t, int)); +#ifdef INET6 +static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *, + socklen_t, int)); +static int ip6_sa2str __P((const struct sockaddr_in6 *, char *, size_t, + int)); +#endif +static int getnameinfo_link __P((const struct sockaddr *, socklen_t, char *, + socklen_t, char *, socklen_t, int)); +static int hexname __P((const u_int8_t *, size_t, char *, socklen_t)); + +/* + * Top-level getnameinfo() code. Look at the address family, and pick an + * appropriate function to call. + */ +int getnameinfo(const struct sockaddr* sa, socklen_t salen, char* host, size_t hostlen, char* serv, size_t servlen, int flags) +{ + switch (sa->sa_family) { + case AF_INET: + case AF_INET6: + return getnameinfo_inet(sa, salen, host, hostlen, + serv, servlen, flags); +#if 0 + case AF_LINK: + return getnameinfo_link(sa, salen, host, hostlen, + serv, servlen, flags); +#endif + default: + return EAI_FAMILY; + } +} + + +/* + * getnameinfo_inet(): + * Format an IPv4 or IPv6 sockaddr into a printable string. + */ +static int +getnameinfo_inet(sa, salen, host, hostlen, serv, servlen, flags) + const struct sockaddr *sa; + socklen_t salen; + char *host; + socklen_t hostlen; + char *serv; + socklen_t servlen; + int flags; +{ + const struct afd *afd; + struct servent *sp; + struct hostent *hp; + u_short port; + int family, i; + const char *addr; + u_int32_t v4a; + char numserv[512]; + char numaddr[512]; + + /* sa is checked below */ + /* host may be NULL */ + /* serv may be NULL */ + + if (sa == NULL) + return EAI_FAIL; + +#ifdef BSD4_4 + if (sa->sa_len != salen) + return EAI_FAIL; +#endif + + family = sa->sa_family; + for (i = 0; afdl[i].a_af; i++) + if (afdl[i].a_af == family) { + afd = &afdl[i]; + goto found; + } + return EAI_FAMILY; + + found: + if (salen != afd->a_socklen) + return EAI_FAIL; + + /* network byte order */ + port = ((const struct sockinet *)(const void *)sa)->si_port; + addr = (const char *)(const void *)sa + afd->a_off; + + if (serv == NULL || servlen == 0) { + /* + * do nothing in this case. + * in case you are wondering if "&&" is more correct than + * "||" here: rfc2553bis-03 says that serv == NULL OR + * servlen == 0 means that the caller does not want the result. + */ + } else { + if (flags & NI_NUMERICSERV) + sp = NULL; + else { + sp = getservbyport(port, + (flags & NI_DGRAM) ? "udp" : "tcp"); + } + if (sp) { + if (strlen(sp->s_name) + 1 > (size_t)servlen) + return EAI_MEMORY; + strlcpy(serv, sp->s_name, servlen); + } else { + snprintf(numserv, sizeof(numserv), "%u", ntohs(port)); + if (strlen(numserv) + 1 > (size_t)servlen) + return EAI_MEMORY; + strlcpy(serv, numserv, servlen); + } + } + + switch (sa->sa_family) { + case AF_INET: + v4a = (u_int32_t) + ntohl(((const struct sockaddr_in *) + (const void *)sa)->sin_addr.s_addr); + if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) + flags |= NI_NUMERICHOST; + v4a >>= IN_CLASSA_NSHIFT; + if (v4a == 0) + flags |= NI_NUMERICHOST; + break; +#ifdef INET6 + case AF_INET6: + { + const struct sockaddr_in6 *sin6; + sin6 = (const struct sockaddr_in6 *)(const void *)sa; + switch (sin6->sin6_addr.s6_addr[0]) { + case 0x00: + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) + ; + else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) + ; + else + flags |= NI_NUMERICHOST; + break; + default: + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + flags |= NI_NUMERICHOST; + } + else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) + flags |= NI_NUMERICHOST; + break; + } + } + break; +#endif + } + if (host == NULL || hostlen == 0) { + /* + * do nothing in this case. + * in case you are wondering if "&&" is more correct than + * "||" here: rfc2553bis-03 says that host == NULL or + * hostlen == 0 means that the caller does not want the result. + */ + } else if (flags & NI_NUMERICHOST) { + size_t numaddrlen; + + /* NUMERICHOST and NAMEREQD conflicts with each other */ + if (flags & NI_NAMEREQD) + return EAI_NONAME; + + switch(afd->a_af) { +#ifdef INET6 + case AF_INET6: + { + int error; + + if ((error = ip6_parsenumeric(sa, addr, host, + hostlen, flags)) != 0) + return(error); + break; + } +#endif + default: + if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) + == NULL) + return EAI_SYSTEM; + numaddrlen = strlen(numaddr); + if (numaddrlen + 1 > (size_t)hostlen) /* don't forget terminator */ + return EAI_MEMORY; + strlcpy(host, numaddr, hostlen); + break; + } + } else { + hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); + + if (hp) { +#if 0 + /* + * commented out, since "for local host" is not + * implemented here - see RFC2553 p30 + */ + if (flags & NI_NOFQDN) { + char *p; + p = strchr(hp->h_name, '.'); + if (p) + *p = '\0'; + } +#endif + if (strlen(hp->h_name) + 1 > (size_t)hostlen) { + return EAI_MEMORY; + } + strlcpy(host, hp->h_name, hostlen); + } else { + if (flags & NI_NAMEREQD) + return EAI_NONAME; + switch(afd->a_af) { +#ifdef INET6 + case AF_INET6: + { + int error; + + if ((error = ip6_parsenumeric(sa, addr, host, + hostlen, + flags)) != 0) + return(error); + break; + } +#endif + default: + if (inet_ntop(afd->a_af, addr, host, + hostlen) == NULL) + return EAI_SYSTEM; + break; + } + } + } + return(0); +} + +#ifdef INET6 +static int +ip6_parsenumeric(sa, addr, host, hostlen, flags) + const struct sockaddr *sa; + const char *addr; + char *host; + socklen_t hostlen; + int flags; +{ + size_t numaddrlen; + char numaddr[512]; + + _DIAGASSERT(sa != NULL); + _DIAGASSERT(addr != NULL); + _DIAGASSERT(host != NULL); + + if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) == NULL) + return EAI_SYSTEM; + + numaddrlen = strlen(numaddr); + if (numaddrlen + 1 > hostlen) /* don't forget terminator */ + return EAI_OVERFLOW; + strlcpy(host, numaddr, hostlen); + + if (((const struct sockaddr_in6 *)(const void *)sa)->sin6_scope_id) { + char zonebuf[MAXHOSTNAMELEN]; + int zonelen; + + zonelen = ip6_sa2str( + (const struct sockaddr_in6 *)(const void *)sa, + zonebuf, sizeof(zonebuf), flags); + if (zonelen < 0) + return EAI_OVERFLOW; + if ((size_t) zonelen + 1 + numaddrlen + 1 > hostlen) + return EAI_OVERFLOW; + /* construct <numeric-addr><delim><zoneid> */ + memcpy(host + numaddrlen + 1, zonebuf, + (size_t)zonelen); + host[numaddrlen] = SCOPE_DELIMITER; + host[numaddrlen + 1 + zonelen] = '\0'; + } + + return 0; +} + +/* ARGSUSED */ +static int +ip6_sa2str(sa6, buf, bufsiz, flags) + const struct sockaddr_in6 *sa6; + char *buf; + size_t bufsiz; + int flags; +{ + unsigned int ifindex; + const struct in6_addr *a6; + int n; + + _DIAGASSERT(sa6 != NULL); + _DIAGASSERT(buf != NULL); + + ifindex = (unsigned int)sa6->sin6_scope_id; + a6 = &sa6->sin6_addr; + +#ifdef NI_NUMERICSCOPE + if ((flags & NI_NUMERICSCOPE) != 0) { + n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id); + if (n < 0 || n >= bufsiz) + return -1; + else + return n; + } +#endif + + /* if_indextoname() does not take buffer size. not a good api... */ + if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) && + bufsiz >= IF_NAMESIZE) { + char *p = if_indextoname(ifindex, buf); + if (p) { + return(strlen(p)); + } + } + + /* last resort */ + n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id); + if (n < 0 || (size_t) n >= bufsiz) + return -1; + else + return n; +} +#endif /* INET6 */ + + +/* + * getnameinfo_link(): + * Format a link-layer address into a printable format, paying attention to + * the interface type. + */ +/* ARGSUSED */ +static int +getnameinfo_link(const struct sockaddr *sa, socklen_t salen, + char *host, socklen_t hostlen, char *serv, socklen_t servlen, + int flags) +{ + const struct sockaddr_dl *sdl = + (const struct sockaddr_dl *)(const void *)sa; + const struct ieee1394_hwaddr *iha; + int n; + + if (serv != NULL && servlen > 0) + *serv = '\0'; + + if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && sdl->sdl_slen == 0) { + n = snprintf(host, hostlen, "link#%u", sdl->sdl_index); + if (n < 0 || (socklen_t) n > hostlen) { + *host = '\0'; + return EAI_MEMORY; + } + return 0; + } + + switch (sdl->sdl_type) { +#ifdef IFT_ECONET + case IFT_ECONET: + if (sdl->sdl_alen < 2) + return EAI_FAMILY; + if (CLLADDR(sdl)[1] == 0) + n = snprintf(host, hostlen, "%u", CLLADDR(sdl)[0]); + else + n = snprintf(host, hostlen, "%u.%u", + CLLADDR(sdl)[1], CLLADDR(sdl)[0]); + if (n < 0 || (socklen_t) n >= hostlen) { + *host = '\0'; + return EAI_MEMORY; + } else + return 0; +#endif + case IFT_IEEE1394: + if (sdl->sdl_alen < sizeof(iha->iha_uid)) + return EAI_FAMILY; + iha = + (const struct ieee1394_hwaddr *)(const void *)CLLADDR(sdl); + return hexname(iha->iha_uid, sizeof(iha->iha_uid), + host, hostlen); + /* + * The following have zero-length addresses. + * IFT_ATM (net/if_atmsubr.c) + * IFT_FAITH (net/if_faith.c) + * IFT_GIF (net/if_gif.c) + * IFT_LOOP (net/if_loop.c) + * IFT_PPP (net/if_ppp.c, net/if_spppsubr.c) + * IFT_SLIP (net/if_sl.c, net/if_strip.c) + * IFT_STF (net/if_stf.c) + * IFT_L2VLAN (net/if_vlan.c) + * IFT_PROPVIRTUAL (net/if_bridge.h> + */ + /* + * The following use IPv4 addresses as link-layer addresses: + * IFT_OTHER (net/if_gre.c) + */ + case IFT_ARCNET: /* default below is believed correct for all these. */ + case IFT_ETHER: + case IFT_FDDI: + case IFT_HIPPI: + case IFT_ISO88025: + default: + return hexname((const u_int8_t *)CLLADDR(sdl), + (size_t)sdl->sdl_alen, host, hostlen); + } +} + +static int +hexname(cp, len, host, hostlen) + const u_int8_t *cp; + char *host; + size_t len; + socklen_t hostlen; +{ + int n; + size_t i; + char *outp = host; + + *outp = '\0'; + for (i = 0; i < len; i++) { + n = snprintf(outp, hostlen, "%s%02x", + i ? ":" : "", cp[i]); + if (n < 0 || (socklen_t) n >= hostlen) { + *host = '\0'; + return EAI_MEMORY; + } + outp += n; + hostlen -= n; + } + return 0; +} diff --git a/libc/netbsd/net/getservbyname.c b/libc/netbsd/net/getservbyname.c new file mode 100644 index 0000000..5ea528e --- /dev/null +++ b/libc/netbsd/net/getservbyname.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <sys/cdefs.h> +#include <sys/types.h> +#include <netdb.h> +#include "servent.h" + +struct servent * +getservbyname(const char *name, const char *proto) +{ + res_static rs = __res_get_static(); + struct servent* s; + + if (rs == NULL || proto == NULL || name == NULL) { + errno = EINVAL; + return NULL; + } + + rs->servent_ptr = NULL; + while (1) { + struct servent* s = getservent_r(rs); + if (s == NULL) + break; + if ( !strcmp( s->s_name, name ) && !strcmp( s->s_proto, proto ) ) + return s; + } + + return NULL; +} diff --git a/libc/netbsd/net/getservbyname_r.c b/libc/netbsd/net/getservbyname_r.c new file mode 100644 index 0000000..fb6dc52 --- /dev/null +++ b/libc/netbsd/net/getservbyname_r.c @@ -0,0 +1,76 @@ +/* $NetBSD: getservbyname_r.c,v 1.3 2005/04/18 19:39:45 kleink Exp $ */ + +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#include <sys/types.h> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)getservbyname.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: getservbyname_r.c,v 1.3 2005/04/18 19:39:45 kleink Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <assert.h> +#include <netdb.h> +#include <string.h> + +#include "servent.h" + +struct servent * +getservbyname_r(const char *name, const char *proto, struct servent *sp, + struct servent_data *sd) +{ + struct servent *s; + char **cp; + + assert(name != NULL); + /* proto may be NULL */ + + setservent_r(sd->stayopen, sd); + while ((s = getservent_r(sp, sd)) != NULL) { + if (strcmp(name, s->s_name) == 0) + goto gotname; + for (cp = s->s_aliases; *cp; cp++) + if (strcmp(name, *cp) == 0) + goto gotname; + continue; +gotname: + if (proto == NULL || strcmp(s->s_proto, proto) == 0) + break; + } + if (!sd->stayopen) + if (sd->fp != NULL) { + (void)fclose(sd->fp); + sd->fp = NULL; + } + return s; +} diff --git a/libc/netbsd/net/getservbyport.c b/libc/netbsd/net/getservbyport.c new file mode 100644 index 0000000..fad7e23 --- /dev/null +++ b/libc/netbsd/net/getservbyport.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <sys/cdefs.h> +#include <netdb.h> +#include "servent.h" + +struct servent * +getservbyport(int port, const char *proto) +{ + res_static rs = __res_get_static(); + struct servent* s; + + if (rs == NULL || proto == NULL) { + errno = EINVAL; + return NULL; + } + + rs->servent_ptr = NULL; + while (1) { + struct servent* s = getservent_r(rs); + if (s == NULL) + break; + if ( s->s_port == port && !strcmp( s->s_proto, proto ) ) + return s; + } + + return NULL; +} diff --git a/libc/netbsd/net/getservbyport_r.c b/libc/netbsd/net/getservbyport_r.c new file mode 100644 index 0000000..6fe4293 --- /dev/null +++ b/libc/netbsd/net/getservbyport_r.c @@ -0,0 +1,65 @@ +/* $NetBSD: getservbyport_r.c,v 1.3 2005/04/18 19:39:45 kleink Exp $ */ + +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)getservbyport.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: getservbyport_r.c,v 1.3 2005/04/18 19:39:45 kleink Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <netdb.h> +#include <string.h> + +#include "servent.h" + +struct servent * +getservbyport_r(int port, const char *proto, struct servent *sp, + struct servent_data *sd) +{ + struct servent *s; + + setservent_r(sd->stayopen, sd); + while ((s = getservent_r(sp, sd)) != NULL) { + if (s->s_port != port) + continue; + if (proto == NULL || strcmp(s->s_proto, proto) == 0) + break; + } + if (!sd->stayopen) + if (sd->fp != NULL) { + (void)fclose(sd->fp); + sd->fp = NULL; + } + return s; +} diff --git a/libc/netbsd/net/getservent.c b/libc/netbsd/net/getservent.c new file mode 100644 index 0000000..45207df --- /dev/null +++ b/libc/netbsd/net/getservent.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <sys/cdefs.h> +#include <sys/types.h> +#include <netdb.h> +#include "servent.h" +#include "services.h" + +void +setservent(int f) +{ + res_static rs = __res_get_static(); + if (rs) { + rs->servent_ptr = NULL; + } +} + +void +endservent(void) +{ + /* nothing to do */ +} + +struct servent * +getservent_r( res_static rs ) +{ + const char* p; + const char* q; + int namelen; + int nn,count; + int total = 0; + char* p2; + + p = rs->servent_ptr; + if (p == NULL) + p = _services; + else if (p[0] == 0) + return NULL; + + /* first compute the total size */ + namelen = p[0]; + total += namelen + 1; + q = p + 1 + namelen + 3; /* skip name + port + proto */ + count = q[0]; /* get aliascount */ + q += 1; + + total += (count+1)*sizeof(char*); + for (nn = 0; nn < count; nn++) { + int len2 = q[0]; + total += 1 + len2; + q += 1 + len2; + } + + /* reallocate the thread-specific servent struct */ + p2 = realloc( (char*)rs->servent.s_aliases, total ); + if (p2 == NULL) + return NULL; + + /* now write to it */ + rs->servent.s_aliases = (char**) p2; + p2 += (count+1)*sizeof(char*); + rs->servent.s_name = p2; + p2 += namelen + 1; + rs->servent.s_proto = p2; + + /* copy name + port + setup protocol */ + memcpy( rs->servent.s_name, p+1, namelen ); + rs->servent.s_name[namelen] = 0; + p += 1 + namelen; + rs->servent.s_port = ((((unsigned char*)p)[0] << 8) | + ((unsigned char*)p)[1]); + + rs->servent.s_proto = p[2] == 't' ? "tcp" : "udp"; + p += 4; /* skip port(2) + proto(1) + aliascount(1) */ + + for (nn = 0; nn < count; nn++) { + int len2 = p[0]; + rs->servent.s_aliases[nn] = p2; + memcpy( p2, p+1, len2 ); + p2[len2] = 0; + p2 += len2 + 1; + p += len2 + 1; + } + rs->servent.s_aliases[nn] = NULL; + + rs->servent_ptr = p; + + return &rs->servent; +} + +struct servent * +getservent(void) +{ + res_static rs = __res_get_static(); + + if (rs == NULL) return NULL; + + return getservent_r(rs); +} diff --git a/libc/netbsd/net/getservent_r.c b/libc/netbsd/net/getservent_r.c new file mode 100644 index 0000000..1668759 --- /dev/null +++ b/libc/netbsd/net/getservent_r.c @@ -0,0 +1,151 @@ +/* $NetBSD: getservent_r.c,v 1.5 2005/04/18 19:39:45 kleink Exp $ */ + +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#include <sys/types.h> + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)getservent.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: getservent_r.c,v 1.5 2005/04/18 19:39:45 kleink Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <netdb.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <netinet/in.h> + +#include "servent.h" + +void +setservent_r(int f, struct servent_data *sd) +{ + if (sd->fp == NULL) + sd->fp = fopen(_PATH_SERVICES, "r"); + else + rewind(sd->fp); + sd->stayopen |= f; +} + +void +endservent_r(struct servent_data *sd) +{ + if (sd->fp) { + (void)fclose(sd->fp); + sd->fp = NULL; + } + if (sd->aliases) { + free(sd->aliases); + sd->aliases = NULL; + sd->maxaliases = 0; + } + if (sd->line) { + free(sd->line); + sd->line = NULL; + } + sd->stayopen = 0; +} + +struct servent * +getservent_r(struct servent *sp, struct servent_data *sd) +{ + char *p, *cp, **q; + size_t i = 0; + int oerrno; + + if (sd->fp == NULL && (sd->fp = fopen(_PATH_SERVICES, "r")) == NULL) + return NULL; + + for (;;) { + if (sd->line) + free(sd->line); +// sd->line = fparseln(sd->fp, NULL, NULL, NULL, FPARSELN_UNESCALL); + fprintf(stderr, "*** FIX ME! getservent_r() is going to fail!!!\n"); + sd->line = NULL; + if (sd->line == NULL) + return NULL; + sp->s_name = p = sd->line; + p = strpbrk(p, " \t"); + if (p == NULL) + continue; + *p++ = '\0'; + while (*p == ' ' || *p == '\t') + p++; + cp = strpbrk(p, ",/"); + if (cp == NULL) + continue; + *cp++ = '\0'; + sp->s_port = htons((u_short)atoi(p)); + sp->s_proto = cp; + if (sd->aliases == NULL) { + sd->maxaliases = 10; + sd->aliases = malloc(sd->maxaliases * sizeof(char *)); + if (sd->aliases == NULL) { + oerrno = errno; + endservent_r(sd); + errno = oerrno; + return NULL; + } + } + q = sp->s_aliases = sd->aliases; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (i == sd->maxaliases - 2) { + sd->maxaliases *= 2; + q = realloc(q, + sd->maxaliases * sizeof(char *)); + if (q == NULL) { + oerrno = errno; + endservent_r(sd); + errno = oerrno; + return NULL; + } + sp->s_aliases = sd->aliases = q; + } + q[i++] = cp; + cp = strpbrk(cp, " \t"); + if (cp != NULL) + *cp++ = '\0'; + } + q[i] = NULL; + return sp; + } +} diff --git a/libc/netbsd/net/nsdispatch.c b/libc/netbsd/net/nsdispatch.c new file mode 100644 index 0000000..fa99366 --- /dev/null +++ b/libc/netbsd/net/nsdispatch.c @@ -0,0 +1,152 @@ +/* $NetBSD: nsdispatch.c,v 1.30 2005/11/29 03:11:59 christos Exp $ */ + +/*- + * Copyright (c) 1997, 1998, 1999, 2004 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn; and by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 2003 Networks Associates Technology, Inc. + * All rights reserved. + * + * Portions of this software were developed for the FreeBSD Project by + * Jacques A. Vidrine, Safeport Network Services, and Network + * Associates Laboratories, the Security Research Division of Network + * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 + * ("CBOSS"), as part of the DARPA CHATS research program. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.h> + +#include <assert.h> +#ifdef __ELF__ +#include <dlfcn.h> +#endif /* __ELF__ */ +#include <fcntl.h> +#define _NS_PRIVATE +#include <nsswitch.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static nss_method +_nsmethod(const char *source, const char *database, const char *method, + const ns_dtab disp_tab[], void **cb_data) +{ + int curdisp; + + if (disp_tab != NULL) { + for (curdisp = 0; disp_tab[curdisp].src != NULL; curdisp++) { + if (strcasecmp(source, disp_tab[curdisp].src) == 0) { + *cb_data = disp_tab[curdisp].cb_data; + return (disp_tab[curdisp].callback); + } + } + } + + *cb_data = NULL; + return (NULL); +} + +int +/*ARGSUSED*/ +nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database, + const char *method, const ns_src defaults[], ...) +{ + va_list ap; + int i, result; + const ns_src *srclist; + int srclistsize; + nss_method cb; + void *cb_data; + + /* retval may be NULL */ + /* disp_tab may be NULL */ + assert(database != NULL); + assert(method != NULL); + assert(defaults != NULL); + if (database == NULL || method == NULL || defaults == NULL) + return (NS_UNAVAIL); + + srclist = defaults; + srclistsize = 0; + while (srclist[srclistsize].name != NULL) + srclistsize++; + + result = 0; + + for (i = 0; i < srclistsize; i++) { + cb = _nsmethod(srclist[i].name, database, method, + disp_tab, &cb_data); + result = 0; + if (cb != NULL) { + va_start(ap, defaults); + result = (*cb)(retval, cb_data, ap); + va_end(ap); + if (defaults[0].flags & NS_FORCEALL) + continue; + if (result & srclist[i].flags) + break; + } + } + result &= NS_STATUSMASK; /* clear private flags in result */ + + return (result ? result : NS_NOTFOUND); +} diff --git a/libc/netbsd/net/reentrant.h b/libc/netbsd/net/reentrant.h new file mode 100644 index 0000000..15507eb --- /dev/null +++ b/libc/netbsd/net/reentrant.h @@ -0,0 +1,268 @@ +/* $NetBSD: reentrant.h,v 1.10 2004/12/14 00:23:19 nathanw Exp $ */ + +/*- + * Copyright (c) 1997, 1998, 2003 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by J.T. Conklin, by Nathan J. Williams, and by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Requirements: + * + * 1. The thread safe mechanism should be lightweight so the library can + * be used by non-threaded applications without unreasonable overhead. + * + * 2. There should be no dependency on a thread engine for non-threaded + * applications. + * + * 3. There should be no dependency on any particular thread engine. + * + * 4. The library should be able to be compiled without support for thread + * safety. + * + * + * Rationale: + * + * One approach for thread safety is to provide discrete versions of the + * library: one thread safe, the other not. The disadvantage of this is + * that libc is rather large, and two copies of a library which are 99%+ + * identical is not an efficent use of resources. + * + * Another approach is to provide a single thread safe library. However, + * it should not add significant run time or code size overhead to non- + * threaded applications. + * + * Since the NetBSD C library is used in other projects, it should be + * easy to replace the mutual exclusion primitives with ones provided by + * another system. Similarly, it should also be easy to remove all + * support for thread safety completely if the target environment does + * not support threads. + * + * + * Implementation Details: + * + * The thread primitives used by the library (mutex_t, mutex_lock, etc.) + * are macros which expand to the cooresponding primitives provided by + * the thread engine or to nothing. The latter is used so that code is + * not unreasonably cluttered with #ifdefs when all thread safe support + * is removed. + * + * The thread macros can be directly mapped to the mutex primitives from + * pthreads, however it should be reasonably easy to wrap another mutex + * implementation so it presents a similar interface. + * + * The thread functions operate by dispatching to symbols which are, by + * default, weak-aliased to no-op functions in thread-stub/thread-stub.c + * (some uses of thread operations are conditional on __isthreaded, but + * not all of them are). + * + * When the thread library is linked in, it provides strong-alias versions + * of those symbols which dispatch to its own real thread operations. + * + */ + +#ifdef _REENTRANT + +/* + * Abtract thread interface for thread-safe libraries. These routines + * will use stubs in libc if the application is not linked against the + * pthread library, and the real function in the pthread library if it + * is. + */ + +#include <pthread.h> +#include <signal.h> + +#define mutex_t pthread_mutex_t +#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER + +#define mutexattr_t pthread_mutexattr_t + +#define MUTEX_TYPE_NORMAL PTHREAD_MUTEX_NORMAL +#define MUTEX_TYPE_ERRORCHECK PTHREAD_MUTEX_ERRORCHECK +#define MUTEX_TYPE_RECURSIVE PTHREAD_MUTEX_RECURSIVE + +#define cond_t pthread_cond_t +#define COND_INITIALIZER PTHREAD_COND_INITIALIZER + +#define condattr_t pthread_condattr_t + +#define rwlock_t pthread_rwlock_t +#define RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER + +#define rwlockattr_t pthread_rwlockattr_t + +#define thread_key_t pthread_key_t + +#define thr_t pthread_t + +#define thrattr_t pthread_attr_t + +#define once_t pthread_once_t +#define ONCE_INITIALIZER PTHREAD_ONCE_INIT + +#ifndef __LIBC_THREAD_STUBS + +__BEGIN_DECLS +int __libc_mutex_init(mutex_t *, const mutexattr_t *); +int __libc_mutex_lock(mutex_t *); +int __libc_mutex_trylock(mutex_t *); +int __libc_mutex_unlock(mutex_t *); +int __libc_mutex_destroy(mutex_t *); + +int __libc_mutexattr_init(mutexattr_t *); +int __libc_mutexattr_settype(mutexattr_t *, int); +int __libc_mutexattr_destroy(mutexattr_t *); +__END_DECLS + +#define mutex_init(m, a) __libc_mutex_init((m), (a)) +#define mutex_lock(m) __libc_mutex_lock((m)) +#define mutex_trylock(m) __libc_mutex_trylock((m)) +#define mutex_unlock(m) __libc_mutex_unlock((m)) +#define mutex_destroy(m) __libc_mutex_destroy((m)) + +#define mutexattr_init(ma) __libc_mutexattr_init((ma)) +#define mutexattr_settype(ma, t) __libc_mutexattr_settype((ma), (t)) +#define mutexattr_destroy(ma) __libc_mutexattr_destroy((ma)) + +__BEGIN_DECLS +int __libc_cond_init(cond_t *, const condattr_t *); +int __libc_cond_signal(cond_t *); +int __libc_cond_broadcast(cond_t *); +int __libc_cond_wait(cond_t *, mutex_t *); +int __libc_cond_timedwait(cond_t *, mutex_t *, const struct timespec *); +int __libc_cond_destroy(cond_t *); +__END_DECLS + +#define cond_init(c, t, a) __libc_cond_init((c), (a)) +#define cond_signal(c) __libc_cond_signal((c)) +#define cond_broadcast(c) __libc_cond_broadcast((c)) +#define cond_wait(c, m) __libc_cond_wait((c), (m)) +#define cond_timedwait(c, m, t) __libc_cond_timedwait((c), (m), (t)) +#define cond_destroy(c) __libc_cond_destroy((c)) + +__BEGIN_DECLS +int __libc_rwlock_init(rwlock_t *, const rwlockattr_t *); +int __libc_rwlock_rdlock(rwlock_t *); +int __libc_rwlock_wrlock(rwlock_t *); +int __libc_rwlock_tryrdlock(rwlock_t *); +int __libc_rwlock_trywrlock(rwlock_t *); +int __libc_rwlock_unlock(rwlock_t *); +int __libc_rwlock_destroy(rwlock_t *); +__END_DECLS + +#define rwlock_init(l, a) __libc_rwlock_init((l), (a)) +#define rwlock_rdlock(l) __libc_rwlock_rdlock((l)) +#define rwlock_wrlock(l) __libc_rwlock_wrlock((l)) +#define rwlock_tryrdlock(l) __libc_rwlock_tryrdlock((l)) +#define rwlock_trywrlock(l) __libc_rwlock_trywrlock((l)) +#define rwlock_unlock(l) __libc_rwlock_unlock((l)) +#define rwlock_destroy(l) __libc_rwlock_destroy((l)) + +__BEGIN_DECLS +int __libc_thr_keycreate(thread_key_t *, void (*)(void *)); +int __libc_thr_setspecific(thread_key_t, const void *); +void *__libc_thr_getspecific(thread_key_t); +int __libc_thr_keydelete(thread_key_t); +__END_DECLS + +#define thr_keycreate(k, d) __libc_thr_keycreate((k), (d)) +#define thr_setspecific(k, p) __libc_thr_setspecific((k), (p)) +#define thr_getspecific(k) __libc_thr_getspecific((k)) +#define thr_keydelete(k) __libc_thr_keydelete((k)) + +__BEGIN_DECLS +int __libc_thr_once(once_t *, void (*)(void)); +int __libc_thr_sigsetmask(int, const sigset_t *, sigset_t *); +thr_t __libc_thr_self(void); +int __libc_thr_yield(void); +void __libc_thr_create(thr_t *, const thrattr_t *, + void *(*)(void *), void *); +void __libc_thr_exit(void *) __attribute__((__noreturn__)); +int *__libc_thr_errno(void); +int __libc_thr_setcancelstate(int, int *); + +extern int __isthreaded; +__END_DECLS + +#define thr_once(o, f) __libc_thr_once((o), (f)) +#define thr_sigsetmask(f, n, o) __libc_thr_sigsetmask((f), (n), (o)) +#define thr_self() __libc_thr_self() +#define thr_yield() __libc_thr_yield() +#define thr_create(tp, ta, f, a) __libc_thr_create((tp), (ta), (f), (a)) +#define thr_exit(v) __libc_thr_exit((v)) +#define thr_errno() __libc_thr_errno() +#define thr_enabled() (__isthreaded) +#define thr_setcancelstate(n, o) __libc_thr_setcancelstate((n),(o)) +#endif /* __LIBC_THREAD_STUBS */ + +#define FLOCKFILE(fp) __flockfile_internal(fp, 1) +#define FUNLOCKFILE(fp) __funlockfile_internal(fp, 1) + +#else /* _REENTRANT */ + +#define mutex_init(m, a) +#define mutex_lock(m) +#define mutex_trylock(m) +#define mutex_unlock(m) +#define mutex_destroy(m) + +#define cond_init(c, t, a) +#define cond_signal(c) +#define cond_broadcast(c) +#define cond_wait(c, m) +#define cond_timedwait(c, m, t) +#define cond_destroy(c) + +#define rwlock_init(l, a) +#define rwlock_rdlock(l) +#define rwlock_wrlock(l) +#define rwlock_tryrdlock(l) +#define rwlock_trywrlock(l) +#define rwlock_unlock(l) +#define rwlock_destroy(l) + +#define thr_keycreate(k, d) +#define thr_setspecific(k, p) +#define thr_getspecific(k) +#define thr_keydelete(k) + +#define thr_once(o, f) +#define thr_sigsetmask(f, n, o) +#define thr_self() +#define thr_errno() + +#define FLOCKFILE(fp) +#define FUNLOCKFILE(fp) + +#endif /* _REENTRANT */ diff --git a/libc/netbsd/net/servent.h b/libc/netbsd/net/servent.h new file mode 100644 index 0000000..822b375 --- /dev/null +++ b/libc/netbsd/net/servent.h @@ -0,0 +1,44 @@ +/* $NetBSD: servent.h,v 1.1 2005/04/18 19:39:45 kleink Exp $ */ + +/*- + * Copyright (c) 2004 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include "resolv_static.h" + +struct servent* getservent_r(res_static rs); diff --git a/libc/netbsd/net/services.h b/libc/netbsd/net/services.h new file mode 100644 index 0000000..fa199d0 --- /dev/null +++ b/libc/netbsd/net/services.h @@ -0,0 +1,480 @@ +/* generated by genserv.py - do not edit */ +static const char _services[] = "\ +\6tcpmux\0\1t\0\ +\4echo\0\7t\0\ +\4echo\0\7u\0\ +\7discard\0\11t\2\4sink\4null\ +\7discard\0\11u\2\4sink\4null\ +\6systat\0\13t\1\5users\ +\7daytime\0\15t\0\ +\7daytime\0\15u\0\ +\7netstat\0\17t\0\ +\4qotd\0\21t\1\5quote\ +\3msp\0\22t\0\ +\3msp\0\22u\0\ +\7chargen\0\23t\2\6ttytst\6source\ +\7chargen\0\23u\2\6ttytst\6source\ +\10ftp-data\0\24t\0\ +\3ftp\0\25t\0\ +\3fsp\0\25u\1\4fspd\ +\3ssh\0\26t\0\ +\3ssh\0\26u\0\ +\6telnet\0\27t\0\ +\4smtp\0\31t\1\4mail\ +\4time\0\45t\1\11timserver\ +\4time\0\45u\1\11timserver\ +\3rlp\0\47u\1\10resource\ +\12nameserver\0\52t\1\4name\ +\5whois\0\53t\1\7nicname\ +\6tacacs\0\61t\0\ +\6tacacs\0\61u\0\ +\12re-mail-ck\0\62t\0\ +\12re-mail-ck\0\62u\0\ +\6domain\0\65t\1\12nameserver\ +\6domain\0\65u\1\12nameserver\ +\3mtp\0\71t\0\ +\11tacacs-ds\0\101t\0\ +\11tacacs-ds\0\101u\0\ +\6bootps\0\103t\0\ +\6bootps\0\103u\0\ +\6bootpc\0\104t\0\ +\6bootpc\0\104u\0\ +\4tftp\0\105u\0\ +\6gopher\0\106t\0\ +\6gopher\0\106u\0\ +\3rje\0\115t\1\6netrjs\ +\6finger\0\117t\0\ +\3www\0\120t\1\4http\ +\3www\0\120u\0\ +\4link\0\127t\1\7ttylink\ +\10kerberos\0\130t\3\11kerberos5\4krb5\14kerberos-sec\ +\10kerberos\0\130u\3\11kerberos5\4krb5\14kerberos-sec\ +\6supdup\0\137t\0\ +\11hostnames\0\145t\1\10hostname\ +\10iso-tsap\0\146t\1\4tsap\ +\10acr-nema\0\150t\1\5dicom\ +\10acr-nema\0\150u\1\5dicom\ +\10csnet-ns\0\151t\1\6cso-ns\ +\10csnet-ns\0\151u\1\6cso-ns\ +\7rtelnet\0\153t\0\ +\7rtelnet\0\153u\0\ +\4pop2\0\155t\2\12postoffice\5pop-2\ +\4pop2\0\155u\1\5pop-2\ +\4pop3\0\156t\1\5pop-3\ +\4pop3\0\156u\1\5pop-3\ +\6sunrpc\0\157t\1\12portmapper\ +\6sunrpc\0\157u\1\12portmapper\ +\4auth\0\161t\3\16authentication\3tap\5ident\ +\4sftp\0\163t\0\ +\11uucp-path\0\165t\0\ +\4nntp\0\167t\2\10readnews\4untp\ +\3ntp\0\173t\0\ +\3ntp\0\173u\0\ +\6pwdgen\0\201t\0\ +\6pwdgen\0\201u\0\ +\7loc-srv\0\207t\1\5epmap\ +\7loc-srv\0\207u\1\5epmap\ +\12netbios-ns\0\211t\0\ +\12netbios-ns\0\211u\0\ +\13netbios-dgm\0\212t\0\ +\13netbios-dgm\0\212u\0\ +\13netbios-ssn\0\213t\0\ +\13netbios-ssn\0\213u\0\ +\5imap2\0\217t\1\4imap\ +\5imap2\0\217u\1\4imap\ +\4snmp\0\241t\0\ +\4snmp\0\241u\0\ +\11snmp-trap\0\242t\1\10snmptrap\ +\11snmp-trap\0\242u\1\10snmptrap\ +\10cmip-man\0\243t\0\ +\10cmip-man\0\243u\0\ +\12cmip-agent\0\244t\0\ +\12cmip-agent\0\244u\0\ +\5mailq\0\256t\0\ +\5mailq\0\256u\0\ +\5xdmcp\0\261t\0\ +\5xdmcp\0\261u\0\ +\10nextstep\0\262t\2\10NeXTStep\10NextStep\ +\10nextstep\0\262u\2\10NeXTStep\10NextStep\ +\3bgp\0\263t\0\ +\3bgp\0\263u\0\ +\10prospero\0\277t\0\ +\10prospero\0\277u\0\ +\3irc\0\302t\0\ +\3irc\0\302u\0\ +\4smux\0\307t\0\ +\4smux\0\307u\0\ +\7at-rtmp\0\311t\0\ +\7at-rtmp\0\311u\0\ +\6at-nbp\0\312t\0\ +\6at-nbp\0\312u\0\ +\7at-echo\0\314t\0\ +\7at-echo\0\314u\0\ +\6at-zis\0\316t\0\ +\6at-zis\0\316u\0\ +\4qmtp\0\321t\0\ +\4qmtp\0\321u\0\ +\5z3950\0\322t\1\4wais\ +\5z3950\0\322u\1\4wais\ +\3ipx\0\325t\0\ +\3ipx\0\325u\0\ +\5imap3\0\334t\0\ +\5imap3\0\334u\0\ +\7pawserv\1\131t\0\ +\7pawserv\1\131u\0\ +\5zserv\1\132t\0\ +\5zserv\1\132u\0\ +\7fatserv\1\133t\0\ +\7fatserv\1\133u\0\ +\13rpc2portmap\1\161t\0\ +\13rpc2portmap\1\161u\0\ +\11codaauth2\1\162t\0\ +\11codaauth2\1\162u\0\ +\11clearcase\1\163t\1\11Clearcase\ +\11clearcase\1\163u\1\11Clearcase\ +\11ulistserv\1\164t\0\ +\11ulistserv\1\164u\0\ +\4ldap\1\205t\0\ +\4ldap\1\205u\0\ +\4imsp\1\226t\0\ +\4imsp\1\226u\0\ +\5https\1\273t\0\ +\5https\1\273u\0\ +\4snpp\1\274t\0\ +\4snpp\1\274u\0\ +\14microsoft-ds\1\275t\0\ +\14microsoft-ds\1\275u\0\ +\4saft\1\347t\0\ +\4saft\1\347u\0\ +\6isakmp\1\364t\0\ +\6isakmp\1\364u\0\ +\4rtsp\2\52t\0\ +\4rtsp\2\52u\0\ +\3nqs\2\137t\0\ +\3nqs\2\137u\0\ +\12npmp-local\2\142t\1\16dqs313_qmaster\ +\12npmp-local\2\142u\1\16dqs313_qmaster\ +\10npmp-gui\2\143t\1\14dqs313_execd\ +\10npmp-gui\2\143u\1\14dqs313_execd\ +\10hmmp-ind\2\144t\1\20dqs313_intercell\ +\10hmmp-ind\2\144u\1\20dqs313_intercell\ +\3ipp\2\167t\0\ +\3ipp\2\167u\0\ +\4exec\2\0t\0\ +\4biff\2\0u\1\6comsat\ +\5login\2\1t\0\ +\3who\2\1u\1\4whod\ +\5shell\2\2t\1\3cmd\ +\6syslog\2\2u\0\ +\7printer\2\3t\1\7spooler\ +\4talk\2\5u\0\ +\5ntalk\2\6u\0\ +\5route\2\10u\2\6router\6routed\ +\5timed\2\15u\1\12timeserver\ +\5tempo\2\16t\1\7newdate\ +\7courier\2\22t\1\3rpc\ +\12conference\2\23t\1\4chat\ +\7netnews\2\24t\1\10readnews\ +\7netwall\2\25u\0\ +\6gdomap\2\32t\0\ +\6gdomap\2\32u\0\ +\4uucp\2\34t\1\5uucpd\ +\6klogin\2\37t\0\ +\6kshell\2\40t\1\5krcmd\ +\12afpovertcp\2\44t\0\ +\12afpovertcp\2\44u\0\ +\10remotefs\2\54t\2\12rfs_server\3rfs\ +\5nntps\2\63t\1\5snntp\ +\5nntps\2\63u\1\5snntp\ +\12submission\2\113t\0\ +\12submission\2\113u\0\ +\5ldaps\2\174t\0\ +\5ldaps\2\174u\0\ +\4tinc\2\217t\0\ +\4tinc\2\217u\0\ +\4silc\2\302t\0\ +\4silc\2\302u\0\ +\14kerberos-adm\2\355t\0\ +\7webster\2\375t\0\ +\7webster\2\375u\0\ +\5rsync\3\151t\0\ +\5rsync\3\151u\0\ +\11ftps-data\3\335t\0\ +\4ftps\3\336t\0\ +\7telnets\3\340t\0\ +\7telnets\3\340u\0\ +\5imaps\3\341t\0\ +\5imaps\3\341u\0\ +\4ircs\3\342t\0\ +\4ircs\3\342u\0\ +\5pop3s\3\343t\0\ +\5pop3s\3\343u\0\ +\5socks\4\70t\0\ +\5socks\4\70u\0\ +\6proofd\4\105t\0\ +\6proofd\4\105u\0\ +\5rootd\4\106t\0\ +\5rootd\4\106u\0\ +\7openvpn\4\252t\0\ +\7openvpn\4\252u\0\ +\13rmiregistry\4\113t\0\ +\13rmiregistry\4\113u\0\ +\5kazaa\4\276t\0\ +\5kazaa\4\276u\0\ +\6nessus\4\331t\0\ +\6nessus\4\331u\0\ +\11lotusnote\5\110t\1\12lotusnotes\ +\11lotusnote\5\110u\1\12lotusnotes\ +\10ms-sql-s\5\231t\0\ +\10ms-sql-s\5\231u\0\ +\10ms-sql-m\5\232t\0\ +\10ms-sql-m\5\232u\0\ +\12ingreslock\5\364t\0\ +\12ingreslock\5\364u\0\ +\13prospero-np\5\365t\0\ +\13prospero-np\5\365u\0\ +\13datametrics\6\155t\1\12old-radius\ +\13datametrics\6\155u\1\12old-radius\ +\13sa-msg-port\6\156t\1\13old-radacct\ +\13sa-msg-port\6\156u\1\13old-radacct\ +\6kermit\6\161t\0\ +\6kermit\6\161u\0\ +\3l2f\6\245t\1\4l2tp\ +\3l2f\6\245u\1\4l2tp\ +\6radius\7\24t\0\ +\6radius\7\24u\0\ +\13radius-acct\7\25t\1\7radacct\ +\13radius-acct\7\25u\1\7radacct\ +\13unix-status\7\245t\0\ +\12log-server\7\246t\0\ +\12remoteping\7\247t\0\ +\3nfs\10\1t\0\ +\3nfs\10\1u\0\ +\12rtcm-sc104\10\65t\0\ +\12rtcm-sc104\10\65u\0\ +\12cvspserver\11\141t\0\ +\12cvspserver\11\141u\0\ +\5venus\11\176t\0\ +\5venus\11\176u\0\ +\10venus-se\11\177t\0\ +\10venus-se\11\177u\0\ +\7codasrv\11\200t\0\ +\7codasrv\11\200u\0\ +\12codasrv-se\11\201t\0\ +\12codasrv-se\11\201u\0\ +\3mon\12\27t\0\ +\3mon\12\27u\0\ +\4dict\12\104t\0\ +\4dict\12\104u\0\ +\4gpsd\13\203t\0\ +\4gpsd\13\203u\0\ +\6gds_db\13\352t\0\ +\6gds_db\13\352u\0\ +\5icpv2\14\72t\1\3icp\ +\5icpv2\14\72u\1\3icp\ +\5mysql\14\352t\0\ +\5mysql\14\352u\0\ +\3nut\15\245t\0\ +\3nut\15\245u\0\ +\6distcc\16\60t\0\ +\6distcc\16\60u\0\ +\4daap\16\151t\0\ +\4daap\16\151u\0\ +\3svn\16\152t\1\12subversion\ +\3svn\16\152u\1\12subversion\ +\3iax\21\331t\0\ +\3iax\21\331u\0\ +\13radmin-port\23\43t\0\ +\13radmin-port\23\43u\0\ +\3rfe\23\212u\0\ +\3rfe\23\212t\0\ +\3sip\23\304t\0\ +\3sip\23\304u\0\ +\7sip-tls\23\305t\0\ +\7sip-tls\23\305u\0\ +\13xmpp-client\24\146t\1\15jabber-client\ +\13xmpp-client\24\146u\1\15jabber-client\ +\13xmpp-server\24\225t\1\15jabber-server\ +\13xmpp-server\24\225u\1\15jabber-server\ +\10cfengine\24\274t\0\ +\10cfengine\24\274u\0\ +\12postgresql\25\70t\1\10postgres\ +\12postgresql\25\70u\1\10postgres\ +\3x11\27\160t\1\5x11-0\ +\3x11\27\160u\1\5x11-0\ +\5x11-1\27\161t\0\ +\5x11-1\27\161u\0\ +\5x11-2\27\162t\0\ +\5x11-2\27\162u\0\ +\5x11-3\27\163t\0\ +\5x11-3\27\163u\0\ +\5x11-4\27\164t\0\ +\5x11-4\27\164u\0\ +\5x11-5\27\165t\0\ +\5x11-5\27\165u\0\ +\5x11-6\27\166t\0\ +\5x11-6\27\166u\0\ +\5x11-7\27\167t\0\ +\5x11-7\27\167u\0\ +\14gnutella-svc\30\312t\0\ +\14gnutella-svc\30\312u\0\ +\14gnutella-rtr\30\313t\0\ +\14gnutella-rtr\30\313u\0\ +\17afs3-fileserver\33\130t\1\3bbs\ +\17afs3-fileserver\33\130u\1\3bbs\ +\15afs3-callback\33\131t\0\ +\15afs3-callback\33\131u\0\ +\15afs3-prserver\33\132t\0\ +\15afs3-prserver\33\132u\0\ +\15afs3-vlserver\33\133t\0\ +\15afs3-vlserver\33\133u\0\ +\15afs3-kaserver\33\134t\0\ +\15afs3-kaserver\33\134u\0\ +\13afs3-volser\33\135t\0\ +\13afs3-volser\33\135u\0\ +\13afs3-errors\33\136t\0\ +\13afs3-errors\33\136u\0\ +\10afs3-bos\33\137t\0\ +\10afs3-bos\33\137u\0\ +\13afs3-update\33\140t\0\ +\13afs3-update\33\140u\0\ +\13afs3-rmtsys\33\141t\0\ +\13afs3-rmtsys\33\141u\0\ +\14font-service\33\274t\1\3xfs\ +\14font-service\33\274u\1\3xfs\ +\12bacula-dir\43\215t\0\ +\12bacula-dir\43\215u\0\ +\11bacula-fd\43\216t\0\ +\11bacula-fd\43\216u\0\ +\11bacula-sd\43\217t\0\ +\11bacula-sd\43\217u\0\ +\6amanda\47\140t\0\ +\6amanda\47\140u\0\ +\3hkp\54\153t\0\ +\3hkp\54\153u\0\ +\4bprd\65\230t\0\ +\4bprd\65\230u\0\ +\5bpdbm\65\231t\0\ +\5bpdbm\65\231u\0\ +\13bpjava-msvc\65\232t\0\ +\13bpjava-msvc\65\232u\0\ +\5vnetd\65\234t\0\ +\5vnetd\65\234u\0\ +\4bpcd\65\326t\0\ +\4bpcd\65\326u\0\ +\6vopied\65\327t\0\ +\6vopied\65\327u\0\ +\4wnn6\127\1t\0\ +\4wnn6\127\1u\0\ +\11kerberos4\2\356u\2\13kerberos-iv\3kdc\ +\11kerberos4\2\356t\2\13kerberos-iv\3kdc\ +\17kerberos_master\2\357u\0\ +\17kerberos_master\2\357t\0\ +\15passwd_server\2\360u\0\ +\10krb_prop\2\362t\2\11krb5_prop\5hprop\ +\11krbupdate\2\370t\1\4kreg\ +\7kpasswd\2\371t\1\4kpwd\ +\4swat\3\205t\0\ +\4kpop\4\125t\0\ +\5knetd\10\5t\0\ +\12zephyr-srv\10\66u\0\ +\12zephyr-clt\10\67u\0\ +\11zephyr-hm\10\70u\0\ +\7eklogin\10\71t\0\ +\2kx\10\77t\0\ +\5iprop\10\111t\0\ +\12supfilesrv\3\147t\0\ +\12supfiledbg\4\147t\0\ +\11linuxconf\0\142t\0\ +\10poppassd\0\152t\0\ +\10poppassd\0\152u\0\ +\5ssmtp\1\321t\1\5smtps\ +\10moira_db\3\7t\0\ +\14moira_update\3\11t\0\ +\12moira_ureg\3\13u\0\ +\5spamd\3\17t\0\ +\5omirr\3\50t\1\6omirrd\ +\5omirr\3\50u\1\6omirrd\ +\7customs\3\351t\0\ +\7customs\3\351u\0\ +\7skkserv\4\232t\0\ +\7predict\4\272u\0\ +\6rmtcfg\4\324t\0\ +\5wipld\5\24t\0\ +\4xtel\5\41t\0\ +\5xtelw\5\42t\0\ +\7support\5\371t\0\ +\5sieve\7\320t\0\ +\7cfinger\7\323t\0\ +\4ndtp\7\332t\0\ +\4frox\10\111t\0\ +\10ninstall\10\146t\0\ +\10ninstall\10\146u\0\ +\10zebrasrv\12\50t\0\ +\5zebra\12\51t\0\ +\4ripd\12\52t\0\ +\6ripngd\12\53t\0\ +\5ospfd\12\54t\0\ +\4bgpd\12\55t\0\ +\6ospf6d\12\56t\0\ +\7ospfapi\12\57t\0\ +\5isisd\12\60t\0\ +\10afbackup\13\254t\0\ +\10afbackup\13\254u\0\ +\11afmbackup\13\255t\0\ +\11afmbackup\13\255u\0\ +\5xtell\20\200t\0\ +\3fax\21\315t\0\ +\7hylafax\21\317t\0\ +\7distmp3\21\370t\0\ +\5munin\23\125t\1\4lrrd\ +\13enbd-cstatd\23\273t\0\ +\13enbd-sstatd\23\274t\0\ +\4pcrd\24\37t\0\ +\6noclog\24\352t\0\ +\6noclog\24\352u\0\ +\7hostmon\24\353t\0\ +\7hostmon\24\353u\0\ +\5rplay\25\263u\0\ +\5rplay\25\263t\0\ +\4rptp\25\264u\0\ +\4rptp\25\264t\0\ +\4nsca\26\43t\0\ +\4mrtd\26\52t\0\ +\6bgpsim\26\53t\0\ +\5canna\26\60t\0\ +\11sane-port\31\246t\2\4sane\5saned\ +\4ircd\32\13t\0\ +\10zope-ftp\37\125t\0\ +\10webcache\37\220t\0\ +\6tproxy\37\221t\0\ +\7omniorb\37\230t\0\ +\7omniorb\37\230u\0\ +\20clc-build-daemon\43\36t\0\ +\6xinetd\43\212t\0\ +\13mandelspawn\44\217u\1\12mandelbrot\ +\4zope\45\311t\0\ +\7kamanda\47\141t\0\ +\7kamanda\47\141u\0\ +\11amandaidx\47\142t\0\ +\11amidxtape\47\143t\0\ +\5smsqp\53\301t\0\ +\5smsqp\53\301u\0\ +\6xpilot\73\361t\0\ +\6xpilot\73\361u\0\ +\10sgi-cmsd\102\151u\0\ +\10sgi-crsd\102\152u\0\ +\7sgi-gcd\102\153u\0\ +\7sgi-cad\102\154t\0\ +\7isdnlog\116\53t\0\ +\7isdnlog\116\53u\0\ +\5vboxd\116\54t\0\ +\5vboxd\116\54u\0\ +\5binkp\137\352t\0\ +\3asp\152\356t\0\ +\3asp\152\356u\0\ +\11dircproxy\336\250t\0\ +\5tfido\353\21t\0\ +\4fido\353\23t\0\ +\0"; + diff --git a/libc/netbsd/resolv/__dn_comp.c b/libc/netbsd/resolv/__dn_comp.c new file mode 100644 index 0000000..93d3f19 --- /dev/null +++ b/libc/netbsd/resolv/__dn_comp.c @@ -0,0 +1,38 @@ +/* $NetBSD: __dn_comp.c,v 1.4 2005/09/13 01:44:10 christos Exp $ */ + +/* + * written by matthew green, 22/04/97. + * public domain. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: __dn_comp.c,v 1.4 2005/09/13 01:44:10 christos Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#if defined(__indr_reference) +__indr_reference(__dn_comp,dn_comp) +#else + +#include <sys/types.h> +#include <netinet/in.h> +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include <resolv.h> +#endif + +/* XXX THIS IS A MESS! SEE <resolv.h> XXX */ + +#undef dn_comp +int dn_comp(const char *, u_char *, int, u_char **, u_char **); + +int +dn_comp(const char *exp_dn, u_char *comp_dn, u_char **dnptrs, + u_char **lastdnptr, int length) +{ + + return __dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr); +} + +#endif diff --git a/libc/netbsd/resolv/__res_close.c b/libc/netbsd/resolv/__res_close.c new file mode 100644 index 0000000..3af50b0 --- /dev/null +++ b/libc/netbsd/resolv/__res_close.c @@ -0,0 +1,33 @@ +/* $NetBSD: __res_close.c,v 1.4 2005/09/13 01:44:10 christos Exp $ */ + +/* + * written by matthew green, 22/04/97. + * public domain. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: __res_close.c,v 1.4 2005/09/13 01:44:10 christos Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#if defined(__indr_reference) +__indr_reference(__res_close, res_close) +#else + +#include <sys/types.h> +#include <netinet/in.h> +#include "resolv_private.h" + +/* XXX THIS IS A MESS! SEE <resolv.h> XXX */ + +#undef res_close +void res_close(void); + +void +res_close(void) +{ + + __res_close(); +} + +#endif diff --git a/libc/netbsd/resolv/__res_send.c b/libc/netbsd/resolv/__res_send.c new file mode 100644 index 0000000..198b05c --- /dev/null +++ b/libc/netbsd/resolv/__res_send.c @@ -0,0 +1,37 @@ +/* $NetBSD: __res_send.c,v 1.4 2005/09/13 01:44:10 christos Exp $ */ + +/* + * written by matthew green, 22/04/97. + * public domain. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: __res_send.c,v 1.4 2005/09/13 01:44:10 christos Exp $"); +#endif + +#if defined(__indr_reference) +__indr_reference(__res_send, res_send) +#else + +#include <sys/types.h> +#include <netinet/in.h> +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include <resolv.h> +#endif + +/* XXX THIS IS A MESS! SEE <resolv.h> XXX */ + +#undef res_send +int res_send(const u_char *, int, u_char *, int); + +int +res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) +{ + + return __res_send(buf, buflen, ans, anssiz); +} + +#endif diff --git a/libc/netbsd/resolv/herror.c b/libc/netbsd/resolv/herror.c new file mode 100644 index 0000000..e90e641 --- /dev/null +++ b/libc/netbsd/resolv/herror.c @@ -0,0 +1,133 @@ +/* $NetBSD: herror.c,v 1.4 2004/05/23 05:09:52 christos Exp $ */ + +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#ifdef notdef +static const char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "Id: herror.c,v 1.2.206.1 2004/03/09 08:33:54 marka Exp"; +#else +__RCSID("$NetBSD: herror.c,v 1.4 2004/05/23 05:09:52 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/uio.h> + +#include <netinet/in.h> +#include "arpa_nameser.h" + +#include <netdb.h> +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include <resolv.h> +#endif +#include <string.h> +#include <unistd.h> + +#ifndef DE_CONST +#define DE_CONST(c,v) v = ((c) ? \ + strchr((const void *)(c), *(const char *)(const void *)(c)) : NULL) +#endif + +const char * const h_errlist[] = { + "Resolver Error 0 (no error)", + "Unknown host", /* 1 HOST_NOT_FOUND */ + "Host name lookup failure", /* 2 TRY_AGAIN */ + "Unknown server error", /* 3 NO_RECOVERY */ + "No address associated with name", /* 4 NO_ADDRESS */ +}; +const int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] }; + +/* + * herror -- + * print the error indicated by the h_errno value. + */ +void +herror(const char *s) { + struct iovec iov[4], *v = iov; + char *t; + + if (s != NULL && *s != '\0') { + DE_CONST(s, t); + v->iov_base = t; + v->iov_len = strlen(t); + v++; + DE_CONST(": ", t); + v->iov_base = t; + v->iov_len = 2; + v++; + } + DE_CONST(hstrerror(h_errno), t); + v->iov_base = t; + v->iov_len = strlen(v->iov_base); + v++; + DE_CONST("\n", t); + v->iov_base = t; + v->iov_len = 1; + writev(STDERR_FILENO, iov, (v - iov) + 1); +} + +/* + * hstrerror -- + * return the string associated with a given "host" errno value. + */ +const char * +hstrerror(int err) { + if (err < 0) + return ("Resolver internal error"); + else if (err < h_nerr) + return (h_errlist[err]); + return ("Unknown resolver error"); +} diff --git a/libc/netbsd/resolv/res_cache.c b/libc/netbsd/resolv/res_cache.c new file mode 100644 index 0000000..210dfdd --- /dev/null +++ b/libc/netbsd/resolv/res_cache.c @@ -0,0 +1,533 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "resolv_cache.h" +#include <stdlib.h> +#include <time.h> +#include "pthread.h" + +/* this code implements a small DNS resolver cache for all gethostbyname* functions + * + * the cache is shared between all threads of the current process, but the result of + * a succesful lookup is always copied to a thread-local variable to honor the persistence + * rules of the gethostbyname*() APIs. + */ + +/* the name of an environment variable that will be checked the first time this code is called + * if its value is "0", then the resolver cache is disabled. + */ +#define CONFIG_ENV "BIONIC_DNSCACHE" + +/* entries older than CONFIG_SECONDS seconds are always discarded. otherwise we could keep + * stale addresses in the cache and be oblivious to DNS server changes + */ +#define CONFIG_SECONDS (60*10) /* 10 minutes */ + +/* maximum number of entries kept in the cache. be frugal, this is the C library + * this MUST BE A POWER OF 2 + */ +#define CONFIG_MAX_ENTRIES 128 + +/****************************************************************************/ +/****************************************************************************/ +/***** *****/ +/***** *****/ +/***** *****/ +/****************************************************************************/ +/****************************************************************************/ + +#define DEBUG 0 + +#if DEBUG +#include <fcntl.h> +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +static void +xlog( const char* fmt, ... ) +{ + static int fd = -2; + int ret; + + if (fd == -2) { + do { + fd = open( "/data/dns.log", O_CREAT | O_APPEND | O_WRONLY, 0666 ); + } while (fd < 0 && errno == EINTR); + } + + if (fd >= 0) { + char temp[128]; + va_list args; + va_start(args, fmt); + vsnprintf( temp, sizeof(temp), fmt, args); + va_end(args); + + do { + ret = write( fd, temp, strlen(temp) ); + } while (ret == -1 && errno == EINTR); + } +} +#define XLOG(...) xlog(__VA_ARGS__) +#else +#define XLOG(...) ((void)0) +#endif + + +static time_t +_time_now( void ) +{ + struct timeval tv; + + gettimeofday( &tv, NULL ); + return tv.tv_sec; +} + +/****************************************************************************/ +/****************************************************************************/ +/***** *****/ +/***** *****/ +/***** *****/ +/****************************************************************************/ +/****************************************************************************/ + +/* used to define the content of _RESOLV_HOSTENT_NONE + */ +const struct hostent _resolv_hostent_none_cst = { + NULL, + NULL, + AF_INET, + 4, + NULL +}; + +struct hostent* +_resolv_hostent_copy( struct hostent* hp ) +{ + struct hostent* dst; + int nn, len; + char* p; + int num_aliases = 0, num_addresses = 0; + + if (hp == NULL) + return NULL; + + if (hp == _RESOLV_HOSTENT_NONE) + return hp; + + len = sizeof(*hp); + len += strlen(hp->h_name) + 1; + + if (hp->h_aliases != NULL) { + for (nn = 0; hp->h_aliases[nn] != NULL; nn++) + len += sizeof(char*) + strlen(hp->h_aliases[nn]) + 1; + num_aliases = nn; + } + len += sizeof(char*); + + for (nn = 0; hp->h_addr_list[nn] != NULL; nn++) { + len += sizeof(char*) + hp->h_length; + } + num_addresses = nn; + len += sizeof(char*); + + dst = malloc( len ); + if (dst == NULL) + return NULL; + + dst->h_aliases = (char**)(dst + 1); + dst->h_addr_list = dst->h_aliases + num_aliases + 1; + dst->h_length = hp->h_length; + dst->h_addrtype = hp->h_addrtype; + + p = (char*)(dst->h_addr_list + num_addresses + 1); + + /* write the addresses first, to help with alignment issues */ + for (nn = 0; nn < num_addresses; nn++) { + dst->h_addr_list[nn] = p; + len = hp->h_length; + memcpy( p, hp->h_addr_list[nn], len ); + p += len; + } + dst->h_addr_list[nn] = NULL; + + for (nn = 0; nn < num_aliases; nn++) { + dst->h_aliases[nn] = p; + len = strlen(hp->h_aliases[nn]) + 1; + memcpy( p, hp->h_aliases[nn], len ); + p += len; + } + dst->h_aliases[nn] = NULL; + + dst->h_name = p; + len = strlen(hp->h_name) + 1; + memcpy(p, hp->h_name, len); + p += len; + + return dst; +} + + +void +_resolv_hostent_free( struct hostent* hp ) +{ + if (hp && hp != _RESOLV_HOSTENT_NONE) + free(hp); +} + +/****************************************************************************/ +/****************************************************************************/ +/***** *****/ +/***** *****/ +/***** *****/ +/****************************************************************************/ +/****************************************************************************/ + +typedef struct Entry { + unsigned int hash; + const char* name; + short af; + short index; + struct Entry* mru_prev; + struct Entry* mru_next; + time_t when; + struct hostent* hp; +} Entry; + + +static void +entry_free( Entry* e ) +{ + /* everything is allocated in a single memory block */ + if (e) { + _resolv_hostent_free(e->hp); + free(e); + } +} + +static void +entry_init_key( Entry* e, const char* name, int af ) +{ + unsigned h = 0; + const char* p = name; + + /* compute hash */ + p = name; + while (*p) { + h = h*33 + *p++; + } + h += af*17; + + e->hash = h; + e->name = name; + e->af = (short) af; +} + + +static __inline__ void +entry_mru_remove( Entry* e ) +{ + e->mru_prev->mru_next = e->mru_next; + e->mru_next->mru_prev = e->mru_prev; +} + +static __inline__ void +entry_mru_add( Entry* e, Entry* list ) +{ + Entry* first = list->mru_next; + + e->mru_next = first; + e->mru_prev = list; + + list->mru_next = e; + first->mru_prev = e; +} + + +static Entry* +entry_alloc( const char* name, int af, int index, struct hostent* hp ) +{ + Entry* e; + int num_aliases = 0; + int num_addresses = 0; + char** aliases; + char** addresses; + + /* compute the length of the memory block that will contain everything */ + int len = sizeof(*e) + strlen(name)+1; + + e = malloc(len); + if (e == NULL) + return e; + + entry_init_key(e, name, af); + + e->mru_next = e->mru_prev = e; + e->index = (short) index; + e->when = _time_now(); + e->hp = _resolv_hostent_copy(hp); + + if (e->hp == NULL) { + free(e); + return NULL; + } + + e->name = (char*)(e+1); + len = strlen(name)+1; + memcpy( (char*)e->name, name, len ); + return e; +} + + +static __inline__ int +entry_equals( const Entry* e1, const Entry* e2 ) +{ + return e1->hash == e2->hash && e1->af == e2->af && !strcmp( e1->name, e2->name ); +} + +/****************************************************************************/ +/****************************************************************************/ +/***** *****/ +/***** *****/ +/***** *****/ +/****************************************************************************/ +/****************************************************************************/ + +#define MAX_HASH_ENTRIES (2*CONFIG_MAX_ENTRIES) + +typedef struct resolv_cache { + int num_entries; + Entry mru_list; + pthread_mutex_t lock; + int disabled; + Entry* entries[ MAX_HASH_ENTRIES ]; /* hash-table of pointers to entries */ +} Cache; + + +void +_resolv_cache_destroy( struct resolv_cache* cache ) +{ + if (cache != NULL) { + int nn; + for (nn = 0; nn < MAX_HASH_ENTRIES; nn++) { + entry_free(cache->entries[nn]); + } + pthread_mutex_destroy(&cache->lock); + free(cache); + } +} + + +struct resolv_cache* +_resolv_cache_create( void ) +{ + struct resolv_cache* cache; + + cache = calloc(sizeof(*cache), 1); + if (cache) { + const char* env = getenv(CONFIG_ENV); + + if (env && atoi(env) == 0) + cache->disabled = 1; + + pthread_mutex_init( &cache->lock, NULL ); + cache->mru_list.mru_prev = cache->mru_list.mru_next = &cache->mru_list; + XLOG("%s: cache=%p %s\n", __FUNCTION__, cache, cache->disabled ? "disabled" : "enabled" ); + } + return cache; +} + + +static int +_resolv_cache_find_index( Cache* cache, + const char* name, + int af ) +{ + Entry key; + int nn, step, tries; + + entry_init_key( &key, name, af ); + + tries = MAX_HASH_ENTRIES; + nn = key.hash % MAX_HASH_ENTRIES; + step = 5; + + while (tries > 0) { + Entry* key2 = cache->entries[nn]; + + if (key2 == NULL) { + return -(nn + 1); + } + + if (entry_equals( &key, key2 ) ) { + return nn; + } + + nn = (nn + step) % MAX_HASH_ENTRIES; + tries -= 1; + } + return -(MAX_HASH_ENTRIES+1); +} + + +static void +_resolv_cache_remove( struct resolv_cache* cache, + Entry* e ) +{ + XLOG("%s: name='%s' af=%d\n", __FUNCTION__, e->name, e->af); + cache->entries[ e->index ] = NULL; /* remove from hash table */ + entry_mru_remove( e ); + entry_free( e ); + cache->num_entries -= 1; +} + + +struct hostent* +_resolv_cache_lookup( struct resolv_cache* cache, + const char* name, + int af ) +{ + int index; + struct hostent* result = NULL; + + if (cache->disabled) + return NULL; + + pthread_mutex_lock( &cache->lock ); + + XLOG( "%s: cache=%p name='%s' af=%d ", __FUNCTION__, cache, name, af ); + index = _resolv_cache_find_index( cache, name, af ); + if (index >= 0) { + Entry* e = cache->entries[index]; + time_t now = _time_now(); + struct hostent** pht; + + /* ignore stale entries, they will be discarded in _resolv_cache_add */ + if ( (unsigned)(now - e->when) >= CONFIG_SECONDS ) { + XLOG( " OLD\n" ); + goto Exit; + } + + /* bump up this entry to the top of the MRU list */ + if (e != cache->mru_list.mru_next) { + entry_mru_remove( e ); + entry_mru_add( e, &cache->mru_list ); + } + + /* now copy the result into a thread-local variable */ + pht = __get_res_cache_hostent_p(); + if (pht == NULL) { + XLOG( " NOTLS\n" ); /* shouldn't happen */ + goto Exit; + } + + if (pht[0]) { + _resolv_hostent_free( pht[0] ); /* clear previous value */ + pht[0] = NULL; + } + result = _resolv_hostent_copy( e->hp ); + if (result == NULL) { + XLOG( " NOMEM\n" ); /* bummer */ + goto Exit; + } + XLOG( " OK\n" ); + pht[0] = result; + goto Exit; + } + XLOG( " KO\n" ); +Exit: + pthread_mutex_unlock( &cache->lock ); + return result; +} + + +void +_resolv_cache_add( struct resolv_cache* cache, + const char* name, + int af, + struct hostent* hp ) +{ + Entry* e; + int index; + + if (cache->disabled) + return; + + pthread_mutex_lock( &cache->lock ); + + XLOG( "%s: cache=%p name='%s' af=%d\n", __FUNCTION__, cache, name, af); + + /* get rid of the oldest entry if needed */ + if (cache->num_entries >= CONFIG_MAX_ENTRIES) { + Entry* oldest = cache->mru_list.mru_prev; + _resolv_cache_remove( cache, oldest ); + } + + index = _resolv_cache_find_index( cache, name, af ); + if (index >= 0) { + /* discard stale entry */ + _resolv_cache_remove( cache, cache->entries[index] ); + } else { + index = -(index+1); + if (index >= MAX_HASH_ENTRIES) + goto Exit; /* should not happen */ + } + + e = entry_alloc( name, af, index, hp ); + if (e != NULL) { + entry_mru_add( e, &cache->mru_list ); + cache->entries[index] = e; + cache->num_entries += 1; + } +Exit: + pthread_mutex_unlock( &cache->lock ); +} + +/****************************************************************************/ +/****************************************************************************/ +/***** *****/ +/***** *****/ +/***** *****/ +/****************************************************************************/ +/****************************************************************************/ + +static struct resolv_cache* _res_cache; +static pthread_once_t _res_cache_once; + +static void +_res_cache_init( void ) +{ + _res_cache = _resolv_cache_create(); +} + + +struct resolv_cache* +__get_res_cache( void ) +{ + pthread_once( &_res_cache_once, _res_cache_init ); + return _res_cache; +} diff --git a/libc/netbsd/resolv/res_comp.c b/libc/netbsd/resolv/res_comp.c new file mode 100644 index 0000000..6991e8b --- /dev/null +++ b/libc/netbsd/resolv/res_comp.c @@ -0,0 +1,259 @@ +/* $NetBSD: res_comp.c,v 1.6 2004/05/22 23:47:09 christos Exp $ */ + +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#ifdef notdef +static const char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "Id: res_comp.c,v 1.1.2.1.4.1 2004/03/09 08:33:54 marka Exp"; +#else +__RCSID("$NetBSD: res_comp.c,v 1.6 2004/05/22 23:47:09 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/param.h> +#include <netinet/in.h> +#include "arpa_nameser.h" +#include <ctype.h> +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include <resolv.h> +#endif +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +/* + * Expand compressed domain name 'src' to full domain name. + * 'msg' is a pointer to the begining of the message, + * 'eom' points to the first location after the message, + * 'dst' is a pointer to a buffer of size 'dstsiz' for the result. + * Return size of compressed name or -1 if there was an error. + */ +int +dn_expand(const u_char *msg, const u_char *eom, const u_char *src, + char *dst, int dstsiz) +{ + int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz); + + if (n > 0 && dst[0] == '.') + dst[0] = '\0'; + return (n); +} + +/* + * Pack domain name 'exp_dn' in presentation form into 'comp_dn'. + * Return the size of the compressed name or -1. + * 'length' is the size of the array pointed to by 'comp_dn'. + */ +int +dn_comp(const char *src, u_char *dst, int dstsiz, + u_char **dnptrs, u_char **lastdnptr) +{ + return (ns_name_compress(src, dst, (size_t)dstsiz, + (const u_char **)dnptrs, + (const u_char **)lastdnptr)); +} + +/* + * Skip over a compressed domain name. Return the size or -1. + */ +int +dn_skipname(const u_char *ptr, const u_char *eom) { + const u_char *saveptr = ptr; + + if (ns_name_skip(&ptr, eom) == -1) + return (-1); + return (ptr - saveptr); +} + +/* + * Verify that a domain name uses an acceptable character set. + */ + +/* + * Note the conspicuous absence of ctype macros in these definitions. On + * non-ASCII hosts, we can't depend on string literals or ctype macros to + * tell us anything about network-format data. The rest of the BIND system + * is not careful about this, but for some reason, we're doing it right here. + */ +#define PERIOD 0x2e +#define hyphenchar(c) ((c) == 0x2d) +#define bslashchar(c) ((c) == 0x5c) +#define periodchar(c) ((c) == PERIOD) +#define asterchar(c) ((c) == 0x2a) +#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \ + || ((c) >= 0x61 && (c) <= 0x7a)) +#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) + +#define borderchar(c) (alphachar(c) || digitchar(c)) +#define middlechar(c) (borderchar(c) || hyphenchar(c)) +#define domainchar(c) ((c) > 0x20 && (c) < 0x7f) + +int +res_hnok(const char *dn) { + int pch = PERIOD, ch = *dn++; + + while (ch != '\0') { + int nch = *dn++; + + if (periodchar(ch)) { + ; + } else if (periodchar(pch)) { + if (!borderchar(ch)) + return (0); + } else if (periodchar(nch) || nch == '\0') { + if (!borderchar(ch)) + return (0); + } else { + if (!middlechar(ch)) + return (0); + } + pch = ch, ch = nch; + } + return (1); +} + +/* + * hostname-like (A, MX, WKS) owners can have "*" as their first label + * but must otherwise be as a host name. + */ +int +res_ownok(const char *dn) { + if (asterchar(dn[0])) { + if (periodchar(dn[1])) + return (res_hnok(dn+2)); + if (dn[1] == '\0') + return (1); + } + return (res_hnok(dn)); +} + +/* + * SOA RNAMEs and RP RNAMEs can have any printable character in their first + * label, but the rest of the name has to look like a host name. + */ +int +res_mailok(const char *dn) { + int ch, escaped = 0; + + /* "." is a valid missing representation */ + if (*dn == '\0') + return (1); + + /* otherwise <label>.<hostname> */ + while ((ch = *dn++) != '\0') { + if (!domainchar(ch)) + return (0); + if (!escaped && periodchar(ch)) + break; + if (escaped) + escaped = 0; + else if (bslashchar(ch)) + escaped = 1; + } + if (periodchar(ch)) + return (res_hnok(dn)); + return (0); +} + +/* + * This function is quite liberal, since RFC 1034's character sets are only + * recommendations. + */ +int +res_dnok(const char *dn) { + int ch; + + while ((ch = *dn++) != '\0') + if (!domainchar(ch)) + return (0); + return (1); +} + +#ifdef BIND_4_COMPAT +/* + * This module must export the following externally-visible symbols: + * ___putlong + * ___putshort + * __getlong + * __getshort + * Note that one _ comes from C and the others come from us. + */ +void __putlong(u_int32_t src, u_char *dst) { ns_put32(src, dst); } +void __putshort(u_int16_t src, u_char *dst) { ns_put16(src, dst); } +#ifndef __ultrix__ +u_int32_t _getlong(const u_char *src) { return (ns_get32(src)); } +u_int16_t _getshort(const u_char *src) { return (ns_get16(src)); } +#endif /*__ultrix__*/ +#endif /*BIND_4_COMPAT*/ diff --git a/libc/netbsd/resolv/res_compat.c b/libc/netbsd/resolv/res_compat.c new file mode 100644 index 0000000..19a1d5f --- /dev/null +++ b/libc/netbsd/resolv/res_compat.c @@ -0,0 +1,87 @@ +/* $NetBSD: res_compat.c,v 1.1 2004/06/09 18:07:03 christos Exp $ */ + +/*- + * Copyright (c) 2004 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: res_compat.c,v 1.1 2004/06/09 18:07:03 christos Exp $"); +#endif + +#include <sys/types.h> +#include <arpa/inet.h> +#include "arpa_nameser.h" +#include <netdb.h> +#include <string.h> +#define __OLD_RES_STATE +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include "resolv.h" +#endif + +#undef _res + +/* + * Binary Compatibility; this symbol does not appear in a header file + * Most userland programs use this to set res_options before res_init() + * is called. There are hooks to res_init() to consult the data in this + * structure. The hooks are provided indirectly by the two functions below. + * We depend on the fact the the first 440 [32 bit machines] bytes are + * shared between the two structures. + */ +#ifndef __BIND_NOSTATIC +struct __res_state _res +#if defined(__BIND_RES_TEXT) + = { RES_TIMEOUT, } /* Motorola, et al. */ +# endif +; + +void *__res_get_old_state(void); +void __res_put_old_state(void *); + +void * +__res_get_old_state(void) +{ + return &_res; +} + +void +__res_put_old_state(void *res) +{ + (void)memcpy(&_res, res, sizeof(_res)); +} +#endif diff --git a/libc/netbsd/resolv/res_data.c b/libc/netbsd/resolv/res_data.c new file mode 100644 index 0000000..e60ecfd --- /dev/null +++ b/libc/netbsd/resolv/res_data.c @@ -0,0 +1,332 @@ +/* $NetBSD: res_data.c,v 1.8 2004/06/09 18:07:03 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1995-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#ifdef notdef +static const char rcsid[] = "Id: res_data.c,v 1.1.206.2 2004/03/16 12:34:18 marka Exp"; +#else +__RCSID("$NetBSD: res_data.c,v 1.8 2004/06/09 18:07:03 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + + + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include "arpa_nameser.h" + +#include <ctype.h> +#include <netdb.h> +#include "resolv_private.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +const char * const _res_opcodes[] = { + "QUERY", + "IQUERY", + "CQUERYM", + "CQUERYU", /* experimental */ + "NOTIFY", /* experimental */ + "UPDATE", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "ZONEINIT", + "ZONEREF", +}; + +#ifdef BIND_UPDATE +const char * const _res_sectioncodes[] = { + "ZONE", + "PREREQUISITES", + "UPDATE", + "ADDITIONAL", +}; +#endif + +#ifndef __BIND_NOSTATIC +extern struct __res_state _nres; + +/* Proto. */ + +int res_ourserver_p(const res_state, const struct sockaddr *); + +#ifdef ANDROID_CHANGES +int res_need_init() { + return ((_nres.options & RES_INIT) == 0U) || res_get_dns_changed(); +} +#else +#define res_need_init() ((_nres.options & RES_INIT) == 0U) +#endif + +int +res_init(void) { + int rv; + extern int __res_vinit(res_state, int); +#ifdef COMPAT__RES + /* + * Compatibility with program that were accessing _res directly + * to set options. We keep another struct res that is the same + * size as the original res structure, and then copy fields to + * it so that we achieve the same initialization + */ + extern void *__res_get_old_state(void); + extern void __res_put_old_state(void *); + res_state ores = __res_get_old_state(); + + if (ores->options != 0) + _nres.options = ores->options; + if (ores->retrans != 0) + _nres.retrans = ores->retrans; + if (ores->retry != 0) + _nres.retry = ores->retry; +#endif + + /* + * These three fields used to be statically initialized. This made + * it hard to use this code in a shared library. It is necessary, + * now that we're doing dynamic initialization here, that we preserve + * the old semantics: if an application modifies one of these three + * fields of _res before res_init() is called, res_init() will not + * alter them. Of course, if an application is setting them to + * _zero_ before calling res_init(), hoping to override what used + * to be the static default, we can't detect it and unexpected results + * will follow. Zero for any of these fields would make no sense, + * so one can safely assume that the applications were already getting + * unexpected results. + * + * _nres.options is tricky since some apps were known to diddle the bits + * before res_init() was first called. We can't replicate that semantic + * with dynamic initialization (they may have turned bits off that are + * set in RES_DEFAULT). Our solution is to declare such applications + * "broken". They could fool us by setting RES_INIT but none do (yet). + */ + if (!_nres.retrans) + _nres.retrans = RES_TIMEOUT; + if (!_nres.retry) + _nres.retry = 4; + if (!(_nres.options & RES_INIT)) + _nres.options = RES_DEFAULT; + + /* + * This one used to initialize implicitly to zero, so unless the app + * has set it to something in particular, we can randomize it now. + */ + if (!_nres.id) + _nres.id = res_randomid(); + + rv = __res_vinit(&_nres, 1); +#ifdef COMPAT__RES + __res_put_old_state(&_nres); +#endif + return rv; +} + +void +p_query(const u_char *msg) { + fp_query(msg, stdout); +} + +void +fp_query(const u_char *msg, FILE *file) { + fp_nquery(msg, PACKETSZ, file); +} + +void +fp_nquery(const u_char *msg, int len, FILE *file) { + if (res_need_init() && res_init() == -1) + return; + + res_pquery(&_nres, msg, len, file); +} + +int +res_mkquery(int op, /* opcode of query */ + const char *dname, /* domain name */ + int class, int type, /* class and type of query */ + const u_char *data, /* resource record data */ + int datalen, /* length of data */ + const u_char *newrr_in, /* new rr for modify or append */ + u_char *buf, /* buffer to put query */ + int buflen) /* size of buffer */ +{ + if (res_need_init() && res_init() == -1) { + RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); + return (-1); + } + return (res_nmkquery(&_nres, op, dname, class, type, + data, datalen, + newrr_in, buf, buflen)); +} + +#ifdef _LIBRESOLV +int +res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { + if (res_need_init() && res_init() == -1) { + RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); + return (-1); + } + + return (res_nmkupdate(&_nres, rrecp_in, buf, buflen)); +} +#endif + +int +res_query(const char *name, /* domain name */ + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen) /* size of answer buffer */ +{ + if (res_need_init() && res_init() == -1) { + RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); + return (-1); + } + return (res_nquery(&_nres, name, class, type, answer, anslen)); +} + +void +res_send_setqhook(res_send_qhook hook) { + _nres.qhook = hook; +} + +void +res_send_setrhook(res_send_rhook hook) { + _nres.rhook = hook; +} + +int +res_isourserver(const struct sockaddr_in *inp) { + return (res_ourserver_p(&_nres, (const struct sockaddr *)(const void *)inp)); +} + +int +res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) { + if (res_need_init() && res_init() == -1) { + /* errno should have been set by res_init() in this case. */ + return (-1); + } + + return (res_nsend(&_nres, buf, buflen, ans, anssiz)); +} + +#ifdef _LIBRESOLV +int +res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key, + u_char *ans, int anssiz) +{ + if (res_need_init() && res_init() == -1) { + /* errno should have been set by res_init() in this case. */ + return (-1); + } + + return (res_nsendsigned(&_nres, buf, buflen, key, ans, anssiz)); +} +#endif + +void +res_close(void) { + res_nclose(&_nres); +} + +#ifdef _LIBRESOLV +int +res_update(ns_updrec *rrecp_in) { + if (res_need_init() && res_init() == -1) { + RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); + return (-1); + } + + return (res_nupdate(&_nres, rrecp_in, NULL)); +} +#endif + +int +res_search(const char *name, /* domain name */ + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen) /* size of answer */ +{ + if (res_need_init() && res_init() == -1) { + RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); + return (-1); + } + + return (res_nsearch(&_nres, name, class, type, answer, anslen)); +} + +int +res_querydomain(const char *name, + const char *domain, + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen) /* size of answer */ +{ + if (res_need_init() && res_init() == -1) { + RES_SET_H_ERRNO(&_nres, NETDB_INTERNAL); + return (-1); + } + + return (res_nquerydomain(&_nres, name, domain, + class, type, + answer, anslen)); +} + +int +res_opt(int a, u_char *b, int c, int d) +{ + return res_nopt(&_nres, a, b, c, d); +} + +const char * +hostalias(const char *name) { + return NULL; +} + +#ifdef ultrix +int +local_hostname_length(const char *hostname) { + int len_host, len_domain; + + if (!*_nres.defdname) + res_init(); + len_host = strlen(hostname); + len_domain = strlen(_nres.defdname); + if (len_host > len_domain && + !strcasecmp(hostname + len_host - len_domain, _nres.defdname) && + hostname[len_host - len_domain - 1] == '.') + return (len_host - len_domain - 1); + return (0); +} +#endif /*ultrix*/ + +#endif diff --git a/libc/netbsd/resolv/res_debug.c b/libc/netbsd/resolv/res_debug.c new file mode 100644 index 0000000..84c6afc --- /dev/null +++ b/libc/netbsd/resolv/res_debug.c @@ -0,0 +1,1174 @@ +/* $NetBSD: res_debug.c,v 1.7 2004/11/07 02:25:01 christos Exp $ */ + +/* + * Copyright (c) 1985 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#ifdef notdef +static const char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "Id: res_debug.c,v 1.3.2.5.4.5 2004/07/28 20:16:46 marka Exp"; +#else +__RCSID("$NetBSD: res_debug.c,v 1.7 2004/11/07 02:25:01 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + + + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include "arpa_nameser.h" + +#include <ctype.h> +#include <errno.h> +#include <math.h> +#include <netdb.h> +#include "resolv_private.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + + + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) sprintf x +#endif + +static const char *precsize_ntoa(u_int32_t); + +extern const char * const _res_opcodes[]; +extern const char * const _res_sectioncodes[]; + +#ifndef _LIBC +/* + * Print the current options. + */ +void +fp_resstat(const res_state statp, FILE *file) { + u_long mask; + + fprintf(file, ";; res options:"); + for (mask = 1; mask != 0U; mask <<= 1) + if (statp->options & mask) + fprintf(file, " %s", p_option(mask)); + putc('\n', file); +} +#endif + +static void +do_section(const res_state statp, + ns_msg *handle, ns_sect section, + int pflag, FILE *file) +{ + int n, sflag, rrnum; + int buflen = 2048; + char *buf; + ns_opcode opcode; + ns_rr rr; + + /* + * Print answer records. + */ + sflag = (statp->pfcode & pflag); + if (statp->pfcode && !sflag) + return; + + buf = malloc((size_t)buflen); + if (buf == NULL) { + fprintf(file, ";; memory allocation failure\n"); + return; + } + + opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode); + rrnum = 0; + for (;;) { + if (ns_parserr(handle, section, rrnum, &rr)) { + if (errno != ENODEV) + fprintf(file, ";; ns_parserr: %s\n", + strerror(errno)); + else if (rrnum > 0 && sflag != 0 && + (statp->pfcode & RES_PRF_HEAD1)) + putc('\n', file); + goto cleanup; + } + if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1)) + fprintf(file, ";; %s SECTION:\n", + p_section(section, opcode)); + if (section == ns_s_qd) + fprintf(file, ";;\t%s, type = %s, class = %s\n", + ns_rr_name(rr), + p_type(ns_rr_type(rr)), + p_class(ns_rr_class(rr))); + else if (section == ns_s_ar && ns_rr_type(rr) == ns_t_opt) { + u_int32_t ttl = ns_rr_ttl(rr); + fprintf(file, + "; EDNS: version: %u, udp=%u, flags=%04x\n", + (ttl>>16)&0xff, ns_rr_class(rr), ttl&0xffff); + } else { + n = ns_sprintrr(handle, &rr, NULL, NULL, + buf, (u_int)buflen); + if (n < 0) { + if (errno == ENOSPC) { + free(buf); + buf = NULL; + if (buflen < 131072) + buf = malloc((size_t)(buflen += 1024)); + if (buf == NULL) { + fprintf(file, + ";; memory allocation failure\n"); + return; + } + continue; + } + fprintf(file, ";; ns_sprintrr: %s\n", + strerror(errno)); + goto cleanup; + } + fputs(buf, file); + fputc('\n', file); + } + rrnum++; + } + cleanup: + if (buf != NULL) + free(buf); +} + +/* + * Print the contents of a query. + * This is intended to be primarily a debugging routine. + */ +void +res_pquery(const res_state statp, const u_char *msg, int len, FILE *file) { + ns_msg handle; + int qdcount, ancount, nscount, arcount; + u_int opcode, rcode, id; + + if (ns_initparse(msg, len, &handle) < 0) { + fprintf(file, ";; ns_initparse: %s\n", strerror(errno)); + return; + } + opcode = ns_msg_getflag(handle, ns_f_opcode); + rcode = ns_msg_getflag(handle, ns_f_rcode); + id = ns_msg_id(handle); + qdcount = ns_msg_count(handle, ns_s_qd); + ancount = ns_msg_count(handle, ns_s_an); + nscount = ns_msg_count(handle, ns_s_ns); + arcount = ns_msg_count(handle, ns_s_ar); + + /* + * Print header fields. + */ + if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX) || rcode) + fprintf(file, + ";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n", + _res_opcodes[opcode], p_rcode((int)rcode), id); + if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX)) + putc(';', file); + if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD2)) { + fprintf(file, "; flags:"); + if (ns_msg_getflag(handle, ns_f_qr)) + fprintf(file, " qr"); + if (ns_msg_getflag(handle, ns_f_aa)) + fprintf(file, " aa"); + if (ns_msg_getflag(handle, ns_f_tc)) + fprintf(file, " tc"); + if (ns_msg_getflag(handle, ns_f_rd)) + fprintf(file, " rd"); + if (ns_msg_getflag(handle, ns_f_ra)) + fprintf(file, " ra"); + if (ns_msg_getflag(handle, ns_f_z)) + fprintf(file, " ??"); + if (ns_msg_getflag(handle, ns_f_ad)) + fprintf(file, " ad"); + if (ns_msg_getflag(handle, ns_f_cd)) + fprintf(file, " cd"); + } + if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD1)) { + fprintf(file, "; %s: %d", + p_section(ns_s_qd, (int)opcode), qdcount); + fprintf(file, ", %s: %d", + p_section(ns_s_an, (int)opcode), ancount); + fprintf(file, ", %s: %d", + p_section(ns_s_ns, (int)opcode), nscount); + fprintf(file, ", %s: %d", + p_section(ns_s_ar, (int)opcode), arcount); + } + if ((!statp->pfcode) || (statp->pfcode & + (RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) { + putc('\n',file); + } + /* + * Print the various sections. + */ + do_section(statp, &handle, ns_s_qd, RES_PRF_QUES, file); + do_section(statp, &handle, ns_s_an, RES_PRF_ANS, file); + do_section(statp, &handle, ns_s_ns, RES_PRF_AUTH, file); + do_section(statp, &handle, ns_s_ar, RES_PRF_ADD, file); + if (qdcount == 0 && ancount == 0 && + nscount == 0 && arcount == 0) + putc('\n', file); +} + +const u_char * +p_cdnname(const u_char *cp, const u_char *msg, int len, FILE *file) { + char name[MAXDNAME]; + int n; + + if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0) + return (NULL); + if (name[0] == '\0') + putc('.', file); + else + fputs(name, file); + return (cp + n); +} + +const u_char * +p_cdname(const u_char *cp, const u_char *msg, FILE *file) { + return (p_cdnname(cp, msg, PACKETSZ, file)); +} + +/* Return a fully-qualified domain name from a compressed name (with + length supplied). */ + +const u_char * +p_fqnname(cp, msg, msglen, name, namelen) + const u_char *cp, *msg; + int msglen; + char *name; + int namelen; +{ + int n, newlen; + + if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0) + return (NULL); + newlen = strlen(name); + if (newlen == 0 || name[newlen - 1] != '.') { + if (newlen + 1 >= namelen) /* Lack space for final dot */ + return (NULL); + else + strcpy(name + newlen, "."); + } + return (cp + n); +} + +/* XXX: the rest of these functions need to become length-limited, too. */ + +const u_char * +p_fqname(const u_char *cp, const u_char *msg, FILE *file) { + char name[MAXDNAME]; + const u_char *n; + + n = p_fqnname(cp, msg, MAXCDNAME, name, sizeof name); + if (n == NULL) + return (NULL); + fputs(name, file); + return (n); +} + +/* + * Names of RR classes and qclasses. Classes and qclasses are the same, except + * that C_ANY is a qclass but not a class. (You can ask for records of class + * C_ANY, but you can't have any records of that class in the database.) + */ +const struct res_sym __p_class_syms[] = { + {C_IN, "IN", (char *)0}, + {C_CHAOS, "CH", (char *)0}, + {C_CHAOS, "CHAOS", (char *)0}, + {C_HS, "HS", (char *)0}, + {C_HS, "HESIOD", (char *)0}, + {C_ANY, "ANY", (char *)0}, + {C_NONE, "NONE", (char *)0}, + {C_IN, (char *)0, (char *)0} +}; + +/* + * Names of message sections. + */ +const struct res_sym __p_default_section_syms[] = { + {ns_s_qd, "QUERY", (char *)0}, + {ns_s_an, "ANSWER", (char *)0}, + {ns_s_ns, "AUTHORITY", (char *)0}, + {ns_s_ar, "ADDITIONAL", (char *)0}, + {0, (char *)0, (char *)0} +}; + +const struct res_sym __p_update_section_syms[] = { + {S_ZONE, "ZONE", (char *)0}, + {S_PREREQ, "PREREQUISITE", (char *)0}, + {S_UPDATE, "UPDATE", (char *)0}, + {S_ADDT, "ADDITIONAL", (char *)0}, + {0, (char *)0, (char *)0} +}; + +const struct res_sym __p_key_syms[] = { + {NS_ALG_MD5RSA, "RSA", "RSA KEY with MD5 hash"}, + {NS_ALG_DH, "DH", "Diffie Hellman"}, + {NS_ALG_DSA, "DSA", "Digital Signature Algorithm"}, + {NS_ALG_EXPIRE_ONLY, "EXPIREONLY", "No algorithm"}, + {NS_ALG_PRIVATE_OID, "PRIVATE", "Algorithm obtained from OID"}, + {0, NULL, NULL} +}; + +const struct res_sym __p_cert_syms[] = { + {cert_t_pkix, "PKIX", "PKIX (X.509v3) Certificate"}, + {cert_t_spki, "SPKI", "SPKI certificate"}, + {cert_t_pgp, "PGP", "PGP certificate"}, + {cert_t_url, "URL", "URL Private"}, + {cert_t_oid, "OID", "OID Private"}, + {0, NULL, NULL} +}; + +/* + * Names of RR types and qtypes. Types and qtypes are the same, except + * that T_ANY is a qtype but not a type. (You can ask for records of type + * T_ANY, but you can't have any records of that type in the database.) + */ +const struct res_sym __p_type_syms[] = { + {ns_t_a, "A", "address"}, + {ns_t_ns, "NS", "name server"}, + {ns_t_md, "MD", "mail destination (deprecated)"}, + {ns_t_mf, "MF", "mail forwarder (deprecated)"}, + {ns_t_cname, "CNAME", "canonical name"}, + {ns_t_soa, "SOA", "start of authority"}, + {ns_t_mb, "MB", "mailbox"}, + {ns_t_mg, "MG", "mail group member"}, + {ns_t_mr, "MR", "mail rename"}, + {ns_t_null, "NULL", "null"}, + {ns_t_wks, "WKS", "well-known service (deprecated)"}, + {ns_t_ptr, "PTR", "domain name pointer"}, + {ns_t_hinfo, "HINFO", "host information"}, + {ns_t_minfo, "MINFO", "mailbox information"}, + {ns_t_mx, "MX", "mail exchanger"}, + {ns_t_txt, "TXT", "text"}, + {ns_t_rp, "RP", "responsible person"}, + {ns_t_afsdb, "AFSDB", "DCE or AFS server"}, + {ns_t_x25, "X25", "X25 address"}, + {ns_t_isdn, "ISDN", "ISDN address"}, + {ns_t_rt, "RT", "router"}, + {ns_t_nsap, "NSAP", "nsap address"}, + {ns_t_nsap_ptr, "NSAP_PTR", "domain name pointer"}, + {ns_t_sig, "SIG", "signature"}, + {ns_t_key, "KEY", "key"}, + {ns_t_px, "PX", "mapping information"}, + {ns_t_gpos, "GPOS", "geographical position (withdrawn)"}, + {ns_t_aaaa, "AAAA", "IPv6 address"}, + {ns_t_loc, "LOC", "location"}, + {ns_t_nxt, "NXT", "next valid name (unimplemented)"}, + {ns_t_eid, "EID", "endpoint identifier (unimplemented)"}, + {ns_t_nimloc, "NIMLOC", "NIMROD locator (unimplemented)"}, + {ns_t_srv, "SRV", "server selection"}, + {ns_t_atma, "ATMA", "ATM address (unimplemented)"}, + {ns_t_tkey, "TKEY", "tkey"}, + {ns_t_tsig, "TSIG", "transaction signature"}, + {ns_t_ixfr, "IXFR", "incremental zone transfer"}, + {ns_t_axfr, "AXFR", "zone transfer"}, + {ns_t_zxfr, "ZXFR", "compressed zone transfer"}, + {ns_t_mailb, "MAILB", "mailbox-related data (deprecated)"}, + {ns_t_maila, "MAILA", "mail agent (deprecated)"}, + {ns_t_naptr, "NAPTR", "URN Naming Authority"}, + {ns_t_kx, "KX", "Key Exchange"}, + {ns_t_cert, "CERT", "Certificate"}, + {ns_t_a6, "A6", "IPv6 Address"}, + {ns_t_dname, "DNAME", "dname"}, + {ns_t_sink, "SINK", "Kitchen Sink (experimental)"}, + {ns_t_opt, "OPT", "EDNS Options"}, + {ns_t_any, "ANY", "\"any\""}, + {0, NULL, NULL} +}; + +/* + * Names of DNS rcodes. + */ +const struct res_sym __p_rcode_syms[] = { + {ns_r_noerror, "NOERROR", "no error"}, + {ns_r_formerr, "FORMERR", "format error"}, + {ns_r_servfail, "SERVFAIL", "server failed"}, + {ns_r_nxdomain, "NXDOMAIN", "no such domain name"}, + {ns_r_notimpl, "NOTIMP", "not implemented"}, + {ns_r_refused, "REFUSED", "refused"}, + {ns_r_yxdomain, "YXDOMAIN", "domain name exists"}, + {ns_r_yxrrset, "YXRRSET", "rrset exists"}, + {ns_r_nxrrset, "NXRRSET", "rrset doesn't exist"}, + {ns_r_notauth, "NOTAUTH", "not authoritative"}, + {ns_r_notzone, "NOTZONE", "Not in zone"}, + {ns_r_max, "", ""}, + {ns_r_badsig, "BADSIG", "bad signature"}, + {ns_r_badkey, "BADKEY", "bad key"}, + {ns_r_badtime, "BADTIME", "bad time"}, + {0, NULL, NULL} +}; + +int +sym_ston(const struct res_sym *syms, const char *name, int *success) { + for (; syms->name != 0; syms++) { + if (strcasecmp (name, syms->name) == 0) { + if (success) + *success = 1; + return (syms->number); + } + } + if (success) + *success = 0; + return (syms->number); /* The default value. */ +} + +const char * +sym_ntos(const struct res_sym *syms, int number, int *success) { + static char unname[20]; + + for (; syms->name != 0; syms++) { + if (number == syms->number) { + if (success) + *success = 1; + return (syms->name); + } + } + + sprintf(unname, "%d", number); /* XXX nonreentrant */ + if (success) + *success = 0; + return (unname); +} + +const char * +sym_ntop(const struct res_sym *syms, int number, int *success) { + static char unname[20]; + + for (; syms->name != 0; syms++) { + if (number == syms->number) { + if (success) + *success = 1; + return (syms->humanname); + } + } + sprintf(unname, "%d", number); /* XXX nonreentrant */ + if (success) + *success = 0; + return (unname); +} + +/* + * Return a string for the type. + */ +const char * +p_type(int type) { + int success; + const char *result; + static char typebuf[20]; + + result = sym_ntos(__p_type_syms, type, &success); + if (success) + return (result); + if (type < 0 || type > 0xffff) + return ("BADTYPE"); + sprintf(typebuf, "TYPE%d", type); + return (typebuf); +} + +/* + * Return a string for the type. + */ +const char * +p_section(int section, int opcode) { + const struct res_sym *symbols; + + switch (opcode) { + case ns_o_update: + symbols = __p_update_section_syms; + break; + default: + symbols = __p_default_section_syms; + break; + } + return (sym_ntos(symbols, section, (int *)0)); +} + +/* + * Return a mnemonic for class. + */ +const char * +p_class(int class) { + int success; + const char *result; + static char classbuf[20]; + + result = sym_ntos(__p_class_syms, class, &success); + if (success) + return (result); + if (class < 0 || class > 0xffff) + return ("BADCLASS"); + sprintf(classbuf, "CLASS%d", class); + return (classbuf); +} + +/* + * Return a mnemonic for an option + */ +const char * +p_option(u_long option) { + static char nbuf[40]; + + switch (option) { + case RES_INIT: return "init"; + case RES_DEBUG: return "debug"; + case RES_AAONLY: return "aaonly(unimpl)"; + case RES_USEVC: return "usevc"; + case RES_PRIMARY: return "primry(unimpl)"; + case RES_IGNTC: return "igntc"; + case RES_RECURSE: return "recurs"; + case RES_DEFNAMES: return "defnam"; + case RES_STAYOPEN: return "styopn"; + case RES_DNSRCH: return "dnsrch"; + case RES_INSECURE1: return "insecure1"; + case RES_INSECURE2: return "insecure2"; + case RES_NOALIASES: return "noaliases"; + case RES_USE_INET6: return "inet6"; +#ifdef RES_USE_EDNS0 /* KAME extension */ + case RES_USE_EDNS0: return "edns0"; +#endif +#ifdef RES_USE_DNAME + case RES_USE_DNAME: return "dname"; +#endif +#ifdef RES_USE_DNSSEC + case RES_USE_DNSSEC: return "dnssec"; +#endif +#ifdef RES_NOTLDQUERY + case RES_NOTLDQUERY: return "no-tld-query"; +#endif +#ifdef RES_NO_NIBBLE2 + case RES_NO_NIBBLE2: return "no-nibble2"; +#endif + /* XXX nonreentrant */ + default: sprintf(nbuf, "?0x%lx?", (u_long)option); + return (nbuf); + } +} + +/* + * Return a mnemonic for a time to live. + */ +const char * +p_time(u_int32_t value) { + static char nbuf[40]; /* XXX nonreentrant */ + + if (ns_format_ttl((u_long)value, nbuf, sizeof nbuf) < 0) + sprintf(nbuf, "%u", value); + return (nbuf); +} + +/* + * Return a string for the rcode. + */ +const char * +p_rcode(int rcode) { + return (sym_ntos(__p_rcode_syms, rcode, (int *)0)); +} + +/* + * Return a string for a res_sockaddr_union. + */ +const char * +p_sockun(union res_sockaddr_union u, char *buf, size_t size) { + char ret[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:123.123.123.123"]; + + switch (u.sin.sin_family) { + case AF_INET: + inet_ntop(AF_INET, &u.sin.sin_addr, ret, sizeof ret); + break; +#ifdef HAS_INET6_STRUCTS + case AF_INET6: + inet_ntop(AF_INET6, &u.sin6.sin6_addr, ret, sizeof ret); + break; +#endif + default: + sprintf(ret, "[af%d]", u.sin.sin_family); + break; + } + if (size > 0U) { + strncpy(buf, ret, size - 1); + buf[size - 1] = '0'; + } + return (buf); +} + +/* + * routines to convert between on-the-wire RR format and zone file format. + * Does not contain conversion to/from decimal degrees; divide or multiply + * by 60*60*1000 for that. + */ + +static const unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000, + 1000000,10000000,100000000,1000000000}; + +/* takes an XeY precision/size value, returns a string representation. */ +static const char * +precsize_ntoa(prec) + u_int32_t prec; +{ + static char retbuf[sizeof "90000000.00"]; /* XXX nonreentrant */ + unsigned long val; + int mantissa, exponent; + + mantissa = (int)((prec >> 4) & 0x0f) % 10; + exponent = (int)((prec >> 0) & 0x0f) % 10; + + val = mantissa * poweroften[exponent]; + + (void) sprintf(retbuf, "%lu.%.2lu", val/100, val%100); + return (retbuf); +} + +/* converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer. */ +static u_int8_t +precsize_aton(const char **strptr) { + unsigned int mval = 0, cmval = 0; + u_int8_t retval = 0; + const char *cp; + int exponent; + int mantissa; + + cp = *strptr; + + while (isdigit((unsigned char)*cp)) + mval = mval * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* centimeters */ + cp++; + if (isdigit((unsigned char)*cp)) { + cmval = (*cp++ - '0') * 10; + if (isdigit((unsigned char)*cp)) { + cmval += (*cp++ - '0'); + } + } + } + cmval = (mval * 100) + cmval; + + for (exponent = 0; exponent < 9; exponent++) + if (cmval < poweroften[exponent+1]) + break; + + mantissa = cmval / poweroften[exponent]; + if (mantissa > 9) + mantissa = 9; + + retval = (mantissa << 4) | exponent; + + *strptr = cp; + + return (retval); +} + +/* converts ascii lat/lon to unsigned encoded 32-bit number. moves pointer. */ +static u_int32_t +latlon2ul(const char **latlonstrptr, int *which) { + const char *cp; + u_int32_t retval; + int deg = 0, min = 0, secs = 0, secsfrac = 0; + + cp = *latlonstrptr; + + while (isdigit((unsigned char)*cp)) + deg = deg * 10 + (*cp++ - '0'); + + while (isspace((unsigned char)*cp)) + cp++; + + if (!(isdigit((unsigned char)*cp))) + goto fndhemi; + + while (isdigit((unsigned char)*cp)) + min = min * 10 + (*cp++ - '0'); + + while (isspace((unsigned char)*cp)) + cp++; + + if (!(isdigit((unsigned char)*cp))) + goto fndhemi; + + while (isdigit((unsigned char)*cp)) + secs = secs * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* decimal seconds */ + cp++; + if (isdigit((unsigned char)*cp)) { + secsfrac = (*cp++ - '0') * 100; + if (isdigit((unsigned char)*cp)) { + secsfrac += (*cp++ - '0') * 10; + if (isdigit((unsigned char)*cp)) { + secsfrac += (*cp++ - '0'); + } + } + } + } + + while (!isspace((unsigned char)*cp)) /* if any trailing garbage */ + cp++; + + while (isspace((unsigned char)*cp)) + cp++; + + fndhemi: + switch (*cp) { + case 'N': case 'n': + case 'E': case 'e': + retval = ((unsigned)1<<31) + + (((((deg * 60) + min) * 60) + secs) * 1000) + + secsfrac; + break; + case 'S': case 's': + case 'W': case 'w': + retval = ((unsigned)1<<31) + - (((((deg * 60) + min) * 60) + secs) * 1000) + - secsfrac; + break; + default: + retval = 0; /* invalid value -- indicates error */ + break; + } + + switch (*cp) { + case 'N': case 'n': + case 'S': case 's': + *which = 1; /* latitude */ + break; + case 'E': case 'e': + case 'W': case 'w': + *which = 2; /* longitude */ + break; + default: + *which = 0; /* error */ + break; + } + + cp++; /* skip the hemisphere */ + + while (!isspace((unsigned char)*cp)) /* if any trailing garbage */ + cp++; + + while (isspace((unsigned char)*cp)) /* move to next field */ + cp++; + + *latlonstrptr = cp; + + return (retval); +} + +/* converts a zone file representation in a string to an RDATA on-the-wire + * representation. */ +int +loc_aton(ascii, binary) + const char *ascii; + u_char *binary; +{ + const char *cp, *maxcp; + u_char *bcp; + + u_int32_t latit = 0, longit = 0, alt = 0; + u_int32_t lltemp1 = 0, lltemp2 = 0; + int altmeters = 0, altfrac = 0, altsign = 1; + u_int8_t hp = 0x16; /* default = 1e6 cm = 10000.00m = 10km */ + u_int8_t vp = 0x13; /* default = 1e3 cm = 10.00m */ + u_int8_t siz = 0x12; /* default = 1e2 cm = 1.00m */ + int which1 = 0, which2 = 0; + + cp = ascii; + maxcp = cp + strlen(ascii); + + lltemp1 = latlon2ul(&cp, &which1); + + lltemp2 = latlon2ul(&cp, &which2); + + switch (which1 + which2) { + case 3: /* 1 + 2, the only valid combination */ + if ((which1 == 1) && (which2 == 2)) { /* normal case */ + latit = lltemp1; + longit = lltemp2; + } else if ((which1 == 2) && (which2 == 1)) { /* reversed */ + longit = lltemp1; + latit = lltemp2; + } else { /* some kind of brokenness */ + return (0); + } + break; + default: /* we didn't get one of each */ + return (0); + } + + /* altitude */ + if (*cp == '-') { + altsign = -1; + cp++; + } + + if (*cp == '+') + cp++; + + while (isdigit((unsigned char)*cp)) + altmeters = altmeters * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* decimal meters */ + cp++; + if (isdigit((unsigned char)*cp)) { + altfrac = (*cp++ - '0') * 10; + if (isdigit((unsigned char)*cp)) { + altfrac += (*cp++ - '0'); + } + } + } + + alt = (10000000 + (altsign * (altmeters * 100 + altfrac))); + + while (!isspace((unsigned char)*cp) && (cp < maxcp)) /* if trailing garbage or m */ + cp++; + + while (isspace((unsigned char)*cp) && (cp < maxcp)) + cp++; + + if (cp >= maxcp) + goto defaults; + + siz = precsize_aton(&cp); + + while (!isspace((unsigned char)*cp) && (cp < maxcp)) /* if trailing garbage or m */ + cp++; + + while (isspace((unsigned char)*cp) && (cp < maxcp)) + cp++; + + if (cp >= maxcp) + goto defaults; + + hp = precsize_aton(&cp); + + while (!isspace((unsigned char)*cp) && (cp < maxcp)) /* if trailing garbage or m */ + cp++; + + while (isspace((unsigned char)*cp) && (cp < maxcp)) + cp++; + + if (cp >= maxcp) + goto defaults; + + vp = precsize_aton(&cp); + + defaults: + + bcp = binary; + *bcp++ = (u_int8_t) 0; /* version byte */ + *bcp++ = siz; + *bcp++ = hp; + *bcp++ = vp; + PUTLONG(latit,bcp); + PUTLONG(longit,bcp); + PUTLONG(alt,bcp); + + return (16); /* size of RR in octets */ +} + +/* takes an on-the-wire LOC RR and formats it in a human readable format. */ +const char * +loc_ntoa(binary, ascii) + const u_char *binary; + char *ascii; +{ + static const char *error = "?"; + static char tmpbuf[sizeof +"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"]; + const u_char *cp = binary; + + int latdeg, latmin, latsec, latsecfrac; + int longdeg, longmin, longsec, longsecfrac; + char northsouth, eastwest; + const char *altsign; + int altmeters, altfrac; + + const u_int32_t referencealt = 100000 * 100; + + int32_t latval, longval, altval; + u_int32_t templ; + u_int8_t sizeval, hpval, vpval, versionval; + + char *sizestr, *hpstr, *vpstr; + + versionval = *cp++; + + if (ascii == NULL) + ascii = tmpbuf; + + if (versionval) { + (void) sprintf(ascii, "; error: unknown LOC RR version"); + return (ascii); + } + + sizeval = *cp++; + + hpval = *cp++; + vpval = *cp++; + + GETLONG(templ, cp); + latval = (templ - ((unsigned)1<<31)); + + GETLONG(templ, cp); + longval = (templ - ((unsigned)1<<31)); + + GETLONG(templ, cp); + if (templ < referencealt) { /* below WGS 84 spheroid */ + altval = referencealt - templ; + altsign = "-"; + } else { + altval = templ - referencealt; + altsign = ""; + } + + if (latval < 0) { + northsouth = 'S'; + latval = -latval; + } else + northsouth = 'N'; + + latsecfrac = latval % 1000; + latval = latval / 1000; + latsec = latval % 60; + latval = latval / 60; + latmin = latval % 60; + latval = latval / 60; + latdeg = latval; + + if (longval < 0) { + eastwest = 'W'; + longval = -longval; + } else + eastwest = 'E'; + + longsecfrac = longval % 1000; + longval = longval / 1000; + longsec = longval % 60; + longval = longval / 60; + longmin = longval % 60; + longval = longval / 60; + longdeg = longval; + + altfrac = altval % 100; + altmeters = (altval / 100); + + sizestr = strdup(precsize_ntoa((u_int32_t)sizeval)); + hpstr = strdup(precsize_ntoa((u_int32_t)hpval)); + vpstr = strdup(precsize_ntoa((u_int32_t)vpval)); + + sprintf(ascii, + "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %s%d.%.2dm %sm %sm %sm", + latdeg, latmin, latsec, latsecfrac, northsouth, + longdeg, longmin, longsec, longsecfrac, eastwest, + altsign, altmeters, altfrac, + (sizestr != NULL) ? sizestr : error, + (hpstr != NULL) ? hpstr : error, + (vpstr != NULL) ? vpstr : error); + + if (sizestr != NULL) + free(sizestr); + if (hpstr != NULL) + free(hpstr); + if (vpstr != NULL) + free(vpstr); + + return (ascii); +} + + +/* Return the number of DNS hierarchy levels in the name. */ +int +dn_count_labels(const char *name) { + int i, len, count; + + len = strlen(name); + for (i = 0, count = 0; i < len; i++) { + /* XXX need to check for \. or use named's nlabels(). */ + if (name[i] == '.') + count++; + } + + /* don't count initial wildcard */ + if (name[0] == '*') + if (count) + count--; + + /* don't count the null label for root. */ + /* if terminating '.' not found, must adjust */ + /* count to include last label */ + if (len > 0 && name[len-1] != '.') + count++; + return (count); +} + + +/* + * Make dates expressed in seconds-since-Jan-1-1970 easy to read. + * SIG records are required to be printed like this, by the Secure DNS RFC. + */ +char * +p_secstodate (u_long secs) { + /* XXX nonreentrant */ + static char output[15]; /* YYYYMMDDHHMMSS and null */ + time_t myclock = secs; + struct tm *mytime; +#ifdef HAVE_TIME_R + struct tm res; + + mytime = gmtime_r(&myclock, &res); +#else + mytime = gmtime(&myclock); +#endif + mytime->tm_year += 1900; + mytime->tm_mon += 1; + sprintf(output, "%04d%02d%02d%02d%02d%02d", + mytime->tm_year, mytime->tm_mon, mytime->tm_mday, + mytime->tm_hour, mytime->tm_min, mytime->tm_sec); + return (output); +} + +u_int16_t +res_nametoclass(const char *buf, int *successp) { + unsigned long result; + char *endptr; + int success; + + result = sym_ston(__p_class_syms, buf, &success); + if (success) + goto done; + + if (strncasecmp(buf, "CLASS", 5) != 0 || + !isdigit((unsigned char)buf[5])) + goto done; + errno = 0; + result = strtoul(buf + 5, &endptr, 10); + if (errno == 0 && *endptr == '\0' && result <= 0xffffU) + success = 1; + done: + if (successp) + *successp = success; + return (u_int16_t)(result); +} + +u_int16_t +res_nametotype(const char *buf, int *successp) { + unsigned long result; + char *endptr; + int success; + + result = sym_ston(__p_type_syms, buf, &success); + if (success) + goto done; + + if (strncasecmp(buf, "type", 4) != 0 || + !isdigit((unsigned char)buf[4])) + goto done; + errno = 0; + result = strtoul(buf + 4, &endptr, 10); + if (errno == 0 && *endptr == '\0' && result <= 0xffffU) + success = 1; + done: + if (successp) + *successp = success; + return (u_int16_t)(result); +} diff --git a/libc/netbsd/resolv/res_debug.h b/libc/netbsd/resolv/res_debug.h new file mode 100644 index 0000000..4341c5a --- /dev/null +++ b/libc/netbsd/resolv/res_debug.h @@ -0,0 +1,36 @@ +/* $NetBSD: res_debug.h,v 1.1.1.1 2004/05/20 17:18:55 christos Exp $ */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _RES_DEBUG_H_ +#define _RES_DEBUG_H_ + +#ifndef DEBUG +# define Dprint(cond, args) /*empty*/ +# define DprintQ(cond, args, query, size) /*empty*/ +# define Aerror(statp, file, string, error, address) /*empty*/ +# define Perror(statp, file, string, error) /*empty*/ +#else +# define Dprint(cond, args) if (cond) {fprintf args;} else {} +# define DprintQ(cond, args, query, size) if (cond) {\ + fprintf args;\ + res_pquery(statp, query, size, stdout);\ + } else {} +#endif + +#endif /* _RES_DEBUG_H_ */ diff --git a/libc/netbsd/resolv/res_init.c b/libc/netbsd/resolv/res_init.c new file mode 100644 index 0000000..fc0272c --- /dev/null +++ b/libc/netbsd/resolv/res_init.c @@ -0,0 +1,863 @@ +/* $NetBSD: res_init.c,v 1.8 2006/03/19 03:10:08 christos Exp $ */ + +/* + * Copyright (c) 1985, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#ifdef notdef +static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93"; +static const char rcsid[] = "Id: res_init.c,v 1.9.2.5.4.2 2004/03/16 12:34:18 marka Exp"; +#else +__RCSID("$NetBSD: res_init.c,v 1.8 2006/03/19 03:10:08 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + + + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include "arpa_nameser.h" + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <netdb.h> + +#ifdef ANDROID_CHANGES +#include <sys/system_properties.h> +#endif /* ANDROID_CHANGES */ + +#ifndef MIN +#define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + +/* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */ +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#define MAX_DNS_PROPERTIES 8 +#define DNS_PROP_NAME_PREFIX "net.dns" +#define DNS_CHANGE_PROP_NAME "net.dnschange" +const prop_info *dns_change_prop; +int dns_last_change_counter; +static int _get_dns_change_count(); +#else +#include <resolv.h> +#endif + +#include "res_private.h" + +/* Options. Should all be left alone. */ +#ifndef DEBUG +#define DEBUG +#endif + +static void res_setoptions __P((res_state, const char *, const char *)); + +static const char sort_mask[] = "/&"; +#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL) +static u_int32_t net_mask __P((struct in_addr)); + +#if !defined(isascii) /* XXX - could be a function */ +# define isascii(c) (!(c & 0200)) +#endif + +/* + * Resolver state default settings. + */ + +/* + * Set up default settings. If the configuration file exist, the values + * there will have precedence. Otherwise, the server address is set to + * INADDR_ANY and the default domain name comes from the gethostname(). + * + * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1 + * rather than INADDR_ANY ("0.0.0.0") as the default name server address + * since it was noted that INADDR_ANY actually meant ``the first interface + * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface, + * it had to be "up" in order for you to reach your own name server. It + * was later decided that since the recommended practice is to always + * install local static routes through 127.0.0.1 for all your network + * interfaces, that we could solve this problem without a code change. + * + * The configuration file should always be used, since it is the only way + * to specify a default domain. If you are running a server on your local + * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1" + * in the configuration file. + * + * Return 0 if completes successfully, -1 on error + */ +int +res_ninit(res_state statp) { + extern int __res_vinit(res_state, int); + + return (__res_vinit(statp, 0)); +} + +/* This function has to be reachable by res_data.c but not publicly. */ +int +__res_vinit(res_state statp, int preinit) { + register FILE *fp; + register char *cp, **pp; + register int n; + char buf[BUFSIZ]; + int nserv = 0; /* number of nameserver records read from file */ + int haveenv = 0; + int havesearch = 0; + int nsort = 0; + char *net; + int dots; + union res_sockaddr_union u[2]; +#ifdef ANDROID_CHANGES + pid_t mypid = getpid(); + int use_proc_props = 0; + int found_prop; + char dnsProperty[PROP_VALUE_MAX]; +#endif + + if (!preinit) { + statp->retrans = RES_TIMEOUT; + statp->retry = RES_DFLRETRY; + statp->options = RES_DEFAULT; + statp->id = res_randomid(); + } + + if ((statp->options & RES_INIT) != 0U) + res_ndestroy(statp); + + memset(u, 0, sizeof(u)); +#ifdef USELOOPBACK + u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); +#else + u[nserv].sin.sin_addr.s_addr = INADDR_ANY; +#endif + u[nserv].sin.sin_family = AF_INET; + u[nserv].sin.sin_port = htons(NAMESERVER_PORT); +#ifdef HAVE_SA_LEN + u[nserv].sin.sin_len = sizeof(struct sockaddr_in); +#endif + nserv++; +#ifdef HAS_INET6_STRUCTS +#ifdef USELOOPBACK + u[nserv].sin6.sin6_addr = in6addr_loopback; +#else + u[nserv].sin6.sin6_addr = in6addr_any; +#endif + u[nserv].sin6.sin6_family = AF_INET6; + u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT); +#ifdef HAVE_SA_LEN + u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6); +#endif + nserv++; +#endif + statp->nscount = 0; + statp->ndots = 1; + statp->pfcode = 0; + statp->_vcsock = -1; + statp->_flags = 0; + statp->qhook = NULL; + statp->rhook = NULL; + statp->_u._ext.nscount = 0; + statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext)); + if (statp->_u._ext.ext != NULL) { + memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext)); + statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr; + strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa"); + strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int"); + } + statp->nsort = 0; + res_setservers(statp, u, nserv); + +#if 0 /* IGNORE THE ENVIRONMENT */ + /* Allow user to override the local domain definition */ + if ((cp = getenv("LOCALDOMAIN")) != NULL) { + (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); + statp->defdname[sizeof(statp->defdname) - 1] = '\0'; + haveenv++; + + /* + * Set search list to be blank-separated strings + * from rest of env value. Permits users of LOCALDOMAIN + * to still have a search list, and anyone to set the + * one that they want to use as an individual (even more + * important now that the rfc1535 stuff restricts searches) + */ + cp = statp->defdname; + pp = statp->dnsrch; + *pp++ = cp; + for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { + if (*cp == '\n') /* silly backwards compat */ + break; + else if (*cp == ' ' || *cp == '\t') { + *cp = 0; + n = 1; + } else if (n) { + *pp++ = cp; + n = 0; + havesearch = 1; + } + } + /* null terminate last domain if there are excess */ + while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') + cp++; + *cp = '\0'; + *pp++ = 0; + } + if (nserv > 0) + statp->nscount = nserv; +#endif +#ifdef ANDROID_CHANGES /* READ FROM SYSTEM PROPERTIES */ + dns_last_change_counter = _get_dns_change_count(); + + nserv = 0; + for(n = 1; n <= MAX_DNS_PROPERTIES && nserv < MAXNS; n++) { + char propname[PROP_NAME_MAX]; + char propvalue[PROP_VALUE_MAX]; + + struct addrinfo hints, *ai; + char sbuf[NI_MAXSERV]; + const size_t minsiz = sizeof(statp->_u._ext.ext->nsaddrs[0]); + + /* + * Check first for process-specific properties, and if those don't + * exist, try the generic properties. + */ + found_prop = 0; + if (n == 1 || use_proc_props) { + snprintf(propname, sizeof(propname), "%s%d.%d", DNS_PROP_NAME_PREFIX, n, mypid); + if(__system_property_get(propname, propvalue) < 1) { + if (use_proc_props) { + break; + } + } else { + found_prop = 1; + use_proc_props = 1; + } + } + if (!found_prop) { + snprintf(propname, sizeof(propname), "%s%d", DNS_PROP_NAME_PREFIX, n); + if(__system_property_get(propname, propvalue) < 1) { + break; + } + } + + cp = propvalue; + + while (*cp == ' ' || *cp == '\t') + cp++; + cp[strcspn(cp, ";# \t\n")] = '\0'; + if ((*cp != '\0') && (*cp != '\n')) { + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + sprintf(sbuf, "%u", NAMESERVER_PORT); + if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 && + (size_t)ai->ai_addrlen <= minsiz) { + if (statp->_u._ext.ext != NULL) { + memcpy(&statp->_u._ext.ext->nsaddrs[nserv], + ai->ai_addr, ai->ai_addrlen); + } + if ((size_t)ai->ai_addrlen <= + sizeof(statp->nsaddr_list[nserv])) { + memcpy(&statp->nsaddr_list[nserv], + ai->ai_addr, ai->ai_addrlen); + } else { + statp->nsaddr_list[nserv].sin_family = 0; + } + freeaddrinfo(ai); + nserv++; + } + } + } +#else /* IGNORE resolv.conf */ +#define MATCH(line, name) \ + (!strncmp(line, name, sizeof(name) - 1) && \ + (line[sizeof(name) - 1] == ' ' || \ + line[sizeof(name) - 1] == '\t')) + + nserv = 0; + if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { + /* read the config file */ + while (fgets(buf, sizeof(buf), fp) != NULL) { + /* skip comments */ + if (*buf == ';' || *buf == '#') + continue; + /* read default domain name */ + if (MATCH(buf, "domain")) { + if (haveenv) /* skip if have from environ */ + continue; + cp = buf + sizeof("domain") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + if ((*cp == '\0') || (*cp == '\n')) + continue; + strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); + statp->defdname[sizeof(statp->defdname) - 1] = '\0'; + if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL) + *cp = '\0'; + havesearch = 0; + continue; + } + /* set search list */ + if (MATCH(buf, "search")) { + if (haveenv) /* skip if have from environ */ + continue; + cp = buf + sizeof("search") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + if ((*cp == '\0') || (*cp == '\n')) + continue; + strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); + statp->defdname[sizeof(statp->defdname) - 1] = '\0'; + if ((cp = strchr(statp->defdname, '\n')) != NULL) + *cp = '\0'; + /* + * Set search list to be blank-separated strings + * on rest of line. + */ + cp = statp->defdname; + pp = statp->dnsrch; + *pp++ = cp; + for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { + if (*cp == ' ' || *cp == '\t') { + *cp = 0; + n = 1; + } else if (n) { + *pp++ = cp; + n = 0; + } + } + /* null terminate last domain if there are excess */ + while (*cp != '\0' && *cp != ' ' && *cp != '\t') + cp++; + *cp = '\0'; + *pp++ = 0; + havesearch = 1; + continue; + } + /* read nameservers to query */ + if (MATCH(buf, "nameserver") && nserv < MAXNS) { + struct addrinfo hints, *ai; + char sbuf[NI_MAXSERV]; + const size_t minsiz = + sizeof(statp->_u._ext.ext->nsaddrs[0]); + + cp = buf + sizeof("nameserver") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + cp[strcspn(cp, ";# \t\n")] = '\0'; + if ((*cp != '\0') && (*cp != '\n')) { + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + sprintf(sbuf, "%u", NAMESERVER_PORT); + if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 && + ai->ai_addrlen <= minsiz) { + if (statp->_u._ext.ext != NULL) { + memcpy(&statp->_u._ext.ext->nsaddrs[nserv], + ai->ai_addr, ai->ai_addrlen); + } + if (ai->ai_addrlen <= + sizeof(statp->nsaddr_list[nserv])) { + memcpy(&statp->nsaddr_list[nserv], + ai->ai_addr, ai->ai_addrlen); + } else + statp->nsaddr_list[nserv].sin_family = 0; + freeaddrinfo(ai); + nserv++; + } + } + continue; + } + if (MATCH(buf, "sortlist")) { + struct in_addr a; + + cp = buf + sizeof("sortlist") - 1; + while (nsort < MAXRESOLVSORT) { + while (*cp == ' ' || *cp == '\t') + cp++; + if (*cp == '\0' || *cp == '\n' || *cp == ';') + break; + net = cp; + while (*cp && !ISSORTMASK(*cp) && *cp != ';' && + isascii(*cp) && !isspace((unsigned char)*cp)) + cp++; + n = *cp; + *cp = 0; + if (inet_aton(net, &a)) { + statp->sort_list[nsort].addr = a; + if (ISSORTMASK(n)) { + *cp++ = n; + net = cp; + while (*cp && *cp != ';' && + isascii(*cp) && + !isspace((unsigned char)*cp)) + cp++; + n = *cp; + *cp = 0; + if (inet_aton(net, &a)) { + statp->sort_list[nsort].mask = a.s_addr; + } else { + statp->sort_list[nsort].mask = + net_mask(statp->sort_list[nsort].addr); + } + } else { + statp->sort_list[nsort].mask = + net_mask(statp->sort_list[nsort].addr); + } + nsort++; + } + *cp = n; + } + continue; + } + if (MATCH(buf, "options")) { + res_setoptions(statp, buf + sizeof("options") - 1, "conf"); + continue; + } + } + if (nserv > 0) + statp->nscount = nserv; + statp->nsort = nsort; + (void) fclose(fp); + } +#endif /* ANDROID_CHANGES */ +/* + * Last chance to get a nameserver. This should not normally + * be necessary + */ +#ifdef NO_RESOLV_CONF + if(nserv == 0) + nserv = get_nameservers(statp); +#endif + + if (statp->defdname[0] == 0 && + gethostname(buf, sizeof(statp->defdname) - 1) == 0 && + (cp = strchr(buf, '.')) != NULL) + strcpy(statp->defdname, cp + 1); + + /* find components of local domain that might be searched */ + if (havesearch == 0) { + pp = statp->dnsrch; + *pp++ = statp->defdname; + *pp = NULL; + + dots = 0; + for (cp = statp->defdname; *cp; cp++) + dots += (*cp == '.'); + + cp = statp->defdname; + while (pp < statp->dnsrch + MAXDFLSRCH) { + if (dots < LOCALDOMAINPARTS) + break; + cp = strchr(cp, '.') + 1; /* we know there is one */ + *pp++ = cp; + dots--; + } + *pp = NULL; +#ifdef DEBUG + if (statp->options & RES_DEBUG) { + printf(";; res_init()... default dnsrch list:\n"); + for (pp = statp->dnsrch; *pp; pp++) + printf(";;\t%s\n", *pp); + printf(";;\t..END..\n"); + } +#endif + } + + if ((cp = getenv("RES_OPTIONS")) != NULL) + res_setoptions(statp, cp, "env"); + if (nserv > 0) { + statp->nscount = nserv; + statp->options |= RES_INIT; + } + return (0); +} + +static void +res_setoptions(res_state statp, const char *options, const char *source) +{ + const char *cp = options; + int i; + struct __res_state_ext *ext = statp->_u._ext.ext; + +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_setoptions(\"%s\", \"%s\")...\n", + options, source); +#endif + while (*cp) { + /* skip leading and inner runs of spaces */ + while (*cp == ' ' || *cp == '\t') + cp++; + /* search for and process individual options */ + if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) { + i = atoi(cp + sizeof("ndots:") - 1); + if (i <= RES_MAXNDOTS) + statp->ndots = i; + else + statp->ndots = RES_MAXNDOTS; +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";;\tndots=%d\n", statp->ndots); +#endif + } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) { + i = atoi(cp + sizeof("timeout:") - 1); + if (i <= RES_MAXRETRANS) + statp->retrans = i; + else + statp->retrans = RES_MAXRETRANS; +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";;\ttimeout=%d\n", statp->retrans); +#endif + } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){ + i = atoi(cp + sizeof("attempts:") - 1); + if (i <= RES_MAXRETRY) + statp->retry = i; + else + statp->retry = RES_MAXRETRY; +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";;\tattempts=%d\n", statp->retry); +#endif + } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) { +#ifdef DEBUG + if (!(statp->options & RES_DEBUG)) { + printf(";; res_setoptions(\"%s\", \"%s\")..\n", + options, source); + statp->options |= RES_DEBUG; + } + printf(";;\tdebug\n"); +#endif + } else if (!strncmp(cp, "no_tld_query", + sizeof("no_tld_query") - 1) || + !strncmp(cp, "no-tld-query", + sizeof("no-tld-query") - 1)) { + statp->options |= RES_NOTLDQUERY; + } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) { + statp->options |= RES_USE_INET6; + } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) { + statp->options |= RES_ROTATE; + } else if (!strncmp(cp, "no-check-names", + sizeof("no-check-names") - 1)) { + statp->options |= RES_NOCHECKNAME; + } +#ifdef RES_USE_EDNS0 + else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) { + statp->options |= RES_USE_EDNS0; + } +#endif + else if (!strncmp(cp, "dname", sizeof("dname") - 1)) { + statp->options |= RES_USE_DNAME; + } + else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) { + if (ext == NULL) + goto skip; + cp += sizeof("nibble:") - 1; + i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1); + strncpy(ext->nsuffix, cp, (size_t)i); + ext->nsuffix[i] = '\0'; + } + else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) { + if (ext == NULL) + goto skip; + cp += sizeof("nibble2:") - 1; + i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1); + strncpy(ext->nsuffix2, cp, (size_t)i); + ext->nsuffix2[i] = '\0'; + } + else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) { + cp += sizeof("v6revmode:") - 1; + /* "nibble" and "bitstring" used to be valid */ + if (!strncmp(cp, "single", sizeof("single") - 1)) { + statp->options |= RES_NO_NIBBLE2; + } else if (!strncmp(cp, "both", sizeof("both") - 1)) { + statp->options &= + ~RES_NO_NIBBLE2; + } + } + else { + /* XXX - print a warning here? */ + } + skip: + /* skip to next run of spaces */ + while (*cp && *cp != ' ' && *cp != '\t') + cp++; + } +} + +/* XXX - should really support CIDR which means explicit masks always. */ +static u_int32_t +net_mask(in) /* XXX - should really use system's version of this */ + struct in_addr in; +{ + register u_int32_t i = ntohl(in.s_addr); + + if (IN_CLASSA(i)) + return (htonl(IN_CLASSA_NET)); + else if (IN_CLASSB(i)) + return (htonl(IN_CLASSB_NET)); + return (htonl(IN_CLASSC_NET)); +} + +u_int +res_randomid(void) { + struct timeval now; + + gettimeofday(&now, NULL); + return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid())); +} + +/* + * This routine is for closing the socket if a virtual circuit is used and + * the program wants to close it. This provides support for endhostent() + * which expects to close the socket. + * + * This routine is not expected to be user visible. + */ +void +res_nclose(res_state statp) { + int ns; + + if (statp->_vcsock >= 0) { + (void) close(statp->_vcsock); + statp->_vcsock = -1; + statp->_flags &= ~(RES_F_VC | RES_F_CONN); + } + for (ns = 0; ns < statp->_u._ext.nscount; ns++) { + if (statp->_u._ext.nssocks[ns] != -1) { + (void) close(statp->_u._ext.nssocks[ns]); + statp->_u._ext.nssocks[ns] = -1; + } + } +} + +void +res_ndestroy(res_state statp) { + res_nclose(statp); + if (statp->_u._ext.ext != NULL) + free(statp->_u._ext.ext); + statp->options &= ~RES_INIT; + statp->_u._ext.ext = NULL; +} + +const char * +res_get_nibblesuffix(res_state statp) { + if (statp->_u._ext.ext) + return (statp->_u._ext.ext->nsuffix); + return ("ip6.arpa"); +} + +const char * +res_get_nibblesuffix2(res_state statp) { + if (statp->_u._ext.ext) + return (statp->_u._ext.ext->nsuffix2); + return ("ip6.int"); +} + +void +res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) { + int i, nserv; + size_t size; + + /* close open servers */ + res_nclose(statp); + + /* cause rtt times to be forgotten */ + statp->_u._ext.nscount = 0; + + nserv = 0; + for (i = 0; i < cnt && nserv < MAXNS; i++) { + switch (set->sin.sin_family) { + case AF_INET: + size = sizeof(set->sin); + if (statp->_u._ext.ext) + memcpy(&statp->_u._ext.ext->nsaddrs[nserv], + &set->sin, size); + if (size <= sizeof(statp->nsaddr_list[nserv])) + memcpy(&statp->nsaddr_list[nserv], + &set->sin, size); +#ifdef notdef + else + statp->nsaddr_list[nserv].sin_family = 0; +#endif + nserv++; + break; + +#ifdef HAS_INET6_STRUCTS + case AF_INET6: + size = sizeof(set->sin6); + if (statp->_u._ext.ext) + memcpy(&statp->_u._ext.ext->nsaddrs[nserv], + &set->sin6, size); + if (size <= sizeof(statp->nsaddr_list[nserv])) + memcpy(&statp->nsaddr_list[nserv], + &set->sin6, size); + else + statp->nsaddr_list[nserv].sin_family = 0; + nserv++; + break; +#endif + + default: + break; + } + set++; + } + statp->nscount = nserv; + +} + +int +res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) { + int i; + size_t size; + u_int16_t family; + + for (i = 0; i < statp->nscount && i < cnt; i++) { + if (statp->_u._ext.ext) + family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family; + else + family = statp->nsaddr_list[i].sin_family; + + switch (family) { + case AF_INET: + size = sizeof(set->sin); + if (statp->_u._ext.ext) + memcpy(&set->sin, + &statp->_u._ext.ext->nsaddrs[i], + size); + else + memcpy(&set->sin, &statp->nsaddr_list[i], + size); + break; + +#ifdef HAS_INET6_STRUCTS + case AF_INET6: + size = sizeof(set->sin6); + if (statp->_u._ext.ext) + memcpy(&set->sin6, + &statp->_u._ext.ext->nsaddrs[i], + size); + else + memcpy(&set->sin6, &statp->nsaddr_list[i], + size); + break; +#endif + + default: + set->sin.sin_family = 0; + break; + } + set++; + } + return (statp->nscount); +} + +#ifdef ANDROID_CHANGES +static int _get_dns_change_count() +{ + if (dns_change_prop == NULL) { + dns_change_prop = __system_property_find(DNS_CHANGE_PROP_NAME); + } + if (dns_change_prop != NULL) { + char propvalue[PROP_VALUE_MAX]; + if (__system_property_read(dns_change_prop, NULL, propvalue) >= 1) { + return atoi(propvalue); + } + } + return -1; +} + +int res_get_dns_changed() +{ + int change_count; + + change_count = _get_dns_change_count(); + if (change_count != dns_last_change_counter) { + if (change_count != -1) { + dns_last_change_counter = change_count; + } + return 1; + } else { + return 0; + } +} +#endif /* ANDROID_CHANGES */ diff --git a/libc/netbsd/resolv/res_mkquery.c b/libc/netbsd/resolv/res_mkquery.c new file mode 100644 index 0000000..fb4de7f --- /dev/null +++ b/libc/netbsd/resolv/res_mkquery.c @@ -0,0 +1,276 @@ +/* $NetBSD: res_mkquery.c,v 1.6 2006/01/24 17:40:32 christos Exp $ */ + +/* + * Copyright (c) 2008 Android Open Source Project (query id randomization) + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#ifdef notdef +static const char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "Id: res_mkquery.c,v 1.1.2.2.4.2 2004/03/16 12:34:18 marka Exp"; +#else +__RCSID("$NetBSD: res_mkquery.c,v 1.6 2006/01/24 17:40:32 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + + + +#include <sys/types.h> +#include <sys/param.h> +#include <netinet/in.h> +#include "arpa_nameser.h" +#include <netdb.h> +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include <resolv.h> +#endif +#include <stdio.h> +#include <string.h> + +/* Options. Leave them on. */ +#ifndef DEBUG +#define DEBUG +#endif + +#ifndef lint +#define UNUSED(a) (void)&a +#else +#define UNUSED(a) a = a +#endif + +extern const char *_res_opcodes[]; + +/* + * Form all types of queries. + * Returns the size of the result or -1. + */ +int +res_nmkquery(res_state statp, + int op, /* opcode of query */ + const char *dname, /* domain name */ + int class, int type, /* class and type of query */ + const u_char *data, /* resource record data */ + int datalen, /* length of data */ + const u_char *newrr_in, /* new rr for modify or append */ + u_char *buf, /* buffer to put query */ + int buflen) /* size of buffer */ +{ + register HEADER *hp; + register u_char *cp, *ep; + register int n; + u_char *dnptrs[20], **dpp, **lastdnptr; + + UNUSED(newrr_in); + +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_nmkquery(%s, %s, %s, %s)\n", + _res_opcodes[op], dname, p_class(class), p_type(type)); +#endif + /* + * Initialize header fields. + */ + if ((buf == NULL) || (buflen < HFIXEDSZ)) + return (-1); + memset(buf, 0, HFIXEDSZ); + hp = (HEADER *)(void *)buf; + hp->id = htons(res_randomid()); + hp->opcode = op; + hp->rd = (statp->options & RES_RECURSE) != 0U; + hp->rcode = NOERROR; + cp = buf + HFIXEDSZ; + ep = buf + buflen; + dpp = dnptrs; + *dpp++ = buf; + *dpp++ = NULL; + lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; + /* + * perform opcode specific processing + */ + switch (op) { + case QUERY: /*FALLTHROUGH*/ + case NS_NOTIFY_OP: + if (ep - cp < QFIXEDSZ) + return (-1); + if ((n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs, + lastdnptr)) < 0) + return (-1); + cp += n; + ns_put16(type, cp); + cp += INT16SZ; + ns_put16(class, cp); + cp += INT16SZ; + hp->qdcount = htons(1); + if (op == QUERY || data == NULL) + break; + /* + * Make an additional record for completion domain. + */ + if ((ep - cp) < RRFIXEDSZ) + return (-1); + n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ, + dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + ns_put16(T_NULL, cp); + cp += INT16SZ; + ns_put16(class, cp); + cp += INT16SZ; + ns_put32(0, cp); + cp += INT32SZ; + ns_put16(0, cp); + cp += INT16SZ; + hp->arcount = htons(1); + break; + + case IQUERY: + /* + * Initialize answer section + */ + if (ep - cp < 1 + RRFIXEDSZ + datalen) + return (-1); + *cp++ = '\0'; /* no domain name */ + ns_put16(type, cp); + cp += INT16SZ; + ns_put16(class, cp); + cp += INT16SZ; + ns_put32(0, cp); + cp += INT32SZ; + ns_put16(datalen, cp); + cp += INT16SZ; + if (datalen) { + memcpy(cp, data, (size_t)datalen); + cp += datalen; + } + hp->ancount = htons(1); + break; + + default: + return (-1); + } + return (cp - buf); +} + +#ifdef RES_USE_EDNS0 +/* attach OPT pseudo-RR, as documented in RFC2671 (EDNS0). */ +#ifndef T_OPT +#define T_OPT 41 +#endif + +int +res_nopt(res_state statp, + int n0, /* current offset in buffer */ + u_char *buf, /* buffer to put query */ + int buflen, /* size of buffer */ + int anslen) /* UDP answer buffer size */ +{ + register HEADER *hp; + register u_char *cp, *ep; + u_int16_t flags = 0; + +#ifdef DEBUG + if ((statp->options & RES_DEBUG) != 0U) + printf(";; res_nopt()\n"); +#endif + + hp = (HEADER *)(void *)buf; + cp = buf + n0; + ep = buf + buflen; + + if ((ep - cp) < 1 + RRFIXEDSZ) + return (-1); + + *cp++ = 0; /* "." */ + + ns_put16(T_OPT, cp); /* TYPE */ + cp += INT16SZ; + ns_put16(anslen & 0xffff, cp); /* CLASS = UDP payload size */ + cp += INT16SZ; + *cp++ = NOERROR; /* extended RCODE */ + *cp++ = 0; /* EDNS version */ + if (statp->options & RES_USE_DNSSEC) { +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_opt()... ENDS0 DNSSEC\n"); +#endif + flags |= NS_OPT_DNSSEC_OK; + } + ns_put16(flags, cp); + cp += INT16SZ; + ns_put16(0, cp); /* RDLEN */ + cp += INT16SZ; + hp->arcount = htons(ntohs(hp->arcount) + 1); + + return (cp - buf); +} +#endif diff --git a/libc/netbsd/resolv/res_private.h b/libc/netbsd/resolv/res_private.h new file mode 100644 index 0000000..8341913 --- /dev/null +++ b/libc/netbsd/resolv/res_private.h @@ -0,0 +1,22 @@ +/* $NetBSD: res_private.h,v 1.1.1.1 2004/05/20 17:18:54 christos Exp $ */ + +#ifndef res_private_h +#define res_private_h + +struct __res_state_ext { + union res_sockaddr_union nsaddrs[MAXNS]; + struct sort_list { + int af; + union { + struct in_addr ina; + struct in6_addr in6a; + } addr, mask; + } sort_list[MAXRESOLVSORT]; + char nsuffix[64]; + char nsuffix2[64]; +}; + +extern int +res_ourserver_p(const res_state statp, const struct sockaddr *sa); + +#endif diff --git a/libc/netbsd/resolv/res_query.c b/libc/netbsd/resolv/res_query.c new file mode 100644 index 0000000..8e1321e --- /dev/null +++ b/libc/netbsd/resolv/res_query.c @@ -0,0 +1,415 @@ +/* $NetBSD: res_query.c,v 1.7 2006/01/24 17:41:25 christos Exp $ */ + +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#ifdef notdef +static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "Id: res_query.c,v 1.2.2.3.4.2 2004/03/16 12:34:19 marka Exp"; +#else +__RCSID("$NetBSD: res_query.c,v 1.7 2006/01/24 17:41:25 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + + + +#include <sys/types.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "arpa_nameser.h" +#include <ctype.h> +#include <errno.h> +#include <netdb.h> +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include <resolv.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#define DISABLE_HOST_ALIAS 1 + +/* Options. Leave them on. */ +#ifndef DEBUG +#define DEBUG +#endif + +#if PACKETSZ > 1024 +#define MAXPACKET PACKETSZ +#else +#define MAXPACKET 1024 +#endif + +/* + * Formulate a normal query, send, and await answer. + * Returned answer is placed in supplied buffer "answer". + * Perform preliminary check of answer, returning success only + * if no error is indicated and the answer count is nonzero. + * Return the size of the response on success, -1 on error. + * Error number is left in H_ERRNO. + * + * Caller must parse answer and determine whether it answers the question. + */ +int +res_nquery(res_state statp, + const char *name, /* domain name */ + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen) /* size of answer buffer */ +{ + u_char buf[MAXPACKET]; + HEADER *hp = (HEADER *)(void *)answer; + int n; + u_int oflags; + + oflags = statp->_flags; + +again: + hp->rcode = NOERROR; /* default */ + +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_query(%s, %d, %d)\n", name, class, type); +#endif + + n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL, + buf, sizeof(buf)); +#ifdef RES_USE_EDNS0 + if (n > 0 && (statp->_flags & RES_F_EDNS0ERR) == 0 && + (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U) + n = res_nopt(statp, n, buf, sizeof(buf), anslen); +#endif + if (n <= 0) { +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_query: mkquery failed\n"); +#endif + RES_SET_H_ERRNO(statp, NO_RECOVERY); + return (n); + } + n = res_nsend(statp, buf, n, answer, anslen); + if (n < 0) { +#ifdef RES_USE_EDNS0 + /* if the query choked with EDNS0, retry without EDNS0 */ + if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U && + ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) { + statp->_flags |= RES_F_EDNS0ERR; + if (statp->options & RES_DEBUG) + printf(";; res_nquery: retry without EDNS0\n"); + goto again; + } +#endif +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_query: send error\n"); +#endif + RES_SET_H_ERRNO(statp, TRY_AGAIN); + return (n); + } + + if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; rcode = (%s), counts = an:%d ns:%d ar:%d\n", + p_rcode(hp->rcode), + ntohs(hp->ancount), + ntohs(hp->nscount), + ntohs(hp->arcount)); +#endif + switch (hp->rcode) { + case NXDOMAIN: + RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); + break; + case SERVFAIL: + RES_SET_H_ERRNO(statp, TRY_AGAIN); + break; + case NOERROR: + RES_SET_H_ERRNO(statp, NO_DATA); + break; + case FORMERR: + case NOTIMP: + case REFUSED: + default: + RES_SET_H_ERRNO(statp, NO_RECOVERY); + break; + } + return (-1); + } + return (n); +} + +/* + * Formulate a normal query, send, and retrieve answer in supplied buffer. + * Return the size of the response on success, -1 on error. + * If enabled, implement search rules until answer or unrecoverable failure + * is detected. Error code, if any, is left in H_ERRNO. + */ +int +res_nsearch(res_state statp, + const char *name, /* domain name */ + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen) /* size of answer */ +{ + const char *cp, * const *domain; + HEADER *hp = (HEADER *)(void *)answer; + char tmp[NS_MAXDNAME]; + u_int dots; + int trailing_dot, ret, saved_herrno; + int got_nodata = 0, got_servfail = 0, root_on_list = 0; + int tried_as_is = 0; + int searched = 0; + + errno = 0; + RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); /* True if we never query. */ + + dots = 0; + for (cp = name; *cp != '\0'; cp++) + dots += (*cp == '.'); + trailing_dot = 0; + if (cp > name && *--cp == '.') + trailing_dot++; + + /* If there aren't any dots, it could be a user-level alias. */ + if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL) + return (res_nquery(statp, cp, class, type, answer, anslen)); + + /* + * If there are enough dots in the name, let's just give it a + * try 'as is'. The threshold can be set with the "ndots" option. + * Also, query 'as is', if there is a trailing dot in the name. + */ + saved_herrno = -1; + if (dots >= statp->ndots || trailing_dot) { + ret = res_nquerydomain(statp, name, NULL, class, type, + answer, anslen); + if (ret > 0 || trailing_dot) + return (ret); + saved_herrno = statp->res_h_errno; + tried_as_is++; + } + + /* + * We do at least one level of search if + * - there is no dot and RES_DEFNAME is set, or + * - there is at least one dot, there is no trailing dot, + * and RES_DNSRCH is set. + */ + if ((!dots && (statp->options & RES_DEFNAMES) != 0U) || + (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0U)) { + int done = 0; + + for (domain = (const char * const *)statp->dnsrch; + *domain && !done; + domain++) { + searched = 1; + + if (domain[0][0] == '\0' || + (domain[0][0] == '.' && domain[0][1] == '\0')) + root_on_list++; + + ret = res_nquerydomain(statp, name, *domain, + class, type, + answer, anslen); + if (ret > 0) + return (ret); + + /* + * If no server present, give up. + * If name isn't found in this domain, + * keep trying higher domains in the search list + * (if that's enabled). + * On a NO_DATA error, keep trying, otherwise + * a wildcard entry of another type could keep us + * from finding this entry higher in the domain. + * If we get some other error (negative answer or + * server failure), then stop searching up, + * but try the input name below in case it's + * fully-qualified. + */ + if (errno == ECONNREFUSED) { + RES_SET_H_ERRNO(statp, TRY_AGAIN); + return (-1); + } + + switch (statp->res_h_errno) { + case NO_DATA: + got_nodata++; + /* FALLTHROUGH */ + case HOST_NOT_FOUND: + /* keep trying */ + break; + case TRY_AGAIN: + if (hp->rcode == SERVFAIL) { + /* try next search element, if any */ + got_servfail++; + break; + } + /* FALLTHROUGH */ + default: + /* anything else implies that we're done */ + done++; + } + + /* if we got here for some reason other than DNSRCH, + * we only wanted one iteration of the loop, so stop. + */ + if ((statp->options & RES_DNSRCH) == 0U) + done++; + } + } + + /* + * If the query has not already been tried as is then try it + * unless RES_NOTLDQUERY is set and there were no dots. + */ + if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0U) && + !(tried_as_is || root_on_list)) { + ret = res_nquerydomain(statp, name, NULL, class, type, + answer, anslen); + if (ret > 0) + return (ret); + } + + /* if we got here, we didn't satisfy the search. + * if we did an initial full query, return that query's H_ERRNO + * (note that we wouldn't be here if that query had succeeded). + * else if we ever got a nodata, send that back as the reason. + * else send back meaningless H_ERRNO, that being the one from + * the last DNSRCH we did. + */ + if (saved_herrno != -1) + RES_SET_H_ERRNO(statp, saved_herrno); + else if (got_nodata) + RES_SET_H_ERRNO(statp, NO_DATA); + else if (got_servfail) + RES_SET_H_ERRNO(statp, TRY_AGAIN); + return (-1); +} + +/* + * Perform a call on res_query on the concatenation of name and domain, + * removing a trailing dot from name if domain is NULL. + */ +int +res_nquerydomain(res_state statp, + const char *name, + const char *domain, + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen) /* size of answer */ +{ + char nbuf[MAXDNAME]; + const char *longname = nbuf; + int n, d; + +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_nquerydomain(%s, %s, %d, %d)\n", + name, domain?domain:"<Nil>", class, type); +#endif + if (domain == NULL) { + /* + * Check for trailing '.'; + * copy without '.' if present. + */ + n = strlen(name); + if (n >= MAXDNAME) { + RES_SET_H_ERRNO(statp, NO_RECOVERY); + return (-1); + } + n--; + if (n >= 0 && name[n] == '.') { + strncpy(nbuf, name, (size_t)n); + nbuf[n] = '\0'; + } else + longname = name; + } else { + n = strlen(name); + d = strlen(domain); + if (n + d + 1 >= MAXDNAME) { + RES_SET_H_ERRNO(statp, NO_RECOVERY); + return (-1); + } + sprintf(nbuf, "%s.%s", name, domain); + } + return (res_nquery(statp, longname, class, type, answer, anslen)); +} + +const char * +res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) { + return (NULL); +} diff --git a/libc/netbsd/resolv/res_random.c b/libc/netbsd/resolv/res_random.c new file mode 100644 index 0000000..4570c4f --- /dev/null +++ b/libc/netbsd/resolv/res_random.c @@ -0,0 +1,275 @@ +/* $OpenBSD: res_random.c,v 1.17 2008/04/13 00:28:35 djm Exp $ */ + +/* + * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> + * Copyright 2008 Damien Miller <djm@openbsd.org> + * Copyright 2008 Android Open Source Project (thread-safety) + * All rights reserved. + * + * Theo de Raadt <deraadt@openbsd.org> came up with the idea of using + * such a mathematical system to generate more random (yet non-repeating) + * ids to solve the resolver/named problem. But Niels designed the + * actual system based on the constraints. + * + * Later modified by Damien Miller to wrap the LCG output in a 15-bit + * permutation generator based on a Luby-Rackoff block cipher. This + * ensures the output is non-repeating and preserves the MSB twiddle + * trick, but makes it more resistant to LCG prediction. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * seed = random 15bit + * n = prime, g0 = generator to n, + * j = random so that gcd(j,n-1) == 1 + * g = g0^j mod n will be a generator again. + * + * X[0] = random seed. + * X[n] = a*X[n-1]+b mod m is a Linear Congruential Generator + * with a = 7^(even random) mod m, + * b = random with gcd(b,m) == 1 + * m = 31104 and a maximal period of m-1. + * + * The transaction id is determined by: + * id[n] = seed xor (g^X[n] mod n) + * + * Effectivly the id is restricted to the lower 15 bits, thus + * yielding two different cycles by toggling the msb on and off. + * This avoids reuse issues caused by reseeding. + * + * The output of this generator is then randomly permuted though a + * custom 15 bit Luby-Rackoff block cipher. + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/time.h> +#include "resolv_private.h" + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +/* BIONIC-BEGIN */ +static pthread_mutex_t _res_random_lock = PTHREAD_MUTEX_INITIALIZER; +#define _RES_RANDOM_LOCK() pthread_mutex_lock(&_res_random_lock) +#define _RES_RANDOM_UNLOCK() pthread_mutex_unlock(&_res_random_lock) +/* BIONIC-END */ + +#define RU_OUT 180 /* Time after wich will be reseeded */ +#define RU_MAX 30000 /* Uniq cycle, avoid blackjack prediction */ +#define RU_GEN 2 /* Starting generator */ +#define RU_N 32749 /* RU_N-1 = 2*2*3*2729 */ +#define RU_AGEN 7 /* determine ru_a as RU_AGEN^(2*rand) */ +#define RU_M 31104 /* RU_M = 2^7*3^5 - don't change */ +#define RU_ROUNDS 11 /* Number of rounds for permute (odd) */ + +struct prf_ctx { + /* PRF lookup table for odd rounds (7 bits input to 8 bits output) */ + u_char prf7[(RU_ROUNDS / 2) * (1 << 7)]; + + /* PRF lookup table for even rounds (8 bits input to 7 bits output) */ + u_char prf8[((RU_ROUNDS + 1) / 2) * (1 << 8)]; +}; + +#define PFAC_N 3 +const static u_int16_t pfacts[PFAC_N] = { + 2, + 3, + 2729 +}; + +static u_int16_t ru_x; +static u_int16_t ru_seed, ru_seed2; +static u_int16_t ru_a, ru_b; +static u_int16_t ru_g; +static u_int16_t ru_counter = 0; +static u_int16_t ru_msb = 0; +static struct prf_ctx *ru_prf = NULL; +static long ru_reseed; + +static u_int16_t pmod(u_int16_t, u_int16_t, u_int16_t); +static void res_initid(void); + +/* + * Do a fast modular exponation, returned value will be in the range + * of 0 - (mod-1) + */ +static u_int16_t +pmod(u_int16_t gen, u_int16_t exp, u_int16_t mod) +{ + u_int16_t s, t, u; + + s = 1; + t = gen; + u = exp; + + while (u) { + if (u & 1) + s = (s * t) % mod; + u >>= 1; + t = (t * t) % mod; + } + return (s); +} + +/* + * 15-bit permutation based on Luby-Rackoff block cipher + */ +u_int +permute15(u_int in) +{ + int i; + u_int left, right, tmp; + + if (ru_prf == NULL) + return in; + + left = (in >> 8) & 0x7f; + right = in & 0xff; + + /* + * Each round swaps the width of left and right. Even rounds have + * a 7-bit left, odd rounds have an 8-bit left. Since this uses an + * odd number of rounds, left is always 8 bits wide at the end. + */ + for (i = 0; i < RU_ROUNDS; i++) { + if ((i & 1) == 0) + tmp = ru_prf->prf8[(i << (8 - 1)) | right] & 0x7f; + else + tmp = ru_prf->prf7[((i - 1) << (7 - 1)) | right]; + tmp ^= left; + left = right; + right = tmp; + } + + return (right << 8) | left; +} + +/* + * Initializes the seed and chooses a suitable generator. Also toggles + * the msb flag. The msb flag is used to generate two distinct + * cycles of random numbers and thus avoiding reuse of ids. + * + * This function is called from res_randomid() when needed, an + * application does not have to worry about it. + */ +static void +res_initid(void) +{ + u_int16_t j, i; + u_int32_t tmp; + int noprime = 1; + struct timeval tv; + + ru_x = arc4random_uniform(RU_M); + + /* 15 bits of random seed */ + tmp = arc4random(); + ru_seed = (tmp >> 16) & 0x7FFF; + ru_seed2 = tmp & 0x7FFF; + + /* Determine the LCG we use */ + tmp = arc4random(); + ru_b = (tmp & 0xfffe) | 1; + ru_a = pmod(RU_AGEN, (tmp >> 16) & 0xfffe, RU_M); + while (ru_b % 3 == 0) + ru_b += 2; + + j = arc4random_uniform(RU_N); + + /* + * Do a fast gcd(j,RU_N-1), so we can find a j with + * gcd(j, RU_N-1) == 1, giving a new generator for + * RU_GEN^j mod RU_N + */ + + while (noprime) { + for (i = 0; i < PFAC_N; i++) + if (j % pfacts[i] == 0) + break; + + if (i >= PFAC_N) + noprime = 0; + else + j = (j + 1) % RU_N; + } + + ru_g = pmod(RU_GEN, j, RU_N); + ru_counter = 0; + + /* Initialise PRF for Luby-Rackoff permutation */ + if (ru_prf == NULL) + ru_prf = malloc(sizeof(*ru_prf)); + if (ru_prf != NULL) + arc4random_buf(ru_prf, sizeof(*ru_prf)); + + gettimeofday(&tv, NULL); + ru_reseed = tv.tv_sec + RU_OUT; + ru_msb = ru_msb == 0x8000 ? 0 : 0x8000; +} + +u_int +res_randomid(void) +{ + struct timeval tv; + u_int result; + + _RES_RANDOM_LOCK() + gettimeofday(&tv, NULL); + if (ru_counter >= RU_MAX || tv.tv_sec > ru_reseed) + res_initid(); + + /* Linear Congruential Generator */ + ru_x = (ru_a * ru_x + ru_b) % RU_M; + ru_counter++; + + result = permute15(ru_seed ^ pmod(ru_g, ru_seed2 + ru_x, RU_N)) | ru_msb; + _RES_RANDOM_UNLOCK() + return result; +} + +#if 0 +int +main(int argc, char **argv) +{ + int i, n; + u_int16_t wert; + + res_initid(); + + printf("Generator: %u\n", ru_g); + printf("Seed: %u\n", ru_seed); + printf("Reseed at %ld\n", ru_reseed); + printf("Ru_X: %u\n", ru_x); + printf("Ru_A: %u\n", ru_a); + printf("Ru_B: %u\n", ru_b); + + n = argc > 1 ? atoi(argv[1]) : 60001; + for (i=0;i<n;i++) { + wert = res_randomid(); + printf("%u\n", wert); + } + return 0; +} +#endif + diff --git a/libc/netbsd/resolv/res_send.c b/libc/netbsd/resolv/res_send.c new file mode 100644 index 0000000..24b740a --- /dev/null +++ b/libc/netbsd/resolv/res_send.c @@ -0,0 +1,1136 @@ +/* $NetBSD: res_send.c,v 1.9 2006/01/24 17:41:25 christos Exp $ */ + +/* + * Copyright 2008 Android Open Source Project (source port randomization) + * Copyright (c) 1985, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#ifdef notdef +static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; +static const char rcsid[] = "Id: res_send.c,v 1.5.2.2.4.5 2004/08/10 02:19:56 marka Exp"; +#else +__RCSID("$NetBSD: res_send.c,v 1.9 2006/01/24 17:41:25 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * Send query to name server and wait for reply. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/uio.h> + +#include <netinet/in.h> +#include <netinet/in6.h> +#include "arpa_nameser.h" +#include <arpa/inet.h> + +#include <errno.h> +#include <netdb.h> +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include <resolv.h> +#endif +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <isc/eventlib.h> + +#ifndef DE_CONST +#define DE_CONST(c,v) v = ((c) ? \ + strchr((const void *)(c), *(const char *)(const void *)(c)) : NULL) +#endif + +/* Options. Leave them on. */ +#ifndef DEBUG +#define DEBUG +#endif +#include "res_debug.h" +#include "res_private.h" + +#define EXT(res) ((res)->_u._ext) + +static const int highestFD = FD_SETSIZE - 1; + +/* Forward. */ + +static int get_salen __P((const struct sockaddr *)); +static struct sockaddr * get_nsaddr __P((res_state, size_t)); +static int send_vc(res_state, const u_char *, int, + u_char *, int, int *, int); +static int send_dg(res_state, const u_char *, int, + u_char *, int, int *, int, + int *, int *); +static void Aerror(const res_state, FILE *, const char *, int, + const struct sockaddr *, int); +static void Perror(const res_state, FILE *, const char *, int); +static int sock_eq(struct sockaddr *, struct sockaddr *); +#ifdef NEED_PSELECT +static int pselect(int, void *, void *, void *, + struct timespec *, + const sigset_t *); +#endif +void res_pquery(const res_state, const u_char *, int, FILE *); + + +/* BIONIC-BEGIN: implement source port randomization */ +typedef union { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; +} _sockaddr_union; + +static int +random_bind( int s, int family ) +{ + _sockaddr_union u; + int j; + socklen_t slen; + + /* clear all, this also sets the IP4/6 address to 'any' */ + memset( &u, 0, sizeof u ); + + switch (family) { + case AF_INET: + u.sin.sin_family = family; + slen = sizeof u.sin; + break; + case AF_INET6: + u.sin6.sin6_family = family; + slen = sizeof u.sin6; + break; + default: + errno = EPROTO; + return -1; + } + + /* first try to bind to a random source port a few times */ + for (j = 0; j < 10; j++) { + /* find a random port between 1025 .. 65534 */ + int port = 1025 + (res_randomid() % (65535-1025)); + if (family == AF_INET) + u.sin.sin_port = htons(port); + else + u.sin6.sin6_port = htons(port); + + if ( !bind( s, &u.sa, slen ) ) + return 0; + } + + /* nothing after 10 tries, our network table is probably busy */ + /* let the system decide which port is best */ + if (family == AF_INET) + u.sin.sin_port = 0; + else + u.sin6.sin6_port = 0; + + return bind( s, &u.sa, slen ); +} +/* BIONIC-END */ + +static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; + +/* Public. */ + +/* int + * res_isourserver(ina) + * looks up "ina" in _res.ns_addr_list[] + * returns: + * 0 : not found + * >0 : found + * author: + * paul vixie, 29may94 + */ +int +res_ourserver_p(const res_state statp, const struct sockaddr *sa) { + const struct sockaddr_in *inp, *srv; + const struct sockaddr_in6 *in6p, *srv6; + int ns; + + switch (sa->sa_family) { + case AF_INET: + inp = (const struct sockaddr_in *)(const void *)sa; + for (ns = 0; ns < statp->nscount; ns++) { + srv = (struct sockaddr_in *)(void *)get_nsaddr(statp, (size_t)ns); + if (srv->sin_family == inp->sin_family && + srv->sin_port == inp->sin_port && + (srv->sin_addr.s_addr == INADDR_ANY || + srv->sin_addr.s_addr == inp->sin_addr.s_addr)) + return (1); + } + break; + case AF_INET6: + if (EXT(statp).ext == NULL) + break; + in6p = (const struct sockaddr_in6 *)(const void *)sa; + for (ns = 0; ns < statp->nscount; ns++) { + srv6 = (struct sockaddr_in6 *)(void *)get_nsaddr(statp, (size_t)ns); + if (srv6->sin6_family == in6p->sin6_family && + srv6->sin6_port == in6p->sin6_port && +#ifdef HAVE_SIN6_SCOPE_ID + (srv6->sin6_scope_id == 0 || + srv6->sin6_scope_id == in6p->sin6_scope_id) && +#endif + (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) || + IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr))) + return (1); + } + break; + default: + break; + } + return (0); +} + +/* int + * res_nameinquery(name, type, class, buf, eom) + * look for (name,type,class) in the query section of packet (buf,eom) + * requires: + * buf + HFIXEDSZ <= eom + * returns: + * -1 : format error + * 0 : not found + * >0 : found + * author: + * paul vixie, 29may94 + */ +int +res_nameinquery(const char *name, int type, int class, + const u_char *buf, const u_char *eom) +{ + const u_char *cp = buf + HFIXEDSZ; + int qdcount = ntohs(((const HEADER*)(const void *)buf)->qdcount); + + while (qdcount-- > 0) { + char tname[MAXDNAME+1]; + int n, ttype, tclass; + + n = dn_expand(buf, eom, cp, tname, sizeof tname); + if (n < 0) + return (-1); + cp += n; + if (cp + 2 * INT16SZ > eom) + return (-1); + ttype = ns_get16(cp); cp += INT16SZ; + tclass = ns_get16(cp); cp += INT16SZ; + if (ttype == type && tclass == class && + ns_samename(tname, name) == 1) + return (1); + } + return (0); +} + +/* int + * res_queriesmatch(buf1, eom1, buf2, eom2) + * is there a 1:1 mapping of (name,type,class) + * in (buf1,eom1) and (buf2,eom2)? + * returns: + * -1 : format error + * 0 : not a 1:1 mapping + * >0 : is a 1:1 mapping + * author: + * paul vixie, 29may94 + */ +int +res_queriesmatch(const u_char *buf1, const u_char *eom1, + const u_char *buf2, const u_char *eom2) +{ + const u_char *cp = buf1 + HFIXEDSZ; + int qdcount = ntohs(((const HEADER*)(const void *)buf1)->qdcount); + + if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2) + return (-1); + + /* + * Only header section present in replies to + * dynamic update packets. + */ + if ((((const HEADER *)(const void *)buf1)->opcode == ns_o_update) && + (((const HEADER *)(const void *)buf2)->opcode == ns_o_update)) + return (1); + + if (qdcount != ntohs(((const HEADER*)(const void *)buf2)->qdcount)) + return (0); + while (qdcount-- > 0) { + char tname[MAXDNAME+1]; + int n, ttype, tclass; + + n = dn_expand(buf1, eom1, cp, tname, sizeof tname); + if (n < 0) + return (-1); + cp += n; + if (cp + 2 * INT16SZ > eom1) + return (-1); + ttype = ns_get16(cp); cp += INT16SZ; + tclass = ns_get16(cp); cp += INT16SZ; + if (!res_nameinquery(tname, ttype, tclass, buf2, eom2)) + return (0); + } + return (1); +} + +int +res_nsend(res_state statp, + const u_char *buf, int buflen, u_char *ans, int anssiz) +{ + int gotsomewhere, terrno, try, v_circuit, resplen, ns, n; + char abuf[NI_MAXHOST]; + + if (statp->nscount == 0) { + errno = ESRCH; + return (-1); + } + if (anssiz < HFIXEDSZ) { + errno = EINVAL; + return (-1); + } + DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY), + (stdout, ";; res_send()\n"), buf, buflen); + v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ; + gotsomewhere = 0; + terrno = ETIMEDOUT; + + /* + * If the ns_addr_list in the resolver context has changed, then + * invalidate our cached copy and the associated timing data. + */ + if (EXT(statp).nscount != 0) { + int needclose = 0; + struct sockaddr_storage peer; + socklen_t peerlen; + + if (EXT(statp).nscount != statp->nscount) + needclose++; + else + for (ns = 0; ns < statp->nscount; ns++) { + if (statp->nsaddr_list[ns].sin_family && + !sock_eq((struct sockaddr *)(void *)&statp->nsaddr_list[ns], + (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[ns])) { + needclose++; + break; + } + + if (EXT(statp).nssocks[ns] == -1) + continue; + peerlen = sizeof(peer); + if (getsockname(EXT(statp).nssocks[ns], + (struct sockaddr *)(void *)&peer, &peerlen) < 0) { + needclose++; + break; + } + if (!sock_eq((struct sockaddr *)(void *)&peer, + get_nsaddr(statp, (size_t)ns))) { + needclose++; + break; + } + } + if (needclose) { + res_nclose(statp); + EXT(statp).nscount = 0; + } + } + + /* + * Maybe initialize our private copy of the ns_addr_list. + */ + if (EXT(statp).nscount == 0) { + for (ns = 0; ns < statp->nscount; ns++) { + EXT(statp).nstimes[ns] = RES_MAXTIME; + EXT(statp).nssocks[ns] = -1; + if (!statp->nsaddr_list[ns].sin_family) + continue; + EXT(statp).ext->nsaddrs[ns].sin = + statp->nsaddr_list[ns]; + } + EXT(statp).nscount = statp->nscount; + } + + /* + * Some resolvers want to even out the load on their nameservers. + * Note that RES_BLAST overrides RES_ROTATE. + */ + if ((statp->options & RES_ROTATE) != 0U && + (statp->options & RES_BLAST) == 0U) { + union res_sockaddr_union inu; + struct sockaddr_in ina; + int lastns = statp->nscount - 1; + int fd; + u_int16_t nstime; + + if (EXT(statp).ext != NULL) + inu = EXT(statp).ext->nsaddrs[0]; + ina = statp->nsaddr_list[0]; + fd = EXT(statp).nssocks[0]; + nstime = EXT(statp).nstimes[0]; + for (ns = 0; ns < lastns; ns++) { + if (EXT(statp).ext != NULL) + EXT(statp).ext->nsaddrs[ns] = + EXT(statp).ext->nsaddrs[ns + 1]; + statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1]; + EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1]; + EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1]; + } + if (EXT(statp).ext != NULL) + EXT(statp).ext->nsaddrs[lastns] = inu; + statp->nsaddr_list[lastns] = ina; + EXT(statp).nssocks[lastns] = fd; + EXT(statp).nstimes[lastns] = nstime; + } + + /* + * Send request, RETRY times, or until successful. + */ + for (try = 0; try < statp->retry; try++) { + for (ns = 0; ns < statp->nscount; ns++) { + struct sockaddr *nsap; + int nsaplen; + nsap = get_nsaddr(statp, (size_t)ns); + nsaplen = get_salen(nsap); + statp->_flags &= ~RES_F_LASTMASK; + statp->_flags |= (ns << RES_F_LASTSHIFT); + same_ns: + if (statp->qhook) { + int done = 0, loops = 0; + + do { + res_sendhookact act; + + act = (*statp->qhook)(&nsap, &buf, &buflen, + ans, anssiz, &resplen); + switch (act) { + case res_goahead: + done = 1; + break; + case res_nextns: + res_nclose(statp); + goto next_ns; + case res_done: + return (resplen); + case res_modified: + /* give the hook another try */ + if (++loops < 42) /*doug adams*/ + break; + /*FALLTHROUGH*/ + case res_error: + /*FALLTHROUGH*/ + default: + goto fail; + } + } while (!done); + } + + Dprint(((statp->options & RES_DEBUG) && + getnameinfo(nsap, (socklen_t)nsaplen, abuf, sizeof(abuf), + NULL, 0, niflags) == 0), + (stdout, ";; Querying server (# %d) address = %s\n", + ns + 1, abuf)); + + + if (v_circuit) { + /* Use VC; at most one attempt per server. */ + try = statp->retry; + n = send_vc(statp, buf, buflen, ans, anssiz, &terrno, + ns); + if (n < 0) + goto fail; + if (n == 0) + goto next_ns; + resplen = n; + } else { + /* Use datagrams. */ + n = send_dg(statp, buf, buflen, ans, anssiz, &terrno, + ns, &v_circuit, &gotsomewhere); + if (n < 0) + goto fail; + if (n == 0) + goto next_ns; + if (v_circuit) + goto same_ns; + resplen = n; + } + + Dprint((statp->options & RES_DEBUG) || + ((statp->pfcode & RES_PRF_REPLY) && + (statp->pfcode & RES_PRF_HEAD1)), + (stdout, ";; got answer:\n")); + + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), + (stdout, "%s", ""), + ans, (resplen > anssiz) ? anssiz : resplen); + + /* + * If we have temporarily opened a virtual circuit, + * or if we haven't been asked to keep a socket open, + * close the socket. + */ + if ((v_circuit && (statp->options & RES_USEVC) == 0U) || + (statp->options & RES_STAYOPEN) == 0U) { + res_nclose(statp); + } + if (statp->rhook) { + int done = 0, loops = 0; + + do { + res_sendhookact act; + + act = (*statp->rhook)(nsap, buf, buflen, + ans, anssiz, &resplen); + switch (act) { + case res_goahead: + case res_done: + done = 1; + break; + case res_nextns: + res_nclose(statp); + goto next_ns; + case res_modified: + /* give the hook another try */ + if (++loops < 42) /*doug adams*/ + break; + /*FALLTHROUGH*/ + case res_error: + /*FALLTHROUGH*/ + default: + goto fail; + } + } while (!done); + + } + return (resplen); + next_ns: ; + } /*foreach ns*/ + } /*foreach retry*/ + res_nclose(statp); + if (!v_circuit) { + if (!gotsomewhere) + errno = ECONNREFUSED; /* no nameservers found */ + else + errno = ETIMEDOUT; /* no answer obtained */ + } else + errno = terrno; + return (-1); + fail: + res_nclose(statp); + return (-1); +} + +/* Private */ + +static int +get_salen(sa) + const struct sockaddr *sa; +{ + +#ifdef HAVE_SA_LEN + /* There are people do not set sa_len. Be forgiving to them. */ + if (sa->sa_len) + return (sa->sa_len); +#endif + + if (sa->sa_family == AF_INET) + return (sizeof(struct sockaddr_in)); + else if (sa->sa_family == AF_INET6) + return (sizeof(struct sockaddr_in6)); + else + return (0); /* unknown, die on connect */ +} + +/* + * pick appropriate nsaddr_list for use. see res_init() for initialization. + */ +static struct sockaddr * +get_nsaddr(statp, n) + res_state statp; + size_t n; +{ + + if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) { + /* + * - EXT(statp).ext->nsaddrs[n] holds an address that is larger + * than struct sockaddr, and + * - user code did not update statp->nsaddr_list[n]. + */ + return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n]; + } else { + /* + * - user code updated statp->nsaddr_list[n], or + * - statp->nsaddr_list[n] has the same content as + * EXT(statp).ext->nsaddrs[n]. + */ + return (struct sockaddr *)(void *)&statp->nsaddr_list[n]; + } +} + +static int +send_vc(res_state statp, + const u_char *buf, int buflen, u_char *ans, int anssiz, + int *terrno, int ns) +{ + const HEADER *hp = (const HEADER *)(const void *)buf; + HEADER *anhp = (HEADER *)(void *)ans; + struct sockaddr *nsap; + int nsaplen; + int truncating, connreset, resplen, n; + struct iovec iov[2]; + u_short len; + u_char *cp; + void *tmp; + + nsap = get_nsaddr(statp, (size_t)ns); + nsaplen = get_salen(nsap); + + connreset = 0; + same_ns: + truncating = 0; + + /* Are we still talking to whom we want to talk to? */ + if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) { + struct sockaddr_storage peer; + socklen_t size = sizeof peer; + + if (getpeername(statp->_vcsock, + (struct sockaddr *)(void *)&peer, &size) < 0 || + !sock_eq((struct sockaddr *)(void *)&peer, nsap)) { + res_nclose(statp); + statp->_flags &= ~RES_F_VC; + } + } + + if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) { + if (statp->_vcsock >= 0) + res_nclose(statp); + + statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0); + if (statp->_vcsock > highestFD) { + res_nclose(statp); + errno = ENOTSOCK; + } + if (statp->_vcsock < 0) { + switch (errno) { + case EPROTONOSUPPORT: +#ifdef EPFNOSUPPORT + case EPFNOSUPPORT: +#endif + case EAFNOSUPPORT: + Perror(statp, stderr, "socket(vc)", errno); + return (0); + default: + *terrno = errno; + Perror(statp, stderr, "socket(vc)", errno); + return (-1); + } + } + errno = 0; + if (random_bind(statp->_vcsock,nsap->sa_family) < 0) { + *terrno = errno; + Aerror(statp, stderr, "bind/vc", errno, nsap, + nsaplen); + res_nclose(statp); + return (0); + } + if (connect(statp->_vcsock, nsap, (socklen_t)nsaplen) < 0) { + *terrno = errno; + Aerror(statp, stderr, "connect/vc", errno, nsap, + nsaplen); + res_nclose(statp); + return (0); + } + statp->_flags |= RES_F_VC; + } + + /* + * Send length & message + */ + ns_put16((u_short)buflen, (u_char*)(void *)&len); + iov[0] = evConsIovec(&len, INT16SZ); + DE_CONST(buf, tmp); + iov[1] = evConsIovec(tmp, (size_t)buflen); + if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) { + *terrno = errno; + Perror(statp, stderr, "write failed", errno); + res_nclose(statp); + return (0); + } + /* + * Receive length & response + */ + read_len: + cp = ans; + len = INT16SZ; + while ((n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0) { + cp += n; + if ((len -= n) == 0) + break; + } + if (n <= 0) { + *terrno = errno; + Perror(statp, stderr, "read failed", errno); + res_nclose(statp); + /* + * A long running process might get its TCP + * connection reset if the remote server was + * restarted. Requery the server instead of + * trying a new one. When there is only one + * server, this means that a query might work + * instead of failing. We only allow one reset + * per query to prevent looping. + */ + if (*terrno == ECONNRESET && !connreset) { + connreset = 1; + res_nclose(statp); + goto same_ns; + } + res_nclose(statp); + return (0); + } + resplen = ns_get16(ans); + if (resplen > anssiz) { + Dprint(statp->options & RES_DEBUG, + (stdout, ";; response truncated\n") + ); + truncating = 1; + len = anssiz; + } else + len = resplen; + if (len < HFIXEDSZ) { + /* + * Undersized message. + */ + Dprint(statp->options & RES_DEBUG, + (stdout, ";; undersized: %d\n", len)); + *terrno = EMSGSIZE; + res_nclose(statp); + return (0); + } + cp = ans; + while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0){ + cp += n; + len -= n; + } + if (n <= 0) { + *terrno = errno; + Perror(statp, stderr, "read(vc)", errno); + res_nclose(statp); + return (0); + } + if (truncating) { + /* + * Flush rest of answer so connection stays in synch. + */ + anhp->tc = 1; + len = resplen - anssiz; + while (len != 0) { + char junk[PACKETSZ]; + + n = read(statp->_vcsock, junk, + (len > sizeof junk) ? sizeof junk : len); + if (n > 0) + len -= n; + else + break; + } + } + /* + * If the calling applicating has bailed out of + * a previous call and failed to arrange to have + * the circuit closed or the server has got + * itself confused, then drop the packet and + * wait for the correct one. + */ + if (hp->id != anhp->id) { + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), + (stdout, ";; old answer (unexpected):\n"), + ans, (resplen > anssiz) ? anssiz: resplen); + goto read_len; + } + + /* + * All is well, or the error is fatal. Signal that the + * next nameserver ought not be tried. + */ + return (resplen); +} + +static int +send_dg(res_state statp, + const u_char *buf, int buflen, u_char *ans, int anssiz, + int *terrno, int ns, int *v_circuit, int *gotsomewhere) +{ + const HEADER *hp = (const HEADER *)(const void *)buf; + HEADER *anhp = (HEADER *)(void *)ans; + const struct sockaddr *nsap; + int nsaplen; + struct timespec now, timeout, finish; + fd_set dsmask; + struct sockaddr_storage from; + socklen_t fromlen; + int resplen, seconds, n, s; + + nsap = get_nsaddr(statp, (size_t)ns); + nsaplen = get_salen(nsap); + if (EXT(statp).nssocks[ns] == -1) { + EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0); + if (EXT(statp).nssocks[ns] > highestFD) { + res_nclose(statp); + errno = ENOTSOCK; + } + if (EXT(statp).nssocks[ns] < 0) { + switch (errno) { + case EPROTONOSUPPORT: +#ifdef EPFNOSUPPORT + case EPFNOSUPPORT: +#endif + case EAFNOSUPPORT: + Perror(statp, stderr, "socket(dg)", errno); + return (0); + default: + *terrno = errno; + Perror(statp, stderr, "socket(dg)", errno); + return (-1); + } + } +#ifndef CANNOT_CONNECT_DGRAM + /* + * On a 4.3BSD+ machine (client and server, + * actually), sending to a nameserver datagram + * port with no nameserver will cause an + * ICMP port unreachable message to be returned. + * If our datagram socket is "connected" to the + * server, we get an ECONNREFUSED error on the next + * socket operation, and select returns if the + * error message is received. We can thus detect + * the absence of a nameserver without timing out. + */ + if (random_bind(EXT(statp).nssocks[ns], nsap->sa_family) < 0) { + Aerror(statp, stderr, "bind(dg)", errno, nsap, + nsaplen); + res_nclose(statp); + return (0); + } + if (connect(EXT(statp).nssocks[ns], nsap, (socklen_t)nsaplen) < 0) { + Aerror(statp, stderr, "connect(dg)", errno, nsap, + nsaplen); + res_nclose(statp); + return (0); + } +#endif /* !CANNOT_CONNECT_DGRAM */ + Dprint(statp->options & RES_DEBUG, + (stdout, ";; new DG socket\n")) + } + s = EXT(statp).nssocks[ns]; +#ifndef CANNOT_CONNECT_DGRAM + if (send(s, (const char*)buf, (size_t)buflen, 0) != buflen) { + Perror(statp, stderr, "send", errno); + res_nclose(statp); + return (0); + } +#else /* !CANNOT_CONNECT_DGRAM */ + if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) + { + Aerror(statp, stderr, "sendto", errno, nsap, nsaplen); + res_nclose(statp); + return (0); + } +#endif /* !CANNOT_CONNECT_DGRAM */ + + /* + * Wait for reply. + */ + seconds = (statp->retrans << ns); + if (ns > 0) + seconds /= statp->nscount; + if (seconds <= 0) + seconds = 1; + now = evNowTime(); + timeout = evConsTime((long)seconds, 0L); + finish = evAddTime(now, timeout); + goto nonow; + wait: + now = evNowTime(); + nonow: + FD_ZERO(&dsmask); + FD_SET(s, &dsmask); + if (evCmpTime(finish, now) > 0) + timeout = evSubTime(finish, now); + else + timeout = evConsTime(0L, 0L); + n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL); + if (n == 0) { + Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n")); + *gotsomewhere = 1; + return (0); + } + if (n < 0) { + if (errno == EINTR) + goto wait; + Perror(statp, stderr, "select", errno); + res_nclose(statp); + return (0); + } + errno = 0; + fromlen = sizeof(from); + resplen = recvfrom(s, (char*)ans, (size_t)anssiz,0, + (struct sockaddr *)(void *)&from, &fromlen); + if (resplen <= 0) { + Perror(statp, stderr, "recvfrom", errno); + res_nclose(statp); + return (0); + } + *gotsomewhere = 1; + if (resplen < HFIXEDSZ) { + /* + * Undersized message. + */ + Dprint(statp->options & RES_DEBUG, + (stdout, ";; undersized: %d\n", + resplen)); + *terrno = EMSGSIZE; + res_nclose(statp); + return (0); + } + if (hp->id != anhp->id) { + /* + * response from old query, ignore it. + * XXX - potential security hazard could + * be detected here. + */ + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), + (stdout, ";; old answer:\n"), + ans, (resplen > anssiz) ? anssiz : resplen); + goto wait; + } + if (!(statp->options & RES_INSECURE1) && + !res_ourserver_p(statp, (struct sockaddr *)(void *)&from)) { + /* + * response from wrong server? ignore it. + * XXX - potential security hazard could + * be detected here. + */ + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), + (stdout, ";; not our server:\n"), + ans, (resplen > anssiz) ? anssiz : resplen); + goto wait; + } +#ifdef RES_USE_EDNS0 + if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) { + /* + * Do not retry if the server do not understand EDNS0. + * The case has to be captured here, as FORMERR packet do not + * carry query section, hence res_queriesmatch() returns 0. + */ + DprintQ(statp->options & RES_DEBUG, + (stdout, "server rejected query with EDNS0:\n"), + ans, (resplen > anssiz) ? anssiz : resplen); + /* record the error */ + statp->_flags |= RES_F_EDNS0ERR; + res_nclose(statp); + return (0); + } +#endif + if (!(statp->options & RES_INSECURE2) && + !res_queriesmatch(buf, buf + buflen, + ans, ans + anssiz)) { + /* + * response contains wrong query? ignore it. + * XXX - potential security hazard could + * be detected here. + */ + DprintQ((statp->options & RES_DEBUG) || + (statp->pfcode & RES_PRF_REPLY), + (stdout, ";; wrong query name:\n"), + ans, (resplen > anssiz) ? anssiz : resplen); + goto wait; + } + if (anhp->rcode == SERVFAIL || + anhp->rcode == NOTIMP || + anhp->rcode == REFUSED) { + DprintQ(statp->options & RES_DEBUG, + (stdout, "server rejected query:\n"), + ans, (resplen > anssiz) ? anssiz : resplen); + res_nclose(statp); + /* don't retry if called from dig */ + if (!statp->pfcode) + return (0); + } + if (!(statp->options & RES_IGNTC) && anhp->tc) { + /* + * To get the rest of answer, + * use TCP with same server. + */ + Dprint(statp->options & RES_DEBUG, + (stdout, ";; truncated answer\n")); + *v_circuit = 1; + res_nclose(statp); + return (1); + } + /* + * All is well, or the error is fatal. Signal that the + * next nameserver ought not be tried. + */ + return (resplen); +} + +static void +Aerror(const res_state statp, FILE *file, const char *string, int error, + const struct sockaddr *address, int alen) +{ + int save = errno; + char hbuf[NI_MAXHOST]; + char sbuf[NI_MAXSERV]; + + alen = alen; + + if ((statp->options & RES_DEBUG) != 0U) { + if (getnameinfo(address, (socklen_t)alen, hbuf, sizeof(hbuf), + sbuf, sizeof(sbuf), niflags)) { + strncpy(hbuf, "?", sizeof(hbuf) - 1); + hbuf[sizeof(hbuf) - 1] = '\0'; + strncpy(sbuf, "?", sizeof(sbuf) - 1); + sbuf[sizeof(sbuf) - 1] = '\0'; + } + fprintf(file, "res_send: %s ([%s].%s): %s\n", + string, hbuf, sbuf, strerror(error)); + } + errno = save; +} + +static void +Perror(const res_state statp, FILE *file, const char *string, int error) { + int save = errno; + + if ((statp->options & RES_DEBUG) != 0U) + fprintf(file, "res_send: %s: %s\n", + string, strerror(error)); + errno = save; +} + +static int +sock_eq(struct sockaddr *a, struct sockaddr *b) { + struct sockaddr_in *a4, *b4; + struct sockaddr_in6 *a6, *b6; + + if (a->sa_family != b->sa_family) + return 0; + switch (a->sa_family) { + case AF_INET: + a4 = (struct sockaddr_in *)(void *)a; + b4 = (struct sockaddr_in *)(void *)b; + return a4->sin_port == b4->sin_port && + a4->sin_addr.s_addr == b4->sin_addr.s_addr; + case AF_INET6: + a6 = (struct sockaddr_in6 *)(void *)a; + b6 = (struct sockaddr_in6 *)(void *)b; + return a6->sin6_port == b6->sin6_port && +#ifdef HAVE_SIN6_SCOPE_ID + a6->sin6_scope_id == b6->sin6_scope_id && +#endif + IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr); + default: + return 0; + } +} + +#ifdef NEED_PSELECT +/* XXX needs to move to the porting library. */ +static int +pselect(int nfds, void *rfds, void *wfds, void *efds, + struct timespec *tsp, const sigset_t *sigmask) +{ + struct timeval tv, *tvp; + sigset_t sigs; + int n; + + if (tsp) { + tvp = &tv; + tv = evTimeVal(*tsp); + } else + tvp = NULL; + if (sigmask) + sigprocmask(SIG_SETMASK, sigmask, &sigs); + n = select(nfds, rfds, wfds, efds, tvp); + if (sigmask) + sigprocmask(SIG_SETMASK, &sigs, NULL); + if (tsp) + *tsp = evTimeSpec(tv); + return (n); +} +#endif diff --git a/libc/netbsd/resolv/res_state.c b/libc/netbsd/resolv/res_state.c new file mode 100644 index 0000000..8f2851a --- /dev/null +++ b/libc/netbsd/resolv/res_state.c @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <sys/cdefs.h> +#include <sys/types.h> +#include <arpa/inet.h> +#include "arpa_nameser.h" +#include <netdb.h> +#include "resolv_private.h" +#include "resolv_cache.h" +#include <pthread.h> +#include <stdlib.h> + +#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ +#include <sys/_system_properties.h> + +static pthread_key_t _res_key; +static pthread_once_t _res_once; + +typedef struct { + int _h_errno; + struct __res_state _nres[1]; + unsigned _serial; + struct prop_info* _pi; + struct hostent* _hostent; + struct res_static _rstatic[1]; +} _res_thread; + +static _res_thread* +_res_thread_alloc(void) +{ + _res_thread* rt = malloc(sizeof(*rt)); + + if (rt) { + rt->_h_errno = 0; + /* Special system property which tracks any changes to 'net.*'. */ + rt->_serial = 0; + rt->_pi = (struct prop_info*) __system_property_find("net.change"); + if (rt->_pi) { + rt->_serial = rt->_pi->serial; + } + if ( res_ninit( rt->_nres ) < 0 ) { + free(rt); + rt = NULL; + } + rt->_hostent = NULL; + memset(rt->_rstatic, 0, sizeof rt->_rstatic); + } + return rt; +} + +static void +_res_static_done( res_static rs ) +{ + /* fortunately, there is nothing to do here, since the + * points in h_addr_ptrs and host_aliases should all + * point to 'hostbuf' + */ + if (rs->hostf) { /* should not happen in theory, but just be safe */ + fclose(rs->hostf); + rs->hostf = NULL; + } + free(rs->servent.s_aliases); +} + +static void +_res_thread_free( void* _rt ) +{ + _res_thread* rt = _rt; + + _res_static_done(rt->_rstatic); + _resolv_hostent_free(rt->_hostent); + res_ndestroy(rt->_nres); + free(rt); +} + +static void +_res_init_key( void ) +{ + pthread_key_create( &_res_key, _res_thread_free ); +} + +static _res_thread* +_res_thread_get(void) +{ + _res_thread* rt; + pthread_once( &_res_once, _res_init_key ); + rt = pthread_getspecific( _res_key ); + if (rt == NULL) { + if ((rt = _res_thread_alloc()) == NULL) { + return NULL; + } + rt->_h_errno = 0; + rt->_serial = 0; + pthread_setspecific( _res_key, rt ); + } + /* Check the serial value for any chanes to net.* properties. */ + if (rt->_pi == NULL) { + rt->_pi = (struct prop_info*) __system_property_find("net.change"); + } + if (rt->_pi == NULL || rt->_serial == rt->_pi->serial) { + return rt; + } + rt->_serial = rt->_pi->serial; + /* Reload from system properties. */ + if ( res_ninit( rt->_nres ) < 0 ) { + free(rt); + rt = NULL; + pthread_setspecific( _res_key, rt ); + } + return rt; +} + +struct __res_state _nres; + +#if 0 +struct resolv_cache* +__get_res_cache(void) +{ + _res_thread* rt = _res_thread_get(); + + if (!rt) + return NULL; + + if (!rt->_cache) { + rt->_cache = _resolv_cache_create(); + } + return rt->_cache; +} +#endif + +int* +__get_h_errno(void) +{ + _res_thread* rt = _res_thread_get(); + static int panic = NETDB_INTERNAL; + + return rt ? &rt->_h_errno : &panic; +} + +res_state +__res_get_state(void) +{ + _res_thread* rt = _res_thread_get(); + + return rt ? rt->_nres : NULL; +} + +void +__res_put_state(res_state res) +{ + /* nothing to do */ + res=res; +} + +struct hostent** +__get_res_cache_hostent_p(void) +{ + _res_thread* rt = _res_thread_get(); + + return rt ? &rt->_hostent : NULL; +} + +res_static +__res_get_static(void) +{ + _res_thread* rt = _res_thread_get(); + + return rt ? rt->_rstatic : NULL; +} |