resolver.c revision 37b4618a5b9589cff5dce1ec15f1eb7ca52a4069
ebf264ea105fc78b8316a1166bae0624d488d83bMark Andrews * Copyright (C) 1999 Internet Software Consortium.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * Permission to use, copy, modify, and distribute this software for any
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * purpose with or without fee is hereby granted, provided that the above
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * copyright notice and this permission notice appear in all copies.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1f1d36a87b65186d9f89aac7f456ab1fd2a39ef6Andreas Gustafsson#define RRTRACE(r, m) isc_log_write(dns_lctx, \
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister "res %p: %s", (r), (m))
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister "fetch %p (fctx %p): %s", \
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister "resquery %p (fctx %p): %s", \
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * Maximum EDNS0 input packet size.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define SEND_BUFFER_SIZE 2048 /* XXXRTH Constant. */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristertypedef struct query {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* Locked by task event serialization. */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister unsigned int magic;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define VALID_QUERY(query) ((query) != NULL && \
1f1d36a87b65186d9f89aac7f456ab1fd2a39ef6Andreas Gustafsson#define RESQUERY_CONNECTING(q) (((q)->attributes & \
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define RESQUERY_CANCELED(q) (((q)->attributes & \
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence fetchstate_init = 0, /* Start event has not run yet. */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister fetchstate_done /* FETCHDONE events posted. */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* Not locked. */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister unsigned int magic;
4844ed026a9b5a91044e76399cee80a6514cbf0dMark Andrews unsigned int options;
4844ed026a9b5a91044e76399cee80a6514cbf0dMark Andrews /* Locked by appropriate bucket lock. */
4844ed026a9b5a91044e76399cee80a6514cbf0dMark Andrews /* Locked by task event serialization. */
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * # of events we're waiting for.
4844ed026a9b5a91044e76399cee80a6514cbf0dMark Andrews unsigned int pending;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define HAVE_ANSWER(f) (((f)->attributes & FCTX_ATTR_HAVEANSWER) != \
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define GLUING(f) (((f)->attributes & FCTX_ATTR_GLUING) != \
b3e77535185043f089b346166440402d092030c3David Lawrence#define ADDRWAIT(f) (((f)->attributes & FCTX_ATTR_ADDRWAIT) != \
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define SHUTTINGDOWN(f) (((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define WANTCACHE(f) (((f)->attributes & FCTX_ATTR_WANTCACHE) != 0)
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define WANTNCACHE(f) (((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0)
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister unsigned int magic;
4844ed026a9b5a91044e76399cee80a6514cbf0dMark Andrews#define DNS_FETCH_VALID(fetch) ((fetch) != NULL && \
4844ed026a9b5a91044e76399cee80a6514cbf0dMark Andrewstypedef struct fctxbucket {
4844ed026a9b5a91044e76399cee80a6514cbf0dMark Andrews /* Unlocked. */
4844ed026a9b5a91044e76399cee80a6514cbf0dMark Andrews unsigned int magic;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister unsigned int options;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister /* Locked by lock. */
600cbd1fcea3c9cc9706dc1ff8fc0d0034ebdeacTatuya JINMEI 神明達哉#define VALID_RESOLVER(res) ((res) != NULL && \
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * Private addrinfo flags. These must not conflict with DNS_FETCHOPT_NOEDNS0,
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * which we also use as an addrinfo flag.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister#define UNMARKED(a) (((a)->flags & FCTX_ADDRINFO_MARK) \
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerstatic isc_result_t resquery_send(resquery_t *query);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerstatic void resquery_response(isc_task_t *task, isc_event_t *event);
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrencestatic void resquery_connected(isc_task_t *task, isc_event_t *event);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerstatic isc_boolean_t fctx_destroy(fetchctx_t *fctx);
1f1d36a87b65186d9f89aac7f456ab1fd2a39ef6Andreas Gustafsson return (isc_timer_reset(fctx->timer, isc_timertype_once,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister return (isc_timer_reset(fctx->timer, isc_timertype_once,
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerstatic inline void
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * We don't return a result if resetting the timer to inactive fails
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * since there's nothing to be done about it. Resetting to inactive
1f1d36a87b65186d9f89aac7f456ab1fd2a39ef6Andreas Gustafsson * should never fail anyway, since the code as currently written
1f1d36a87b65186d9f89aac7f456ab1fd2a39ef6Andreas Gustafsson * cannot fail in that case.
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister result = isc_timer_reset(fctx->timer, isc_timertype_inactive,
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence "isc_timer_reset(): %s",
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerstatic inline void
600cbd1fcea3c9cc9706dc1ff8fc0d0034ebdeacTatuya JINMEI 神明達哉 isc_mem_put(query->fctx->res->mctx, query, sizeof *query);
f3ca27e9fe307b55e35ea8d7b37351650630e5a3Andreas Gustafssonfctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence isc_time_t *finish, isc_boolean_t no_response)
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister unsigned int rtt;
b3e77535185043f089b346166440402d092030c3David Lawrence unsigned int factor;
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * Should we update the RTT?
b3e77535185043f089b346166440402d092030c3David Lawrence * We have both the start and finish times for this
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * packet, so we can compute a real RTT.
b3e77535185043f089b346166440402d092030c3David Lawrence rtt = (unsigned int)isc_time_microdiff(finish,
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister * We don't have an RTT for this query. Maybe the
b3e77535185043f089b346166440402d092030c3David Lawrence * packet was lost, or maybe this server is very
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister * slow. We don't know. Increase the RTT.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * Replace the current RTT with our value.
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister dns_adb_adjustsrtt(fctx->res->view->adb, query->addrinfo, rtt,
b3e77535185043f089b346166440402d092030c3David Lawrence dns_dispatch_removeresponse(query->dispatch, &query->dispentry,
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister * Cancel the connect.
b3e77535185043f089b346166440402d092030c3David Lawrence socket = dns_dispatch_getsocket(query->dispatch);
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_CONNECT);
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * It's safe to destroy the query now.
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Bristerfctx_cancelqueries(fetchctx_t *fctx, isc_boolean_t no_response) {
5475a2d296215b7a93bd89804dc33c36a6de7cb5James Brister fctx_cancelquery(&query, NULL, NULL, no_response);
d25dd5b0567f67ecf40b7ed1cb20e0dce7b41c49Brian Wellington ISC_LIST_UNLINK(fctx->finds, find, publink);
d25dd5b0567f67ecf40b7ed1cb20e0dce7b41c49Brian Wellington for (addr = ISC_LIST_HEAD(fctx->forwaddrs);
3e42bdfdc901b6b921b02028bd51ca2af8e84adcMark Andrews ISC_LIST_UNLINK(fctx->forwaddrs, addr, publink);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister dns_adb_freeaddrinfo(fctx->res->view->adb, &addr);
b3e77535185043f089b346166440402d092030c3David Lawrencestatic inline void
3e42bdfdc901b6b921b02028bd51ca2af8e84adcMark Andrewsstatic inline void
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerfctx_sendevents(fetchctx_t *fctx, isc_result_t result) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * Caller must be holding the appropriate bucket lock.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence isc_task_sendanddetach(&task, (isc_event_t **)&event);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerfctx_done(fetchctx_t *fctx, isc_result_t result) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Bristerresquery_senddone(isc_task_t *task, isc_event_t *event) {
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister isc_socketevent_t *sevent = (isc_socketevent_t *)event;
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence REQUIRE(event->type == ISC_SOCKEVENT_SENDDONE);
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * Currently we don't wait for the senddone event before retrying
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * a query. This means that if we get really behind, we may end
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister * up doing extra work!
2cde028c51055c9fd4837337116cd4fdfe8ff623James Brister fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
590f840d3484114576d9f8a7f7d73fbe31228888Brian Wellington result = dns_message_gettemprdatalist(message, &rdatalist);
590f840d3484114576d9f8a7f7d73fbe31228888Brian Wellington result = dns_message_gettemprdata(message, &rdata);
590f840d3484114576d9f8a7f7d73fbe31228888Brian Wellington result = dns_message_gettemprdataset(message, &rdataset);
590f840d3484114576d9f8a7f7d73fbe31228888Brian Wellington * Set Maximum UDP buffer size.
590f840d3484114576d9f8a7f7d73fbe31228888Brian Wellington * Set EXTENDED-RCODE, VERSION, and Z to 0.
600cbd1fcea3c9cc9706dc1ff8fc0d0034ebdeacTatuya JINMEI 神明達哉 * No ENDS options.
600cbd1fcea3c9cc9706dc1ff8fc0d0034ebdeacTatuya JINMEI 神明達哉 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
600cbd1fcea3c9cc9706dc1ff8fc0d0034ebdeacTatuya JINMEI 神明達哉 dns_rdatalist_tordataset(rdatalist, rdataset);
600cbd1fcea3c9cc9706dc1ff8fc0d0034ebdeacTatuya JINMEI 神明達哉 return (dns_message_setopt(message, rdataset));
600cbd1fcea3c9cc9706dc1ff8fc0d0034ebdeacTatuya JINMEI 神明達哉static inline void
600cbd1fcea3c9cc9706dc1ff8fc0d0034ebdeacTatuya JINMEI 神明達哉fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) {
600cbd1fcea3c9cc9706dc1ff8fc0d0034ebdeacTatuya JINMEI 神明達哉 * We retry every 2 seconds the first two times through the address
600cbd1fcea3c9cc9706dc1ff8fc0d0034ebdeacTatuya JINMEI 神明達哉 * list, and then we do exponential back-off.
600cbd1fcea3c9cc9706dc1ff8fc0d0034ebdeacTatuya JINMEI 神明達哉 * Double the round-trip time and convert to seconds.
static isc_result_t
unsigned int options)
return (result);
goto stop_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;
return (ISC_R_SUCCESS);
NULL);
return (result);
(void)task;
unsigned int bucketnum;
(void)task;
if (want_try)
else if (want_done)
else if (bucket_empty)
static isc_result_t
isc_region_t r;
return (DNS_R_SERVFAIL);
goto out;
&find);
return (result);
out:
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);
#ifdef notyet
static inline isc_result_t
void *data;
unsigned int options;
return (result);
return (result);
&node);
return (result);
#ifdef notyet
&validation);
options = 0;
eresult =
eresult =
return (result);
static inline isc_result_t
section++) {
&name);
return (result);
static inline isc_result_t
void *data;
return (result);
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);
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;
(void)task;
covers = 0;
goto done;
switch (result) {
case DNS_R_UNEXPECTEDEND:
goto done;
case DNS_R_FORMERR:
goto done;
case DNS_R_MOREDATA:
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);
(void)task;
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;
(void)forwarders;
return (ISC_R_NOMEMORY);
goto unlock;
goto unlock;
if (new_fctx) {
return (result);
link);
unsigned int bucketnum;
if (bucket_empty)