def parse(cls, packet): """ Parse DNS packet data and return DNSRecord instance Recursively parses sections (calling appropriate parse method) """ buffer = DNSBufferExt(packet) try: header = DNSHeader.parse(buffer) questions = [] rr = [] auth = [] ar = [] for i in range(header.q): questions.append(DNSQuestion.parse(buffer)) for i in range(header.a): rr.append(RR.parse(buffer)) for i in range(header.auth): auth.append(RR.parse(buffer)) for i in range(header.ar): ar.append(RR.parse(buffer)) return cls(header, questions, rr, auth=auth, ar=ar) except DNSError: raise except (BufferError, BimapError) as e: raise DNSError(f"Error unpacking DNSRecord [offset={buffer.offset:d}]: {e}")
def transmit(self, payload): """ This is the original transmit method from ServerTarget overwritten with DNS response code specific reporting Accordin to: https://support.umbrella.com/hc/en-us/articles/232254248-Common-DNS-return-codes-for-any-DNS-service-and-Umbrella- NOERROR RCODE:0 DNS Query completed successfully FORMERR RCODE:1 DNS Query Format Error SERVFAIL RCODE:2 Server failed to complete the DNS request NXDOMAIN RCODE:3 Domain name does not exist. NOTIMP RCODE:4 Function not implemented REFUSED RCODE:5 The server refused to answer for the query YXDOMAIN RCODE:6 Name that should not exist, does exist XRRSET RCODE:7 RRset that should not exist, does exist NOTAUTH RCODE:8 Server not authoritative for the zone NOTZONE RCODE:9 Name not in zone Original method docstring: Transmit single payload, and receive response, if expected. The actual implementation of the send/receive should be in ``_send_to_target`` and ``_receive_from_target``. :type payload: str :param payload: payload to send :rtype: str :return: the response (if received) """ DNS_RETRUN_CODES = [ 'NOERROR', 'FORMERR', 'SERVFAIL', 'NXDOMAIN', 'NOTIMP', 'REFUSED', 'YXDOMAIN', 'XRRSET', 'NOTAUTH', 'NOTZONE' ] DNS_EXCLUDE = [0, 3, 5] response = None trans_report_name = 'transmission_0x%04x' % self.transmission_count trans_report = Report(trans_report_name) self.transmission_report = trans_report self.report.add(trans_report_name, trans_report) try: trans_report.add('request (hex)', hexlify(payload).decode()) trans_report.add('request (raw)', '%s' % payload) trans_report.add('request length', len(payload)) trans_report.add('request time', time.time()) request = hexlify(payload).decode() request = request if len(request) < 100 else (request[:100] + ' ...') self.logger.info(f"request({len(payload)}): {request}") self._send_to_target(payload) trans_report.success() if self.expect_response: try: response = self._receive_from_target() trans_report.add('response time', time.time()) trans_report.add('response (hex)', hexlify(response).decode()) trans_report.add('response (raw)', '%s' % response) trans_report.add('response length', len(response)) trans_report.add('Session ID', str(self._uuid)) printed_response = hexlify(response).decode() printed_response = printed_response if len(printed_response) < 100 else (printed_response[:100] + ' ...') self.logger.info(f"response({len(response)}): {printed_response}") server_message = response.split(b',', 0) reply = codecs.encode(server_message[0], 'hex') # USE DNS LIB TO HELP DEBUGGING MALFORMED HEADER debug_response_header = DNSBufferExt(unhexlify(reply)) parsed_dns_response_header = DNSHeader.parse(debug_response_header) dns_response_message = DNSRecordExt.parse(server_message[0]) if int(parsed_dns_response_header.rcode) not in DNS_EXCLUDE: self.logger.error(f"DNS response code: " f"{DNS_RETRUN_CODES[int(parsed_dns_response_header.rcode)]}") self.logger.error(f"Debug header: {str(parsed_dns_response_header)}") trans_report.failed(f"Failure in response, code: " f"{DNS_RETRUN_CODES[int(parsed_dns_response_header.rcode)]}") trans_report.add('Response', str(dns_response_message)) trans_report.add('traceback', traceback.format_exc()) self.receive_failure = True self.report.set_status('failed') except Exception as ex2: trans_report.failed('failed to receive response: %s' % ex2) trans_report.add('traceback', traceback.format_exc()) self.logger.error(f"target.transmit - failure in receive (exception: {ex2})") self.logger.error(traceback.format_exc()) self.receive_failure = True else: response = '' except Exception as ex1: trans_report.failed('failed to send payload: %s' % ex1) trans_report.add('traceback', traceback.format_exc()) self.logger.error(f"target.transmit - failure in send (exception: {ex1})") self.logger.error(traceback.format_exc()) self.send_failure = True self.transmission_count += 1 return response