Coverage for /root/GitHubProjects/impacket/impacket/dns.py : 74%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved.
2#
3# This software is provided under under a slightly modified version
4# of the Apache Software License. See the accompanying LICENSE file
5# for more information.
6#
7# Author:
8# Andres Blanco
9# Gustavo Moreira
11#
12# RFCs for the DNS Server service
13#
14# 1034 - Domain Names -- Concepts and Facilities [https://www.ietf.org/rfc/rfc1034.txt]
15# 1035 - Domain Names -- Implementation and Specification [https://www.ietf.org/rfc/rfc1035.txt]
16# 1123 - Requirements for Internet Hosts -- Application and Support [https://www.ietf.org/rfc/rfc1123.txt]
17# 1886 - DNS Extensions to Support IP Version 6 [https://www.ietf.org/rfc/rfc1886.txt]
18# 1995 - Incremental Zone Transfer in DNS [https://www.ietf.org/rfc/rfc1995.txt]
19# 1996 - A Mechanism for Prompt Notification of Zone Changes (DNS NOTIFY) [https://www.ietf.org/rfc/rfc1996.txt]
20# 2136 - Dynamic Updates in the Domain Name System (DNS UPDATE) [https://www.ietf.org/rfc/rfc2136.txt]
21# 2181 - Clarifications to the DNS Specification [https://www.ietf.org/rfc/rfc2181.txt]
22# 2308 - Negative Caching of DNS Queries (DNS NCACHE) [https://www.ietf.org/rfc/rfc2308.txt]
23# 2535 - Domain Name System Security Extensions (DNSSEC) [https://www.ietf.org/rfc/rfc2535.txt]
24# 2671 - Extension Mechanisms for DNS (EDNS0) [https://www.ietf.org/rfc/rfc2671.txt]
25# 2782 - A DNS RR for specifying the location of services (DNS SRV) [https://www.ietf.org/rfc/rfc2782.txt]
26# 2930 - Secret Key Establishment for DNS (TKEY RR) [https://www.ietf.org/rfc/rfc2930.txt]
27# 3645 - Generic Security Service Algorithm for Secret Key Transaction Authentication for DNS (GSS-TSIG) [https://www.ietf.org/rfc/rfc3645.txt]
28# 3646 - DNS Configuration options for Dynamic Host Configuration Protocol for IPv6 (DHCPv6) [https://www.ietf.org/rfc/rfc3646.txt]
29#
31import socket
32import struct
34from impacket.ImpactPacket import ProtocolPacket
37class DNSFlags():
38 'Bitmap with the flags of a dns packet.'
39 # QR - Query/Response - 1 bit
40 QR_QUERY = int("0000000000000000", 2)
41 QR_RESPONSE = int("1000000000000000", 2)
42 # OP - Opcode - 4 bits
43 OP_STANDARD_QUERY = int("0000000000000000", 2) # Standard query.
44 OP_INVERSE_QUERY = int("0100000000000000", 2) # Inverse query.
45 OP_STATUS_QUERY = int("0010000000000000", 2) # Server status request.
46 OP_NOTIFY = int("0000100000000000", 2) # Notify.
47 OP_UPDATE = int("0100100000000000", 2) # Update.
48 # AA - Authority Answer - 1 bit
49 AA_NOT_AUTH_ANSWER = int("0000000000000000", 2) # Not authoritative.
50 AA_AUTH_ANSWER = int("0000010000000000", 2) # Is authoritative.
51 # TC - Truncated - 1 bit
52 TC_NOT_TRUNCATED = int("0000000000000000", 2) # Not truncated.
53 TC_TRUNCATED = int("0000001000000000", 2) # Message truncated.
54 # RD - Recursion Desired - 1 bit
55 RD_NOT_RECURSIVE_QUERY = int("0000000000000000", 2) # Recursion not desired.
56 RD_RECURSIVE_QUERY = int("0000000100000000", 2) # Recursion desired.
57 # RA - Recursion Available - 1 bit
58 RA_NOT_AVAILABLE = int("0000000000000000", 2) # Recursive query support not available.
59 RA_AVAILABLE = int("0000000010000000", 2) # Recursive query support available.
60 # Z - 3 bits
61 Z = int("0000000000000000", 2)
62 # AD - Authenticated Data - 1 bit
63 AUTHENTICATED_DATA = int("0000000000100000", 2)
64 # CD - Checking Disabled - 1 bit
65 CHECKING_DISABLED = int("0000000000010000", 2)
66 # RCODE - 4 bits
67 RCODE_NO_ERROR = int("0000000000000000", 2) # The request completed successfully.
68 RCODE_FORMAT_ERROR = int("0000000000001000", 2) # The name server was unable to interpret the query.
69 RCODE_SERVER_FAILURE = int("0000000000000100", 2) # The name server was unable to process this query due to a problem with the name server.
70 RCODE_NAME_ERROR = int("0000000000001100", 2) # Meaningful only for responses from an authoritative name server, this code signifies that the domain name referenced in the query does not exist.
71 RCODE_NOT_IMPLEMENTED = int("0000000000000010", 2) # Not Implemented. The name server does not support the requested kind of query.
72 RCODE_REFUSED = int("0000000000001010", 2) # The name server refuses to perform the specified operation for policy reasons.
73 RCODE_YXDOMAIN = int("0000000000000110", 2) # Name Exists when it should not.
74 RCODE_YXRRSET = int("0000000000001110", 2) # RR Set Exists when it should not.
75 RCODE_NXRRSET = int("0000000000000001", 2) # RR Set that should exist does not.
76 RCODE_NOAUTH = int("0000000000001001", 2) # Server Not Authoritative for zone.
77 RCODE_NOTZONE = int("0000000000000101", 2) # Name not contained in zone.
79class DNSType():
80 A = 1 # IPv4 address.
81 NS = 2 # Authoritative name server.
82 MD = 3 # Mail destination. Obsolete use MX instead.
83 MF = 4 # Mail forwarder. Obsolete use MX instead.
84 CNAME = 5 # Canonical name for an alias.
85 SOA = 6 # Marks the start of a zone of authority.
86 MB = 7 # Mailbox domain name.
87 MG = 8 # Mail group member.
88 MR = 9 # Mail rename domain name.
89 NULL = 10 # Null resource record.
90 WKS = 11 # Well known service description.
91 PTR = 12 # Domain name pointer.
92 HINFO = 13 # Host information.
93 MINFO = 14 # Mailbox or mail list information.
94 MX = 15 # Mail exchange.
95 TXT = 16 # Text strings.
96 RP = 17 # Responsible Person.
97 AFSDB = 18 # AFS Data Base location.
98 X25 = 19 # X.25 PSDN address.
99 ISDN = 20 # ISDN address.
100 RT = 21 # Route Through.
101 NSAP = 22 # NSAP address. NSAP style A record.
102 NSAP_PTR = 23 # NSAP pointer.
103 SIG = 24 # Security signature.
104 KEY = 25 # Security key.
105 PX = 26 # X.400 mail mapping information.
106 GPOS = 27 # Geographical Position.
107 AAAA = 28 # IPv6 Address.
108 LOC = 29 # Location Information.
109 NXT = 30 # Next Domain (obsolete).
110 EID = 31 # Endpoint Identifier.
111 NB = 32 # NetBIOS general Name Service.
112 NBSTAT = 33 # NetBIOS NODE STATUS.
113 ATMA = 34 # ATM Address.
114 NAPTR = 35 # Naming Authority Pointer.
115 KX = 36 # Key Exchanger.
116 CERT = 37
117 A6 = 38
118 DNAME = 39
119 SINK = 40
120 OPT = 41
121 APL = 42
122 DS = 43 # Delegation Signer.
123 SSHFP = 44 # SSH Key Fingerprint.
124 IPSECKEY = 45
125 RRSIG = 46
126 NSEC = 47 # NextSECure.
127 DNSKEY = 48
128 DHCID = 49 # DHCP identifier.
129 NSEC3 = 50
130 NSEC3PARAM = 51
132 HIP = 55 # Host Identity Protocol.
133 NINFO = 56
134 RKEY = 57
136 SPF = 99 # Sender Policy Framework.
137 UINFO = 100
138 UID = 101
139 GID = 102
140 UNSPEC = 103
142 TKEY = 249
143 TSIG = 250 # Transaction Signature.
144 IXFR = 251 # Incremental transfer.
145 AXFR = 252 # A request for a transfer of an entire zone.
146 MAILB = 253 # A request for mailbox-related records (MB, MG or MR).
147 MAILA = 254 # A request for mail agent RRs. Obsolete.
148 ALL = 255 # A request for all records.
150 DNSSEC = 32768 # Trust Authorities.
151 DNSSEC = 32769 # DNSSEC Lookaside Validation.
153 @staticmethod
154 def getTypeName(type):
155 for item, value in list(DNSType.__dict__.items()): 155 ↛ exitline 155 didn't return from function 'getTypeName', because the loop on line 155 didn't complete
156 if value == type:
157 return item
160class DNSClass():
161 RESERVED = 0
162 IN = 1 # Internet.
163 CH = 3 # Chaos.
164 HS = 4 # Hesiod.
166 NONE = 254
167 ANY = 255 # QCLASS only
169 @staticmethod
170 def getClassName(type):
171 for item, value in list(DNSClass.__dict__.items()): 171 ↛ exitline 171 didn't return from function 'getClassName', because the loop on line 171 didn't complete
172 if value == type:
173 return item
175class DNS(ProtocolPacket):
176 '''The Message Header is present in all messages. Never empty.
177 Contains various flags and values which control the transaction.'''
179 __TYPE_LEN = 2 # Unsigned 16 bit value.
180 __CLASS_LEN = 2 # Unsigned 16 bit value.
181 __POINTER_LEN = 2 # A pointer is an unsigned 16-bit value.
182 __TTL_LEN = 4 # Unsigned 32 bit value. The time in seconds that the record may be cached.
183 __RDLENGTH_LEN = 2 # Unsigned 16-bit value that defines the length in bytes (octets) of the RDATA record.
184 __TYPE_A_LEN = 4 # Unsigned 32-bit value representing the IP address.
185 __SERIAL_LEN = 4 # Serial Number Unsigned 32-bit integer.
186 __REFRESH_LEN = 4 # Refresh interval Unsigned 32-bit integer.
187 __RETRY_LEN = 4 # Retry Interval Unsigned 32-bit integer.
188 __EXPIRATION_LEN = 4 # Expiration Limit Unsigned 32-bit integer.
189 __MINTTL_LEN = 4 # Minimum TTL Unsigned 32-bit integer.
190 __PREF_LEN = 2 # Preference Unsigned 16-bit integer.
191 __IS_POINTER = int("11000000", 2)
192 __OFFSETMASK = int("00111111", 2)
194 def __init__(self, aBuffer = None):
195 self.__HEADER_BASE_SIZE = 12
196 self.__TAIL_SIZE = 0
197 ProtocolPacket.__init__(self, self.__HEADER_BASE_SIZE, self.__TAIL_SIZE)
198 if aBuffer: 198 ↛ exitline 198 didn't return from function '__init__', because the condition on line 198 was never false
199 self.load_packet(aBuffer)
201 def get_transaction_id(self):
202 'Get 16 bit message ID.'
203 return self.header.get_word(0)
205 def set_transaction_id(self, value):
206 'Set 16 bit message ID.'
207 self.header.set_word(0, value)
209 def get_transaction_id_tcp(self):
210 'Get 16 bit message ID.'
211 return self.header.get_word(2)
213 def set_transaction_id_tcp(self, value):
214 'Set 16 bit message ID.'
215 self.header.set_word(2, value)
217 def get_flags(self):
218 'Get 16 bit flags.'
219 return self.header.get_word(2)
221 def set_flags(self, value):
222 'Set 16 bit flags.'
223 self.header.set_word(2, value)
225 def get_flags_tcp(self):
226 'Get 16 bit flags.'
227 return self.header.get_word(4)
229 def set_flags_tcp(self, value):
230 'Set 16 bit flags.'
231 self.header.set_word(4, value)
233 def get_qdcount(self):
234 'Get Unsigned 16 bit integer specifying the number of entries in the question section.'
235 return self.header.get_word(4)
237 def set_qdcount(self, value):
238 'Set Unsigned 16 bit integer specifying the number of entries in the question section.'
239 self.header.set_word(4, value)
241 def get_qdcount_tcp(self):
242 'Get Unsigned 16 bit integer specifying the number of entries in the question section.'
243 return self.header.get_word(6)
245 def set_qdcount_tcp(self, value):
246 'Set Unsigned 16 bit integer specifying the number of entries in the question section.'
247 self.header.set_word(6, value)
249 def get_ancount(self):
250 'Get Unsigned 16 bit integer specifying the number of resource records in the answer section'
251 return self.header.get_word(6)
253 def set_ancount(self, value):
254 'Set Unsigned 16 bit integer specifying the number of resource records in the answer section'
255 self.header.set_word(6, value)
257 def get_nscount(self):
258 'Get Unsigned 16 bit integer specifying the number of name server resource records in the authority section.'
259 return self.header.get_word(8)
261 def set_nscount(self, value):
262 'Set Unsigned 16 bit integer specifying the number of name server resource records in the authority section.'
263 self.header.set_word(8, value)
265 def get_arcount(self):
266 'Get Unsigned 16 bit integer specifying the number of resource records in the additional records section.'
267 return self.header.get_word(10)
269 def set_arcount(self, value):
270 'Set Unsigned 16 bit integer specifying the number of resource records in the additional records section.'
271 self.header.set_word(10, value)
273 def get_questions(self):
274 'Get a list of the DNS Question.'
275 return self.__get_questions()[0]
277 def __get_questions(self):
278 aux = []
279 offset = 0
280 qdcount = self.get_qdcount()
281 data = self.get_body_as_string()
282 for _ in range(qdcount): # number of questions
283 offset, qname = self.parseCompressedMessage(data, offset)
284 qtype = data[offset:offset+self.__TYPE_LEN]
285 offset += self.__TYPE_LEN
286 qclass = data[offset:offset+self.__CLASS_LEN]
287 offset += self.__CLASS_LEN
288 qtype = struct.unpack("!H", qtype)[0]
289 qclass = struct.unpack("!H", qclass)[0]
290 aux.append((qname, qtype, qclass))
291 return (aux, offset)
293 def get_questions_tcp(self):
294 'Get a list of the DNS Question.'
295 return self.__get_questions_tcp()[0]
297 def __get_questions_tcp(self):
298 aux = []
299 offset = 2
300 qdcount = self.get_qdcount_tcp()
301 data = self.get_body_as_string()
302 for _ in range(qdcount): # number of questions
303 offset, qname = self.parseCompressedMessage(data, offset)
304 qtype = data[offset:offset+self.__TYPE_LEN]
305 offset += self.__TYPE_LEN
306 qclass = data[offset:offset+self.__CLASS_LEN]
307 offset += self.__CLASS_LEN
308 qtype = struct.unpack("!H", qtype)[0]
309 qclass = struct.unpack("!H", qclass)[0]
310 aux.append((qname, qtype, qclass))
311 return (aux, offset)
313 def parseCompressedMessage(self, buf, offset=0):
314 'Parse compressed message defined on rfc1035 4.1.4.'
315 if offset >= len(buf): 315 ↛ 316line 315 didn't jump to line 316, because the condition on line 315 was never true
316 raise Exception("No more data to parse. Offset is bigger than length of buffer.")
317 byte = struct.unpack("B", buf[offset:offset+1])[0]
318 # if the first two bits are ones (11000000=0xC0), the next bits are the offset
319 if byte & 0xC0 == 0xC0:
320 # It's a pointer
321 pointer = struct.unpack("!H", buf[offset:offset+2])[0] # network unsigned short
322 pointer = (pointer & 0x3FFF) - self.__HEADER_BASE_SIZE
323 if offset == pointer: 323 ↛ 324line 323 didn't jump to line 324, because the condition on line 323 was never true
324 raise Exception("The infinite loop is in DNS decompression. Encountered pointer points to the current offset.")
325 offset += 2
326 name = self.parseCompressedMessage(buf, pointer)[1]
327 return (offset, name)
328 else:
329 # It's a label
330 if byte == 0x00:
331 offset += 1
332 return (offset, '')
333 offset += 1
334 name = buf[offset:offset+byte]
335 offset += byte
336 offset, unnamed = self.parseCompressedMessage(buf, offset)
337 if not unnamed:
338 return (offset, name)
339 else:
340 return (offset, name + b"." + unnamed)
342 def get_answers(self):
343 return self.__get_answers()[0]
345 def get_authoritative(self):
346 return self.__get_authoritative()[0]
348 def get_additionals(self):
349 return self.__get_additionals()[0]
351 def __get_answers(self):
352 offset = self.__get_questions()[1] # get the initial offset
353 ancount = self.get_ancount()
354 return self.__process_answer_structure(offset, ancount)
356 def __get_authoritative(self):
357 'Get a list of the DNS Authoritative.'
358 offset = self.__get_answers()[1] # get the initial offset
359 nscount = self.get_nscount()
360 return self.__process_answer_structure(offset, nscount)
362 def __get_additionals(self):
363 'Get a list of the DNS Additional Records.'
364 offset = self.__get_authoritative()[1] # get the initial offset
365 arcount = self.get_arcount()
366 return self.__process_answer_structure(offset, arcount)
368 def __process_answer_structure(self, offset, num):
369 aux = []
370 data = self.get_body_as_string()
371 for _ in range(num):
372 offset, qname = self.parseCompressedMessage(data, offset)
373 qtype = data[offset:offset+self.__TYPE_LEN]
374 qtype = struct.unpack("!H", qtype)[0]
375 offset += self.__TYPE_LEN
377 qclass = data[offset:offset+self.__CLASS_LEN]
378 qclass = struct.unpack("!H", qclass)[0]
379 offset += self.__CLASS_LEN
381 qttl_raw = data[offset:offset+self.__TTL_LEN]
382 qttl = struct.unpack("!L", qttl_raw)[0]
383 offset += self.__TTL_LEN
385 qrdlength = data[offset:offset+self.__RDLENGTH_LEN]
386 qrdlength = struct.unpack("!H", qrdlength)[0]
387 offset += self.__RDLENGTH_LEN
389 qrdata = {}
390 if qtype == DNSType.A:
391 # IP Address Unsigned 32-bit value representing the IP address
392 qrdata["IPAddress"] = socket.inet_ntoa(data[offset:offset+qrdlength])
393 offset += self.__TYPE_A_LEN
394 elif qtype == DNSType.SOA: 394 ↛ 396line 394 didn't jump to line 396, because the condition on line 394 was never true
395 # Primary NS Variable length. The name of the Primary Master for the domain. May be a label, pointer or any combination.
396 offset, primaryNs = self.parseCompressedMessage(data, offset)
397 qrdata["PrimaryNS"] = primaryNs
398 # Admin MB Variable length. The administrator's mailbox. May be a label, pointer or any combination.
399 offset, adminMb = self.parseCompressedMessage(data, offset)
400 qrdata["AdminMB"] = adminMb
401 # Serial Number Unsigned 32-bit integer.
402 qrdata["SerialNumber"] = struct.unpack("!L", data[offset:offset+self.__SERIAL_LEN])[0]
403 offset += self.__SERIAL_LEN
404 # Refresh interval Unsigned 32-bit integer.
405 qrdata["RefreshInterval"] = struct.unpack("!L", data[offset:offset+self.__REFRESH_LEN])[0]
406 offset += self.__REFRESH_LEN
407 # Retry Interval Unsigned 32-bit integer.
408 qrdata["RetryInterval"] = struct.unpack("!L", data[offset:offset+self.__RETRY_LEN])[0]
409 offset += self.__RETRY_LEN
410 # Expiration Limit Unsigned 32-bit integer.
411 qrdata["ExpirationLimit"] = struct.unpack("!L", data[offset:offset+self.__EXPIRATION_LEN])[0]
412 offset += self.__EXPIRATION_LEN
413 # Minimum TTL Unsigned 32-bit integer.
414 qrdata["MinimumTTL"] = struct.unpack("!L", data[offset:offset+self.__MINTTL_LEN])[0]
415 offset += self.__MINTTL_LEN
416 elif qtype == DNSType.MX: 416 ↛ 418line 416 didn't jump to line 418, because the condition on line 416 was never true
417 # Preference Unsigned 16-bit integer.
418 qrdata["Preference"] = struct.unpack("!H", data[offset:offset+self.__PREF_LEN])[0]
419 # Mail Exchanger The name host name that provides the service. May be a label, pointer or any combination.
420 offset, mailExch = self.parseCompressedMessage(data, offset)
421 qrdata["MailExchanger"] = mailExch
422 elif qtype == DNSType.PTR or qtype == DNSType.NS or qtype == DNSType.CNAME: 422 ↛ 426line 422 didn't jump to line 426, because the condition on line 422 was never false
423 # Name The host name that represents the supplied IP address (in the case of a PTR) or the NS name for the supplied domain (in the case of NS). May be a label, pointer or any combination.
424 offset, name = self.parseCompressedMessage(data, offset)
425 qrdata["Name"] = str(name.decode('ascii'))
426 elif qtype == DNSType.OPT:
427 # rfc2671 4.3
428 #NAME domain name empty (root domain)
429 #TYPE u_int16_t OPT
430 #CLASS u_int16_t sender's UDP payload size
431 #TTL u_int32_t extended RCODE and flags
432 #RDLEN u_int16_t describes RDATA
433 #RDATA octet stream {attribute,value} pairs
434 #udp_payload = qclass
435 udp_payload_size = qclass
436 ext_rcode = struct.unpack("B", qttl_raw[0:1])[0]
437 version = struct.unpack("B", qttl_raw[1:2])[0]
438 flags = struct.unpack("!H", qttl_raw[2:4])[0]
439 qrdata["RDATA"] = data[offset:offset+qrdlength]
440 offset += qrdlength
441 aux.append((qname, qtype, udp_payload_size, ext_rcode, version, flags, qrdata))
442 continue
443 else:
444 # We don't know how to parse it, just skip it
445 offset += qrdlength
447 aux.append((qname, qtype, qclass, qttl, qrdata))
448 return (aux, offset)
450 def get_header_size(self):
451 return self.__HEADER_BASE_SIZE
453 def __str__(self):
454 res = ""
456 id = self.get_transaction_id()
457 flags = self.get_flags()
458 qdcount = self.get_qdcount()
459 ancount = self.get_ancount()
460 nscount = self.get_nscount()
461 arcount = self.get_arcount()
463 res += "DNS "
464 if flags & DNSFlags.QR_RESPONSE:
465 res += "RESPONSE\n"
466 else:
467 res += "QUERY\n"
469 res += " - Transaction ID -- [0x%04x] %d\n" % (id, id)
470 res += " - Flags ----------- [0x%04x] %d\n" % (flags, flags)
471 res += " - QdCount --------- [0x%04x] %d\n" % (qdcount, qdcount)
472 res += " - AnCount --------- [0x%04x] %d\n" % (ancount, ancount)
473 res += " - NsCount --------- [0x%04x] %d\n" % (nscount, nscount)
474 res += " - ArCount --------- [0x%04x] %d\n" % (arcount, arcount)
476 if qdcount > 0: 476 ↛ 485line 476 didn't jump to line 485, because the condition on line 476 was never false
477 res += " - Questions:\n"
478 questions = self.get_questions()
479 questions.reverse()
480 while(questions):
481 qname, qtype, qclass = questions.pop()
482 format = (str(qname.decode('ascii')), DNSType.getTypeName(qtype), qtype, DNSClass.getClassName(qclass), qclass)
483 res += " * Domain: %s - Type: %s [0x%04x] - Class: %s [0x%04x]\n" % format
485 if ancount > 0:
486 res += " - Answers:\n"
487 answers = self.get_answers()
488 answers.reverse()
489 while(answers):
490 qname, qtype, qclass, qttl, qrdata = answers.pop()
491 format = (str(qname.decode('ascii')), DNSType.getTypeName(qtype), qtype, DNSClass.getClassName(qclass), qclass, qttl, repr(qrdata))
492 res += " * Domain: %s - Type: %s [0x%04x] - Class: %s [0x%04x] - TTL: %d seconds - %s\n" % format
494 if nscount > 0:
495 res += " - Authoritative:\n"
496 authoritative = self.get_authoritative()
497 authoritative.reverse()
498 while(authoritative):
499 qname, qtype, qclass, qttl, qrdata = authoritative.pop()
500 format = (str(qname.decode('ascii')), DNSType.getTypeName(qtype), qtype, DNSClass.getClassName(qclass), qclass, qttl, repr(qrdata))
501 res += " * Domain: %s - Type: %s [0x%04x] - Class: %s [0x%04x] - TTL: %d seconds - %s\n" % format
503 if arcount > 0:
504 res += " - Additionals:\n"
505 additionals = self.get_additionals()
506 for additional in additionals:
507 qtype = additional[1]
508 if qtype == DNSType.OPT: 508 ↛ 510line 508 didn't jump to line 510, because the condition on line 508 was never true
510 qname, qtype, udp_payload_size, ext_rcode, version, flags, qrdata = additional
511 format = (DNSType.getTypeName(qtype), qtype, udp_payload_size, ext_rcode, version, flags, repr(qrdata['RDATA']))
512 res += " * Name: <Root> - Type: %s [0x%04x] - udp payload size: [%d] - extended RCODE: [0x%02x] - EDNS0 version: [0x%02x] - Z Flags: [0x%02x] - RDATA: [%s]\n" % format
513 else:
514 qname, qtype, qclass, qttl, qrdata = additional
515 format = (str(qname.decode('ascii')), DNSType.getTypeName(qtype), qtype, DNSClass.getClassName(qclass), qclass, qttl, repr(qrdata))
516 res += " * Domain: %s - Type: %s [0x%04x] - Class: %s [0x%04x] - TTL: %d seconds - %s\n" % format
518 return res
520 def __get_questions_raw(self):
521 if self.get_qdcount() == 0:
522 return ''
523 questions_offset = self.__get_questions()[1]
524 raw_data = self.get_body_as_string()[:questions_offset]
525 return raw_data
527 def __get_answers_raw(self):
528 if self.get_ancount() == 0:
529 return ''
530 questions_offset = self.__get_questions()[1]
531 answers_offset = self.__get_answers()[1]
532 raw_data = self.get_body_as_string()[questions_offset: answers_offset]
533 return raw_data
535 def __get_authoritative_raw(self):
536 if self.get_nscount() == 0:
537 return ''
538 answers_offset = self.__get_answers()[1]
539 authoritative_offset = self.__get_authoritative()[1]
540 raw_data = self.get_body_as_string()[answers_offset:authoritative_offset]
541 return raw_data
543 def __get_additionals_raw(self):
544 if self.get_arcount() == 0:
545 return ''
546 authoritative_offset = self.__get_authoritative()[1]
547 raw_data = self.get_body_as_string()[authoritative_offset:]
548 return raw_data
550 def add_answer(self, answer_raw):
551 '''Add a raw answer'''
552 questions_raw = self.__get_questions_raw()
553 answers_raw = self.__get_answers_raw()
554 authoritative_raw = self.__get_authoritative_raw()
555 additionals_raw = self.__get_additionals_raw()
557 answers_raw += answer_raw
559 body = questions_raw + answers_raw + authoritative_raw + additionals_raw
560 self.load_body(body) # It breaks children hierarchy
562 # Increment the answer count
563 cur_answer_count = self.get_ancount()+1
564 self.set_ancount(cur_answer_count)
566 def is_edns0(self):
567 additionals = self.get_additionals()
568 for item in additionals:
569 response_type = item[1]
570 if response_type == DNSType.OPT:
571 return True
572 return False