Skip to content

Commit d8a1dff

Browse files
committed
DefaultDnsRecordDecoder compression and index decode bug, backport netty/netty#5923
1 parent 24a4cdb commit d8a1dff

File tree

2 files changed

+75
-3
lines changed

2 files changed

+75
-3
lines changed

netty-bp/codec-dns/src/main/java/io/netty/handler/codec/dns/DefaultDnsRecordDecoder.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,17 @@ protected DnsRecord decodeRecord(
8888
String name, DnsRecordType type, int dnsClass, long timeToLive,
8989
ByteBuf in, int offset, int length) throws Exception {
9090

91+
// DNS message compression means that domain names may contain "pointers" to other positions in the packet
92+
// to build a full message. This means the indexes are meaningful and we need the ability to reference the
93+
// indexes un-obstructed, and thus we cannot use a slice here.
94+
// See https://www.ietf.org/rfc/rfc1035 [4.1.4. Message compression]
9195
if (type == DnsRecordType.PTR) {
9296
in.setIndex(offset, offset + length);
93-
return new DefaultDnsPtrRecord(name, dnsClass, timeToLive, decodeName0(in.slice(offset, length)));
97+
return new DefaultDnsPtrRecord(
98+
name, dnsClass, timeToLive, decodeName0(in.duplicate().setIndex(offset, offset + length)));
9499
}
95100
return new DefaultDnsRawRecord(
96-
name, type, dnsClass, timeToLive, in.slice(offset, length).retain());
101+
name, type, dnsClass, timeToLive, in.duplicate().setIndex(offset, offset + length).retain());
97102
}
98103

99104
/**

netty-bp/codec-dns/src/test/java/io/netty/handler/codec/dns/DefaultDnsRecordEncoderTest.java

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
package io.netty.handler.codec.dns;
1717

1818
import io.netty.buffer.ByteBuf;
19-
import io.netty.buffer.ByteBufUtil;
2019
import io.netty.buffer.Unpooled;
2120
import io.netty.util.internal.StringUtil;
2221
import org.junit.Test;
@@ -63,4 +62,72 @@ private static void testEncodeName(byte[] expected, String name) throws Exceptio
6362
expectedBuf.release();
6463
}
6564
}
65+
66+
@Test
67+
public void testDecodeMessageCompression() throws Exception {
68+
// See https://www.ietf.org/rfc/rfc1035 [4.1.4. Message compression]
69+
DefaultDnsRecordDecoder decoder = new DefaultDnsRecordDecoder();
70+
byte[] rfcExample = new byte[] { 1, 'F', 3, 'I', 'S', 'I', 4, 'A', 'R', 'P', 'A',
71+
0, 3, 'F', 'O', 'O',
72+
(byte) 0xC0, 0, // this is 20 in the example
73+
(byte) 0xC0, 6, // this is 26 in the example
74+
};
75+
DefaultDnsRawRecord rawPlainRecord = null;
76+
DefaultDnsRawRecord rawUncompressedRecord = null;
77+
DefaultDnsRawRecord rawUncompressedIndexedRecord = null;
78+
ByteBuf buffer = Unpooled.wrappedBuffer(rfcExample);
79+
try {
80+
// First lets test that our utility funciton can correctly handle index references and decompression.
81+
String plainName = DefaultDnsRecordDecoder.decodeName(buffer.duplicate());
82+
assertEquals("F.ISI.ARPA.", plainName);
83+
String uncompressedPlainName = DefaultDnsRecordDecoder.decodeName(buffer.duplicate().setIndex(16, 20));
84+
assertEquals(plainName, uncompressedPlainName);
85+
String uncompressedIndexedName = DefaultDnsRecordDecoder.decodeName(buffer.duplicate().setIndex(12, 20));
86+
assertEquals("FOO." + plainName, uncompressedIndexedName);
87+
88+
// Now lets make sure out object parsing produces the same results for non PTR type (just use CNAME).
89+
rawPlainRecord = (DefaultDnsRawRecord) decoder.decodeRecord(
90+
plainName, DnsRecordType.CNAME, DnsRecord.CLASS_IN, 60, buffer, 0, 11);
91+
assertEquals(plainName, rawPlainRecord.name());
92+
assertEquals(plainName, DefaultDnsRecordDecoder.decodeName(rawPlainRecord.content()));
93+
94+
rawUncompressedRecord = (DefaultDnsRawRecord) decoder.decodeRecord(
95+
uncompressedPlainName, DnsRecordType.CNAME, DnsRecord.CLASS_IN, 60, buffer, 16, 4);
96+
assertEquals(uncompressedPlainName, rawUncompressedRecord.name());
97+
assertEquals(uncompressedPlainName, DefaultDnsRecordDecoder.decodeName(rawUncompressedRecord.content()));
98+
99+
rawUncompressedIndexedRecord = (DefaultDnsRawRecord) decoder.decodeRecord(
100+
uncompressedIndexedName, DnsRecordType.CNAME, DnsRecord.CLASS_IN, 60, buffer, 12, 8);
101+
assertEquals(uncompressedIndexedName, rawUncompressedIndexedRecord.name());
102+
assertEquals(uncompressedIndexedName,
103+
DefaultDnsRecordDecoder.decodeName(rawUncompressedIndexedRecord.content()));
104+
105+
// Now lets make sure out object parsing produces the same results for PTR type.
106+
DnsPtrRecord ptrRecord = (DnsPtrRecord) decoder.decodeRecord(
107+
plainName, DnsRecordType.PTR, DnsRecord.CLASS_IN, 60, buffer, 0, 11);
108+
assertEquals(plainName, ptrRecord.name());
109+
assertEquals(plainName, ptrRecord.hostname());
110+
111+
ptrRecord = (DnsPtrRecord) decoder.decodeRecord(
112+
uncompressedPlainName, DnsRecordType.PTR, DnsRecord.CLASS_IN, 60, buffer, 16, 4);
113+
assertEquals(uncompressedPlainName, ptrRecord.name());
114+
assertEquals(uncompressedPlainName, ptrRecord.hostname());
115+
116+
ptrRecord = (DnsPtrRecord) decoder.decodeRecord(
117+
uncompressedIndexedName, DnsRecordType.PTR, DnsRecord.CLASS_IN, 60, buffer, 12, 8);
118+
assertEquals(uncompressedIndexedName, ptrRecord.name());
119+
assertEquals(uncompressedIndexedName, ptrRecord.hostname());
120+
} finally {
121+
if (rawPlainRecord != null) {
122+
rawPlainRecord.release();
123+
}
124+
if (rawUncompressedRecord != null) {
125+
rawUncompressedRecord.release();
126+
}
127+
if (rawUncompressedIndexedRecord != null) {
128+
rawUncompressedIndexedRecord.release();
129+
}
130+
buffer.release();
131+
}
132+
}
66133
}

0 commit comments

Comments
 (0)