From: Bob Halley Date: Fri, 4 Apr 2014 13:16:44 +0000 (-0700) Subject: Responses to messages signed with TSIG were broken. X-Git-Tag: v1.12.0-py3~22 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c7b16bfeea84266936b04345fd65aff191ed126d;p=thirdparty%2Fdnspython.git Responses to messages signed with TSIG were broken. --- diff --git a/ChangeLog b/ChangeLog index 51ea381d..ed81d986 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. + 2014-01-10 Bob Halley * dns/inet.py (is_multicast): Removed lingering ord()s. diff --git a/dns/message.py b/dns/message.py index 85096f3a..869a2476 100644 --- a/dns/message.py +++ b/dns/message.py @@ -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 diff --git a/dns/tsig.py b/dns/tsig.py index 6d801d49..4333016e 100644 --- a/dns/tsig.py +++ b/dns/tsig.py @@ -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)