def resolve(self, request, handler): reply = request.reply() # DNSLabel qname qname = request.q.qname if qname.matchSuffix("time.") or qname.matchSuffix("date."): utc_now = pytz.utc.localize(datetime.datetime.utcnow()) try: timezone = str(qname)[:-6].replace('.', '/') tz_now = utc_now.astimezone(pytz.timezone(timezone)) except pytz.UnknownTimeZoneError: reply.header.rcode = RCODE.REFUSED return reply if qname.matchSuffix("time."): reply.add_answer(RR(qname, QTYPE.A, ttl=0, rdata=A(tz_now.strftime("%H.%M.%S.0")))) elif qname.matchSuffix("date."): reply.add_answer(RR(qname, QTYPE.A, ttl=0, rdata=A(tz_now.strftime("%y.%m.%d.0")))) reply.add_answer(RR(qname, QTYPE.TXT, ttl=0, rdata=TXT(tz_now.strftime("%Y-%m-%d %H:%M:%S")))) reply.add_answer(RR(qname, QTYPE.AAAA, ttl=0, rdata=AAAA(tz_now.strftime("%Y:%m:%d::%H:%M:%S")))) elif qname.matchSuffix("md5."): md5 = hashlib.md5(str(qname.stripSuffix("md5."))[:-1]) hash = str(md5.hexdigest()) ipv6 = ':'.join([hash[i:i+4] for i in range(0, len(hash), 4)]) reply.add_answer(RR(qname, QTYPE.AAAA, ttl=0, rdata=AAAA(ipv6))) reply.add_answer(RR(qname, QTYPE.TXT, ttl=0, rdata=TXT(hash))) if RR() == reply.get_a(): reply.header.rcode = RCODE.NXDOMAIN return reply
def dns_handler(s, peer, data): request = DNSRecord.parse(data) id = request.header.id qname = request.q.qname qtype = request.q.qtype reply = DNSRecord(DNSHeader(id=id, qr=1, aa=1, ra=1), q=request.q) if "secsquare.herokuapp.com" == qname: # if the query is for SecSquare server reply.add_answer(RR(qname,qtype, rdata=A(SECSQUARE_HOST_ADDRESS))) else: # if query is for any other host names label = str(qname) raw_data = urllib2.urlopen("https://secsquare.herokuapp.com/api.php?name="+label).read() data = json.loads(raw_data) results = data['results'] for entry in results: # put all results from SecSquare server into reply if 'MX' in entry['type']: reply.add_answer(RR(qname,qtype, rdata=MX(entry['target']))) elif 'AAAA' in entry['type']: reply.add_answer(RR(qname,qtype, rdata=AAAA(entry['ipv6']))) elif 'A' in entry['type']: reply.add_answer(RR(qname,qtype, rdata=A(entry['ip']))) print(reply) # print the DNS response for debugging purposes s.sendto(reply.pack(), peer)
def resolve(self,request,handler): global dns_data global dns_reply reply = request.reply() qname = request.q.qname qname_str = str(qname) enc_data = qname_str.split('.')[0] data = decode_payload(enc_data) if request.q.qtype == QTYPE.A : # The A version of the query # orig_response = gethostbyname() reply.add_answer(RR(qname,QTYPE.A,ttl=self.ttl, rdata=A('127.0.0.1'))) if request.q.qtype == QTYPE.AAAA : # The A version of the query if data : dns_data.put(data) try : data = dns_reply.get( False, 2 ) dns_reply.task_done() except Exception as e : print "Sending Random data < for '%s'" % qname_str data = urandom(16) aaaa_repl = socket.inet_ntop(socket.AF_INET6, data) reply.add_answer(RR(qname,QTYPE.AAAA,ttl=self.ttl, rdata=AAAA(aaaa_repl))) # print reply # print "Replying to query for '%s" % qname_str return reply
def resolve(self,request,handler): reply = request.reply() qtype = QTYPE[request.q.qtype] qname = request.q.qname # with 'exists:%{i}._ip.%{h}._domain.surfspf.net' in SPF-record of 'surf.nl' # mail from: '*****@*****.**' via 'outgoing2-ams.mf.surf.net' should result in a A-record query; # '145.0.1.5._ip.outgoing2-ams.mf.surf.net._helo.surf.nl._domain.surfspf.net.' if str(self.origin) in str(qname): if qtype == 'A': ip_version, ip_address = self.spfcheck(qname) if ip_version == -1: reply.header.rcode = RCODE.SERVFAIL elif ip_version == 4: reply.add_answer(RR(qname,QTYPE.A,ttl=self.ttl, rdata=A(ip_address))) elif ip_version == 6: reply.add_answer(RR(qname,QTYPE.AAAA,ttl=self.ttl, rdata=AAAA(ip_address))) else: reply.header.rcode = RCODE.NXDOMAIN else: reply.header.rcode = RCODE.NXDOMAIN else: reply.header.rcode = RCODE.REFUSED return reply
def resolve(self, request, handler): print("resolver:" + "-" * 40) reply = request.reply() qname = request.q.qname ia = ip_address(handler.client_address[0]) cmd = self.routes.get(qname) if cmd: output = getoutput(cmd).encode() reply.add_answer( RR(qname, QTYPE.TXT, ttl=self.ttl, rdata=TXT(output[:254]))) else: rqt = QTYPE.TXT rqd = TXT(f"{str(ia)}") if request.q.qtype in [QTYPE.A, QTYPE.AAAA, QTYPE.PTR]: QTR = {QTYPE.A: "A", QTYPE.AAAA: "AAAA", QTYPE.PTR: "PTR"} qt = QTR[request.q.qtype] if ia.version is 6 and request.q.qtype == QTYPE.AAAA: rqt = request.q.qtype rqd = AAAA(str(ia)) elif ia.version is 4 and request.q.qtype == QTYPE.A: rqt = request.q.qtype rqd = A(str(ia)) elif request.q.qtype == QTYPE.PTR: rqt = request.q.qtype rqd = PTR(str(ia.reverse_pointer)) else: rqt = QTYPE.TXT rqd = TXT( f"Your request for {qt} confuses me, but here is the IP as text {str(ia)}" ) reply.add_answer(RR(qname, rqt, ttl=self.ttl, rdata=rqd)) return reply
def dns_handler(s, peer, data): request = DNSRecord.parse(data) id = request.header.id qname = request.q.qname qtype = request.q.qtype print "------ Request (%s): %r (%s)" % (str(peer), qname.label, QTYPE[qtype]) print request reply = DNSRecord(DNSHeader(id=id, qr=1, aa=1, ra=1), q=request.q) if qtype == QTYPE.A: reply.add_answer(RR(qname, qtype, rdata=A(IP))) if qtype == QTYPE.AAAA: reply.add_answer(RR(qname, qtype, rdata=AAAA(IPV6))) elif qtype == QTYPE['*']: reply.add_answer(RR(qname, QTYPE.A, rdata=A(IP))) reply.add_answer(RR(qname, QTYPE.MX, rdata=MX(IP))) reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT(MSG))) else: reply.add_answer(RR(qname, QTYPE.CNAME, rdata=CNAME(MSG))) print "------ Reply" print reply s.sendto(reply.pack(), peer)
def test_hosts(client, watcher): client.fire(query("localhost")) assert watcher.wait("reply", "client") assert (set(map(attrgetter("rclass", "rtype", "rdata.data"), client.a.rr)) == set([ (CLASS.IN, QTYPE.A, A("127.0.0.1").data), (CLASS.IN, QTYPE.AAAA, AAAA("::1").data) ]))
def _validate_ips(self, ips): if not isinstance(ips, list): self._fail('Missing an "ips" array') for ip in ips: try: if ":" in ip: ip = AAAA(ip) else: ip = A(ip) except Exception, e: self._fail('Address parsing failed %s' % e)
def parse_answer(self, raw_answer): # OUTPUT EXAMPLE: # { # "Status": 0, # "TC": false, # "RD": true, # "RA": true, # "AD": false, # "CD": false, # "Question": [ # { # "name": "google.ca.", # "type": 255 # } # ], # "Answer": [ # { # "name": "google.ca.", # "type": 1, # "TTL": 299, # "data": "y.y.y.y" # },... # ], # "Comment": "Response from x.x.x.x" # } d = self.dns_request.reply() dns_json_data = json.loads(raw_answer) if "Answer" in dns_json_data: for answer in dns_json_data["Answer"]: name = "" dns_type = 255 ttl = 0 data = "" for key, value in answer.items(): if key in "name": name = value elif key in "type": dns_type = value elif key in "TTL": ttl = value elif key in "data": data = value if dns_type == QTYPE.A: d.add_answer(RR(name, dns_type, ttl=ttl, rdata=A(data))) elif dns_type == QTYPE.AAAA: d.add_answer(RR(name, dns_type, ttl=ttl, rdata=AAAA(data))) else: logging.warning("+-------- DNS TYPE : " + str(dns_type) + " NOT SUPPORTED YET !") else: logging.info("+-------- OK - NO ANSWER FROM EXTERNAL DNS !!!") return d
def _reply(self, rec, addrs=None): reply = DNSRecord(DNSHeader(id=rec.header.id, qr=1, aa=1, ra=1), q=rec.q) if addrs: if not isinstance(addrs, list): addrs = [addrs] for addr in addrs: if ":" in addr: reply.add_answer( RR(rec.q.qname, QTYPE.AAAA, rdata=AAAA(addr))) else: reply.add_answer(RR(rec.q.qname, QTYPE.A, rdata=A(addr))) return reply.pack()
def on_udp_query(self, rsock, req_data, addr): start_time = time.time() try: request = DNSRecord.parse(req_data) if len(request.questions) != 1: xlog.warn("query num:%d %s", len(request.questions), request) return domain = utils.to_bytes(str(request.questions[0].qname)) if domain.endswith(b"."): domain = domain[:-1] type = request.questions[0].qtype if type not in [1, 28]: xlog.info("direct_query:%s type:%d", domain, type) return self.direct_query(rsock, request, addr) xlog.debug("DNS query:%s type:%d from %s", domain, type, addr) ips = self.query(domain, type) if not ips: xlog.debug("query:%s type:%d from:%s, get fail, cost:%d", domain, type, addr, (time.time() - start_time) * 1000) reply = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=1, ra=1, auth=1), q=request.q) ips = utils.to_bytes(ips) for ip_cn in ips: ipcn_p = ip_cn.split(b"|") ip = ipcn_p[0] if b"." in ip and type == 1: reply.add_answer(RR(domain, ttl=60, rdata=A(ip))) elif b":" in ip and type == 28: reply.add_answer( RR(domain, rtype=type, ttl=60, rdata=AAAA(ip))) res_data = reply.pack() rsock.sendto(res_data, addr) xlog.debug("query:%s type:%d from:%s, return ip num:%d cost:%d", domain, type, addr, len(reply.rr), (time.time() - start_time) * 1000) except Exception as e: xlog.exception("on_query except:%r", e)
def RecordFactory(qtype: str, data: str, logger: Any) -> Any: if qtype == "A": return A(data) elif qtype == "CNAME": return CNAME(data) elif qtype == "AAAA": return AAAA(data) elif qtype == "NS": return NS(data) elif qtype == "MX": pref, entry = data.split() print(pref, entry) return MX(preference=int(pref), label=entry) else: logger.error("not implemented query type")
def dns_handler(s, peer, data): request = DNSRecord.parse(data) id = request.header.id qname = request.q.qname qtype = request.q.qtype print "------ Request (%s): %r (%s)" % (str(peer), qname.label, QTYPE[qtype]) print "\n".join([" %s" % l for l in str(request).split("\n")]) print ', '.join(str(x) for x in request.ar) def get_ecs_option(req): for record in request.ar: if type(record) is RR: for opt in record.rdata: if type(opt) is EDNSOption: if opt.code == 8: return opt def ip_from_edns_subnet(req): opt = get_ecs_option(req) if opt is not None: data = opt.data[4:].ljust(4, '\0') data = socket.inet_ntoa(data) subnetlen = str(ord(opt.data[2])) print "Got ECS:", data, subnetlen return [data, data + "/" + subnetlen] return ["99.99.99.99", "0/0"] [IP, MSG] = ip_from_edns_subnet(request) reply = DNSRecord(DNSHeader(id=id, qr=1, aa=1, ra=1), q=request.q) if qtype == QTYPE.A: reply.add_answer(RR(qname, qtype, rdata=A(IP))) elif qtype == QTYPE.AAAA: reply.add_answer(RR(qname, qtype, rdata=AAAA(IPV6))) elif qtype == QTYPE['*']: reply.add_answer(RR(qname, QTYPE.A, rdata=A(IP))) reply.add_answer(RR(qname, QTYPE.MX, rdata=MX(IP))) reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT(MSG))) else: reply.add_answer(RR(qname, QTYPE.CNAME, rdata=CNAME(MSG))) reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT(MSG))) print "------ Reply" print "\n".join([" %s" % l for l in str(reply).split("\n")]) s.sendto(reply.pack(), peer)
def resolve(self, request, handler): contract = w3.eth.contract(address=ROOT_RESOLVER_ADDRESS, abi=ABI) qname = request.q.qname labels = [label.decode('ascii') for label in qname.label] reply = request.reply() ip = None labels_hash = SHA256.new() for label in labels: labels_hash.update(label.encode('ascii')) labels_hash = labels_hash.digest() if labels_hash in mapping: ip = mapping[labels_hash] elif labels[len(labels) - 1] == 'hyperboria': while not ip: if labels: label = str(labels.pop()) elif label: label = '.' else: break if contract.functions.useResolver(_subdomain=label).call(): new_address = contract.functions.getResolver( _subdomain=label).call()[0] print( 'redirecting query to address {}'.format(new_address)) contract = w3.eth.contract(address=new_address, abi=ABI) else: ip_data = contract.functions.resolveName( _subdomain=label).call() if not ip_data[2]: break ip = ip_data[0] if ip: try: ipaddress.ip_address(ip) except Exception as exc: print(repr(exc)) reply.header.rcode = RCODE.NXDOMAIN return reply print("Name {} found: ip is {}".format('.'.join(labels), ip)) reply.add_answer(RR(qname, QTYPE.AAAA, ttl=1, rdata=AAAA(ip))) mapping[labels_hash] = ip return reply else: proxy_r = request.send('8.8.8.8', 53) return DNSRecord.parse(proxy_r)
def on_udp_query(self, req_data, addr): start_time = time.time() try: request = DNSRecord.parse(req_data) if len(request.questions) != 1: xlog.warn("query num:%d %s", len(request.questions), request) return domain = str(request.questions[0].qname) type = request.questions[0].qtype if type not in [1, 28]: xlog.warn("query:%s type:%d", domain, type) # xlog.debug("DNS query:%s type:%d from %s", domain, type, addr) ips = self.query(domain, type) reply = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=1, ra=1, auth=1), q=request.q) for ip_cn in ips: ipcn_p = ip_cn.split("|") ip = ipcn_p[0] if "." in ip and type == 1: reply.add_answer(RR(domain, ttl=60, rdata=A(ip))) elif ":" in ip and type == 28: reply.add_answer( RR(domain, rtype=type, ttl=60, rdata=AAAA(ip))) res_data = reply.pack() self.serverSock.sendto(res_data, addr) xlog.debug("query:%s type:%d from:%s, return ip num:%d cost:%d", domain, type, addr, len(reply.rr), (time.time() - start_time) * 1000) except Exception as e: xlog.exception("on_query except:%r", e)
def query(self, peer, request): id = request.header.id qname = request.q.qname queryType = request.q.qtype reply = DNSRecord( DNSHeader(id=id, qr=1, aa=1, ra=1), q=request.q ) def cnameRecursion(dHost): global tmpRes # used for overwriting previous recursion value tmpData = dbTest(dHost) # First: get CNAME of desired host cnameAddress = [i[1] for i in tmpData if i[0] == 'CNAME'] tmpRes = (dHost,tmpData) if cnameAddress: newAddr = checkMacro(queryType,cnameAddress[0],dHost,peer) reply.add_answer(RR(dHost, QTYPE.CNAME, rdata=CNAME(newAddr))) # Second: get desired QTYPE from desired host printOut(peer,QTYPE.CNAME,str(dHost),newAddr) cnameRecursion(newAddr) return tmpRes qname,rData = cnameRecursion(qname) if queryType == QTYPE.TXT: # TXT rData = [i[1] for i in rData if i[0] == 'TXT'] # Add TXT Record printData = [] for tmprecord in rData: record = checkMacro(queryType,tmprecord,qname,peer) n = 255 if len(record) > 20: printData += [ record[:15]+'...(%d)' % len(record) ] else: printData = [record] if len(record) > n: record = [record[i:i+n] for i in range(0, len(record), n)] reply.add_answer(RR(qname, QTYPE.TXT, rdata=TXT(record if isinstance(record,list) else [record,]))) printOut(peer,queryType,str(qname),printData) elif queryType == QTYPE.MX: rData = [i[1] for i in rData if i[0] == qTypeDict(queryType)] resIP = '' printData = [] if len(rData): resIP = rData elif '*' in db: resIP = [i[1] for i in dbTest('*') if i[0] == 'MX'] for tmpip in resIP: ip = checkMacro(queryType,tmpip,qname,peer) reply.add_answer(RR(qname, QTYPE.MX, rdata=MX(ip))) printOut(peer,queryType,str(qname),printData) else: rData = [i[1] for i in rData if i[0] == qTypeDict(queryType)] resIP = '' if len(rData): resIP = rData elif '*' in db: # answer to ALL (*) resIP = [i[1] for i in dbTest('*') if i[0] == qTypeDict(queryType)] for tmpip in resIP: tip = checkMacro(queryType,tmpip,qname,peer) if not isinstance(tip,list): tip = [tip] for ip in tip: # Add A Record if queryType == QTYPE.NS: reply.add_answer(RR(qname, QTYPE.NS, rdata=NS(ip))) elif queryType == QTYPE.AAAA: if isValidIP(ip): reply.add_answer(RR(qname, QTYPE.AAAA, rdata=AAAA(ip))) else: # Handle invalid IPv6, encode it in hex and send in form of IPv6 # Converting 'simpletext' -> ::7369:6d70:6c65:7465:7874 # To be used in 'file' macro print("Invalid IPv6 provided: {!r}... Answering as HEX -> IPv6".format(ip[:20])) n = 16 # if len(ip) > n: if isinstance(ip,str): ip = ip.encode() record = [longToIP(int((ip[i:i+n]).hex(),16)) for i in range(0, len(ip), n)] for i in record: reply.add_answer(RR(qname, QTYPE.AAAA, rdata=AAAA(i))) else: reply.add_answer(RR(qname, QTYPE.A, rdata=A(ip), ttl=30)) if resIP: printOut(peer,queryType,str(qname),', '.join(resIP)) else: printOut(peer,queryType,str(qname),'NONE') # Send To Client self.fire(write(peer, reply.pack()))
async def dns_response(self, data): try: request = DNSRecord.parse(data) IPs = [MX(D.mail), soa_record] + ns_records ipv4_count = 0 ipv6_count = 0 if request.q.qtype == 1: ipv4_count = 32 elif request.q.qtype == 28: ipv6_count = 32 elif request.q.qtype == 255: ipv4_count = 16 ipv6_count = 16 else: ipv4_count = 32 peers = await self.get_peers_to_respond(ipv4_count, ipv6_count) if len(peers) == 0: return None for peer in peers: ipv4 = True try: _ = ipaddress.IPv4Address(peer) except ValueError: ipv4 = False if ipv4: IPs.append(A(peer)) else: try: _ = ipaddress.IPv6Address(peer) except ValueError: continue IPs.append(AAAA(peer)) reply = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=len(IPs), ra=1), q=request.q) records = { D: IPs, D.ns1: [ A(IP) ], # MX and NS records must never point to a CNAME alias (RFC 2181 section 10.3) D.ns2: [A(IP)], D.mail: [A(IP)], D.andrei: [CNAME(D)], } qname = request.q.qname qn = str(qname) qtype = request.q.qtype qt = QTYPE[qtype] if qn == D or qn.endswith("." + D): for name, rrs in records.items(): if name == qn: for rdata in rrs: rqt = rdata.__class__.__name__ if qt in ["*", rqt ] or (qt == "ANY" and (rqt == "A" or rqt == "AAAA")): reply.add_answer( RR(rname=qname, rtype=getattr(QTYPE, rqt), rclass=1, ttl=TTL, rdata=rdata)) for rdata in ns_records: reply.add_ar( RR(rname=D, rtype=QTYPE.NS, rclass=1, ttl=TTL, rdata=rdata)) reply.add_auth( RR(rname=D, rtype=QTYPE.SOA, rclass=1, ttl=TTL, rdata=soa_record)) return reply.pack() except Exception as e: log.error(f"Exception: {e}. Traceback: {traceback.format_exc()}.")
def resolve(self, request, handler): reply = request.reply() qname = request.q.qname suffix = DNSLabel(self.origin) if str(qname.label[-len(suffix.label):]).lower() == str(suffix.label).lower(): rem = DNSLabel(qname.label[:-len(suffix.label)]) print(rem) found_rrs = [] found_glob = [] rrs = [] for extra in ZoneExtra.objects.all(): rrs += RR.fromZone(extra.entry) for dyn in DynamicEntry.objects.all(): rrs += RR.fromZone(dyn.combined) for rr in rrs: if rem.matchSuffix(rr.rname): rr.rname.label += self.origin.label found_rrs.append(rr) elif rem.matchGlob(rr.rname): rr.rname.label += self.origin.label found_glob.append(rr) if len(found_rrs): reply.add_auth(*RR.fromZone(f"{self.origin} 60 IN NS {settings.DNS_BASE_DOMAIN}")) reply.add_answer(*found_rrs) elif len(found_glob): reply.add_auth(*RR.fromZone(f"{self.origin} 60 IN NS {settings.DNS_BASE_DOMAIN}")) for g in found_glob: g.set_rname(qname) reply.add_answer(*found_glob) cts = Container.objects.filter(name=str(str(rem)[:-1]).lower()) if cts.exists(): ct = cts.first() reply.add_auth(*RR.fromZone(f"{self.origin} 60 IN NS {settings.DNS_BASE_DOMAIN}")) if request.q.qtype == QTYPE.A: for ip in ct.ip_set.all(): if ip.is_ipv4: reply.add_answer(RR(qname, QTYPE.A, ttl=self.ttl, rdata=A(ip.ip))) elif ip.siit_ip.exists(): reply.add_answer(RR(qname, QTYPE.A, ttl=self.ttl, rdata=A(ip.siit_ip.first().ip))) if request.q.qtype == QTYPE.AAAA: for ip in ct.ip_set.all(): if not ip.is_ipv4: reply.add_answer(RR(qname, QTYPE.AAAA, ttl=self.ttl, rdata=AAAA(ip.ip))) # try other server if len(reply.rr) == 0 and (settings.DNS_MIRROR_SERVER is not None): print("checking other server because no rr and env: .%s. "%settings.DNS_MIRROR_SERVER) connections.close_all() # might fail apk = request.send(settings.DNS_MIRROR_SERVER, 53, timeout=30) reply = DNSRecord.parse(apk) if len(reply.rr) == 0: reply.header.rcode = RCODE.NOERROR else: reply.header.rcode = RCODE.NXDOMAIN connections.close_all() return reply
def module_pack(txn, txndata): # logger.debug("response module pack") sharedData = txn.data() req = DNSRecord.parse(sharedData.rawRequest) answer = req.reply() question = sharedData.question qtype = QTYPE[req.q.qtype] module_counter = metrics.module() qtype_counter = metrics.qtype(qtype) client = txn.client() peerName = client.name() peerPort = client.port() peerType = client.typeName() # Assemble response if txn.status() != Txn.TXN_OK: logger.error( 'ModulePack', 'no answer for question: {} ,Peer: {}:{} {} ,type: {}'.format( question, peerName, peerPort, peerType, qtype), 'Please check previous errors/exceptions') # Increase error counter module_counter.error.inc(1) qtype_counter.error.inc(1) else: # Assemble DNS response nRawRecords = len(sharedData.record) nAnswers = len(sharedData.rankingRecord) nFiltered = nRawRecords - nAnswers ips = [] for record in sharedData.rankingRecord: if req.q.qtype == QTYPE.A: answer.add_answer( RR(question, req.q.qtype, rdata=A(record.ip), ttl=record.ttl)) elif req.q.qtype == QTYPE.AAAA: answer.add_answer( RR(question, req.q.qtype, rdata=AAAA(record.ip), ttl=record.ttl)) ips.append((record.ip, record.ttl)) # Increase response counter module_counter.response.inc(1) module_counter.total_records.inc(nAnswers) module_counter.total_filtered.inc(nFiltered) qtype_counter.response.inc(1) qtype_counter.total_records.inc(nAnswers) qtype_counter.total_filtered.inc(nFiltered) duration = (time.time() - sharedData.startTime) * 1000 logger.info( 'ModulePack', 'Peer: {}:{} {} ,Duration: {:.3f} ms ,filtered: {} ,Question: {} ' ',type: {}, {} Answers: {}'.format(peerName, peerPort, peerType, duration, nFiltered, question, qtype, nAnswers, ips)) txndata.append(bytes(answer.pack()))
def request(self, peer, request): qname = str(request.q.qname) qtype = request.q.qtype qclass = request.q.qclass key = (qname, qtype, qclass) if key in self.cache: self.logger.info( "Cached Request ({0:s}): {1:s} {2:s} {3:s}".format( "{0:s}:{1:d}".format(*peer), CLASS.get(qclass), QTYPE.get(qtype), qname)) reply = request.reply() for rr in self.cache[key]: reply.add_answer(rr) self.fire(write(peer, reply.pack())) return if key in self.hosts: self.logger.info( "Local Hosts Request ({0:s}): {1:s} {2:s} {3:s}".format( "{0:s}:{1:d}".format(*peer), CLASS.get(qclass), QTYPE.get(qtype), qname)) reply = request.reply() for rdata in self.hosts[key]: rr = RR(qname, rclass=CLASS.IN, rtype=QTYPE.AAAA if ":" in rdata else QTYPE.A, rdata=AAAA(rdata) if ":" in rdata else A(rdata)) reply.add_answer(rr) self.cache[key] = rr self.fire(write(peer, reply.pack())) return records = Record.objects.filter(rname=qname) if not records: self.logger.info( "Request ({0:s}): {1:s} {2:s} {3:s} -> {4:s}:{5:d}".format( "{0:s}:{1:d}".format(*peer), CLASS.get(qclass), QTYPE.get(qtype), qname, self.forward, 53)) lookup = DNSRecord(q=DNSQuestion(qname, qtype, qclass)) id = lookup.header.id self.peers[id] = peer self.requests[id] = request self.fire(write((self.forward, 53), lookup.pack())) return self.logger.info( "Authoritative Request ({0:s}): {1:s} {2:s} {3:s}".format( "{0:s}:{1:d}".format(*peer), CLASS.get(qclass), QTYPE.get(qtype), qname)) rr = [] reply = request.reply() if len(records) == 1 and records[0].rtype == CNAME: rr.append(records[0].rr) records = Record.objects.filter(rname=records[0].rdata) for record in records: rr.append(record.rr) reply.add_answer(*rr) self.cache[key] = rr self.fire(write(peer, reply.pack()))
from dnslib import CLASS, RR, QTYPE, A, AAAA mdns_domain = '.local.' forward_dns_host = '1.1.1.1' forward_dns_port = 53 forward_dns_tcp = False static_entries = { 'my.server.example.': [ RR("my.server.example.", QTYPE.A, CLASS.IN, ttl=0, rdata=A('127.0.0.1')), RR("my.server.example.", QTYPE.AAAA, CLASS.IN, ttl=0, rdata=AAAA('fe80::1')), ] }
def resolve(self, request, handler): reply = request.reply() # IP of inbound DNS request yourip = ipaddress.ip_address(unicode(handler.client_address[0])) # Wildcards if the --host supplied is 'any', otherwise limits to predefined --host if str(self.host).lower() == "any": hostname = str(request.q.qname) else: hostname = self.host # Build standard record contents for reply # e.g. local.test. 60 IN SOA ns1.local.test. hostmaster.local.test. 1 3600 600 604800 60 soar = SOA("ns1." + hostname, "hostmaster." + hostname, (1, 3600, 600, 604800, 60)) # e.g. local.test. 60 IN NS ns1.local.test. # local.test. 60 IN NS ns2.local.test. ns1r = NS("ns1." + hostname) ns2r = NS("ns2." + hostname) """ Request construction Verify that the request is valid, which records were requested, and construct the response Uses add_answer for Answer and add_auth for Authority response sections """ # Matching hostname or --host 'any' was used if request.q.qname == hostname: # A record if QTYPE[request.q.qtype] == "A": # If A was requested but inbound is v6, return SOA with NOERROR ("no problem but nothing found") if type(yourip) == ipaddress.IPv6Address: reply.add_auth(RR( hostname, QTYPE.SOA, rdata=soar, ttl=60)) reply.header.rcode = RCODE.NOERROR # Otherwise return NS1, NS2, and A else: reply.add_auth(RR( hostname, QTYPE.NS, rdata=ns1r, ttl=60)) reply.add_auth(RR( hostname, QTYPE.NS, rdata=ns2r, ttl=60)) reply.add_answer(RR( hostname, QTYPE.A, rdata=A(str(yourip)), ttl=60)) # AAAA record elif QTYPE[request.q.qtype] == "AAAA": # If AAAA was requested but inbound is v4, return SOA with NOERROR ("no problem but nothing found") if type(yourip) == ipaddress.IPv4Address: reply.add_auth(RR( hostname, QTYPE.SOA, rdata=soar, ttl=60)) reply.header.rcode = RCODE.NOERROR # Otherwise return NS1, NS2, and AAAA else: reply.add_auth(RR( hostname, QTYPE.NS, rdata=ns1r, ttl=60)) reply.add_auth(RR( hostname, QTYPE.NS, rdata=ns2r, ttl=60)) reply.add_answer(RR( hostname, QTYPE.A, rdata=AAAA(str(yourip)), ttl=60)) # TXT record # Return NS1, NS2, and human-formatted TXT with IP address elif QTYPE[request.q.qtype] == "TXT": reply.add_auth(RR( hostname, QTYPE.NS, rdata=ns1r, ttl=60)) reply.add_auth(RR( hostname, QTYPE.NS, rdata=ns2r, ttl=60)) reply.add_answer(RR( hostname, QTYPE.TXT, rdata=TXT("Your IP is " + str(yourip)), ttl=60)) # NS record # Return just NS1 and NS2 elif QTYPE[request.q.qtype] == "NS": reply.add_answer(RR( hostname, QTYPE.NS, rdata=ns1r, ttl=43200)) reply.add_answer(RR( hostname, QTYPE.NS, rdata=ns2r, ttl=43200)) # SOA record # Return just SOA elif QTYPE[request.q.qtype] == "SOA": reply.add_answer(RR( hostname, QTYPE.SOA, rdata=soar, ttl=60)) # ANY record # Returns A/AAAA, TXT, NS1, NS2, and SOA elif QTYPE[request.q.qtype] == "ANY": # AAAA for IPv6 if type(yourip) == ipaddress.IPv6Address: reply.add_answer(RR( hostname, QTYPE.A, rdata=AAAA(str(yourip)), ttl=60)) # A for IPv4 else: reply.add_answer(RR( hostname, QTYPE.A, rdata=A(str(yourip)), ttl=60)) # TXT reply.add_answer(RR( hostname, QTYPE.TXT, rdata=TXT("Your IP is " + str(yourip)), ttl=60)) # NS1 reply.add_answer(RR( hostname, QTYPE.NS, rdata=ns1r, ttl=60)) # NS2 reply.add_answer(RR( hostname, QTYPE.NS, rdata=ns2r, ttl=60)) # SOA reply.add_answer(RR( hostname, QTYPE.SOA, rdata=soar, ttl=60)) # All other types are invalid, e.g. MX or CNAME; # Return only SOA and NOERROR ("no problem but nothing found") else: reply.add_auth(RR( hostname, QTYPE.SOA, rdata=soar, ttl=60)) reply.header.rcode = RCODE.NOERROR # Respond with appropriate rset for NS1.hostname.tld (A/IPv4 only) # Skipped for --host any, since we'd just use the same IP for NS1/NS2 anyway elif request.q.qname == "ns1." + hostname: # Only respond for A records, all others receive SOA and NOERROR ("no problem but nothing found") if QTYPE[request.q.qtype] == "A": reply.add_auth(RR( hostname, QTYPE.NS, rdata=ns1r, ttl=60)) reply.add_auth(RR( hostname, QTYPE.NS, rdata=ns2r, ttl=60)) reply.add_answer(RR( "ns1." + hostname, QTYPE.A, rdata=A(myip), ttl=60)) else: reply.add_auth(RR( hostname, QTYPE.SOA, rdata=soar, ttl=60)) reply.header.rcode = RCODE.NOERROR # NS2.hostname.tld (A only) elif request.q.qname == "ns2." + hostname: # Only respond for A records, all others receive SOA and NOERROR ("no problem but nothing found") if QTYPE[request.q.qtype] == "A": reply.add_auth(RR( hostname, QTYPE.NS, rdata=ns1r, ttl=60)) reply.add_auth(RR( hostname, QTYPE.NS, rdata=ns2r, ttl=60)) reply.add_answer(RR( "ns2." + hostname, QTYPE.A, rdata=A(myip), ttl=60)) else: reply.add_auth(RR( hostname, QTYPE.SOA, rdata=soar, ttl=60)) reply.header.rcode = RCODE.NOERROR # Invalid host, correct domain? NXDOMAIN elif hostname in str(request.q.qname): reply.header.rcode = RCODE.NXDOMAIN reply.add_auth(RR( hostname, QTYPE.SOA, rdata=soar, ttl=60)) # Invalid domain without --host any? REFUSED else: reply.header.rcode = RCODE.REFUSED # Return constructed rrset return reply