From bd210d124bdcadb5ea2bf4677a13631f79758dea Mon Sep 17 00:00:00 2001 From: "W.C.A. Wijngaards" Date: Thu, 3 Sep 2026 17:20:35 +0200 Subject: [PATCH] - Fix that when a partial EDNS option is in a query, the response is a more RFC conformant FORMERR, since the EDNS option is malformed. Also fix to have an EDNS size for the reply error encoding for failed EDNS parse of the query. Thanks to Qifan Zhang, Palo Alto Networks, for the report. --- daemon/worker.c | 2 ++ doc/Changelog | 5 +++++ testdata/edns_downstream_cookie_short.rpl | 18 ++++++++++++++++++ util/data/msgparse.c | 12 +++++++++--- 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/daemon/worker.c b/daemon/worker.c index 5cc586442..bbd91e05f 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1706,6 +1706,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error, } memset(&reply_edns, 0, sizeof(reply_edns)); reply_edns.edns_present = 1; + reply_edns.edns_version = EDNS_ADVERTISED_VERSION; + reply_edns.udp_size = EDNS_ADVERTISED_SIZE; error_encode(c->buffer, ret, &qinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns); diff --git a/doc/Changelog b/doc/Changelog index 5448f8d3a..818302ce7 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -13,6 +13,11 @@ udpsize, the reply is truncated with TC and fix for the rcode in that short reply to be a sensible rcode. Thanks to Qifan Zhang, Palo Alto Networks, for the report. + - Fix that when a partial EDNS option is in a query, the + response is a more RFC conformant FORMERR, since the EDNS + option is malformed. Also fix to have an EDNS size for + the reply error encoding for failed EDNS parse of the query. + Thanks to Qifan Zhang, Palo Alto Networks, for the report. 2 September 2026: Wouter - Fix to not commit to have_zone at apply AXFR time for auth diff --git a/testdata/edns_downstream_cookie_short.rpl b/testdata/edns_downstream_cookie_short.rpl index dedd7f174..22fd6e6fa 100644 --- a/testdata/edns_downstream_cookie_short.rpl +++ b/testdata/edns_downstream_cookie_short.rpl @@ -53,4 +53,22 @@ SECTION QUESTION test. IN TXT ENTRY_END +; Check an EDNS option with a too short content +; The EDNS OPT rdata is too short, for the option opt_len. +STEP 30 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +test. IN TXT +SECTION ADDITIONAL +. 32768 CLASS1230 OPT \# 04 00 0a 00 08 +ENTRY_END +STEP 31 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA DO FORMERR +SECTION QUESTION +test. IN TXT +ENTRY_END + SCENARIO_END diff --git a/util/data/msgparse.c b/util/data/msgparse.c index f9beb605c..e00f570c7 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -974,7 +974,6 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, } /* while still more options, and have code+len to read */ - /* ignores partial content (i.e. rdata len 3) */ while(rdata_len >= 4 && i < MAX_PARSED_EDNS_OPTIONS) { uint16_t opt_code = sldns_read_uint16(rdata_ptr); uint16_t opt_len = sldns_read_uint16(rdata_ptr+2); @@ -984,8 +983,10 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, rdata_ptr += 4; rdata_len -= 4; - if(opt_len > rdata_len) - break; /* option code partial */ + if(opt_len > rdata_len) { + /* option code partial */ + return LDNS_RCODE_FORMERR; + } /* handle parse time edns options here */ switch(opt_code) { @@ -1160,6 +1161,9 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, rdata_len -= opt_len; i++; } + /* partial content (i.e. rdata len 3) is FORMERR */ + if(rdata_len > 0 && rdata_len <= 3) + return LDNS_RCODE_FORMERR; return LDNS_RCODE_NOERROR; } @@ -1240,6 +1244,8 @@ parse_extract_edns_from_response_msg(struct msg_parse* msg, rdata_len -= 4; if(opt_len > rdata_len) break; /* option code partial */ + /* This is lenient for partially broken messages + * from upstream. With a partial EDNS option. */ if(!edns_opt_list_append(&edns->opt_list_in, opt_code, opt_len, rdata_ptr, region)) {