def _packetize_txt(self, query, response, opcode, data=None): """ will break up the transmitted data into payloads that can be sent over the network. The size of the packets will be 255 - 3 for the header bytes needed to reassemble packets by resolution. :param query: A DNSRecord query :param response: A DNSRecord response skeleton made by doing query.reply() :param opcode: an integer representing the opcode for resolution to interpret :param data: the data to encode :return: a dnslib.DNSRecord with the first payload chunk and a deque() of next chunks to be sent """ if not data: data = "010vsp1=This is a DNS TXT Record" self.prev_cmd = [] rest = deque() _, constructor, msg_size = Records.TXT.value rr_type = query.questions[0].qtype chunks = [ f"{data[i:i+msg_size]}" for i in range(0, len(data), msg_size) ] #self.logger.debug(chunks) for i, chunk in enumerate(chunks): answer = RR(rname=query.get_q().get_qname(), rtype=rr_type, rclass=CLASS.IN, rdata=constructor(f"{opcode}{len(chunks)}{i}" + chunk), ttl=1337) self.prev_cmd.append(answer) # Add at least one response to the query if i == 0: response.add_answer(answer) continue # If Extended DNS is enabled, we can have up to 2048 bytes. # Otherwise we're going to send command over multiple queries if self.edns and i > 0: response.add_answer(answer) else: rest.append(answer) if len(chunks) > 1: # Add the end transmission packet to signal that it is done rest.append( RR(rname=query.get_q().get_qname(), rtype=rr_type, rclass=CLASS.IN, rdata=constructor("510END-TRANSMISSION"), ttl=1337)) return response, rest
def get_chromecast_mdns_response_2017_22(query_data, chromecast_ip, chromecast_uuid, friendly_name, bs): from dnslib import dns, RR, QTYPE, A, PTR, TXT, SRV # query_a = dns.DNSRecord.parse(query_data) query_a = query_data ans = query_a.reply(ra=0) ans.questions = [] collapsed_uuid=chromecast_uuid.replace("-","") long_mdns_name = "Chromecast-%s._googlecast._tcp.local"%collapsed_uuid ans.add_answer(RR("_googlecast._tcp.local", QTYPE.PTR, rdata=PTR(long_mdns_name), ttl=120)) ans.add_ar(RR(long_mdns_name, QTYPE.TXT, rdata=TXT(["id=%s"%collapsed_uuid, "rm=", "ve=05", "md=Chromecast", "ic=/setup/icon.png", "fn=%s"%friendly_name, "ca=4101", "st=0", "bs=%s"%bs, "rs="]), ttl=4500, rclass=32769)) ans.add_ar(RR(long_mdns_name, QTYPE.SRV, rdata=SRV(0, 0, 8009, "%s.local"%chromecast_uuid), rclass=32769,ttl=120)) ans.add_ar(RR("%s.local"%chromecast_uuid, QTYPE.A, rdata=A(chromecast_ip),rclass=32769,ttl=120)) return [ans]
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 resolve(self, request, handler): print(request.q.qname) if request.q.qname in self.blacklist: answer = RR(rdata=A(self.host)) answer.set_rname(self.answer) reply = request.reply() reply.add_answer(answer) print(reply) print("-" * 200) return reply return ProxyResolver.resolve(self, request, handler)
def dns_response(self, data): request = DNSRecord.parse(data) logger.debug('%s', request) reply = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=1, ra=1), q=request.q) qname = request.q.qname qn = str(qname) if qn.endswith('.'): qn = qn[:-1] qtype = request.q.qtype qt = QTYPE[qtype] qnhost, qndomain = qn.split('.', 1) # # OK, so we are not conformant to the standards at all, as we never # return any SOA records and stuff... # if qndomain == settings.IPAUTH_DNSSERVER_DOMAIN: if qt in ['*', 'A']: for u in User.objects.filter(iptouser__isnull=False): if qnhost == username_to_hostname(u.username): for itu in u.iptouser_set.all(): reply.add_answer(RR(rname=qname, rtype=QTYPE.A, rclass=1, ttl=self.server.command.options['ttl'], rdata=A(itu.ip_addr))) elif qn.endswith('.in-addr.arpa'): if qt in ['*', 'PTR']: qn = qn[:-len('.in-addr.arpa')] parts = qn.split('.') if len(parts) == 4: ip = '.'.join(reversed(parts)) try: iptu = IpToUser.objects.get(ip_addr=ip) fqdn = username_to_hostname(iptu.user.username) + \ '.' + settings.IPAUTH_DNSSERVER_DOMAIN + '.' reply.add_answer(RR(rname=qname, rtype=QTYPE.PTR, rclass=1, ttl=self.server.command.options['ttl'], rdata=PTR(fqdn))) except IpToUser.DoesNotExist: pass logger.debug('%s', reply) 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 gen_response(qt, qn): global serving_domains prefix_ = list( filter(lambda d: qn == d or qn.endswith('.' + d), serving_domains)) if len(prefix_) != 1: # print("Error: invalid request domain {} in {}".format(qn, serving_domains)) return None prefix = prefix_[0] print('REQ: ', qt, qn) if qt == 'SOA': generated_soa = dnslib.SOA( mname="todo." + domain_text, rname="*****@*****.**", times=( 201307231, # serial number 10000, # refresh 2400, # retry 604800, # expire 3600, # minimum )) return RR(rname=prefix, rtype=QTYPE.SOA, rclass=1, ttl=86400, rdata=generated_soa) # return {"mname": "todo."+domain_text, "rname": "*****@*****.**", "serial": "10", "refresh": 3600, "retry": 600, "expire": 604800, "minimum": 86400} elif qt == 'A': requested_ip = qn[:len(qn) - len(prefix)].strip('.') if not re.match(r'^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$', requested_ip): print("Invalid requested_ip: " + requested_ip) return None generated_a = dnslib.A(requested_ip) return RR(rname=qn, rtype=QTYPE.A, rclass=1, ttl=86400, rdata=generated_a) elif qt == 'NS': generated_ns = dnslib.NS(ns_ipaddr) return RR(rname=prefix, rtype=QTYPE.NS, rclass=1, ttl=86400, rdata=generated_ns) else: print("Invalid qt=" + qt) return None
def from_zone(cls, zone): records = [] logger.info(f"loading zone: {zone.domain}/{zone.ip} ({zone.id})") dns_records = zone.dns_records or [] # if the zone has no records, create some default ones if not dns_records: logger.warning( f"zone has no dns_records. loading defaults: {zone.domain}/{zone.ip} ({zone.id})" ) rrs = RR.fromZone( ZONE_TEMPLATE.format(domain_name=zone.domain, domain_ip=zone.ip)) zone_records = [Record.make(zone, rr) for rr in rrs] for zr in zone_records: # TODO: make this clean on output rrstr = str(dedent(str(zr.rr))) logger.debug(f"loading record entry: {rrstr}") logger.debug( "loaded record details - name: {} | rtype: {} | rr: {}". format(str(zr.rr.rname), str(QTYPE[zr.rr.rtype]), str(zr.rr))) else: # loop over each dns_record of the zone and convert it to RR record dns_records = sorted(dns_records, key=lambda x: x.sort) zone_records = [] for dns_record in dns_records: try: rrs = RR.fromZone(dns_record.record) _zone_records = [Record.make(zone, rr) for rr in rrs] for zr in _zone_records: rrstr = str(dedent(str(zr.rr))) logger.debug( f"loading record: {str(dns_record.record)}") logger.debug(f"loading record entry: {rrstr}") logger.debug( "loaded record details - name: {} | rtype: {} | rr: {}" .format(str(zr.rr.rname), str(QTYPE[zr.rr.rtype]), str(zr.rr))) zone_records = zone_records + _zone_records except Exception as e: logger.critical( f'Error processing line ({e.__class__.__name__}: {e}) "{dns_record.id}:{dns_record.record}" ' ) raise e # add the records for the zone to the rest of the records records = records + zone_records return cls(records)
def _a_page_encoder(self, data, encoder, nonce): data = encoder.encode(data, nonce, symmetric=encoder.kex_completed) length = struct.pack('B', len(data)) payload = length + data if len(payload) > 48: raise ValueError('Page size more than 45 bytes ({})'.format( len(payload))) response = [] for idx, part in enumerate( [payload[i:i + 3] for i in xrange(0, len(payload), 3)]): header = (random.randint(1, 6) << 29) idx = idx << 25 bits = (struct.unpack( '>I', '\x00' + part + chr(random.randrange(0, 255)) * (3 - len(part)))[0]) << 1 packed = struct.unpack( '!BBBB', struct.pack('>I', header | idx | bits | int(not bool(bits & 6)))) address = '.'.join(['{}'.format(int(x)) for x in packed]) response.append(RR('.', QTYPE.A, rdata=A(address), ttl=600)) return response
def create_result(self, qname, qtype, value): """Create a result response for a question""" record_class = getattr(dnslib, qtype) return RR(rname=qname, rtype=dnslib.QTYPE[qtype], rdata=record_class(value))
def resolve(self, request, handler): reply = request.reply() zone = self.zones.get(request.q.qname) if zone is not None: for zone_records in zone: rr = zone_records.try_rr(request.q) rr and reply.add_answer(rr) else: # no direct zone so look for an SOA record for a higher level zone found = False for zone_label, zone_records in self.zones.items(): if request.q.qname.matchSuffix(zone_label): try: soa_record = next(r for r in zone_records if r.is_soa) except StopIteration: continue else: reply.add_answer(soa_record.as_rr(zone_label)) found = True break if not found: reply.add_answer( RR(str(request.q.qname), QTYPE.A, rdata=A( socket.gethostbyname_ex(str( request.q.qname))[2][0]), ttl=60)) return reply
def resolve(self,request,handler): reply = request.reply() # the object that this function will return in the end, with modifications qname = request.q.qname # the domain that was looked up burrow_log("Request for " + str(DNSLabel(qname.label[-5:])), 0) # First, we make sure the domain ends in burrow.tech. # If not, we return an NXDOMAIN result. if not qname.matchSuffix("burrow.tech"): reply.header.rcode = RCODE.NXDOMAIN return reply # Next, we try to look up the domain in our list of fixed test records. found_fixed_rr = False for rr in self.fixedrrs: a = copy.copy(rr) if (a.rname == qname): found_fixed_rr = True LOG("Found a fixed record for " + str(a.rname)) reply.add_answer(a) if found_fixed_rr: return reply # Alright, if we've gotten here it must be a Transmission API message! assert(not found_fixed_rr) response_dict = self.handle_transmission_api_message(qname) zone = generate_TXT_zone(str(qname), dict_to_attributes(response_dict)) rrs = RR.fromZone(zone) for rr in rrs: reply.add_answer(rr) return reply
def resolve(self, request, handler): qname = request.q.qname qtype = QTYPE[request.q.qtype] qname = str(qname).split('.') if qname[-1] == '': qname.pop(-1) if qname[-1] == 'novalocal' and qtype in ['A', 'AAAA', 'MX']: reply = request.reply() servername = qname[-2] if len(qname) == 2: query = 'fixed' elif len(qname) == 3: query = qname[0] else: return reply if query not in ['fixed', 'floating']: return reply print(qname) for server in CachedNovaLookup.get_list(): if server.name == servername: for interface in server.addresses.values(): for ip in interface: if ip['OS-EXT-IPS:type'] == query and qtype == 'A': ans = RR.fromZone('{} 60 IN A {}'.format( request.q.qname, ip['addr']))[0] print(ans) ans.rname = request.q.qname reply.add_answer(ans) return reply else: return super(NovaResolver, self).resolve(request, handler)
def resolve(self,request,handler): reply = request.reply() qname = request.q.qname # Format is 00.DATA.domain.tld' qstr = str(qname) label = qstr.split('.') if SYNTAX.match(qstr): chunk_id = int(label[0]) chunk_data = label[1] if chunk_id not in self.chunks: self.chunks[chunk_id] = chunk_data # Decrypt and dump the chunk if len(self.chunks) == self.chunk_num: block = "".join([ self.chunks[i] for i in sorted(self.chunks.keys())]).decode('hex') plain = self.decrypt(block) try: print('[+] %s: Credentials logged for user %s' % (time.ctime(), plain.split(':')[0])) with open(self.out, 'ab') as o: o.write('[%s] %s\n' % (time.ctime(), plain)) except: pass self.chunks.clear() reply.add_answer(RR(qname,QTYPE.TXT,ttl=self.ttl, rdata=TXT("x00x00x00x00x00"))) return reply
def resolve(self, request, handler): type_name = QTYPE[request.q.qtype] reply = request.reply() for record in self.records: if record.match(request.q): reply.add_answer(record.rr) if reply.rr: logger.info('found zone for %s[%s], %d replies', request.q.qname, type_name, len(reply.rr)) return reply # no direct zone so look for an SOA record for a higher level zone for record in self.records: if record.sub_match(request.q): reply.add_answer(record.rr) if reply.rr: logger.info('found higher level SOA resource for %s[%s]', request.q.qname, type_name) return reply logger.info('no local zone found, proxying %s[%s]', request.q.qname, type_name) proxy_resp = super().resolve(request, handler) if type_name == 'A': if (self.check_block(proxy_resp.rr)): rr = RR(proxy_resp.rr[0].get_rname(), request.q.qtype, ttl=60, rdata=A("127.0.0.1")) proxy_resp.rr = [rr] return proxy_resp return super().resolve(request, handler)
def _A(self, name): if name.label[0] == "data": print base64.b64decode(name.label[1]), else: print name return RR(name, QTYPE.A, rdata=A(IP_ADDRESS), ttl=0)
def resolve_mdns(self, request, handler, rewrite=None): sock = get_mdns_socket() d = DNSRecord(DNSHeader(id=0, bitmap=0), q=request.q) sock.sendto(d.pack(), (nameserver4, 5353)) # sock.sendto(d.pack(), (nameserver6, 5353)) qname = request.q.qname if rewrite: request.q.qname = rewrite reply = request.reply() while True: buf, remote = sock.recvfrom(8192) d = DNSRecord.parse(buf) success = False if (d.header.aa == 1) and (d.header.a > 0): for response in d.rr: if str(response.rname) == qname: success = True response.rclass = CLASS.IN # These two lines can be deleted if we dont want the original response reply.add_answer(response) response = RR.fromZone(response.toZone())[0] if rewrite: response.rname = rewrite reply.add_answer(response) # print(reply) if success: break return reply
def __init__(self, rname, rtype, args): self._rname = DNSLabel(rname) rd_cls, self._rtype = TYPE_LOOKUP[rtype] if self._rtype == QTYPE.SOA and len(args) == 2: # add sensible times to SOA args += (SERIAL_NO, 3600, 3600 * 3, 3600 * 24, 3600), if self._rtype == QTYPE.TXT and len(args) == 1 and isinstance( args[0], str) and len(args[0]) > 255: # wrap long TXT records as per dnslib's docs. args = wrap(args[0], 255), if self._rtype in (QTYPE.NS, QTYPE.SOA): ttl = 3600 * 24 else: ttl = 300 self.rr = RR( rname=self._rname, rtype=self._rtype, rdata=rd_cls(*args), ttl=ttl, )
def resolve(self, request, handler): reply = request.reply() if request.q.qtype != QTYPE.A: log.error("Unsupported query qtype: `{}`".format(request.q.qtype)) reply.header.rcode = getattr(RCODE, 'NXDOMAIN') return reply query = str(request.q.qname) if query not in self._records: log.error("qname `{}` not present in DB".format(query)) reply.header.rcode = getattr(RCODE, 'NXDOMAIN') return reply log.info( "DNS query for `{}`, type `{}`, reply `{}`, ttl `{}`".format( query, request.q.qtype, self._records[query]['ip'], self._records[query]['ttl']) ) reply.add_answer( *RR.fromZone("{} {} A {}".format( query, self._records[query]['ttl'], self._records[query]['ip'], ) ) ) return reply
def resolve(self, request, handler): qname = request.q.qname qtype = QTYPE[request.q.qtype] # Custom answer only for A (ipv4) or ANY requests if fnmatch.fnmatch(str(qname), self.match) and qtype in ('A', 'ANY'): reply = request.reply() ip = self.get_ip_from_dns(str(qname)) if len(ip) == 0: reply.header.rcode = getattr(RCODE, 'NXDOMAIN') else: reply.add_answer(RR(qname, QTYPE.A, rdata=A(ip), ttl=60)) return reply try: if handler.protocol == 'udp': proxy_r = request.send(self.address, self.port, timeout=self.timeout) else: proxy_r = request.send(self.address, self.port, tcp=True, timeout=self.timeout) reply = DNSRecord.parse(proxy_r) except socket.timeout: reply = request.reply() reply.header.rcode = getattr(RCODE, 'NXDOMAIN') return reply
def __init__(self,zone=False): # add zone if supplied self.zone = [] if zone: for rr in RR.fromZone(zone): if not self.exist(rr): self.add_record(rr)
def _resolve(self, request, handler): qname = request.q.qname reply = request.reply() # TODO: # Resolve NS?, DS, SOA somehow if not qname.matchSuffix(self.domain): if self.recursor: try: return DNSRecord.parse(request.send(self.recursor, timeout=2)) except socket.error: pass except Exception as e: logger.exception('DNS request forwarding failed ({})'.format(e)) else: logger.debug('Bad domain: {} (suffix={})'.format(qname, self.domain)) reply.header.rcode = RCODE.NXDOMAIN return reply arecords = self.process(qname.stripSuffix(self.domain).idna()[:-1]) if arecords: for address in arecords: reply.add_answer(RR(qname, QTYPE.A, rdata=A(address), ttl=600)) else: reply.header.rcode = RCODE.NXDOMAIN return reply
def resolve(self, request, handler): reply = request.reply() qname = request.q.qname cc_record = "in." + domain + "." qstr = str(qname) if cc_record in qstr: try: command_txt = q_commands.get(block=False, timeout=None) except queue.Empty: command_txt = "" reply.add_answer(*RR.fromZone( "{} 0 IN TXT \"{}\"".format(qname, base58.b58encode(command_txt.encode("utf-8")).decode("ascii")))) elif request.q.qtype == 1 and ("out." + domain + ".") in qstr: self.__parse_out(qstr) reply.add_answer(*RR.fromZone("{} 0 IN A {}".format(qname, "127.255.255.255"))) return reply
def get_chromecast_mdns_response_2018_03(query_data, chromecast_ip, chromecast_uuid, friendly_name, bs, cd="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", rs="", ca=4101, st=0, nf=1): from dnslib import dns, RR, QTYPE, A, PTR, TXT, SRV query_a = query_data results = [] collapsed_uuid=chromecast_uuid.replace("-","") long_mdns_name = "Chromecast-%s-1._googlecast._tcp.local"%collapsed_uuid for question in query_a.questions: ans = query_a.reply(ra=0) ans.questions = [] ans.add_answer(RR(question.qname, QTYPE.PTR, rdata=PTR(long_mdns_name), ttl=120)) ans.add_ar(RR(long_mdns_name, QTYPE.TXT, rdata=TXT(["id=%s"%collapsed_uuid, "cd=%s"%cd,"rm=", "ve=05", "md=Chromecast", "ic=/setup/icon.png", "fn=%s"%friendly_name, "ca=%s"%ca, "st=%s"%st, "bs=%s"%bs, "nf=%s"%nf,"rs=%s"%rs]), ttl=4500, rclass=32769)) ans.add_ar(RR(long_mdns_name, QTYPE.SRV, rdata=SRV(0, 0, 8009, "%s.local"%chromecast_uuid), rclass=32769,ttl=120)) ans.add_ar(RR("%s.local"%chromecast_uuid, QTYPE.A, rdata=A(chromecast_ip),rclass=32769,ttl=120)) results.append(ans) return results
def respond(self, request): """Returns response containing self.ip.""" address = str(request.questions[0].qname) self.logger.log(self.parseloglevel(), "{b} - Responding to request for address:'{addr}'".format(b=str(self), addr=address)) response = request.reply() response.add_answer(RR(address, QTYPE.A, rdata=A(self.ip))) return response
def __init__(self, address, port, ttl, intercept, skip, nxdomain, timeout=0): """ address/port - upstream server ttl - default ttl for intercept records intercept - list of wildcard RRs to respond to (zone format) skip - list of wildcard labels to skip nxdomain - list of wildcard labels to retudn NXDOMAIN timeout - timeout for upstream server """ self.address = address self.port = port self.ttl = parse_time(ttl) self.skip = skip self.nxdomain = nxdomain self.timeout = timeout self.zone = [] for i in intercept: if i == '-': i = sys.stdin.read() for rr in RR.fromZone(i, ttl=self.ttl): self.zone.append((rr.rname, QTYPE[rr.rtype], rr))
def DNSGuard(ip, port, blacklist): octetsize = 512 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((ip, port)) data = None addr = None R = resolver.Resolver() logging.debug("DNSGuard SERVER ACTIVE ON {}:{}".format(ip, port)) while True: data, addr = sock.recvfrom(octetsize) packet = DNSRecord.parse(data) question = packet.get_q() fqdn = FQDN(question) logging.debug("Query: {}".format(str(packet))) if allowed(fqdn, blacklist): try: zones = R.resolveZone([fqdn]) logging.debug("Allowed: {}".format(zones)) reply = packet.reply() for zone in zones: reply.add_answer(*RR.fromZone(zone)) sock.sendto(DNSRecord.pack(reply), addr) except Exception as e: logging.error("Error: {}".format(e)) pass pass
def resolve_forward(self, qname, qtype, reply): """ Build a response to a forward DNS query (i.e. one that contains a hostname) :param dnslib.DNSRecord qname: The query's target. :param str qtype: The type of query (e.g. ``"SRV"``) :param dnslib.DNSRecord reply: The DNSRecord to populate with the reply. """ # Request isn't even in our domain if not qname.matchSuffix(self.domain): logging.warning("Rejecting query outside our domain: %s", qname) reply.header.rcode = RCODE.NOTAUTH return with self.lock: # Is the request for a service alias? for srv_domain, addrs in self.services.items(): if qname.matchSuffix(srv_domain): if not addrs: if (time.time() - self._startup > STARTUP_QUIET_PERIOD): logging.warning( "No instances found, returning " "SERVFAIL for %s", qname) # If there are no instances, we are unable to read from # ZK (or else the relevant service is down), so return # SERVFAIL reply.header.rcode = RCODE.SERVFAIL return for addr in addrs: reply.add_answer(RR(qname, QTYPE.A, rdata=A(addr))) return logging.warning("Unknown service: %s", qname) reply.header.rcode = RCODE.NXDOMAIN
def __init__(self): fixed_zone = open("fixed_zone/primary.txt").read() + open("fixed_zone/tests.txt").read() self.fixedrrs = RR.fromZone(fixed_zone) self.active_transmissions = {} # Dictionary of Transmission objects. # Their ID's are the keys, for easy/quick lookup. self.cache = ExpiringDict(max_len=100000, max_age_seconds=70) self.transmission_handler_lock = multiprocessing.Lock()
def resolve(self, request, handler): reply = request.reply( ) # the object that this function will return in the end, with modifications qname = request.q.qname # the domain that was looked up burrow_log("Request for " + str(DNSLabel(qname.label[-5:])), 0) # First, we make sure the domain ends in burrow.tech. # If not, we return an NXDOMAIN result. if not qname.matchSuffix("burrow.tech"): reply.header.rcode = RCODE.NXDOMAIN return reply # Next, we try to look up the domain in our list of fixed test records. found_fixed_rr = False for rr in self.fixedrrs: a = copy.copy(rr) if (a.rname == qname): found_fixed_rr = True LOG("Found a fixed record for " + str(a.rname)) reply.add_answer(a) if found_fixed_rr: return reply # Alright, if we've gotten here it must be a Transmission API message! assert (not found_fixed_rr) response_dict = self.handle_transmission_api_message(qname) zone = generate_TXT_zone(str(qname), dict_to_attributes(response_dict)) rrs = RR.fromZone(zone) for rr in rrs: reply.add_answer(rr) return reply
def resolve(self, request, handler): """ Respond to DNS request - parameters are request packet & handler. Method is expected to return DNS response """ reply = request.reply() qname = request.q.qname qtype = QTYPE[request.q.qtype] if qtype == "TXT": txtpath = os.path.join(tempfile.gettempdir(), str(qname).lower()) if os.path.isfile(txtpath): reply.add_answer( RR(qname, QTYPE.TXT, rdata=TXT(open(txtpath).read().strip())) ) for name, rtype, rr in self.zone: # Check if label & type match if getattr(qname, self.eq)(name) and ( qtype == rtype or qtype == "ANY" or rtype == "CNAME" ): # If we have a glob match fix reply label if self.glob: a = copy.copy(rr) a.rname = qname reply.add_answer(a) else: reply.add_answer(rr) # Check for A/AAAA records associated with reply and # add in additional section if rtype in ["CNAME", "NS", "MX", "PTR"]: for a_name, a_rtype, a_rr in self.zone: if a_name == rr.rdata.label and a_rtype in ["A", "AAAA"]: reply.add_ar(a_rr) if not reply.rr: reply.header.rcode = RCODE.NXDOMAIN return reply
def manufactory_DNS(self): response_packet = DNSRecord() response_packet.header.id = self.query_id response_packet.add_question(DNSQuestion(self.qname, self.qtype)) related_rr = filter(lambda rr: self.qname in rr, intercept_rr) for answer in related_rr: response_packet.add_answer(*RR.fromZone(answer)) self.response_packet = response_packet.pack().__str__()
def __init__(self,zone,glob=False): """ Initialise resolver from zone file. Stores RRs as a list of (label,type,rr) tuples If 'glob' is True use glob match against zone file """ self.zone = [(rr.rname,QTYPE[rr.rtype],rr) for rr in RR.fromZone(zone)] self.glob = glob self.eq = 'matchGlob' if glob else '__eq__'
def load_rules(cls, rules): for rule in rules: zone = None try: zone = RR.fromZone(rule) except Exception: print('[e] Malformed rule -- {rule}'.format(rule=rule)) continue domain = rule.split()[0] cls._rules_tables[domain] = zone
def resolve(self, request, handler): db = Data() reply = request.reply() print(type(request)) print('------------') #print(request.q) host = None ip = None for i in request.questions: host = i.qname ip = db.get_ip_by_host(host) print("Host {0} got ip {1}".format(host, ip)) break print('------------') reply.add_answer(*RR.fromZone("{0} 60 A {1}".format(host, ip[0]))) return reply
def resolve(self,request,handler): reply = request.reply() qname = request.q.qname qtype = QTYPE[request.q.qtype] if qtype == 'SRV': port = 389 if qname.label[0] == '_kpasswd': port = 464 a = RR.fromZone('. 60 IN SRV 0 100 %d 192.168.0.1' % port)[0] a.rname = qname reply.add_answer(a) else: # Replace labels with request label for rr in self.rrs: a = copy.copy(rr) a.rname = qname reply.add_answer(a) return reply
def __init__(self, address, port, ttl, intercept, skip, nxdomain): """ address/port - upstream server ttl - default ttl for intercept records intercept - list of wildcard RRs to respond to (zone format) skip - list of wildcard labels to skip nxdomain - list of wildcard labels to retudn NXDOMAIN """ self.address = address self.port = port self.ttl = parse_time(ttl) self.skip = skip self.nxdomain = nxdomain self.zone = [] for i in intercept: if i == "-": i = sys.stdin.read() for rr in RR.fromZone(i, ttl=self.ttl): self.zone.append((rr.rname, QTYPE[rr.rtype], rr))
def __init__(self, proxy=False, upstream=None): # Prepare the RRs self.rrs = RR.fromZone(LOCALHOST_ZONE) # Set which domain to serve self.domains = set() # Set the upstream DNS server if proxy and upstream: try: self.upstream, self.upstream_port = upstream.split(":") self.upstream_port = int(self.upstream_port) except ValueError: self.upstream = upstream self.upstream_port = 53 finally: self.proxy = True else: self.proxy = False self.lock = threading.Lock()
def resolve(self,request,handler): client_ip = handler.client_address[0] #print "Request from IP: {}".format(client_ip) qname = request.q.qname qtype = QTYPE[request.q.qtype] reply = request.reply() self.log.debug("{} request for {} by {}".format(qtype,qname,client_ip)) #print "query: {}".format(qname) #print "query: {}".format(qname.matchGlob("*.yahoo.com")) # Try to resolve locally unless on skip list rules = self.get_matching_rules(client_ip,qname) self.log.debug("Matched rules: {}".format(rules)) if any(rules): ## Collecting info on match for logging match_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') match_name = client_ip match_hosts = [h.name for h in self.hosts if h.ip == client_ip] if any(match_hosts): match_name = ",".join(match_hosts) for rule in rules: if rule.action == 'monitor': monitor.info({'time':match_time,'match_name':match_name,'client_ip':client_ip,'qname':str(qname)}) if rule.action == 'redirect': self.log.debug( "[{}] REDIRECT {}-->{} to {}".format(match_time,match_name,qname,rule.redirect) ) redir = rule.redirect reply.add_answer(*RR.fromZone("{} 3600 IN A {}".format(qname,redir))) return reply if rule.action == 'block': self.log.debug( "[{}] BLOCKED {}({})-->{}".format(match_time,match_name,client_ip,qname) ) return reply if rule.action == 'allow': self.log.debug( "[{}] ALLOWED {}({})-->{}".format(match_time,match_name,client_ip,qname) ) ## If no match or action == 'allow', then proxy the request to IP_UP if handler.protocol == 'udp': proxy_r = request.send(self.UP_IP,self.UP_PORT) else: proxy_r = request.send(self.UP_IP,self.UP_PORT,tcp=True) reply = DNSRecord.parse(proxy_r) return reply
def resolve(self, request, handler): reply = request.reply() # we handle A queries only if QTYPE[request.q.qtype] == 'A': # filter db for this domain domain = str(request.q.qname).rstrip('.') server = Server.objects.get_for_dns_or_none(domain=domain) if server: # add the answer to the request reply.add_answer(*RR.fromZone( '{domain} {ttl} A {ip}'.format( domain=domain, ttl=300, ip=server.ip ) )) # if there's no anser already, send query upstream if not reply.rr: proxy_r = request.send('8.8.8.8', 53) reply = DNSRecord.parse(proxy_r) return reply
def _resolve(self, request, handler): qname = request.q.qname reply = request.reply() # TODO: # Resolve NS?, DS, SOA somehow if not qname.matchSuffix(self.domain): if self.recursor: try: return DNSRecord.parse(request.send(self.recursor, timeout=2)) except socket.error: pass except Exception as e: logging.exception('DNS request forwarding failed') reply.header.rcode = RCODE.NXDOMAIN return reply responses = [] session = None nonce = None try: request, session, nonce = self._q_page_decoder(qname) if session and session.last_nonce and session.last_qname: if nonce < session.last_nonce: logging.info('Ignore nonce from past: {} < {}'.format( nonce, session.last_nonce)) reply.header.rcode = RCODE.NXDOMAIN return reply elif session.last_nonce == nonce and session.last_qname != qname: logging.info('Last nonce but different qname: {} != {}'.format( session.last_qname, qname)) reply.header.rcode = RCODE.NXDOMAIN return reply for command in Parcel.unpack(request): for response in self._cmd_processor(command, session): responses.append(response) if session: session.last_nonce = nonce session.last_qname = qname except DnsCommandServerException as e: nonce = e.nonce responses = [e.error, Policy(self.interval, self.kex), Poll()] except ParcelInvalidCrc as e: responses = [e.error] except DnsNoCommandServerException: reply.header.rcode = RCODE.NXDOMAIN return reply except DnsPingRequest, e: for i in xrange(e.args[0]): x = (i % 65536) >> 8 y = i % 256 a = RR('.', QTYPE.A, rdata=A('127.0.{}.{}'.format(x, y)), ttl=10) a.rname = qname reply.add_answer(a) return reply
def __init__(self,zone): # Parse RRs self.rrs = RR.fromZone(zone)
def load(self): logging.info("Loading DNS information from cloud providers") self.zone = [(rr.rname,QTYPE[rr.rtype],rr) for rr in RR.fromZone(self.zone_file_generator())]
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()))
def resolve(self, request, handler): reply = request.reply() domain = request.q.qname if request.q.qtype == QTYPE.TXT: #acme server validates dns challenge reply.add_answer( RR(self.TXTrecord_domain, QTYPE.TXT, rdata=TXT(self.TXTrecord_data), ttl=100)) else: reply.add_answer( RR(domain, QTYPE.A, rdata=A(self.address), ttl=100)) #print("DNS SERVER REPLY: ",reply) return reply