| /* | |
| * ++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. 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-- | |
| */ | |
| /* | |
| * Portions copyright (c) 1999, 2000 | |
| * Intel Corporation. | |
| * 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 Intel Corporation and | |
| * its contributors. | |
| * | |
| * 4. Neither the name of Intel Corporation or its contributors may be | |
| * used to endorse or promote products derived from this software | |
| * without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION 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 INTEL CORPORATION 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. | |
| * | |
| */ | |
| #if defined(LIBC_SCCS) && !defined(lint) | |
| static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93"; | |
| static char fromrcsid[] = "From: Id: gethnamaddr.c,v 8.23 1998/04/07 04:59:46 vixie Exp $"; | |
| static char rcsid[] = "$Id: gethostbydns.c,v 1.1.1.1 2003/11/19 01:51:27 kyu3 Exp $"; | |
| #endif /* LIBC_SCCS and not lint */ | |
| #include <sys/types.h> | |
| #include <sys/param.h> | |
| #include <sys/socket.h> | |
| #include <netinet/in.h> | |
| #include <arpa/inet.h> | |
| #include <arpa/nameser.h> | |
| #include <stdio.h> | |
| #include <unistd.h> | |
| #include <string.h> | |
| #include <netdb.h> | |
| #include <resolv.h> | |
| #include <ctype.h> | |
| #include <errno.h> | |
| #ifdef _ORG_FREEBSD_ | |
| #include <syslog.h> | |
| #else | |
| #include <stdlib.h> | |
| u_int32_t _getlong(const u_char *src); | |
| u_int16_t _getshort(const u_char *src); | |
| #endif | |
| #include "res_config.h" | |
| #include "Socklib_internals.h" | |
| #define SPRINTF(x) ((size_t)sprintf x) | |
| #define MAXALIASES 35 | |
| #define MAXADDRS 35 | |
| static const char AskedForGot[] = | |
| "gethostby*.gethostanswer: asked for \"%s\", got \"%s\""; | |
| static char *h_addr_ptrs[MAXADDRS + 1]; | |
| static struct hostent host; | |
| static char *host_aliases[MAXALIASES]; | |
| static char hostbuf[8*1024]; | |
| static u_char host_addr[16]; /* IPv4 or IPv6 */ | |
| #ifdef RESOLVSORT | |
| static void addrsort(char **, int); | |
| #endif | |
| #if PACKETSZ > 1024 | |
| #define MAXPACKET PACKETSZ | |
| #else | |
| #define MAXPACKET 1024 | |
| #endif | |
| typedef union { | |
| HEADER hdr; | |
| u_char buf[MAXPACKET]; | |
| } querybuf; | |
| typedef union { | |
| int32_t al; | |
| char ac; | |
| } align; | |
| extern int h_errno; | |
| int _dns_ttl_; | |
| #ifdef DEBUG_RES | |
| static void | |
| dprintf(char *msg, int num) | |
| { | |
| if (_res.options & RES_DEBUG) { | |
| int save = errno; | |
| printf(msg, num); | |
| errno = save; | |
| } | |
| } | |
| #else | |
| # define dprintf(msg, num) /*nada*/ | |
| #endif | |
| #define BOUNDED_INCR(x) \ | |
| do { \ | |
| cp += x; \ | |
| if (cp > eom) { \ | |
| h_errno = NO_RECOVERY; \ | |
| return (NULL); \ | |
| } \ | |
| } while (0) | |
| #define BOUNDS_CHECK(ptr, count) \ | |
| do { \ | |
| if ((ptr) + (count) > eom) { \ | |
| h_errno = NO_RECOVERY; \ | |
| return (NULL); \ | |
| } \ | |
| } while (0) | |
| static struct hostent * | |
| gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype) | |
| { | |
| register const HEADER *hp; | |
| register const u_char *cp; | |
| register int n; | |
| const u_char *eom, *erdata; | |
| char *bp, **ap, **hap; | |
| int type, class, buflen, ancount, qdcount; | |
| int haveanswer, had_error; | |
| int toobig = 0; | |
| char tbuf[MAXDNAME]; | |
| const char *tname; | |
| int (*name_ok)(const char *); | |
| tname = qname; | |
| 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: | |
| h_errno = NO_RECOVERY; | |
| return (NULL); /* XXX should be abort(); */ | |
| } | |
| /* | |
| * find first satisfactory answer | |
| */ | |
| hp = &answer->hdr; | |
| ancount = ntohs(hp->ancount); | |
| qdcount = ntohs(hp->qdcount); | |
| bp = hostbuf; | |
| buflen = sizeof hostbuf; | |
| cp = answer->buf; | |
| BOUNDED_INCR(HFIXEDSZ); | |
| if (qdcount != 1) { | |
| h_errno = NO_RECOVERY; | |
| return (NULL); | |
| } | |
| n = dn_expand(answer->buf, eom, cp, bp, buflen); | |
| 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 = (int)strlen(bp) + 1; /* for the \0 */ | |
| if (n >= MAXHOSTNAMELEN) { | |
| h_errno = NO_RECOVERY; | |
| return (NULL); | |
| } | |
| host.h_name = bp; | |
| bp += n; | |
| buflen -= n; | |
| /* The qname can be abbreviated, but h_name is now absolute. */ | |
| qname = host.h_name; | |
| } | |
| ap = host_aliases; | |
| *ap = NULL; | |
| host.h_aliases = host_aliases; | |
| hap = h_addr_ptrs; | |
| *hap = NULL; | |
| host.h_addr_list = h_addr_ptrs; | |
| haveanswer = 0; | |
| had_error = 0; | |
| _dns_ttl_ = -1; | |
| while (ancount-- > 0 && cp < eom && !had_error) { | |
| n = dn_expand(answer->buf, eom, cp, bp, buflen); | |
| 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; /* class */ | |
| if (qtype == T_A && type == T_A) | |
| _dns_ttl_ = _getlong(cp); | |
| cp += INT32SZ; /* 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 >= &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 = (int)strlen(bp) + 1; /* for the \0 */ | |
| if (n >= MAXHOSTNAMELEN) { | |
| had_error++; | |
| continue; | |
| } | |
| bp += n; | |
| buflen -= n; | |
| /* Get canonical name. */ | |
| n = (int)strlen(tbuf) + 1; /* for the \0 */ | |
| if (n > buflen || n >= MAXHOSTNAMELEN) { | |
| had_error++; | |
| continue; | |
| } | |
| strcpy(bp, tbuf); | |
| host.h_name = bp; | |
| bp += n; | |
| buflen -= 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 = (int)strlen(tbuf) + 1; /* for the \0 */ | |
| if (n > buflen || n >= MAXHOSTNAMELEN) { | |
| had_error++; | |
| continue; | |
| } | |
| strcpy(bp, tbuf); | |
| tname = bp; | |
| bp += n; | |
| buflen -= n; | |
| continue; | |
| } | |
| if (type != qtype) { | |
| #ifdef _ORG_FREEBSD_ | |
| syslog(LOG_NOTICE|LOG_AUTH, | |
| "gethostby*.gethostanswer: asked for \"%s %s %s\", got type \"%s\"", | |
| qname, p_class(C_IN), p_type(qtype), | |
| p_type(type)); | |
| #endif | |
| cp += n; | |
| continue; /* XXX - had_error++ ? */ | |
| } | |
| switch (type) { | |
| case T_PTR: | |
| if (strcasecmp(tname, bp) != 0) { | |
| #ifdef _ORG_FREEBSD_ | |
| syslog(LOG_NOTICE|LOG_AUTH, | |
| AskedForGot, qname, bp); | |
| #endif | |
| cp += n; | |
| continue; /* XXX - had_error++ ? */ | |
| } | |
| n = dn_expand(answer->buf, eom, cp, bp, buflen); | |
| 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) | |
| host.h_name = bp; | |
| else if (ap < &host_aliases[MAXALIASES-1]) | |
| *ap++ = bp; | |
| else | |
| n = -1; | |
| if (n != -1) { | |
| n = (int)strlen(bp) + 1; /* for the \0 */ | |
| if (n >= MAXHOSTNAMELEN) { | |
| had_error++; | |
| break; | |
| } | |
| bp += n; | |
| buflen -= n; | |
| } | |
| break; | |
| #else | |
| 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; | |
| buflen -= n; | |
| _map_v4v6_hostent(&host, &bp, &buflen); | |
| } | |
| h_errno = NETDB_SUCCESS; | |
| return (&host); | |
| #endif | |
| case T_A: | |
| case T_AAAA: | |
| if (strcasecmp(host.h_name, bp) != 0) { | |
| #ifdef _ORG_FREEBSD_ | |
| syslog(LOG_NOTICE|LOG_AUTH, | |
| AskedForGot, host.h_name, bp); | |
| #endif | |
| cp += n; | |
| continue; /* XXX - had_error++ ? */ | |
| } | |
| if (n != host.h_length) { | |
| cp += n; | |
| continue; | |
| } | |
| if (!haveanswer) { | |
| register int nn; | |
| host.h_name = bp; | |
| nn = (int)strlen(bp) + 1; /* for the \0 */ | |
| bp += nn; | |
| buflen -= nn; | |
| } | |
| bp += sizeof(align) - ((size_t)bp % sizeof(align)); | |
| if (bp + n >= &hostbuf[sizeof hostbuf]) { | |
| dprintf("size (%d) too big\n", n); | |
| had_error++; | |
| continue; | |
| } | |
| if (hap >= &h_addr_ptrs[MAXADDRS-1]) { | |
| if (!toobig++) | |
| dprintf("Too many addresses (%d)\n", | |
| MAXADDRS); | |
| cp += n; | |
| continue; | |
| } | |
| *hap++ = bp; | |
| bcopy(cp, bp, n); | |
| bp += n; | |
| buflen -= n; | |
| cp += n; | |
| if (cp != erdata) { | |
| h_errno = NO_RECOVERY; | |
| return (NULL); | |
| } | |
| break; | |
| default: | |
| dprintf("Impossible condition (type=%d)\n", type); | |
| h_errno = NO_RECOVERY; | |
| return (NULL); | |
| /* BIND has abort() here, too risky on bad data */ | |
| } | |
| if (!had_error) | |
| haveanswer++; | |
| } | |
| if (haveanswer) { | |
| *ap = NULL; | |
| *hap = NULL; | |
| # if defined(RESOLVSORT) | |
| /* | |
| * 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(h_addr_ptrs, haveanswer); | |
| # endif /*RESOLVSORT*/ | |
| if (!host.h_name) { | |
| n = (int)strlen(qname) + 1; /* for the \0 */ | |
| if (n > buflen || n >= MAXHOSTNAMELEN) | |
| goto no_recovery; | |
| strcpy(bp, qname); | |
| host.h_name = bp; | |
| bp += n; | |
| buflen -= n; | |
| } | |
| if (_res.options & RES_USE_INET6) | |
| _map_v4v6_hostent(&host, &bp, &buflen); | |
| h_errno = NETDB_SUCCESS; | |
| return (&host); | |
| } | |
| no_recovery: | |
| h_errno = NO_RECOVERY; | |
| return (NULL); | |
| } | |
| struct hostent * | |
| __dns_getanswer(const char *answer, int anslen, const char *qname, int qtype) | |
| { | |
| switch(qtype) { | |
| case T_AAAA: | |
| host.h_addrtype = AF_INET6; | |
| host.h_length = IN6ADDRSZ; | |
| break; | |
| case T_A: | |
| default: | |
| host.h_addrtype = AF_INET; | |
| host.h_length = INADDRSZ; | |
| break; | |
| } | |
| return(gethostanswer((const querybuf *)answer, anslen, qname, qtype)); | |
| } | |
| struct hostent * | |
| _gethostbydnsname(const char *name, int af) | |
| { | |
| querybuf buf; | |
| register const char *cp; | |
| char *bp; | |
| int n, size, type, len; | |
| if ((_res.options & RES_INIT) == 0 && res_init() == -1) { | |
| h_errno = NETDB_INTERNAL; | |
| return (NULL); | |
| } | |
| switch (af) { | |
| case AF_INET: | |
| size = INADDRSZ; | |
| type = T_A; | |
| break; | |
| case AF_INET6: | |
| size = IN6ADDRSZ; | |
| type = T_AAAA; | |
| break; | |
| default: | |
| h_errno = NETDB_INTERNAL; | |
| errno = EAFNOSUPPORT; | |
| return (NULL); | |
| } | |
| host.h_addrtype = af; | |
| host.h_length = size; | |
| /* | |
| * if there aren't any dots, it could be a user-level alias. | |
| * this is also done in res_query() since we are not the only | |
| * function that looks up host names. | |
| */ | |
| if (!strchr(name, '.') && ( NULL != (cp = __hostalias(name)))) | |
| name = cp; | |
| /* | |
| * disallow names consisting only of digits/dots, unless | |
| * they end in a dot. | |
| */ | |
| if (isdigit(name[0])) | |
| for (cp = name;; ++cp) { | |
| if (!*cp) { | |
| if (*--cp == '.') | |
| break; | |
| /* | |
| * All-numeric, no dot at the end. | |
| * Fake up a hostent as if we'd actually | |
| * done a lookup. | |
| */ | |
| if (inet_pton(af, name, host_addr) <= 0) { | |
| h_errno = HOST_NOT_FOUND; | |
| return (NULL); | |
| } | |
| strncpy(hostbuf, name, MAXDNAME); | |
| hostbuf[MAXDNAME] = '\0'; | |
| bp = hostbuf + MAXDNAME; | |
| len = sizeof hostbuf - MAXDNAME; | |
| host.h_name = hostbuf; | |
| host.h_aliases = host_aliases; | |
| host_aliases[0] = NULL; | |
| h_addr_ptrs[0] = (char *)host_addr; | |
| h_addr_ptrs[1] = NULL; | |
| host.h_addr_list = h_addr_ptrs; | |
| if (_res.options & RES_USE_INET6) | |
| _map_v4v6_hostent(&host, &bp, &len); | |
| h_errno = NETDB_SUCCESS; | |
| return (&host); | |
| } | |
| if (!isdigit(*cp) && *cp != '.') | |
| break; | |
| } | |
| if ((isxdigit(name[0]) && strchr(name, ':') != NULL) || | |
| name[0] == ':') | |
| for (cp = name;; ++cp) { | |
| if (!*cp) { | |
| if (*--cp == '.') | |
| break; | |
| /* | |
| * All-IPv6-legal, no dot at the end. | |
| * Fake up a hostent as if we'd actually | |
| * done a lookup. | |
| */ | |
| if (inet_pton(af, name, host_addr) <= 0) { | |
| h_errno = HOST_NOT_FOUND; | |
| return (NULL); | |
| } | |
| strncpy(hostbuf, name, MAXDNAME); | |
| hostbuf[MAXDNAME] = '\0'; | |
| bp = hostbuf + MAXDNAME; | |
| len = sizeof hostbuf - MAXDNAME; | |
| host.h_name = hostbuf; | |
| host.h_aliases = host_aliases; | |
| host_aliases[0] = NULL; | |
| h_addr_ptrs[0] = (char *)host_addr; | |
| h_addr_ptrs[1] = NULL; | |
| host.h_addr_list = h_addr_ptrs; | |
| h_errno = NETDB_SUCCESS; | |
| return (&host); | |
| } | |
| if (!isxdigit(*cp) && *cp != ':' && *cp != '.') | |
| break; | |
| } | |
| if ((n = res_search(name, C_IN, type, buf.buf, sizeof(buf))) < 0) { | |
| dprintf("res_search failed (%d)\n", n); | |
| return (NULL); | |
| } | |
| return (gethostanswer(&buf, n, name, type)); | |
| } | |
| struct hostent * | |
| _gethostbydnsaddr(const char *addr, int len, int af) | |
| { | |
| const u_char *uaddr = (const u_char *)addr; | |
| static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff }; | |
| static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; | |
| int n, size; | |
| querybuf buf; | |
| register struct hostent *hp; | |
| char qbuf[MAXDNAME+1], *qp; | |
| #ifdef SUNSECURITY | |
| register struct hostent *rhp; | |
| char **haddr; | |
| u_long old_options; | |
| char hname2[MAXDNAME+1]; | |
| #endif /*SUNSECURITY*/ | |
| if ((_res.options & RES_INIT) == 0 && res_init() == -1) { | |
| h_errno = NETDB_INTERNAL; | |
| return (NULL); | |
| } | |
| if (af == AF_INET6 && len == IN6ADDRSZ && | |
| (!bcmp(uaddr, mapped, sizeof mapped) || | |
| !bcmp(uaddr, tunnelled, sizeof tunnelled))) { | |
| /* Unmap. */ | |
| addr += sizeof mapped; | |
| uaddr += sizeof mapped; | |
| 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); | |
| } | |
| switch (af) { | |
| case AF_INET: | |
| (void) sprintf(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; | |
| for (n = IN6ADDRSZ - 1; n >= 0; n--) { | |
| qp += SPRINTF((qp, "%x.%x.", | |
| uaddr[n] & 0xf, | |
| (uaddr[n] >> 4) & 0xf)); | |
| } | |
| strcpy(qp, "ip6.int"); | |
| break; | |
| default: | |
| abort(); | |
| } | |
| n = res_query(qbuf, C_IN, T_PTR, (u_char *)buf.buf, sizeof buf.buf); | |
| if (n < 0) { | |
| dprintf("res_query failed (%d)\n", n); | |
| return (NULL); | |
| } | |
| if ( NULL == (hp = gethostanswer(&buf, n, qbuf, T_PTR))) | |
| return (NULL); /* h_errno was set by gethostanswer() */ | |
| #ifdef SUNSECURITY | |
| if (af == AF_INET) { | |
| /* | |
| * turn off search as the name should be absolute, | |
| * 'localhost' should be matched by defnames | |
| */ | |
| strncpy(hname2, hp->h_name, MAXDNAME); | |
| hname2[MAXDNAME] = '\0'; | |
| old_options = _res.options; | |
| _res.options &= ~RES_DNSRCH; | |
| _res.options |= RES_DEFNAMES; | |
| if (!(rhp = gethostbyname(hname2))) { | |
| #ifdef _ORG_FREEBSD_ | |
| syslog(LOG_NOTICE|LOG_AUTH, | |
| "gethostbyaddr: No A record for %s (verifying [%s])", | |
| hname2, inet_ntoa(*((struct in_addr *)addr))); | |
| #endif | |
| _res.options = old_options; | |
| h_errno = HOST_NOT_FOUND; | |
| return (NULL); | |
| } | |
| _res.options = old_options; | |
| for (haddr = rhp->h_addr_list; *haddr; haddr++) | |
| if (!memcmp(*haddr, addr, INADDRSZ)) | |
| break; | |
| if (!*haddr) { | |
| #ifdef _ORG_FREEBSD_ | |
| syslog(LOG_NOTICE|LOG_AUTH, | |
| "gethostbyaddr: A record of %s != PTR record [%s]", | |
| hname2, inet_ntoa(*((struct in_addr *)addr))); | |
| #endif | |
| h_errno = HOST_NOT_FOUND; | |
| return (NULL); | |
| } | |
| } | |
| #endif /*SUNSECURITY*/ | |
| hp->h_addrtype = af; | |
| hp->h_length = len; | |
| bcopy(addr, host_addr, len); | |
| h_addr_ptrs[0] = (char *)host_addr; | |
| h_addr_ptrs[1] = NULL; | |
| if (af == AF_INET && (_res.options & RES_USE_INET6)) { | |
| _map_v4v6_address((char*)host_addr, (char*)host_addr); | |
| hp->h_addrtype = AF_INET6; | |
| hp->h_length = IN6ADDRSZ; | |
| } | |
| h_errno = NETDB_SUCCESS; | |
| return (hp); | |
| } | |
| #ifdef RESOLVSORT | |
| static void | |
| addrsort(char **ap, int num) | |
| { | |
| short i, j; | |
| char **p; | |
| short aval[MAXADDRS]; | |
| short needsort = 0; | |
| 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 *)(*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++; | |
| } | |
| } | |
| #endif | |
| void | |
| _sethostdnsent(int stayopen) | |
| { | |
| if ((_res.options & RES_INIT) == 0 && res_init() == -1) | |
| return; | |
| if (stayopen) | |
| _res.options |= RES_STAYOPEN | RES_USEVC; | |
| } | |
| void | |
| _endhostdnsent() | |
| { | |
| _res.options &= ~(RES_STAYOPEN | RES_USEVC); | |
| res_close(); | |
| } |