From 7d7233dbce5653bd45b9bbd4c088880d1748273d Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Sat, 16 Nov 2024 07:08:44 +1100 Subject: [PATCH] Grease EDNS version response --- lib/ns/client.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/lib/ns/client.c b/lib/ns/client.c index c02a25a390..db57e0f3e3 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -1042,6 +1042,17 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message, unsigned char expire[4]; unsigned char advtimo[2]; dns_aclenv_t *env = NULL; + unsigned char version = 0; + unsigned int grease_rate = 0; + time_t grease_until = 0; + bool grease_response_edns_flags = false; + bool grease_response_edns_option = false; + bool grease_response_edns_version = false; + uint32_t grease_edns_known_flags = ~0; + time_t tnow = time(NULL); + +#define GREASE \ + (grease_rate > 0 ? (grease_rate >= isc_random_uniform(99) + 1) : false) REQUIRE(NS_CLIENT_VALID(client)); REQUIRE(opt != NULL && *opt == NULL); @@ -1049,6 +1060,38 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message, env = client->manager->aclenv; view = client->view; + + /* + * Grease normal QUERY responses. + */ + if (view != NULL && message->opcode == dns_opcode_query && + (message->rcode == dns_rcode_noerror || + message->rcode == dns_rcode_nxdomain)) + { + dns_peer_t *peer = NULL; + isc_netaddr_t srcip; + + grease_rate = view->grease_rate; + grease_until = view->grease_until; + grease_edns_known_flags = view->grease_edns_known_flags; + + grease_response_edns_flags = view->grease_response_edns_flags; + grease_response_edns_option = view->grease_response_edns_option; + grease_response_edns_version = + view->grease_response_edns_version; + + isc_netaddr_fromsockaddr(&srcip, &client->peeraddr); + result = dns_peerlist_peerbyaddr(view->peers, &srcip, &peer); + if (result == ISC_R_SUCCESS && peer != NULL) { + dns_peer_getrespednsflags(peer, + &grease_response_edns_flags); + dns_peer_getrespednsoption( + peer, &grease_response_edns_option); + dns_peer_getrespednsversion( + peer, &grease_response_edns_version); + } + } + if (view != NULL) { udpsize = dns_view_getudpsize(view); } else { @@ -1057,6 +1100,32 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message, flags = client->extflags & DNS_MESSAGEEXTFLAG_REPLYPRESERVE; + /* + * Don't grease EDNS flags if there is an unknown flag in the request. + */ + if ((client->extflags & ~grease_edns_known_flags & 0xffff) != 0) { + grease_response_edns_flags = false; + } + + if (grease_response_edns_flags && tnow < grease_until && GREASE) { + uint16_t ednsflags = 1 << isc_random_uniform(14); + ednsflags &= ~grease_edns_known_flags; + flags |= ednsflags; + } + + if (grease_response_edns_option && tnow < grease_until && GREASE) { + uint16_t code = 100 + isc_random_uniform(65000 - 100); + INSIST(count < DNS_EDNSOPTIONS); + ednsopts[count].code = code; + ednsopts[count].length = 0; + ednsopts[count].value = NULL; + count++; + } + + if (grease_response_edns_version && tnow < grease_until && GREASE) { + version = 1 + isc_random_uniform(254); + } + /* Set EDNS options if applicable */ if (WANTNSID(client)) { if (client->manager->sctx->server_id != NULL) { @@ -1230,8 +1299,8 @@ no_nsid: } } - result = dns_message_buildopt(message, opt, 0, udpsize, flags, ednsopts, - count); + result = dns_message_buildopt(message, opt, version, udpsize, flags, + ednsopts, count); return result; } @@ -1652,7 +1721,7 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) { result = DNS_R_BADVERS; } ns_client_error(client, result); - return (result); + return result; } ns_stats_increment(client->manager->sctx->nsstats,