Fix zero-length RAW_RR losing type metadata during parsing (#1129)
ares_dns_parse_rr_raw_rr() returned early when rdlength==0 without
setting ARES_RR_RAW_RR_TYPE, so the record's type was lost (left as 0).
Move the type assignment to the top of the function so it is set
unconditionally, before the zero-length early return.
Add test with a hand-crafted DNS packet containing a zero-length RAW_RR
with type 65432, verifying the type survives the parse.
---------
Signed-off-by: David Hotham (@dimbleby)
diff --git a/src/lib/record/ares_dns_parse.c b/src/lib/record/ares_dns_parse.c
index 01f3f43..6430e7f 100644
--- a/src/lib/record/ares_dns_parse.c
+++ b/src/lib/record/ares_dns_parse.c
@@ -768,6 +768,12 @@
ares_status_t status;
unsigned char *bytes = NULL;
+ /* Can't fail */
+ status = ares_dns_rr_set_u16(rr, ARES_RR_RAW_RR_TYPE, raw_type);
+ if (status != ARES_SUCCESS) {
+ return status;
+ }
+
if (rdlength == 0) {
return ARES_SUCCESS;
}
@@ -777,13 +783,6 @@
return status;
}
- /* Can't fail */
- status = ares_dns_rr_set_u16(rr, ARES_RR_RAW_RR_TYPE, raw_type);
- if (status != ARES_SUCCESS) {
- ares_free(bytes);
- return status;
- }
-
status = ares_dns_rr_set_bin_own(rr, ARES_RR_RAW_RR_DATA, bytes, rdlength);
if (status != ARES_SUCCESS) {
ares_free(bytes);
diff --git a/test/ares-test-internal.cc b/test/ares-test-internal.cc
index 11b7c14..4b03b0d 100644
--- a/test/ares-test-internal.cc
+++ b/test/ares-test-internal.cc
@@ -1574,6 +1574,47 @@
ares_socket_t s;
} test_htable_asvp_t;
+TEST_F(LibraryTest, ZeroLengthRawRrKeepsType) {
+ ares_dns_record_t *parsed = NULL;
+ ares_dns_rr_t *rr = NULL;
+
+ /* Hand-crafted minimal DNS response with a zero-length RAW_RR.
+ * Header: id=0x1234, QR=1 RD=1 RA=1, QDCOUNT=1, ANCOUNT=1
+ * Question: \x07example\x03com\x00, type A (1), class IN (1)
+ * Answer: \xc0\x0c (name ptr), type=0xFF98 (65432), class IN,
+ * TTL=300, RDLENGTH=0 */
+ const unsigned char pkt[] = {
+ /* Header */
+ 0x12, 0x34, /* ID */
+ 0x81, 0x80, /* Flags: QR=1, RD=1, RA=1 */
+ 0x00, 0x01, /* QDCOUNT=1 */
+ 0x00, 0x01, /* ANCOUNT=1 */
+ 0x00, 0x00, /* NSCOUNT=0 */
+ 0x00, 0x00, /* ARCOUNT=0 */
+ /* Question: example.com, type A, class IN */
+ 0x07, 'e','x','a','m','p','l','e',
+ 0x03, 'c','o','m',
+ 0x00,
+ 0x00, 0x01, /* QTYPE=A */
+ 0x00, 0x01, /* QCLASS=IN */
+ /* Answer RR: example.com (compressed), type 65432, class IN, TTL 300 */
+ 0xc0, 0x0c, /* Name pointer */
+ 0xff, 0x98, /* TYPE=65432 */
+ 0x00, 0x01, /* CLASS=IN */
+ 0x00, 0x00, 0x01, 0x2c, /* TTL=300 */
+ 0x00, 0x00 /* RDLENGTH=0 */
+ };
+
+ EXPECT_EQ(ARES_SUCCESS,
+ ares_dns_parse(pkt, sizeof(pkt), 0, &parsed));
+ EXPECT_EQ(1, ares_dns_record_rr_cnt(parsed, ARES_SECTION_ANSWER));
+ rr = ares_dns_record_rr_get(parsed, ARES_SECTION_ANSWER, 0);
+ EXPECT_EQ(ARES_REC_TYPE_RAW_RR, ares_dns_rr_get_type(rr));
+ EXPECT_EQ(65432, ares_dns_rr_get_u16(rr, ARES_RR_RAW_RR_TYPE));
+
+ ares_dns_record_destroy(parsed);
+}
+
TEST_F(LibraryTest, RawRrTypeTostrFromstrRoundtrip) {
const char *str;
ares_dns_rec_type_t qtype = (ares_dns_rec_type_t)0;