class Scanner: """scan bytes""" __mark_offset_byte, __mark_offset_bit (): self.data = data self.__offset_byte = offset_byte self.__offset_bit = offset_bit def next_bits(self, n=1): .__offset_bit: raise RuntimeError('剩余数据不足{}位'.format(n)) .__offset_bit: raise RuntimeError('不能跨字节读取读取位') result .__offset_bit .__offset_bit += n : .__offset_byte result , move=True): .__offset_bit == 0: raise RuntimeError('当前字节不完整,请先读取完当前字节的所有位') .__offset_byte: raise RuntimeError('剩余数据不足{}字节'.format(n)) result = self.data[self.__offset_byte: self.__offset_byte + n] if move: self.__offset_byte += n if convert: result = int.from_bytes(result, 'big') return result def next_bytes_until(self, stop, convert=True): .__offset_bit == 0: raise RuntimeError('当前字节不完整,请先读取完当前字节的所有位') end = self.__offset_byte .__offset_byte): end += 1 result = self.data[self.__offset_byte: end] self.__offset_byte = end if convert: if result: result ) else x + y, ) else '.', result)) else: result result
然后需要做的是当收到114 DNS服务器的响应消息后,将消息缓存起来:
# 缓存响应结果 message = Message.from_bytes(response_data) message.save()
以上save方法就是将message中包含的各条RR保存起来,可以直接用一个集合来保存,也可以保存在一些专业的缓存设施中,比如redis。需要注意的是TTL的处理,若用redis缓存,它自带了TTL功能,可以直接使用。若是自己实现的,需要在保存的时候记录当前的时间,以便取出的时候能够判断是否过期。这些应该很容易实现,但是本人比较懒,这里就不写了……
4.3 添加记录功能最后,它需要具备能够读取我们自定义的记录,并将记录加入缓存。。这个也不想写了……
另外,Message类还应该有一个to_bytes方法,它能将一个Message对象转换为bytes对象,用于将 从缓存中取出的数据(即RR记录)转换为bytes,返回给用户。这个其实就是from_bytes的逆过程,但实现起来应该比from_bytes简单许多,因为你可以不使用指针来压缩数据,这样处理起来就没什么难度了。同样不想写了……
最后稍微做一下测试,算是做个结束:
: server = Server('172.16.42.254') server.start()
使用nsloop发送DNS请求到我们自己写的服务器上,响应结果如下:
$ nslookup api.sina.com.cn 172.16.42.254 Server: 172.16.42.254 Address: 172.16.42.254#53 Non-authoritative answer: api.sina.com.cn canonical name = common6.dpool.sina.com.cn. Name: common6.dpool.sina.com.cn Address: 123.126.56.253