def read_cache_file(self, cache_file=Consts.CACHE_FILE): """ Read the cache file from disk """ #Empty current cache self.records = [] #Load from file try: with open(cache_file + ".timestamp") as infile: self.lastCleanup = int(infile.readline()) with open(cache_file, "r") as infile: curTime = int(time.time()) dcts = json.load(infile) self.records = [ResourceRecord.from_dict(dct) for dct in dcts] #Don't add the entries whose TTL is expired and update the ttls self.cleanup() except (ValueError, IOError, FileNotFoundError) as e: print("An error has occured while loading cache from disk: " + str(e)) with open(cache_file, 'w') as outfile: json.dump([], outfile, indent=2) with open(cache_file + ".timestamp", 'w') as outfile: outfile.write(str(self.lastCleanup)) if isinstance(e, FileNotFoundError): print("Missing files were created") self.records = []
def read_cache_file(self): """Read the cache file from disk""" dcts = [] try: with open("cache", "r") as file_: dcts = json.load(file_) except: print("could not read cache") self.records = [ResourceRecord.from_dict(dct) for dct in dcts]
def read_master_file(self, filename): """Read the zone from a master file See section 5 of RFC 1035. Args: filename (str): the filename of the master file """ typeData = {"NS": "nsdname", "A": "address", "CNAME": "cname"} try: with open(filename, "r") as file_: for l in file_: rr = l.split(";")[0] if not rr: continue entries = re.split("[\\n]?[\ +]*[\\t+]*", rr)[:-1] name = entries[0] ttl = int(entries[1]) type_ = entries[2] address = entries[3] if type_ not in typeData: continue rr = { "type": type_, "name": name, "class": "IN", "ttl": ttl, "rdata": { typeData[type_]: address } } if name not in self.records: self.records[name] = [ResourceRecord.from_dict(rr)] else: self.records[name].append(ResourceRecord.from_dict(rr)) except: print("could not read zone file") return self
def lookup(self, dname, type_, class_): """Lookup resource records in cache Lookup for the resource records for a domain name with a specific type and class. Args: dname (str): domain name type_ (Type): type class_ (Class): class """ dname = Name(dname) rrs = [ ResourceRecord.from_dict(r) for r in self.records if (time.time() - r["timestamp"]) < r["ttl"] ] rs = [ r for r in rrs if r.name == dname and r.class_ == class_ and r.type_ == type_ ] return rs
def run(self): """ Run the handler thread""" msg = Message.from_bytes(self.data) header = msg.header recursion = header.rd != 0 questions = msg.questions answers = [] authorative = [] additional = [] for question in questions: qname = question.qname qtype = question.qtype if question.qclass != Class.IN: pass domains = self.getdomains(str(qname)) for domain in domains: if not self.zone.records.get(domain, False): continue for rr in self.zone.records[domain]: if (rr.type_ == Type.A or rr.type_ == Type.CNAME) and domain == str(qname): answers.append(rr) if rr.type_ == Type.NS: authorative.append(rr) for rec in self.zone.records[str(rr.rdata.nsdname)]: if rec not in additional: if rec.qtype == Type.A: additional.append(rec) if authorative or answers: header_response = Header(9001, 0, 1, len(answers), len(authorative), len(additionals)) header_response.qr = True header_response.opcode(1) header_response.aa(False) header_respones.tc(False) header_response.rd(False) header_response.ra(True) header_response.z(False) header_respones.rcode(False) respons = Message(header_response, [question], answers, authorities, additionals) self.sock.sendto(respons.to_bytes(), self.addr) break if recursion and (qtype == Type.A or qtype == Type.CNAME): answers = [] resolver = Resolver(100, False, 0, True) (hostname, aliaslist, ipaddrlist) = resolver.gethostbyname(question.qname) header_response = Header(9001, 0, 1, len(aliaslist) + len(ipaddrlist), 0, 0) header_response.qr = 1 header_response.opcode = 1 header_response.aa = 0 header_response.tc = 0 header_response.rd = 0 header_response.ra = 1 header_response.rcode = 0 for addr in ipaddrlist: answers.append( ResourceRecord.from_dict({ "name": str(hostname), "type": str(Type.A), "class": str(Class.IN), "ttl": 0, "rdata": { "address": str(addr) } })) for alias in aliaslist: answers.append( ResourceRecord.from_dict({ "name": str(hostname), "type": str(Type.CNAME), "class": str(Class.IN), "ttl": 0, "rdata": { "cname": str(alias) } })) response = Message(header_response, questions, answers) self.sock.sendto(response.to_bytes(), self.addr) break