def from_bytes(cls, packet, offset): """Convert ResourceRecord from bytes.""" name, offset = Name.from_bytes(packet, offset) type_ = Type(struct.unpack_from("!H", packet, offset)[0]) class_ = Class(struct.unpack_from("!H", packet, offset + 2)[0]) ttl, rdlength = struct.unpack_from("!iH", packet, offset + 4) offset += 10 rdata = RecordData.create_from_bytes(type_, packet, offset, rdlength) offset += rdlength return cls(name, type_, class_, ttl, rdata), offset
def default(self, obj): if isinstance(obj, ResourceRecord): return { "name": obj.name, "type": Type.to_string(obj.type_), "class": Class.to_string(obj.class_), "ttl": obj.ttl, "rdata": obj.rdata.data } return json.JSONEncoder.default(self, obj)
def default(self, obj): if isinstance(obj, ResourceRecord): return { "name": obj.name, "type": Type.to_string(obj.type_), "class": Class.to_string(obj.class_), "ttl": obj.ttl, "rdata": obj.rdata.data, "time": obj.time } return json.JSONEncoder.default(self, obj)
def resource_from_json(dct): """ Convert JSON object to ResourceRecord Usage: records = json.loads(string, object_hook=resource_from_json) """ name = dct["name"] type_ = Type.from_string(dct["type"]) class_ = Class.from_string(dct["class"]) ttl = dct["ttl"] rdata = RecordData.create(type_, dct["rdata"]) return ResourceRecord(name, type_, class_, ttl, rdata)
def resource_from_json(dct): """ Convert JSON object to ResourceRecord Usage: records = json.loads(string, object_hook=resource_from_json) """ name = dct["name"] type_ = Type.from_string(dct["type"]) class_ = Class.from_string(dct["class"]) ttl = dct["ttl"] rdata = RecordData.create(type_, dct["rdata"]) t = dct["time"] return ResourceRecord(name, type_, class_, ttl, rdata, t)
def test_single_lookup(self): """Ask for a single existing hostname""" dnsID = randint(0, 65535) header = dns.message.Header(dnsID, 0, 1, 0, 0, 0) header.qr = 0 header.opcode = 0 header.aa = 0 header.tc = 0 header.rd = 1 header.ra = 0 header.z = 0 header.rcode = 0 qname = "www.funnygames.com" qtype = Type.ANY # request for all records qclass = Class.IN # ANY question = dns.message.Question(qname, qtype, qclass) request = dns.message.Message(header, [question], [], [], []) requestByte = request.to_bytes() self.client_socket.sendto(requestByte, (server, portnr)) print Type.to_string(question.qtype) + Class.to_string(question.qclass) responseData = self.client_socket.recv(512) response = dns.message.Message.from_bytes(responseData) self.assertNotEquals(response.answers, [])
def add_record(self, record): """ Add a new Record to the cache Args: record (ResourceRecord): the record added to the cache """ if record.ttl == 0: raise CacheException( 'RRs with a ttl of 0 may not be cached') # see rfc 1035 p.11 elif record.ttl < 0: raise CacheException('ttl smaller than 0') elif record.type_ not in [Type.A, Type.CNAME, Type.NS]: raise CacheException( 'Only A, CNAME and NS-Resource Records may be cached, actual type is ' + Type.to_string(record.type_)) self.records = set([ r for r in self.records if not ( r.name == record.name and r.rdata.data == record.rdata.data) ]) self.records.add(record)
def from_bytes(cls, packet, offset): """Convert Question from bytes.""" qname, offset = Name.from_bytes(packet, offset) qtype = Type(struct.unpack_from("!H", packet, offset)[0]) qclass = Class(struct.unpack_from("!H", packet, offset + 2)[0]) return cls(qname, qtype, qclass), offset + 4
def add_record(self, record): """ Add a new Record to the cache Args: record (ResourceRecord): the record added to the cache """ if record.ttl == 0: raise CacheException('RRs with a ttl of 0 may not be cached') # see rfc 1035 p.11 elif record.ttl < 0: raise CacheException('ttl smaller than 0') elif record.type_ not in [Type.A, Type.CNAME, Type.NS]: raise CacheException('Only A, CNAME and NS-Resource Records may be cached, actual type is ' + Type.to_string(record.type_)) self.records = set([r for r in self.records if not (r.name == record.name and r.rdata.data == record.rdata.data)]) self.records.add(record)
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 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) """ if self.caching: #self.cache.update() This was meant for TTL but it ended up not working. alternatives = self.cache.lookup(hostname, Type.CNAME, Class.IN) ips = self.cache.lookup(hostname, Type.A, Class.IN) if ips is not None: print("pulled from cache:") return hostname, alternatives, [ips.rdata.data] # Rootservers hints = [ '198.41.0.4', '192.228.79.201', '192.33.4.12', '199.7.91.13', '192.203.230.10', '192.5.5.241', '192.112.36.4', '198.97.190.53', '192.36.148.17', '192.58.128.30', '193.0.14.129', '199.7.83.42', '202.12.27.33' ] timeout = 2 # Time waited for a response sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.settimeout(timeout) # Create query question = dns.message.Question(hostname, Type.ANY, Class.IN) header = dns.message.Header(9001, 0, 1, 0, 0, 0) header.qr = 0 header.opcode = 0 header.rd = 0 query = dns.message.Message(header, [question]) targetfound = False hintindex = 0 while hintindex < len(hints) and not targetfound: currenthint = hints[hintindex] try: # Send query sock.sendto(query.to_bytes(), (currenthint, 53)) # Receive response data = sock.recv(512) response = dns.message.Message.from_bytes(data) if response is not None: if self.caching: for record in response.answers + response.authorities + response.additionals: self.cache.add_record(record) print "\nanswers:" for answer in response.answers: if answer.type_ in [1,2,5]: print Type.to_string(answer.type_) print answer.name print answer.rdata.data print "Answer found.\n" targetfound = True print "\nauthorities:" for authority in response.authorities: if authority.type_ in [1,2,5]: print Type.to_string(authority.type_) print authority.name print authority.rdata.data print "\nadditionals:" for additional in response.additionals: if additional.type_ in [1,2,5]: print Type.to_string(additional.type_) print additional.name print additional.rdata.data if additional.rdata.data is not None and additional.rdata.data not in hints: hints.append(additional.rdata.data) except socket.timeout: print "Server timed out" hintindex += 1 if self.caching: self.cache.write_cache_file() if targetfound: # Get data aliases = [] for additional in response.additionals: if additional.type_ == Type.CNAME: aliases.append(additional.rdata.data) addresses = [] for answer in response.answers: if answer.type_ == Type.A: addresses.append(answer.rdata.data) return hostname, aliases, addresses return hostname, [], []