【问题标题】:Custom DNS Server using Netty使用 Netty 自定义 DNS 服务器
【发布时间】:2018-03-19 00:08:25
【问题描述】:

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

这是我到目前为止所做的事情

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 设置为 127.0.0.1 时,我得到了多个 DNS 请求的输出 但我找不到发送虚拟 DNS 响应的方法,以便为请求的域解析 IP 地址。 (我认为我应该初始化一个DatagramDnsResponse 对象并将其写回给用户,但这样对吗?如果是这样,我如何使用虚拟IP 作为解析的IP 对其进行初始化) 我是不是走错了路,有人可以指导我走正确的路吗?谢谢。

【问题讨论】:

  • 我已经添加了我到目前为止所做的事情,并进一步解释了。谢谢。

标签: java dns netty nameservers


【解决方案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);

编辑

要对名称进行编码,请使用此函数(我从 netty 中提取):

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 记录,您可以使用这个 sn-p:

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));
}

【讨论】:

  • 你能举一个编码my.domain.tld的例子吗?
猜你喜欢
  • 2011-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-29
  • 1970-01-01
  • 1970-01-01
  • 2011-05-22
  • 2019-06-10
相关资源
最近更新 更多