2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 14:35:26 +00:00

Fix transfer of glue records in stub zones if master has minimal-responses set

Stub zones don't make use of AXFR/IXFR for the transfering of zone
data, instead, a single query is issued to the master asking for
their nameserver records (NS).

That works fine unless master is configured with 'minimal-responses'
set to yes, in which case glue records are not provided by master
in the answer with nameservers authoritative for the zone, leaving
stub zones with incomplete databases.

This commit fix this problem in a simple way, when the answer with
the authoritative nameservers is received from master (stub_callback),
for each nameserver listed (save_nsrrset), a A and AAAA records for
the name is verified in the additional section, and if not present
a query is created to resolve the corresponsing missing glue.

A struct 'stub_cb_args' was added to keep relevant information for
performing a query, like TSIG key, udp size, dscp value, etc, this
information is borrowed from, and created within function 'ns_query',
where the resolving of nameserver from master starts.

A new field was added to the struct 'dns_stub', an atomic integer,
namely pending_requests, which is used to keep how many queries are
created when resolving nameserver addresses that were missing in
the glue.

When the value of pending_requests is zero we know we can release
resources, adjust zone timers, dump to zone file, etc.
This commit is contained in:
Diego Fronza
2020-09-10 15:09:14 -03:00
parent 803d12d430
commit 1cee557993

View File

