Netty DNS Answer Section未正确解码

时间:2016-08-23 07:17:36

标签: java dns netty

我正在使用netty开发DNS客户端。 为了测试它,我写了一个简单的带有netty的DNS服务器,它返回了我期待的DnsRecords。

这是我的客户代码:

final NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup();
final EventLoop next = nioEventLoopGroup.next();
final DnsNameResolverBuilder dnsNameResolverBuilder = new 
DnsNameResolverBuilder(next).channelFactory(new ChannelFactory<DatagramChannel>() {
        @Override
        public DatagramChannel newChannel() {
            return new NioDatagramChannel();
        }
    }).queryTimeoutMillis(100000).nameServerAddresses(new 
        DnsServerAddresses() {
        @Override
        public DnsServerAddressStream stream() {
            return new DnsServerAddressStream() {
                @Override
                public InetSocketAddress next() {
                    return new InetSocketAddress("127.0.0.1", 
                    TEST_DNS_SD_SERVER_PORT);
                }
            };
        }
    });
    final DnsNameResolver build = dnsNameResolverBuilder.build();
    final DefaultDnsQuestion defaultDnsQuestion = new 
    DefaultDnsQuestion(TEST_BASE_RECORD_NAME, DnsRecordType.PTR);
    build.query(defaultDnsQuestion).addListener(new GenericFutureListener<Future<? super AddressedEnvelope<DnsResponse, InetSocketAddress>>>() {
        @Override
        public void operationComplete(final Future<? super AddressedEnvelope<DnsResponse, InetSocketAddress>> future) throws Exception {
            final AddressedEnvelope<DnsResponse, InetSocketAddress> answer = (AddressedEnvelope<DnsResponse, InetSocketAddress>) future.get();
            final DnsResponse content = answer.content();
            final int count = content.count(DnsSection.ANSWER);
            for (int i = 0; i < count; i++) {
                final DnsRecord recordAt = content.recordAt(DnsSection.ANSWER, i);
                System.out.println(recordAt);
            }
        }
    }).await();
    Thread.sleep(Long.MAX_VALUE);

TEST_BASE_RECORD_NAME是答案部分中包含3个DnsPtrRecords的记录。

TEST_DNS_SD_SERVER_PORT后面我在一个单独的线程中运行DNS服务器,它以下列方式处理请求: (LocalDNSSDHandler的一部分:)

public void channelRead(final ChannelHandlerContext ctx, final Object msg) { 
        final DatagramDnsQuery query = (DatagramDnsQuery) msg;
        DatagramDnsResponse defaultDnsResponse = null;
        try {
            final DnsRecord recordAt = query.recordAt(DnsSection.QUESTION);
            final Name name = Name.fromString(recordAt.name(), Name.root);
            final DnsEntryKey dnsEntryKey = 
            new DnsEntryKey(name, recordAt.type().intValue());
            final List<Record> list = 
            LocalTestServer.this.getDnsEntries().get(dnsEntryKey);
            defaultDnsResponse = 
            new DatagramDnsResponse(query.recipient(),
            query.sender(), query.id());
            defaultDnsResponse.addRecord(DnsSection.QUESTION, recordAt);
            for (final Record record : list) {
                final ByteBuf buffer = ctx.alloc().buffer();
                buffer.writeBytes(record.toWireCanonical());
                defaultDnsResponse.addRecord(DnsSection.ANSWER, new 
                DefaultDnsRawRecord(record.getName().toString(), 
                this.fromRecord(record), Long.MAX_VALUE, buffer));
            }
        } catch (final Exception e) {
        }
        ctx.writeAndFlush(defaultDnsResponse);
    }

服务器定义ChannelHandler

public void initChannel(final DatagramChannel ch) throws Exception {
                ch.pipeline().addLast(new DatagramDnsResponseEncoder());
                ch.pipeline().addLast(new DatagramDnsQueryDecoder());
                ch.pipeline().addLast(new LocalDNSSDHandler());
            }

我在客户端期待的是为我所期待的3个DnsPtrRecords看3 System.out.println。但我得到的只有1。

当我调试它时,我可以看到,服务器端的编码/解码工作正常。 但是当客户端解码相应的ByteBuf(其中包含我期望的数据)时,它只返回1个记录,并在代码中跳过另外2个:

(DatagramDnsResponseDecoder)

@Override
protected void decode(ChannelHandlerContext ctx, DatagramPacket packet, 
List<Object> out) throws Exception {
    final ByteBuf buf = packet.content();
    final DnsResponse response = newResponse(packet, buf);
    boolean success = false;
    try {
        final int questionCount = buf.readUnsignedShort();
        final int answerCount = buf.readUnsignedShort();
        final int authorityRecordCount = buf.readUnsignedShort();
        final int additionalRecordCount = buf.readUnsignedShort();
        decodeQuestions(response, buf, questionCount);
        decodeRecords(response, DnsSection.ANSWER, buf, answerCount);
        decodeRecords(response, DnsSection.AUTHORITY, buf,
        authorityRecordCount);
        decodeRecords(response, DnsSection.ADDITIONAL, buf, 
        additionalRecordCount);
        ...//source code of netty 4.1, trimmed

我期待的answerCount是3。但是什么时候

decodeRecords(response, DnsSection.ANSWER, buf, answerCount);

被调用,它将调用

(DefaultDnsRecordDecoder)

protected DnsRecord decodeRecord(
        String name, DnsRecordType type, int dnsClass, long timeToLive,
        ByteBuf in, int offset, int length) throws Exception {
    if (type == DnsRecordType.PTR) {
        in.setIndex(offset, offset + length);
        return 
        new DefaultDnsPtrRecord(name, dnsClass, timeToLive, decodeName0(in));
    }
    return new DefaultDnsRawRecord(
            name, type, dnsClass, timeToLive, 
            in.retainedDuplicate().setIndex(offset, offset + length));
}

我不明白

in.setIndex(offset, offset + length);

因为它设置了ByteBuf(in)的读写索引,这将跳过Answer部分中的其他DnsRecords,并使其仅返回一个DnsRecord。

我使用的是Netty 4.1.4.Final

1 个答案:

答案 0 :(得分:0)

Norman Maurer证实这是一个Bug并在发布中修复它: 4.1.6.Final

谢谢诺曼!