]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
add IXFR support
authorBob Halley <halley@dnspython.org>
Thu, 20 Jul 2006 01:40:28 +0000 (01:40 +0000)
committerBob Halley <halley@dnspython.org>
Thu, 20 Jul 2006 01:40:28 +0000 (01:40 +0000)
ChangeLog
dns/query.py

index 79fe31b8773f2c771867d07b4dcdfccff3111fed..3d011320d8315cdd832babb5def7b86bee835448 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2006-07-19  Bob Halley  <halley@dnspython.org>
+
+       * dns/query.py (xfr): Add IXFR support.
+
 2006-06-22  Bob Halley  <halley@dnspython.org>
 
        * dns/rdtypes/IN/IPSECKEY.py: Added support for the IPSECKEY RR type.
index 38bbcafd2d7990ca6e7e498d7e2cad4b9e2bcc95..fa79ad8ea15ceb1cced84444bb21555f1f8f715f 100644 (file)
@@ -222,7 +222,7 @@ def tcp(q, where, timeout=None, port=53, af=None, source=None, source_port=0):
 
 def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN,
         timeout=None, port=53, keyring=None, keyname=None, relativize=True,
-        af=None, lifetime=None, source=None, source_port=0):
+        af=None, lifetime=None, source=None, source_port=0, serial=0):
     """Return a generator for the responses to a zone transfer.
 
     @param where: where to send the message
@@ -261,11 +261,18 @@ def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN,
     @type source: string
     @param source_port: The port from which to send the message.
     The default is 0.
-    @type source_port: int"""
+    @type source_port: int
+    @param serial: The SOA serial number to use as the base for an IXFR diff
+    sequence (only meaningful if rdtype == dns.rdatatype.IXFR).
+    @type serial: int"""
 
     if isinstance(zone, (str, unicode)):
         zone = dns.name.from_text(zone)
     q = dns.message.make_query(zone, rdtype, rdclass)
+    if rdtype == dns.rdatatype.IXFR:
+        rrset = dns.rrset.from_text(zone, 0, 'IN', 'SOA',
+                                    '. . %u 0 0 0 0' % serial)
+        q.authority.append(rrset)
     if not keyring is None:
         q.use_tsig(keyring, keyname)
     wire = q.to_wire()
@@ -291,7 +298,8 @@ def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN,
     tcpmsg = struct.pack("!H", l) + wire
     _net_write(s, tcpmsg, expiration)
     done = False
-    seen_soa = False
+    soa_rrset = None
+    soa_count = 0
     if relativize:
         origin = zone
         oname = dns.name.empty
@@ -312,24 +320,29 @@ def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN,
                                   multi=True, first=first)
         tsig_ctx = r.tsig_ctx
         first = False
-        if not seen_soa:
+        if soa_rrset is None:
             if not r.answer or r.answer[0].name != oname:
                 raise dns.exception.FormError
             rrset = r.answer[0]
             if rrset.rdtype != dns.rdatatype.SOA:
                 raise dns.exception.FormError
-            seen_soa = True
-            if len(r.answer) > 1 and r.answer[-1].name == oname:
-                rrset = r.answer[-1]
-                if rrset.rdtype == dns.rdatatype.SOA:
-                    if q.keyring and not r.had_tsig:
-                        raise dns.exception.FormError, "missing TSIG"
-                    done = True
-        elif r.answer and r.answer[-1].name == oname:
+            soa_rrset = rrset.copy()
+        #
+        # Count the number of origin SOA RRs in this message
+        #
+        for rrset in r.answer:
+            if rrset.rdtype == dns.rdatatype.SOA and rrset.name == oname:
+                soa_count += 1
+        #
+        # Are we done?
+        #
+        if len(r.answer) > 1 and r.answer[-1].name == oname:
             rrset = r.answer[-1]
-            if rrset.rdtype == dns.rdatatype.SOA:
-                if q.keyring and not r.had_tsig:
-                    raise dns.exception.FormError, "missing TSIG"
+            if rrset == soa_rrset and \
+               (rdtype == dns.rdatatype.AXFR or \
+                (rdtype == dns.rdatatype.IXFR and soa_count % 2 == 0)):
                 done = True
+            if done and q.keyring and not r.had_tsig:
+                raise dns.exception.FormError, "missing TSIG"
         yield r
     s.close()