resolver.c revision 6fe8621e7fa1daaf3bec4f4fb36e17289baef7d4
431a83fb29482c5170b3e4026e59bb14849a6707Tinderbox User * Copyright (C) 1999 Internet Software Consortium.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * Permission to use, copy, modify, and distribute this software for any
ec5347e2c775f027573ce5648b910361aa926c01Automatic Updater * purpose with or without fee is hereby granted, provided that the above
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * 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
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews "res %p: %s", (r), (m))
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews "fetch %p (fctx %p): %s", \
add4043305ca411202ed9cf1929a4179016515ceBrian Wellington "resquery %p (fctx %p): %s", \
5fc7ba3e1ac5d72239e9971e0f469dd5796738f9Andreas Gustafssontypedef struct query {
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff /* Not locked. */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence unsigned int magic;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews /* Locked by fctx lock. */
9f139761ca06977d1db8051842efc620c15b8199Andreas Gustafsson#define QUERY_MAGIC 0x51212121U /* Q!!! */
e502b133d630bda0ee64c1e2ce6729d96750d8abMark Andrews#define VALID_QUERY(query) ((query) != NULL && \
af669cb4fd7ecfb67ed145b176e5e764b249573bMark Andrewstypedef enum {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews /* Not locked. */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews unsigned int magic;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews unsigned int options;
5fc7ba3e1ac5d72239e9971e0f469dd5796738f9Andreas Gustafsson /* Locked by lock. */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews /* Only changable by event actions running in the context's task */
5fc7ba3e1ac5d72239e9971e0f469dd5796738f9Andreas Gustafsson#define VALID_FCTX(fctx) ((fctx) != NULL && \
5fc7ba3e1ac5d72239e9971e0f469dd5796738f9Andreas Gustafsson#define DNS_FETCH_MAGIC 0x46746368U /* Ftch */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews#define DNS_FETCH_VALID(fetch) ((fetch) != NULL && \
9f139761ca06977d1db8051842efc620c15b8199Andreas Gustafssontypedef struct fctxbucket {
bf33eb0b522801792a6663b0360bc94b9e9b77c2Automatic Updater /* Unlocked */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews unsigned int magic;
ae114ded82e773a4d9058f833f964a17514712a8Brian Wellington /* Locked by lock. */
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff#define VALID_RESOLVER(res) ((res) != NULL && \
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic void resquery_response(isc_task_t *task, isc_event_t *event);
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff return (isc_timer_reset(fctx->timer, isc_timertype_once,
cdc50af0bff41accc02c613b9c6d8cd41b171ffeBrian Wellington return (isc_timer_reset(fctx->timer, isc_timertype_once,
94a08e09db3dc844b6ee4841c368a2d7074a9c3fAndreas Gustafssonstatic inline void
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * We don't return a result if resetting the timer to inactive fails
8dd2e6e7c1328ba00d734ce939777e06d9a15493Michael Graff * since there's nothing to be done about it. Resetting to inactive
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * should never fail anyway, since the code as currently written
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * cannot fail in that case.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews result = isc_timer_reset(fctx->timer, isc_timertype_inactive,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews "isc_timer_reset(): %s",
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsstatic inline void
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Grafffctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp) {
e6c22f37d8df55a9f66b479a22717e179bcf79a3Andreas Gustafsson dns_dispatch_removeresponse(query->dispatch, &query->dispentry,
b589e90689c6e87bf9608424ca8d99571c18bc61Mark Andrews isc_mem_put(fctx->res->mctx, query, sizeof *query);
e6c22f37d8df55a9f66b479a22717e179bcf79a3Andreas Gustafsson next_address = ISC_LIST_NEXT(address, link);
e6c22f37d8df55a9f66b479a22717e179bcf79a3Andreas Gustafsson isc_mem_put(fctx->res->mctx, address, sizeof *address);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsfctx_done(fetchctx_t *fctx, isc_result_t result) {
63cef8bde8b92aeb30ccdcf21d4e44c9be9cc6e3Andreas Gustafsson LOCK(&res->buckets[fctx->bucketnum].lock);
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff isc_task_sendanddetach(&task, (isc_event_t **)&event);
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews * XXXRTH check for finished state.
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrewsresquery_senddone(isc_task_t *task, isc_event_t *event) {
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews isc_socketevent_t *sevent = (isc_socketevent_t *)event;
a560a0bfb2fd48ddd1900f61a655397a5c4f7343Mark Andrews REQUIRE(event->type == ISC_SOCKEVENT_SENDDONE);
05f90cac85760b4edef2962209df49ea019c180fMark Andrews * Currently we don't wait for the senddone event before retrying
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews * a query. This means that if we get really behind, we may end
05f90cac85760b4edef2962209df49ea019c180fMark Andrews * up doing extra work!
a560a0bfb2fd48ddd1900f61a655397a5c4f7343Mark Andrewsfctx_sendquery(fetchctx_t *fctx, isc_sockaddr_t *address) {
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE);
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews result = dns_message_gettempname(fctx->qmessage, &qname);
8dd2e6e7c1328ba00d734ce939777e06d9a15493Michael Graff result = dns_message_gettemprdataset(fctx->qmessage, &qrdataset);
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews isc_buffer_init(&query->buffer, query->data, sizeof query->data,
90f9d00f087ddb4442d1ebf628c1bcaff18226a0Andreas Gustafsson * If this is a TCP query, then we need to make a socket and
8dd2e6e7c1328ba00d734ce939777e06d9a15493Michael Graff * a dispatch for it here. Otherwise we use the resolver's
8dd2e6e7c1328ba00d734ce939777e06d9a15493Michael Graff * shared dispatch. We do not attach to the resolver's shared
d981ca645597116d227a48bf37cc5edc061c854dBob Halley * dispatch if we use it, so the resolver MUST ensure that no
8dd2e6e7c1328ba00d734ce939777e06d9a15493Michael Graff * fetches are running before changing the shared dispatch.
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff if ((fctx->options & DNS_FETCHOPT_TCP) != 0) {
d981ca645597116d227a48bf37cc5edc061c854dBob Halley /* XXXRTH */
e27a69f8bd9538e08f775265167ba6cc5f47c587Bob Halley * We should always have a valid dispatcher here. If we
e27a69f8bd9538e08f775265167ba6cc5f47c587Bob Halley * don't support a protocol family, then its dispatcher
8dd2e6e7c1328ba00d734ce939777e06d9a15493Michael Graff * will be NULL, but we shouldn't be finding addresses for
e27a69f8bd9538e08f775265167ba6cc5f47c587Bob Halley * protocol types we don't support, so the dispatcher
e27a69f8bd9538e08f775265167ba6cc5f47c587Bob Halley * we found should never be NULL.
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews * Get a query id from the dispatch.
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews result = dns_dispatch_addresponse(query->dispatch,
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews * Set up question.
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews dns_rdataset_makequestion(qrdataset, res->rdclass, fctx->type);
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews dns_message_addname(fctx->qmessage, qname, DNS_SECTION_QUESTION);
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews if ((fctx->options & DNS_FETCHOPT_RECURSIVE) != 0)
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews * We don't have to set opcode because it defaults to query.
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews * XXXRTH Add TSIG and/or ENDS0 OPT record tailored to the current
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews * recipient.
3d17a3ba61a303d5c4d9867068d0fbe9f24d2988Mark Andrews * Convert the question to wire format.
3d17a3ba61a303d5c4d9867068d0fbe9f24d2988Mark Andrews result = dns_message_renderbegin(fctx->qmessage, &query->buffer);
goto cleanup_message;
DNS_SECTION_QUESTION, 0, 0);
goto cleanup_message;
DNS_SECTION_ADDITIONAL, 0, 0);
goto cleanup_message;
goto cleanup_message;
goto cleanup_message;
return (ISC_R_SUCCESS);
NULL);
return (result);
static isc_result_t
isc_region_t r;
sizeof *address);
link);
return (result);
INSIST(0);
static isc_boolean_t
unsigned int bucketnum;
return (ISC_TRUE);
return (ISC_FALSE);
unsigned int bucketnum;
if (need_done)
else 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;
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);
static inline isc_result_t
void *data;
return (result);
return (result);
&node);
return (result);
if (need_validation) {
return (DNS_R_NOTIMPLEMENTED);
eresult =
eresult =
return (result);
static inline isc_result_t
return (result);
section++) {
&name);
return (result);
static inline isc_result_t
void *data;
return (result);
return (result);
goto unlock;
&node);
goto unlock;
goto unlock;
return (result);
if (external)
static isc_result_t
NULL);
&rdataset);
* 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 (DNS_R_FORMERR);
* query.c. We don't want to return
(void)dns_rdataset_additionaldata(
fctx);
return (DNS_R_FORMERR);
if (aa)
return (result);
return (ISC_R_SUCCESS);
return (DNS_R_FORMERR);
return (DNS_R_FORMERR);
return (ISC_R_SUCCESS);
return (DNS_R_FORMERR);
return (result);
return (DNS_R_DELEGATION);
return (ISC_R_SUCCESS);
static inline 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);
(void)task;
covers = 0;
switch (result) {
case DNS_R_FORMERR:
case DNS_R_UNEXPECTEDEND:
case DNS_R_MOREDATA:
goto done;
goto done;
goto done;
goto done;
goto done;
goto done;
goto done;
goto done;
done:
if (keep_trying) {
if (get_nameservers) {
dns_rdatatype_ns, 0, 0,
NULL);
if (need_destroy)
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_buckets;
goto cleanup_udpsocket4;
goto cleanup_dispatch4;
goto cleanup_udpsocket6;
goto cleanup_dispatch6;
return (ISC_R_SUCCESS);
for (i = 0; i < buckets_created; i++) {
return (result);
if (need_destroy)
static inline isc_boolean_t
unsigned int options)
return (ISC_FALSE);
unsigned int bucketnum;
(void)forwarders;
return (DNS_R_NOTIMPLEMENTED);
return (ISC_R_NOMEMORY);
goto unlock;
goto unlock;
if (new_fctx) {
return (result);
link);
&cevent);