diff options
Diffstat (limited to 'REORG.TODO/resolv/res_query.c')
-rw-r--r-- | REORG.TODO/resolv/res_query.c | 649 |
1 files changed, 649 insertions, 0 deletions
diff --git a/REORG.TODO/resolv/res_query.c b/REORG.TODO/resolv/res_query.c new file mode 100644 index 0000000000..0ca3a65028 --- /dev/null +++ b/REORG.TODO/resolv/res_query.c @@ -0,0 +1,649 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include <assert.h> +#include <sys/types.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include <resolv.h> +#include <resolv/resolv-internal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <resolv/resolv-internal.h> + +/* Options. Leave them on. */ +/* #undef DEBUG */ + +#if PACKETSZ > 65536 +#define MAXPACKET PACKETSZ +#else +#define MAXPACKET 65536 +#endif + +#define QUERYSIZE (HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1) + +static int +__libc_res_nquerydomain(res_state statp, const char *name, const char *domain, + int class, int type, u_char *answer, int anslen, + u_char **answerp, u_char **answerp2, int *nanswerp2, + int *resplen2, int *answerp2_malloced); + +/* + * 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. + */ +int +__libc_res_nquery(res_state statp, + const char *name, /* domain name */ + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen, /* size of answer buffer */ + u_char **answerp, /* if buffer needs to be enlarged */ + u_char **answerp2, + int *nanswerp2, + int *resplen2, + int *answerp2_malloced) +{ + HEADER *hp = (HEADER *) answer; + HEADER *hp2; + int n, use_malloc = 0; + + size_t bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * QUERYSIZE; + u_char *buf = alloca (bufsize); + u_char *query1 = buf; + int nquery1 = -1; + u_char *query2 = NULL; + int nquery2 = 0; + + again: + hp->rcode = NOERROR; /* default */ + +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_query(%s, %d, %d)\n", name, class, type); +#endif + + if (type == T_QUERY_A_AND_AAAA) + { + n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL, + query1, bufsize); + if (n > 0) + { + if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) + { + /* Use RESOLV_EDNS_BUFFER_SIZE because the receive + buffer can be reallocated. */ + n = __res_nopt (statp, n, query1, bufsize, + RESOLV_EDNS_BUFFER_SIZE); + if (n < 0) + goto unspec_nomem; + } + + nquery1 = n; + /* Align the buffer. */ + int npad = ((nquery1 + __alignof__ (HEADER) - 1) + & ~(__alignof__ (HEADER) - 1)) - nquery1; + if (n > bufsize - npad) + { + n = -1; + goto unspec_nomem; + } + int nused = n + npad; + query2 = buf + nused; + n = res_nmkquery(statp, QUERY, name, class, T_AAAA, NULL, 0, + NULL, query2, bufsize - nused); + if (n > 0 + && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) + /* Use RESOLV_EDNS_BUFFER_SIZE because the receive + buffer can be reallocated. */ + n = __res_nopt (statp, n, query2, bufsize, + RESOLV_EDNS_BUFFER_SIZE); + nquery2 = n; + } + + unspec_nomem:; + } + else + { + n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL, + query1, bufsize); + + if (n > 0 + && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) + { + /* Use RESOLV_EDNS_BUFFER_SIZE if the receive buffer + can be reallocated. */ + size_t advertise; + if (answerp == NULL) + advertise = anslen; + else + advertise = RESOLV_EDNS_BUFFER_SIZE; + n = __res_nopt (statp, n, query1, bufsize, advertise); + } + + nquery1 = n; + } + + if (__glibc_unlikely (n <= 0) && !use_malloc) { + /* Retry just in case res_nmkquery failed because of too + short buffer. Shouldn't happen. */ + bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * MAXPACKET; + buf = malloc (bufsize); + if (buf != NULL) { + query1 = buf; + use_malloc = 1; + goto again; + } + } + if (__glibc_unlikely (n <= 0)) { +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_query: mkquery failed\n"); +#endif + RES_SET_H_ERRNO(statp, NO_RECOVERY); + if (use_malloc) + free (buf); + return (n); + } + assert (answerp == NULL || (void *) *answerp == (void *) answer); + n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer, + anslen, answerp, answerp2, nanswerp2, resplen2, + answerp2_malloced); + if (use_malloc) + free (buf); + if (n < 0) { +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_query: send error\n"); +#endif + RES_SET_H_ERRNO(statp, TRY_AGAIN); + return (n); + } + + if (answerp != NULL) + /* __libc_res_nsend might have reallocated the buffer. */ + hp = (HEADER *) *answerp; + + /* We simplify the following tests by assigning HP to HP2 or + vice versa. It is easy to verify that this is the same as + ignoring all tests of HP or HP2. */ + if (answerp2 == NULL || *resplen2 < (int) sizeof (HEADER)) + { + hp2 = hp; + } + else + { + hp2 = (HEADER *) *answerp2; + if (n < (int) sizeof (HEADER)) + { + hp = hp2; + } + } + + /* Make sure both hp and hp2 are defined */ + assert((hp != NULL) && (hp2 != NULL)); + + if ((hp->rcode != NOERROR || ntohs(hp->ancount) == 0) + && (hp2->rcode != NOERROR || ntohs(hp2->ancount) == 0)) { +#ifdef DEBUG + if (statp->options & RES_DEBUG) { + printf(";; rcode = %d, ancount=%d\n", hp->rcode, + ntohs(hp->ancount)); + if (hp != hp2) + printf(";; rcode2 = %d, ancount2=%d\n", hp2->rcode, + ntohs(hp2->ancount)); + } +#endif + switch (hp->rcode == NOERROR ? hp2->rcode : hp->rcode) { + case NXDOMAIN: + if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0) + || (hp2->rcode == NOERROR + && ntohs (hp2->ancount) != 0)) + goto success; + RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); + break; + case SERVFAIL: + RES_SET_H_ERRNO(statp, TRY_AGAIN); + break; + case NOERROR: + if (ntohs (hp->ancount) != 0 + || ntohs (hp2->ancount) != 0) + goto success; + RES_SET_H_ERRNO(statp, NO_DATA); + break; + case FORMERR: + case NOTIMP: + /* Servers must not reply to AAAA queries with + NOTIMP etc but some of them do. */ + if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0) + || (hp2->rcode == NOERROR + && ntohs (hp2->ancount) != 0)) + goto success; + /* FALLTHROUGH */ + case REFUSED: + default: + RES_SET_H_ERRNO(statp, NO_RECOVERY); + break; + } + return (-1); + } + success: + return (n); +} +libresolv_hidden_def (__libc_res_nquery) + +int +res_nquery(res_state statp, + const char *name, /* domain name */ + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen) /* size of answer buffer */ +{ + return __libc_res_nquery(statp, name, class, type, answer, anslen, + NULL, NULL, NULL, NULL, NULL); +} +libresolv_hidden_def (res_nquery) + +/* + * 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. + */ +int +__libc_res_nsearch(res_state statp, + const char *name, /* domain name */ + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen, /* size of answer */ + u_char **answerp, + u_char **answerp2, + int *nanswerp2, + int *resplen2, + int *answerp2_malloced) +{ + const char *cp, * const *domain; + HEADER *hp = (HEADER *) answer; + char tmp[NS_MAXDNAME]; + 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; + + __set_errno (0); + RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); /* True if we never query. */ + + dots = 0; + for (cp = name; *cp != '\0'; 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(statp, name, tmp, sizeof tmp))!= NULL) + return (__libc_res_nquery(statp, cp, class, type, answer, + anslen, answerp, answerp2, + nanswerp2, resplen2, answerp2_malloced)); + +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf("dots=%d, statp->ndots=%d, trailing_dot=%d, name=%s\n", + (int)dots,(int)statp->ndots,(int)trailing_dot,name); +#endif + + /* + * 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 >= statp->ndots || trailing_dot) { + ret = __libc_res_nquerydomain(statp, name, NULL, class, type, + answer, anslen, answerp, + answerp2, nanswerp2, resplen2, + answerp2_malloced); + if (ret > 0 || trailing_dot + /* If the second response is valid then we use that. */ + || (ret == 0 && resplen2 != NULL && *resplen2 > 0)) + return (ret); + saved_herrno = h_errno; + tried_as_is++; + if (answerp && *answerp != answer) { + answer = *answerp; + anslen = MAXPACKET; + } + if (answerp2 && *answerp2_malloced) + { + free (*answerp2); + *answerp2 = NULL; + *nanswerp2 = 0; + *answerp2_malloced = 0; + } + } + + /* + * 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 && (statp->options & RES_DEFNAMES) != 0) || + (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) { + int done = 0; + + for (domain = (const char * const *)statp->dnsrch; + *domain && !done; + domain++) { + const char *dname = domain[0]; + searched = 1; + + /* __libc_res_nquerydoman concatenates name + with dname with a "." in between. If we + pass it in dname the "." we got from the + configured default search path, we'll end + up with "name..", which won't resolve. + OTOH, passing it "" will result in "name.", + which has the intended effect for both + possible representations of the root + domain. */ + if (dname[0] == '.') + dname++; + if (dname[0] == '\0') + root_on_list++; + + ret = __libc_res_nquerydomain(statp, name, dname, + class, type, + answer, anslen, answerp, + answerp2, nanswerp2, + resplen2, answerp2_malloced); + if (ret > 0 || (ret == 0 && resplen2 != NULL + && *resplen2 > 0)) + return (ret); + + if (answerp && *answerp != answer) { + answer = *answerp; + anslen = MAXPACKET; + } + if (answerp2 && *answerp2_malloced) + { + free (*answerp2); + *answerp2 = NULL; + *nanswerp2 = 0; + *answerp2_malloced = 0; + } + + /* + * If no server present, give up. + * If name isn't found in this domain, + * keep trying higher domains in the search list + * (if that's enabled). + * On a NO_DATA error, keep trying, otherwise + * a wildcard entry of another type could keep us + * from finding this entry higher in the domain. + * If we get some other error (negative answer or + * server failure), then stop searching up, + * but try the input name below in case it's + * fully-qualified. + */ + if (errno == ECONNREFUSED) { + RES_SET_H_ERRNO(statp, TRY_AGAIN); + return (-1); + } + + switch (statp->res_h_errno) { + case NO_DATA: + got_nodata++; + /* FALLTHROUGH */ + case HOST_NOT_FOUND: + /* keep trying */ + break; + case TRY_AGAIN: + if (hp->rcode == SERVFAIL) { + /* try next search element, if any */ + got_servfail++; + break; + } + /* FALLTHROUGH */ + default: + /* anything else implies that we're done */ + done++; + } + + /* if we got here for some reason other than DNSRCH, + * we only wanted one iteration of the loop, so stop. + */ + if ((statp->options & RES_DNSRCH) == 0) + done++; + } + } + + /* + * If the query has not already been tried as is then try it + * unless RES_NOTLDQUERY is set and there were no dots. + */ + if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0) + && !(tried_as_is || root_on_list)) { + ret = __libc_res_nquerydomain(statp, name, NULL, class, type, + answer, anslen, answerp, + answerp2, nanswerp2, resplen2, + answerp2_malloced); + if (ret > 0 || (ret == 0 && resplen2 != NULL + && *resplen2 > 0)) + return (ret); + } + + /* if we got here, we didn't satisfy the search. + * if we did an initial full query, return that query's H_ERRNO + * (note that we wouldn't be here if that query had succeeded). + * else if we ever got a nodata, send that back as the reason. + * else send back meaningless H_ERRNO, that being the one from + * the last DNSRCH we did. + */ + if (answerp2 && *answerp2_malloced) + { + free (*answerp2); + *answerp2 = NULL; + *nanswerp2 = 0; + *answerp2_malloced = 0; + } + if (saved_herrno != -1) + RES_SET_H_ERRNO(statp, saved_herrno); + else if (got_nodata) + RES_SET_H_ERRNO(statp, NO_DATA); + else if (got_servfail) + RES_SET_H_ERRNO(statp, TRY_AGAIN); + return (-1); +} +libresolv_hidden_def (__libc_res_nsearch) + +int +res_nsearch(res_state statp, + const char *name, /* domain name */ + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen) /* size of answer */ +{ + return __libc_res_nsearch(statp, name, class, type, answer, + anslen, NULL, NULL, NULL, NULL, NULL); +} +libresolv_hidden_def (res_nsearch) + +/* + * Perform a call on res_query on the concatenation of name and domain. + */ +static int +__libc_res_nquerydomain(res_state statp, + const char *name, + const char *domain, + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen, /* size of answer */ + u_char **answerp, + u_char **answerp2, + int *nanswerp2, + int *resplen2, + int *answerp2_malloced) +{ + char nbuf[MAXDNAME]; + const char *longname = nbuf; + size_t n, d; + +#ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_nquerydomain(%s, %s, %d, %d)\n", + name, domain?domain:"<Nil>", class, type); +#endif + if (domain == NULL) { + n = strlen(name); + + /* Decrement N prior to checking it against MAXDNAME + so that we detect a wrap to SIZE_MAX and return + a reasonable error. */ + n--; + if (n >= MAXDNAME - 1) { + RES_SET_H_ERRNO(statp, NO_RECOVERY); + return (-1); + } + longname = name; + } else { + n = strlen(name); + d = strlen(domain); + if (n + d + 1 >= MAXDNAME) { + RES_SET_H_ERRNO(statp, NO_RECOVERY); + return (-1); + } + sprintf(nbuf, "%s.%s", name, domain); + } + return (__libc_res_nquery(statp, longname, class, type, answer, + anslen, answerp, answerp2, nanswerp2, + resplen2, answerp2_malloced)); +} + +int +res_nquerydomain(res_state statp, + const char *name, + const char *domain, + int class, int type, /* class and type of query */ + u_char *answer, /* buffer to put answer */ + int anslen) /* size of answer */ +{ + return __libc_res_nquerydomain(statp, name, domain, class, type, + answer, anslen, NULL, NULL, NULL, NULL, + NULL); +} +libresolv_hidden_def (res_nquerydomain) + +const char * +res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) { + char *file, *cp1, *cp2; + char buf[BUFSIZ]; + FILE *fp; + + if (statp->options & RES_NOALIASES) + return (NULL); + file = getenv("HOSTALIASES"); + if (file == NULL || (fp = fopen(file, "rce")) == NULL) + return (NULL); + setbuf(fp, NULL); + buf[sizeof(buf) - 1] = '\0'; + while (fgets(buf, sizeof(buf), fp)) { + for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1) + ; + if (!*cp1) + break; + *cp1 = '\0'; + if (ns_samename(buf, name) == 1) { + while (isspace(*++cp1)) + ; + if (!*cp1) + break; + for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2) + ; + *cp2 = '\0'; + strncpy(dst, cp1, siz - 1); + dst[siz - 1] = '\0'; + fclose(fp); + return (dst); + } + } + fclose(fp); + return (NULL); +} +libresolv_hidden_def (res_hostalias) |