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

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

## 403 statements

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#

32

33 import socket

34 import struct

35

36 from impacket.ImpactPacket import ProtocolPacket

37

38

39 class 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.

80

81 class 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

133

134 HIP = 55 # Host Identity Protocol.

135 NINFO = 56

136 RKEY = 57

137

138 SPF = 99 # Sender Policy Framework.

139 UINFO = 100

140 UID = 101

141 GID = 102

142 UNSPEC = 103

143

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.

151

152 DNSSEC = 32768 # Trust Authorities.

153 DNSSEC = 32769 # DNSSEC Lookaside Validation.

154

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

160

161

162 class DNSClass():

163 RESERVED = 0

164 IN = 1 # Internet.

165 CH = 3 # Chaos.

166 HS = 4 # Hesiod.

167

168 NONE = 254

169 ANY = 255 # QCLASS only

170

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

176

177 class DNS(ProtocolPacket):

178 '''The Message Header is present in all messages. Never empty.

179 Contains various flags and values which control the transaction.'''

180

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)

195

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)

202

203 def get_transaction_id(self):

204 'Get 16 bit message ID.'

205 return self.header.get_word(0)

206

207 def set_transaction_id(self, value):

208 'Set 16 bit message ID.'

209 self.header.set_word(0, value)

210

211 def get_transaction_id_tcp(self):

212 'Get 16 bit message ID.'

213 return self.header.get_word(2)

214

215 def set_transaction_id_tcp(self, value):

216 'Set 16 bit message ID.'

217 self.header.set_word(2, value)

218

219 def get_flags(self):

220 'Get 16 bit flags.'

221 return self.header.get_word(2)

222

223 def set_flags(self, value):

224 'Set 16 bit flags.'

225 self.header.set_word(2, value)

226

227 def get_flags_tcp(self):

228 'Get 16 bit flags.'

229 return self.header.get_word(4)

230

231 def set_flags_tcp(self, value):

232 'Set 16 bit flags.'

233 self.header.set_word(4, value)

234

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)

238

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)

242

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)

246

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)

250

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)

254

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)

258

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)

262

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)

266

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)

270

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)

274

275 def get_questions(self):

276 'Get a list of the DNS Question.'

277 return self.__get_questions()[0]

278

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)

294

295 def get_questions_tcp(self):

296 'Get a list of the DNS Question.'

297 return self.__get_questions_tcp()[0]

298

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)

314

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)

343

344 def get_answers(self):

345 return self.__get_answers()[0]

346

347 def get_authoritative(self):

348 return self.__get_authoritative()[0]

349

350 def get_additionals(self):

351 return self.__get_additionals()[0]

352

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)

357

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)

363

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)

369

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

378

379 qclass = data[offset: offset+self.__CLASS_LEN]

380 qclass = struct.unpack("!H", qclass)[0]

381 offset += self.__CLASS_LEN

382

383 qttl_raw = data[offset: offset+self.__TTL_LEN]

384 qttl = struct.unpack("!L", qttl_raw)[0]

385 offset += self.__TTL_LEN

386

387 qrdlength = data[offset: offset+self.__RDLENGTH_LEN]

388 qrdlength = struct.unpack("!H", qrdlength)[0]

389 offset += self.__RDLENGTH_LEN

390

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

448

449 aux.append((qname, qtype, qclass, qttl, qrdata))

450 return (aux, offset)

451

452 def get_header_size(self):

453 return self.__HEADER_BASE_SIZE

454

455 def __str__(self):

456 res = ""

457

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()

464

465 res += "DNS "

466 if flags & DNSFlags.QR_RESPONSE:

467 res += "RESPONSE\n"

468 else:

469 res += "QUERY\n"

470

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)

477

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

486

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

495

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

504

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

511

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

519

520 return res

521

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

528

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

536

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

544

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

551

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()

558

559 answers_raw += answer_raw

560

561 body = questions_raw + answers_raw + authoritative_raw + additionals_raw

562 self.load_body(body) # It breaks children hierarchy

563

564 # Increment the answer count

565 cur_answer_count = self.get_ancount()+1

566 self.set_ancount(cur_answer_count)

567

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