summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Halley <halley@dnspython.org>2006-07-20 21:29:42 +0000
committerBob Halley <halley@dnspython.org>2006-07-20 21:29:42 +0000
commitc3fc24674e8eb2c9a35c4f4d22a4f402bd633b6b (patch)
tree7f6e01d89a4b613979ab439217cbeefb2990742b
parent5e3b3c80f9e614abcf6e77bbf339b0baefecb748 (diff)
downloaddnspython-c3fc24674e8eb2c9a35c4f4d22a4f402bd633b6b.tar.gz
fix IXFR bugs, check more of IXFR for correctness
-rw-r--r--dns/query.py54
1 files changed, 37 insertions, 17 deletions
diff --git a/dns/query.py b/dns/query.py
index 66bf946..1e6d22a 100644
--- a/dns/query.py
+++ b/dns/query.py
@@ -320,31 +320,51 @@ def xfr(where, zone, rdtype=dns.rdatatype.AXFR, rdclass=dns.rdataclass.IN,
multi=True, first=first)
tsig_ctx = r.tsig_ctx
first = False
+ answer_index = 0
+ delete_mode = False
+ expecting_SOA = False
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
+ raise dns.exception.FormError, "first RRset is not an SOA"
+ answer_index = 1
soa_rrset = rrset.copy()
- if soa_rrset.serial == serial:
- done = True
+ if rdtype == dns.rdatatype.IXFR:
+ if soa_rrset[0].serial == serial:
+ #
+ # We're already up-to-date.
+ #
+ done = True
+ else:
+ expecting_SOA = True
#
- # Count the number of origin SOA RRs in this message
+ # Process SOAs in the answer section (other than the initial
+ # SOA in the first message).
#
- for rrset in r.answer:
+ for rrset in r.answer[answer_index:]:
+ if done:
+ raise dns.exception.FormError, "answers after final SOA"
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 == 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"
+ if expecting_SOA:
+ if rrset[0].serial != serial:
+ raise dns.exception.FormError, \
+ "IXFR base serial mismatch"
+ expecting_SOA = False
+ elif rdtype == dns.rdatatype.IXFR:
+ delete_mode = not delete_mode
+ if rrset == soa_rrset and not delete_mode:
+ done = True
+ elif expecting_SOA:
+ #
+ # We made an IXFR request and are expecting another
+ # SOA RR, but saw something else, so this must be an
+ # AXFR response.
+ #
+ rdtype = dns.rdatatype.AXFR
+ expecting_SOA = False
+ if done and q.keyring and not r.had_tsig:
+ raise dns.exception.FormError, "missing TSIG"
yield r
s.close()