From 996042c30dc6f70d592c6685b1d10ab9412089b8 Mon Sep 17 00:00:00 2001
From: Guillaume Valadon <guillaume@valadon.net>
Date: Fri, 30 Jun 2017 16:54:35 +0200
Subject: [PATCH] DNS TSIG Ressource Record

---
 scapy/layers/dns.py | 60 +++++++++++++++++++++++++++++++++++++++++++++
 test/dnssecRR.uts   | 17 +++++++++++++
 2 files changed, 77 insertions(+)

diff --git a/scapy/layers/dns.py b/scapy/layers/dns.py
index ba753794..8a0cd329 100644
--- a/scapy/layers/dns.py
+++ b/scapy/layers/dns.py
@@ -618,6 +618,65 @@ class DNSRRNSEC3PARAM(_DNSRRdummy):
                     StrLenField("salt", "", length_from=lambda pkt: pkt.saltlength)
                   ]
 
+# RFC 2845 - Secret Key Transaction Authentication for DNS (TSIG)
+tsig_algo_sizes = { "HMAC-MD5.SIG-ALG.REG.INT": 16,
+                    "hmac-sha1": 20 }
+
+class TimeSignedField(StrFixedLenField):
+    def __init__(self, name, default):
+        StrFixedLenField.__init__(self, name, default, 6)
+
+    def _convert_seconds(self, packed_seconds):
+        """Unpack the internal representation."""
+        seconds = struct.unpack("!H", packed_seconds[:2])[0]
+        seconds += struct.unpack("!I", packed_seconds[2:])[0]
+        return seconds
+
+    def h2i(self, pkt, seconds):
+        """Convert the number of seconds since 1-Jan-70 UTC to the packed
+           representation."""
+
+        if seconds is None:
+            seconds = 0
+
+        tmp_short = (seconds >> 32) & 0xFFFF
+        tmp_int = seconds & 0xFFFFFFFF
+
+        return struct.pack("!HI", tmp_short, tmp_int)
+
+    def i2h(self, pkt, packed_seconds):
+        """Convert the internal representation to the number of seconds
+           since 1-Jan-70 UTC."""
+
+        if packed_seconds is None:
+            return None
+
+        return self._convert_seconds(packed_seconds)
+
+    def i2repr(self, pkt, packed_seconds):
+        """Convert the internal representation to a nice one using the RFC
+           format."""
+        time_struct = time.gmtime(self._convert_seconds(packed_seconds))
+        return time.strftime("%a %b %d %H:%M:%S %Y", time_struct)
+
+class DNSRRTSIG(_DNSRRdummy):
+    name = "DNS TSIG Resource Record"
+    fields_desc = [ DNSStrField("rrname", ""),
+                    ShortEnumField("type", 250, dnstypes),
+                    ShortEnumField("rclass", 1, dnsclasses),
+                    IntField("ttl", 0),
+                    ShortField("rdlen", None),
+                    DNSStrField("algo_name", "hmac-sha1"),
+                    TimeSignedField("time_signed", 0),
+                    ShortField("fudge", 0),
+                    FieldLenField("mac_len", 20, fmt="!H", length_of="mac_data"),
+                    StrLenField("mac_data", "", length_from=lambda pkt: pkt.mac_len),
+                    ShortField("original_id", 0),
+                    ShortField("error", 0),
+                    FieldLenField("other_len", 0, fmt="!H", length_of="other_data"),
+                    StrLenField("other_data", "", length_from=lambda pkt: pkt.other_len)
+                  ]
+
 
 DNSRR_DISPATCHER = {
     41: DNSRROPT,        # RFC 1671
@@ -627,6 +686,7 @@ DNSRR_DISPATCHER = {
     48: DNSRRDNSKEY,     # RFC 4034
     50: DNSRRNSEC3,      # RFC 5155
     51: DNSRRNSEC3PARAM, # RFC 5155
+    250: DNSRRTSIG,      # RFC 2845
     32769: DNSRRDLV,     # RFC 4431
 }
 
diff --git a/test/dnssecRR.uts b/test/dnssecRR.uts
index fa2d0303..becb1905 100644
--- a/test/dnssecRR.uts
+++ b/test/dnssecRR.uts
@@ -120,3 +120,20 @@ t = DNSRR(type="TXT", rdata="test")
 = DNSRRR(), check parameters
 t = DNSRR(b'\x04test\x00\x00\x10\x00\x01\x00\x00\x00\x00\x018\xffScapy is an interactive packet manipulation program that enables you to sniff, mangle, send network packets ; test equipments ; probe and discover networks ; quickly develop new protocols. It can easily handle most classical tasks like scanning, tracerout7ing, probing, unit tests, attacks or network discovery.')
 t.type == 16 and t.rdlen == 312 and t.rdata[:5] == "Scapy" and t.rdata[-10:] == "discovery."
+
++ Test DNSRRTSIG RR
+
+= DNSRRTSIG basic instanciation
+t = DNSRRTSIG()
+str(t) == b"\x00\x00\xfa\x00\x01\x00\x00\x00\x00\x00\x1b\thmac-sha1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00"
+
+= DNSRRTSIG(), check parameters
+t = DNSRRTSIG(rrname="SAMPLE-ALG.EXAMPLE.", time_signed=853804800, fudge=300)
+str(t) == b"\nSAMPLE-ALG\x07EXAMPLE\x00\x00\xfa\x00\x01\x00\x00\x00\x00\x00\x1b\thmac-sha1\x00\x00\x002\xe4\x07\x00\x01,\x00\x14\x00\x00\x00\x00\x00\x00"
+
+= TimeField methods
+
+packed_data = b"\x00\x002\xe4\x07\x00"
+assert(TimeSignedField("", 0).h2i("", 853804800) == packed_data)
+assert(TimeSignedField("", 0).i2h("", packed_data) == 853804800)
+assert(TimeSignedField("", 0).i2repr("", packed_data) == "Tue Jan 21 00:00:00 1997")
-- 
GitLab