def send_request(self, ip, name): #create socket and request sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.settimeout(self.timeout) question = Question(name, Type.A, Class.IN) header = Header(9001, 0, 1, 0, 0, 0) header.qr = 0 header.opcode = 0 header.rd = self.rd query = Message(header, [question]) sock.sendto(query.to_bytes(), (ip, 53)) # Receive response data = sock.recv(512) sock.close() response = Message.from_bytes(data) self.logHeader(response.header) if self.caching: for r in response.resources: if r.type_ == Type.A or r.type_ == Type.CNAME or r.type_ == Type.NS: self.cache.add_record(r) return response.answers, response.authorities, response.additionals
def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) question = Question(Name("google.com."), Type.A, Class.IN) header = Header(9001, 0, 1, 0, 0, 0) header.qr = 0 # 0 for query header.opcode = 0 # standad query header.rd = 1 # recursive query = Message(header, [question]) ip = (([ ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.") ] or [[(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) + ["no IP found"])[0] sock.sendto(query.to_bytes(), (ip, 53)) data = sock.recv(1024) mess = Message.from_bytes(data) """ answer = ResourceRecord.to_dict(mess.answers[0]) auth = ResourceRecord.to_dict(mess.authorities[0]) addi = ResourceRecord.to_dict(mess.additionals[0]) """ rrs = [] rrs += mess.answers + mess.authorities + mess.additionals for r in rrs: print("R", r.to_dict())
def build_message(self,id, rd, aa, rcode, questions, answers, authorities, additionals): header = Header(id, 0, len(questions), len(answers), len(authorities), len(additionals)) header.qr = 1 header.opcode = 0 header.rd = rd header.ra = 1 header.aa = aa header.rcode = rcode return Message(header, questions=questions, answers=answers, authorities=authorities, additionals=additionals)
def test_concurrent_requests(self): queries = [] answers = [] question = Question(Name("gaia.cs.umass.edu"), Type.A, Class.IN) header = Header(1337, 0, 1, 0, 0, 0) header.rd = 1 queries.append(Message(header, questions=[question])) answers.append([ ResourceRecord(name=Name("gaia.cs.umass.edu"), type_=Type.A, class_=Class.IN, ttl=0, rdata=ARecordData("128.119.245.12")), ]) question = Question(Name("server2.gumpe"), Type.A, Class.IN) header = Header(420, 0, 1, 0, 0, 0) queries.append(Message(header, questions=[question])) answers.append([ ResourceRecord(name=Name("server2.gumpe"), type_=Type.A, class_=Class.IN, ttl=0, rdata=ARecordData("10.0.1.7")), ]) header = Header(69, 0, 1, 0, 0, 0) question = Question(Name("www.gumpe"), Type.A, Class.IN) queries.append(Message(header, questions=[question])) answers.append([ ResourceRecord(name=Name("www.gumpe"), type_=Type.A, class_=Class.IN, ttl=0, rdata=ARecordData("10.0.1.7")), ResourceRecord(name=Name("www.gumpe"), type_=Type.CNAME, class_=Class.IN, ttl=0, rdata=CNAMERecordData(Name("server2.gumpe"))), ]) sockets = [ socket.socket(socket.AF_INET, socket.SOCK_DGRAM) for _ in range(len(queries)) ] for i in range(len(sockets)): sockets[i].sendto(queries[i].to_bytes(), (SERVER, PORT)) responses = [] for i in range(len(sockets)): responses.append(Message.from_bytes(sockets[i].recv(1024))) for i in range(len(sockets)): sockets[i].close() for i in range(len(queries)): self.assertCountEqual(responses[i].answers, answers[i])
def send_query(sock, hostname, ip): # Create and send query question = Question(Name(hostname), Type.A, Class.IN) header = Header(randint(0, 2**16), 0, 1, 0, 0, 0) header.qr = 0 header.opcode = 0 header.rd = 0 # no recursion desired query = Message(header, [question]) sock.sendto(query.to_bytes(), (ip, 53)) # Receive response data = sock.recv(512) return Message.from_bytes(data)
def send_response(self, records, authoritative, error=0): """Send a response to some message.""" if not error and len(records) == 0: error = 3 # NXDOMAIN (Domain Name not found) if error != 0: header = Header(self.message.header.ident, 0, 0, 0, 0, 0) header.rcode = error else: header = Header(self.message.header.ident, 0, 0, len(records), 0, 0) header.aa = authoritative # Authoritative Answer header.qr = 1 # Message is Response header.rd = self.message.header.rd # Recursion desired header.ra = 1 # Recursion Available response = Message(header, answers=records) self.sock.sendto(response.to_bytes(), self.address)
def test_outside_zone(self): question = Question(Name("gaia.cs.umass.edu"), Type.A, Class.IN) header = Header(1337, 0, 1, 0, 0, 0) header.rd = 1 query = Message(header, questions=[question]) s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.sendto(query.to_bytes(), (SERVER, PORT)) data = s.recv(512) s.close() message = Message.from_bytes(data) self.assertEqual(message.answers, [ ResourceRecord(name=Name("gaia.cs.umass.edu"), type_=Type.A, class_=Class.IN, ttl=0, rdata=ARecordData("128.119.245.12")), ])
def sendQuestion(self, hostname, server): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.settimeout(self.timeout) # Create and send query identifier = 9001 # placeholder question = Question(Name(hostname), Type.A, Class.IN) header = Header(identifier, 0, 1, 0, 0, 0) header.qr = 0 header.opcode = 0 header.rd = 1 query = Message(header, [question]) sock.sendto(query.to_bytes(), (server, 53)) # Receive response data = sock.recv(512) response = Message.from_bytes(data) sock.close() return response
def send_query(self, hostname, port): question = Question(Name(hostname), Type.A, Class.IN) # use port as id header = Header(port, 0, 1, 0, 0, 0) header.qr = 0 # 0 for query header.opcode = 0 # standad query header.rd = 1 # recursive query = Message(header, [question]) ip = (([ ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.") ] or [[(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)] ][0][1]]) + ["no IP found"])[0] sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((ip, port)) print("Sock Test:", sock) sock.sendto(query.to_bytes(), (ip, PORT)) data = sock.recv(1024) sock.close() return data
def test_flags_rd(self): header = Header(0, 0, 0, 0, 0, 0) header.rd = 1 self.assertEqual(header.flags, 1 << 8)
def test_rd(self): header = Header(0, 0, 0, 0, 0, 0) header.rd = 1 self.assertEqual(header.rd, 1)
def gethostbyname(self, hostname, dnsserv='192.112.36.4'): """Translate a host name to IPv4 address. Currently this method contains an example. You will have to replace this example with the algorithm described in section 5.3.3 in RFC 1034. Args: hostname (str): the hostname to resolve Returns: (str, [str], [str]): (hostname, aliaslist, ipaddrlist) """ ipaddrlist = [] cnames = [] temp = [] if (self.caching): rcache = RecordCache(self.ttl) rcord = rcache.lookup(hostname, Type.ANY, Class.IN) if (rcord): for rec in rcord: if rec.type_ == Type.A: arec = rec.rdata ipaddrlist.append(arec.address) elif rec.type_ == Type.CNAME: crec = rec.rdata cnames.append(crec.cname) if ipaddrlist: return hostname, cnames, ipaddrlist elif cnames: return self.gethostbyname(cnames[0], dnsserv) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.settimeout(self.timeout) # Create and send query question = Question(Name(str(hostname)), Type.A, Class.IN) header = Header(9001, 0, 1, 0, 0, 0) header.qr = 0 header.opcode = 0 header.rd = 1 query = Message(header, [question]) sock.sendto(query.to_bytes(), (str(dnsserv), 53)) # Receive response data = sock.recv(2048) response = Message.from_bytes(data) print("Number of answers: " + str(len(response.answers))) print("Number of authorities: " + str(len(response.authorities))) print("Number of additionals: " + str(len(response.additionals))) # Get data aliaslist = cnames ipaddrlist = [] dnslist = [] while response.answers: for answer in response.answers: if answer.type_ == Type.A: print("found A RR") if (self.caching): rcache.add_record(answer) ipaddrlist.append(answer.rdata.address) if answer.type_ == Type.CNAME: aliaslist.append(answer.rdata.cname) if answer.type_ == Type.NS: dnslist.append(answer.rdata.nsdname) if ipaddrlist: return hostname, aliaslist, ipaddrlist elif aliaslist: question = Question(Name(aliaslist[0]), Type.A, Class.IN) query = Message(header, [question]) sock.sendto(query.to_bytes(), (dnsserv, 53)) data = sock.recv(2048) response = Message.from_bytes(data) elif dnslist: nsname = dnslist.pop() maybe_dnsserv = self.getnsaddr(nsname, response.additionals) if maybe_dnsserv: dnsserv = maybe_dnsserv else: pass sock.sendto(query.to_bytes(), (dnsserv, 53)) data = sock.recv(2048) response = Message.from_bytes(data) else: break if response.authorities: for authority in response.authorities: if authority.type_ != Type.NS: pass dnslist.append(authority.rdata.nsdname) while dnslist: nsname = dnslist.pop() maybe_next_dnsserv = self.getnsaddr(nsname, response.additionals) if maybe_next_dnsserv: next_dns_serv = maybe_next_dnsserv else: pass (hname, aliasl, ipaddrl) = self.gethostbyname(hostname, nsname) if ipaddrl: return hname, aliasl, ipaddrl
def gethostbyname(self, hostname): """Translate a host name to IPv4 address. Currently this method contains an example. You will have to replace this example with the algorithm described in section 5.3.3 in RFC 1034. Args: hostname (str): the hostname to resolve Returns: (str, [str], [str]): (hostname, aliaslist, ipaddrlist) """ alias_list = [] a_list = [] slist = [] found = False acs = self.getRecordsFromCache(hostname, Type.A, Class.IN) if acs: a_list += acs return hostname, alias_list, a_list nscs = self.matchByLabel(hostname, Type.NS, Class.IN) for ns in nscs: glue = self.getRecordsFromCache(str(ns.rdata.nsdname)) if glue: slist += glue else: slist += [ns] id = self._make_id() # Create and send query question = Question(Name(hostname), Type.A, Class.IN) header = Header(id, 0, 1, 0, 0, 0) header.qr = 0 # 0 for query header.opcode = 0 # standad query header.rd = 0 # not recursive query = Message(header, [question]) self.zone.read_master_file('dns/root.zone') sbelt = [] for root in list(self.zone.records.values()): sbelt += [r for r in root if r.type_ == Type.A] while not found: if slist: rr = slist.pop() if rr.type_ == Type.A: addr = rr.rdata.address self.sock.send((query, addr, 53)) elif rr.type_ == Type.NS: fqdn = str(rr.rdata.nsdname) _, _, a_rrs = self.gethostbyname(fqdn) slist += a_rrs continue elif rr.type_ == Type.CNAME: fqdn = str(rr.rdata.cname) _, cname_rrs, a_rrs = self.gethostbyname(fqdn) a_list += a_rrs alias_list += cname_rrs break elif sbelt: rr = sbelt.pop() addr = rr.rdata.address self.sock.send((query, addr, 53)) else: break # Receive response data = None while not data: data = self.sock.msgThere(id) response, _ = data[0] #response = Message.from_bytes(data) for answer in response.answers: if answer.type_ == Type.A: self.addRecordToCache(answer) a_list.append(answer) found = True if answer.type_ == Type.CNAME: self.addRecordToCache(answer) alias_list.append(answer) slist += [answer] continue nss = [] for auth in response.authorities: if auth.type_ == Type.NS: nss.append(auth) self.addRecordToCache(auth) a_add = {} for add in response.additionals: if add.type_ == Type.A: name = str(add.name) a_add[name] = add self.addRecordToCache(add) for ns in nss: name = str(ns.rdata.nsdname) if name in a_add: slist += [a_add[name]] else: slist += [ns] return hostname, alias_list, a_list
def handle_request(self): """ Attempts to answer the received query """ #Check this next to the given algorithm #print("Catalog:",self.catalog.zones) #for zone in self.catalog.zones: # print("Records:",self.catalog.zones[zone].records) if self.message.header.opcode != 0: #Send a not implemented error, we don't need to support those kinds of queries print("[-] - Received a nonstandard query. This is unsupported.") header = Header(ident, 0, 1, 0, 0, 0) header.qr = 1 header.rd = self.message.header.rd header.ra = 1 header.rcode = 4 self.sendResponse(Message(header, self.message.questions, [])) return #print("[*] - Handling request.") if len(self.message.questions) != 1: #Send a format error response print("[-] - Invalid request.") header = Header(ident, 0, 1, 0, 0, 0) header.qr = 1 header.rd = self.message.header.rd header.ra = 1 header.rcode = 1 self.sendResponse(Message(header, self.message.questions, [])) return #print("MSG:",self.message) #print("RECEIVED QUESTION",self.message.questions[0]) hname = str(self.message.questions[0].qname) #print("Solving",hname,type(hname)) ident = self.message.header.ident #print("Checking zone") answer, authority, found = self.check_zone(hname) #print("Wat we in de zone hebben gevonden") #print("ANS:",answer,"AUTH:",authority,"FOUND:",found) #found = False if found: print("Found in zone") header = Header(ident, 0, 1, len(answer), len(authority), 0) header.qr = 1 header.aa = 1 header.rd = self.message.header.rd header.ra = 1 self.sendResponse( Message(header, self.message.questions, answer, authority)) elif self.message.header.rd == 1: h, al, ad = self.resolver.gethostbyname(hname) #Make and send th appropriate response header = Header(ident, 0, 1, len(al) + len(ad), 0, 0) header.qr = 1 header.rd = self.message.header.rd header.ra = 1 aliases = [ ResourceRecord(Name(h), Type.CNAME, Class.IN, self.ttl, RecordData.create(Type.CNAME, Name(alias))) for alias in al ] addresses = [ ResourceRecord(Name(h), Type.A, Class.IN, self.ttl, RecordData.create(Type.A, address)) for address in ad ] self.sendResponse( Message(header, self.message.questions, aliases + addresses)) else: #Send an empty response header = Header(ident, 0, 1, 0, 0, 0) header.qr = 1 header.rd = self.message.header.rd header.ra = 1 header.rcode = 0 self.sendResponse(Message(header, self.message.questions, []))
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