2017-10-07 61 views
2

我一直在尝试使用netty编写自定义DNS服务器。我已经使用DatagramDnsQueryDecoder解析传入的DNSQuery UDP数据包,但我无法弄清楚如何发送响应来解析域名。我已收到处理程序的DatagramDnsQuery对象,但找不到初始化DatagramDnsResponse并添加测试DNS记录并通过DatagramDnsResponseEncoder将其发送回客户端的方法。使用Netty的自定义DNS服务器

这是我迄今

public class DNSListen { 
public static void main(String[] args) { 
    final NioEventLoopGroup group = new NioEventLoopGroup(); 

    try { 
     Bootstrap bootstrap = new Bootstrap(); 
     bootstrap.group(group) 
       .channel(NioDatagramChannel.class) 
       .handler(new ChannelInitializer<NioDatagramChannel>() { 
        @Override 
        protected void initChannel(NioDatagramChannel nioDatagramChannel) throws Exception { 
         nioDatagramChannel.pipeline().addLast(new DatagramDnsQueryDecoder()); 
         nioDatagramChannel.pipeline().addLast(new DatagramDnsResponseEncoder()); 
         nioDatagramChannel.pipeline().addLast(new DNSMessageHandler()); 
        } 
       }) 
       .option(ChannelOption.SO_BROADCAST, true); 

     ChannelFuture future = bootstrap.bind(53).sync(); 
     future.channel().closeFuture().sync(); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } finally { 
     group.shutdownGracefully(); 
    } 

} 
} 

这里做的是,DNSMessages

public class DNSMessageHandler extends SimpleChannelInboundHandler<DatagramDnsQuery> { 

@Override 
protected void channelRead0(ChannelHandlerContext ctx, DatagramDnsQuery dnsMessage) throws Exception { 
    System.out.println(dnsMessage.content()); 
} 

@Override 
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 
    cause.printStackTrace(); 
} 
} 

我得到了多个DNS请求输出,当我运行这一点,并设置系统DNS的处理程序127.0.0.1 但我无法找到发送虚拟DNS响应的方式,以便为请求的域解析IP地址。 (我认为我应该初始化一个DatagramDnsResponse对象并将它写回给用户,但这是否正确?如果是的话,我如何使用伪IP将其初始化为已解析的IP) 我是否在错误的路径中,有人可以请指引我走向正确的道路。谢谢。

+0

不可能说你是否正确。你没有显示你做了什么。 http://idownvotedbecau.se/nocode/ – blafasel

+0

我已经添加了我迄今为止所做的,并进一步解释。谢谢。 –

回答

1

这很容易,你只需要一个DatagramDnsResponse的实例,并用addRecord方法添加一个dns记录即可。

这里用于SRV回答的例子:

DatagramDnsResponse response = new DatagramDnsResponse(msg.recipient(), msg.sender(), msg.id()); 
ByteBuf buf = Unpooled.buffer(); 
buf.writeShort(0); // priority 
buf.writeShort(0); // weight 
buf.writeShort(993); // port 
encodeName("my.domain.tld", buf); // target (special encoding: https://tools.ietf.org/html/rfc1101) 
response.addRecord(DnsSection.ANSWER, new DefaultDnsRawRecord("_myprotocol._tcp.domain.tld." /* requested domain */, DnsRecordType.SRV, 30 /* ttl */ , buf)); 
ctx.writeAndFlush(response); 

编辑

为了编码名称使用此函数(I萃取它从网状):

public void encodeName(String name, ByteBuf buf) throws Exception { 
    if(".".equals(name)) { 
     buf.writeByte(0); 
     return; 
    } 

    final String[] labels = name.split("\\."); 
    for (String label : labels) { 
     final int labelLen = label.length(); 
     if (labelLen == 0) 
      break; 

     buf.writeByte(labelLen); 
     ByteBufUtil.writeAscii(buf, label); 
    } 

    buf.writeByte(0); 
} 

为了解码您可以使用此代码段的SRV记录:

DnsRawRecord record = msg.recordAt(DnsSection.ANSWER, 0); //msg is a DnsResponse 
if(record.type() == DnsRecordType.SRV) { 
    ByteBuf buf = record.content(); 
    System.out.println("\tPriority: " + buf.readUnsignedShort()); 
    System.out.println("\tWeight: " + buf.readUnsignedShort()); 
    System.out.println("\tPort: " + buf.readUnsignedShort()); 
    System.out.println("\tTarget:" + DefaultDnsRecordDecoder.decodeName(buf)); 
} 
+0

你能举一个编码my.domain.tld的例子吗? – rich