From owner-p4-projects@FreeBSD.ORG Sat Jun 17 14:34:51 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id BA9AE16A47A; Sat, 17 Jun 2006 14:34:51 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 96EB116A474 for ; Sat, 17 Jun 2006 14:34:51 +0000 (UTC) (envelope-from bushman@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 4CFAF43D46 for ; Sat, 17 Jun 2006 14:34:51 +0000 (GMT) (envelope-from bushman@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id k5HEYpdM053747 for ; Sat, 17 Jun 2006 14:34:51 GMT (envelope-from bushman@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id k5HEYox8053744 for perforce@freebsd.org; Sat, 17 Jun 2006 14:34:50 GMT (envelope-from bushman@freebsd.org) Date: Sat, 17 Jun 2006 14:34:50 GMT Message-Id: <200606171434.k5HEYox8053744@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to bushman@freebsd.org using -f From: Michael Bushkov To: Perforce Change Reviews Cc: Subject: PERFORCE change 99427 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 17 Jun 2006 14:34:52 -0000 http://perforce.freebsd.org/chv.cgi?CH=99427 Change 99427 by bushman@bushman_nss_ldap_cached on 2006/06/17 14:34:21 changes in the resolver-related parts that allow painless code migration from libc to nss-modules Affected files ... .. //depot/projects/soc2006/nss_ldap_cached/src/lib/libc/net/getaddrinfo.c#2 edit .. //depot/projects/soc2006/nss_ldap_cached/src/lib/libc/net/gethostnamadr.c#3 edit .. //depot/projects/soc2006/nss_ldap_cached/src/lib/libc/net/name6.c#2 edit .. //depot/projects/soc2006/nss_ldap_cached/src/lib/libc/net/netdb_private.h#3 edit Differences ... ==== //depot/projects/soc2006/nss_ldap_cached/src/lib/libc/net/getaddrinfo.c#2 (text+ko) ==== @@ -93,11 +93,11 @@ #include #include -#include "res_config.h" +//#include "res_config.h" -#ifdef DEBUG -#include -#endif +//#ifdef DEBUG +//#include +//#endif #include #include @@ -127,14 +127,6 @@ }; #endif -struct policyqueue { - TAILQ_ENTRY(policyqueue) pc_entry; -#ifdef INET6 - struct in6_addrpolicy pc_policy; -#endif -}; -TAILQ_HEAD(policyhead, policyqueue); - static const struct afd { int a_af; int a_addrlen; @@ -161,6 +153,14 @@ {0, 0, 0, 0, NULL, NULL, 0}, }; +struct policyqueue { + TAILQ_ENTRY(policyqueue) pc_entry; +#ifdef INET6 + struct in6_addrpolicy pc_policy; +#endif +}; +TAILQ_HEAD(policyhead, policyqueue); + struct explore { int e_af; int e_socktype; @@ -219,22 +219,6 @@ { 0 } }; -struct res_target { - struct res_target *next; - const char *name; /* domain name */ - int qclass, qtype; /* class and type of query */ - u_char *answer; /* buffer to put answer */ - int anslen; /* size of answer buffer */ - int n; /* result length */ -}; - -#define MAXPACKET (64*1024) - -typedef union { - HEADER hdr; - u_char buf[MAXPACKET]; -} querybuf; - static int str2number(const char *); static int explore_null(const struct addrinfo *, const char *, struct addrinfo **); @@ -267,7 +251,7 @@ struct policyhead *); static int matchlen(struct sockaddr *, struct sockaddr *); -static struct addrinfo *getanswer(const querybuf *, int, const char *, int, +/*static struct addrinfo *getanswer(const querybuf *, int, const char *, int, const struct addrinfo *, res_state); #if defined(RESOLVSORT) static int addr4sort(struct addrinfo *, res_state); @@ -281,17 +265,17 @@ #ifdef YP static struct addrinfo *_yphostent(char *, const struct addrinfo *); static int _yp_getaddrinfo(void *, void *, va_list); -#endif +#endif*/ #ifdef NS_CACHING static int addrinfo_id_func(char *, size_t *, va_list, void *); static int addrinfo_marshal_func(char *, size_t *, void *, va_list, void *); static int addrinfo_unmarshal_func(char *, size_t, void *, va_list, void *); #endif -static int res_queryN(const char *, struct res_target *, res_state); +/*static int res_queryN(const char *, struct res_target *, res_state); static int res_searchN(const char *, struct res_target *, res_state); static int res_querydomainN(const char *, const char *, - struct res_target *, res_state); + struct res_target *, res_state);*/ /* XXX macros that make external reference is BAD. */ @@ -1730,9 +1714,6 @@ addrinfo_unmarshal_func); #endif static const ns_dtab dtab[] = { - NS_FILES_CB(_files_getaddrinfo, NULL) - { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ - NS_NIS_CB(_yp_getaddrinfo, NULL) #ifdef NS_CACHING NS_CACHE_CB(&cache_info) #endif @@ -1776,997 +1757,3 @@ freeaddrinfo(result); return error; } - -#ifdef DEBUG -static const char AskedForGot[] = - "gethostby*.getanswer: asked for \"%s\", got \"%s\""; -#endif - -static struct addrinfo * -getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, - const struct addrinfo *pai, res_state res) -{ - struct addrinfo sentinel, *cur; - struct addrinfo ai; - const struct afd *afd; - char *canonname; - const HEADER *hp; - const u_char *cp; - int n; - const u_char *eom; - char *bp, *ep; - int type, class, ancount, qdcount; - int haveanswer, had_error; - char tbuf[MAXDNAME]; - int (*name_ok)(const char *); - char hostbuf[8*1024]; - - memset(&sentinel, 0, sizeof(sentinel)); - cur = &sentinel; - - canonname = NULL; - eom = answer->buf + anslen; - switch (qtype) { - case T_A: - case T_AAAA: - case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ - name_ok = res_hnok; - break; - default: - return (NULL); /* XXX should be abort(); */ - } - /* - * find first satisfactory answer - */ - hp = &answer->hdr; - ancount = ntohs(hp->ancount); - qdcount = ntohs(hp->qdcount); - bp = hostbuf; - ep = hostbuf + sizeof hostbuf; - cp = answer->buf + HFIXEDSZ; - if (qdcount != 1) { - RES_SET_H_ERRNO(res, NO_RECOVERY); - return (NULL); - } - n = dn_expand(answer->buf, eom, cp, bp, ep - bp); - if ((n < 0) || !(*name_ok)(bp)) { - RES_SET_H_ERRNO(res, NO_RECOVERY); - return (NULL); - } - cp += n + QFIXEDSZ; - if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { - /* res_send() has already verified that the query name is the - * same as the one we sent; this just gets the expanded name - * (i.e., with the succeeding search-domain tacked on). - */ - n = strlen(bp) + 1; /* for the \0 */ - if (n >= MAXHOSTNAMELEN) { - RES_SET_H_ERRNO(res, NO_RECOVERY); - return (NULL); - } - canonname = bp; - bp += n; - /* The qname can be abbreviated, but h_name is now absolute. */ - qname = canonname; - } - haveanswer = 0; - had_error = 0; - while (ancount-- > 0 && cp < eom && !had_error) { - n = dn_expand(answer->buf, eom, cp, bp, ep - bp); - if ((n < 0) || !(*name_ok)(bp)) { - had_error++; - continue; - } - cp += n; /* name */ - type = _getshort(cp); - cp += INT16SZ; /* type */ - class = _getshort(cp); - cp += INT16SZ + INT32SZ; /* class, TTL */ - n = _getshort(cp); - cp += INT16SZ; /* len */ - if (class != C_IN) { - /* XXX - debug? syslog? */ - cp += n; - continue; /* XXX - had_error++ ? */ - } - if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && - type == T_CNAME) { - n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); - if ((n < 0) || !(*name_ok)(tbuf)) { - had_error++; - continue; - } - cp += n; - /* Get canonical name. */ - n = strlen(tbuf) + 1; /* for the \0 */ - if (n > ep - bp || n >= MAXHOSTNAMELEN) { - had_error++; - continue; - } - strlcpy(bp, tbuf, ep - bp); - canonname = bp; - bp += n; - continue; - } - if (qtype == T_ANY) { - if (!(type == T_A || type == T_AAAA)) { - cp += n; - continue; - } - } else if (type != qtype) { -#ifdef DEBUG - if (type != T_KEY && type != T_SIG) - syslog(LOG_NOTICE|LOG_AUTH, - "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", - qname, p_class(C_IN), p_type(qtype), - p_type(type)); -#endif - cp += n; - continue; /* XXX - had_error++ ? */ - } - switch (type) { - case T_A: - case T_AAAA: - if (strcasecmp(canonname, bp) != 0) { -#ifdef DEBUG - syslog(LOG_NOTICE|LOG_AUTH, - AskedForGot, canonname, bp); -#endif - cp += n; - continue; /* XXX - had_error++ ? */ - } - if (type == T_A && n != INADDRSZ) { - cp += n; - continue; - } - if (type == T_AAAA && n != IN6ADDRSZ) { - cp += n; - continue; - } -#ifdef FILTER_V4MAPPED - if (type == T_AAAA) { - struct in6_addr in6; - memcpy(&in6, cp, sizeof(in6)); - if (IN6_IS_ADDR_V4MAPPED(&in6)) { - cp += n; - continue; - } - } -#endif - if (!haveanswer) { - int nn; - - canonname = bp; - nn = strlen(bp) + 1; /* for the \0 */ - bp += nn; - } - - /* don't overwrite pai */ - ai = *pai; - ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; - afd = find_afd(ai.ai_family); - if (afd == NULL) { - cp += n; - continue; - } - cur->ai_next = get_ai(&ai, afd, (const char *)cp); - if (cur->ai_next == NULL) - had_error++; - while (cur && cur->ai_next) - cur = cur->ai_next; - cp += n; - break; - default: - abort(); - } - if (!had_error) - haveanswer++; - } - if (haveanswer) { -#if defined(RESOLVSORT) - /* - * We support only IPv4 address for backward - * compatibility against gethostbyname(3). - */ - if (res->nsort && qtype == T_A) { - if (addr4sort(&sentinel, res) < 0) { - freeaddrinfo(sentinel.ai_next); - RES_SET_H_ERRNO(res, NO_RECOVERY); - return NULL; - } - } -#endif /*RESOLVSORT*/ - if (!canonname) - (void)get_canonname(pai, sentinel.ai_next, qname); - else - (void)get_canonname(pai, sentinel.ai_next, canonname); - RES_SET_H_ERRNO(res, NETDB_SUCCESS); - return sentinel.ai_next; - } - - RES_SET_H_ERRNO(res, NO_RECOVERY); - return NULL; -} - -#ifdef RESOLVSORT -struct addr_ptr { - struct addrinfo *ai; - int aval; -}; - -static int -addr4sort(struct addrinfo *sentinel, res_state res) -{ - struct addrinfo *ai; - struct addr_ptr *addrs, addr; - struct sockaddr_in *sin; - int naddrs, i, j; - int needsort = 0; - - if (!sentinel) - return -1; - naddrs = 0; - for (ai = sentinel->ai_next; ai; ai = ai->ai_next) - naddrs++; - if (naddrs < 2) - return 0; /* We don't need sorting. */ - if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL) - return -1; - i = 0; - for (ai = sentinel->ai_next; ai; ai = ai->ai_next) { - sin = (struct sockaddr_in *)ai->ai_addr; - for (j = 0; (unsigned)j < res->nsort; j++) { - if (res->sort_list[j].addr.s_addr == - (sin->sin_addr.s_addr & res->sort_list[j].mask)) - break; - } - addrs[i].ai = ai; - addrs[i].aval = j; - if (needsort == 0 && i > 0 && j < addrs[i - 1].aval) - needsort = i; - i++; - } - if (!needsort) { - free(addrs); - return 0; - } - - while (needsort < naddrs) { - for (j = needsort - 1; j >= 0; j--) { - if (addrs[j].aval > addrs[j+1].aval) { - addr = addrs[j]; - addrs[j] = addrs[j + 1]; - addrs[j + 1] = addr; - } else - break; - } - needsort++; - } - - ai = sentinel; - for (i = 0; i < naddrs; ++i) { - ai->ai_next = addrs[i].ai; - ai = ai->ai_next; - } - ai->ai_next = NULL; - free(addrs); - return 0; -} -#endif /*RESOLVSORT*/ - -/*ARGSUSED*/ -static int -_dns_getaddrinfo(void *rv, void *cb_data, va_list ap) -{ - struct addrinfo *ai; - querybuf *buf, *buf2; - const char *hostname; - const struct addrinfo *pai; - struct addrinfo sentinel, *cur; - struct res_target q, q2; - res_state res; - - hostname = va_arg(ap, char *); - pai = va_arg(ap, const struct addrinfo *); - - memset(&q, 0, sizeof(q)); - memset(&q2, 0, sizeof(q2)); - memset(&sentinel, 0, sizeof(sentinel)); - cur = &sentinel; - - buf = malloc(sizeof(*buf)); - if (!buf) { - RES_SET_H_ERRNO(res, NETDB_INTERNAL); - return NS_NOTFOUND; - } - buf2 = malloc(sizeof(*buf2)); - if (!buf2) { - free(buf); - RES_SET_H_ERRNO(res, NETDB_INTERNAL); - return NS_NOTFOUND; - } - - switch (pai->ai_family) { - case AF_UNSPEC: - q.name = hostname; - q.qclass = C_IN; - q.qtype = T_A; - q.answer = buf->buf; - q.anslen = sizeof(buf->buf); - q.next = &q2; - q2.name = hostname; - q2.qclass = C_IN; - q2.qtype = T_AAAA; - q2.answer = buf2->buf; - q2.anslen = sizeof(buf2->buf); - break; - case AF_INET: - q.name = hostname; - q.qclass = C_IN; - q.qtype = T_A; - q.answer = buf->buf; - q.anslen = sizeof(buf->buf); - break; - case AF_INET6: - q.name = hostname; - q.qclass = C_IN; - q.qtype = T_AAAA; - q.answer = buf->buf; - q.anslen = sizeof(buf->buf); - break; - default: - free(buf); - free(buf2); - return NS_UNAVAIL; - } - - res = __res_state(); - if ((res->options & RES_INIT) == 0 && res_ninit(res) == -1) { - RES_SET_H_ERRNO(res, NETDB_INTERNAL); - free(buf); - free(buf2); - return NS_NOTFOUND; - } - - if (res_searchN(hostname, &q, res) < 0) { - free(buf); - free(buf2); - return NS_NOTFOUND; - } - /* prefer IPv6 */ - if (q.next) { - ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai, res); - if (ai) { - cur->ai_next = ai; - while (cur && cur->ai_next) - cur = cur->ai_next; - } - } - ai = getanswer(buf, q.n, q.name, q.qtype, pai, res); - if (ai) - cur->ai_next = ai; - free(buf); - free(buf2); - if (sentinel.ai_next == NULL) - switch (res->res_h_errno) { - case HOST_NOT_FOUND: - return NS_NOTFOUND; - case TRY_AGAIN: - return NS_TRYAGAIN; - default: - return NS_UNAVAIL; - } - *((struct addrinfo **)rv) = sentinel.ai_next; - return NS_SUCCESS; -} - -static void -_sethtent(FILE **hostf) -{ - if (!*hostf) - *hostf = fopen(_PATH_HOSTS, "r"); - else - rewind(*hostf); -} - -static void -_endhtent(FILE **hostf) -{ - if (*hostf) { - (void) fclose(*hostf); - *hostf = NULL; - } -} - -static struct addrinfo * -_gethtent(FILE **hostf, const char *name, const struct addrinfo *pai) -{ - char *p; - char *cp, *tname, *cname; - struct addrinfo hints, *res0, *res; - int error; - const char *addr; - char hostbuf[8*1024]; - - if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "r"))) - return (NULL); -again: - if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf))) - return (NULL); - if (*p == '#') - goto again; - cp = strpbrk(p, "#\n"); - if (cp != NULL) - *cp = '\0'; - if (!(cp = strpbrk(p, " \t"))) - goto again; - *cp++ = '\0'; - addr = p; - cname = NULL; - /* if this is not something we're looking for, skip it. */ - while (cp && *cp) { - if (*cp == ' ' || *cp == '\t') { - cp++; - continue; - } - tname = cp; - if (cname == NULL) - cname = cp; - if ((cp = strpbrk(cp, " \t")) != NULL) - *cp++ = '\0'; - if (strcasecmp(name, tname) == 0) - goto found; - } - goto again; - -found: - /* we should not glob socktype/protocol here */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = pai->ai_family; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = 0; - hints.ai_flags = AI_NUMERICHOST; - error = getaddrinfo(addr, "0", &hints, &res0); - if (error) - goto again; -#ifdef FILTER_V4MAPPED - /* XXX should check all items in the chain */ - if (res0->ai_family == AF_INET6 && - IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) { - freeaddrinfo(res0); - goto again; - } -#endif - for (res = res0; res; res = res->ai_next) { - /* cover it up */ - res->ai_flags = pai->ai_flags; - res->ai_socktype = pai->ai_socktype; - res->ai_protocol = pai->ai_protocol; - - if (pai->ai_flags & AI_CANONNAME) { - if (get_canonname(pai, res, cname) != 0) { - freeaddrinfo(res0); - goto again; - } - } - } - return res0; -} - -/*ARGSUSED*/ -static int -_files_getaddrinfo(void *rv, void *cb_data, va_list ap) -{ - const char *name; - const struct addrinfo *pai; - struct addrinfo sentinel, *cur; - struct addrinfo *p; - FILE *hostf = NULL; - - name = va_arg(ap, char *); - pai = va_arg(ap, struct addrinfo *); - - memset(&sentinel, 0, sizeof(sentinel)); - cur = &sentinel; - - _sethtent(&hostf); - while ((p = _gethtent(&hostf, name, pai)) != NULL) { - cur->ai_next = p; - while (cur && cur->ai_next) - cur = cur->ai_next; - } - _endhtent(&hostf); - - *((struct addrinfo **)rv) = sentinel.ai_next; - if (sentinel.ai_next == NULL) - return NS_NOTFOUND; - return NS_SUCCESS; -} - -#ifdef YP -/*ARGSUSED*/ -static struct addrinfo * -_yphostent(char *line, const struct addrinfo *pai) -{ - struct addrinfo sentinel, *cur; - struct addrinfo hints, *res, *res0; - int error; - char *p = line; - const char *addr, *canonname; - char *nextline; - char *cp; - - addr = canonname = NULL; - - memset(&sentinel, 0, sizeof(sentinel)); - cur = &sentinel; - -nextline: - /* terminate line */ - cp = strchr(p, '\n'); - if (cp) { - *cp++ = '\0'; - nextline = cp; - } else - nextline = NULL; - - cp = strpbrk(p, " \t"); - if (cp == NULL) { - if (canonname == NULL) - return (NULL); - else - goto done; - } - *cp++ = '\0'; - - addr = p; - - while (cp && *cp) { - if (*cp == ' ' || *cp == '\t') { - cp++; - continue; - } - if (!canonname) - canonname = cp; - if ((cp = strpbrk(cp, " \t")) != NULL) - *cp++ = '\0'; - } - - hints = *pai; - hints.ai_flags = AI_NUMERICHOST; - error = getaddrinfo(addr, NULL, &hints, &res0); - if (error == 0) { - for (res = res0; res; res = res->ai_next) { - /* cover it up */ - res->ai_flags = pai->ai_flags; - - if (pai->ai_flags & AI_CANONNAME) - (void)get_canonname(pai, res, canonname); - } - } else - res0 = NULL; - if (res0) { - cur->ai_next = res0; - while (cur && cur->ai_next) - cur = cur->ai_next; - } - - if (nextline) { - p = nextline; - goto nextline; - } - -done: - return sentinel.ai_next; -} - -/*ARGSUSED*/ -static int -_yp_getaddrinfo(void *rv, void *cb_data, va_list ap) -{ - struct addrinfo sentinel, *cur; - struct addrinfo *ai = NULL; - char *ypbuf; - int ypbuflen, r; - const char *name; - const struct addrinfo *pai; - char *ypdomain; - - if (_yp_check(&ypdomain) == 0) - return NS_UNAVAIL; - - name = va_arg(ap, char *); - pai = va_arg(ap, const struct addrinfo *); - - memset(&sentinel, 0, sizeof(sentinel)); - cur = &sentinel; - - /* hosts.byname is only for IPv4 (Solaris8) */ - if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { - r = yp_match(ypdomain, "hosts.byname", name, - (int)strlen(name), &ypbuf, &ypbuflen); - if (r == 0) { - struct addrinfo ai4; - - ai4 = *pai; - ai4.ai_family = AF_INET; - ai = _yphostent(ypbuf, &ai4); - if (ai) { - cur->ai_next = ai; - while (cur && cur->ai_next) - cur = cur->ai_next; - } - free(ypbuf); - } - } - - /* ipnodes.byname can hold both IPv4/v6 */ - r = yp_match(ypdomain, "ipnodes.byname", name, - (int)strlen(name), &ypbuf, &ypbuflen); - if (r == 0) { - ai = _yphostent(ypbuf, pai); - if (ai) - cur->ai_next = ai; - free(ypbuf); - } - - if (sentinel.ai_next == NULL) { - RES_SET_H_ERRNO(__res_state(), HOST_NOT_FOUND); - return NS_NOTFOUND; - } - *((struct addrinfo **)rv) = sentinel.ai_next; - return NS_SUCCESS; -} -#endif - -/* resolver logic */ - -/* - * Formulate a normal query, send, and await answer. - * Returned answer is placed in supplied buffer "answer". - * Perform preliminary check of answer, returning success only - * if no error is indicated and the answer count is nonzero. - * Return the size of the response on success, -1 on error. - * Error number is left in h_errno. - * - * Caller must parse answer and determine whether it answers the question. - */ -static int -res_queryN(const char *name, struct res_target *target, res_state res) -{ - u_char *buf; - HEADER *hp; - int n; - u_int oflags; - struct res_target *t; - int rcode; - int ancount; - - rcode = NOERROR; - ancount = 0; - - buf = malloc(MAXPACKET); - if (!buf) { - RES_SET_H_ERRNO(res, NETDB_INTERNAL); - return -1; - } - - for (t = target; t; t = t->next) { - int class, type; - u_char *answer; - int anslen; - - hp = (HEADER *)(void *)t->answer; - - /* make it easier... */ - class = t->qclass; - type = t->qtype; - answer = t->answer; - anslen = t->anslen; - - oflags = res->_flags; - -again: - hp->rcode = NOERROR; /* default */ - -#ifdef DEBUG - if (res->options & RES_DEBUG) - printf(";; res_query(%s, %d, %d)\n", name, class, type); -#endif - - n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL, - buf, MAXPACKET); - if (n > 0 && (res->_flags & RES_F_EDNS0ERR) == 0 && - (res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U) - n = res_nopt(res, n, buf, MAXPACKET, anslen); - if (n <= 0) { -#ifdef DEBUG - if (res->options & RES_DEBUG) - printf(";; res_query: mkquery failed\n"); -#endif - free(buf); - RES_SET_H_ERRNO(res, NO_RECOVERY); - return (n); - } - n = res_nsend(res, buf, n, answer, anslen); - if (n < 0) { - /* - * if the query choked with EDNS0, retry - * without EDNS0 - */ - if ((res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) - != 0U && - ((oflags ^ res->_flags) & RES_F_EDNS0ERR) != 0) { - res->_flags |= RES_F_EDNS0ERR; - if (res->options & RES_DEBUG) - printf(";; res_nquery: retry without EDNS0\n"); - goto again; - } - rcode = hp->rcode; /* record most recent error */ -#ifdef DEBUG - if (res->options & RES_DEBUG) - printf(";; res_query: send error\n"); -#endif - continue; - } - - if (n > anslen) - hp->rcode = FORMERR; /* XXX not very informative */ - if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { - rcode = hp->rcode; /* record most recent error */ -#ifdef DEBUG - if (res->options & RES_DEBUG) - printf(";; rcode = %u, ancount=%u\n", hp->rcode, - ntohs(hp->ancount)); -#endif - continue; - } - - ancount += ntohs(hp->ancount); - - t->n = n; - } - - free(buf); - - if (ancount == 0) { - switch (rcode) { - case NXDOMAIN: - RES_SET_H_ERRNO(res, HOST_NOT_FOUND); - break; - case SERVFAIL: - RES_SET_H_ERRNO(res, TRY_AGAIN); - break; - case NOERROR: - RES_SET_H_ERRNO(res, NO_DATA); - break; - case FORMERR: - case NOTIMP: - case REFUSED: - default: - RES_SET_H_ERRNO(res, NO_RECOVERY); - break; - } - return (-1); - } - return (ancount); -} - -/* - * Formulate a normal query, send, and retrieve answer in supplied buffer. - * Return the size of the response on success, -1 on error. - * If enabled, implement search rules until answer or unrecoverable failure - * is detected. Error code, if any, is left in h_errno. - */ -static int -res_searchN(const char *name, struct res_target *target, res_state res) -{ - const char *cp, * const *domain; - HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/ - u_int dots; - int trailing_dot, ret, saved_herrno; - int got_nodata = 0, got_servfail = 0, root_on_list = 0; - int tried_as_is = 0; - int searched = 0; - char abuf[MAXDNAME]; - - errno = 0; - RES_SET_H_ERRNO(res, HOST_NOT_FOUND); /* default, if we never query */ - dots = 0; - for (cp = name; *cp; cp++) - dots += (*cp == '.'); - trailing_dot = 0; - if (cp > name && *--cp == '.') - trailing_dot++; - - /* - * if there aren't any dots, it could be a user-level alias - */ - if (!dots && - (cp = res_hostalias(res, name, abuf, sizeof(abuf))) != NULL) - return (res_queryN(cp, target, res)); - - /* - * If there are enough dots in the name, let's just give it a - * try 'as is'. The threshold can be set with the "ndots" option. - * Also, query 'as is', if there is a trailing dot in the name. - */ - saved_herrno = -1; - if (dots >= res->ndots || trailing_dot) { - ret = res_querydomainN(name, NULL, target, res); - if (ret > 0 || trailing_dot) - return (ret); - if (errno == ECONNREFUSED) { - RES_SET_H_ERRNO(res, TRY_AGAIN); - return (-1); - } - switch (res->res_h_errno) { - case NO_DATA: - case HOST_NOT_FOUND: - break; - case TRY_AGAIN: - if (hp->rcode == SERVFAIL) - break; - /* FALLTHROUGH */ - default: - return (-1); - } - saved_herrno = res->res_h_errno; - tried_as_is++; - } - - /* - * We do at least one level of search if - * - there is no dot and RES_DEFNAME is set, or - * - there is at least one dot, there is no trailing dot, - * and RES_DNSRCH is set. - */ - if ((!dots && (res->options & RES_DEFNAMES)) || - (dots && !trailing_dot && (res->options & RES_DNSRCH))) { - int done = 0; - - for (domain = (const char * const *)res->dnsrch; - *domain && !done; - domain++) { - searched = 1; - - if (domain[0][0] == '\0' || - (domain[0][0] == '.' && domain[0][1] == '\0')) - root_on_list++; - - if (root_on_list && tried_as_is) - continue; - - ret = res_querydomainN(name, *domain, target, res); - if (ret > 0) - return (ret); - - /* - * If no server present, give up. - * If name isn't found in this domain, - * keep trying higher domains in the search list - * (if that's enabled). - * On a NO_DATA error, keep trying, otherwise - * a wildcard entry of another type could keep us >>> TRUNCATED FOR MAIL (1000 lines) <<<