我一直在尝试使用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请求的输出,并将系统DNS设置为127.0.0.1 但我找不到发送虚拟DNS响应的方法,以便为请求的域解析IP地址。 (我想我应该初始化一个DatagramDnsResponse对象并将其写回给用户,但这是正确的吗?如果是这样的话,我如何用虚拟IP初始化它作为已解析的IP) 我是在错误的道路上,有人可以指引我走正确的道路。感谢。
答案 0 :(得分:2)
实际上,您只需要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记录,您可以使用此代码段:
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));
}