Skip to content
Snippets Groups Projects
Commit dfd55c57 authored by Guillaume Valadon's avatar Guillaume Valadon Committed by GitHub
Browse files

Merge pull request #413 from p-l-/enh-dns

Add & test DNS over TCP, update dnstypes
parents f69f5616 8c93b479
No related branches found
No related tags found
No related merge requests found
...@@ -14,7 +14,7 @@ from scapy.packet import * ...@@ -14,7 +14,7 @@ from scapy.packet import *
from scapy.fields import * from scapy.fields import *
from scapy.ansmachine import * from scapy.ansmachine import *
from scapy.sendrecv import sr1 from scapy.sendrecv import sr1
from scapy.layers.inet import IP, DestIPField, UDP from scapy.layers.inet import IP, DestIPField, UDP, TCP
from scapy.layers.inet6 import DestIP6Field from scapy.layers.inet6 import DestIP6Field
class DNSStrField(StrField): class DNSStrField(StrField):
...@@ -233,36 +233,43 @@ class RDLenField(Field): ...@@ -233,36 +233,43 @@ class RDLenField(Field):
rdataf = pkt.get_field("rdata") rdataf = pkt.get_field("rdata")
x = len(rdataf.i2m(pkt, pkt.rdata)) x = len(rdataf.i2m(pkt, pkt.rdata))
return x return x
class DNS(Packet): class DNS(Packet):
name = "DNS" name = "DNS"
fields_desc = [ ShortField("id", 0), fields_desc = [
BitField("qr", 0, 1), ConditionalField(ShortField("length", None),
BitEnumField("opcode", 0, 4, {0:"QUERY",1:"IQUERY",2:"STATUS"}), lambda p: isinstance(p.underlayer, TCP)),
BitField("aa", 0, 1), ShortField("id", 0),
BitField("tc", 0, 1), BitField("qr", 0, 1),
BitField("rd", 1, 1), BitEnumField("opcode", 0, 4, {0: "QUERY", 1: "IQUERY", 2: "STATUS"}),
BitField("ra", 0, 1), BitField("aa", 0, 1),
BitField("z", 0, 1), BitField("tc", 0, 1),
# AD and CD bits are defined in RFC 2535 BitField("rd", 1, 1),
BitField("ad", 0, 1), # Authentic Data BitField("ra", 0, 1),
BitField("cd", 0, 1), # Checking Disabled BitField("z", 0, 1),
BitEnumField("rcode", 0, 4, {0:"ok", 1:"format-error", 2:"server-failure", 3:"name-error", 4:"not-implemented", 5:"refused"}), # AD and CD bits are defined in RFC 2535
DNSRRCountField("qdcount", None, "qd"), BitField("ad", 0, 1), # Authentic Data
DNSRRCountField("ancount", None, "an"), BitField("cd", 0, 1), # Checking Disabled
DNSRRCountField("nscount", None, "ns"), BitEnumField("rcode", 0, 4, {0: "ok", 1: "format-error",
DNSRRCountField("arcount", None, "ar"), 2: "server-failure", 3: "name-error",
DNSQRField("qd", "qdcount"), 4: "not-implemented", 5: "refused"}),
DNSRRField("an", "ancount"), DNSRRCountField("qdcount", None, "qd"),
DNSRRField("ns", "nscount"), DNSRRCountField("ancount", None, "an"),
DNSRRField("ar", "arcount",0) ] DNSRRCountField("nscount", None, "ns"),
DNSRRCountField("arcount", None, "ar"),
DNSQRField("qd", "qdcount"),
DNSRRField("an", "ancount"),
DNSRRField("ns", "nscount"),
DNSRRField("ar", "arcount", 0),
]
def answers(self, other): def answers(self, other):
return (isinstance(other, DNS) return (isinstance(other, DNS)
and self.id == other.id and self.id == other.id
and self.qr == 1 and self.qr == 1
and other.qr == 0) and other.qr == 0)
def mysummary(self): def mysummary(self):
type = ["Qry","Ans"][self.qr] type = ["Qry","Ans"][self.qr]
name = "" name = ""
...@@ -276,14 +283,30 @@ class DNS(Packet): ...@@ -276,14 +283,30 @@ class DNS(Packet):
name = ' "%s"' % self.qd.qname name = ' "%s"' % self.qd.qname
return 'DNS %s%s ' % (type, name) return 'DNS %s%s ' % (type, name)
dnstypes = { 0:"ANY", 255:"ALL", def post_build(self, pkt, pay):
1:"A", 2:"NS", 3:"MD", 4:"MF", 5:"CNAME", 6:"SOA", 7: "MB", 8:"MG", if isinstance(self.underlayer, TCP) and self.length is None:
9:"MR",10:"NULL",11:"WKS",12:"PTR",13:"HINFO",14:"MINFO",15:"MX",16:"TXT", pkt = struct.pack("!H", len(pkt) - 2) + pkt[2:]
17:"RP",18:"AFSDB",28:"AAAA", 33:"SRV",38:"A6",39:"DNAME", return pkt + pay
41:"OPT", 43:"DS", 46:"RRSIG", 47:"NSEC", 48:"DNSKEY",
50: "NSEC3", 51: "NSEC3PARAM", 32769:"DLV" }
# http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
dnstypes = {
0:"ANY",
1: "A", 2: "NS", 3: "MD", 4: "MF", 5: "CNAME", 6: "SOA", 7: "MB", 8: "MG",
9: "MR", 10: "NULL", 11: "WKS", 12: "PTR", 13: "HINFO", 14: "MINFO",
15: "MX", 16: "TXT", 17: "RP", 18: "AFSDB", 19: "X25", 20: "ISDN", 21: "RT",
22: "NSAP", 23: "NSAP-PTR", 24: "SIG", 25: "KEY", 26: "PX", 27: "GPOS",
28: "AAAA", 29: "LOC", 30: "NXT", 31: "EID", 32: "NIMLOC", 33: "SRV",
34: "ATMA", 35: "NAPTR", 36: "KX", 37: "CERT", 38: "A6", 39: "DNAME",
40: "SINK", 41: "OPT", 42: "APL", 43: "DS", 44: "SSHFP", 45: "IPSECKEY",
46: "RRSIG", 47: "NSEC", 48: "DNSKEY", 49: "DHCID", 50: "NSEC3",
51: "NSEC3PARAM", 55: "HIP", 56: "NINFO", 57: "RKEY", 58: "TALINK",
99: "SPF", 100: "UINFO", 101: "UID", 102: "GID", 103: "UNSPEC", 249: "TKEY",
250: "TSIG",
32768: "TA", 32769:"DLV",
}
dnsqtypes = {251:"IXFR",252:"AXFR",253:"MAILB",254:"MAILA",255:"ALL"} dnsqtypes = {251: "IXFR", 252: "AXFR", 253: "MAILB", 254: "MAILA", 255: "ALL"}
dnsqtypes.update(dnstypes) dnsqtypes.update(dnstypes)
dnsclasses = {1: 'IN', 2: 'CS', 3: 'CH', 4: 'HS', 255: 'ANY'} dnsclasses = {1: 'IN', 2: 'CS', 3: 'CH', 4: 'HS', 255: 'ANY'}
...@@ -627,6 +650,8 @@ bind_layers(UDP, DNS, dport=53) ...@@ -627,6 +650,8 @@ bind_layers(UDP, DNS, dport=53)
bind_layers(UDP, DNS, sport=53) bind_layers(UDP, DNS, sport=53)
DestIPField.bind_addr(UDP, "224.0.0.251", dport=5353) DestIPField.bind_addr(UDP, "224.0.0.251", dport=5353)
DestIP6Field.bind_addr(UDP, "ff02::fb", dport=5353) DestIP6Field.bind_addr(UDP, "ff02::fb", dport=5353)
bind_layers(TCP, DNS, dport=53)
bind_layers(TCP, DNS, sport=53)
@conf.commands.register @conf.commands.register
......
...@@ -4822,6 +4822,20 @@ pkt = IP(len=42, ihl=6, options=[IPOption_RR()]) / UDP() / ("A" * 10) ...@@ -4822,6 +4822,20 @@ pkt = IP(len=42, ihl=6, options=[IPOption_RR()]) / UDP() / ("A" * 10)
bpkt = IP(str(pkt)) bpkt = IP(str(pkt))
assert bpkt.chksum == 0x70bd and bpkt.payload.chksum == 0xbb17 assert bpkt.chksum == 0x70bd and bpkt.payload.chksum == 0xbb17
= DNS
* DNS over UDP
pkt = IP(str(IP(src="10.0.0.1", dst="8.8.8.8")/UDP(sport=RandShort(), dport=53)/DNS(qd=DNSQR(qname="secdev.org."))))
assert UDP in pkt and isinstance(pkt[UDP].payload, DNS)
assert pkt[UDP].dport == 53 and pkt[UDP].length is None
assert pkt[DNS].qdcount == 1 and pkt[DNS].qd.qname == "secdev.org."
* DNS over TCP
pkt = IP(str(IP(src="10.0.0.1", dst="8.8.8.8")/TCP(sport=RandShort(), dport=53, flags="P")/DNS(qd=DNSQR(qname="secdev.org."))))
assert TCP in pkt and isinstance(pkt[TCP].payload, DNS)
assert pkt[TCP].dport == 53 and pkt[DNS].length is not None
assert pkt[DNS].qdcount == 1 and pkt[DNS].qd.qname == "secdev.org."
= Layer binding = Layer binding
* Test DestMACField & DestIPField * Test DestMACField & DestIPField
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment