]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2049. [bug] Restore SOA before AXFR when falling back from
authorMark Andrews <marka@isc.org>
Thu, 3 Aug 2006 23:17:35 +0000 (23:17 +0000)
committerMark Andrews <marka@isc.org>
Thu, 3 Aug 2006 23:17:35 +0000 (23:17 +0000)
                        a attempted IXFR when transfering in a zone.
                        Allow a initial SOA query before attempting
                        a AXFR to be requested. [RT #16156]

CHANGES
lib/dns/include/dns/xfrin.h
lib/dns/xfrin.c
lib/dns/zone.c

diff --git a/CHANGES b/CHANGES
index 2366ccd2509e4e9e35e9090f208222f3545b2cc0..53d692cf9efc87ed8c0db38b5c1ffd8484a73280 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,10 @@
 2066.  [security]      Handle SIG queries gracefully. [RT #16330]
 
+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]
+
        --- 9.3.2-WFB-3 released ---
 
 2035.  [func]          Make falling back to TCP on UDP refresh failure
index 0050238f94a14f86dc9c7881411f85038d7bf860..e484897558f2eb25b5b3f9d5896b31d6d9cbc06b 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: xfrin.h,v 1.18.136.2 2004/03/06 08:14:01 marka Exp $ */
+/* $Id: xfrin.h,v 1.18.136.2.18.1 2006/08/03 23:16:40 marka Exp $ */
 
 #ifndef DNS_XFRIN_H
 #define DNS_XFRIN_H 1
@@ -75,10 +75,12 @@ dns_xfrin_create2(dns_zone_t *zone, dns_rdatatype_t xfrtype,
  * code as arguments when the transfer finishes.
  *
  * Requires:
- *     'xfrtype' is dns_rdatatype_axfr or dns_rdatatype_ixfr.
+ *     'xfrtype' is dns_rdatatype_axfr, dns_rdatatype_ixfr
+ *     of dns_rdatatype_soa (soa query followed by axfr if
+ *     serial is greater than current serial).
  *
- *     If 'xfrtype' is dns_rdatatype_ixfr, the zone has a
- *     database.
+ *     If 'xfrtype' is dns_rdatatype_ixfr or dns_rdatatype_soa,
+ *     the zone has a database.
  */
 
 void
index 8a824a73ef5ec4804fcaaf27e6306443a8ad53a0..278eb35ee5cdacee9fdbeaa5f452ba898dfcac7d 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: xfrin.c,v 1.124.2.4.2.12 2005/11/03 23:08:41 marka Exp $ */
+/* $Id: xfrin.c,v 1.124.2.4.2.12.2.1 2006/08/03 23:16:40 marka Exp $ */
 
 #include <config.h>
 
@@ -73,6 +73,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,
@@ -424,6 +426,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,
@@ -589,6 +615,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));
@@ -754,7 +783,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;
@@ -987,7 +1019,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++;
@@ -1148,8 +1182,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;
        }
@@ -1246,7 +1280,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.
                 */
index 3d2154412db202f63bb0d700e8851a39d56df54d..0db7aeca19e0cd6c9d9ab3a94b01368ef8960bb4 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: zone.c,v 1.333.2.23.2.59.4.3 2006/06/04 23:33:26 marka Exp $ */
+/* $Id: zone.c,v 1.333.2.23.2.59.4.4 2006/08/03 23:16:40 marka Exp $ */
 
 #include <config.h>
 
@@ -264,6 +264,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)
 
@@ -3548,8 +3549,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 "
@@ -3616,6 +3622,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);
@@ -5528,6 +5537,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) {
@@ -5881,7 +5891,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",