1## This file is part of Scapy 2## See http://www.secdev.org/projects/scapy for more informations 3## Copyright (C) Philippe Biondi <phil@secdev.org> 4## This program is published under a GPLv2 license 5 6""" 7DNS: Domain Name System. 8""" 9 10from __future__ import absolute_import 11import socket,struct 12 13from scapy.config import conf 14from scapy.packet import * 15from scapy.fields import * 16from scapy.compat import * 17from scapy.ansmachine import * 18from scapy.sendrecv import sr1 19from scapy.layers.inet import IP, DestIPField, UDP, TCP 20from scapy.layers.inet6 import DestIP6Field 21from scapy.error import warning 22from functools import reduce 23import scapy.modules.six as six 24from scapy.modules.six.moves import range 25 26class InheritOriginDNSStrPacket(Packet): 27 __slots__ = Packet.__slots__ + ["_orig_s", "_orig_p"] 28 29 def __init__(self, _pkt=None, _orig_s=None, _orig_p=None, *args, **kwargs): 30 self._orig_s = _orig_s 31 self._orig_p = _orig_p 32 Packet.__init__(self, _pkt=_pkt, *args, **kwargs) 33 34class DNSStrField(StrField): 35 def h2i(self, pkt, x): 36 if not x: 37 return b"." 38 return x 39 40 def i2m(self, pkt, x): 41 if x == b".": 42 return b"\x00" 43 44 # Truncate chunks that cannot be encoded (more than 63 bytes..) 45 x = b"".join(chb(len(y)) + y for y in (k[:63] for k in x.split(b"."))) 46 if orb(x[-1]) != 0: 47 x += b"\x00" 48 return x 49 50 def getfield(self, pkt, s): 51 n = b"" 52 if orb(s[0]) == 0: 53 return s[1:], b"." 54 while True: 55 l = orb(s[0]) 56 s = s[1:] 57 if not l: 58 break 59 if l & 0xc0: 60 p = ((l & ~0xc0) << 8) + orb(s[0]) - 12 61 if hasattr(pkt, "_orig_s") and pkt._orig_s: 62 ns = DNSgetstr(pkt._orig_s, p)[0] 63 n += ns 64 s = s[1:] 65 if not s: 66 break 67 else: 68 raise Scapy_Exception("DNS message can't be compressed at this point!") 69 else: 70 n += s[:l] + b"." 71 s = s[l:] 72 return s, n 73 74 75class DNSRRCountField(ShortField): 76 __slots__ = ["rr"] 77 def __init__(self, name, default, rr): 78 ShortField.__init__(self, name, default) 79 self.rr = rr 80 def _countRR(self, pkt): 81 x = getattr(pkt,self.rr) 82 i = 0 83 while isinstance(x, DNSRR) or isinstance(x, DNSQR) or isdnssecRR(x): 84 x = x.payload 85 i += 1 86 return i 87 88 def i2m(self, pkt, x): 89 if x is None: 90 x = self._countRR(pkt) 91 return x 92 def i2h(self, pkt, x): 93 if x is None: 94 x = self._countRR(pkt) 95 return x 96 97 98def DNSgetstr(s, p): 99 name = b"" 100 q = 0 101 jpath = [p] 102 while True: 103 if p >= len(s): 104 warning("DNS RR prematured end (ofs=%i, len=%i)"%(p,len(s))) 105 break 106 l = orb(s[p]) # current value of the string at p 107 p += 1 108 if l & 0xc0: # Pointer label 109 if not q: 110 q = p+1 111 if p >= len(s): 112 warning("DNS incomplete jump token at (ofs=%i)" % p) 113 break 114 p = ((l & ~0xc0) << 8) + orb(s[p]) - 12 115 if p in jpath: 116 warning("DNS decompression loop detected") 117 break 118 jpath.append(p) 119 continue 120 elif l > 0: # Label 121 name += s[p:p+l] + b"." 122 p += l 123 continue 124 break 125 if q: 126 p = q 127 return name, p 128 129 130class DNSRRField(StrField): 131 __slots__ = ["countfld", "passon"] 132 holds_packets = 1 133 def __init__(self, name, countfld, passon=1): 134 StrField.__init__(self, name, None) 135 self.countfld = countfld 136 self.passon = passon 137 def i2m(self, pkt, x): 138 if x is None: 139 return b"" 140 return raw(x) 141 def decodeRR(self, name, s, p): 142 ret = s[p:p+10] 143 type,cls,ttl,rdlen = struct.unpack("!HHIH", ret) 144 p += 10 145 rr = DNSRR(b"\x00"+ret+s[p:p+rdlen], _orig_s=s, _orig_p=p) 146 if type in [2, 3, 4, 5]: 147 rr.rdata = DNSgetstr(s,p)[0] 148 del(rr.rdlen) 149 elif type in DNSRR_DISPATCHER: 150 rr = DNSRR_DISPATCHER[type](b"\x00"+ret+s[p:p+rdlen], _orig_s=s, _orig_p=p) 151 else: 152 del(rr.rdlen) 153 154 p += rdlen 155 156 rr.rrname = name 157 return rr, p 158 def getfield(self, pkt, s): 159 if isinstance(s, tuple) : 160 s,p = s 161 else: 162 p = 0 163 ret = None 164 c = getattr(pkt, self.countfld) 165 if c > len(s): 166 warning("wrong value: DNS.%s=%i", self.countfld, c) 167 return s,b"" 168 while c: 169 c -= 1 170 name,p = DNSgetstr(s,p) 171 rr,p = self.decodeRR(name, s, p) 172 if ret is None: 173 ret = rr 174 else: 175 ret.add_payload(rr) 176 if self.passon: 177 return (s,p),ret 178 else: 179 return s[p:],ret 180 181 182class DNSQRField(DNSRRField): 183 def decodeRR(self, name, s, p): 184 ret = s[p:p+4] 185 p += 4 186 rr = DNSQR(b"\x00"+ret, _orig_s=s, _orig_p=p) 187 rr.qname = name 188 return rr, p 189 190 191 192class RDataField(StrLenField): 193 def m2i(self, pkt, s): 194 family = None 195 if pkt.type == 1: # A 196 family = socket.AF_INET 197 elif pkt.type in [2, 5, 12]: # NS, CNAME, PTR 198 l = orb(s[0]) 199 if l & 0xc0 and hasattr(pkt, "_orig_s") and pkt._orig_s: # Compression detected 200 p = ((l & ~0xc0) << 8) + orb(s[1]) - 12 201 s = DNSgetstr(pkt._orig_s, p)[0] 202 else: # No compression / Cannot decompress 203 if hasattr(pkt, "_orig_s") and pkt._orig_s: 204 s = DNSgetstr(pkt._orig_s, pkt._orig_p)[0] 205 else: 206 s = DNSgetstr(s, 0)[0] 207 elif pkt.type == 16: # TXT 208 ret_s = b"" 209 tmp_s = s 210 # RDATA contains a list of strings, each are prepended with 211 # a byte containing the size of the following string. 212 while tmp_s: 213 tmp_len = orb(tmp_s[0]) + 1 214 if tmp_len > len(tmp_s): 215 warning("DNS RR TXT prematured end of character-string (size=%i, remaining bytes=%i)" % (tmp_len, len(tmp_s))) 216 ret_s += tmp_s[1:tmp_len] 217 tmp_s = tmp_s[tmp_len:] 218 s = ret_s 219 elif pkt.type == 28: # AAAA 220 family = socket.AF_INET6 221 if family is not None: 222 s = inet_ntop(family, s) 223 return s 224 def i2m(self, pkt, s): 225 if pkt.type == 1: # A 226 if s: 227 s = inet_aton(s) 228 elif pkt.type in [2, 3, 4, 5, 12]: # NS, MD, MF, CNAME, PTR 229 s = b"".join(chb(len(x)) + x for x in s.split(b'.')) 230 if orb(s[-1]): 231 s += b"\x00" 232 elif pkt.type == 16: # TXT 233 if s: 234 s = raw(s) 235 ret_s = b"" 236 # The initial string must be splitted into a list of strings 237 # prepended with theirs sizes. 238 while len(s) >= 255: 239 ret_s += b"\xff" + s[:255] 240 s = s[255:] 241 # The remaining string is less than 255 bytes long 242 if len(s): 243 ret_s += struct.pack("!B", len(s)) + s 244 s = ret_s 245 elif pkt.type == 28: # AAAA 246 if s: 247 s = inet_pton(socket.AF_INET6, s) 248 return s 249 250class RDLenField(Field): 251 def __init__(self, name): 252 Field.__init__(self, name, None, "H") 253 def i2m(self, pkt, x): 254 if x is None: 255 rdataf = pkt.get_field("rdata") 256 x = len(rdataf.i2m(pkt, pkt.rdata)) 257 return x 258 def i2h(self, pkt, x): 259 if x is None: 260 rdataf = pkt.get_field("rdata") 261 x = len(rdataf.i2m(pkt, pkt.rdata)) 262 return x 263 264 265class DNS(Packet): 266 name = "DNS" 267 fields_desc = [ 268 ConditionalField(ShortField("length", None), 269 lambda p: isinstance(p.underlayer, TCP)), 270 ShortField("id", 0), 271 BitField("qr", 0, 1), 272 BitEnumField("opcode", 0, 4, {0: "QUERY", 1: "IQUERY", 2: "STATUS"}), 273 BitField("aa", 0, 1), 274 BitField("tc", 0, 1), 275 BitField("rd", 1, 1), 276 BitField("ra", 0, 1), 277 BitField("z", 0, 1), 278 # AD and CD bits are defined in RFC 2535 279 BitField("ad", 0, 1), # Authentic Data 280 BitField("cd", 0, 1), # Checking Disabled 281 BitEnumField("rcode", 0, 4, {0: "ok", 1: "format-error", 282 2: "server-failure", 3: "name-error", 283 4: "not-implemented", 5: "refused"}), 284 DNSRRCountField("qdcount", None, "qd"), 285 DNSRRCountField("ancount", None, "an"), 286 DNSRRCountField("nscount", None, "ns"), 287 DNSRRCountField("arcount", None, "ar"), 288 DNSQRField("qd", "qdcount"), 289 DNSRRField("an", "ancount"), 290 DNSRRField("ns", "nscount"), 291 DNSRRField("ar", "arcount", 0), 292 ] 293 294 def answers(self, other): 295 return (isinstance(other, DNS) 296 and self.id == other.id 297 and self.qr == 1 298 and other.qr == 0) 299 300 def mysummary(self): 301 type = ["Qry","Ans"][self.qr] 302 name = "" 303 if self.qr: 304 type = "Ans" 305 if self.ancount > 0 and isinstance(self.an, DNSRR): 306 name = ' "%s"' % self.an.rdata 307 else: 308 type = "Qry" 309 if self.qdcount > 0 and isinstance(self.qd, DNSQR): 310 name = ' "%s"' % self.qd.qname 311 return 'DNS %s%s ' % (type, name) 312 313 def post_build(self, pkt, pay): 314 if isinstance(self.underlayer, TCP) and self.length is None: 315 pkt = struct.pack("!H", len(pkt) - 2) + pkt[2:] 316 return pkt + pay 317 318 319# https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4 320dnstypes = { 321 0:"ANY", 322 1: "A", 2: "NS", 3: "MD", 4: "MF", 5: "CNAME", 6: "SOA", 7: "MB", 8: "MG", 323 9: "MR", 10: "NULL", 11: "WKS", 12: "PTR", 13: "HINFO", 14: "MINFO", 324 15: "MX", 16: "TXT", 17: "RP", 18: "AFSDB", 19: "X25", 20: "ISDN", 21: "RT", 325 22: "NSAP", 23: "NSAP-PTR", 24: "SIG", 25: "KEY", 26: "PX", 27: "GPOS", 326 28: "AAAA", 29: "LOC", 30: "NXT", 31: "EID", 32: "NIMLOC", 33: "SRV", 327 34: "ATMA", 35: "NAPTR", 36: "KX", 37: "CERT", 38: "A6", 39: "DNAME", 328 40: "SINK", 41: "OPT", 42: "APL", 43: "DS", 44: "SSHFP", 45: "IPSECKEY", 329 46: "RRSIG", 47: "NSEC", 48: "DNSKEY", 49: "DHCID", 50: "NSEC3", 330 51: "NSEC3PARAM", 52: "TLSA", 53: "SMIMEA", 55: "HIP", 56: "NINFO", 57: "RKEY", 331 58: "TALINK", 59: "CDS", 60: "CDNSKEY", 61: "OPENPGPKEY", 62: "CSYNC", 332 99: "SPF", 100: "UINFO", 101: "UID", 102: "GID", 103: "UNSPEC", 104: "NID", 333 105: "L32", 106: "L64", 107: "LP", 108: "EUI48", 109: "EUI64", 334 249: "TKEY", 250: "TSIG", 256: "URI", 257: "CAA", 258: "AVC", 335 32768: "TA", 32769: "DLV", 65535: "RESERVED" 336} 337 338dnsqtypes = {251: "IXFR", 252: "AXFR", 253: "MAILB", 254: "MAILA", 255: "ALL"} 339dnsqtypes.update(dnstypes) 340dnsclasses = {1: 'IN', 2: 'CS', 3: 'CH', 4: 'HS', 255: 'ANY'} 341 342 343class DNSQR(InheritOriginDNSStrPacket): 344 name = "DNS Question Record" 345 show_indent=0 346 fields_desc = [DNSStrField("qname", "www.example.com"), 347 ShortEnumField("qtype", 1, dnsqtypes), 348 ShortEnumField("qclass", 1, dnsclasses)] 349 350 351 352# RFC 2671 - Extension Mechanisms for DNS (EDNS0) 353 354class EDNS0TLV(Packet): 355 name = "DNS EDNS0 TLV" 356 fields_desc = [ ShortEnumField("optcode", 0, { 0: "Reserved", 1: "LLQ", 2: "UL", 3: "NSID", 4: "Reserved", 5: "PING" }), 357 FieldLenField("optlen", None, "optdata", fmt="H"), 358 StrLenField("optdata", "", length_from=lambda pkt: pkt.optlen) ] 359 360 def extract_padding(self, p): 361 return "", p 362 363class DNSRROPT(InheritOriginDNSStrPacket): 364 name = "DNS OPT Resource Record" 365 fields_desc = [ DNSStrField("rrname",""), 366 ShortEnumField("type", 41, dnstypes), 367 ShortField("rclass", 4096), 368 ByteField("extrcode", 0), 369 ByteField("version", 0), 370 # version 0 means EDNS0 371 BitEnumField("z", 32768, 16, { 32768: "D0" }), 372 # D0 means DNSSEC OK from RFC 3225 373 FieldLenField("rdlen", None, length_of="rdata", fmt="H"), 374 PacketListField("rdata", [], EDNS0TLV, length_from=lambda pkt: pkt.rdlen) ] 375 376# RFC 4034 - Resource Records for the DNS Security Extensions 377 378# 09/2013 from http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml 379dnssecalgotypes = { 0:"Reserved", 1:"RSA/MD5", 2:"Diffie-Hellman", 3:"DSA/SHA-1", 380 4:"Reserved", 5:"RSA/SHA-1", 6:"DSA-NSEC3-SHA1", 381 7:"RSASHA1-NSEC3-SHA1", 8:"RSA/SHA-256", 9:"Reserved", 382 10:"RSA/SHA-512", 11:"Reserved", 12:"GOST R 34.10-2001", 383 13:"ECDSA Curve P-256 with SHA-256", 14: "ECDSA Curve P-384 with SHA-384", 384 252:"Reserved for Indirect Keys", 253:"Private algorithms - domain name", 385 254:"Private algorithms - OID", 255:"Reserved" } 386 387# 09/2013 from http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml 388dnssecdigesttypes = { 0:"Reserved", 1:"SHA-1", 2:"SHA-256", 3:"GOST R 34.11-94", 4:"SHA-384" } 389 390 391class TimeField(IntField): 392 393 def any2i(self, pkt, x): 394 if isinstance(x, str): 395 import time, calendar 396 t = time.strptime(x, "%Y%m%d%H%M%S") 397 return int(calendar.timegm(t)) 398 return x 399 400 def i2repr(self, pkt, x): 401 import time 402 x = self.i2h(pkt, x) 403 t = time.strftime("%Y%m%d%H%M%S", time.gmtime(x)) 404 return "%s (%d)" % (t ,x) 405 406 407def bitmap2RRlist(bitmap): 408 """ 409 Decode the 'Type Bit Maps' field of the NSEC Resource Record into an 410 integer list. 411 """ 412 # RFC 4034, 4.1.2. The Type Bit Maps Field 413 414 RRlist = [] 415 416 while bitmap: 417 418 if len(bitmap) < 2: 419 warning("bitmap too short (%i)" % len(bitmap)) 420 return 421 422 window_block = orb(bitmap[0]) # window number 423 offset = 256 * window_block # offset of the Resource Record 424 bitmap_len = orb(bitmap[1]) # length of the bitmap in bytes 425 426 if bitmap_len <= 0 or bitmap_len > 32: 427 warning("bitmap length is no valid (%i)" % bitmap_len) 428 return 429 430 tmp_bitmap = bitmap[2:2+bitmap_len] 431 432 # Let's compare each bit of tmp_bitmap and compute the real RR value 433 for b in range(len(tmp_bitmap)): 434 v = 128 435 for i in range(8): 436 if orb(tmp_bitmap[b]) & v: 437 # each of the RR is encoded as a bit 438 RRlist += [ offset + b*8 + i ] 439 v = v >> 1 440 441 # Next block if any 442 bitmap = bitmap[2+bitmap_len:] 443 444 return RRlist 445 446 447def RRlist2bitmap(lst): 448 """ 449 Encode a list of integers representing Resource Records to a bitmap field 450 used in the NSEC Resource Record. 451 """ 452 # RFC 4034, 4.1.2. The Type Bit Maps Field 453 454 import math 455 456 bitmap = b"" 457 lst = [abs(x) for x in sorted(set(lst)) if x <= 65535] 458 459 # number of window blocks 460 max_window_blocks = int(math.ceil(lst[-1] / 256.)) 461 min_window_blocks = int(math.floor(lst[0] / 256.)) 462 if min_window_blocks == max_window_blocks: 463 max_window_blocks += 1 464 465 for wb in range(min_window_blocks, max_window_blocks+1): 466 # First, filter out RR not encoded in the current window block 467 # i.e. keep everything between 256*wb <= 256*(wb+1) 468 rrlist = sorted(x for x in lst if 256 * wb <= x < 256 * (wb + 1)) 469 if not rrlist: 470 continue 471 472 # Compute the number of bytes used to store the bitmap 473 if rrlist[-1] == 0: # only one element in the list 474 bytes_count = 1 475 else: 476 max = rrlist[-1] - 256*wb 477 bytes_count = int(math.ceil(max // 8)) + 1 # use at least 1 byte 478 if bytes_count > 32: # Don't encode more than 256 bits / values 479 bytes_count = 32 480 481 bitmap += struct.pack("BB", wb, bytes_count) 482 483 # Generate the bitmap 484 # The idea is to remove out of range Resource Records with these steps 485 # 1. rescale to fit into 8 bits 486 # 2. x gives the bit position ; compute the corresponding value 487 # 3. sum everything 488 bitmap += b"".join( 489 struct.pack( 490 b"B", 491 sum(2 ** (7 - (x - 256 * wb) + (tmp * 8)) for x in rrlist 492 if 256 * wb + 8 * tmp <= x < 256 * wb + 8 * tmp + 8), 493 ) for tmp in range(bytes_count) 494 ) 495 496 return bitmap 497 498 499class RRlistField(StrField): 500 def h2i(self, pkt, x): 501 if isinstance(x, list): 502 return RRlist2bitmap(x) 503 return x 504 505 def i2repr(self, pkt, x): 506 x = self.i2h(pkt, x) 507 rrlist = bitmap2RRlist(x) 508 return [ dnstypes.get(rr, rr) for rr in rrlist ] if rrlist else repr(x) 509 510 511class _DNSRRdummy(InheritOriginDNSStrPacket): 512 name = "Dummy class that implements post_build() for Resource Records" 513 def post_build(self, pkt, pay): 514 if not self.rdlen == None: 515 return pkt 516 517 lrrname = len(self.fields_desc[0].i2m("", self.getfieldval("rrname"))) 518 l = len(pkt) - lrrname - 10 519 pkt = pkt[:lrrname+8] + struct.pack("!H", l) + pkt[lrrname+8+2:] 520 521 return pkt 522 523class DNSRRSOA(_DNSRRdummy): 524 name = "DNS SOA Resource Record" 525 fields_desc = [ DNSStrField("rrname",""), 526 ShortEnumField("type", 6, dnstypes), 527 ShortEnumField("rclass", 1, dnsclasses), 528 IntField("ttl", 0), 529 ShortField("rdlen", None), 530 DNSStrField("mname", ""), 531 DNSStrField("rname", ""), 532 IntField("serial", 0), 533 IntField("refresh", 0), 534 IntField("retry", 0), 535 IntField("expire", 0), 536 IntField("minimum", 0) 537 ] 538 539class DNSRRRSIG(_DNSRRdummy): 540 name = "DNS RRSIG Resource Record" 541 fields_desc = [ DNSStrField("rrname",""), 542 ShortEnumField("type", 46, dnstypes), 543 ShortEnumField("rclass", 1, dnsclasses), 544 IntField("ttl", 0), 545 ShortField("rdlen", None), 546 ShortEnumField("typecovered", 1, dnstypes), 547 ByteEnumField("algorithm", 5, dnssecalgotypes), 548 ByteField("labels", 0), 549 IntField("originalttl", 0), 550 TimeField("expiration", 0), 551 TimeField("inception", 0), 552 ShortField("keytag", 0), 553 DNSStrField("signersname", ""), 554 StrField("signature", "") 555 ] 556 557 558class DNSRRNSEC(_DNSRRdummy): 559 name = "DNS NSEC Resource Record" 560 fields_desc = [ DNSStrField("rrname",""), 561 ShortEnumField("type", 47, dnstypes), 562 ShortEnumField("rclass", 1, dnsclasses), 563 IntField("ttl", 0), 564 ShortField("rdlen", None), 565 DNSStrField("nextname", ""), 566 RRlistField("typebitmaps", "") 567 ] 568 569 570class DNSRRDNSKEY(_DNSRRdummy): 571 name = "DNS DNSKEY Resource Record" 572 fields_desc = [ DNSStrField("rrname",""), 573 ShortEnumField("type", 48, dnstypes), 574 ShortEnumField("rclass", 1, dnsclasses), 575 IntField("ttl", 0), 576 ShortField("rdlen", None), 577 FlagsField("flags", 256, 16, "S???????Z???????"), 578 # S: Secure Entry Point 579 # Z: Zone Key 580 ByteField("protocol", 3), 581 ByteEnumField("algorithm", 5, dnssecalgotypes), 582 StrField("publickey", "") 583 ] 584 585 586class DNSRRDS(_DNSRRdummy): 587 name = "DNS DS Resource Record" 588 fields_desc = [ DNSStrField("rrname",""), 589 ShortEnumField("type", 43, dnstypes), 590 ShortEnumField("rclass", 1, dnsclasses), 591 IntField("ttl", 0), 592 ShortField("rdlen", None), 593 ShortField("keytag", 0), 594 ByteEnumField("algorithm", 5, dnssecalgotypes), 595 ByteEnumField("digesttype", 5, dnssecdigesttypes), 596 StrField("digest", "") 597 ] 598 599 600# RFC 5074 - DNSSEC Lookaside Validation (DLV) 601class DNSRRDLV(DNSRRDS): 602 name = "DNS DLV Resource Record" 603 def __init__(self, *args, **kargs): 604 DNSRRDS.__init__(self, *args, **kargs) 605 if not kargs.get('type', 0): 606 self.type = 32769 607 608# RFC 5155 - DNS Security (DNSSEC) Hashed Authenticated Denial of Existence 609class DNSRRNSEC3(_DNSRRdummy): 610 name = "DNS NSEC3 Resource Record" 611 fields_desc = [ DNSStrField("rrname",""), 612 ShortEnumField("type", 50, dnstypes), 613 ShortEnumField("rclass", 1, dnsclasses), 614 IntField("ttl", 0), 615 ShortField("rdlen", None), 616 ByteField("hashalg", 0), 617 BitEnumField("flags", 0, 8, {1:"Opt-Out"}), 618 ShortField("iterations", 0), 619 FieldLenField("saltlength", 0, fmt="!B", length_of="salt"), 620 StrLenField("salt", "", length_from=lambda x: x.saltlength), 621 FieldLenField("hashlength", 0, fmt="!B", length_of="nexthashedownername"), 622 StrLenField("nexthashedownername", "", length_from=lambda x: x.hashlength), 623 RRlistField("typebitmaps", "") 624 ] 625 626 627class DNSRRNSEC3PARAM(_DNSRRdummy): 628 name = "DNS NSEC3PARAM Resource Record" 629 fields_desc = [ DNSStrField("rrname",""), 630 ShortEnumField("type", 51, dnstypes), 631 ShortEnumField("rclass", 1, dnsclasses), 632 IntField("ttl", 0), 633 ShortField("rdlen", None), 634 ByteField("hashalg", 0), 635 ByteField("flags", 0), 636 ShortField("iterations", 0), 637 FieldLenField("saltlength", 0, fmt="!B", length_of="salt"), 638 StrLenField("salt", "", length_from=lambda pkt: pkt.saltlength) 639 ] 640 641# RFC 2782 - A DNS RR for specifying the location of services (DNS SRV) 642 643class DNSRRSRV(InheritOriginDNSStrPacket): 644 name = "DNS SRV Resource Record" 645 fields_desc = [ DNSStrField("rrname",""), 646 ShortEnumField("type", 51, dnstypes), 647 ShortEnumField("rclass", 1, dnsclasses), 648 IntField("ttl", 0), 649 ShortField("rdlen", None), 650 ShortField("priority", 0), 651 ShortField("weight", 0), 652 ShortField("port", 0), 653 DNSStrField("target",""), ] 654 655# RFC 2845 - Secret Key Transaction Authentication for DNS (TSIG) 656tsig_algo_sizes = { "HMAC-MD5.SIG-ALG.REG.INT": 16, 657 "hmac-sha1": 20 } 658 659class TimeSignedField(StrFixedLenField): 660 def __init__(self, name, default): 661 StrFixedLenField.__init__(self, name, default, 6) 662 663 def _convert_seconds(self, packed_seconds): 664 """Unpack the internal representation.""" 665 seconds = struct.unpack("!H", packed_seconds[:2])[0] 666 seconds += struct.unpack("!I", packed_seconds[2:])[0] 667 return seconds 668 669 def h2i(self, pkt, seconds): 670 """Convert the number of seconds since 1-Jan-70 UTC to the packed 671 representation.""" 672 673 if seconds is None: 674 seconds = 0 675 676 tmp_short = (seconds >> 32) & 0xFFFF 677 tmp_int = seconds & 0xFFFFFFFF 678 679 return struct.pack("!HI", tmp_short, tmp_int) 680 681 def i2h(self, pkt, packed_seconds): 682 """Convert the internal representation to the number of seconds 683 since 1-Jan-70 UTC.""" 684 685 if packed_seconds is None: 686 return None 687 688 return self._convert_seconds(packed_seconds) 689 690 def i2repr(self, pkt, packed_seconds): 691 """Convert the internal representation to a nice one using the RFC 692 format.""" 693 time_struct = time.gmtime(self._convert_seconds(packed_seconds)) 694 return time.strftime("%a %b %d %H:%M:%S %Y", time_struct) 695 696class DNSRRTSIG(_DNSRRdummy): 697 name = "DNS TSIG Resource Record" 698 fields_desc = [ DNSStrField("rrname", ""), 699 ShortEnumField("type", 250, dnstypes), 700 ShortEnumField("rclass", 1, dnsclasses), 701 IntField("ttl", 0), 702 ShortField("rdlen", None), 703 DNSStrField("algo_name", "hmac-sha1"), 704 TimeSignedField("time_signed", 0), 705 ShortField("fudge", 0), 706 FieldLenField("mac_len", 20, fmt="!H", length_of="mac_data"), 707 StrLenField("mac_data", "", length_from=lambda pkt: pkt.mac_len), 708 ShortField("original_id", 0), 709 ShortField("error", 0), 710 FieldLenField("other_len", 0, fmt="!H", length_of="other_data"), 711 StrLenField("other_data", "", length_from=lambda pkt: pkt.other_len) 712 ] 713 714 715DNSRR_DISPATCHER = { 716 33: DNSRRSRV, # RFC 2782 717 41: DNSRROPT, # RFC 1671 718 43: DNSRRDS, # RFC 4034 719 46: DNSRRRSIG, # RFC 4034 720 47: DNSRRNSEC, # RFC 4034 721 48: DNSRRDNSKEY, # RFC 4034 722 50: DNSRRNSEC3, # RFC 5155 723 51: DNSRRNSEC3PARAM, # RFC 5155 724 250: DNSRRTSIG, # RFC 2845 725 32769: DNSRRDLV, # RFC 4431 726} 727 728DNSSEC_CLASSES = tuple(six.itervalues(DNSRR_DISPATCHER)) 729 730def isdnssecRR(obj): 731 return isinstance(obj, DNSSEC_CLASSES) 732 733class DNSRR(InheritOriginDNSStrPacket): 734 name = "DNS Resource Record" 735 show_indent=0 736 fields_desc = [ DNSStrField("rrname",""), 737 ShortEnumField("type", 1, dnstypes), 738 ShortEnumField("rclass", 1, dnsclasses), 739 IntField("ttl", 0), 740 RDLenField("rdlen"), 741 RDataField("rdata", "", length_from=lambda pkt:pkt.rdlen) ] 742 743 744bind_layers(UDP, DNS, dport=5353) 745bind_layers(UDP, DNS, sport=5353) 746bind_layers(UDP, DNS, dport=53) 747bind_layers(UDP, DNS, sport=53) 748DestIPField.bind_addr(UDP, "224.0.0.251", dport=5353) 749DestIP6Field.bind_addr(UDP, "ff02::fb", dport=5353) 750bind_layers(TCP, DNS, dport=53) 751bind_layers(TCP, DNS, sport=53) 752 753 754@conf.commands.register 755def dyndns_add(nameserver, name, rdata, type="A", ttl=10): 756 """Send a DNS add message to a nameserver for "name" to have a new "rdata" 757dyndns_add(nameserver, name, rdata, type="A", ttl=10) -> result code (0=ok) 758 759example: dyndns_add("ns1.toto.com", "dyn.toto.com", "127.0.0.1") 760RFC2136 761""" 762 zone = name[name.find(".")+1:] 763 r=sr1(IP(dst=nameserver)/UDP()/DNS(opcode=5, 764 qd=[DNSQR(qname=zone, qtype="SOA")], 765 ns=[DNSRR(rrname=name, type="A", 766 ttl=ttl, rdata=rdata)]), 767 verbose=0, timeout=5) 768 if r and r.haslayer(DNS): 769 return r.getlayer(DNS).rcode 770 else: 771 return -1 772 773 774 775 776@conf.commands.register 777def dyndns_del(nameserver, name, type="ALL", ttl=10): 778 """Send a DNS delete message to a nameserver for "name" 779dyndns_del(nameserver, name, type="ANY", ttl=10) -> result code (0=ok) 780 781example: dyndns_del("ns1.toto.com", "dyn.toto.com") 782RFC2136 783""" 784 zone = name[name.find(".")+1:] 785 r=sr1(IP(dst=nameserver)/UDP()/DNS(opcode=5, 786 qd=[DNSQR(qname=zone, qtype="SOA")], 787 ns=[DNSRR(rrname=name, type=type, 788 rclass="ANY", ttl=0, rdata="")]), 789 verbose=0, timeout=5) 790 if r and r.haslayer(DNS): 791 return r.getlayer(DNS).rcode 792 else: 793 return -1 794 795 796class DNS_am(AnsweringMachine): 797 function_name="dns_spoof" 798 filter = "udp port 53" 799 800 def parse_options(self, joker="192.168.1.1", match=None): 801 if match is None: 802 self.match = {} 803 else: 804 self.match = match 805 self.joker=joker 806 807 def is_request(self, req): 808 return req.haslayer(DNS) and req.getlayer(DNS).qr == 0 809 810 def make_reply(self, req): 811 ip = req.getlayer(IP) 812 dns = req.getlayer(DNS) 813 resp = IP(dst=ip.src, src=ip.dst)/UDP(dport=ip.sport,sport=ip.dport) 814 rdata = self.match.get(dns.qd.qname, self.joker) 815 resp /= DNS(id=dns.id, qr=1, qd=dns.qd, 816 an=DNSRR(rrname=dns.qd.qname, ttl=10, rdata=rdata)) 817 return resp 818 819 820