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