From 2db54ba975ed5be22f92af105bb2bd6b0ccbbef1 Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Fri, 4 Apr 2014 05:34:49 -0700 Subject: Responses to messages signed with TSIG were broken. --- ChangeLog | 6 ++++++ dns/message.py | 15 +++++++++++---- dns/tsig.py | 16 ++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2e48d9c..6654bb1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2014-04-04 Bob Halley + + * 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. + 2013-12-11 Bob Halley * dns/query.py: Fix problems with the IXFR state machine which caused diff --git a/dns/message.py b/dns/message.py index 52c0eae..e523931 100644 --- a/dns/message.py +++ b/dns/message.py @@ -665,6 +665,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, @@ -1071,7 +1075,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 @@ -1088,6 +1093,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: @@ -1100,8 +1107,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 diff --git a/dns/tsig.py b/dns/tsig.py index 6e97dce..2dd4b42 100644 --- a/dns/tsig.py +++ b/dns/tsig.py @@ -221,3 +221,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) -- cgit v1.2.1