[#5014] Correctly encode / decode zero-length names when encoding DnsRecords.
Motivation: Zero-length names needs to be "prefixed" by the length as well when encoded into a ByteBuf. Also some servers not correctly prefix these so we should ensure we can workaround this and even decode in such case. Modifications: - Always encode the length of the name into the ByteBuf even if its zero-length. - If there are no readable bytes for the name just asume its an empty name to workaround dns servers that not fully respect the RFC. Result: Correctly encode zero-length names and be able to decode empty names even when the rfc is not strictly followed.
This commit is contained in:
parent
9a183ec38f
commit
6bf7e24389
@ -107,7 +107,19 @@ public class DefaultDnsRecordDecoder implements DnsRecordDecoder {
|
||||
int position = -1;
|
||||
int checked = 0;
|
||||
final int end = in.writerIndex();
|
||||
final StringBuilder name = new StringBuilder(in.readableBytes() << 1);
|
||||
final int readable = in.readableBytes();
|
||||
|
||||
// Looking at the spec we should always have at least enough readable bytes to read a byte here but it seems
|
||||
// some servers do not respect this for empty names. So just workaround this and return an empty name in this
|
||||
// case.
|
||||
//
|
||||
// See:
|
||||
// - https://github.com/netty/netty/issues/5014
|
||||
// - https://www.ietf.org/rfc/rfc1035.txt , Section 3.1
|
||||
if (readable == 0) {
|
||||
return StringUtil.EMPTY_STRING;
|
||||
}
|
||||
final StringBuilder name = new StringBuilder(readable << 1);
|
||||
for (int len = in.readUnsignedByte(); in.isReadable() && len != 0; len = in.readUnsignedByte()) {
|
||||
boolean pointer = (len & 0xc0) == 0xc0;
|
||||
if (pointer) {
|
||||
|
@ -80,10 +80,14 @@ public class DefaultDnsRecordEncoder implements DnsRecordEncoder {
|
||||
String[] parts = StringUtil.split(name, '.');
|
||||
for (String part: parts) {
|
||||
final int partLen = part.length();
|
||||
// We always need to write the length even if its 0.
|
||||
// See:
|
||||
// - https://github.com/netty/netty/issues/5014
|
||||
// - https://www.ietf.org/rfc/rfc1035.txt , Section 3.1
|
||||
buf.writeByte(partLen);
|
||||
if (partLen == 0) {
|
||||
continue;
|
||||
}
|
||||
buf.writeByte(partLen);
|
||||
ByteBufUtil.writeAscii(buf, part);
|
||||
}
|
||||
buf.writeByte(0); // marks end of name field
|
||||
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2016 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.handler.codec.dns;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DefaultDnsRecordDecoderTest {
|
||||
|
||||
@Test
|
||||
public void testDecodeEmptyName() {
|
||||
testDecodeEmptyName0(Unpooled.buffer().writeByte('0'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecodeEmptyNameNonRFC() {
|
||||
testDecodeEmptyName0(Unpooled.EMPTY_BUFFER);
|
||||
}
|
||||
|
||||
private static void testDecodeEmptyName0(ByteBuf buffer) {
|
||||
try {
|
||||
DefaultDnsRecordDecoder decoder = new DefaultDnsRecordDecoder();
|
||||
Assert.assertEquals(StringUtil.EMPTY_STRING, decoder.decodeName(buffer));
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2016 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.handler.codec.dns;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class DefaultDnsRecordEncoderTest {
|
||||
|
||||
// Test for https://github.com/netty/netty/issues/5014
|
||||
@Test
|
||||
public void testEncodeEmptyName() throws Exception {
|
||||
DefaultDnsRecordEncoder encoder = new DefaultDnsRecordEncoder();
|
||||
ByteBuf out = Unpooled.buffer();
|
||||
try {
|
||||
encoder.encodeName(StringUtil.EMPTY_STRING, out);
|
||||
assertEquals(2, out.readableBytes());
|
||||
assertEquals(0, out.readByte());
|
||||
assertEquals(0, out.readByte());
|
||||
} finally {
|
||||
out.release();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user