Hide keyboard shortcuts

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 

33import socket 

34import struct 

35 

36from impacket.ImpactPacket import ProtocolPacket 

37 

38 

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. 

80 

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 

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 

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

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