resolver.c revision a5166d5fce30e5924f279d3e92d1f20b9fb7b4dc
495591bf3af0f60bc7359c69413789a24ca19411Michael Graff * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC")
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * Copyright (C) 1999-2003 Internet Software Consortium.
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * Permission to use, copy, modify, and/or distribute this software for any
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * purpose with or without fee is hereby granted, provided that the above
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * copyright notice and this permission notice appear in all copies.
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * PERFORMANCE OF THIS SOFTWARE.
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff/* $Id: resolver.c,v 1.439 2011/11/04 03:38:44 marka Exp $ */
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff#define RRTRACE(r, m) isc_log_write(dns_lctx, \
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff "res %p: %s", (r), (m))
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff "fctx %p(%s): %s %s", \
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff "fetch %p (fctx %p(%s)): %s", \
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff "resquery %p (fctx %p(%s)): %s", \
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff#define DEFAULT_QUERY_TIMEOUT 10 /* The default time in seconds for the whole query to live. */
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff#define MAXIMUM_QUERY_TIMEOUT 30 /* The maximum time in seconds for the whole query to live. */
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * Maximum EDNS0 input packet size.
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff#define RECV_BUFFER_SIZE 4096 /* XXXRTH Constant. */
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * This defines the maximum number of timeouts we will permit before we
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * disable EDNS0 on the query.
f9fdb43a912a53c44627449ace57921b143eef60Michael Grafftypedef struct query {
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff /* Locked by task event serialization. */
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff unsigned int magic;
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff unsigned int options;
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff unsigned int sends;
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff#define QUERY_MAGIC ISC_MAGIC('Q', '!', '!', '!')
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff#define VALID_QUERY(query) ISC_MAGIC_VALID(query, QUERY_MAGIC)
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff#define RESQUERY_CONNECTING(q) ((q)->connects > 0)
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff#define RESQUERY_CANCELED(q) (((q)->attributes & \
f9fdb43a912a53c44627449ace57921b143eef60Michael Grafftypedef enum {
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff fetchstate_init = 0, /*%< Start event has not run yet. */
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff fetchstate_done /*%< FETCHDONE events posted. */
f9fdb43a912a53c44627449ace57921b143eef60Michael Grafftypedef enum {
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff /*% Not locked. */
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff unsigned int magic;
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff unsigned int options;
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff /*% Locked by appropriate bucket lock. */
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff /*% Locked by task event serialization. */
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * The number of events we're waiting for.
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff unsigned int pending;
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * The number of times we've "restarted" the current
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * nameserver set. This acts as a failsafe to prevent
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * us from pounding constantly on a particular set of
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * servers that, for whatever reason, are not giving
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * us useful responses, but are responding in such a
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * way that they are not marked "bad".
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * The number of timeouts that have occurred since we
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * last successfully received a response packet. This
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * is used for EDNS0 black hole detection.
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * Look aside state for DS lookups.
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * Number of queries that reference this context.
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * The reason to print when logging a successful
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * response to a query.
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff const char * reason;
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * Random numbers to use for mixing up server addresses.
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff * Fetch-local statistics for detailed logging.
f9fdb43a912a53c44627449ace57921b143eef60Michael Graff isc_result_t vresult; /*%< validation result */
915723e4007e177b10c0e1c9d1bfe77ac2bfe853Michael Graff unsigned int neterr;
915723e4007e177b10c0e1c9d1bfe77ac2bfe853Michael Graff unsigned int badresp;
915723e4007e177b10c0e1c9d1bfe77ac2bfe853Michael Graff unsigned int adberr;
915723e4007e177b10c0e1c9d1bfe77ac2bfe853Michael Graff unsigned int valfail;
} dns_valarg_t;
struct dns_fetch {
unsigned int magic;
typedef struct fctxbucket {
} fctxbucket_t;
typedef struct alternate {
} _n;
} _u;
} alternate_t;
struct dns_badcache {
unsigned int hashval;
struct dns_resolver {
unsigned int magic;
unsigned int options;
unsigned int ndisps;
unsigned int nbuckets;
#if USE_ALGLOCK
#if USE_MBSLOCK
unsigned int spillatmax;
unsigned int spillatmin;
unsigned int query_timeout;
unsigned int references;
unsigned int activebuckets;
unsigned int nextdisp;
unsigned int badcount;
unsigned int badhash;
unsigned int badsweep;
unsigned int nfctx;
FCTX_ADDRINFO_FORWARDER) != 0)
FCTX_ADDRINFO_TRIED) != 0)
static isc_result_t
sizeof(*valarg));
return (ISC_R_NOMEMORY);
&validator);
return (result);
static isc_boolean_t
int order;
unsigned int labels;
return (ISC_TRUE);
return (ISC_FALSE);
static isc_boolean_t
return (ISC_FALSE);
&name);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
goto munge;
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
if (!keep_auth)
return (ISC_TRUE);
static inline isc_result_t
static inline isc_result_t
unsigned int factor;
0, factor);
0, factor);
0, factor);
0, factor);
unsigned int count = 0;
unsigned int old_spillat;
count++;
&i, ISC_TRUE);
if (logit)
* isc_socket_sendto/connect() was in progress.
case ISC_R_SUCCESS:
case ISC_R_HOSTUNREACH:
case ISC_R_NETUNREACH:
case ISC_R_NOPERM:
case ISC_R_ADDRNOTAVAIL:
case ISC_R_CONNREFUSED:
if (retry) {
static inline isc_result_t
return (result);
return (result);
return (result);
if (request_nsid) {
unsigned int seconds;
unsigned int us;
static isc_result_t
unsigned int options)
unsigned int srtt;
return (result);
sizeof(*query));
goto stop_idle_timer;
int pf;
if (!have_addr) {
switch (pf) {
case PF_INET:
result =
&addr);
case PF_INET6:
result =
&addr);
goto cleanup_query;
goto cleanup_query;
#ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
goto cleanup_socket;
if (have_addr) {
case AF_INET:
case AF_INET6:
goto cleanup_query;
goto cleanup_query;
case PF_INET:
case PF_INET6:
goto cleanup_query;
goto cleanup_socket;
goto cleanup_dispatch;
return (ISC_R_SUCCESS);
return (result);
static isc_boolean_t
return (ISC_TRUE);
return (ISC_FALSE);
sizeof(*sa));
static isc_boolean_t
return (ISC_TRUE);
return (ISC_FALSE);
sizeof(*sa));
static isc_boolean_t
return (ISC_TRUE);
return (ISC_FALSE);
sizeof(*sa));
static isc_result_t
isc_region_t r;
unsigned int edns_fetchopt_flag;
goto cleanup_temps;
goto cleanup_temps;
task,
goto cleanup_temps;
if (secure_domain)
goto cleanup_message;
goto cleanup_message;
DNS_SECTION_QUESTION, 0);
goto cleanup_message;
now);
!useedns)
* * broken/misconfigured firewalls and NAT implementations
* * broken/misconfigured firewalls that don't handle responses
* * broken/misconfigured firewalls that don't handle EDNS, DO
unsigned int flags;
goto cleanup_message;
goto cleanup_message;
goto cleanup_message;
goto cleanup_message;
goto cleanup_message;
goto cleanup_message;
query);
goto cleanup_message;
if (connecting) {
goto cleanup_message;
return (ISC_R_SUCCESS);
if (cleanup_cctx)
return (result);
unsigned int attrs;
case ISC_R_SUCCESS:
attrs = 0;
case ISC_R_NETUNREACH:
case ISC_R_HOSTUNREACH:
case ISC_R_CONNREFUSED:
case ISC_R_NOPERM:
case ISC_R_ADDRNOTAVAIL:
case ISC_R_CONNECTIONRESET:
if (retry) {
unsigned int bucketnum;
if (want_try)
else if (want_done)
else if (bucket_empty)
static inline isc_boolean_t
return (ISC_TRUE);
return (ISC_FALSE);
static inline isc_boolean_t
return (all_bad);
isc_buffer_t b;
switch (badtype) {
case badns_unreachable:
case badns_response:
case badns_validation:
sizeof(*sa));
if (port != 0)
port);
static isc_boolean_t
int order;
unsigned int nlabels;
static isc_result_t
unsigned int stdoptions = 0;
return (DNS_R_SERVFAIL);
unsigned int labels;
return (result);
goto out;
return (result);
if (need_alternate) {
int family;
alternate_t *a;
a != NULL;
if (!a->isaddress) {
&ai, 0);
publink);
out:
if (all_bad) {
if (badcache &&
return (result);
int match;
match > 0)
if (aborted) {
static inline dns_adbaddrinfo_t *
return (addrinfo);
return (addrinfo);
return (addrinfo);
else if (retrying)
static isc_boolean_t
unsigned int bucketnum;
return (ISC_TRUE);
return (ISC_FALSE);
&cevent);
unsigned int bucketnum;
if (bucket_empty)
unsigned int bucketnum;
if (!done) {
} else if (bucket_empty)
static inline isc_result_t
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
static isc_result_t
unsigned int findoptions = 0;
return (ISC_R_NOMEMORY);
goto cleanup_fetch;
goto cleanup_info;
unsigned int labels;
NULL);
goto cleanup_name;
goto cleanup_name;
goto cleanup_name;
goto cleanup_name;
goto cleanup_domain;
goto cleanup_qmessage;
goto cleanup_rmessage;
goto cleanup_rmessage;
return (ISC_R_SUCCESS);
return (result);
static inline isc_boolean_t
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
int order;
unsigned int labels;
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_TRUE);
return (ISC_FALSE);
static inline isc_result_t
return (DNS_R_FORMERR);
return (result);
return (DNS_R_FORMERR);
return (ISC_R_SUCCESS);
unsigned int bucketnum;
if (bucket_empty)
goto cleanup_event;
!negative &&
NULL,
NULL,
NULL);
0, NULL);
else if (sentresponse)
if (negative &&
if (negative) {
&node);
goto noanswer_response;
ttl = 0;
goto noanswer_response;
goto answer_response;
goto noanswer_response;
goto noanswer_response;
goto noanswer_response;
if (sentresponse) {
goto cleanup_event;
goto cleanup_event;
&name);
&nsnode);
sigrdataset, 0,
NULL);
== ISC_R_SUCCESS);
static inline isc_result_t
unsigned int options;
unsigned int valoptions = 0;
return (result);
!need_validation) {
return (result);
return (result);
sizeof(typebuf));
sizeof(classbuf));
if (fail) {
return (DNS_R_BADNAME);
* Cache this rdataset/sigrdataset pair as
0, addedrdataset);
if (!need_validation &&
eresult =
eresult =
sigrdataset, 0,
options = 0;
task);
return (result);
static inline isc_result_t
section++) {
&name);
return (result);
static isc_result_t
return (result);
static inline isc_result_t
unsigned int valoptions = 0;
return (result);
if (secure_domain) {
&tname);
return (result);
if (need_validation) {
return (result);
goto unlock;
goto unlock;
ttl = 0;
goto unlock;
return (result);
if (gluing) {
if (external)
static isc_result_t
return (ISC_R_SUCCESS);
gluing);
&rdataset);
gluing);
return (ISC_R_SUCCESS);
static isc_result_t
#ifndef CHECK_FOR_GLUE_IN_ANSWER
#define CHECK_FOR_GLUE_IN_ANSWER 0
static isc_result_t
&name);
fctx);
if (rescan)
goto again;
static inline isc_result_t
return (result);
return (result);
return (ISC_R_SUCCESS);
static inline isc_result_t
unsigned int nlabels;
int order;
return (result);
return (result);
return (DNS_R_FORMERR);
return (result);
static isc_boolean_t
int match;
return (ISC_TRUE);
return (ISC_TRUE);
sizeof(typebuf));
sizeof(classbuf));
return (ISC_FALSE);
return (ISC_TRUE);
static isc_boolean_t
return (ISC_TRUE);
return (ISC_TRUE);
return (ISC_TRUE);
sizeof(classbuf));
return (ISC_FALSE);
return (ISC_TRUE);
static isc_result_t
unsigned int look_in_options)
return (ISC_R_SUCCESS);
sizeof(tbuf));
sizeof(nbuf));
sizeof(qbuf));
return (DNS_R_FORMERR);
return (DNS_R_FORMERR);
return (DNS_R_FORMERR);
if (aa)
return (result);
if (negative_response) {
if (aa)
return (DNS_R_FORMERR);
return (DNS_R_FORMERR);
if (aa)
return (result);
return (DNS_R_CHASEDSSERVERS);
return (ISC_R_SUCCESS);
return (DNS_R_FORMERR);
return (DNS_R_FORMERR);
return (DNS_R_FORMERR);
return (DNS_R_FORMERR);
fctx);
return (result);
return (DNS_R_DELEGATION);
return (ISC_R_SUCCESS);
static isc_result_t
unsigned int aflag;
aflag = 0;
return (DNS_R_FORMERR);
rdataset)) {
return (DNS_R_SERVFAIL);
&& !found_cname) {
&& !found_type) {
return (DNS_R_FORMERR);
&tname);
return (result);
name,
&tname,
return (DNS_R_SERVFAIL);
&& !found_type) {
if (found) {
if (!chaining) {
if (aflag ==
if (aa)
} else if (external) {
(void)dns_rdataset_additionaldata(
fctx);
if (want_chaining) {
if (wanted_chaining)
aflag = 0;
return (DNS_R_FORMERR);
&dname);
return (result);
return (DNS_R_SERVFAIL);
if (found) {
if (!chaining) {
if (aflag ==
if (aa)
} else if (external) {
if (found_dname) {
NULL);
return (result);
&fqname);
if (wanted_chaining)
return (result);
if (!have_answer) {
return (DNS_R_FORMERR);
if (chaining) {
return (DNS_R_FORMERR);
if (!external) {
(void)dns_rdataset_additionaldata(
fctx);
return (result);
static isc_boolean_t
return (bucket_empty);
unsigned int bucketnum;
goto cleanup;
goto cleanup;
&nameservers);
if (!locked)
if (bucket_empty)
ISC_FALSE) ||
static isc_result_t
return (ISC_R_FAILURE);
return (ISC_R_FAILURE);
return (ISC_R_FAILURE);
return (ISC_R_NOSPACE);
p = buf;
for (i = 0; i < nsid_len; i++) {
nsid++;
sizeof(addrbuf));
return (ISC_R_SUCCESS);
0, &buffer);
buf);
static isc_boolean_t
static isc_boolean_t
return (ISC_TRUE);
return (ISC_FALSE);
unsigned int options;
unsigned int findoptions;
goto done;
goto done;
sizeof(addrbuf));
goto done;
goto done;
switch (result) {
case ISC_R_UNEXPECTEDEND:
goto done;
case DNS_R_FORMERR:
goto done;
goto done;
goto done;
sizeof(addrbuf));
if (truncated) {
goto done;
goto done;
case dns_rcode_nxdomain:
case dns_rcode_servfail:
case dns_rcode_formerr:
unsigned int version;
switch (version) {
goto done;
goto done;
goto done;
sizeof(classbuf));
sizeof(addrbuf));
goto done;
goto force_referral;
goto done;
goto done;
goto done;
goto done;
done:
if (keep_trying) {
if (get_nameservers) {
findoptions = 0;
NULL);
} else if (resend) {
alternate_t *a;
if (!a->isaddress)
#if USE_ALGLOCK
#if USE_MBSLOCK
unsigned int count;
if (logit)
unsigned int options,
unsigned int i, buckets_created = 0;
unsigned dispattr;
return (ISC_R_NOMEMORY);
goto cleanup_res;
for (i = 0; i < ntasks; i++) {
goto cleanup_buckets;
goto cleanup_buckets;
#ifdef ISC_PLATFORM_USETHREADS
goto cleanup_buckets;
goto cleanup_dispatches;
goto cleanup_lock;
goto cleanup_nlock;
goto cleanup_primelock;
goto cleanup_primelock;
#if USE_ALGLOCK
goto cleanup_spillattimer;
#if USE_MBSLOCK
goto cleanup_alglock;
return (ISC_R_SUCCESS);
#if USE_MBSLOCK
#if USE_ALGLOCK
for (i = 0; i < buckets_created; i++) {
return (result);
#ifdef BIND9
if (want_priming) {
if (need_destroy)
static inline isc_boolean_t
unsigned int options)
return (ISC_FALSE);
return (ISC_FALSE);
unsigned int bucketnum;
unsigned int count = 0;
unsigned int spillat;
unsigned int spillatmin;
return (ISC_R_NOMEMORY);
goto unlock;
goto unlock;
count++;
goto unlock;
goto unlock;
if (new_fctx) {
return (result);
unsigned int bucketnum;
if (bucket_empty)
alternate_t *a;
if (a == NULL)
return (ISC_R_NOMEMORY);
return (result);
return (ISC_R_SUCCESS);
goto unlock;
unsigned int newsize;
if (grow)
unsigned int i, hashval;
goto cleanup;
goto cleanup;
goto unlock;
return (answer);
isc_uint64_t t;
goto unlock;
sizeof(typebuf));
#if USE_ALGLOCK
#if USE_ALGLOCK
unsigned int alg)
unsigned char *new;
unsigned char *algorithms;
return (ISC_R_RANGE);
#if USE_ALGLOCK
goto cleanup;
goto cleanup;
*algorithms);
#if USE_ALGLOCK
return (result);
unsigned int alg)
unsigned char *algorithms;
#if USE_ALGLOCK
goto unlock;
#if USE_ALGLOCK
if (found)
return (ISC_FALSE);
#if USE_MBSLOCK
#if USE_MBSLOCK
#if USE_MBSLOCK
goto cleanup;
#if USE_MBSLOCK
return (result);
#if USE_MBSLOCK
goto unlock;
#if USE_MBSLOCK
return (value);
if (seconds == 0)