diff options
Diffstat (limited to 'resolv/res_query.c')
-rw-r--r-- | resolv/res_query.c | 149 |
1 files changed, 114 insertions, 35 deletions
diff --git a/resolv/res_query.c b/resolv/res_query.c index 4371af5b05..a8e8d7b739 100644 --- a/resolv/res_query.c +++ b/resolv/res_query.c @@ -97,7 +97,7 @@ static const char rcsid[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vix 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 **answerp, u_char **answerp2, int *nanswerp2); /* * Formulate a normal query, send, and await answer. @@ -115,15 +115,20 @@ __libc_res_nquery(res_state statp, 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 **answerp, /* if buffer needs to be enlarged */ + u_char **answerp2, + int *nanswerp2) { - u_char *buf; HEADER *hp = (HEADER *) answer; int n, use_malloc = 0; u_int oflags = statp->_flags; - size_t bufsize = QUERYSIZE; - buf = alloca (bufsize); + size_t bufsize = (type == T_UNSPEC ? 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 */ @@ -133,18 +138,47 @@ __libc_res_nquery(res_state statp, printf(";; res_query(%s, %d, %d)\n", name, class, type); #endif - n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL, - buf, bufsize); - if (n > 0 - && (oflags & RES_F_EDNS0ERR) == 0 - && (statp->options & RES_USE_EDNS0) != 0) - n = __res_nopt(statp, n, buf, bufsize, anslen); + if (type == T_UNSPEC) + { + n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL, + query1, bufsize); + if (n > 0) + { + if ((oflags & RES_F_EDNS0ERR) == 0 + && (statp->options & RES_USE_EDNS0) != 0) + n = __res_nopt(statp, n, query1, bufsize, anslen / 2); + + nquery1 = n; + query2 = buf + nquery1; + n = res_nmkquery(statp, QUERY, name, class, T_AAAA, NULL, 0, + NULL, query2, bufsize - n); + if (n > 0 + && (oflags & RES_F_EDNS0ERR) == 0 + && (statp->options & RES_USE_EDNS0) != 0) + n = __res_nopt(statp, n, query2, bufsize - n, anslen / 2); + nquery2 = n; + } + } + else + { + n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL, + query1, bufsize); + + if (n > 0 + && (oflags & RES_F_EDNS0ERR) == 0 + && (statp->options & RES_USE_EDNS0) != 0) + n = __res_nopt(statp, n, query1, bufsize, anslen); + + nquery1 = n; + } + if (__builtin_expect (n <= 0, 0) && !use_malloc) { /* Retry just in case res_nmkquery failed because of too short buffer. Shouldn't happen. */ - bufsize = MAXPACKET; + bufsize = (type == T_UNSPEC ? 2 : 1) * MAXPACKET; buf = malloc (bufsize); if (buf != NULL) { + query1 = buf; use_malloc = 1; goto again; } @@ -168,7 +202,8 @@ __libc_res_nquery(res_state statp, return (n); } assert (answerp == NULL || (void *) *answerp == (void *) answer); - n = __libc_res_nsend(statp, buf, n, answer, anslen, answerp); + n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer, + anslen, answerp, answerp2, nanswerp2); if (use_malloc) free (buf); if (n < 0) { @@ -184,20 +219,37 @@ __libc_res_nquery(res_state statp, /* __libc_res_nsend might have reallocated the buffer. */ hp = (HEADER *) *answerp; - if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { + /* We simplify the following tests by assigning HP to HP2. It + is easy to verify that this is the same as ignoring all + tests of HP2. */ + HEADER *hp2 = answerp2 ? (HEADER *) *answerp2 : hp; + + if ((hp->rcode != NOERROR || ntohs(hp->ancount) == 0) + && (hp2->rcode != NOERROR || ntohs(hp2->ancount) == 0)) { #ifdef DEBUG - if (statp->options & RES_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) { + 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: @@ -209,6 +261,7 @@ __libc_res_nquery(res_state statp, } return (-1); } + success: return (n); } libresolv_hidden_def (__libc_res_nquery) @@ -221,7 +274,7 @@ res_nquery(res_state statp, int anslen) /* size of answer buffer */ { return __libc_res_nquery(statp, name, class, type, answer, anslen, - NULL); + NULL, NULL, NULL); } libresolv_hidden_def (res_nquery) @@ -233,11 +286,13 @@ libresolv_hidden_def (res_nquery) */ 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) + 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) { const char *cp, * const *domain; HEADER *hp = (HEADER *) answer; @@ -260,7 +315,8 @@ __libc_res_nsearch(res_state statp, /* 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)); + anslen, answerp, answerp2, + nanswerp2)); #ifdef DEBUG if (statp->options & RES_DEBUG) @@ -276,7 +332,8 @@ __libc_res_nsearch(res_state statp, saved_herrno = -1; if (dots >= statp->ndots || trailing_dot) { ret = __libc_res_nquerydomain(statp, name, NULL, class, type, - answer, anslen, answerp); + answer, anslen, answerp, + answerp2, nanswerp2); if (ret > 0 || trailing_dot) return (ret); saved_herrno = h_errno; @@ -285,6 +342,12 @@ __libc_res_nsearch(res_state statp, answer = *answerp; anslen = MAXPACKET; } + if (answerp2 + && (*answerp2 < answer || *answerp2 >= answer + anslen)) + { + free (*answerp2); + *answerp2 = NULL; + } } /* @@ -307,7 +370,8 @@ __libc_res_nsearch(res_state statp, ret = __libc_res_nquerydomain(statp, name, *domain, class, type, - answer, anslen, answerp); + answer, anslen, answerp, + answerp2, nanswerp2); if (ret > 0) return (ret); @@ -315,6 +379,13 @@ __libc_res_nsearch(res_state statp, answer = *answerp; anslen = MAXPACKET; } + if (answerp2 + && (*answerp2 < answer + || *answerp2 >= answer + anslen)) + { + free (*answerp2); + *answerp2 = NULL; + } /* * If no server present, give up. @@ -368,7 +439,8 @@ __libc_res_nsearch(res_state statp, */ if (dots && !(tried_as_is || root_on_list)) { ret = __libc_res_nquerydomain(statp, name, NULL, class, type, - answer, anslen, answerp); + answer, anslen, answerp, + answerp2, nanswerp2); if (ret > 0) return (ret); } @@ -380,6 +452,11 @@ __libc_res_nsearch(res_state statp, * else send back meaningless H_ERRNO, that being the one from * the last DNSRCH we did. */ + if (answerp2 && (*answerp2 < answer || *answerp2 >= answer + anslen)) + { + free (*answerp2); + *answerp2 = NULL; + } if (saved_herrno != -1) RES_SET_H_ERRNO(statp, saved_herrno); else if (got_nodata) @@ -398,7 +475,7 @@ res_nsearch(res_state statp, int anslen) /* size of answer */ { return __libc_res_nsearch(statp, name, class, type, answer, - anslen, NULL); + anslen, NULL, NULL, NULL); } libresolv_hidden_def (res_nsearch) @@ -408,12 +485,14 @@ libresolv_hidden_def (res_nsearch) */ 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) + 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) { char nbuf[MAXDNAME]; const char *longname = nbuf; @@ -450,7 +529,7 @@ __libc_res_nquerydomain(res_state statp, sprintf(nbuf, "%s.%s", name, domain); } return (__libc_res_nquery(statp, longname, class, type, answer, - anslen, answerp)); + anslen, answerp, answerp2, nanswerp2)); } int @@ -462,7 +541,7 @@ res_nquerydomain(res_state statp, int anslen) /* size of answer */ { return __libc_res_nquerydomain(statp, name, domain, class, type, - answer, anslen, NULL); + answer, anslen, NULL, NULL, NULL); } libresolv_hidden_def (res_nquerydomain) |