]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
Responses to messages signed with TSIG were broken.
authorBob Halley <halley@dnspython.org>
Fri, 4 Apr 2014 13:16:44 +0000 (06:16 -0700)
committerBob Halley <halley@dnspython.org>
Fri, 4 Apr 2014 13:16:44 +0000 (06:16 -0700)
ChangeLog
dns/message.py
dns/tsig.py

index 51ea381d4eb9694f5bb2822be1b09c4fef311410..ed81d9862906a91562ff8ce4708beb02ab60a1e8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2014-04-04  Bob Halley  <halley@dnspython.org>
+
+       * dns/message.py: Making a response didn't work correctly if the
+         query was signed with TSIG and we knew the key.  Thanks to Jeffrey
+         Stiles for reporting the problem.
+
 2014-01-10  Bob Halley  <halley@ndnspython.org>
 
        * dns/inet.py (is_multicast): Removed lingering ord()s.
index 85096f3ac84d8da600250a426dcf71caa8e78eed..869a24764ce1bb6687b6736b521a34ebfdf24e53 100644 (file)
@@ -666,6 +666,10 @@ class _WireReader(object):
                 secret = self.message.keyring.get(absolute_name)
                 if secret is None:
                     raise UnknownTSIGKey("key '%s' unknown" % name)
+                self.message.keyname = absolute_name
+                (self.message.keyalgorithm, self.message.mac) = \
+                    dns.tsig.get_algorithm_and_mac(self.wire, self.current,
+                                                   rdlen)
                 self.message.tsig_ctx = \
                                       dns.tsig.validate(self.wire,
                                           absolute_name,
@@ -1065,7 +1069,8 @@ def make_query(qname, rdtype, rdclass = dns.rdataclass.IN, use_edns=None,
     m.want_dnssec(want_dnssec)
     return m
 
-def make_response(query, recursion_available=False, our_payload=8192):
+def make_response(query, recursion_available=False, our_payload=8192,
+                  fudge=300):
     """Make a message which is a response for the specified query.
     The message returned is really a response skeleton; it has all
     of the infrastructure required of a response, but none of the
@@ -1082,6 +1087,8 @@ def make_response(query, recursion_available=False, our_payload=8192):
     @param our_payload: payload size to advertise in EDNS responses; default
     is 8192.
     @type our_payload: int
+    @param fudge: TSIG time fudge; default is 300 seconds.
+    @type fudge: int
     @rtype: dns.message.Message object"""
 
     if query.flags & dns.flags.QR:
@@ -1094,8 +1101,8 @@ def make_response(query, recursion_available=False, our_payload=8192):
     response.question = list(query.question)
     if query.edns >= 0:
         response.use_edns(0, 0, our_payload, query.payload)
-    if not query.keyname is None:
-        response.keyname = query.keyname
-        response.keyring = query.keyring
+    if query.had_tsig:
+        response.use_tsig(query.keyring, query.keyname, fudge, None, 0, '',
+                          query.keyalgorithm)
         response.request_mac = query.mac
     return response
index 6d801d4980efb995f6af9ba6aff7634e07670e74..4333016ed270b53c6f1b4620bea06d615bc53250 100644 (file)
@@ -216,3 +216,19 @@ def get_algorithm(algorithm):
     except KeyError:
         raise NotImplementedError("TSIG algorithm " + str(algorithm) +
                                   " is not supported")
+
+def get_algorithm_and_mac(wire, tsig_rdata, tsig_rdlen):
+    """Return the tsig algorithm for the specified tsig_rdata
+    @raises FormError: The TSIG is badly formed.
+    """
+    current = tsig_rdata
+    (aname, used) = dns.name.from_wire(wire, current)
+    current = current + used
+    (upper_time, lower_time, fudge, mac_size) = \
+                 struct.unpack("!HIHH", wire[current:current + 10])
+    current += 10
+    mac = wire[current:current + mac_size]
+    current += mac_size
+    if current > tsig_rdata + tsig_rdlen:
+        raise dns.exception.FormError
+    return (aname, mac)