]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2049. [bug] Restore SOA before AXFR when falling back from
authorMark Andrews <marka@isc.org>
Wed, 19 Jul 2006 00:53:42 +0000 (00:53 +0000)
committerMark Andrews <marka@isc.org>
Wed, 19 Jul 2006 00:53:42 +0000 (00:53 +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 c8237e56d9021d4a6f4adcd0508ab279a2fcaf12..8ec9c9af80c88cc6a826b4685e33cd645ff27a08 100644 (file)
--- 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.
index ab6469d8cccf1f6affc57abc8f0ede643c9d5b4a..2158d24af76a4013280bda9615ba0a5823d49944 100644 (file)
@@ -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
index 2b640eedc772c56a2d0c94be7bdbd1d34988885a..7d45035b0e96a48ceac2c58485b29651b1935b27 100644 (file)
@@ -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.
                 */
index 6f65db39ed71a799bf60c9473b4e1f1016381c5c..fb94c8066c1c71976309fa0bc5dc42f36b3487f8 100644 (file)
@@ -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",