From 1c8949c6fbae34c92c24886929c01456fdfe3fb3 Mon Sep 17 00:00:00 2001 From: basavaraj-sm05 Date: Wed, 15 Jul 2026 17:21:06 +0530 Subject: [PATCH] read DNS RDLENGTH as an unsigned 16-bit value --- .../okhttp3/dnsoverhttps/-DnsMessageReader.kt | 2 +- .../DnsMessageReaderWriterTest.kt | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/-DnsMessageReader.kt b/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/-DnsMessageReader.kt index e93b2a4f06a3..406a473a45ee 100644 --- a/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/-DnsMessageReader.kt +++ b/okhttp-dnsoverhttps/src/main/kotlin/okhttp3/dnsoverhttps/-DnsMessageReader.kt @@ -140,7 +140,7 @@ internal class DnsMessageReader( val type = readShort().toInt() val `class` = readShort().toInt() val timeToLive = readInt() - val recordDataLength = readShort().toLong() + val recordDataLength = readShort().toUShort().toLong() when { `class` == CLASS_IN && type == TYPE_A -> { diff --git a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsMessageReaderWriterTest.kt b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsMessageReaderWriterTest.kt index de80efeddcea..024a756e47c1 100644 --- a/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsMessageReaderWriterTest.kt +++ b/okhttp-dnsoverhttps/src/test/java/okhttp3/dnsoverhttps/DnsMessageReaderWriterTest.kt @@ -134,6 +134,54 @@ class DnsMessageReaderWriterTest { ) } + /** + * An RDLENGTH is a 16-bit unsigned field, so a record may legitimately declare up to 65535 bytes + * of data. A value with the high bit set must still be skipped for record types we don't decode, + * otherwise the reader loses sync with the stream. + */ + @Test + fun `unsupported record with high-bit record length is skipped`() { + val buffer = + Buffer().apply { + writeShort(0x0000) // id + writeShort(0x8180) // flags + writeShort(1) // question count + writeShort(1) // answer count + writeShort(0) // authority record count + writeShort(0) // additional record count + + // Question: "a", type A, class IN. + writeByte(1) + writeByte('a'.code) + writeByte(0) + writeShort(TYPE_A) + writeShort(CLASS_IN) + + // Answer with an unsupported type and 0x8000 bytes of record data. + writeShort(0xc00c) // Name compressed to the question's name. + writeShort(16) // TYPE_TXT, which this reader doesn't decode. + writeShort(CLASS_IN) + writeInt(0) // time to live + writeShort(0x8000) // record data length, 32768 + write(ByteArray(0x8000)) + } + + assertThat(DnsMessageReader(buffer).read()).isEqualTo( + DnsMessage( + id = 0, + flags = -32384, + questions = + listOf( + Question( + name = "a", + type = TYPE_A, + ), + ), + answers = listOf(), + ), + ) + } + private fun assertRoundTrip(message: DnsMessage) { val buffer = Buffer() DnsMessageWriter(buffer).write(message)