resolver.c revision 06fd648cf2b04912160c9f145b19fe75d4648dc3
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Copyright (C) 1999, 2000 Internet Software Consortium.
bf8267aa453e5d2a735ed732a043b77a0b355b20Mark Andrews * Permission to use, copy, modify, and distribute this software for any
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * purpose with or without fee is hereby granted, provided that the above
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * copyright notice and this permission notice appear in all copies.
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
2f4561bc9cd5e5cdc58e29e600303c812f6902eeAutomatic Updater * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews "res %p: %s", (r), (m))
cc51cd2d2076e33117c60c9effcb8caccde4983bWitold Krecicki#define FCTXTRACE(m) isc_log_write(dns_lctx, \
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews "fetch %p (fctx %p): %s", \
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt "resquery %p (fctx %p): %s", \
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt * Maximum EDNS0 input packet size.
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews#define SEND_BUFFER_SIZE 2048 /* XXXRTH Constant. */
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunttypedef struct query {
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt /* Locked by task event serialization. */
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews unsigned int magic;
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews unsigned int options;
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunt#define RESQUERY_CONNECTING(q) (((q)->attributes & \
75b8de87879ad017c9cd2ffc328e5d2391d16e99Evan Hunttypedef enum {
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews fetchstate_init = 0, /* Start event has not run yet. */
cc51cd2d2076e33117c60c9effcb8caccde4983bWitold Krecicki fetchstate_done /* FETCHDONE events posted. */
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt /* Not locked. */
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews unsigned int magic;
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt unsigned int bucketnum;
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt /* Locked by appropriate bucket lock. */
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt unsigned int references;
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews /* Locked by task event serialization. */
e11a0c114cdaf8f7e7832e9f1a011138248093a6Evan Hunt unsigned int attributes;
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews * # of events we're waiting for.
5ae2eac4c16bdbbef032544bd9fc86f47e7bdc2cMark Andrews unsigned int pending;
5ae2eac4c16bdbbef032544bd9fc86f47e7bdc2cMark Andrews unsigned int restarts;
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews#define HAVE_ANSWER(f) (((f)->attributes & FCTX_ATTR_HAVEANSWER) != \
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews#define GLUING(f) (((f)->attributes & FCTX_ATTR_GLUING) != \
61bcc232038f0a2cb77ed6269675fdc288f5ec98Evan Hunt#define ADDRWAIT(f) (((f)->attributes & FCTX_ATTR_ADDRWAIT) != \
61bcc232038f0a2cb77ed6269675fdc288f5ec98Evan Hunt#define SHUTTINGDOWN(f) (((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \
61bcc232038f0a2cb77ed6269675fdc288f5ec98Evan Hunt#define WANTCACHE(f) (((f)->attributes & FCTX_ATTR_WANTCACHE) != 0)
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews#define WANTNCACHE(f) (((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0)
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews#define NEEDEDNS0(f) (((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0)
61bcc232038f0a2cb77ed6269675fdc288f5ec98Evan Hunt unsigned int magic;
61bcc232038f0a2cb77ed6269675fdc288f5ec98Evan Hunt#define DNS_FETCH_VALID(fetch) ((fetch) != NULL && \
ad127d839d2e7aa542939a8a336691407e23397eMark Andrewstypedef struct fctxbucket {
61bcc232038f0a2cb77ed6269675fdc288f5ec98Evan Hunt /* Unlocked. */
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews unsigned int magic;
79ce3a9e82384cc31fd6b86be8f3d1474fcfd9f4Evan Hunt unsigned int options;
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews unsigned int nbuckets;
b47c020d5c635b662ac57e5485d266fd62c796c0Evan Hunt /* Locked by lock. */
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews * Private addrinfo flags. These must not conflict with DNS_FETCHOPT_NOEDNS0,
99f6179191e583d23f3c5567d3c00b57b64eb52dEvan Hunt * which we also use as an addrinfo flag.
ad127d839d2e7aa542939a8a336691407e23397eMark Andrews#define UNMARKED(a) (((a)->flags & FCTX_ADDRINFO_MARK) \
e939674d53a127ddeeaf4b41fd72933f0b493308Mark Andrewsstatic isc_result_t resquery_send(resquery_t *query);
e939674d53a127ddeeaf4b41fd72933f0b493308Mark Andrewsstatic void resquery_response(isc_task_t *task, isc_event_t *event);
e939674d53a127ddeeaf4b41fd72933f0b493308Mark Andrewsstatic void resquery_connected(isc_task_t *task, isc_event_t *event);
e939674d53a127ddeeaf4b41fd72933f0b493308Mark Andrewsstatic isc_boolean_t fctx_destroy(fetchctx_t *fctx);
677f507de7c546c187c1505c48bc7b440545485cMark Andrews * Start the lifetime timer for fctx.
677f507de7c546c187c1505c48bc7b440545485cMark Andrews * This is also used for stopping the idle timer; in that
677f507de7c546c187c1505c48bc7b440545485cMark Andrews * case we must purge events already posted to ensure that
677f507de7c546c187c1505c48bc7b440545485cMark Andrews * no further idle events are delivered.
677f507de7c546c187c1505c48bc7b440545485cMark Andrews return (isc_timer_reset(fctx->timer, isc_timertype_once,
ISC_TRUE));
static inline isc_result_t
ISC_FALSE));
unsigned int rtt;
unsigned int factor;
factor);
deventp);
static inline isc_result_t
return (result);
return (result);
return (result);
unsigned int seconds;
static isc_result_t
unsigned int options)
return (result);
goto stop_idle_timer;
goto cleanup_query;
&socket);
goto cleanup_query;
goto cleanup_dispatch;
case PF_INET:
case PF_INET6:
goto cleanup_dispatch;
goto cleanup_dispatch;
goto cleanup_dispatch;
return (ISC_R_SUCCESS);
return (result);
static isc_result_t
isc_region_t r;
goto cleanup_temps;
goto cleanup_temps;
task,
goto cleanup_temps;
goto cleanup_message;
DNS_SECTION_QUESTION, 0);
goto cleanup_message;
goto cleanup_message;
goto cleanup_message;
goto cleanup_message;
goto cleanup_message;
goto cleanup_message;
return (ISC_R_SUCCESS);
NULL);
return (result);
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);
static isc_result_t
isc_region_t r;
return (DNS_R_SERVFAIL);
goto out;
&find);
return (result);
out:
if (all_bad) {
} else if (pruned) {
goto restart;
return (result);
static inline dns_adbaddrinfo_t *
return (addrinfo);
return (addrinfo);
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
return (ISC_R_NOMEMORY);
goto cleanup_fetch;
0, ISC_TRUE,
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_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;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
static inline isc_result_t
unsigned int options;
return (result);
if (need_validation) {
!need_validation) {
return (result);
return (result);
* Cache this rdataset/sigrdataset pair as
#ifdef notyet
sigrdataset, 0,
NULL);
name,
task,
fctx,
options = 0;
eresult =
eresult =
return (result);
static inline isc_result_t
section++) {
&name);
return (result);
static inline isc_result_t
return (result);
if (need_validation) {
return (ISC_R_NOTIMPLEMENTED);
goto unlock;
&node);
goto unlock;
goto unlock;
return (result);
if (gluing)
if (external)
static isc_result_t
NULL);
gluing);
&rdataset);
gluing);
* See query.c.
return (ISC_R_SUCCESS);
static inline isc_result_t
isc_region_t r;
return (result);
return (ISC_R_SUCCESS);
static inline isc_result_t
isc_region_t r;
int order;
return (result);
&nbits);
return (DNS_R_FORMERR);
return (result);
static isc_result_t
return (ISC_R_SUCCESS);
return (DNS_R_FORMERR);
return (DNS_R_FORMERR);
if (aa)
return (result);
return (ISC_R_SUCCESS);
return (DNS_R_FORMERR);
return (DNS_R_FORMERR);
return (DNS_R_FORMERR);
fctx);
return (result);
return (DNS_R_DELEGATION);
if (negative_response)
return (ISC_R_SUCCESS);
static isc_result_t
unsigned int aflag;
aflag = 0;
return (DNS_R_FORMERR);
&tname);
return (result);
if (found) {
if (!chaining) {
if (aflag ==
if (aa)
} else if (external) {
(void)dns_rdataset_additionaldata(
fctx);
if (want_chaining) {
aflag = 0;
return (DNS_R_FORMERR);
&dname);
return (result);
if (found) {
if (!chaining) {
if (aa)
} else if (external) {
if (want_chaining) {
&dname);
return (result);
if (!have_answer)
return (DNS_R_FORMERR);
if (want_chaining) {
return (DNS_R_FORMERR);
if (!external) {
(void)dns_rdataset_additionaldata(
fctx);
return (result);
return (ISC_R_SUCCESS);
unsigned int options;
covers = 0;
goto done;
goto done;
switch (result) {
case ISC_R_UNEXPECTEDEND:
goto done;
case DNS_R_FORMERR:
goto done;
case DNS_R_MOREDATA:
goto done;
goto done;
goto done;
goto done;
if (truncated) {
goto done;
goto done;
goto done;
goto done;
goto done;
goto done;
goto done;
goto done;
done:
if (keep_trying) {
if (broken_server) {
if (get_nameservers) {
NULL);
} else if (resend) {
unsigned int options,
unsigned int i, buckets_created = 0;
return (ISC_R_NOMEMORY);
goto cleanup_res;
for (i = 0; i < ntasks; i++) {
goto cleanup_buckets;
goto cleanup_buckets;
goto cleanup_buckets;
goto cleanup_udpsocketv4;
goto cleanup_dispatchv4;
goto cleanup_udpsocketv6;
goto cleanup_dispatchv6;
return (ISC_R_SUCCESS);
for (i = 0; i < buckets_created; i++) {
return (result);
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
return (ISC_R_SUCCESS);
if (want_priming) {
if (need_destroy)
static inline isc_boolean_t
unsigned int options)
return (ISC_FALSE);
isc_buffer_t b;
isc_region_t r;
isc_buffer_available(&b, &r);
isc_buffer_used(&b, &r);
unsigned int bucketnum;
return (ISC_R_NOMEMORY);
goto unlock;
goto unlock;
if (new_fctx) {
return (result);
unsigned int bucketnum;
if (bucket_empty)