Netty提供了丰富的编解码器方便了网络应用开发,我们可以基于Netty提供的DNS编解码器来做内网的DNS解析同时也能代理公网的域名解析,我们将来不再需要本地HOST文件来维护内网的域名解析处理。
1、DNS代理实现处理流程
我们通过对本地DNS(A记录)请求的拦截直接返回DNS响应结果,如果未在本地DNS做解析处理那么将请求转发给公网DNS服务做解析,在做DNS代理时我们处理DNS请求时需要将本地发起的DNS RequestId设置到DNS请求中,这样操作相当于实现了从本地发起DNS解析的请求。
sequenceDiagram
DNS解析请求->>DNSServer: DNS解析请求(A记录)
DNSServer ->> DNSServer : 本地解析记录存在返回
DNSServer->>DNS解析请求: 本地DNS(A记录响应)
DNSServer ->> DNSRemoteServer : 公网DNS(A记录)请求
DNSRemoteServer ->> DNSRemoteServer : 公网DNS请求响应
DNSRemoteServer ->> DNSServer : 公网DNS请求响应
DNSServer ->> DNS解析请求 : DNS响应
DNS请求判断处理
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramDnsQuery query) throws Exception {
this.dnsProxy.setClientSender(query.sender());
this.dnsProxy.setClientRecipient(query.recipient());
DefaultDnsQuestion dnsQuestion = query.recordAt(DnsSection.QUESTION);
log.info("查询的域名:{},ID:{}",dnsQuestion.name(),query.id());
ILocalDnsService localDnsService=SpringUtil.getBean(ILocalDnsService.class);
byte[] dnsRecord=localDnsService.dnsResolver(dnsQuestion.name(),query.recipient().getAddress().getHostAddress());
if(dnsRecord[0]!=0){
DatagramDnsResponse response = new DatagramDnsResponse(query.recipient(), query.sender(), query.id());
response.setId(query.id());
response.addRecord(DnsSection.QUESTION, dnsQuestion);
ByteBuf buf=ctx.channel().alloc().buffer().writeBytes(dnsRecord);
DefaultDnsRawRecord queryAnswer = new DefaultDnsRawRecord(dnsQuestion.name(), DnsRecordType.A, 10, buf);
response.addRecord(DnsSection.ANSWER, queryAnswer);
ctx.writeAndFlush(response);
}else{
this.dnsProxy.sendDnsQuery(query);
}
}
DNS转发RemoteServer处理
处理过程也相当简单只是将DatagramDnsResponse重新封装成客户端返回的DatagramDnsResponse即可。
protected void channelRead0(ChannelHandlerContext channelHandlerContext, DatagramDnsResponse response) throws Exception{
if(this.clientChannel!=null){
DatagramDnsResponse newResponse = new DatagramDnsResponse(dnsProxy.getClientRecipient(),dnsProxy.getClientSender(), response.id());
for(int i=0;i<response.count(DnsSection.QUESTION);i++){
try{
DnsRecord dnsRecord=response.recordAt(DnsSection.QUESTION,i);
newResponse.addRecord(DnsSection.QUESTION,dnsRecord);
}catch (Exception e){
break;
}
}
for(int i=0;i<response.count(DnsSection.ANSWER);i++){
try{
DnsRecord dnsRecord=response.recordAt(DnsSection.ANSWER,i);
newResponse.addRecord(DnsSection.ANSWER,dnsRecord);
}catch (Exception e){
break;
}
}
for(int i=0;i<response.count(DnsSection.AUTHORITY);i++){
try{
DnsRecord dnsRecord=response.recordAt(DnsSection.AUTHORITY,i);
newResponse.addRecord(DnsSection.AUTHORITY,dnsRecord);
}catch (Exception e){
break;
}
}
this.clientChannel.writeAndFlush(newResponse);
}
}
DNS代理本地测试方式
测试本地域名解析
nslookup -query=a www.test123.com DNS服务IP
测试远程域名解析
nslookup -query=a www.baidu.com DNS服务IP