121057Speter/* 221057Speter * ++Copyright++ 1985, 1988, 1993 321057Speter * - 43070Spst * Copyright (c) 1985, 1988, 1993 53070Spst * The Regents of the University of California. All rights reserved. 63070Spst * 73070Spst * Redistribution and use in source and binary forms, with or without 83070Spst * modification, are permitted provided that the following conditions 93070Spst * are met: 103070Spst * 1. Redistributions of source code must retain the above copyright 113070Spst * notice, this list of conditions and the following disclaimer. 123070Spst * 2. Redistributions in binary form must reproduce the above copyright 133070Spst * notice, this list of conditions and the following disclaimer in the 143070Spst * documentation and/or other materials provided with the distribution. 153070Spst * 4. Neither the name of the University nor the names of its contributors 163070Spst * may be used to endorse or promote products derived from this software 173070Spst * without specific prior written permission. 183070Spst * 193070Spst * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 203070Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 213070Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 223070Spst * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 233070Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 243070Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 253070Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 263070Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 273070Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 283070Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 293070Spst * SUCH DAMAGE. 303070Spst * - 313070Spst * Portions Copyright (c) 1993 by Digital Equipment Corporation. 328870Srgrimes * 333070Spst * Permission to use, copy, modify, and distribute this software for any 343070Spst * purpose with or without fee is hereby granted, provided that the above 353070Spst * copyright notice and this permission notice appear in all copies, and that 363070Spst * the name of Digital Equipment Corporation not be used in advertising or 373070Spst * publicity pertaining to distribution of the document or software without 383070Spst * specific, written prior permission. 398870Srgrimes * 403070Spst * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 413070Spst * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 423070Spst * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 433070Spst * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 443070Spst * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 453070Spst * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 463070Spst * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 473070Spst * SOFTWARE. 483070Spst * - 493070Spst * --Copyright-- 503070Spst */ 513070Spst 523070Spst#if defined(LIBC_SCCS) && !defined(lint) 533070Spststatic char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93"; 5435623Speterstatic char fromrcsid[] = "From: Id: gethnamaddr.c,v 8.23 1998/04/07 04:59:46 vixie Exp $"; 553070Spst#endif /* LIBC_SCCS and not lint */ 5692986Sobrien#include <sys/cdefs.h> 5792986Sobrien__FBSDID("$FreeBSD$"); 583070Spst 5917903Speter#include <sys/types.h> 603070Spst#include <sys/param.h> 613070Spst#include <sys/socket.h> 623070Spst#include <netinet/in.h> 633070Spst#include <arpa/inet.h> 643070Spst#include <arpa/nameser.h> 6510133Speter 6610133Speter#include <stdio.h> 67104415Sume#include <stdlib.h> 6811661Sphk#include <unistd.h> 6910133Speter#include <string.h> 703070Spst#include <netdb.h> 713070Spst#include <resolv.h> 723070Spst#include <ctype.h> 733070Spst#include <errno.h> 743070Spst#include <syslog.h> 7565532Snectar#include <stdarg.h> 7665532Snectar#include <nsswitch.h> 773070Spst 78145602Sume#include "netdb_private.h" 7910150Sbde#include "res_config.h" 803070Spst 8117903Speter#define SPRINTF(x) ((size_t)sprintf x) 8217903Speter 833070Spststatic const char AskedForGot[] = 8413408Speter "gethostby*.gethostanswer: asked for \"%s\", got \"%s\""; 853070Spst 8613408Speter#ifdef RESOLVSORT 87156960Sumestatic void addrsort(char **, int, res_state); 8813408Speter#endif 8913408Speter 9081975Skris#ifdef DEBUG 91156960Sumestatic void dprintf(char *, int, res_state) __printflike(1, 0); 9281975Skris#endif 9381975Skris 94104415Sume#define MAXPACKET (64*1024) 953070Spst 963070Spsttypedef union { 973070Spst HEADER hdr; 983070Spst u_char buf[MAXPACKET]; 993070Spst} querybuf; 1003070Spst 1013070Spsttypedef union { 1023070Spst int32_t al; 1033070Spst char ac; 1043070Spst} align; 1053070Spst 10619301Speterint _dns_ttl_; 1073070Spst 10810133Speter#ifdef DEBUG 10910133Speterstatic void 110156960Sumedprintf(msg, num, res) 11110133Speter char *msg; 11210133Speter int num; 113156960Sume res_state res; 11410133Speter{ 115156960Sume if (res->options & RES_DEBUG) { 11610133Speter int save = errno; 11710133Speter 11810133Speter printf(msg, num); 11910133Speter errno = save; 12010133Speter } 12110133Speter} 12210133Speter#else 123156960Sume# define dprintf(msg, num, res) /*nada*/ 12410133Speter#endif 12510133Speter 12635623Speter#define BOUNDED_INCR(x) \ 12735623Speter do { \ 12835623Speter cp += x; \ 12935623Speter if (cp > eom) { \ 130157779Sume RES_SET_H_ERRNO(statp, NO_RECOVERY); \ 131157779Sume return (-1); \ 13235623Speter } \ 13335623Speter } while (0) 13435623Speter 13535623Speter#define BOUNDS_CHECK(ptr, count) \ 13635623Speter do { \ 13735623Speter if ((ptr) + (count) > eom) { \ 138157779Sume RES_SET_H_ERRNO(statp, NO_RECOVERY); \ 139157779Sume return (-1); \ 14035623Speter } \ 14135623Speter } while (0) 14235623Speter 143145633Sumestatic int 144145633Sumegethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype, 145157779Sume struct hostent *he, struct hostent_data *hed, res_state statp) 1463070Spst{ 14792889Sobrien const HEADER *hp; 14892889Sobrien const u_char *cp; 14992889Sobrien int n; 15035623Speter const u_char *eom, *erdata; 15198865Simp char *bp, *ep, **ap, **hap; 15298865Simp int type, class, ancount, qdcount; 1533070Spst int haveanswer, had_error; 1543070Spst int toobig = 0; 15521057Speter char tbuf[MAXDNAME]; 15613408Speter const char *tname; 15792905Sobrien int (*name_ok)(const char *); 1583070Spst 15913408Speter tname = qname; 160145633Sume he->h_name = NULL; 1613070Spst eom = answer->buf + anslen; 16217903Speter switch (qtype) { 16317903Speter case T_A: 16417903Speter case T_AAAA: 16517903Speter name_ok = res_hnok; 16617903Speter break; 16717903Speter case T_PTR: 16817903Speter name_ok = res_dnok; 16917903Speter break; 17017903Speter default: 171157779Sume RES_SET_H_ERRNO(statp, NO_RECOVERY); 172157779Sume return (-1); /* XXX should be abort(); */ 17317903Speter } 1743070Spst /* 1753070Spst * find first satisfactory answer 1763070Spst */ 1773070Spst hp = &answer->hdr; 1783070Spst ancount = ntohs(hp->ancount); 1793070Spst qdcount = ntohs(hp->qdcount); 180145633Sume bp = hed->hostbuf; 181145633Sume ep = hed->hostbuf + sizeof hed->hostbuf; 18235623Speter cp = answer->buf; 18335623Speter BOUNDED_INCR(HFIXEDSZ); 1843070Spst if (qdcount != 1) { 185157779Sume RES_SET_H_ERRNO(statp, NO_RECOVERY); 186157779Sume return (-1); 1873070Spst } 18898865Simp n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 18917903Speter if ((n < 0) || !(*name_ok)(bp)) { 190157779Sume RES_SET_H_ERRNO(statp, NO_RECOVERY); 191157779Sume return (-1); 1923070Spst } 19335623Speter BOUNDED_INCR(n + QFIXEDSZ); 19417903Speter if (qtype == T_A || qtype == T_AAAA) { 1953070Spst /* res_send() has already verified that the query name is the 1963070Spst * same as the one we sent; this just gets the expanded name 1973070Spst * (i.e., with the succeeding search-domain tacked on). 1983070Spst */ 1993070Spst n = strlen(bp) + 1; /* for the \0 */ 20026974Speter if (n >= MAXHOSTNAMELEN) { 201157779Sume RES_SET_H_ERRNO(statp, NO_RECOVERY); 202157779Sume return (-1); 20326974Speter } 204145633Sume he->h_name = bp; 2053070Spst bp += n; 2063070Spst /* The qname can be abbreviated, but h_name is now absolute. */ 207145633Sume qname = he->h_name; 2083070Spst } 209145633Sume ap = hed->host_aliases; 2103070Spst *ap = NULL; 211145633Sume he->h_aliases = hed->host_aliases; 212145633Sume hap = hed->h_addr_ptrs; 2133070Spst *hap = NULL; 214145633Sume he->h_addr_list = hed->h_addr_ptrs; 2153070Spst haveanswer = 0; 2163070Spst had_error = 0; 21719301Speter _dns_ttl_ = -1; 2183070Spst while (ancount-- > 0 && cp < eom && !had_error) { 21998865Simp n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 22017903Speter if ((n < 0) || !(*name_ok)(bp)) { 2213070Spst had_error++; 2223070Spst continue; 2233070Spst } 2243070Spst cp += n; /* name */ 22535623Speter BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); 2263070Spst type = _getshort(cp); 2273070Spst cp += INT16SZ; /* type */ 2283070Spst class = _getshort(cp); 22919301Speter cp += INT16SZ; /* class */ 23019301Speter if (qtype == T_A && type == T_A) 23119301Speter _dns_ttl_ = _getlong(cp); 23219301Speter cp += INT32SZ; /* TTL */ 2333070Spst n = _getshort(cp); 2343070Spst cp += INT16SZ; /* len */ 23535623Speter BOUNDS_CHECK(cp, n); 23635623Speter erdata = cp + n; 23717903Speter if (class != C_IN) { 2383070Spst /* XXX - debug? syslog? */ 2393070Spst cp += n; 2403070Spst continue; /* XXX - had_error++ ? */ 2413070Spst } 24217903Speter if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { 243145633Sume if (ap >= &hed->host_aliases[_MAXALIASES-1]) 2443070Spst continue; 2453070Spst n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 24617903Speter if ((n < 0) || !(*name_ok)(tbuf)) { 2473070Spst had_error++; 2483070Spst continue; 2493070Spst } 2503070Spst cp += n; 25135623Speter if (cp != erdata) { 252157779Sume RES_SET_H_ERRNO(statp, NO_RECOVERY); 253157779Sume return (-1); 25435623Speter } 2553070Spst /* Store alias. */ 2563070Spst *ap++ = bp; 2573070Spst n = strlen(bp) + 1; /* for the \0 */ 25826974Speter if (n >= MAXHOSTNAMELEN) { 25926974Speter had_error++; 26026974Speter continue; 26126974Speter } 2623070Spst bp += n; 2633070Spst /* Get canonical name. */ 2643070Spst n = strlen(tbuf) + 1; /* for the \0 */ 26598865Simp if (n > ep - bp || n >= MAXHOSTNAMELEN) { 2663070Spst had_error++; 2673070Spst continue; 2683070Spst } 2693070Spst strcpy(bp, tbuf); 270145633Sume he->h_name = bp; 2713070Spst bp += n; 2723070Spst continue; 2733070Spst } 27413408Speter if (qtype == T_PTR && type == T_CNAME) { 27513408Speter n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 27626974Speter if (n < 0 || !res_dnok(tbuf)) { 27713408Speter had_error++; 27813408Speter continue; 27913408Speter } 28013408Speter cp += n; 28135623Speter if (cp != erdata) { 282157779Sume RES_SET_H_ERRNO(statp, NO_RECOVERY); 283157779Sume return (-1); 28435623Speter } 28513408Speter /* Get canonical name. */ 28613408Speter n = strlen(tbuf) + 1; /* for the \0 */ 28798865Simp if (n > ep - bp || n >= MAXHOSTNAMELEN) { 28813408Speter had_error++; 28913408Speter continue; 29013408Speter } 29113408Speter strcpy(bp, tbuf); 29213408Speter tname = bp; 29313408Speter bp += n; 29413408Speter continue; 29513408Speter } 2963070Spst if (type != qtype) { 297188316Sume if (type != T_SIG && type != ns_t_dname) 29855174Srwatson syslog(LOG_NOTICE|LOG_AUTH, 29921057Speter "gethostby*.gethostanswer: asked for \"%s %s %s\", got type \"%s\"", 30055174Srwatson qname, p_class(C_IN), p_type(qtype), 30155174Srwatson p_type(type)); 3023070Spst cp += n; 3033070Spst continue; /* XXX - had_error++ ? */ 3043070Spst } 3053070Spst switch (type) { 3063070Spst case T_PTR: 30713408Speter if (strcasecmp(tname, bp) != 0) { 3083070Spst syslog(LOG_NOTICE|LOG_AUTH, 3093070Spst AskedForGot, qname, bp); 3103070Spst cp += n; 3113070Spst continue; /* XXX - had_error++ ? */ 3123070Spst } 31398865Simp n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 31417903Speter if ((n < 0) || !res_hnok(bp)) { 3153070Spst had_error++; 3163070Spst break; 3173070Spst } 31817903Speter#if MULTI_PTRS_ARE_ALIASES 3193070Spst cp += n; 32035623Speter if (cp != erdata) { 321157779Sume RES_SET_H_ERRNO(statp, NO_RECOVERY); 322157779Sume return (-1); 32335623Speter } 3243070Spst if (!haveanswer) 325145633Sume he->h_name = bp; 326145633Sume else if (ap < &hed->host_aliases[_MAXALIASES-1]) 3273070Spst *ap++ = bp; 3283070Spst else 3293070Spst n = -1; 3303070Spst if (n != -1) { 3313070Spst n = strlen(bp) + 1; /* for the \0 */ 33226974Speter if (n >= MAXHOSTNAMELEN) { 33326974Speter had_error++; 33426974Speter break; 33526974Speter } 3363070Spst bp += n; 3373070Spst } 3383070Spst break; 3393070Spst#else 340145633Sume he->h_name = bp; 341157779Sume if (statp->options & RES_USE_INET6) { 34217903Speter n = strlen(bp) + 1; /* for the \0 */ 34326974Speter if (n >= MAXHOSTNAMELEN) { 34426974Speter had_error++; 34526974Speter break; 34626974Speter } 34717903Speter bp += n; 348145635Sume _map_v4v6_hostent(he, &bp, ep); 34917903Speter } 350157779Sume RES_SET_H_ERRNO(statp, NETDB_SUCCESS); 351157779Sume return (0); 3523070Spst#endif 3533070Spst case T_A: 35417903Speter case T_AAAA: 355145633Sume if (strcasecmp(he->h_name, bp) != 0) { 3563070Spst syslog(LOG_NOTICE|LOG_AUTH, 357145633Sume AskedForGot, he->h_name, bp); 3583070Spst cp += n; 3593070Spst continue; /* XXX - had_error++ ? */ 3603070Spst } 361145633Sume if (n != he->h_length) { 36218608Spst cp += n; 36318608Spst continue; 36418608Spst } 36518608Spst if (!haveanswer) { 36692889Sobrien int nn; 3673070Spst 368145633Sume he->h_name = bp; 3693070Spst nn = strlen(bp) + 1; /* for the \0 */ 3703070Spst bp += nn; 3713070Spst } 3723070Spst 3733070Spst bp += sizeof(align) - ((u_long)bp % sizeof(align)); 3743070Spst 37598865Simp if (bp + n >= ep) { 376157779Sume dprintf("size (%d) too big\n", n, statp); 3773070Spst had_error++; 3783070Spst continue; 3793070Spst } 380145633Sume if (hap >= &hed->h_addr_ptrs[_MAXADDRS-1]) { 38110133Speter if (!toobig++) 38210133Speter dprintf("Too many addresses (%d)\n", 383157779Sume _MAXADDRS, statp); 3843070Spst cp += n; 3853070Spst continue; 3863070Spst } 387145687Sume memcpy(*hap++ = bp, cp, n); 3883070Spst bp += n; 3893070Spst cp += n; 39035623Speter if (cp != erdata) { 391157779Sume RES_SET_H_ERRNO(statp, NO_RECOVERY); 392157779Sume return (-1); 39335623Speter } 3943070Spst break; 3953070Spst default: 396156960Sume dprintf("Impossible condition (type=%d)\n", type, 397157779Sume statp); 398157779Sume RES_SET_H_ERRNO(statp, NO_RECOVERY); 399157779Sume return (-1); 40021057Speter /* BIND has abort() here, too risky on bad data */ 40121057Speter } 4023070Spst if (!had_error) 4033070Spst haveanswer++; 40421057Speter } 4053070Spst if (haveanswer) { 4063070Spst *ap = NULL; 4073070Spst *hap = NULL; 4083070Spst# if defined(RESOLVSORT) 4093070Spst /* 4103070Spst * Note: we sort even if host can take only one address 4113070Spst * in its return structures - should give it the "best" 4123070Spst * address in that case, not some random one 4133070Spst */ 414157779Sume if (statp->nsort && haveanswer > 1 && qtype == T_A) 415157779Sume addrsort(hed->h_addr_ptrs, haveanswer, statp); 4163070Spst# endif /*RESOLVSORT*/ 417145633Sume if (!he->h_name) { 4183070Spst n = strlen(qname) + 1; /* for the \0 */ 41998865Simp if (n > ep - bp || n >= MAXHOSTNAMELEN) 42026974Speter goto no_recovery; 4213070Spst strcpy(bp, qname); 422145633Sume he->h_name = bp; 42317903Speter bp += n; 4243070Spst } 425157779Sume if (statp->options & RES_USE_INET6) 426145635Sume _map_v4v6_hostent(he, &bp, ep); 427157779Sume RES_SET_H_ERRNO(statp, NETDB_SUCCESS); 428157779Sume return (0); 4293070Spst } 43026974Speter no_recovery: 431157779Sume RES_SET_H_ERRNO(statp, NO_RECOVERY); 432157779Sume return (-1); 4333070Spst} 4343070Spst 435145633Sume/* XXX: for async DNS resolver in ypserv */ 4363070Spststruct hostent * 437145633Sume__dns_getanswer(const char *answer, int anslen, const char *qname, int qtype) 43820817Swpaul{ 439157779Sume struct hostent *he; 440157779Sume struct hostent_data *hed; 441145633Sume int error; 442156960Sume res_state statp; 443145633Sume 444156960Sume statp = __res_state(); 445157779Sume if ((he = __hostent_init()) == NULL || 446157779Sume (hed = __hostent_data_init()) == NULL) { 447156960Sume RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 448157779Sume return (NULL); 449145633Sume } 450145633Sume switch (qtype) { 45120892Swpaul case T_AAAA: 452157779Sume he->h_addrtype = AF_INET6; 453157779Sume he->h_length = NS_IN6ADDRSZ; 45420892Swpaul break; 45520892Swpaul case T_A: 45620892Swpaul default: 457157779Sume he->h_addrtype = AF_INET; 458157779Sume he->h_length = NS_INADDRSZ; 45920892Swpaul break; 46020892Swpaul } 46120892Swpaul 462145633Sume error = gethostanswer((const querybuf *)answer, anslen, qname, qtype, 463157779Sume he, hed, statp); 464157779Sume return (error == 0) ? he : NULL; 46520817Swpaul} 46620817Swpaul 46765532Snectarint 46865532Snectar_dns_gethostbyname(void *rval, void *cb_data, va_list ap) 46965532Snectar{ 4703070Spst const char *name; 47117903Speter int af; 472157779Sume char *buffer; 473157779Sume size_t buflen; 474157779Sume int *errnop, *h_errnop; 475157779Sume struct hostent *hptr, he; 476145633Sume struct hostent_data *hed; 477104415Sume querybuf *buf; 478157779Sume int n, type, error; 479157779Sume res_state statp; 4803070Spst 48165532Snectar name = va_arg(ap, const char *); 48265532Snectar af = va_arg(ap, int); 483157779Sume hptr = va_arg(ap, struct hostent *); 484157779Sume buffer = va_arg(ap, char *); 485157779Sume buflen = va_arg(ap, size_t); 486157779Sume errnop = va_arg(ap, int *); 487157779Sume h_errnop = va_arg(ap, int *); 48865532Snectar 489157779Sume *((struct hostent **)rval) = NULL; 490157779Sume 491157779Sume statp = __res_state(); 492157779Sume if ((hed = __hostent_data_init()) == NULL) { 493157779Sume RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 494157779Sume *h_errnop = statp->res_h_errno; 495157779Sume return (NS_NOTFOUND); 496157779Sume } 497157779Sume 498157779Sume he.h_addrtype = af; 49917903Speter switch (af) { 50017903Speter case AF_INET: 501157779Sume he.h_length = NS_INADDRSZ; 50217903Speter type = T_A; 50317903Speter break; 50417903Speter case AF_INET6: 505157779Sume he.h_length = NS_IN6ADDRSZ; 50617903Speter type = T_AAAA; 50717903Speter break; 50817903Speter default: 509157779Sume RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 510157779Sume *h_errnop = statp->res_h_errno; 51117903Speter errno = EAFNOSUPPORT; 512157779Sume return (NS_UNAVAIL); 51317903Speter } 51417903Speter 515104415Sume if ((buf = malloc(sizeof(*buf))) == NULL) { 516157779Sume RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 517157779Sume *h_errnop = statp->res_h_errno; 518157779Sume return (NS_NOTFOUND); 519104415Sume } 520157779Sume n = res_nsearch(statp, name, C_IN, type, buf->buf, sizeof(buf->buf)); 521103350Snectar if (n < 0) { 522104415Sume free(buf); 523157779Sume dprintf("res_nsearch failed (%d)\n", n, statp); 524157779Sume *h_errnop = statp->res_h_errno; 525211340Sume return (NS_NOTFOUND); 526104415Sume } else if (n > sizeof(buf->buf)) { 527104415Sume free(buf); 528157779Sume dprintf("static buffer is too small (%d)\n", n, statp); 529157779Sume *h_errnop = statp->res_h_errno; 530211340Sume return (NS_UNAVAIL); 5313070Spst } 532157779Sume error = gethostanswer(buf, n, name, type, &he, hed, statp); 533104415Sume free(buf); 534157779Sume if (error != 0) { 535157779Sume *h_errnop = statp->res_h_errno; 536211340Sume switch (statp->res_h_errno) { 537211340Sume case HOST_NOT_FOUND: 538211340Sume return (NS_NOTFOUND); 539211340Sume case TRY_AGAIN: 540211340Sume return (NS_TRYAGAIN); 541211340Sume default: 542211340Sume return (NS_UNAVAIL); 543211340Sume } 544211340Sume /*NOTREACHED*/ 545157779Sume } 546157779Sume if (__copy_hostent(&he, hptr, buffer, buflen) != 0) { 547211276Sume *errnop = errno; 548211276Sume RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 549157779Sume *h_errnop = statp->res_h_errno; 550211276Sume return (NS_RETURN); 551157779Sume } 552211276Sume RES_SET_H_ERRNO(statp, NETDB_SUCCESS); 553157779Sume *((struct hostent **)rval) = hptr; 554157779Sume return (NS_SUCCESS); 5553070Spst} 5563070Spst 55765532Snectarint 55865532Snectar_dns_gethostbyaddr(void *rval, void *cb_data, va_list ap) 55965532Snectar{ 560158477Sume const void *addr; 561158477Sume socklen_t len; 562158477Sume int af; 563157779Sume char *buffer; 564157779Sume size_t buflen; 565157779Sume int *errnop, *h_errnop; 566158477Sume const u_char *uaddr; 567157779Sume struct hostent *hptr, he; 568145633Sume struct hostent_data *hed; 569157779Sume int n; 570104415Sume querybuf *buf; 57117903Speter char qbuf[MAXDNAME+1], *qp; 572157779Sume res_state statp; 57310133Speter#ifdef SUNSECURITY 574145633Sume struct hostdata rhd; 575145633Sume struct hostent *rhe; 57610133Speter char **haddr; 57710133Speter u_long old_options; 578145677Sume char hname2[MAXDNAME+1], numaddr[46]; 579157779Sume int ret_h_error; 58010133Speter#endif /*SUNSECURITY*/ 58165532Snectar 582158477Sume addr = va_arg(ap, const void *); 583158477Sume len = va_arg(ap, socklen_t); 58465532Snectar af = va_arg(ap, int); 585157779Sume hptr = va_arg(ap, struct hostent *); 586157779Sume buffer = va_arg(ap, char *); 587157779Sume buflen = va_arg(ap, size_t); 588157779Sume errnop = va_arg(ap, int *); 589157779Sume h_errnop = va_arg(ap, int *); 590158477Sume uaddr = (const u_char *)addr; 591145633Sume 592157779Sume *((struct hostent **)rval) = NULL; 593157779Sume 594157779Sume statp = __res_state(); 595157779Sume if ((hed = __hostent_data_init()) == NULL) { 596157779Sume RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 597157779Sume *h_errnop = statp->res_h_errno; 598157779Sume return (NS_NOTFOUND); 599157779Sume } 600157779Sume 60117903Speter switch (af) { 60217903Speter case AF_INET: 60317903Speter (void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa", 60417903Speter (uaddr[3] & 0xff), 60517903Speter (uaddr[2] & 0xff), 60617903Speter (uaddr[1] & 0xff), 60717903Speter (uaddr[0] & 0xff)); 60817903Speter break; 60917903Speter case AF_INET6: 61017903Speter qp = qbuf; 611157779Sume for (n = NS_IN6ADDRSZ - 1; n >= 0; n--) { 61217903Speter qp += SPRINTF((qp, "%x.%x.", 61317903Speter uaddr[n] & 0xf, 61417903Speter (uaddr[n] >> 4) & 0xf)); 61517903Speter } 616114443Snectar strlcat(qbuf, "ip6.arpa", sizeof(qbuf)); 61717903Speter break; 61817903Speter default: 61917903Speter abort(); 62017903Speter } 621104415Sume if ((buf = malloc(sizeof(*buf))) == NULL) { 622157779Sume RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 623157779Sume *h_errnop = statp->res_h_errno; 624104415Sume return NS_NOTFOUND; 625104415Sume } 626157779Sume n = res_nquery(statp, qbuf, C_IN, T_PTR, (u_char *)buf->buf, 627156960Sume sizeof buf->buf); 6283070Spst if (n < 0) { 629104415Sume free(buf); 630157779Sume dprintf("res_nquery failed (%d)\n", n, statp); 631157779Sume *h_errnop = statp->res_h_errno; 632157779Sume return (NS_UNAVAIL); 6333070Spst } 634104415Sume if (n > sizeof buf->buf) { 635104415Sume free(buf); 636157779Sume dprintf("static buffer is too small (%d)\n", n, statp); 637157779Sume *h_errnop = statp->res_h_errno; 638157779Sume return (NS_UNAVAIL); 63957252Sfenner } 640157779Sume if (gethostanswer(buf, n, qbuf, T_PTR, &he, hed, statp) != 0) { 641104415Sume free(buf); 642157779Sume *h_errnop = statp->res_h_errno; 643211340Sume switch (statp->res_h_errno) { 644211340Sume case HOST_NOT_FOUND: 645211340Sume return (NS_NOTFOUND); 646211340Sume case TRY_AGAIN: 647211340Sume return (NS_TRYAGAIN); 648211340Sume default: 649211340Sume return (NS_UNAVAIL); 650211340Sume } 651211340Sume /*NOTREACHED*/ 652104415Sume } 653104415Sume free(buf); 65410133Speter#ifdef SUNSECURITY 65517903Speter if (af == AF_INET) { 65617903Speter /* 65717903Speter * turn off search as the name should be absolute, 65817903Speter * 'localhost' should be matched by defnames 65917903Speter */ 660157779Sume strncpy(hname2, he.h_name, MAXDNAME); 66117903Speter hname2[MAXDNAME] = '\0'; 662157779Sume old_options = statp->options; 663157779Sume statp->options &= ~RES_DNSRCH; 664157779Sume statp->options |= RES_DEFNAMES; 665145633Sume memset(&rhd, 0, sizeof rhd); 666157779Sume rhe = gethostbyname_r(hname2, &rhd.host, &rhd.data, 667157779Sume sizeof(rhd.data), &ret_h_error); 668157779Sume if (rhe == NULL) { 669145677Sume if (inet_ntop(af, addr, numaddr, sizeof(numaddr)) == NULL) 670145677Sume strlcpy(numaddr, "UNKNOWN", sizeof(numaddr)); 67110133Speter syslog(LOG_NOTICE|LOG_AUTH, 67210133Speter "gethostbyaddr: No A record for %s (verifying [%s])", 673145677Sume hname2, numaddr); 674157779Sume statp->options = old_options; 675157779Sume RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); 676157779Sume *h_errnop = statp->res_h_errno; 677157779Sume return (NS_NOTFOUND); 67817903Speter } 679157779Sume statp->options = old_options; 680145633Sume for (haddr = rhe->h_addr_list; *haddr; haddr++) 681157779Sume if (!memcmp(*haddr, addr, NS_INADDRSZ)) 68210133Speter break; 68317903Speter if (!*haddr) { 684145677Sume if (inet_ntop(af, addr, numaddr, sizeof(numaddr)) == NULL) 685145677Sume strlcpy(numaddr, "UNKNOWN", sizeof(numaddr)); 68610133Speter syslog(LOG_NOTICE|LOG_AUTH, 68710133Speter "gethostbyaddr: A record of %s != PTR record [%s]", 688145677Sume hname2, numaddr); 689157779Sume RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); 690157779Sume *h_errnop = statp->res_h_errno; 691157779Sume return (NS_NOTFOUND); 69217903Speter } 69310133Speter } 69410133Speter#endif /*SUNSECURITY*/ 695157779Sume he.h_addrtype = af; 696157779Sume he.h_length = len; 697145687Sume memcpy(hed->host_addr, uaddr, len); 698145633Sume hed->h_addr_ptrs[0] = (char *)hed->host_addr; 699145633Sume hed->h_addr_ptrs[1] = NULL; 700157779Sume if (af == AF_INET && (statp->options & RES_USE_INET6)) { 701145633Sume _map_v4v6_address((char*)hed->host_addr, (char*)hed->host_addr); 702157779Sume he.h_addrtype = AF_INET6; 703157779Sume he.h_length = NS_IN6ADDRSZ; 70417903Speter } 705157779Sume if (__copy_hostent(&he, hptr, buffer, buflen) != 0) { 706211276Sume *errnop = errno; 707211276Sume RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 708157779Sume *h_errnop = statp->res_h_errno; 709211276Sume return (NS_RETURN); 710157779Sume } 711211276Sume RES_SET_H_ERRNO(statp, NETDB_SUCCESS); 712157779Sume *((struct hostent **)rval) = hptr; 713157779Sume return (NS_SUCCESS); 7143070Spst} 7153070Spst 71613408Speter#ifdef RESOLVSORT 71713408Speterstatic void 718157779Sumeaddrsort(char **ap, int num, res_state res) 71913408Speter{ 72013408Speter int i, j; 72113408Speter char **p; 722145633Sume short aval[_MAXADDRS]; 72313408Speter int needsort = 0; 72413408Speter 72513408Speter p = ap; 72613408Speter for (i = 0; i < num; i++, p++) { 727156960Sume for (j = 0 ; (unsigned)j < res->nsort; j++) 728156960Sume if (res->sort_list[j].addr.s_addr == 729156960Sume (((struct in_addr *)(*p))->s_addr & res->sort_list[j].mask)) 73013408Speter break; 73113408Speter aval[i] = j; 73213408Speter if (needsort == 0 && i > 0 && j < aval[i-1]) 73313408Speter needsort = i; 73413408Speter } 73513408Speter if (!needsort) 73613408Speter return; 73713408Speter 73813408Speter while (needsort < num) { 73913408Speter for (j = needsort - 1; j >= 0; j--) { 74013408Speter if (aval[j] > aval[j+1]) { 74113408Speter char *hp; 74213408Speter 74313408Speter i = aval[j]; 74413408Speter aval[j] = aval[j+1]; 74513408Speter aval[j+1] = i; 74613408Speter 74713408Speter hp = ap[j]; 74813408Speter ap[j] = ap[j+1]; 74913408Speter ap[j+1] = hp; 75013408Speter 75113408Speter } else 75213408Speter break; 75313408Speter } 75413408Speter needsort++; 75513408Speter } 75613408Speter} 75713408Speter#endif 758156960Sume 7593070Spstvoid 760157779Sume_sethostdnsent(int stayopen) 7613070Spst{ 762156960Sume res_state statp; 763156960Sume 764156960Sume statp = __res_state(); 765156960Sume if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) 76613408Speter return; 7673070Spst if (stayopen) 768156960Sume statp->options |= RES_STAYOPEN | RES_USEVC; 7693070Spst} 7703070Spst 7713070Spstvoid 7723070Spst_endhostdnsent() 7733070Spst{ 774156960Sume res_state statp; 775156960Sume 776156960Sume statp = __res_state(); 777156960Sume statp->options &= ~(RES_STAYOPEN | RES_USEVC); 778156960Sume res_nclose(statp); 7793070Spst} 780