Browse Source

[1279] Retry with AXFR if IXFR fails

Michal 'vorner' Vaner 13 years ago
parent
commit
56d8610a9e
3 changed files with 32 additions and 8 deletions
  1. 7 0
      src/bin/xfrin/tests/xfrin_test.py
  2. 19 8
      src/bin/xfrin/xfrin.py.in
  3. 6 0
      src/bin/xfrin/xfrin_messages.mes

+ 7 - 0
src/bin/xfrin/tests/xfrin_test.py

@@ -2234,6 +2234,13 @@ class TestXfrinProcess(unittest.TestCase):
         self.__rets = self.__rets[1:]
         return ret
 
+    def zone_str(self):
+        """
+        Part of pretending to be the connection. It provides the logging name
+        of zone.
+        """
+        return "example.org/IN"
+
     def publish_xfrin_news(self, zone_name, rrclass, ret):
         """
         Part of pretending to be the server as well. This just logs the

+ 19 - 8
src/bin/xfrin/xfrin.py.in

@@ -820,14 +820,25 @@ def process_xfrin(server, xfrin_recorder, zone_name, rrclass, db_file,
 
     # Create a TCP connection for the XFR session and perform the operation.
     sock_map = {}
-    conn = XfrinConnection(sock_map, zone_name, rrclass, datasrc_client,
-                           shutdown_event, master_addrinfo, tsig_key)
-    # XXX: We still need _db_file for temporary workaround in _create_query().
-    # This should be removed when we eliminate the need for the workaround.
-    conn._db_file = db_file
-    ret = XFRIN_FAIL
-    if conn.connect_to_master():
-        ret = conn.do_xfrin(check_soa, request_type)
+    retry = True
+    while retry:
+        retry = False
+        conn = XfrinConnection(sock_map, zone_name, rrclass, datasrc_client,
+                               shutdown_event, master_addrinfo, tsig_key)
+        # XXX: We still need _db_file for temporary workaround in _create_query().
+        # This should be removed when we eliminate the need for the workaround.
+        conn._db_file = db_file
+        ret = XFRIN_FAIL
+        if conn.connect_to_master():
+            ret = conn.do_xfrin(check_soa, request_type)
+            if ret == XFRIN_FAIL and request_type == RRType.IXFR():
+                # IXFR failed for some reason. It might mean the server can't
+                # handle it, or we don't have the zone or we are out of sync or
+                # whatever else. So we retry with with AXFR, as it may succeed
+                # in manu such cases.
+                retry = True
+                request_type = RRType.AXFR()
+                logger.warn(XFRIN_XFR_TRANSFER_FALLBACK, conn.zone_str())
 
     # Publish the zone transfer result news, so zonemgr can reset the
     # zone timer, and xfrout can notify the zone's slaves if the result

+ 6 - 0
src/bin/xfrin/xfrin_messages.mes

@@ -29,6 +29,12 @@ this can only happen for AXFR.
 The XFR transfer for the given zone has failed due to a protocol error.
 The error is shown in the log message.
 
+% XFRIN_XFR_TRANSFER_FALLBACK falling back from IXFR to AXFR for %1
+The IXFR transfer of the given zone failed. This might happen in many cases,
+such that the remote server doesn't support IXFR, we don't have the SOA record
+(or the zone at all), we are out of sync, etc. In many of these situations,
+AXFR could still work. Therefore we try that one in case it helps.
+
 % XFRIN_XFR_TRANSFER_STARTED %1 transfer of zone %2 started
 A connection to the master server has been made, the serial value in
 the SOA record has been checked, and a zone transfer has been started.