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

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

## 405 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# 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

10

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#

30

31 import socket

32 import struct

33

34 from impacket.ImpactPacket import ProtocolPacket

35

36

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

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

158

159

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

174

175 class 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: 198 ↛ exitline 198 didn't return from function '__init__', because the condition on line 198 was never false

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

341

342 def get_answers(self):

343 return self.__get_answers()[0]

344

345 def get_authoritative(self):

346 return self.__get_authoritative()[0]

347

348 def get_additionals(self):

349 return self.__get_additionals()[0]

350

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)

355

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)

361

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)

367

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

376

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

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

379 offset += self.__CLASS_LEN

380

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

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

383 offset += self.__TTL_LEN

384

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

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

387 offset += self.__RDLENGTH_LEN

388

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

446

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

448 return (aux, offset)

449

450 def get_header_size(self):

451 return self.__HEADER_BASE_SIZE

452

453 def __str__(self):

454 res = ""

455

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

462

463 res += "DNS "

464 if flags & DNSFlags.QR_RESPONSE:

465 res += "RESPONSE\n"

466 else:

467 res += "QUERY\n"

468

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)

475

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

484

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

493

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

502

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

509

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

517

518 return res

519

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

526

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

534

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

542

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

549

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

556

557 answers_raw += answer_raw

558

559 body = questions_raw + answers_raw + authoritative_raw + additionals_raw

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

561

562 # Increment the answer count

563 cur_answer_count = self.get_ancount()+1

564 self.set_ancount(cur_answer_count)

565

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