decode接受一个ByteBuf对象,首先调用LengthFieldBasedFrameDecoder的decode方法,将真正需要解析的内容解析出来,然后再调用DnsMessageUtil的decodeDnsQuery方法将真正的ByteBuf内容解码成为DnsQuery返回 。
这样就可以在自定义的handler中处理DnsQuery消息了 。
上面代码中,自定义的handler叫做Do53ServerInboundHandler:
class Do53ServerInboundHandler extends SimpleChannelInboundHandler<DnsQuery>从定义看 , Do53ServerInboundHandler要处理的消息就是DnsQuery 。
看一下它的channelRead0方法:
protected void channelRead0(ChannelHandlerContext ctx, DnsQuery msg) throws Exception { DnsQuestion question = msg.recordAt(DnsSection.QUESTION); log.info("Query is: {}", question); ctx.writeAndFlush(newResponse(msg, question, 1000, QUERY_RESULT)); }我们从DnsQuery的QUESTION section中拿到DnsQuestion,然后解析DnsQuestion的内容,根据DnsQuestion的内容返回一个response给客户端 。
这里的respone是我们自定义的:
private DefaultDnsResponse newResponse(DnsQuery query, DnsQuestion question, long ttl, byte[]... addresses) { DefaultDnsResponse response = new DefaultDnsResponse(query.id()); response.addRecord(DnsSection.QUESTION, question); for (byte[] address : addresses) { DefaultDnsRawRecord queryAnswer = new DefaultDnsRawRecord( question.name(), DnsRecordType.A, ttl, Unpooled.wrappedBuffer(address)); response.addRecord(DnsSection.ANSWER, queryAnswer); } return response; }上面的代码封装了一个新的DefaultDnsResponse对象,并使用query的id作为DefaultDnsResponse的id 。并将question作为response的QUESEION section 。
除了QUESTION section,response中还需要ANSWER section,这个ANSWER section需要填充一个DnsRecord 。
这里构造了一个DefaultDnsRawRecord,传入了record的name,type , ttl和具体内容 。
最后将构建好的DefaultDnsResponse返回 。
因为客户端查询的是A address,按道理我们需要通过QUESTION中传入的domain名字,然后根据DNS服务器中存储的记录进行查找,最终返回对应域名的IP地址 。
但是因为我们只是模拟的DNS服务器,所以并没有真实的域名IP记录,所以这里我们伪造了一个ip地址:
private static final byte[] QUERY_RESULT = new byte[]{46, 53, 107, 110};然后调用Unpooled的wrappedBuffer方法,将byte数组转换成为ByteBuf,传入DefaultDnsRawRecord的构造函数中 。
这样我们的DNS服务器就搭建好了 。
DNS客户端消息请求上面我们搭建好了DNS服务器 , 接下来就可以使用DNS客户端来请求DNS服务器了 。
这里我们使用之前创建好的netty DNS客户端,只不过进行少许改动 , 将DNS服务器的域名和IP地址替换成下面的值:
Do53TcpClient client = new Do53TcpClient(); final String dnsServer = "127.0.0.1"; final int dnsPort = 53; final String queryDomain ="www.flydean.com"; client.startDnsClient(dnsServer,dnsPort,queryDomain);
推荐阅读
- MySQL该使用哪种CPU架构服务器?
- Pwn学习随笔
- 手记系列之三 ----- 关于使用Nginx的一些使用方法和经验
- Day10:for循环结构的使用详解
- Re:从零开始教你使用 Sublime Text
- 我的世界漏斗矿车怎么用(漏斗矿车如何使用)
- kafka-consumer-groups 命令行工具使用手册
- 二十四 设计模式学习:Spring 中使用到的设计模式
- 3 onps栈使用说明——tcp、udp通讯测试
- 云原生之旅 - 10)手把手教你安装 Jenkins on Kubernetes