2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 22:15:20 +00:00

4020. [bug] Change 3736 broke nsupdate's SOA MNAME discovery

resulting in updates being sent to the wrong server.
                        [RT #37925]
This commit is contained in:
Mark Andrews
2014-12-05 18:26:38 +11:00
parent 017aa9aef6
commit 03fd9cb81c
3 changed files with 159 additions and 57 deletions

View File

@@ -1,3 +1,7 @@
4020. [bug] Change 3736 broke nsupdate's SOA MNAME discovery
resulting in updates being sent to the wrong server.
[RT #37925]
4019. [func] If named is not configured to validate the answer 4019. [func] If named is not configured to validate the answer
then allow fallback to plain DNS on timeout even then allow fallback to plain DNS on timeout even
when we know the server supports EDNS. [RT #37978] when we know the server supports EDNS. [RT #37978]

View File

@@ -160,10 +160,14 @@ static dst_key_t *sig0key = NULL;
static lwres_context_t *lwctx = NULL; static lwres_context_t *lwctx = NULL;
static lwres_conf_t *lwconf; static lwres_conf_t *lwconf;
static isc_sockaddr_t *servers = NULL; static isc_sockaddr_t *servers = NULL;
static isc_sockaddr_t *master_servers = NULL;
static isc_boolean_t default_servers = ISC_TRUE; static isc_boolean_t default_servers = ISC_TRUE;
static int ns_inuse = 0; static int ns_inuse = 0;
static int master_inuse = 0;
static int ns_total = 0; static int ns_total = 0;
static isc_sockaddr_t *localaddr = NULL; static int master_total = 0;
static isc_sockaddr_t *localaddr4 = NULL;
static isc_sockaddr_t *localaddr6 = NULL;
static const char *keyfile = NULL; static const char *keyfile = NULL;
static char *keystr = NULL; static char *keystr = NULL;
static isc_entropy_t *entropy = NULL; static isc_entropy_t *entropy = NULL;
@@ -190,8 +194,10 @@ typedef struct nsu_requestinfo {
} nsu_requestinfo_t; } nsu_requestinfo_t;
static void static void
sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, sendrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
dns_message_t *msg, dns_request_t **request); dns_request_t **request);
static void
send_update(dns_name_t *zonename, isc_sockaddr_t *master);
ISC_PLATFORM_NORETURN_PRE static void ISC_PLATFORM_NORETURN_PRE static void
fatal(const char *format, ...) fatal(const char *format, ...)
@@ -218,9 +224,8 @@ typedef struct nsu_gssinfo {
static void static void
start_gssrequest(dns_name_t *master); start_gssrequest(dns_name_t *master);
static void static void
send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, send_gssrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
dns_message_t *msg, dns_request_t **request, dns_request_t **request, gss_ctx_id_t context);
gss_ctx_id_t context);
static void static void
recvgss(isc_task_t *task, isc_event_t *event); recvgss(isc_task_t *task, isc_event_t *event);
#endif /* GSSAPI */ #endif /* GSSAPI */
@@ -295,6 +300,16 @@ cleanup_entropy(isc_entropy_t **ectx) {
isc_entropy_detach(ectx); isc_entropy_detach(ectx);
} }
static void
master_from_servers(void) {
if (master_servers != NULL && master_servers != servers)
isc_mem_put(mctx, master_servers,
master_total * sizeof(isc_sockaddr_t));
master_servers = servers;
master_total = ns_total;
master_inuse = ns_inuse;
}
static dns_rdataclass_t static dns_rdataclass_t
getzoneclass(void) { getzoneclass(void) {
@@ -715,11 +730,22 @@ static void
doshutdown(void) { doshutdown(void) {
isc_task_detach(&global_task); isc_task_detach(&global_task);
/*
* The isc_mem_put of master_servers must be before the
* isc_mem_put of servers must is it NULL the pointer.
*/
if (master_servers != NULL && master_servers != servers)
isc_mem_put(mctx, master_servers,
master_total * sizeof(isc_sockaddr_t));
if (servers != NULL) if (servers != NULL)
isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t)); isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t));
if (localaddr != NULL) if (localaddr4 != NULL)
isc_mem_put(mctx, localaddr, sizeof(isc_sockaddr_t)); isc_mem_put(mctx, localaddr4, sizeof(isc_sockaddr_t));
if (localaddr6 != NULL)
isc_mem_put(mctx, localaddr6, sizeof(isc_sockaddr_t));
if (tsigkey != NULL) { if (tsigkey != NULL) {
ddebug("Freeing TSIG key"); ddebug("Freeing TSIG key");
@@ -825,6 +851,12 @@ setup_system(void) {
(void)lwres_conf_parse(lwctx, RESOLV_CONF); (void)lwres_conf_parse(lwctx, RESOLV_CONF);
lwconf = lwres_conf_get(lwctx); lwconf = lwres_conf_get(lwctx);
if (servers != NULL) {
if (master_servers == servers)
master_servers = NULL;
isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t));
}
ns_inuse = 0; ns_inuse = 0;
if (local_only || lwconf->nsnext <= 0) { if (local_only || lwconf->nsnext <= 0) {
struct in_addr in; struct in_addr in;
@@ -833,11 +865,7 @@ setup_system(void) {
if (local_only && keyfile == NULL) if (local_only && keyfile == NULL)
keyfile = SESSION_KEYFILE; keyfile = SESSION_KEYFILE;
default_servers = ISC_FALSE; default_servers = !local_only;
if (servers != NULL)
isc_mem_put(mctx, servers,
ns_total * sizeof(isc_sockaddr_t));
ns_total = (have_ipv4 ? 1 : 0) + (have_ipv6 ? 1 : 0); ns_total = (have_ipv4 ? 1 : 0) + (have_ipv6 ? 1 : 0);
servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t));
@@ -1425,12 +1453,16 @@ evaluate_server(char *cmdline) {
} }
} }
if (servers != NULL) if (servers != NULL) {
if (master_servers == servers)
master_servers = NULL;
isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t)); isc_mem_put(mctx, servers, ns_total * sizeof(isc_sockaddr_t));
}
default_servers = ISC_FALSE; default_servers = ISC_FALSE;
ns_total = MAX_SERVERADDRS; ns_total = MAX_SERVERADDRS;
ns_inuse = 0;
servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t));
if (servers == NULL) if (servers == NULL)
fatal("out of memory"); fatal("out of memory");
@@ -1471,17 +1503,19 @@ evaluate_local(char *cmdline) {
} }
} }
if (localaddr == NULL) { if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1) {
localaddr = isc_mem_get(mctx, sizeof(isc_sockaddr_t)); if (localaddr6 == NULL)
if (localaddr == NULL) localaddr6 = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
if (localaddr6 == NULL)
fatal("out of memory"); fatal("out of memory");
} isc_sockaddr_fromin6(localaddr6, &in6, (in_port_t)port);
} else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1) {
if (have_ipv6 && inet_pton(AF_INET6, local, &in6) == 1) if (localaddr4 == NULL)
isc_sockaddr_fromin6(localaddr, &in6, (in_port_t)port); localaddr4 = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
else if (have_ipv4 && inet_pton(AF_INET, local, &in4) == 1) if (localaddr4 == NULL)
isc_sockaddr_fromin(localaddr, &in4, (in_port_t)port); fatal("out of memory");
else { isc_sockaddr_fromin(localaddr4, &in4, (in_port_t)port);
} else {
fprintf(stderr, "invalid address %s", local); fprintf(stderr, "invalid address %s", local);
return (STATUS_SYNTAX); return (STATUS_SYNTAX);
} }
@@ -2202,6 +2236,19 @@ check_tsig_error(dns_rdataset_t *rdataset, isc_buffer_t *b) {
} }
} }
static isc_boolean_t
next_master(const char *caller, isc_sockaddr_t *addr, isc_result_t eresult) {
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
fprintf(stderr, "; Communication with %s failed: %s\n",
addrbuf, isc_result_totext(eresult));
if (++master_inuse >= master_total)
return (ISC_FALSE);
ddebug("%s: trying next server", caller);
return (ISC_TRUE);
}
static void static void
update_completed(isc_task_t *task, isc_event_t *event) { update_completed(isc_task_t *task, isc_event_t *event) {
dns_requestevent_t *reqev = NULL; dns_requestevent_t *reqev = NULL;
@@ -2226,10 +2273,19 @@ update_completed(isc_task_t *task, isc_event_t *event) {
} }
if (reqev->result != ISC_R_SUCCESS) { if (reqev->result != ISC_R_SUCCESS) {
fprintf(stderr, "; Communication with server failed: %s\n", if (!next_master("recvsoa", &master_servers[master_inuse],
isc_result_totext(reqev->result)); reqev->result)) {
seenerror = ISC_TRUE; seenerror = ISC_TRUE;
goto done; goto done;
}
ddebug("Destroying request [%p]", request);
dns_request_destroy(&request);
dns_message_renderreset(updatemsg);
dns_message_settsigkey(updatemsg, NULL);
send_update(zonename, &master_servers[master_inuse]);
isc_event_free(&event);
return;
} }
result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &answer); result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &answer);
@@ -2294,12 +2350,11 @@ update_completed(isc_task_t *task, isc_event_t *event) {
} }
static void static void
send_update(dns_name_t *zonename, isc_sockaddr_t *master, send_update(dns_name_t *zonename, isc_sockaddr_t *master) {
isc_sockaddr_t *srcaddr)
{
isc_result_t result; isc_result_t result;
dns_request_t *request = NULL; dns_request_t *request = NULL;
unsigned int options = DNS_REQUESTOPT_CASE; unsigned int options = DNS_REQUESTOPT_CASE;
isc_sockaddr_t *srcaddr;
ddebug("send_update()"); ddebug("send_update()");
@@ -2318,6 +2373,11 @@ send_update(dns_name_t *zonename, isc_sockaddr_t *master,
fprintf(stderr, "Sending update to %s\n", addrbuf); fprintf(stderr, "Sending update to %s\n", addrbuf);
} }
if (isc_sockaddr_pf(master) == AF_INET6)
srcaddr = localaddr6;
else
srcaddr = localaddr4;
/* Windows doesn't like the tsig name to be compressed. */ /* Windows doesn't like the tsig name to be compressed. */
if (updatemsg->tsigname) if (updatemsg->tsigname)
updatemsg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS; updatemsg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
@@ -2363,6 +2423,7 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
nsu_requestinfo_t *reqinfo; nsu_requestinfo_t *reqinfo;
dns_message_t *soaquery = NULL; dns_message_t *soaquery = NULL;
isc_sockaddr_t *addr; isc_sockaddr_t *addr;
isc_sockaddr_t *srcaddr;
isc_boolean_t seencname = ISC_FALSE; isc_boolean_t seencname = ISC_FALSE;
dns_name_t tname; dns_name_t tname;
unsigned int nlabels; unsigned int nlabels;
@@ -2396,7 +2457,7 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
dns_request_destroy(&request); dns_request_destroy(&request);
dns_message_renderreset(soaquery); dns_message_renderreset(soaquery);
dns_message_settsigkey(soaquery, NULL); dns_message_settsigkey(soaquery, NULL);
sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); sendrequest(&servers[ns_inuse], soaquery, &request);
isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t)); isc_mem_put(mctx, reqinfo, sizeof(nsu_requestinfo_t));
isc_event_free(&event); isc_event_free(&event);
setzoneclass(dns_rdataclass_none); setzoneclass(dns_rdataclass_none);
@@ -2424,8 +2485,14 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
reqinfo->addr = addr; reqinfo->addr = addr;
dns_message_renderreset(soaquery); dns_message_renderreset(soaquery);
ddebug("retrying soa request without TSIG"); ddebug("retrying soa request without TSIG");
result = dns_request_createvia3(requestmgr, soaquery,
localaddr, addr, 0, NULL, if (isc_sockaddr_pf(addr) == AF_INET6)
srcaddr = localaddr6;
else
srcaddr = localaddr4;
result = dns_request_createvia3(requestmgr, soaquery, srcaddr,
addr, 0, NULL,
FIND_TIMEOUT * 20, FIND_TIMEOUT * 20,
FIND_TIMEOUT, 3, FIND_TIMEOUT, 3,
global_task, recvsoa, reqinfo, global_task, recvsoa, reqinfo,
@@ -2529,23 +2596,30 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
fprintf(stderr, "The master is: %s\n", namestr); fprintf(stderr, "The master is: %s\n", namestr);
} }
if (servers == NULL) { if (default_servers) {
char serverstr[DNS_NAME_MAXTEXT+1]; char serverstr[DNS_NAME_MAXTEXT+1];
isc_buffer_t buf; isc_buffer_t buf;
size_t size;
isc_buffer_init(&buf, serverstr, sizeof(serverstr)); isc_buffer_init(&buf, serverstr, sizeof(serverstr));
result = dns_name_totext(&master, ISC_TRUE, &buf); result = dns_name_totext(&master, ISC_TRUE, &buf);
check_result(result, "dns_name_totext"); check_result(result, "dns_name_totext");
serverstr[isc_buffer_usedlength(&buf)] = 0; serverstr[isc_buffer_usedlength(&buf)] = 0;
ns_total = MAX_SERVERADDRS; if (master_servers != NULL && master_servers != servers)
servers = isc_mem_get(mctx, ns_total * sizeof(isc_sockaddr_t)); isc_mem_put(mctx, master_servers,
if (servers == NULL) master_total * sizeof(isc_sockaddr_t));
master_total = MAX_SERVERADDRS;
size = master_total * sizeof(isc_sockaddr_t);
master_servers = isc_mem_get(mctx, size);
if (master_servers == NULL)
fatal("out of memory"); fatal("out of memory");
memset(servers, 0, ns_total * sizeof(isc_sockaddr_t)); memset(master_servers, 0, size);
get_addresses(serverstr, dnsport, servers, ns_total); get_addresses(serverstr, dnsport, master_servers, master_total);
} master_inuse = 0;
} else
master_from_servers();
dns_rdata_freestruct(&soa); dns_rdata_freestruct(&soa);
#ifdef GSSAPI #ifdef GSSAPI
@@ -2556,11 +2630,11 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
dns_name_dup(&master, mctx, &restart_master); dns_name_dup(&master, mctx, &restart_master);
start_gssrequest(&master); start_gssrequest(&master);
} else { } else {
send_update(zonename, &servers[ns_inuse], localaddr); send_update(zonename, &master_servers[master_inuse]);
setzoneclass(dns_rdataclass_none); setzoneclass(dns_rdataclass_none);
} }
#else #else
send_update(zonename, &servers[ns_inuse], localaddr); send_update(zonename, &master_servers[master_inuse]);
setzoneclass(dns_rdataclass_none); setzoneclass(dns_rdataclass_none);
#endif #endif
@@ -2586,22 +2660,29 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
dns_request_destroy(&request); dns_request_destroy(&request);
dns_message_renderreset(soaquery); dns_message_renderreset(soaquery);
dns_message_settsigkey(soaquery, NULL); dns_message_settsigkey(soaquery, NULL);
sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); sendrequest(&servers[ns_inuse], soaquery, &request);
goto out; goto out;
} }
static void static void
sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, sendrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
dns_message_t *msg, dns_request_t **request) dns_request_t **request)
{ {
isc_result_t result; isc_result_t result;
nsu_requestinfo_t *reqinfo; nsu_requestinfo_t *reqinfo;
isc_sockaddr_t *srcaddr;
reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t)); reqinfo = isc_mem_get(mctx, sizeof(nsu_requestinfo_t));
if (reqinfo == NULL) if (reqinfo == NULL)
fatal("out of memory"); fatal("out of memory");
reqinfo->msg = msg; reqinfo->msg = msg;
reqinfo->addr = destaddr; reqinfo->addr = destaddr;
if (isc_sockaddr_pf(destaddr) == AF_INET6)
srcaddr = localaddr6;
else
srcaddr = localaddr4;
result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0, result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, 0,
default_servers ? NULL : tsigkey, default_servers ? NULL : tsigkey,
FIND_TIMEOUT * 20, FIND_TIMEOUT, 3, FIND_TIMEOUT * 20, FIND_TIMEOUT, 3,
@@ -2756,17 +2837,17 @@ start_gssrequest(dns_name_t *master) {
fatal("dns_tkey_buildgssquery failed: %s", fatal("dns_tkey_buildgssquery failed: %s",
isc_result_totext(result)); isc_result_totext(result));
send_gssrequest(localaddr, kserver, rmsg, &request, context); send_gssrequest(kserver, rmsg, &request, context);
} }
static void static void
send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, send_gssrequest(isc_sockaddr_t *destaddr, dns_message_t *msg,
dns_message_t *msg, dns_request_t **request, dns_request_t **request, gss_ctx_id_t context)
gss_ctx_id_t context)
{ {
isc_result_t result; isc_result_t result;
nsu_gssinfo_t *reqinfo; nsu_gssinfo_t *reqinfo;
unsigned int options = 0; unsigned int options = 0;
isc_sockaddr_t *srcaddr;
debug("send_gssrequest"); debug("send_gssrequest");
reqinfo = isc_mem_get(mctx, sizeof(nsu_gssinfo_t)); reqinfo = isc_mem_get(mctx, sizeof(nsu_gssinfo_t));
@@ -2777,6 +2858,12 @@ send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
reqinfo->context = context; reqinfo->context = context;
options |= DNS_REQUESTOPT_TCP; options |= DNS_REQUESTOPT_TCP;
if (isc_sockaddr_pf(destaddr) == AF_INET6)
srcaddr = localaddr6;
else
srcaddr = localaddr4;
result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr, result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr,
options, tsigkey, FIND_TIMEOUT * 20, options, tsigkey, FIND_TIMEOUT * 20,
FIND_TIMEOUT, 3, global_task, recvgss, FIND_TIMEOUT, 3, global_task, recvgss,
@@ -2831,7 +2918,7 @@ recvgss(isc_task_t *task, isc_event_t *event) {
ddebug("Destroying request [%p]", request); ddebug("Destroying request [%p]", request);
dns_request_destroy(&request); dns_request_destroy(&request);
dns_message_renderreset(tsigquery); dns_message_renderreset(tsigquery);
sendrequest(localaddr, &servers[ns_inuse], tsigquery, &request); sendrequest(&servers[ns_inuse], tsigquery, &request);
isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t)); isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
isc_event_free(&event); isc_event_free(&event);
return; return;
@@ -2885,8 +2972,7 @@ recvgss(isc_task_t *task, isc_event_t *event) {
switch (result) { switch (result) {
case DNS_R_CONTINUE: case DNS_R_CONTINUE:
send_gssrequest(localaddr, kserver, tsigquery, &request, send_gssrequest(kserver, tsigquery, &request, context);
context);
break; break;
case ISC_R_SUCCESS: case ISC_R_SUCCESS:
@@ -2919,7 +3005,7 @@ recvgss(isc_task_t *task, isc_event_t *event) {
check_result(result, "dns_message_checksig"); check_result(result, "dns_message_checksig");
#endif /* 0 */ #endif /* 0 */
send_update(&tmpzonename, &servers[ns_inuse], localaddr); send_update(&tmpzonename, &master_servers[master_inuse]);
setzoneclass(dns_rdataclass_none); setzoneclass(dns_rdataclass_none);
break; break;
@@ -2953,8 +3039,14 @@ start_update(void) {
if (answer != NULL) if (answer != NULL)
dns_message_destroy(&answer); dns_message_destroy(&answer);
if (userzone != NULL && ! usegsstsig) { /*
send_update(userzone, &servers[ns_inuse], localaddr); * If we have both the zone and the servers we have enough information
* to send the update straight away otherwise we need to discover
* the zone and / or the master server.
*/
if (userzone != NULL && !default_servers && !usegsstsig) {
master_from_servers();
send_update(userzone, &master_servers[master_inuse]);
setzoneclass(dns_rdataclass_none); setzoneclass(dns_rdataclass_none);
return; return;
} }
@@ -3016,7 +3108,7 @@ start_update(void) {
dns_message_addname(soaquery, name, DNS_SECTION_QUESTION); dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
ns_inuse = 0; ns_inuse = 0;
sendrequest(localaddr, &servers[ns_inuse], soaquery, &request); sendrequest(&servers[ns_inuse], soaquery, &request);
} }
static void static void

View File

@@ -417,6 +417,12 @@
[RT #37965] [RT #37965]
</para> </para>
</listitem> </listitem>
<listitem>
<para>
A regression caused nsupdate to use the default recursive servers
rather than the SOA MNAME server when sending the UPDATE.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</sect2> </sect2>
<sect2 id="end_of_life"> <sect2 id="end_of_life">