Skip to content

Commit d665201

Browse files
committed
dhcp: extract the RCODE that was sent and abort query if non-zero and notify the
caller instaed of waiting for the timer to expire
1 parent 69746df commit d665201

3 files changed

Lines changed: 65 additions & 3 deletions

File tree

src/test/unit/unit.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,7 @@ Suite *wolf_suite(void)
674674
tcase_add_test(tc_proto, test_regression_fast_recovery_cwnd_ssthresh_rfc5681);
675675
tcase_add_test(tc_proto, test_regression_paws_rejects_stale_timestamp);
676676
tcase_add_test(tc_proto, test_regression_dhcp_nak_restarts_configuration);
677+
tcase_add_test(tc_proto, test_regression_dns_rcode_error_aborts_query);
677678

678679
tcase_add_test(tc_utils, test_transport_checksum);
679680
tcase_add_test(tc_utils, test_iphdr_set_checksum);

src/test/unit/unit_tests_proto.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4264,5 +4264,57 @@ START_TEST(test_regression_dhcp_nak_restarts_configuration)
42644264
}
42654265
END_TEST
42664266

4267+
/* DNS response parser does not check the RCODE field. An error response
4268+
* such as NXDOMAIN (RCODE=3) passes the QR+RD check, the empty answer
4269+
* section is silently skipped, and the query stays active until the
4270+
* retry timer fires. RFC 1035 s4.1.1: RCODE != 0 is an error. */
4271+
START_TEST(test_regression_dns_rcode_error_aborts_query)
4272+
{
4273+
struct wolfIP s;
4274+
struct tsocket *ts;
4275+
uint8_t response[64];
4276+
struct dns_header *hdr = (struct dns_header *)response;
4277+
struct dns_question *q;
4278+
int pos;
4279+
4280+
wolfIP_init(&s);
4281+
mock_link_init(&s);
4282+
s.dns_server = 0x08080808U;
4283+
4284+
/* Set up an active DNS query */
4285+
s.dns_udp_sd = wolfIP_sock_socket(&s, AF_INET, IPSTACK_SOCK_DGRAM, WI_IPPROTO_UDP);
4286+
ck_assert_int_gt(s.dns_udp_sd, 0);
4287+
ts = &s.udpsockets[SOCKET_UNMARK(s.dns_udp_sd)];
4288+
s.dns_id = 0xABCD;
4289+
s.dns_query_type = DNS_QUERY_TYPE_A;
4290+
s.dns_lookup_cb = test_dns_lookup_cb;
4291+
4292+
/* Build a DNS response with RCODE=3 (NXDOMAIN).
4293+
* flags = 0x8183: QR=1, RD=1, RA=1, RCODE=3
4294+
* ancount=0 (no answers, as expected for NXDOMAIN). */
4295+
memset(response, 0, sizeof(response));
4296+
hdr->id = ee16(0xABCD);
4297+
hdr->flags = ee16(0x8183);
4298+
hdr->qdcount = ee16(1);
4299+
hdr->ancount = ee16(0);
4300+
pos = sizeof(struct dns_header);
4301+
response[pos++] = 3; memcpy(&response[pos], "foo", 3); pos += 3;
4302+
response[pos++] = 3; memcpy(&response[pos], "com", 3); pos += 3;
4303+
response[pos++] = 0;
4304+
q = (struct dns_question *)(response + pos);
4305+
q->qtype = ee16(DNS_A);
4306+
q->qclass = ee16(1);
4307+
pos += sizeof(struct dns_question);
4308+
4309+
enqueue_udp_rx(ts, response, (uint16_t)pos, DNS_PORT);
4310+
dns_callback(s.dns_udp_sd, CB_EVENT_READABLE, &s);
4311+
4312+
/* The query must be aborted after receiving an authoritative error,
4313+
* not left active for the retry timer to fire. */
4314+
ck_assert_uint_eq(s.dns_id, 0);
4315+
ck_assert_int_eq(s.dns_query_type, DNS_QUERY_TYPE_NONE);
4316+
}
4317+
END_TEST
4318+
42674319

42684320
/* ----------------------------------------------------------------------- */

src/wolfip.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6637,6 +6637,10 @@ void dns_callback(int dns_sd, uint16_t ev, void *arg)
66376637
char buf[MAX_DNS_RESPONSE];
66386638
struct dns_header *hdr = (struct dns_header *)buf;
66396639
int dns_len;
6640+
int pos;
6641+
int qcount;
6642+
int ancount;
6643+
66406644
if (!s)
66416645
return;
66426646
if (ev & CB_EVENT_READABLE) {
@@ -6653,9 +6657,14 @@ void dns_callback(int dns_sd, uint16_t ev, void *arg)
66536657
return;
66546658
/* Parse DNS response */
66556659
if ((ee16(hdr->flags) & 0x8100) == 0x8100) {
6656-
int pos = sizeof(struct dns_header);
6657-
int qcount = ee16(hdr->qdcount);
6658-
int ancount = ee16(hdr->ancount);
6660+
/* RFC 1035 s4.1.1: RCODE != 0 is an error; abort query. */
6661+
if ((ee16(hdr->flags) & 0x000F) != 0) {
6662+
dns_abort_query(s);
6663+
return;
6664+
}
6665+
pos = sizeof(struct dns_header);
6666+
qcount = ee16(hdr->qdcount);
6667+
ancount = ee16(hdr->ancount);
66596668
while (qcount-- > 0) {
66606669
pos = dns_skip_name((const uint8_t *)buf, dns_len, pos);
66616670
if (pos < 0 || pos + (int)sizeof(struct dns_question) > dns_len) {

0 commit comments

Comments
 (0)