@@ -614,6 +614,7 @@ struct dns_stub {
dns_zone_t *zone;
dns_db_t *db;
dns_dbversion_t *version;
atomic_uint_fast32_t pending_requests;
};
/*%
@@ -937,6 +938,22 @@ struct ssevent {
uint32_t serial;
};
struct stub_cb_args {
dns_stub_t *stub;
dns_tsigkey_t *tsig_key;
isc_dscp_t dscp;
uint16_t udpsize;
int timeout;
bool reqnsid;
};
struct stub_glue_request {
dns_request_t *request;
dns_name_t name;
struct stub_cb_args *args;
bool ipv4;
};
/*%
* Increment resolver-related statistics counters. Zone must be locked.
*/
@@ -12491,9 +12508,395 @@ cleanup1:
/***
*** Private
***/
static inline isc_result_t
create_query(dns_zone_t *zone, dns_rdatatype_t rdtype, dns_name_t *name,
dns_message_t **messagep) {
dns_message_t *message = NULL;
dns_name_t *qname = NULL;
dns_rdataset_t *qrdataset = NULL;
isc_result_t result;
dns_message_create(zone->mctx, DNS_MESSAGE_INTENTRENDER, &message);
message->opcode = dns_opcode_query;
message->rdclass = zone->rdclass;
result = dns_message_gettempname(message, &qname);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
result = dns_message_gettemprdataset(message, &qrdataset);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
/*
* Make question.
*/
dns_name_init(qname, NULL);
dns_name_clone(name, qname);
dns_rdataset_makequestion(qrdataset, zone->rdclass, rdtype);
ISC_LIST_APPEND(qname->list, qrdataset, link);
dns_message_addname(message, qname, DNS_SECTION_QUESTION);
*messagep = message;
return (ISC_R_SUCCESS);
cleanup:
if (qname != NULL) {
dns_message_puttempname(message, &qname);
}
if (qrdataset != NULL) {
dns_message_puttemprdataset(message, &qrdataset);
}
dns_message_detach(&message);
return (result);
}
static isc_result_t
add_opt(dns_message_t *message, uint16_t udpsize, bool reqnsid,
bool reqexpire) {
isc_result_t result;
dns_rdataset_t *rdataset = NULL;
dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS];
int count = 0;
/* Set EDNS options if applicable. */
if (reqnsid) {
INSIST(count < DNS_EDNSOPTIONS);
ednsopts[count].code = DNS_OPT_NSID;
ednsopts[count].length = 0;
ednsopts[count].value = NULL;
count++;
}
if (reqexpire) {
INSIST(count < DNS_EDNSOPTIONS);
ednsopts[count].code = DNS_OPT_EXPIRE;
ednsopts[count].length = 0;
ednsopts[count].value = NULL;
count++;
}
result = dns_message_buildopt(message, &rdataset, 0, udpsize, 0,
ednsopts, count);
if (result != ISC_R_SUCCESS) {
return (result);
}
return (dns_message_setopt(message, rdataset));
}
/*
* Called when stub zone update is finished.
* Update zone refresh, retry, expire values accordingly with
* SOA received from master, sync database to file, restart
* zone management timer.
*/
static void
stub_finish_zone_update(dns_stub_t *stub, isc_time_t now) {
uint32_t refresh, retry, expire;
isc_result_t result;
isc_interval_t i;
unsigned int soacount;
dns_zone_t *zone = stub->zone;
/*
* Tidy up.
*/
dns_db_closeversion(stub->db, &stub->version, true);
ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write);
if (zone->db == NULL) {
zone_attachdb(zone, stub->db);
}
result = zone_get_from_db(zone, zone->db, NULL, &soacount, NULL,
&refresh, &retry, &expire, NULL, NULL);
if (result == ISC_R_SUCCESS && soacount > 0U) {
zone->refresh = RANGE(refresh, zone->minrefresh,
zone->maxrefresh);
zone->retry = RANGE(retry, zone->minretry, zone->maxretry);
zone->expire = RANGE(expire, zone->refresh + zone->retry,
DNS_MAX_EXPIRE);
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS);
}
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);
dns_db_detach(&stub->db);
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH);
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED);
DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime);
isc_interval_set(&i, zone->expire, 0);
DNS_ZONE_TIME_ADD(&now, zone->expire, &zone->expiretime);
if (zone->masterfile != NULL) {
zone_needdump(zone, 0);
}
zone_settimer(zone, &now);
}
/*
* Process answers for A and AAAA queries when
* resolving nameserver addresses for which glue
* was missing in a previous answer for a NS query.
*/
static void
stub_glue_response_cb(isc_task_t *task, isc_event_t *event) {
const char me[] = "stub_glue_response_cb";
dns_requestevent_t *revent = (dns_requestevent_t *)event;
dns_stub_t *stub = NULL;
dns_message_t *msg = NULL;
dns_zone_t *zone = NULL;
char master[ISC_SOCKADDR_FORMATSIZE];
char source[ISC_SOCKADDR_FORMATSIZE];
uint32_t addr_count, cnamecnt;
isc_result_t result;
isc_time_t now;
struct stub_glue_request *request;
struct stub_cb_args *cb_args;
dns_rdataset_t *addr_rdataset = NULL;
dns_dbnode_t *node = NULL;
UNUSED(task);
request = revent->ev_arg;
cb_args = request->args;
stub = cb_args->stub;
INSIST(DNS_STUB_VALID(stub));
zone = stub->zone;
ENTER;
TIME_NOW(&now);
LOCK_ZONE(zone);
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) {
zone_debuglog(zone, me, 1, "exiting");
goto cleanup;
}
isc_sockaddr_format(&zone->masteraddr, master, sizeof(master));
isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source));
if (revent->result != ISC_R_SUCCESS) {
dns_zonemgr_unreachableadd(zone->zmgr, &zone->masteraddr,
&zone->sourceaddr, &now);
dns_zone_log(zone, ISC_LOG_INFO,
"could not refresh stub from master %s"
" (source %s): %s",
master, source, dns_result_totext(revent->result));
goto cleanup;
}
dns_message_create(zone->mctx, DNS_MESSAGE_INTENTPARSE, &msg);
result = dns_request_getresponse(revent->request, msg, 0);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_INFO,
"refreshing stub: unable to parse response (%s)",
isc_result_totext(result));
goto cleanup;
}
/*
* Unexpected rcode.
*/
if (msg->rcode != dns_rcode_noerror) {
char rcode[128];
isc_buffer_t rb;
isc_buffer_init(&rb, rcode, sizeof(rcode));
(void)dns_rcode_totext(msg->rcode, &rb);
dns_zone_log(zone, ISC_LOG_INFO,
"refreshing stub: "
"unexpected rcode (%.*s) from %s (source %s)",
(int)rb.used, rcode, master, source);
goto cleanup;
}
/*
* We need complete messages.
*/
if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) {
if (dns_request_usedtcp(revent->request)) {
dns_zone_log(zone, ISC_LOG_INFO,
"refreshing stub: truncated TCP "
"response from master %s (source %s)",
master, source);
}
goto cleanup;
}
/*
* If non-auth log.
*/
if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0) {
dns_zone_log(zone, ISC_LOG_INFO,
"refreshing stub: "
"non-authoritative answer from "
"master %s (source %s)",
master, source);
goto cleanup;
}
/*
* Sanity checks.
*/
cnamecnt = message_count(msg, DNS_SECTION_ANSWER, dns_rdatatype_cname);
addr_count = message_count(msg, DNS_SECTION_ANSWER,
request->ipv4 ? dns_rdatatype_a
: dns_rdatatype_aaaa);
if (cnamecnt != 0) {
dns_zone_log(zone, ISC_LOG_INFO,
"refreshing stub: unexpected CNAME response "
"from master %s (source %s)",
master, source);
goto cleanup;
}
if (addr_count == 0) {
dns_zone_log(zone, ISC_LOG_INFO,
"refreshing stub: no %s records in response "
"from master %s (source %s)",
request->ipv4 ? "A" : "AAAA", master, source);
goto cleanup;
}
/*
* Extract A or AAAA RRset from message.
*/
result = dns_message_findname(msg, DNS_SECTION_ANSWER, &request->name,
request->ipv4 ? dns_rdatatype_a
: dns_rdatatype_aaaa,
dns_rdatatype_none, NULL, &addr_rdataset);
if (result != ISC_R_SUCCESS) {
if (result != DNS_R_NXDOMAIN && result != DNS_R_NXRRSET) {
char namebuf[DNS_NAME_FORMATSIZE];
dns_name_format(&request->name, namebuf,
sizeof(namebuf));
dns_zone_log(
zone, ISC_LOG_INFO,
"refreshing stub: dns_message_findname(%s/%s) "
"failed (%s)",
namebuf, request->ipv4 ? "A" : "AAAA",
isc_result_totext(result));
}
goto cleanup;
}
result = dns_db_findnode(stub->db, &request->name, true, &node);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_INFO,
"refreshing stub: "
"dns_db_findnode() failed: %s",
dns_result_totext(result));
goto cleanup;
}
result = dns_db_addrdataset(stub->db, node, stub->version, 0,
addr_rdataset, 0, NULL);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_INFO,
"refreshing stub: "
"dns_db_addrdataset() failed: %s",
dns_result_totext(result));
}
dns_db_detachnode(stub->db, &node);
cleanup:
if (msg != NULL) {
dns_message_detach(&msg);
}
isc_event_free(&event);
dns_name_free(&request->name, zone->mctx);
dns_request_destroy(&request->request);
isc_mem_put(zone->mctx, request, sizeof(*request));
/* If last request, release all related resources */
if (atomic_fetch_sub_release(&stub->pending_requests, 1) == 1) {
isc_mem_put(zone->mctx, cb_args, sizeof(*cb_args));
stub_finish_zone_update(stub, now);
UNLOCK_ZONE(zone);
stub->magic = 0;
dns_zone_idetach(&stub->zone);
INSIST(stub->db == NULL);
INSIST(stub->version == NULL);
isc_mem_put(stub->mctx, stub, sizeof(*stub));
} else {
UNLOCK_ZONE(zone);
}
}
/*
* Create and send an A or AAAA query to the master
* server of the stub zone given.
*/
static isc_result_t
stub_request_nameserver_address(struct stub_cb_args *args, bool ipv4,
const dns_name_t *name) {
dns_message_t *message = NULL;
dns_zone_t *zone;
isc_result_t result;
struct stub_glue_request *request;
zone = args->stub->zone;
request = isc_mem_get(zone->mctx, sizeof(*request));
request->request = NULL;
request->args = args;
request->name = (dns_name_t)DNS_NAME_INITEMPTY;
request->ipv4 = ipv4;
dns_name_dup(name, zone->mctx, &request->name);
result = create_query(zone, ipv4 ? dns_rdatatype_a : dns_rdatatype_aaaa,
&request->name, &message);
INSIST(result == ISC_R_SUCCESS);
if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) {
result = add_opt(message, args->udpsize, args->reqnsid, false);
if (result != ISC_R_SUCCESS) {
zone_debuglog(zone, "stub_send_query", 1,
"unable to add opt record: %s",
dns_result_totext(result));
goto fail;
}
}
atomic_fetch_add_release(&args->stub->pending_requests, 1);
result = dns_request_createvia(
zone->view->requestmgr, message, &zone->sourceaddr,
&zone->masteraddr, args->dscp, DNS_REQUESTOPT_TCP,
args->tsig_key, args->timeout * 3, args->timeout, 0, zone->task,
stub_glue_response_cb, request, &request->request);
if (result != ISC_R_SUCCESS) {
INSIST(atomic_fetch_sub_release(&args->stub->pending_requests,
1) > 1);
zone_debuglog(zone, "stub_send_query", 1,
"dns_request_createvia() failed: %s",
dns_result_totext(result));
goto fail;
}
dns_message_detach(&message);
return (ISC_R_SUCCESS);
fail:
dns_name_free(&request->name, zone->mctx);
isc_mem_put(zone->mctx, request, sizeof(*request));
if (message != NULL) {
dns_message_detach(&message);
}
return (result);
}
static inline isc_result_t
save_nsrrset(dns_message_t *message, dns_name_t *name, dns_db_t *db,
save_nsrrset(dns_message_t *message, dns_name_t *name,
struct stub_cb_args *cb_args, dns_db_t *db,
dns_dbversion_t *version) {
dns_rdataset_t *nsrdataset = NULL;
dns_rdataset_t *rdataset = NULL;
@@ -12501,6 +12904,14 @@ save_nsrrset(dns_message_t *message, dns_name_t *name, dns_db_t *db,
dns_rdata_ns_t ns;
isc_result_t result;
dns_rdata_t rdata = DNS_RDATA_INIT;
bool has_glue = false;
dns_name_t *ns_name;
/*
* List of NS entries in answer, keep names that will be used
* to resolve missing A/AAAA glue for each entry.
*/
dns_namelist_t ns_list;
ISC_LIST_INIT(ns_list);
/*
* Extract NS RRset from message.
@@ -12509,7 +12920,7 @@ save_nsrrset(dns_message_t *message, dns_name_t *name, dns_db_t *db,
dns_rdatatype_ns, dns_rdatatype_none,
NULL, &nsrdataset);
if (result != ISC_R_SUCCESS) {
goto fail;
goto done;
}
/*
@@ -12517,12 +12928,12 @@ save_nsrrset(dns_message_t *message, dns_name_t *name, dns_db_t *db,
*/
result = dns_db_findnode(db, name, true, &node);
if (result != ISC_R_SUCCESS) {
goto fail;
goto done;
}
result = dns_db_addrdataset(db, node, version, 0, nsrdataset, 0, NULL);
dns_db_detachnode(db, &node);
if (result != ISC_R_SUCCESS) {
goto fail;
goto done;
}
/*
* Add glue rdatasets.
@@ -12534,6 +12945,7 @@ save_nsrrset(dns_message_t *message, dns_name_t *name, dns_db_t *db,
result = dns_rdata_tostruct(&rdata, &ns, NULL);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
dns_rdata_reset(&rdata);
if (!dns_name_issubdomain(&ns.name, name)) {
continue;
}
@@ -12543,41 +12955,92 @@ save_nsrrset(dns_message_t *message, dns_name_t *name, dns_db_t *db,
dns_rdatatype_none, NULL,
&rdataset);
if (result == ISC_R_SUCCESS) {
has_glue = true;
result = dns_db_findnode(db, &ns.name, true, &node);
if (result != ISC_R_SUCCESS) {
goto fail;
goto done;
}
result = dns_db_addrdataset(db, node, version, 0,
rdataset, 0, NULL);
dns_db_detachnode(db, &node);
if (result != ISC_R_SUCCESS) {
goto fail;
goto done;
}
}
rdataset = NULL;
result = dns_message_findname(
message, DNS_SECTION_ADDITIONAL, &ns.name,
dns_rdatatype_a, dns_rdatatype_none, NULL, &rdataset);
if (result == ISC_R_SUCCESS) {
has_glue = true;
result = dns_db_findnode(db, &ns.name, true, &node);
if (result != ISC_R_SUCCESS) {
goto fail;
goto done;
}
result = dns_db_addrdataset(db, node, version, 0,
rdataset, 0, NULL);
dns_db_detachnode(db, &node);
if (result != ISC_R_SUCCESS) {
goto fail;
goto done;
}
}
/*
* If no glue is found so far, we add the name to the list to
* resolve the A/AAAA glue later. If any glue is found in any
* iteration step, this list will be discarded and only the glue
* provided in this message will be used.
*/
if (!has_glue && dns_name_issubdomain(&ns.name, name)) {
dns_name_t *tmp_name;
tmp_name = isc_mem_get(cb_args->stub->mctx,
sizeof(*tmp_name));
dns_name_init(tmp_name, NULL);
dns_name_dup(&ns.name, cb_args->stub->mctx, tmp_name);
ISC_LIST_APPEND(ns_list, tmp_name, link);
}
}
if (result != ISC_R_NOMORE) {
goto done;
}
/*
* If no glue records were found, we attempt to resolve A/AAAA
* for each NS entry found in the answer.
*/
if (!has_glue) {
for (ns_name = ISC_LIST_HEAD(ns_list); ns_name != NULL;
ns_name = ISC_LIST_NEXT(ns_name, link))
{
/*
* Resolve NS IPv4 address/A.
*/
result = stub_request_nameserver_address(cb_args, true,
ns_name);
if (result != ISC_R_SUCCESS) {
goto done;
}
/*
* Resolve NS IPv6 address/AAAA.
*/
result = stub_request_nameserver_address(cb_args, false,
ns_name);
if (result != ISC_R_SUCCESS) {
goto done;
}
}
}
if (result != ISC_R_NOMORE) {
goto fail;
result = ISC_R_SUCCESS;
done:
while ((ns_name = ISC_LIST_HEAD(ns_list)) != NULL) {
ISC_LIST_UNLINK(ns_list, ns_name, link);
dns_name_free(ns_name, cb_args->stub->mctx);
isc_mem_put(cb_args->stub->mctx, ns_name, sizeof(*ns_name));
}
return (ISC_R_SUCCESS);
fail:
return (result);
}
@@ -12590,14 +13053,15 @@ stub_callback(isc_task_t *task, isc_event_t *event) {
dns_zone_t *zone = NULL;
char master[ISC_SOCKADDR_FORMATSIZE];
char source[ISC_SOCKADDR_FORMATSIZE];
uint32_t nscnt, cnamecnt, refresh, retry, expire;
uint32_t nscnt, cnamecnt;
isc_result_t result;
isc_time_t now;
bool exiting = false;
isc_interval_t i;
unsigned int j, soacount;
unsigned int j;
struct stub_cb_args *cb_args;
stub = revent->ev_arg;
cb_args = revent->ev_arg;
stub = cb_args->stub;
INSIST(DNS_STUB_VALID(stub));
UNUSED(task);
@@ -12725,10 +13189,13 @@ stub_callback(isc_task_t *task, isc_event_t *event) {
goto next_master;
}
atomic_fetch_add(&stub->pending_requests, 1);
/*
* Save answer.
*/
result = save_nsrrset(msg, &zone->origin, stub->db, stub->version);
result = save_nsrrset(msg, &zone->origin, cb_args, stub->db,
stub->version);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_INFO,
"refreshing stub: unable to save NS records "
@@ -12737,45 +13204,25 @@ stub_callback(isc_task_t *task, isc_event_t *event) {
goto next_master;
}
/*
* Tidy up.
*/
dns_db_closeversion(stub->db, &stub->version, true);
ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write);
if (zone->db == NULL) {
zone_attachdb(zone, stub->db);
}
result = zone_get_from_db(zone, zone->db, NULL, &soacount, NULL,
&refresh, &retry, &expire, NULL, NULL);
if (result == ISC_R_SUCCESS && soacount > 0U) {
zone->refresh = RANGE(refresh, zone->minrefresh,
zone->maxrefresh);
zone->retry = RANGE(retry, zone->minretry, zone->maxretry);
zone->expire = RANGE(expire, zone->refresh + zone->retry,
DNS_MAX_EXPIRE);
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_HAVETIMERS);
}
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);
dns_db_detach(&stub->db);
dns_message_detach(&msg);
isc_event_free(&event);
dns_request_destroy(&zone->request);
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH);
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED);
DNS_ZONE_JITTER_ADD(&now, zone->refresh, &zone->refreshtime);
isc_interval_set(&i, zone->expire, 0);
DNS_ZONE_TIME_ADD(&now, zone->expire, &zone->expiretime);
if (zone->masterfile != NULL) {
zone_needdump(zone, 0);
/*
* Check to see if there are no outstanding requests and
* finish off if that is so.
*/
if (atomic_fetch_sub(&stub->pending_requests, 1) == 1) {
isc_mem_put(zone->mctx, cb_args, sizeof(*cb_args));
stub_finish_zone_update(stub, now);
goto free_stub;
}
zone_settimer(zone, &now);
goto free_stub;
UNLOCK_ZONE(zone);
return;
next_master:
isc_mem_put(zone->mctx, cb_args, sizeof(*cb_args));
if (stub->version != NULL) {
dns_db_closeversion(stub->db, &stub->version, false);
}
@@ -12836,6 +13283,7 @@ next_master:
goto free_stub;
same_master:
isc_mem_put(zone->mctx, cb_args, sizeof(*cb_args));
if (msg != NULL) {
dns_message_detach(&msg);
}
@@ -13416,84 +13864,6 @@ queue_soa_query(dns_zone_t *zone) {
}
}
static inline isc_result_t
create_query(dns_zone_t *zone, dns_rdatatype_t rdtype,
dns_message_t **messagep) {
dns_message_t *message = NULL;
dns_name_t *qname = NULL;
dns_rdataset_t *qrdataset = NULL;
isc_result_t result;
dns_message_create(zone->mctx, DNS_MESSAGE_INTENTRENDER, &message);
message->opcode = dns_opcode_query;
message->rdclass = zone->rdclass;
result = dns_message_gettempname(message, &qname);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
result = dns_message_gettemprdataset(message, &qrdataset);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
/*
* Make question.
*/
dns_name_init(qname, NULL);
dns_name_clone(&zone->origin, qname);
dns_rdataset_makequestion(qrdataset, zone->rdclass, rdtype);
ISC_LIST_APPEND(qname->list, qrdataset, link);
dns_message_addname(message, qname, DNS_SECTION_QUESTION);
*messagep = message;
return (ISC_R_SUCCESS);
cleanup:
if (qname != NULL) {
dns_message_puttempname(message, &qname);
}
if (qrdataset != NULL) {
dns_message_puttemprdataset(message, &qrdataset);
}
dns_message_detach(&message);
return (result);
}
static isc_result_t
add_opt(dns_message_t *message, uint16_t udpsize, bool reqnsid,
bool reqexpire) {
isc_result_t result;
dns_rdataset_t *rdataset = NULL;
dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS];
int count = 0;
/* Set EDNS options if applicable */
if (reqnsid) {
INSIST(count < DNS_EDNSOPTIONS);
ednsopts[count].code = DNS_OPT_NSID;
ednsopts[count].length = 0;
ednsopts[count].value = NULL;
count++;
}
if (reqexpire) {
INSIST(count < DNS_EDNSOPTIONS);
ednsopts[count].code = DNS_OPT_EXPIRE;
ednsopts[count].length = 0;
ednsopts[count].value = NULL;
count++;
}
result = dns_message_buildopt(message, &rdataset, 0, udpsize, 0,
ednsopts, count);
if (result != ISC_R_SUCCESS) {
return (result);
}
return (dns_message_setopt(message, rdataset));
}
static void
soa_query(isc_task_t *task, isc_event_t *event) {
const char me[] = "soa_query";
@@ -13528,7 +13898,7 @@ soa_query(isc_task_t *task, isc_event_t *event) {
}
again:
result = create_query(zone, dns_rdatatype_soa, &message);
result = create_query(zone, dns_rdatatype_soa, &zone->origin, &message);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
@@ -13729,6 +14099,7 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) {
bool reqnsid;
uint16_t udpsize = SEND_BUFFER_SIZE;
isc_dscp_t dscp = -1;
struct stub_cb_args *cb_args;
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(LOCKED_ZONE(zone));
@@ -13745,6 +14116,7 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) {
stub->zone = NULL;
stub->db = NULL;
stub->version = NULL;
atomic_init(&stub->pending_requests, 0);
/*
* Attach so that the zone won't disappear from under us.
@@ -13815,7 +14187,7 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) {
/*
* XXX Optimisation: Create message when zone is setup and reuse.
*/
result = create_query(zone, dns_rdatatype_ns, &message);
result = create_query(zone, dns_rdatatype_ns, &zone->origin, &message);
INSIST(result == ISC_R_SUCCESS);
INSIST(zone->masterscnt > 0);
@@ -13920,10 +14292,21 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) {
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALREFRESH)) {
timeout = 30;
}
/* Save request parameters so we can reuse them later on
for resolving missing glue A/AAAA records. */
cb_args = isc_mem_get(zone->mctx, sizeof(*cb_args));
cb_args->stub = stub;
cb_args->tsig_key = key;
cb_args->dscp = dscp;
cb_args->udpsize = udpsize;
cb_args->timeout = timeout;
cb_args->reqnsid = reqnsid;
result = dns_request_createvia(
zone->view->requestmgr, message, &zone->sourceaddr,
&zone->masteraddr, dscp, DNS_REQUESTOPT_TCP, key, timeout * 3,
timeout, 0, zone->task, stub_callback, stub, &zone->request);
timeout, 0, zone->task, stub_callback, cb_args, &zone->request);
if (result != ISC_R_SUCCESS) {
zone_debuglog(zone, me, 1, "dns_request_createvia() failed: %s",
dns_result_totext(result));