Home | History | Annotate | Line # | Download | only in irs
dns_ho.c revision 1.1.1.2
      1      1.1  christos /*	$NetBSD: dns_ho.c,v 1.1.1.2 2012/09/09 16:07:58 christos Exp $	*/
      2      1.1  christos 
      3      1.1  christos /*
      4      1.1  christos  * Portions Copyright (C) 2004-2006, 2008  Internet Systems Consortium, Inc. ("ISC")
      5      1.1  christos  * Portions Copyright (C) 1996-2003  Internet Software Consortium.
      6      1.1  christos  *
      7      1.1  christos  * Permission to use, copy, modify, and/or distribute this software for any
      8      1.1  christos  * purpose with or without fee is hereby granted, provided that the above
      9      1.1  christos  * copyright notice and this permission notice appear in all copies.
     10      1.1  christos  *
     11      1.1  christos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
     12      1.1  christos  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     13      1.1  christos  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
     14      1.1  christos  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
     15      1.1  christos  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
     16      1.1  christos  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     17      1.1  christos  * PERFORMANCE OF THIS SOFTWARE.
     18      1.1  christos  */
     19      1.1  christos 
     20      1.1  christos /*
     21      1.1  christos  * Copyright (c) 1985, 1988, 1993
     22      1.1  christos  *    The Regents of the University of California.  All rights reserved.
     23      1.1  christos  *
     24      1.1  christos  * Redistribution and use in source and binary forms, with or without
     25      1.1  christos  * modification, are permitted provided that the following conditions
     26      1.1  christos  * are met:
     27      1.1  christos  * 1. Redistributions of source code must retain the above copyright
     28      1.1  christos  *    notice, this list of conditions and the following disclaimer.
     29      1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     30      1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     31      1.1  christos  *    documentation and/or other materials provided with the distribution.
     32      1.1  christos  * 3. All advertising materials mentioning features or use of this software
     33      1.1  christos  *    must display the following acknowledgement:
     34      1.1  christos  * 	This product includes software developed by the University of
     35      1.1  christos  * 	California, Berkeley and its contributors.
     36      1.1  christos  * 4. Neither the name of the University nor the names of its contributors
     37      1.1  christos  *    may be used to endorse or promote products derived from this software
     38      1.1  christos  *    without specific prior written permission.
     39      1.1  christos  *
     40      1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     41      1.1  christos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     42      1.1  christos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     43      1.1  christos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     44      1.1  christos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     45      1.1  christos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     46      1.1  christos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     47      1.1  christos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     48      1.1  christos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     49      1.1  christos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     50      1.1  christos  * SUCH DAMAGE.
     51      1.1  christos  */
     52      1.1  christos 
     53      1.1  christos /* from gethostnamadr.c	8.1 (Berkeley) 6/4/93 */
     54      1.1  christos /* BIND Id: gethnamaddr.c,v 8.15 1996/05/22 04:56:30 vixie Exp $ */
     55      1.1  christos 
     56      1.1  christos #if defined(LIBC_SCCS) && !defined(lint)
     57  1.1.1.2  christos static const char rcsid[] = "Id: dns_ho.c,v 1.23 2008/11/14 02:36:51 marka Exp ";
     58      1.1  christos #endif /* LIBC_SCCS and not lint */
     59      1.1  christos 
     60      1.1  christos /* Imports. */
     61      1.1  christos 
     62      1.1  christos #include "port_before.h"
     63      1.1  christos 
     64      1.1  christos #include <sys/types.h>
     65      1.1  christos #include <sys/param.h>
     66      1.1  christos #include <sys/socket.h>
     67      1.1  christos 
     68      1.1  christos #include <netinet/in.h>
     69      1.1  christos #include <arpa/inet.h>
     70      1.1  christos #include <arpa/nameser.h>
     71      1.1  christos 
     72      1.1  christos #include <ctype.h>
     73      1.1  christos #include <errno.h>
     74      1.1  christos #include <stdlib.h>
     75      1.1  christos #include <netdb.h>
     76      1.1  christos #include <resolv.h>
     77      1.1  christos #include <stdio.h>
     78      1.1  christos #include <string.h>
     79      1.1  christos #include <syslog.h>
     80      1.1  christos 
     81      1.1  christos #include <isc/memcluster.h>
     82      1.1  christos #include <irs.h>
     83      1.1  christos 
     84      1.1  christos #include "port_after.h"
     85      1.1  christos 
     86      1.1  christos #include "irs_p.h"
     87      1.1  christos #include "dns_p.h"
     88      1.1  christos 
     89      1.1  christos #ifdef SPRINTF_CHAR
     90      1.1  christos # define SPRINTF(x) strlen(sprintf/**/x)
     91      1.1  christos #else
     92      1.1  christos # define SPRINTF(x) sprintf x
     93      1.1  christos #endif
     94      1.1  christos 
     95      1.1  christos /* Definitions. */
     96      1.1  christos 
     97      1.1  christos #define	MAXALIASES	35
     98      1.1  christos #define	MAXADDRS	35
     99      1.1  christos 
    100      1.1  christos #define MAXPACKET (65535)	/*%< Maximum TCP message size */
    101      1.1  christos #define BOUNDS_CHECK(ptr, count) \
    102      1.1  christos 	if ((ptr) + (count) > eom) { \
    103      1.1  christos 		had_error++; \
    104      1.1  christos 		continue; \
    105      1.1  christos 	} else (void)0
    106      1.1  christos 
    107      1.1  christos typedef union {
    108      1.1  christos 	HEADER hdr;
    109      1.1  christos 	u_char buf[MAXPACKET];
    110      1.1  christos } querybuf;
    111      1.1  christos 
    112      1.1  christos struct dns_res_target {
    113      1.1  christos 	struct dns_res_target *next;
    114      1.1  christos 	querybuf qbuf;		/*%< query buffer */
    115      1.1  christos 	u_char *answer;		/*%< buffer to put answer */
    116      1.1  christos 	int anslen;		/*%< size of answer buffer */
    117      1.1  christos 	int qclass, qtype;	/*%< class and type of query */
    118      1.1  christos 	int action;		/*%< condition whether query is really issued */
    119      1.1  christos 	char qname[MAXDNAME +1]; /*%< domain name */
    120      1.1  christos #if 0
    121      1.1  christos 	int n;			/*%< result length */
    122      1.1  christos #endif
    123      1.1  christos };
    124      1.1  christos enum {RESTGT_DOALWAYS, RESTGT_AFTERFAILURE, RESTGT_IGNORE};
    125      1.1  christos enum {RESQRY_SUCCESS, RESQRY_FAIL};
    126      1.1  christos 
    127      1.1  christos struct pvt {
    128      1.1  christos 	struct hostent	host;
    129      1.1  christos 	char *		h_addr_ptrs[MAXADDRS + 1];
    130      1.1  christos 	char *		host_aliases[MAXALIASES];
    131      1.1  christos 	char		hostbuf[8*1024];
    132      1.1  christos 	u_char		host_addr[16];	/*%< IPv4 or IPv6 */
    133      1.1  christos 	struct __res_state  *res;
    134      1.1  christos 	void		(*free_res)(void *);
    135      1.1  christos };
    136      1.1  christos 
    137      1.1  christos typedef union {
    138      1.1  christos 	int32_t al;
    139      1.1  christos 	char ac;
    140      1.1  christos } align;
    141      1.1  christos 
    142      1.1  christos static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
    143      1.1  christos static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
    144      1.1  christos /* Note: the IPv6 loopback address is in the "tunnel" space */
    145      1.1  christos static const u_char v6local[] = { 0,0, 0,1 }; /*%< last 4 bytes of IPv6 addr */
    146      1.1  christos /* Forwards. */
    147      1.1  christos 
    148      1.1  christos static void		ho_close(struct irs_ho *this);
    149      1.1  christos static struct hostent *	ho_byname(struct irs_ho *this, const char *name);
    150      1.1  christos static struct hostent *	ho_byname2(struct irs_ho *this, const char *name,
    151      1.1  christos 				   int af);
    152      1.1  christos static struct hostent *	ho_byaddr(struct irs_ho *this, const void *addr,
    153      1.1  christos 				  int len, int af);
    154      1.1  christos static struct hostent *	ho_next(struct irs_ho *this);
    155      1.1  christos static void		ho_rewind(struct irs_ho *this);
    156      1.1  christos static void		ho_minimize(struct irs_ho *this);
    157      1.1  christos static struct __res_state * ho_res_get(struct irs_ho *this);
    158      1.1  christos static void		ho_res_set(struct irs_ho *this,
    159      1.1  christos 				   struct __res_state *res,
    160      1.1  christos 				   void (*free_res)(void *));
    161      1.1  christos static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
    162      1.1  christos 				     const struct addrinfo *pai);
    163      1.1  christos 
    164      1.1  christos static void		map_v4v6_hostent(struct hostent *hp, char **bp,
    165      1.1  christos 					 char *ep);
    166      1.1  christos static void		addrsort(res_state, char **, int);
    167      1.1  christos static struct hostent *	gethostans(struct irs_ho *this,
    168      1.1  christos 				   const u_char *ansbuf, int anslen,
    169      1.1  christos 				   const char *qname, int qtype,
    170      1.1  christos 				   int af, int size,
    171      1.1  christos 				   struct addrinfo **ret_aip,
    172      1.1  christos 				   const struct addrinfo *pai);
    173      1.1  christos static int add_hostent(struct pvt *pvt, char *bp, char **hap,
    174      1.1  christos 		       struct addrinfo *ai);
    175      1.1  christos static int		init(struct irs_ho *this);
    176      1.1  christos 
    177      1.1  christos /* Exports. */
    178      1.1  christos 
    179      1.1  christos struct irs_ho *
    180      1.1  christos irs_dns_ho(struct irs_acc *this) {
    181      1.1  christos 	struct irs_ho *ho;
    182      1.1  christos 	struct pvt *pvt;
    183      1.1  christos 
    184      1.1  christos 	UNUSED(this);
    185      1.1  christos 
    186      1.1  christos 	if (!(pvt = memget(sizeof *pvt))) {
    187      1.1  christos 		errno = ENOMEM;
    188      1.1  christos 		return (NULL);
    189      1.1  christos 	}
    190      1.1  christos 	memset(pvt, 0, sizeof *pvt);
    191      1.1  christos 
    192      1.1  christos 	if (!(ho = memget(sizeof *ho))) {
    193      1.1  christos 		memput(pvt, sizeof *pvt);
    194      1.1  christos 		errno = ENOMEM;
    195      1.1  christos 		return (NULL);
    196      1.1  christos 	}
    197      1.1  christos 	memset(ho, 0x5e, sizeof *ho);
    198      1.1  christos 	ho->private = pvt;
    199      1.1  christos 	ho->close = ho_close;
    200      1.1  christos 	ho->byname = ho_byname;
    201      1.1  christos 	ho->byname2 = ho_byname2;
    202      1.1  christos 	ho->byaddr = ho_byaddr;
    203      1.1  christos 	ho->next = ho_next;
    204      1.1  christos 	ho->rewind = ho_rewind;
    205      1.1  christos 	ho->minimize = ho_minimize;
    206      1.1  christos 	ho->res_get = ho_res_get;
    207      1.1  christos 	ho->res_set = ho_res_set;
    208      1.1  christos 	ho->addrinfo = ho_addrinfo;
    209      1.1  christos 	return (ho);
    210      1.1  christos }
    211      1.1  christos 
    212      1.1  christos /* Methods. */
    213      1.1  christos 
    214      1.1  christos static void
    215      1.1  christos ho_close(struct irs_ho *this) {
    216      1.1  christos 	struct pvt *pvt = (struct pvt *)this->private;
    217      1.1  christos 
    218      1.1  christos 	ho_minimize(this);
    219      1.1  christos 	if (pvt->res && pvt->free_res)
    220      1.1  christos 		(*pvt->free_res)(pvt->res);
    221      1.1  christos 	memput(pvt, sizeof *pvt);
    222      1.1  christos 	memput(this, sizeof *this);
    223      1.1  christos }
    224      1.1  christos 
    225      1.1  christos static struct hostent *
    226      1.1  christos ho_byname(struct irs_ho *this, const char *name) {
    227      1.1  christos 	struct pvt *pvt = (struct pvt *)this->private;
    228      1.1  christos 	struct hostent *hp;
    229      1.1  christos 
    230      1.1  christos 	if (init(this) == -1)
    231      1.1  christos 		return (NULL);
    232      1.1  christos 
    233      1.1  christos 	if (pvt->res->options & RES_USE_INET6) {
    234      1.1  christos 		hp = ho_byname2(this, name, AF_INET6);
    235      1.1  christos 		if (hp)
    236      1.1  christos 			return (hp);
    237      1.1  christos 	}
    238      1.1  christos 	return (ho_byname2(this, name, AF_INET));
    239      1.1  christos }
    240      1.1  christos 
    241      1.1  christos static struct hostent *
    242      1.1  christos ho_byname2(struct irs_ho *this, const char *name, int af)
    243      1.1  christos {
    244      1.1  christos 	struct pvt *pvt = (struct pvt *)this->private;
    245      1.1  christos 	struct hostent *hp = NULL;
    246      1.1  christos 	int n, size;
    247      1.1  christos 	char tmp[NS_MAXDNAME];
    248      1.1  christos 	const char *cp;
    249      1.1  christos 	struct addrinfo ai;
    250      1.1  christos 	struct dns_res_target *q, *p;
    251      1.1  christos 	int querystate = RESQRY_FAIL;
    252      1.1  christos 
    253      1.1  christos 	if (init(this) == -1)
    254      1.1  christos 		return (NULL);
    255      1.1  christos 
    256      1.1  christos 	q = memget(sizeof(*q));
    257      1.1  christos 	if (q == NULL) {
    258      1.1  christos 		RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
    259      1.1  christos 		errno = ENOMEM;
    260      1.1  christos 		goto cleanup;
    261      1.1  christos 	}
    262      1.1  christos 	memset(q, 0, sizeof(*q));
    263      1.1  christos 
    264      1.1  christos 	switch (af) {
    265      1.1  christos 	case AF_INET:
    266      1.1  christos 		size = INADDRSZ;
    267      1.1  christos 		q->qclass = C_IN;
    268      1.1  christos 		q->qtype = T_A;
    269      1.1  christos 		q->answer = q->qbuf.buf;
    270      1.1  christos 		q->anslen = sizeof(q->qbuf);
    271      1.1  christos 		q->action = RESTGT_DOALWAYS;
    272      1.1  christos 		break;
    273      1.1  christos 	case AF_INET6:
    274      1.1  christos 		size = IN6ADDRSZ;
    275      1.1  christos 		q->qclass = C_IN;
    276      1.1  christos 		q->qtype = T_AAAA;
    277      1.1  christos 		q->answer = q->qbuf.buf;
    278      1.1  christos 		q->anslen = sizeof(q->qbuf);
    279      1.1  christos 		q->action = RESTGT_DOALWAYS;
    280      1.1  christos 		break;
    281      1.1  christos 	default:
    282      1.1  christos 		RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
    283      1.1  christos 		errno = EAFNOSUPPORT;
    284      1.1  christos 		hp = NULL;
    285      1.1  christos 		goto cleanup;
    286      1.1  christos 	}
    287      1.1  christos 
    288      1.1  christos 	/*
    289      1.1  christos 	 * if there aren't any dots, it could be a user-level alias.
    290      1.1  christos 	 * this is also done in res_nquery() since we are not the only
    291      1.1  christos 	 * function that looks up host names.
    292      1.1  christos 	 */
    293      1.1  christos 	if (!strchr(name, '.') && (cp = res_hostalias(pvt->res, name,
    294      1.1  christos 						      tmp, sizeof tmp)))
    295      1.1  christos 		name = cp;
    296      1.1  christos 
    297      1.1  christos 	for (p = q; p; p = p->next) {
    298      1.1  christos 		switch(p->action) {
    299      1.1  christos 		case RESTGT_DOALWAYS:
    300      1.1  christos 			break;
    301      1.1  christos 		case RESTGT_AFTERFAILURE:
    302      1.1  christos 			if (querystate == RESQRY_SUCCESS)
    303      1.1  christos 				continue;
    304      1.1  christos 			break;
    305      1.1  christos 		case RESTGT_IGNORE:
    306      1.1  christos 			continue;
    307      1.1  christos 		}
    308      1.1  christos 
    309      1.1  christos 		if ((n = res_nsearch(pvt->res, name, p->qclass, p->qtype,
    310      1.1  christos 				     p->answer, p->anslen)) < 0) {
    311      1.1  christos 			querystate = RESQRY_FAIL;
    312      1.1  christos 			continue;
    313      1.1  christos 		}
    314      1.1  christos 
    315      1.1  christos 		memset(&ai, 0, sizeof(ai));
    316      1.1  christos 		ai.ai_family = af;
    317      1.1  christos 		if ((hp = gethostans(this, p->answer, n, name, p->qtype,
    318      1.1  christos 				     af, size, NULL,
    319      1.1  christos 				     (const struct addrinfo *)&ai)) != NULL)
    320      1.1  christos 			goto cleanup;	/*%< no more loop is necessary */
    321      1.1  christos 		querystate = RESQRY_FAIL;
    322      1.1  christos 		continue;
    323      1.1  christos 	}
    324      1.1  christos 
    325      1.1  christos  cleanup:
    326      1.1  christos 	if (q != NULL)
    327      1.1  christos 		memput(q, sizeof(*q));
    328      1.1  christos 	return(hp);
    329      1.1  christos }
    330      1.1  christos 
    331      1.1  christos static struct hostent *
    332      1.1  christos ho_byaddr(struct irs_ho *this, const void *addr, int len, int af)
    333      1.1  christos {
    334      1.1  christos 	struct pvt *pvt = (struct pvt *)this->private;
    335      1.1  christos 	const u_char *uaddr = addr;
    336      1.1  christos 	char *qp;
    337      1.1  christos 	struct hostent *hp = NULL;
    338      1.1  christos 	struct addrinfo ai;
    339      1.1  christos 	struct dns_res_target *q, *q2, *p;
    340      1.1  christos 	int n, size, i;
    341      1.1  christos 	int querystate = RESQRY_FAIL;
    342      1.1  christos 
    343      1.1  christos 	if (init(this) == -1)
    344      1.1  christos 		return (NULL);
    345      1.1  christos 
    346      1.1  christos 	q = memget(sizeof(*q));
    347      1.1  christos 	q2 = memget(sizeof(*q2));
    348      1.1  christos 	if (q == NULL || q2 == NULL) {
    349      1.1  christos 		RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
    350      1.1  christos 		errno = ENOMEM;
    351      1.1  christos 		goto cleanup;
    352      1.1  christos 	}
    353      1.1  christos 	memset(q, 0, sizeof(*q));
    354      1.1  christos 	memset(q2, 0, sizeof(*q2));
    355      1.1  christos 
    356      1.1  christos 	if (af == AF_INET6 && len == IN6ADDRSZ &&
    357      1.1  christos 	    (!memcmp(uaddr, mapped, sizeof mapped) ||
    358      1.1  christos 	   (!memcmp(uaddr, tunnelled, sizeof tunnelled) &&
    359      1.1  christos 	    memcmp(&uaddr[sizeof tunnelled], v6local, sizeof(v6local))))) {
    360      1.1  christos 		/* Unmap. */
    361      1.1  christos 		addr = (const char *)addr + sizeof mapped;
    362      1.1  christos 		uaddr += sizeof mapped;
    363      1.1  christos 		af = AF_INET;
    364      1.1  christos 		len = INADDRSZ;
    365      1.1  christos 	}
    366      1.1  christos 	switch (af) {
    367      1.1  christos 	case AF_INET:
    368      1.1  christos 		size = INADDRSZ;
    369      1.1  christos 		q->qclass = C_IN;
    370      1.1  christos 		q->qtype = T_PTR;
    371      1.1  christos 		q->answer = q->qbuf.buf;
    372      1.1  christos 		q->anslen = sizeof(q->qbuf);
    373      1.1  christos 		q->action = RESTGT_DOALWAYS;
    374      1.1  christos 		break;
    375      1.1  christos 	case AF_INET6:
    376      1.1  christos 		size = IN6ADDRSZ;
    377      1.1  christos 		q->qclass = C_IN;
    378      1.1  christos 		q->qtype = T_PTR;
    379      1.1  christos 		q->answer = q->qbuf.buf;
    380      1.1  christos 		q->anslen = sizeof(q->qbuf);
    381      1.1  christos 		q->next = q2;
    382      1.1  christos 		q->action = RESTGT_DOALWAYS;
    383      1.1  christos 		q2->qclass = C_IN;
    384      1.1  christos 		q2->qtype = T_PTR;
    385      1.1  christos 		q2->answer = q2->qbuf.buf;
    386      1.1  christos 		q2->anslen = sizeof(q2->qbuf);
    387      1.1  christos 		if ((pvt->res->options & RES_NO_NIBBLE2) != 0U)
    388      1.1  christos 			q2->action = RESTGT_IGNORE;
    389      1.1  christos 		else
    390      1.1  christos 			q2->action = RESTGT_AFTERFAILURE;
    391      1.1  christos 		break;
    392      1.1  christos 	default:
    393      1.1  christos 		errno = EAFNOSUPPORT;
    394      1.1  christos 		RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
    395      1.1  christos 		hp = NULL;
    396      1.1  christos 		goto cleanup;
    397      1.1  christos 	}
    398      1.1  christos 	if (size > len) {
    399      1.1  christos 		errno = EINVAL;
    400      1.1  christos 		RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
    401      1.1  christos 		hp = NULL;
    402      1.1  christos 		goto cleanup;
    403      1.1  christos 	}
    404      1.1  christos 	switch (af) {
    405      1.1  christos 	case AF_INET:
    406      1.1  christos 		qp = q->qname;
    407      1.1  christos 		(void) sprintf(qp, "%u.%u.%u.%u.in-addr.arpa",
    408      1.1  christos 			       (uaddr[3] & 0xff),
    409      1.1  christos 			       (uaddr[2] & 0xff),
    410      1.1  christos 			       (uaddr[1] & 0xff),
    411      1.1  christos 			       (uaddr[0] & 0xff));
    412      1.1  christos 		break;
    413      1.1  christos 	case AF_INET6:
    414      1.1  christos 		if (q->action != RESTGT_IGNORE) {
    415      1.1  christos 			const char *nibsuff = res_get_nibblesuffix(pvt->res);
    416      1.1  christos 			qp = q->qname;
    417      1.1  christos 			for (n = IN6ADDRSZ - 1; n >= 0; n--) {
    418      1.1  christos 				i = SPRINTF((qp, "%x.%x.",
    419      1.1  christos 					       uaddr[n] & 0xf,
    420      1.1  christos 					       (uaddr[n] >> 4) & 0xf));
    421      1.1  christos 				if (i != 4)
    422      1.1  christos 					abort();
    423      1.1  christos 				qp += i;
    424      1.1  christos 			}
    425      1.1  christos 			if (strlen(q->qname) + strlen(nibsuff) + 1 >
    426      1.1  christos 			    sizeof q->qname) {
    427      1.1  christos 				errno = ENAMETOOLONG;
    428      1.1  christos 				RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
    429      1.1  christos 				hp = NULL;
    430      1.1  christos 				goto cleanup;
    431      1.1  christos 			}
    432      1.1  christos 			strcpy(qp, nibsuff);	/* (checked) */
    433      1.1  christos 		}
    434      1.1  christos 		if (q2->action != RESTGT_IGNORE) {
    435      1.1  christos 			const char *nibsuff2 = res_get_nibblesuffix2(pvt->res);
    436      1.1  christos 			qp = q2->qname;
    437      1.1  christos 			for (n = IN6ADDRSZ - 1; n >= 0; n--) {
    438      1.1  christos 				i = SPRINTF((qp, "%x.%x.",
    439      1.1  christos 					       uaddr[n] & 0xf,
    440      1.1  christos 					       (uaddr[n] >> 4) & 0xf));
    441      1.1  christos 				if (i != 4)
    442      1.1  christos 					abort();
    443      1.1  christos 				qp += i;
    444      1.1  christos 			}
    445      1.1  christos 			if (strlen(q2->qname) + strlen(nibsuff2) + 1 >
    446      1.1  christos 			    sizeof q2->qname) {
    447      1.1  christos 				errno = ENAMETOOLONG;
    448      1.1  christos 				RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
    449      1.1  christos 				hp = NULL;
    450      1.1  christos 				goto cleanup;
    451      1.1  christos 			}
    452      1.1  christos 			strcpy(qp, nibsuff2);	/* (checked) */
    453      1.1  christos 		}
    454      1.1  christos 		break;
    455      1.1  christos 	default:
    456      1.1  christos 		abort();
    457      1.1  christos 	}
    458      1.1  christos 
    459      1.1  christos 	for (p = q; p; p = p->next) {
    460      1.1  christos 		switch(p->action) {
    461      1.1  christos 		case RESTGT_DOALWAYS:
    462      1.1  christos 			break;
    463      1.1  christos 		case RESTGT_AFTERFAILURE:
    464      1.1  christos 			if (querystate == RESQRY_SUCCESS)
    465      1.1  christos 				continue;
    466      1.1  christos 			break;
    467      1.1  christos 		case RESTGT_IGNORE:
    468      1.1  christos 			continue;
    469      1.1  christos 		}
    470      1.1  christos 
    471      1.1  christos 		if ((n = res_nquery(pvt->res, p->qname, p->qclass, p->qtype,
    472      1.1  christos 				    p->answer, p->anslen)) < 0) {
    473      1.1  christos 			querystate = RESQRY_FAIL;
    474      1.1  christos 			continue;
    475      1.1  christos 		}
    476      1.1  christos 
    477      1.1  christos 		memset(&ai, 0, sizeof(ai));
    478      1.1  christos 		ai.ai_family = af;
    479      1.1  christos 		hp = gethostans(this, p->answer, n, p->qname, T_PTR, af, size,
    480      1.1  christos 				NULL, (const struct addrinfo *)&ai);
    481      1.1  christos 		if (!hp) {
    482      1.1  christos 			querystate = RESQRY_FAIL;
    483      1.1  christos 			continue;
    484      1.1  christos 		}
    485      1.1  christos 
    486      1.1  christos 		memcpy(pvt->host_addr, addr, len);
    487      1.1  christos 		pvt->h_addr_ptrs[0] = (char *)pvt->host_addr;
    488      1.1  christos 		pvt->h_addr_ptrs[1] = NULL;
    489      1.1  christos 		if (af == AF_INET && (pvt->res->options & RES_USE_INET6)) {
    490      1.1  christos 			map_v4v6_address((char*)pvt->host_addr,
    491      1.1  christos 					 (char*)pvt->host_addr);
    492      1.1  christos 			pvt->host.h_addrtype = AF_INET6;
    493      1.1  christos 			pvt->host.h_length = IN6ADDRSZ;
    494      1.1  christos 		}
    495      1.1  christos 
    496      1.1  christos 		RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
    497      1.1  christos 		goto cleanup;	/*%< no more loop is necessary. */
    498      1.1  christos 	}
    499      1.1  christos 	hp = NULL; /*%< H_ERRNO was set by subroutines */
    500      1.1  christos  cleanup:
    501      1.1  christos 	if (q != NULL)
    502      1.1  christos 		memput(q, sizeof(*q));
    503      1.1  christos 	if (q2 != NULL)
    504      1.1  christos 		memput(q2, sizeof(*q2));
    505      1.1  christos 	return(hp);
    506      1.1  christos }
    507      1.1  christos 
    508      1.1  christos static struct hostent *
    509      1.1  christos ho_next(struct irs_ho *this) {
    510      1.1  christos 
    511      1.1  christos 	UNUSED(this);
    512      1.1  christos 
    513      1.1  christos 	return (NULL);
    514      1.1  christos }
    515      1.1  christos 
    516      1.1  christos static void
    517      1.1  christos ho_rewind(struct irs_ho *this) {
    518      1.1  christos 
    519      1.1  christos 	UNUSED(this);
    520      1.1  christos 
    521      1.1  christos 	/* NOOP */
    522      1.1  christos }
    523      1.1  christos 
    524      1.1  christos static void
    525      1.1  christos ho_minimize(struct irs_ho *this) {
    526      1.1  christos 	struct pvt *pvt = (struct pvt *)this->private;
    527      1.1  christos 
    528      1.1  christos 	if (pvt->res)
    529      1.1  christos 		res_nclose(pvt->res);
    530      1.1  christos }
    531      1.1  christos 
    532      1.1  christos static struct __res_state *
    533      1.1  christos ho_res_get(struct irs_ho *this) {
    534      1.1  christos 	struct pvt *pvt = (struct pvt *)this->private;
    535      1.1  christos 
    536      1.1  christos 	if (!pvt->res) {
    537      1.1  christos 		struct __res_state *res;
    538      1.1  christos 		res = (struct __res_state *)malloc(sizeof *res);
    539      1.1  christos 		if (!res) {
    540      1.1  christos 			errno = ENOMEM;
    541      1.1  christos 			return (NULL);
    542      1.1  christos 		}
    543      1.1  christos 		memset(res, 0, sizeof *res);
    544      1.1  christos 		ho_res_set(this, res, free);
    545      1.1  christos 	}
    546      1.1  christos 
    547      1.1  christos 	return (pvt->res);
    548      1.1  christos }
    549      1.1  christos 
    550      1.1  christos /* XXX */
    551      1.1  christos extern struct addrinfo *addr2addrinfo __P((const struct addrinfo *,
    552      1.1  christos 					   const char *));
    553      1.1  christos 
    554      1.1  christos static struct addrinfo *
    555      1.1  christos ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
    556      1.1  christos {
    557      1.1  christos 	struct pvt *pvt = (struct pvt *)this->private;
    558      1.1  christos 	int n;
    559      1.1  christos 	char tmp[NS_MAXDNAME];
    560      1.1  christos 	const char *cp;
    561      1.1  christos 	struct dns_res_target *q, *q2, *p;
    562      1.1  christos 	struct addrinfo sentinel, *cur;
    563      1.1  christos 	int querystate = RESQRY_FAIL;
    564      1.1  christos 
    565      1.1  christos 	if (init(this) == -1)
    566      1.1  christos 		return (NULL);
    567      1.1  christos 
    568      1.1  christos 	memset(&sentinel, 0, sizeof(sentinel));
    569      1.1  christos 	cur = &sentinel;
    570      1.1  christos 
    571      1.1  christos 	q = memget(sizeof(*q));
    572      1.1  christos 	q2 = memget(sizeof(*q2));
    573      1.1  christos 	if (q == NULL || q2 == NULL) {
    574      1.1  christos 		RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
    575      1.1  christos 		errno = ENOMEM;
    576      1.1  christos 		goto cleanup;
    577      1.1  christos 	}
    578      1.1  christos 	memset(q, 0, sizeof(*q2));
    579      1.1  christos 	memset(q2, 0, sizeof(*q2));
    580      1.1  christos 
    581      1.1  christos 	switch (pai->ai_family) {
    582      1.1  christos 	case AF_UNSPEC:
    583      1.1  christos 		/* prefer IPv6 */
    584      1.1  christos 		q->qclass = C_IN;
    585      1.1  christos 		q->qtype = T_AAAA;
    586      1.1  christos 		q->answer = q->qbuf.buf;
    587      1.1  christos 		q->anslen = sizeof(q->qbuf);
    588      1.1  christos 		q->next = q2;
    589      1.1  christos 		q->action = RESTGT_DOALWAYS;
    590      1.1  christos 		q2->qclass = C_IN;
    591      1.1  christos 		q2->qtype = T_A;
    592      1.1  christos 		q2->answer = q2->qbuf.buf;
    593      1.1  christos 		q2->anslen = sizeof(q2->qbuf);
    594      1.1  christos 		q2->action = RESTGT_DOALWAYS;
    595      1.1  christos 		break;
    596      1.1  christos 	case AF_INET:
    597      1.1  christos 		q->qclass = C_IN;
    598      1.1  christos 		q->qtype = T_A;
    599      1.1  christos 		q->answer = q->qbuf.buf;
    600      1.1  christos 		q->anslen = sizeof(q->qbuf);
    601      1.1  christos 		q->action = RESTGT_DOALWAYS;
    602      1.1  christos 		break;
    603      1.1  christos 	case AF_INET6:
    604      1.1  christos 		q->qclass = C_IN;
    605      1.1  christos 		q->qtype = T_AAAA;
    606      1.1  christos 		q->answer = q->qbuf.buf;
    607      1.1  christos 		q->anslen = sizeof(q->qbuf);
    608      1.1  christos 		q->action = RESTGT_DOALWAYS;
    609      1.1  christos 		break;
    610      1.1  christos 	default:
    611      1.1  christos 		RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /*%< better error? */
    612      1.1  christos 		goto cleanup;
    613      1.1  christos 	}
    614      1.1  christos 
    615      1.1  christos 	/*
    616      1.1  christos 	 * if there aren't any dots, it could be a user-level alias.
    617      1.1  christos 	 * this is also done in res_nquery() since we are not the only
    618      1.1  christos 	 * function that looks up host names.
    619      1.1  christos 	 */
    620      1.1  christos 	if (!strchr(name, '.') && (cp = res_hostalias(pvt->res, name,
    621      1.1  christos 						      tmp, sizeof tmp)))
    622      1.1  christos 		name = cp;
    623      1.1  christos 
    624      1.1  christos 	for (p = q; p; p = p->next) {
    625      1.1  christos 		struct addrinfo *ai;
    626      1.1  christos 
    627      1.1  christos 		switch(p->action) {
    628      1.1  christos 		case RESTGT_DOALWAYS:
    629      1.1  christos 			break;
    630      1.1  christos 		case RESTGT_AFTERFAILURE:
    631      1.1  christos 			if (querystate == RESQRY_SUCCESS)
    632      1.1  christos 				continue;
    633      1.1  christos 			break;
    634      1.1  christos 		case RESTGT_IGNORE:
    635      1.1  christos 			continue;
    636      1.1  christos 		}
    637      1.1  christos 
    638      1.1  christos 		if ((n = res_nsearch(pvt->res, name, p->qclass, p->qtype,
    639      1.1  christos 				     p->answer, p->anslen)) < 0) {
    640      1.1  christos 			querystate = RESQRY_FAIL;
    641      1.1  christos 			continue;
    642      1.1  christos 		}
    643      1.1  christos 		(void)gethostans(this, p->answer, n, name, p->qtype,
    644      1.1  christos 				 pai->ai_family, /*%< XXX: meaningless */
    645      1.1  christos 				 0, &ai, pai);
    646      1.1  christos 		if (ai) {
    647      1.1  christos 			querystate = RESQRY_SUCCESS;
    648      1.1  christos 			cur->ai_next = ai;
    649      1.1  christos 			while (cur->ai_next)
    650      1.1  christos 				cur = cur->ai_next;
    651      1.1  christos 		} else
    652      1.1  christos 			querystate = RESQRY_FAIL;
    653      1.1  christos 	}
    654      1.1  christos 
    655      1.1  christos  cleanup:
    656      1.1  christos 	if (q != NULL)
    657      1.1  christos 		memput(q, sizeof(*q));
    658      1.1  christos 	if (q2 != NULL)
    659      1.1  christos 		memput(q2, sizeof(*q2));
    660      1.1  christos 	return(sentinel.ai_next);
    661      1.1  christos }
    662      1.1  christos 
    663      1.1  christos static void
    664      1.1  christos ho_res_set(struct irs_ho *this, struct __res_state *res,
    665      1.1  christos 		void (*free_res)(void *)) {
    666      1.1  christos 	struct pvt *pvt = (struct pvt *)this->private;
    667      1.1  christos 
    668      1.1  christos 	if (pvt->res && pvt->free_res) {
    669      1.1  christos 		res_nclose(pvt->res);
    670      1.1  christos 		(*pvt->free_res)(pvt->res);
    671      1.1  christos 	}
    672      1.1  christos 
    673      1.1  christos 	pvt->res = res;
    674      1.1  christos 	pvt->free_res = free_res;
    675      1.1  christos }
    676      1.1  christos 
    677      1.1  christos /* Private. */
    678      1.1  christos 
    679      1.1  christos static struct hostent *
    680      1.1  christos gethostans(struct irs_ho *this,
    681      1.1  christos 	   const u_char *ansbuf, int anslen, const char *qname, int qtype,
    682      1.1  christos 	   int af, int size,	/*!< meaningless for addrinfo cases  */
    683      1.1  christos 	   struct addrinfo **ret_aip, const struct addrinfo *pai)
    684      1.1  christos {
    685      1.1  christos 	struct pvt *pvt = (struct pvt *)this->private;
    686      1.1  christos 	int type, class, ancount, qdcount, n, haveanswer, had_error;
    687      1.1  christos 	int error = NETDB_SUCCESS;
    688      1.1  christos 	int (*name_ok)(const char *);
    689      1.1  christos 	const HEADER *hp;
    690      1.1  christos 	const u_char *eom;
    691      1.1  christos 	const u_char *eor;
    692      1.1  christos 	const u_char *cp;
    693      1.1  christos 	const char *tname;
    694      1.1  christos 	const char *hname;
    695      1.1  christos 	char *bp, *ep, **ap, **hap;
    696      1.1  christos 	char tbuf[MAXDNAME+1];
    697      1.1  christos 	struct addrinfo sentinel, *cur, ai;
    698      1.1  christos 
    699      1.1  christos 	if (pai == NULL) abort();
    700      1.1  christos 	if (ret_aip != NULL)
    701      1.1  christos 		*ret_aip = NULL;
    702      1.1  christos 	memset(&sentinel, 0, sizeof(sentinel));
    703      1.1  christos 	cur = &sentinel;
    704      1.1  christos 
    705      1.1  christos 	tname = qname;
    706      1.1  christos 	eom = ansbuf + anslen;
    707      1.1  christos 	switch (qtype) {
    708      1.1  christos 	case T_A:
    709      1.1  christos 	case T_AAAA:
    710      1.1  christos 	case T_ANY:	/*%< use T_ANY only for T_A/T_AAAA lookup */
    711      1.1  christos 		name_ok = res_hnok;
    712      1.1  christos 		break;
    713      1.1  christos 	case T_PTR:
    714      1.1  christos 		name_ok = res_dnok;
    715      1.1  christos 		break;
    716      1.1  christos 	default:
    717      1.1  christos 		abort();
    718      1.1  christos 	}
    719      1.1  christos 
    720      1.1  christos 	pvt->host.h_addrtype = af;
    721      1.1  christos 	pvt->host.h_length = size;
    722      1.1  christos 	hname = pvt->host.h_name = NULL;
    723      1.1  christos 
    724      1.1  christos 	/*
    725      1.1  christos 	 * Find first satisfactory answer.
    726      1.1  christos 	 */
    727      1.1  christos 	if (ansbuf + HFIXEDSZ > eom) {
    728      1.1  christos 		RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
    729      1.1  christos 		return (NULL);
    730      1.1  christos 	}
    731      1.1  christos 	hp = (const HEADER *)ansbuf;
    732      1.1  christos 	ancount = ntohs(hp->ancount);
    733      1.1  christos 	qdcount = ntohs(hp->qdcount);
    734      1.1  christos 	bp = pvt->hostbuf;
    735      1.1  christos 	ep = pvt->hostbuf + sizeof(pvt->hostbuf);
    736      1.1  christos 	cp = ansbuf + HFIXEDSZ;
    737      1.1  christos 	if (qdcount != 1) {
    738      1.1  christos 		RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
    739      1.1  christos 		return (NULL);
    740      1.1  christos 	}
    741      1.1  christos 	n = dn_expand(ansbuf, eom, cp, bp, ep - bp);
    742      1.1  christos 	if (n < 0 || !maybe_ok(pvt->res, bp, name_ok)) {
    743      1.1  christos 		RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
    744      1.1  christos 		return (NULL);
    745      1.1  christos 	}
    746      1.1  christos 	cp += n + QFIXEDSZ;
    747      1.1  christos 	if (cp > eom) {
    748      1.1  christos 		RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
    749      1.1  christos 		return (NULL);
    750      1.1  christos 	}
    751      1.1  christos 	if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
    752      1.1  christos 		/* res_nsend() has already verified that the query name is the
    753      1.1  christos 		 * same as the one we sent; this just gets the expanded name
    754      1.1  christos 		 * (i.e., with the succeeding search-domain tacked on).
    755      1.1  christos 		 */
    756      1.1  christos 		n = strlen(bp) + 1;		/*%< for the \\0 */
    757      1.1  christos 		if (n > MAXHOSTNAMELEN) {
    758      1.1  christos 			RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
    759      1.1  christos 			return (NULL);
    760      1.1  christos 		}
    761      1.1  christos 		pvt->host.h_name = bp;
    762      1.1  christos 		hname = bp;
    763      1.1  christos 		bp += n;
    764      1.1  christos 		/* The qname can be abbreviated, but hname is now absolute. */
    765      1.1  christos 		qname = pvt->host.h_name;
    766      1.1  christos 	}
    767      1.1  christos 	ap = pvt->host_aliases;
    768      1.1  christos 	*ap = NULL;
    769      1.1  christos 	pvt->host.h_aliases = pvt->host_aliases;
    770      1.1  christos 	hap = pvt->h_addr_ptrs;
    771      1.1  christos 	*hap = NULL;
    772      1.1  christos 	pvt->host.h_addr_list = pvt->h_addr_ptrs;
    773      1.1  christos 	haveanswer = 0;
    774      1.1  christos 	had_error = 0;
    775      1.1  christos 	while (ancount-- > 0 && cp < eom && !had_error) {
    776      1.1  christos 		n = dn_expand(ansbuf, eom, cp, bp, ep - bp);
    777      1.1  christos 		if (n < 0 || !maybe_ok(pvt->res, bp, name_ok)) {
    778      1.1  christos 			had_error++;
    779      1.1  christos 			continue;
    780      1.1  christos 		}
    781      1.1  christos 		cp += n;			/*%< name */
    782      1.1  christos 		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
    783      1.1  christos 		type = ns_get16(cp);
    784      1.1  christos 		cp += INT16SZ;			/*%< type */
    785      1.1  christos 		class = ns_get16(cp);
    786      1.1  christos 		cp += INT16SZ + INT32SZ;	/*%< class, TTL */
    787      1.1  christos 		n = ns_get16(cp);
    788      1.1  christos 		cp += INT16SZ;			/*%< len */
    789      1.1  christos 		BOUNDS_CHECK(cp, n);
    790      1.1  christos 		if (class != C_IN) {
    791      1.1  christos 			cp += n;
    792      1.1  christos 			continue;
    793      1.1  christos 		}
    794      1.1  christos 		eor = cp + n;
    795      1.1  christos 		if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
    796      1.1  christos 		    type == T_CNAME) {
    797      1.1  christos 			if (haveanswer) {
    798      1.1  christos 				int level = LOG_CRIT;
    799      1.1  christos #ifdef LOG_SECURITY
    800      1.1  christos 				level |= LOG_SECURITY;
    801      1.1  christos #endif
    802      1.1  christos 				syslog(level,
    803      1.1  christos  "gethostans: possible attempt to exploit buffer overflow while looking up %s",
    804      1.1  christos 					*qname ? qname : ".");
    805      1.1  christos 			}
    806      1.1  christos 			n = dn_expand(ansbuf, eor, cp, tbuf, sizeof tbuf);
    807      1.1  christos 			if (n < 0 || !maybe_ok(pvt->res, tbuf, name_ok)) {
    808      1.1  christos 				had_error++;
    809      1.1  christos 				continue;
    810      1.1  christos 			}
    811      1.1  christos 			cp += n;
    812      1.1  christos 			/* Store alias. */
    813      1.1  christos 			if (ap >= &pvt->host_aliases[MAXALIASES-1])
    814      1.1  christos 				continue;
    815      1.1  christos 			*ap++ = bp;
    816      1.1  christos 			n = strlen(bp) + 1;	/*%< for the \\0 */
    817      1.1  christos 			bp += n;
    818      1.1  christos 			/* Get canonical name. */
    819      1.1  christos 			n = strlen(tbuf) + 1;	/*%< for the \\0 */
    820      1.1  christos 			if (n > (ep - bp) || n > MAXHOSTNAMELEN) {
    821      1.1  christos 				had_error++;
    822      1.1  christos 				continue;
    823      1.1  christos 			}
    824      1.1  christos 			strcpy(bp, tbuf);	/* (checked) */
    825      1.1  christos 			pvt->host.h_name = bp;
    826      1.1  christos 			hname = bp;
    827      1.1  christos 			bp += n;
    828      1.1  christos 			continue;
    829      1.1  christos 		}
    830      1.1  christos 		if (qtype == T_PTR && type == T_CNAME) {
    831      1.1  christos 			n = dn_expand(ansbuf, eor, cp, tbuf, sizeof tbuf);
    832      1.1  christos 			if (n < 0 || !maybe_dnok(pvt->res, tbuf)) {
    833      1.1  christos 				had_error++;
    834      1.1  christos 				continue;
    835      1.1  christos 			}
    836      1.1  christos 			cp += n;
    837      1.1  christos #ifdef RES_USE_DNAME
    838      1.1  christos 			if ((pvt->res->options & RES_USE_DNAME) != 0U)
    839      1.1  christos #endif
    840      1.1  christos 			{
    841      1.1  christos 				/*
    842      1.1  christos 				 * We may be able to check this regardless
    843      1.1  christos 				 * of the USE_DNAME bit, but we add the check
    844      1.1  christos 				 * for now since the DNAME support is
    845      1.1  christos 				 * experimental.
    846      1.1  christos 				 */
    847      1.1  christos 				if (ns_samename(tname, bp) != 1)
    848      1.1  christos 					continue;
    849      1.1  christos 			}
    850      1.1  christos 			/* Get canonical name. */
    851      1.1  christos 			n = strlen(tbuf) + 1;	/*%< for the \\0 */
    852      1.1  christos 			if (n > (ep - bp)) {
    853      1.1  christos 				had_error++;
    854      1.1  christos 				continue;
    855      1.1  christos 			}
    856      1.1  christos 			strcpy(bp, tbuf);	/* (checked) */
    857      1.1  christos 			tname = bp;
    858      1.1  christos 			bp += n;
    859      1.1  christos 			continue;
    860      1.1  christos 		}
    861      1.1  christos 		if (qtype == T_ANY) {
    862      1.1  christos 			if (!(type == T_A || type == T_AAAA)) {
    863      1.1  christos 				cp += n;
    864      1.1  christos 				continue;
    865      1.1  christos 			}
    866      1.1  christos 		} else if (type != qtype) {
    867      1.1  christos 			cp += n;
    868      1.1  christos 			continue;
    869      1.1  christos 		}
    870      1.1  christos 		switch (type) {
    871      1.1  christos 		case T_PTR:
    872      1.1  christos 			if (ret_aip != NULL) {
    873      1.1  christos 				/* addrinfo never needs T_PTR */
    874      1.1  christos 				cp += n;
    875      1.1  christos 				continue;
    876      1.1  christos 			}
    877      1.1  christos 			if (ns_samename(tname, bp) != 1) {
    878      1.1  christos 				cp += n;
    879      1.1  christos 				continue;
    880      1.1  christos 			}
    881      1.1  christos 			n = dn_expand(ansbuf, eor, cp, bp, ep - bp);
    882      1.1  christos 			if (n < 0 || !maybe_hnok(pvt->res, bp) ||
    883      1.1  christos 			    n >= MAXHOSTNAMELEN) {
    884      1.1  christos 				had_error++;
    885      1.1  christos 				break;
    886      1.1  christos 			}
    887      1.1  christos 			cp += n;
    888      1.1  christos 			if (!haveanswer) {
    889      1.1  christos 				pvt->host.h_name = bp;
    890      1.1  christos 				hname = bp;
    891      1.1  christos 			}
    892      1.1  christos 			else if (ap < &pvt->host_aliases[MAXALIASES-1])
    893      1.1  christos 				*ap++ = bp;
    894      1.1  christos 			else
    895      1.1  christos 				n = -1;
    896      1.1  christos 			if (n != -1) {
    897      1.1  christos 				n = strlen(bp) + 1;	/*%< for the \\0 */
    898      1.1  christos 				bp += n;
    899      1.1  christos 			}
    900      1.1  christos 			break;
    901      1.1  christos 		case T_A:
    902      1.1  christos 		case T_AAAA:
    903      1.1  christos 			if (ns_samename(hname, bp) != 1) {
    904      1.1  christos 				cp += n;
    905      1.1  christos 				continue;
    906      1.1  christos 			}
    907      1.1  christos 			if (type == T_A && n != INADDRSZ) {
    908      1.1  christos 				cp += n;
    909      1.1  christos 				continue;
    910      1.1  christos 			}
    911      1.1  christos 			if (type == T_AAAA && n != IN6ADDRSZ) {
    912      1.1  christos 				cp += n;
    913      1.1  christos 				continue;
    914      1.1  christos 			}
    915      1.1  christos 
    916      1.1  christos 			/* make addrinfo. don't overwrite constant PAI */
    917      1.1  christos 			ai = *pai;
    918      1.1  christos 			ai.ai_family = (type == T_AAAA) ? AF_INET6 : AF_INET;
    919      1.1  christos 			cur->ai_next = addr2addrinfo(
    920      1.1  christos 					(const struct addrinfo *)&ai,
    921      1.1  christos 					(const char *)cp);
    922      1.1  christos 			if (cur->ai_next == NULL)
    923      1.1  christos 				had_error++;
    924      1.1  christos 
    925      1.1  christos 			if (!haveanswer) {
    926      1.1  christos 				int nn;
    927      1.1  christos 
    928      1.1  christos 				nn = strlen(bp) + 1;	/*%< for the \\0 */
    929      1.1  christos 				if (nn >= MAXHOSTNAMELEN) {
    930      1.1  christos 					cp += n;
    931      1.1  christos 					had_error++;
    932      1.1  christos 					continue;
    933      1.1  christos 				}
    934      1.1  christos 				pvt->host.h_name = bp;
    935      1.1  christos 				hname = bp;
    936      1.1  christos 				bp += nn;
    937      1.1  christos 			}
    938      1.1  christos 			/* Ensure alignment. */
    939      1.1  christos 			bp = (char *)(((u_long)bp + (sizeof(align) - 1)) &
    940      1.1  christos 				      ~(sizeof(align) - 1));
    941      1.1  christos 			/* Avoid overflows. */
    942      1.1  christos 			if (bp + n > &pvt->hostbuf[sizeof(pvt->hostbuf) - 1]) {
    943      1.1  christos 				had_error++;
    944      1.1  christos 				continue;
    945      1.1  christos 			}
    946      1.1  christos 			if (ret_aip) { /*%< need addrinfo. keep it. */
    947      1.1  christos 				while (cur->ai_next)
    948      1.1  christos 					cur = cur->ai_next;
    949      1.1  christos 			} else if (cur->ai_next) { /*%< need hostent */
    950      1.1  christos 				struct addrinfo *aip = cur->ai_next;
    951      1.1  christos 
    952      1.1  christos 				for (aip = cur->ai_next; aip;
    953      1.1  christos 				     aip = aip->ai_next) {
    954      1.1  christos 					int m;
    955      1.1  christos 
    956      1.1  christos 					m = add_hostent(pvt, bp, hap, aip);
    957      1.1  christos 					if (m < 0) {
    958      1.1  christos 						had_error++;
    959      1.1  christos 						break;
    960      1.1  christos 					}
    961      1.1  christos 					if (m == 0)
    962      1.1  christos 						continue;
    963      1.1  christos 					if (hap < &pvt->h_addr_ptrs[MAXADDRS])
    964      1.1  christos 						hap++;
    965      1.1  christos 					*hap = NULL;
    966      1.1  christos 					bp += m;
    967      1.1  christos 				}
    968      1.1  christos 
    969      1.1  christos 				freeaddrinfo(cur->ai_next);
    970      1.1  christos 				cur->ai_next = NULL;
    971      1.1  christos 			}
    972      1.1  christos 			cp += n;
    973      1.1  christos 			break;
    974      1.1  christos 		default:
    975      1.1  christos 			abort();
    976      1.1  christos 		}
    977      1.1  christos 		if (!had_error)
    978      1.1  christos 			haveanswer++;
    979      1.1  christos 	}
    980      1.1  christos 	if (haveanswer) {
    981      1.1  christos 		if (ret_aip == NULL) {
    982      1.1  christos 			*ap = NULL;
    983      1.1  christos 			*hap = NULL;
    984      1.1  christos 
    985      1.1  christos 			if (pvt->res->nsort && hap != pvt->h_addr_ptrs &&
    986      1.1  christos 			    qtype == T_A)
    987      1.1  christos 				addrsort(pvt->res, pvt->h_addr_ptrs,
    988      1.1  christos 					 hap - pvt->h_addr_ptrs);
    989      1.1  christos 			if (pvt->host.h_name == NULL) {
    990      1.1  christos 				n = strlen(qname) + 1;	/*%< for the \\0 */
    991      1.1  christos 				if (n > (ep - bp) || n >= MAXHOSTNAMELEN)
    992      1.1  christos 					goto no_recovery;
    993      1.1  christos 				strcpy(bp, qname);	/* (checked) */
    994      1.1  christos 				pvt->host.h_name = bp;
    995      1.1  christos 				bp += n;
    996      1.1  christos 			}
    997      1.1  christos 			if (pvt->res->options & RES_USE_INET6)
    998      1.1  christos 				map_v4v6_hostent(&pvt->host, &bp, ep);
    999      1.1  christos 			RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
   1000      1.1  christos 			return (&pvt->host);
   1001      1.1  christos 		} else {
   1002      1.1  christos 			if ((pai->ai_flags & AI_CANONNAME) != 0) {
   1003      1.1  christos 				if (pvt->host.h_name == NULL) {
   1004      1.1  christos 					sentinel.ai_next->ai_canonname =
   1005      1.1  christos 						strdup(qname);
   1006      1.1  christos 				}
   1007      1.1  christos 				else {
   1008      1.1  christos 					sentinel.ai_next->ai_canonname =
   1009      1.1  christos 						strdup(pvt->host.h_name);
   1010      1.1  christos 				}
   1011      1.1  christos 			}
   1012      1.1  christos 			*ret_aip = sentinel.ai_next;
   1013      1.1  christos 			return(NULL);
   1014      1.1  christos 		}
   1015      1.1  christos 	}
   1016      1.1  christos  no_recovery:
   1017      1.1  christos 	if (sentinel.ai_next) {
   1018      1.1  christos 		/* this should be impossible, but check it for safety */
   1019      1.1  christos 		freeaddrinfo(sentinel.ai_next);
   1020      1.1  christos 	}
   1021      1.1  christos 	if (error == NETDB_SUCCESS)
   1022      1.1  christos 		RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
   1023      1.1  christos 	else
   1024      1.1  christos 		RES_SET_H_ERRNO(pvt->res, error);
   1025      1.1  christos 	return(NULL);
   1026      1.1  christos }
   1027      1.1  christos 
   1028      1.1  christos static int
   1029      1.1  christos add_hostent(struct pvt *pvt, char *bp, char **hap, struct addrinfo *ai)
   1030      1.1  christos {
   1031      1.1  christos 	int addrlen;
   1032      1.1  christos 	char *addrp;
   1033      1.1  christos 	const char **tap;
   1034      1.1  christos 	char *obp = bp;
   1035      1.1  christos 
   1036      1.1  christos 	switch(ai->ai_addr->sa_family) {
   1037      1.1  christos 	case AF_INET6:
   1038      1.1  christos 		addrlen = IN6ADDRSZ;
   1039      1.1  christos 		addrp = (char *)&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
   1040      1.1  christos 		break;
   1041      1.1  christos 	case AF_INET:
   1042      1.1  christos 		addrlen = INADDRSZ;
   1043      1.1  christos 		addrp = (char *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr;
   1044      1.1  christos 		break;
   1045      1.1  christos 	default:
   1046      1.1  christos 		return(-1);	/*%< abort? */
   1047      1.1  christos 	}
   1048      1.1  christos 
   1049      1.1  christos 	/* Ensure alignment. */
   1050      1.1  christos 	bp = (char *)(((u_long)bp + (sizeof(align) - 1)) &
   1051      1.1  christos 		      ~(sizeof(align) - 1));
   1052      1.1  christos 	/* Avoid overflows. */
   1053      1.1  christos 	if (bp + addrlen > &pvt->hostbuf[sizeof(pvt->hostbuf) - 1])
   1054      1.1  christos 		return(-1);
   1055      1.1  christos 	if (hap >= &pvt->h_addr_ptrs[MAXADDRS])
   1056      1.1  christos 		return(0); /*%< fail, but not treat it as an error. */
   1057      1.1  christos 	/* Suppress duplicates. */
   1058      1.1  christos 	for (tap = (const char **)pvt->h_addr_ptrs;
   1059      1.1  christos 	     *tap != NULL;
   1060      1.1  christos 	     tap++)
   1061      1.1  christos 		if (memcmp(*tap, addrp, addrlen) == 0)
   1062      1.1  christos 			break;
   1063      1.1  christos 	if (*tap != NULL)
   1064      1.1  christos 		return (0);
   1065      1.1  christos 
   1066      1.1  christos 	memcpy(*hap = bp, addrp, addrlen);
   1067      1.1  christos 	return((bp + addrlen) - obp);
   1068      1.1  christos }
   1069      1.1  christos 
   1070      1.1  christos static void
   1071      1.1  christos map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep) {
   1072      1.1  christos 	char **ap;
   1073      1.1  christos 
   1074      1.1  christos 	if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
   1075      1.1  christos 		return;
   1076      1.1  christos 	hp->h_addrtype = AF_INET6;
   1077      1.1  christos 	hp->h_length = IN6ADDRSZ;
   1078      1.1  christos 	for (ap = hp->h_addr_list; *ap; ap++) {
   1079      1.1  christos 		int i = (u_long)*bpp % sizeof(align);
   1080      1.1  christos 
   1081      1.1  christos 		if (i != 0)
   1082      1.1  christos 			i = sizeof(align) - i;
   1083      1.1  christos 
   1084      1.1  christos 		if ((ep - *bpp) < (i + IN6ADDRSZ)) {
   1085      1.1  christos 			/* Out of memory.  Truncate address list here. */
   1086      1.1  christos 			*ap = NULL;
   1087      1.1  christos 			return;
   1088      1.1  christos 		}
   1089      1.1  christos 		*bpp += i;
   1090      1.1  christos 		map_v4v6_address(*ap, *bpp);
   1091      1.1  christos 		*ap = *bpp;
   1092      1.1  christos 		*bpp += IN6ADDRSZ;
   1093      1.1  christos 	}
   1094      1.1  christos }
   1095      1.1  christos 
   1096      1.1  christos static void
   1097      1.1  christos addrsort(res_state statp, char **ap, int num) {
   1098      1.1  christos 	int i, j, needsort = 0, aval[MAXADDRS];
   1099      1.1  christos 	char **p;
   1100      1.1  christos 
   1101      1.1  christos 	p = ap;
   1102      1.1  christos 	for (i = 0; i < num; i++, p++) {
   1103      1.1  christos 		for (j = 0 ; (unsigned)j < statp->nsort; j++)
   1104      1.1  christos 			if (statp->sort_list[j].addr.s_addr ==
   1105      1.1  christos 			    (((struct in_addr *)(*p))->s_addr &
   1106      1.1  christos 			     statp->sort_list[j].mask))
   1107      1.1  christos 				break;
   1108      1.1  christos 		aval[i] = j;
   1109      1.1  christos 		if (needsort == 0 && i > 0 && j < aval[i-1])
   1110      1.1  christos 			needsort = i;
   1111      1.1  christos 	}
   1112      1.1  christos 	if (!needsort)
   1113      1.1  christos 		return;
   1114      1.1  christos 
   1115      1.1  christos 	while (needsort < num) {
   1116      1.1  christos 		for (j = needsort - 1; j >= 0; j--) {
   1117      1.1  christos 			if (aval[j] > aval[j+1]) {
   1118      1.1  christos 				char *hp;
   1119      1.1  christos 
   1120      1.1  christos 				i = aval[j];
   1121      1.1  christos 				aval[j] = aval[j+1];
   1122      1.1  christos 				aval[j+1] = i;
   1123      1.1  christos 
   1124      1.1  christos 				hp = ap[j];
   1125      1.1  christos 				ap[j] = ap[j+1];
   1126      1.1  christos 				ap[j+1] = hp;
   1127      1.1  christos 
   1128      1.1  christos 			} else
   1129      1.1  christos 				break;
   1130      1.1  christos 		}
   1131      1.1  christos 		needsort++;
   1132      1.1  christos 	}
   1133      1.1  christos }
   1134      1.1  christos 
   1135      1.1  christos static int
   1136      1.1  christos init(struct irs_ho *this) {
   1137      1.1  christos 	struct pvt *pvt = (struct pvt *)this->private;
   1138      1.1  christos 
   1139      1.1  christos 	if (!pvt->res && !ho_res_get(this))
   1140      1.1  christos 		return (-1);
   1141      1.1  christos 	if (((pvt->res->options & RES_INIT) == 0U) &&
   1142      1.1  christos 	    res_ninit(pvt->res) == -1)
   1143      1.1  christos 		return (-1);
   1144      1.1  christos 	return (0);
   1145      1.1  christos }
   1146