1# Copyright (c) 2003-2016 CORE Security Technologies
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
10
11#
12# RFCs for the DNS Server service
13#
14# 1034 - Domain Names -- Concepts and Facilities [http://www.faqs.org/rfcs/rfc1034.html]
15# 1035 - Domain Names -- Implementation and Specification [http://www.faqs.org/rfcs/rfc1035.html]
16# 1123 - Requirements for Internet Hosts -- Application and Support [http://www.faqs.org/rfcs/rfc1123.html]
17# 1886 - DNS Extensions to Support IP Version 6 [http://www.faqs.org/rfcs/rfc1886.html]
18# 1995 - Incremental Zone Transfer in DNS [http://www.faqs.org/rfcs/rfc1995.html]
19# 1996 - A Mechanism for Prompt Notification of Zone Changes (DNS NOTIFY) [http://www.faqs.org/rfcs/rfc1996.html]
20# 2136 - Dynamic Updates in the Domain Name System (DNS UPDATE) [http://www.faqs.org/rfcs/rfc2136.html]
21# 2181 - Clarifications to the DNS Specification [http://www.faqs.org/rfcs/rfc2181.html]
22# 2308 - Negative Caching of DNS Queries (DNS NCACHE) [http://www.faqs.org/rfcs/rfc2308.html]
23# 2535 - Domain Name System Security Extensions (DNSSEC) [http://www.faqs.org/rfcs/rfc2535.html]
24# 2671 - Extension Mechanisms for DNS (EDNS0) [http://www.faqs.org/rfcs/rfc2671.html]
25# 2782 - A DNS RR for specifying the location of services (DNS SRV) [http://www.faqs.org/rfcs/rfc2782.html]
26# 2930 - Secret Key Establishment for DNS (TKEY RR) [http://www.faqs.org/rfcs/rfc2930.html]
27# 3645 - Generic Security Service Algorithm for Secret Key Transaction Authentication for DNS (GSS-TSIG) [http://www.faqs.org/rfcs/rfc3645.html]
28# 3646 - DNS Configuration options for Dynamic Host Configuration Protocol for IPv6 (DHCPv6) [http://www.faqs.org/rfcs/rfc3646.html]
29#
30
31import socket
32import struct
33
34from ImpactPacket import ProtocolPacket
35
36
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.
78
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
131
132    HIP          = 55    # Host Identity Protocol.
133    NINFO        = 56
134    RKEY         = 57
135
136    SPF          = 99    # Sender Policy Framework.
137    UINFO        = 100
138    UID          = 101
139    GID          = 102
140    UNSPEC       = 103
141
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.
149
150    DNSSEC       = 32768 # Trust Authorities.
151    DNSSEC       = 32769 # DNSSEC Lookaside Validation.
152
153    @staticmethod
154    def getTypeName(type):
155        for item, value in DNSType.__dict__.items():
156            if value == type:
157                return item
158
159
160class DNSClass():
161    RESERVED     = 0
162    IN           = 1 # Internet.
163    CH           = 3 # Chaos.
164    HS           = 4 # Hesiod.
165
166    NONE         = 254
167    ANY          = 255 # QCLASS only
168
169    @staticmethod
170    def getClassName(type):
171        for item, value in DNSClass.__dict__.items():
172            if value == type:
173                return item
174
175class DNS(ProtocolPacket):
176    '''The Message Header is present in all messages. Never empty.
177    Contains various flags and values which control the transaction.'''
178
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)
193
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:
199            self.load_packet(aBuffer)
200
201    def get_transaction_id(self):
202        'Get 16 bit message ID.'
203        return self.header.get_word(0)
204
205    def set_transaction_id(self, value):
206        'Set 16 bit message ID.'
207        self.header.set_word(0, value)
208
209    def get_transaction_id_tcp(self):
210        'Get 16 bit message ID.'
211        return self.header.get_word(2)
212
213    def set_transaction_id_tcp(self, value):
214        'Set 16 bit message ID.'
215        self.header.set_word(2, value)
216
217    def get_flags(self):
218        'Get 16 bit flags.'
219        return self.header.get_word(2)
220
221    def set_flags(self, value):
222        'Set 16 bit flags.'
223        self.header.set_word(2, value)
224
225    def get_flags_tcp(self):
226        'Get 16 bit flags.'
227        return self.header.get_word(4)
228
229    def set_flags_tcp(self, value):
230        'Set 16 bit flags.'
231        self.header.set_word(4, value)
232
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)
236
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)
240
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)
244
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)
248
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)
252
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)
256
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)
260
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)
264
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)
268
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)
272
273    def get_questions(self):
274        'Get a list of the DNS Question.'
275        return self.__get_questions()[0]
276
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)
292
293    def get_questions_tcp(self):
294        'Get a list of the DNS Question.'
295        return self.__get_questions_tcp()[0]
296
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)
312
313    def parseCompressedMessage(self, buf, offset=0):
314        'Parse compressed message defined on rfc1035 4.1.4.'
315        if offset >= len(buf):
316            raise Exception("No more data to parse. Offset is bigger than length of buffer.")
317        byte = struct.unpack("B", buf[offset])[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            offset += 2
324            name = self.parseCompressedMessage(buf, pointer)[1]
325            return (offset, name)
326        else:
327            # It's a label
328            if byte == 0x00:
329                offset += 1
330                return (offset, '')
331            offset += 1
332            name = buf[offset:offset+byte]
333            offset += byte
334            offset, unnamed = self.parseCompressedMessage(buf, offset)
335            if not unnamed:
336                return (offset, name)
337            else:
338                return (offset, name + "." + unnamed)
339
340    def get_answers(self):
341        return self.__get_answers()[0]
342
343    def get_authoritative(self):
344        return self.__get_authoritative()[0]
345
346    def get_additionals(self):
347        return self.__get_additionals()[0]
348
349    def __get_answers(self):
350        offset  = self.__get_questions()[1] # get the initial offset
351        ancount = self.get_ancount()
352        return self.__process_answer_structure(offset, ancount)
353
354    def __get_authoritative(self):
355        'Get a list of the DNS Authoritative.'
356        offset  = self.__get_answers()[1] # get the initial offset
357        nscount = self.get_nscount()
358        return self.__process_answer_structure(offset, nscount)
359
360    def __get_additionals(self):
361        'Get a list of the DNS Additional Records.'
362        offset  = self.__get_authoritative()[1] # get the initial offset
363        arcount = self.get_arcount()
364        return self.__process_answer_structure(offset, arcount)
365
366    def __process_answer_structure(self, offset, num):
367        aux  = []
368        data = self.get_body_as_string()
369        for _ in range(num):
370            offset, qname = self.parseCompressedMessage(data, offset)
371            qtype  = data[offset:offset+self.__TYPE_LEN]
372            qtype  = struct.unpack("!H", qtype)[0]
373            offset  += self.__TYPE_LEN
374
375            qclass = data[offset:offset+self.__CLASS_LEN]
376            qclass = struct.unpack("!H", qclass)[0]
377            offset  += self.__CLASS_LEN
378
379            qttl_raw = data[offset:offset+self.__TTL_LEN]
380            qttl = struct.unpack("!L", qttl_raw)[0]
381            offset  += self.__TTL_LEN
382
383            qrdlength = data[offset:offset+self.__RDLENGTH_LEN]
384            qrdlength = struct.unpack("!H", qrdlength)[0]
385            offset  += self.__RDLENGTH_LEN
386
387            qrdata = {}
388            if qtype == DNSType.A:
389                # IP Address  Unsigned 32-bit value representing the IP address
390                qrdata["IPAddress"] = socket.inet_ntoa(data[offset:offset+qrdlength])
391                offset  += self.__TYPE_A_LEN
392            elif qtype == DNSType.SOA:
393                # Primary NS  Variable length. The name of the Primary Master for the domain. May be a label, pointer or any combination.
394                offset, primaryNs = self.parseCompressedMessage(data, offset)
395                qrdata["PrimaryNS"] = primaryNs
396                # Admin MB  Variable length. The administrator's mailbox. May be a label, pointer or any combination.
397                offset, adminMb = self.parseCompressedMessage(data, offset)
398                qrdata["AdminMB"] = adminMb
399                # Serial Number  Unsigned 32-bit integer.
400                qrdata["SerialNumber"] = struct.unpack("!L", data[offset:offset+self.__SERIAL_LEN])[0]
401                offset += self.__SERIAL_LEN
402                # Refresh interval  Unsigned 32-bit integer.
403                qrdata["RefreshInterval"] = struct.unpack("!L", data[offset:offset+self.__REFRESH_LEN])[0]
404                offset += self.__REFRESH_LEN
405                # Retry Interval  Unsigned 32-bit integer.
406                qrdata["RetryInterval"] = struct.unpack("!L", data[offset:offset+self.__RETRY_LEN])[0]
407                offset += self.__RETRY_LEN
408                # Expiration Limit  Unsigned 32-bit integer.
409                qrdata["ExpirationLimit"] = struct.unpack("!L", data[offset:offset+self.__EXPIRATION_LEN])[0]
410                offset += self.__EXPIRATION_LEN
411                # Minimum TTL  Unsigned 32-bit integer.
412                qrdata["MinimumTTL"] = struct.unpack("!L", data[offset:offset+self.__MINTTL_LEN])[0]
413                offset += self.__MINTTL_LEN
414            elif qtype == DNSType.MX:
415                # Preference  Unsigned 16-bit integer.
416                qrdata["Preference"] = struct.unpack("!H", data[offset:offset+self.__PREF_LEN])[0]
417                # Mail Exchanger  The name host name that provides the service. May be a label, pointer or any combination.
418                offset, mailExch = self.parseCompressedMessage(data, offset)
419                qrdata["MailExchanger"] = mailExch
420            elif qtype == DNSType.PTR or qtype == DNSType.NS or qtype == DNSType.CNAME:
421                # 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.
422                offset, name = self.parseCompressedMessage(data, offset)
423                qrdata["Name"] = name
424            elif qtype == DNSType.OPT:
425                # rfc2671 4.3
426                #NAME         domain name    empty (root domain)
427                #TYPE         u_int16_t      OPT
428                #CLASS        u_int16_t      sender's UDP payload size
429                #TTL          u_int32_t      extended RCODE and flags
430                #RDLEN        u_int16_t      describes RDATA
431                #RDATA        octet stream   {attribute,value} pairs
432                #udp_payload = qclass
433                udp_payload_size = qclass
434                ext_rcode = struct.unpack("B", qttl_raw[0])[0]
435                version = struct.unpack("B", qttl_raw[1])[0]
436                flags = struct.unpack("!H", qttl_raw[2:4])[0]
437                qrdata["RDATA"] = data[offset:offset+qrdlength]
438                offset  += qrdlength
439                aux.append((qname, qtype, udp_payload_size, ext_rcode, version, flags, qrdata))
440                continue
441            else:
442                # We don't know how to parse it, just skip it
443                offset  += qrdlength
444
445            aux.append((qname, qtype, qclass, qttl, qrdata))
446        return (aux, offset)
447
448    def get_header_size(self):
449        return self.__HEADER_BASE_SIZE
450
451    def __str__(self):
452        res = ""
453
454        id      = self.get_transaction_id()
455        flags   = self.get_flags()
456        qdcount = self.get_qdcount()
457        ancount = self.get_ancount()
458        nscount = self.get_nscount()
459        arcount = self.get_arcount()
460
461        res += "DNS "
462        if flags & DNSFlags.QR_RESPONSE:
463            res += "RESPONSE\n"
464        else:
465            res += "QUERY\n"
466
467        res += " - Transaction ID -- [0x%04x] %d\n" % (id, id)
468        res += " - Flags ----------- [0x%04x] %d\n" % (flags, flags)
469        res += " - QdCount --------- [0x%04x] %d\n" % (qdcount, qdcount)
470        res += " - AnCount --------- [0x%04x] %d\n" % (ancount, ancount)
471        res += " - NsCount --------- [0x%04x] %d\n" % (nscount, nscount)
472        res += " - ArCount --------- [0x%04x] %d\n" % (arcount, arcount)
473
474        if qdcount > 0:
475            res += " - Questions:\n"
476            questions = self.get_questions()
477            questions.reverse()
478            while(questions):
479                qname, qtype, qclass = questions.pop()
480                format = (qname, DNSType.getTypeName(qtype), qtype, DNSClass.getClassName(qclass), qclass)
481                res += "  * Domain: %s - Type: %s [0x%04x] - Class: %s [0x%04x]\n" % format
482
483        if ancount > 0:
484            res += " - Answers:\n"
485            answers = self.get_answers()
486            answers.reverse()
487            while(answers):
488                qname, qtype, qclass, qttl, qrdata = answers.pop()
489                format = (qname, DNSType.getTypeName(qtype), qtype, DNSClass.getClassName(qclass), qclass, qttl, repr(qrdata))
490                res += "  * Domain: %s - Type: %s [0x%04x] - Class: %s [0x%04x] - TTL: %d seconds - %s\n" % format
491
492        if nscount > 0:
493            res += " - Authoritative:\n"
494            authoritative = self.get_authoritative()
495            authoritative.reverse()
496            while(authoritative):
497                qname, qtype, qclass, qttl, qrdata = authoritative.pop()
498                format = (qname, DNSType.getTypeName(qtype), qtype, DNSClass.getClassName(qclass), qclass, qttl, repr(qrdata))
499                res += "  * Domain: %s - Type: %s [0x%04x] - Class: %s [0x%04x] - TTL: %d seconds - %s\n" % format
500
501        if arcount > 0:
502            res += " - Additionals:\n"
503            additionals = self.get_additionals()
504            for additional in additionals:
505                qtype = additional[1]
506                if qtype == DNSType.OPT:
507
508                    qname, qtype, udp_payload_size, ext_rcode, version, flags, qrdata = additional
509                    format = (DNSType.getTypeName(qtype), qtype, udp_payload_size, ext_rcode, version, flags, repr(qrdata['RDATA']))
510                    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
511                else:
512                    qname, qtype, qclass, qttl, qrdata = additional
513                    format = (qname, DNSType.getTypeName(qtype), qtype, DNSClass.getClassName(qclass), qclass, qttl, repr(qrdata))
514                    res += "  * Domain: %s - Type: %s [0x%04x] - Class: %s [0x%04x] - TTL: %d seconds - %s\n" % format
515
516        return res
517
518    def __get_questions_raw(self):
519        if self.get_qdcount() == 0:
520            return ''
521        questions_offset = self.__get_questions()[1]
522        raw_data  = self.get_body_as_string()[:questions_offset]
523        return raw_data
524
525    def __get_answers_raw(self):
526        if self.get_ancount() == 0:
527            return ''
528        questions_offset = self.__get_questions()[1]
529        answers_offset = self.__get_answers()[1]
530        raw_data  = self.get_body_as_string()[questions_offset: answers_offset]
531        return raw_data
532
533    def __get_authoritative_raw(self):
534        if self.get_nscount() == 0:
535            return ''
536        answers_offset = self.__get_answers()[1]
537        authoritative_offset = self.__get_authoritative()[1]
538        raw_data  = self.get_body_as_string()[answers_offset:authoritative_offset]
539        return raw_data
540
541    def __get_additionals_raw(self):
542        if self.get_arcount() == 0:
543            return ''
544        authoritative_offset = self.__get_authoritative()[1]
545        raw_data  = self.get_body_as_string()[authoritative_offset:]
546        return raw_data
547
548    def add_answer(self, answer_raw):
549        '''Add a raw answer'''
550        questions_raw = self.__get_questions_raw()
551        answers_raw = self.__get_answers_raw()
552        authoritative_raw = self.__get_authoritative_raw()
553        additionals_raw = self.__get_additionals_raw()
554
555        answers_raw += answer_raw
556
557        body = questions_raw + answers_raw + authoritative_raw + additionals_raw
558        self.load_body(body) # It breaks children hierarchy
559
560        # Increment the answer count
561        cur_answer_count = self.get_ancount()+1
562        self.set_ancount(cur_answer_count)
563
564    def is_edns0(self):
565        additionals = self.get_additionals()
566        for item in additionals:
567            response_type = item[1]
568            if response_type == DNSType.OPT:
569                return True
570        return False
571
572if __name__ == "__main__":
573    pkts = [
574            "\x6a\x8c\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03\x77\x77\x77" \
575            "\x05\x74\x61\x72\x74\x61\x03\x63\x6f\x6d\x00\x00\x01\x00\x01",
576            "\x6a\x8c\x81\x80\x00\x01\x00\x02\x00\x02\x00\x00\x03\x77\x77\x77" \
577            "\x05\x74\x61\x72\x74\x61\x03\x63\x6f\x6d\x00\x00\x01\x00\x01\xc0" \
578            "\x0c\x00\x05\x00\x01\x00\x00\x07\x08\x00\x02\xc0\x10\xc0\x10\x00" \
579            "\x01\x00\x01\x00\x00\x07\x08\x00\x04\x45\x59\x1f\xc7\xc0\x10\x00" \
580            "\x02\x00\x01\x00\x02\xa3\x00\x00\x0f\x03\x6e\x73\x31\x08\x62\x6c" \
581            "\x75\x65\x68\x6f\x73\x74\xc0\x16\xc0\x10\x00\x02\x00\x01\x00\x02" \
582            "\xa3\x00\x00\x06\x03\x6e\x73\x32\xc0\x4d",
583            "\x82\x75\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03\x77\x77\x77" \
584            "\x04\x6a\x68\x6f\x6e\x03\x63\x6f\x6d\x00\x00\x01\x00\x01",
585            "\x82\x75\x81\x80\x00\x01\x00\x01\x00\x02\x00\x02\x03\x77\x77\x77" \
586            "\x04\x6a\x68\x6f\x6e\x03\x63\x6f\x6d\x00\x00\x01\x00\x01\xc0\x0c" \
587            "\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04\xd1\x3b\xc3\x14\xc0\x10" \
588            "\x00\x02\x00\x01\x00\x00\x06\xf8\x00\x0f\x03\x6e\x73\x31\x08\x74" \
589            "\x72\x61\x66\x66\x69\x63\x7a\xc0\x15\xc0\x10\x00\x02\x00\x01\x00" \
590            "\x00\x06\xf8\x00\x06\x03\x6e\x73\x32\xc0\x3e\xc0\x3a\x00\x01\x00" \
591            "\x01\x00\x00\x00\x0d\x00\x04\xd1\x3b\xc2\xf6\xc0\x55\x00\x01\x00" \
592            "\x01\x00\x00\x00\x85\x00\x04\xd1\x3b\xc3\xf6",
593            "\xef\x55\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04\x6d\x61\x69" \
594            "\x6c\x06\x67\x6f\x6f\x67\x6c\x65\x03\x63\x6f\x6d\x00\x00\x01\x00" \
595            "\x01",
596            "\xef\x55\x81\x80\x00\x01\x00\x04\x00\x04\x00\x04\x04\x6d\x61\x69" \
597            "\x6c\x06\x67\x6f\x6f\x67\x6c\x65\x03\x63\x6f\x6d\x00\x00\x01\x00" \
598            "\x01\xc0\x0c\x00\x05\x00\x01\x00\x00\x06\x79\x00\x0f\x0a\x67\x6f" \
599            "\x6f\x67\x6c\x65\x6d\x61\x69\x6c\x01\x6c\xc0\x11\xc0\x2d\x00\x01" \
600            "\x00\x01\x00\x00\x00\x77\x00\x04\xd1\x55\xc3\x53\xc0\x2d\x00\x01" \
601            "\x00\x01\x00\x00\x00\x77\x00\x04\xd1\x55\xc3\x12\xc0\x2d\x00\x01" \
602            "\x00\x01\x00\x00\x00\x77\x00\x04\xd1\x55\xc3\x13\xc0\x11\x00\x02" \
603            "\x00\x01\x00\x00\x00\x5d\x00\x06\x03\x6e\x73\x33\xc0\x11\xc0\x11" \
604            "\x00\x02\x00\x01\x00\x00\x00\x5d\x00\x06\x03\x6e\x73\x34\xc0\x11" \
605            "\xc0\x11\x00\x02\x00\x01\x00\x00\x00\x5d\x00\x06\x03\x6e\x73\x31" \
606            "\xc0\x11\xc0\x11\x00\x02\x00\x01\x00\x00\x00\x5d\x00\x06\x03\x6e" \
607            "\x73\x32\xc0\x11\xc0\x9c\x00\x01\x00\x01\x00\x00\x04\x4e\x00\x04" \
608            "\xd8\xef\x20\x0a\xc0\xae\x00\x01\x00\x01\x00\x00\x06\x64\x00\x04" \
609            "\xd8\xef\x22\x0a\xc0\x78\x00\x01\x00\x01\x00\x00\x00\x05\x00\x04" \
610            "\xd8\xef\x24\x0a\xc0\x8a\x00\x01\x00\x01\x00\x00\x00\x08\x00\x04" \
611            "\xd8\xef\x26\x0a"
612           ]
613
614    for pkt in pkts:
615        d = DNS(pkt)
616        print d
617