diff --git a/CHANGES b/CHANGES index 4eaa6bd7b0..a50335aa2d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ +1226. [func] Use EDNS for zone refresh queries. [RT #2551] + 1225. [func] dns_message_setopt() no longer requires that dns_message_renderbegin() to have been called. diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 69bed4b4f5..e6a2873607 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.363 2002/02/20 03:34:24 marka Exp $ */ +/* $Id: zone.c,v 1.364 2002/03/11 04:41:53 marka Exp $ */ #include @@ -256,6 +256,7 @@ struct dns_zone { #define DNS_ZONEFLG_SHUTDOWN 0x00080000U #define DNS_ZONEFLAG_NOIXFR 0x00100000U /* IXFR failed, force AXFR */ #define DNS_ZONEFLG_FLUSH 0x00200000U +#define DNS_ZONEFLG_NOEDNS 0x00400000U #define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0) @@ -362,6 +363,8 @@ struct dns_io { isc_event_t *event; }; +#define SEND_BUFFER_SIZE 2048 + static void zone_settimer(dns_zone_t *, isc_time_t *); static void cancel_refresh(dns_zone_t *); static void zone_debuglog(dns_zone_t *zone, const char *, int debuglevel, @@ -2133,6 +2136,7 @@ dns_zone_refresh(dns_zone_t *zone) { goto unlock; } DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_REFRESH); + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOEDNS); if ((oldflags & (DNS_ZONEFLG_REFRESH|DNS_ZONEFLG_LOADING)) != 0) goto unlock; @@ -3086,6 +3090,16 @@ stub_callback(isc_task_t *task, isc_event_t *event) { isc_sockaddr_format(&zone->masteraddr, master, sizeof(master)); if (revent->result != ISC_R_SUCCESS) { + if (revent->result == ISC_R_TIMEDOUT && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { + LOCK_ZONE(zone); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); + UNLOCK_ZONE(zone); + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "refreshing stub: timeout retrying " + " without EDNS master %s", master); + goto same_master; + } dns_zone_log(zone, ISC_LOG_INFO, "could not refresh stub from master %s: %s", master, dns_result_totext(revent->result)); @@ -3110,6 +3124,20 @@ stub_callback(isc_task_t *task, isc_event_t *event) { isc_buffer_init(&rb, rcode, sizeof(rcode)); (void)dns_rcode_totext(msg->rcode, &rb); + if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS) && + (msg->rcode == dns_rcode_servfail || + msg->rcode == dns_rcode_notimp || + msg->rcode == dns_rcode_formerr)) { + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "refreshing stub: rcode (%.*s) retrying " + "without EDNS master %s", + (int)rb.used, rcode, master); + LOCK_ZONE(zone); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); + UNLOCK_ZONE(zone); + goto same_master; + } + dns_zone_log(zone, ISC_LOG_INFO, "refreshing stub: " "unexpected rcode (%.*s) from %s", @@ -3213,6 +3241,7 @@ stub_callback(isc_task_t *task, isc_event_t *event) { LOCK_ZONE(zone); dns_request_destroy(&zone->request); zone->curmaster++; + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOEDNS); if (exiting || zone->curmaster >= zone->masterscnt) { DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); @@ -3280,6 +3309,16 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { TIME_NOW(&now); if (revent->result != ISC_R_SUCCESS) { + if (revent->result == ISC_R_TIMEDOUT && + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { + LOCK_ZONE(zone); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); + UNLOCK_ZONE(zone); + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "refresh: timeout retrying without EDNS " + "master %s", master); + goto same_master; + } if (revent->result == ISC_R_TIMEDOUT && !dns_request_usedtcp(revent->request)) { dns_zone_log(zone, ISC_LOG_INFO, @@ -3314,6 +3353,19 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { isc_buffer_init(&rb, rcode, sizeof(rcode)); (void)dns_rcode_totext(msg->rcode, &rb); + if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS) && + (msg->rcode == dns_rcode_servfail || + msg->rcode == dns_rcode_notimp || + msg->rcode == dns_rcode_formerr)) { + dns_zone_log(zone, ISC_LOG_DEBUG(1), + "refresh: rcode (%.*s) retrying without " + "EDNS master %s", (int)rb.used, rcode, + master); + LOCK_ZONE(zone); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); + UNLOCK_ZONE(zone); + goto same_master; + } dns_zone_log(zone, ISC_LOG_INFO, "refresh: unexpected rcode (%.*s) from master %s", (int)rb.used, rcode, master); @@ -3481,6 +3533,7 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { LOCK_ZONE(zone); dns_request_destroy(&zone->request); zone->curmaster++; + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOEDNS); if (zone->curmaster >= zone->masterscnt) { DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDREFRESH)) { @@ -3598,6 +3651,64 @@ create_query(dns_zone_t *zone, dns_rdatatype_t rdtype, return (result); } +static isc_result_t +add_opt(dns_message_t *message) { + dns_rdataset_t *rdataset = NULL; + dns_rdatalist_t *rdatalist = NULL; + dns_rdata_t *rdata = NULL; + isc_result_t result; + + result = dns_message_gettemprdatalist(message, &rdatalist); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_message_gettemprdata(message, &rdata); + if (result != ISC_R_SUCCESS) + goto cleanup; + result = dns_message_gettemprdataset(message, &rdataset); + if (result != ISC_R_SUCCESS) + goto cleanup; + dns_rdataset_init(rdataset); + + rdatalist->type = dns_rdatatype_opt; + rdatalist->covers = 0; + + /* + * Set Maximum UDP buffer size. + */ + rdatalist->rdclass = SEND_BUFFER_SIZE; + + /* + * Set EXTENDED-RCODE, VERSION, DO and Z to 0. + */ + rdatalist->ttl = 0; + + /* + * No EDNS options. + */ + rdata->data = NULL; + rdata->length = 0; + rdata->rdclass = rdatalist->rdclass; + rdata->type = rdatalist->type; + rdata->flags = 0; + + ISC_LIST_INIT(rdatalist->rdata); + ISC_LIST_APPEND(rdatalist->rdata, rdata, link); + RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) + == ISC_R_SUCCESS); + + return (dns_message_setopt(message, rdataset)); + + cleanup: + if (rdatalist != NULL) + dns_message_puttemprdatalist(message, &rdatalist); + if (rdataset != NULL) + dns_message_puttemprdataset(message, &rdataset); + if (rdata != NULL) + dns_message_puttemprdata(message, &rdata); + + return (result); +} + static void soa_query(isc_task_t *task, isc_event_t *event) { const char me[] = "soa_query"; @@ -3641,6 +3752,24 @@ soa_query(isc_task_t *task, isc_event_t *event) { isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); (void)dns_view_getpeertsig(zone->view, &masterip, &key); + if (zone->view->peers != NULL) { + dns_peer_t *peer = NULL; + isc_boolean_t edns; + result = dns_peerlist_peerbyaddr(zone->view->peers, + &masterip, &peer); + if (result == ISC_R_SUCCESS) + result = dns_peer_getsupportedns(peer, &edns); + if (result == ISC_R_SUCCESS && !edns) + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); + } + if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { + result = add_opt(message); + if (result != ISC_R_SUCCESS) + zone_debuglog(zone, me, 1, + "unable to add opt record: %s", + dns_result_totext(result)); + } + options = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_USEVC) ? DNS_REQUESTOPT_TCP : 0; switch (isc_sockaddr_pf(&zone->masteraddr)) { @@ -3782,6 +3911,24 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) { isc_netaddr_fromsockaddr(&masterip, &zone->masteraddr); (void)dns_view_getpeertsig(zone->view, &masterip, &key); + if (zone->view->peers != NULL) { + dns_peer_t *peer = NULL; + isc_boolean_t edns; + result = dns_peerlist_peerbyaddr(zone->view->peers, + &masterip, &peer); + if (result == ISC_R_SUCCESS) + result = dns_peer_getsupportedns(peer, &edns); + if (result == ISC_R_SUCCESS && !edns) + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NOEDNS); + } + if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOEDNS)) { + result = add_opt(message); + if (result != ISC_R_SUCCESS) + zone_debuglog(zone, me, 1, + "unable to add opt record: %s", + dns_result_totext(result)); + } + /* * Always use TCP so that we shouldn't truncate in additional section. */