From a27d2baa0c1a2ec70f47ea9199b1dd6762c8a349 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 21 Oct 2008 07:00:00 -0700 Subject: Initial Contribution --- libc/netbsd/gethnamaddr.c | 1235 ++++++++++++++++++++++++ libc/netbsd/inet/nsap_addr.c | 121 +++ libc/netbsd/isc/ev_streams.c | 311 ++++++ libc/netbsd/isc/ev_timers.c | 504 ++++++++++ libc/netbsd/isc/eventlib_p.h | 233 +++++ libc/netbsd/nameser/ns_name.c | 970 +++++++++++++++++++ libc/netbsd/nameser/ns_netint.c | 59 ++ libc/netbsd/nameser/ns_parse.c | 209 ++++ libc/netbsd/nameser/ns_print.c | 915 ++++++++++++++++++ libc/netbsd/nameser/ns_samedomain.c | 211 +++++ libc/netbsd/nameser/ns_ttl.c | 164 ++++ libc/netbsd/net/base64.c | 340 +++++++ libc/netbsd/net/getaddrinfo.c | 1792 +++++++++++++++++++++++++++++++++++ libc/netbsd/net/getnameinfo.c | 519 ++++++++++ libc/netbsd/net/getservbyname.c | 54 ++ libc/netbsd/net/getservbyname_r.c | 76 ++ libc/netbsd/net/getservbyport.c | 53 ++ libc/netbsd/net/getservbyport_r.c | 65 ++ libc/netbsd/net/getservent.c | 124 +++ libc/netbsd/net/getservent_r.c | 151 +++ libc/netbsd/net/nsdispatch.c | 152 +++ libc/netbsd/net/reentrant.h | 268 ++++++ libc/netbsd/net/servent.h | 44 + libc/netbsd/net/services.h | 480 ++++++++++ libc/netbsd/resolv/__dn_comp.c | 38 + libc/netbsd/resolv/__res_close.c | 33 + libc/netbsd/resolv/__res_send.c | 37 + libc/netbsd/resolv/herror.c | 133 +++ libc/netbsd/resolv/res_cache.c | 533 +++++++++++ libc/netbsd/resolv/res_comp.c | 259 +++++ libc/netbsd/resolv/res_compat.c | 87 ++ libc/netbsd/resolv/res_data.c | 332 +++++++ libc/netbsd/resolv/res_debug.c | 1174 +++++++++++++++++++++++ libc/netbsd/resolv/res_debug.h | 36 + libc/netbsd/resolv/res_init.c | 863 +++++++++++++++++ libc/netbsd/resolv/res_mkquery.c | 276 ++++++ libc/netbsd/resolv/res_private.h | 22 + libc/netbsd/resolv/res_query.c | 415 ++++++++ libc/netbsd/resolv/res_random.c | 275 ++++++ libc/netbsd/resolv/res_send.c | 1136 ++++++++++++++++++++++ libc/netbsd/resolv/res_state.c | 194 ++++ 41 files changed, 14893 insertions(+) create mode 100644 libc/netbsd/gethnamaddr.c create mode 100644 libc/netbsd/inet/nsap_addr.c create mode 100644 libc/netbsd/isc/ev_streams.c create mode 100644 libc/netbsd/isc/ev_timers.c create mode 100644 libc/netbsd/isc/eventlib_p.h create mode 100644 libc/netbsd/nameser/ns_name.c create mode 100644 libc/netbsd/nameser/ns_netint.c create mode 100644 libc/netbsd/nameser/ns_parse.c create mode 100644 libc/netbsd/nameser/ns_print.c create mode 100644 libc/netbsd/nameser/ns_samedomain.c create mode 100644 libc/netbsd/nameser/ns_ttl.c create mode 100644 libc/netbsd/net/base64.c create mode 100644 libc/netbsd/net/getaddrinfo.c create mode 100644 libc/netbsd/net/getnameinfo.c create mode 100644 libc/netbsd/net/getservbyname.c create mode 100644 libc/netbsd/net/getservbyname_r.c create mode 100644 libc/netbsd/net/getservbyport.c create mode 100644 libc/netbsd/net/getservbyport_r.c create mode 100644 libc/netbsd/net/getservent.c create mode 100644 libc/netbsd/net/getservent_r.c create mode 100644 libc/netbsd/net/nsdispatch.c create mode 100644 libc/netbsd/net/reentrant.h create mode 100644 libc/netbsd/net/servent.h create mode 100644 libc/netbsd/net/services.h create mode 100644 libc/netbsd/resolv/__dn_comp.c create mode 100644 libc/netbsd/resolv/__res_close.c create mode 100644 libc/netbsd/resolv/__res_send.c create mode 100644 libc/netbsd/resolv/herror.c create mode 100644 libc/netbsd/resolv/res_cache.c create mode 100644 libc/netbsd/resolv/res_comp.c create mode 100644 libc/netbsd/resolv/res_compat.c create mode 100644 libc/netbsd/resolv/res_data.c create mode 100644 libc/netbsd/resolv/res_debug.c create mode 100644 libc/netbsd/resolv/res_debug.h create mode 100644 libc/netbsd/resolv/res_init.c create mode 100644 libc/netbsd/resolv/res_mkquery.c create mode 100644 libc/netbsd/resolv/res_private.h create mode 100644 libc/netbsd/resolv/res_query.c create mode 100644 libc/netbsd/resolv/res_random.c create mode 100644 libc/netbsd/resolv/res_send.c create mode 100644 libc/netbsd/resolv/res_state.c (limited to 'libc/netbsd') 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 +#include + +#include +#include +#include +#include +#include "arpa_nameser.h" +#include "resolv_private.h" +#include "resolv_cache.h" +#include +#include +#include +#include +#include +#include +#include + +#ifndef LOG_AUTH +# define LOG_AUTH 0 +#endif + +#define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */ + +#include "nsswitch.h" +#include +#include + +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 +#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 +#include +#include + +#include +#include +#include "arpa_nameser.h" + +#include +#include +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include +#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 +#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 +#include + +#include + +#include +#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 +#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 + +#include +#include +#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 +#include +#include +#include +#include + +#define EVENTLIB_DEBUG 1 + +#include +#include +#include +#include +#include + +#include +#include +#include + + +#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 +#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 + +#include +#include "arpa_nameser.h" + +#include +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include +#endif +#include +#include +#include +#include + +#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 is present, the number of digits in the + * MUST be just sufficient to contain the number of bits specified + * by the . 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 +#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 +#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 + +#include +#include "arpa_nameser.h" + +#include +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include +#endif +#include + +/* 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 +#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 +#include + +#include +#include "arpa_nameser.h" +#include + +#include +#include +#include +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include +#endif +#include +#include +#include + +#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 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 +#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 +#include "arpa_nameser.h" +#include +#include + +#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 +#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 +#include +#include +#include + +#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 +#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 +#include +#include +#include +#include +#include "arpa_nameser.h" + +#include +#include +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include +#endif +#include + +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include "arpa_nameser.h" +#include +#include +#include +#include +#include "resolv_private.h" +#include +#include +#include +#include +#include + +#include +#include +#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 + */ + 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:""); +#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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include "arpa_nameser.h" +#include +#include +#include +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include +#endif +#include +#include + +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 */ + 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 +#include +#include +#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 +#include +#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 +#include +#include + +#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 +#include +#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 +#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 +#include + +#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 +#include +#include +#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 +#include + +#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 +#include +#include +#include +#include +#include + +#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 +#include +#include +#include + +#include +#ifdef __ELF__ +#include +#endif /* __ELF__ */ +#include +#define _NS_PRIVATE +#include +#include +#include +#include +#include +#include + +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 +#include + +#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 +#include +#include +#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 +#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 +#include +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include +#endif + +/* XXX THIS IS A MESS! SEE 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 +#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 +#include +#include "resolv_private.h" + +/* XXX THIS IS A MESS! SEE 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 +#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 +#include +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include +#endif + +/* XXX THIS IS A MESS! SEE 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 +#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 +#include +#include + +#include +#include "arpa_nameser.h" + +#include +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include +#endif +#include +#include + +#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 +#include +#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 +#include +#include +#include +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 +#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 +#include +#include +#include "arpa_nameser.h" +#include +#ifdef ANDROID_CHANGES +#include "resolv_private.h" +#else +#include +#endif +#include +#include +#include + +/* + * 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