From 2db8db63992d081c75d664340866e2a21913705d Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Wed, 19 Jul 2006 00:53:42 +0000 Subject: [PATCH] 2049. [bug] Restore SOA before AXFR when falling back from a attempted IXFR when transfering in a zone. Allow a initial SOA query before attempting a AXFR to be requested. [RT #16156] --- CHANGES | 5 ++++ lib/dns/include/dns/xfrin.h | 10 +++++--- lib/dns/xfrin.c | 50 ++++++++++++++++++++++++++++++++----- lib/dns/zone.c | 19 +++++++++++--- 4 files changed, 71 insertions(+), 13 deletions(-) diff --git a/CHANGES b/CHANGES index c8237e56d9..8ec9c9af80 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +2049. [bug] Restore SOA before AXFR when falling back from + a attempted IXFR when transfering in a zone. + Allow a initial SOA query before attempting + a AXFR to be requested. [RT #16156] + 2048. [bug] It was possible to loop forever when using avoid-v4-udp-ports / avoid-v6-udp-ports when the OS always returned the same local port. diff --git a/lib/dns/include/dns/xfrin.h b/lib/dns/include/dns/xfrin.h index ab6469d8cc..2158d24af7 100644 --- a/lib/dns/include/dns/xfrin.h +++ b/lib/dns/include/dns/xfrin.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: xfrin.h,v 1.22 2005/04/29 00:23:06 marka Exp $ */ +/* $Id: xfrin.h,v 1.23 2006/07/19 00:53:42 marka Exp $ */ #ifndef DNS_XFRIN_H #define DNS_XFRIN_H 1 @@ -77,10 +77,12 @@ dns_xfrin_create2(dns_zone_t *zone, dns_rdatatype_t xfrtype, * code as arguments when the transfer finishes. * * Requires: - *\li 'xfrtype' is dns_rdatatype_axfr or dns_rdatatype_ixfr. + *\li 'xfrtype' is dns_rdatatype_axfr, dns_rdatatype_ixfr + * of dns_rdatatype_soa (soa query followed by axfr if + * serial is greater than current serial). * - *\li If 'xfrtype' is dns_rdatatype_ixfr, the zone has a - * database. + *\li If 'xfrtype' is dns_rdatatype_ixfr or dns_rdatatype_soa, + * the zone has a database. */ void diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c index 2b640eedc7..7d45035b0e 100644 --- a/lib/dns/xfrin.c +++ b/lib/dns/xfrin.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: xfrin.c,v 1.146 2006/03/01 02:05:11 marka Exp $ */ +/* $Id: xfrin.c,v 1.147 2006/07/19 00:53:42 marka Exp $ */ /*! \file */ @@ -75,6 +75,8 @@ * when the first two (2) response RRs have already been received. */ typedef enum { + XFRST_SOAQUERY, + XFRST_GOTSOA, XFRST_INITIALSOA, XFRST_FIRSTDATA, XFRST_IXFR_DELSOA, @@ -426,6 +428,30 @@ xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name, isc_uint32_t ttl, redo: switch (xfr->state) { + case XFRST_SOAQUERY: + if (rdata->type != dns_rdatatype_soa) { + xfrin_log(xfr, ISC_LOG_ERROR, + "non-SOA response to SOA query"); + FAIL(DNS_R_FORMERR); + } + xfr->end_serial = dns_soa_getserial(rdata); + if (!DNS_SERIAL_GT(xfr->end_serial, xfr->ixfr.request_serial) && + !dns_zone_isforced(xfr->zone)) { + xfrin_log(xfr, ISC_LOG_DEBUG(3), + "requested serial %u, " + "master has %u, not updating", + xfr->ixfr.request_serial, xfr->end_serial); + FAIL(DNS_R_UPTODATE); + } + xfr->state = XFRST_GOTSOA; + break; + + case XFRST_GOTSOA: + /* + * Skip other records in the answer section. + */ + break; + case XFRST_INITIALSOA: if (rdata->type != dns_rdatatype_soa) { xfrin_log(xfr, ISC_LOG_ERROR, @@ -591,6 +617,9 @@ dns_xfrin_create2(dns_zone_t *zone, dns_rdatatype_t xfrtype, (void)dns_zone_getdb(zone, &db); + if (xfrtype == dns_rdatatype_soa || xfrtype == dns_rdatatype_ixfr) + REQUIRE(db != NULL); + CHECK(xfrin_create(mctx, zone, db, task, timermgr, socketmgr, zonename, dns_zone_getclass(zone), xfrtype, masteraddr, sourceaddr, tsigkey, &xfr)); @@ -759,7 +788,10 @@ xfrin_create(isc_mem_t *mctx, dns_diff_init(xfr->mctx, &xfr->diff); xfr->difflen = 0; - xfr->state = XFRST_INITIALSOA; + if (reqtype == dns_rdatatype_soa) + xfr->state = XFRST_SOAQUERY; + else + xfr->state = XFRST_INITIALSOA; /* end_serial */ xfr->nmsg = 0; @@ -1005,7 +1037,9 @@ xfrin_send_request(dns_xfrin_ctx_t *xfr) { CHECK(tuple2msgname(soatuple, msg, &msgsoaname)); dns_message_addname(msg, msgsoaname, DNS_SECTION_AUTHORITY); - } + } else if (xfr->reqtype == dns_rdatatype_soa) + CHECK(dns_db_getsoaserial(xfr->db, NULL, + &xfr->ixfr.request_serial)); xfr->checkid = ISC_TRUE; xfr->id++; @@ -1166,8 +1200,8 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) { try_axfr: dns_message_destroy(&msg); xfrin_reset(xfr); - xfr->reqtype = dns_rdatatype_axfr; - xfr->state = XFRST_INITIALSOA; + xfr->reqtype = dns_rdatatype_soa; + xfr->state = XFRST_SOAQUERY; (void)xfrin_start(xfr); return; } @@ -1264,7 +1298,11 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) { dns_message_destroy(&msg); - if (xfr->state == XFRST_END) { + if (xfr->state == XFRST_GOTSOA) { + xfr->reqtype = dns_rdatatype_axfr; + xfr->state = XFRST_INITIALSOA; + CHECK(xfrin_send_request(xfr)); + } else if (xfr->state == XFRST_END) { /* * Inform the caller we succeeded. */ diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 6f65db39ed..fb94c8066c 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.456 2006/06/04 23:17:06 marka Exp $ */ +/* $Id: zone.c,v 1.457 2006/07/19 00:53:42 marka Exp $ */ /*! \file */ @@ -297,6 +297,7 @@ struct dns_zone { #define DNS_ZONEFLG_FLUSH 0x00200000U #define DNS_ZONEFLG_NOEDNS 0x00400000U #define DNS_ZONEFLG_USEALTXFRSRC 0x00800000U +#define DNS_ZONEFLG_SOABEFOREAXFR 0x01000000U #define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0) @@ -4286,8 +4287,13 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { master, source); /* Try with slave with TCP. */ if (zone->type == dns_zone_slave && - DNS_ZONE_OPTION(zone, DNS_ZONEOPT_TRYTCPREFRESH)) + DNS_ZONE_OPTION(zone, DNS_ZONEOPT_TRYTCPREFRESH)) { + LOCK_ZONE(zone); + DNS_ZONE_SETFLAG(zone, + DNS_ZONEFLG_SOABEFOREAXFR); + UNLOCK_ZONE(zone); goto tcp_transfer; + } } else dns_zone_log(zone, ISC_LOG_INFO, "refresh: failure trying master " @@ -4354,6 +4360,9 @@ refresh_callback(isc_task_t *task, isc_event_t *event) { "initiating TCP zone xfer " "for master %s (source %s)", master, source); + LOCK_ZONE(zone); + DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR); + UNLOCK_ZONE(zone); goto tcp_transfer; } else { INSIST(zone->type == dns_zone_stub); @@ -6334,6 +6343,7 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { LOCK_ZONE(zone); INSIST((zone->flags & DNS_ZONEFLG_REFRESH) != 0); DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESH); + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR); TIME_NOW(&now); switch (result) { @@ -6691,7 +6701,10 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) { "IXFR disabled, " "requesting AXFR from %s", mastertext); - xfrtype = dns_rdatatype_axfr; + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR)) + xfrtype = dns_rdatatype_soa; + else + xfrtype = dns_rdatatype_axfr; } else { dns_zone_log(zone, ISC_LOG_DEBUG(1), "requesting IXFR from %s",