diff --git a/bin/delv/delv.c b/bin/delv/delv.c index f462a13c16..a4c262b53e 100644 --- a/bin/delv/delv.c +++ b/bin/delv/delv.c @@ -2085,8 +2085,8 @@ sendquery(void *arg) { mrdataset = NULL; mname = NULL; - CHECK(dns_message_buildopt(message, &opt, 0, 0, DNS_MESSAGEEXTFLAG_DO, - NULL, 0)); + dns_message_ednsinit(message, 0, 0, DNS_MESSAGEEXTFLAG_DO, 0); + CHECK(dns_message_buildopt(message, &opt)); CHECK(dns_message_setopt(message, opt)); CHECK(dns_requestmgr_create(isc_g_mctx, dispatchmgr, NULL, NULL, diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 12209c8e6a..1499761f78 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -1437,25 +1437,6 @@ save_opt(dig_lookup_t *lookup, char *code, char *value) { lookup->ednsoptscnt++; } -/*% - * Add EDNS0 option record to a message. Currently, the only supported - * options are UDP buffer size, the DO bit, and EDNS options - * (e.g., NSID, COOKIE, client-subnet) - */ -static void -add_opt(dns_message_t *msg, uint16_t udpsize, uint16_t edns, unsigned int flags, - dns_ednsopt_t *opts, size_t count) { - dns_rdataset_t *rdataset = NULL; - isc_result_t result; - - debug("add_opt()"); - result = dns_message_buildopt(msg, &rdataset, edns, udpsize, flags, - opts, count); - check_result(result, "dns_message_buildopt"); - result = dns_message_setopt(msg, rdataset); - check_result(result, "dns_message_setopt"); -} - /*% * Add a question section to a message, asking for the specified name, * type, and class. @@ -2134,6 +2115,7 @@ setup_lookup(dig_lookup_t *lookup) { char cookiebuf[256]; char *origin = NULL; char *textname = NULL; + dns_rdataset_t *rdataset = NULL; REQUIRE(lookup != NULL); @@ -2395,17 +2377,19 @@ setup_lookup(dig_lookup_t *lookup) { if (lookup->udpsize > -1 || lookup->dnssec || lookup->edns > -1 || lookup->ecs_addr != NULL) { -#define MAXOPTS (EDNSOPT_OPTIONS + DNS_EDNSOPTIONS) - dns_ednsopt_t opts[MAXOPTS]; - unsigned int flags; - unsigned int i = 0; + dns_ednsopt_t option; - /* - * There can't be more than MAXOPTS options to send: - * a maximum of EDNSOPT_OPTIONS set by +ednsopt - * and DNS_EDNSOPTIONS set by other arguments - * (+nsid, +cookie, etc). - */ + /* Set the EDNS flags */ + unsigned int flags = lookup->ednsflags; + flags &= ~(DNS_MESSAGEEXTFLAG_DO | DNS_MESSAGEEXTFLAG_CO); + if (lookup->dnssec) { + flags |= DNS_MESSAGEEXTFLAG_DO; + } + if (lookup->coflag) { + flags |= DNS_MESSAGEEXTFLAG_CO; + } + + /* Set the EDNS UDP size */ if (lookup->udpsize < 0) { lookup->udpsize = DEFAULT_EDNS_BUFSIZE; } @@ -2414,21 +2398,33 @@ setup_lookup(dig_lookup_t *lookup) { DEFAULT_EDNS_VERSION; } + /* + * Initialize EDNS in the message. + * + * Allow space for EDNSOPT_OPTIONS options to be + * set by +ednsopt, plus DNS_EDNSOPTIONS to be set + * by other arguments (+nsid, +cookie, etc). + */ + constexpr size_t MAXOPTS = + (EDNSOPT_OPTIONS + DNS_EDNS_MAX_OPTIONS); + + dns_message_ednsinit(lookup->sendmsg, lookup->edns, + lookup->udpsize, flags, MAXOPTS); + if (lookup->nsid) { - INSIST(i < MAXOPTS); - opts[i].code = DNS_OPT_NSID; - opts[i].length = 0; - opts[i].value = NULL; - i++; + option = (dns_ednsopt_t){ .code = DNS_OPT_NSID }; + result = dns_message_ednsaddopt(lookup->sendmsg, + &option); + check_result(result, "dns_message_ednsaddopt"); } if (lookup->ecs_addr != NULL) { uint8_t addr[16]; uint16_t family = 0; uint32_t plen; - struct sockaddr *sa; - struct sockaddr_in *sin; - struct sockaddr_in6 *sin6; + struct sockaddr *sa = NULL; + struct sockaddr_in *sin = NULL; + struct sockaddr_in6 *sin6 = NULL; size_t addrl; sa = &lookup->ecs_addr->type.sa; @@ -2437,10 +2433,8 @@ setup_lookup(dig_lookup_t *lookup) { /* Round up prefix len to a multiple of 8 */ addrl = (plen + 7) / 8; - INSIST(i < MAXOPTS); - opts[i].code = DNS_OPT_CLIENT_SUBNET; - opts[i].length = (uint16_t)addrl + 4; - check_result(result, "isc_buffer_allocate"); + option.code = DNS_OPT_CLIENT_SUBNET; + option.length = (uint16_t)addrl + 4; /* * XXXMUKS: According to RFC7871, "If there is @@ -2502,85 +2496,78 @@ setup_lookup(dig_lookup_t *lookup) { (unsigned int)addrl); } - opts[i].value = (uint8_t *)ecsbuf; - i++; + option.value = (uint8_t *)ecsbuf; + result = dns_message_ednsaddopt(lookup->sendmsg, + &option); + check_result(result, "dns_message_ednsaddopt"); } if (lookup->sendcookie) { - INSIST(i < MAXOPTS); - opts[i].code = DNS_OPT_COOKIE; + option.code = DNS_OPT_COOKIE; if (lookup->cookie != NULL) { isc_buffer_init(&b, cookiebuf, sizeof(cookiebuf)); result = isc_hex_decodestring(lookup->cookie, &b); check_result(result, "isc_hex_decodestring"); - opts[i].value = isc_buffer_base(&b); - opts[i].length = isc_buffer_usedlength(&b); + option.value = isc_buffer_base(&b); + option.length = isc_buffer_usedlength(&b); } else { compute_cookie(cookie, sizeof(cookie)); - opts[i].length = 8; - opts[i].value = cookie; + option.length = 8; + option.value = cookie; } - i++; + + result = dns_message_ednsaddopt(lookup->sendmsg, + &option); + check_result(result, "dns_message_ednsaddopt"); } if (lookup->expire) { - INSIST(i < MAXOPTS); - opts[i].code = DNS_OPT_EXPIRE; - opts[i].length = 0; - opts[i].value = NULL; - i++; + option = (dns_ednsopt_t){ .code = DNS_OPT_EXPIRE }; + result = dns_message_ednsaddopt(lookup->sendmsg, + &option); + check_result(result, "dns_message_ednsaddopt"); } if (lookup->tcp_keepalive) { - INSIST(i < MAXOPTS); - opts[i].code = DNS_OPT_TCP_KEEPALIVE; - opts[i].length = 0; - opts[i].value = NULL; - i++; + option = (dns_ednsopt_t){ + .code = DNS_OPT_TCP_KEEPALIVE, + }; + result = dns_message_ednsaddopt(lookup->sendmsg, + &option); + check_result(result, "dns_message_ednsaddopt"); } if (lookup->zoneversion) { - INSIST(i < MAXOPTS); - opts[i].code = DNS_OPT_ZONEVERSION; - opts[i].length = 0; - opts[i].value = NULL; - i++; + option = (dns_ednsopt_t){ + .code = DNS_OPT_ZONEVERSION, + }; + result = dns_message_ednsaddopt(lookup->sendmsg, + &option); + check_result(result, "dns_message_ednsaddopt"); } if (lookup->ednsoptscnt != 0) { - INSIST(i + lookup->ednsoptscnt <= MAXOPTS); - memmove(&opts[i], lookup->ednsopts, - sizeof(dns_ednsopt_t) * lookup->ednsoptscnt); - i += lookup->ednsoptscnt; - } - - if (lookup->padding != 0 && (i >= MAXOPTS)) { - debug("turned off padding because of EDNS overflow"); - lookup->padding = 0; + for (size_t i = 0; i < lookup->ednsoptscnt; i++) { + result = dns_message_ednsaddopt( + lookup->sendmsg, &lookup->ednsopts[i]); + check_result(result, "dns_message_ednsaddopt"); + } } if (lookup->padding != 0) { - INSIST(i < MAXOPTS); - opts[i].code = DNS_OPT_PAD; - opts[i].length = 0; - opts[i].value = NULL; - i++; + option = (dns_ednsopt_t){ .code = DNS_OPT_PAD }; + /* This can fail harmlessly */ + (void)dns_message_ednsaddopt(lookup->sendmsg, &option); dns_message_setpadding(lookup->sendmsg, lookup->padding); } - flags = lookup->ednsflags; - flags &= ~(DNS_MESSAGEEXTFLAG_DO | DNS_MESSAGEEXTFLAG_CO); - if (lookup->dnssec) { - flags |= DNS_MESSAGEEXTFLAG_DO; - } - if (lookup->coflag) { - flags |= DNS_MESSAGEEXTFLAG_CO; - } - add_opt(lookup->sendmsg, lookup->udpsize, lookup->edns, flags, - opts, i); + result = dns_message_buildopt(lookup->sendmsg, &rdataset); + check_result(result, "dns_message_buildopt"); + result = dns_message_setopt(lookup->sendmsg, rdataset); + check_result(result, "dns_message_setopt"); } result = dns_message_rendersection(lookup->sendmsg, diff --git a/bin/dig/nslookup.c b/bin/dig/nslookup.c index d5ec48464d..177cdeba6d 100644 --- a/bin/dig/nslookup.c +++ b/bin/dig/nslookup.c @@ -264,6 +264,8 @@ detailsection(dig_query_t *query, dns_message_t *msg, bool headers, case DNS_SECTION_ADDITIONAL: puts(" ADDITIONAL RECORDS:"); break; + default: + UNREACHABLE(); } } diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index 4ceff56466..f0f1a613a9 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -1493,35 +1493,28 @@ evaluate_prereq(char *cmdline) { static void updateopt(void) { isc_result_t result; - dns_ednsopt_t ednsopts[1]; + dns_rdataset_t *opt = NULL; unsigned char ul[8]; - unsigned int count = 0; + isc_buffer_t b; + dns_ednsopt_t option = { + .code = DNS_OPT_UL, + .length = keylease_set ? 8 : 4, + .value = ul, + }; - if (lease_set) { - isc_buffer_t b; - INSIST(count < ARRAY_SIZE(ednsopts)); - ednsopts[count++] = (dns_ednsopt_t){ .code = DNS_OPT_UL, - .length = keylease_set ? 8 - : 4, - .value = ul }; - - isc_buffer_init(&b, ul, sizeof(ul)); - isc_buffer_putuint32(&b, lease); - isc_buffer_putuint32(&b, keylease); + if (!lease_set) { + return; } - if (count != 0) { - dns_rdataset_t *opt = NULL; - result = dns_message_buildopt(updatemsg, &opt, 0, - DEFAULT_EDNS_BUFSIZE, 0, ednsopts, - count); - check_result(result, "dns_message_buildopt"); - result = dns_message_setopt(updatemsg, opt); - check_result(result, "dns_message_setopt"); - } else { - result = dns_message_setopt(updatemsg, NULL); - check_result(result, "dns_message_setopt"); - } + isc_buffer_init(&b, ul, sizeof(ul)); + isc_buffer_putuint32(&b, lease); + isc_buffer_putuint32(&b, keylease); + + dns_message_ednsinit(updatemsg, 0, DEFAULT_EDNS_BUFSIZE, 0, 0); + dns_message_ednsaddopt(updatemsg, &option); + result = dns_message_buildopt(updatemsg, &opt); + check_result(result, "dns_message_buildopt"); + result = dns_message_setopt(updatemsg, opt); } static uint16_t diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c index ddfddee46d..2f4e79b20e 100644 --- a/bin/tools/mdig.c +++ b/bin/tools/mdig.c @@ -524,24 +524,6 @@ cleanup: return; } -/*% - * Add EDNS0 option record to a message. Currently, the only supported - * options are UDP buffer size, the DO bit, and EDNS options - * (e.g., NSID, COOKIE, client-subnet) - */ -static void -add_opt(dns_message_t *msg, uint16_t udpsize, uint16_t edns, unsigned int flags, - dns_ednsopt_t *opts, size_t count) { - dns_rdataset_t *rdataset = NULL; - isc_result_t result; - - result = dns_message_buildopt(msg, &rdataset, edns, udpsize, flags, - opts, count); - CHECK("dns_message_buildopt", result); - result = dns_message_setopt(msg, rdataset); - CHECK("dns_message_setopt", result); -} - static void compute_cookie(unsigned char *cookie, size_t len) { /* XXXMPA need to fix, should be per server. */ @@ -603,11 +585,16 @@ sendquery(struct query *query) { if (query->udpsize > 0 || query->dnssec || query->edns > -1 || query->ecs_addr != NULL) { - dns_ednsopt_t opts[EDNSOPTS + DNS_EDNSOPTIONS]; unsigned int flags; - int i = 0; char ecsbuf[20]; unsigned char cookie[40]; + dns_rdataset_t *rdataset = NULL; + + flags = query->ednsflags; + flags &= ~DNS_MESSAGEEXTFLAG_DO; + if (query->dnssec) { + flags |= DNS_MESSAGEEXTFLAG_DO; + } if (query->udpsize == 0) { query->udpsize = 1232; @@ -616,12 +603,13 @@ sendquery(struct query *query) { query->edns = 0; } + dns_message_ednsinit(message, query->edns, query->udpsize, + flags, 0); + if (query->nsid) { - INSIST(i < DNS_EDNSOPTIONS); - opts[i].code = DNS_OPT_NSID; - opts[i].length = 0; - opts[i].value = NULL; - i++; + dns_ednsopt_t option = { .code = DNS_OPT_NSID }; + result = dns_message_ednsaddopt(message, &option); + CHECK("dns_message_ednsaddopt", result); } if (query->ecs_addr != NULL) { @@ -639,10 +627,6 @@ sendquery(struct query *query) { /* Round up prefix len to a multiple of 8 */ addrl = (plen + 7) / 8; - INSIST(i < DNS_EDNSOPTIONS); - opts[i].code = DNS_OPT_CLIENT_SUBNET; - opts[i].length = (uint16_t)addrl + 4; - CHECK("isc_buffer_allocate", result); isc_buffer_init(&b, ecsbuf, sizeof(ecsbuf)); if (sa->sa_family == AF_INET) { family = 1; @@ -675,13 +659,16 @@ sendquery(struct query *query) { (unsigned int)addrl); } - opts[i].value = (uint8_t *)ecsbuf; - i++; + dns_ednsopt_t option = { .code = DNS_OPT_CLIENT_SUBNET, + .value = (uint8_t *)ecsbuf, + .length = (uint16_t)addrl + + 4 }; + result = dns_message_ednsaddopt(message, &option); + CHECK("dns_message_ednsaddopt", result); } if (query->send_cookie) { - INSIST(i < DNS_EDNSOPTIONS); - opts[i].code = DNS_OPT_COOKIE; + dns_ednsopt_t option = { .code = DNS_OPT_COOKIE }; if (query->cookie != NULL) { isc_buffer_t b; @@ -689,36 +676,36 @@ sendquery(struct query *query) { result = isc_hex_decodestring(query->cookie, &b); CHECK("isc_hex_decodestring", result); - opts[i].value = isc_buffer_base(&b); - opts[i].length = isc_buffer_usedlength(&b); + option.value = isc_buffer_base(&b); + option.length = isc_buffer_usedlength(&b); } else { compute_cookie(cookie, 8); - opts[i].length = 8; - opts[i].value = cookie; + option.length = 8; + option.value = cookie; } - i++; + + result = dns_message_ednsaddopt(message, &option); + CHECK("dns_message_ednsaddopt", result); } if (query->expire) { - INSIST(i < DNS_EDNSOPTIONS); - opts[i].code = DNS_OPT_EXPIRE; - opts[i].length = 0; - opts[i].value = NULL; - i++; + dns_ednsopt_t option = { .code = DNS_OPT_EXPIRE }; + result = dns_message_ednsaddopt(message, &option); + CHECK("dns_message_ednsaddopt", result); } if (query->ednsoptscnt != 0) { - memmove(&opts[i], query->ednsopts, - sizeof(dns_ednsopt_t) * query->ednsoptscnt); - i += query->ednsoptscnt; + for (size_t i = 0; i < query->ednsoptscnt; i++) { + result = dns_message_ednsaddopt( + message, &query->ednsopts[i]); + CHECK("dns_message_ednsaddopt", result); + } } - flags = query->ednsflags; - flags &= ~DNS_MESSAGEEXTFLAG_DO; - if (query->dnssec) { - flags |= DNS_MESSAGEEXTFLAG_DO; - } - add_opt(message, query->udpsize, query->edns, flags, opts, i); + result = dns_message_buildopt(message, &rdataset); + CHECK("dns_message_buildopt", result); + result = dns_message_setopt(message, rdataset); + CHECK("dns_message_setopt", result); } if (tcp_mode) { diff --git a/lib/dns/ede.c b/lib/dns/ede.c index af7cc0b57f..48fc153188 100644 --- a/lib/dns/ede.c +++ b/lib/dns/ede.c @@ -34,7 +34,7 @@ dns__ede_checkandupdateedeused(dns_edectx_t *edectx, uint16_t code) { void dns_ede_add(dns_edectx_t *edectx, uint16_t code, const char *text) { REQUIRE(DNS_EDE_VALID(edectx)); - REQUIRE(code <= DNS_EDE_MAX_CODE); + REQUIRE(code < DNS_EDE_MAX_CODE); uint16_t becode = htobe16(code); dns_ednsopt_t *edns = NULL; diff --git a/lib/dns/include/dns/ede.h b/lib/dns/include/dns/ede.h index 37194dd5ef..a9470306cb 100644 --- a/lib/dns/include/dns/ede.h +++ b/lib/dns/include/dns/ede.h @@ -18,33 +18,34 @@ #include /*%< EDNS0 extended DNS errors */ -#define DNS_EDE_OTHER 0 /*%< Other Error */ -#define DNS_EDE_DNSKEYALG 1 /*%< Unsupported DNSKEY Algorithm */ -#define DNS_EDE_DSDIGESTTYPE 2 /*%< Unsupported DS Digest Type */ -#define DNS_EDE_STALEANSWER 3 /*%< Stale Answer */ -#define DNS_EDE_FORGEDANSWER 4 /*%< Forged Answer */ -#define DNS_EDE_DNSSECINDETERMINATE 5 /*%< DNSSEC Indeterminate */ -#define DNS_EDE_DNSSECBOGUS 6 /*%< DNSSEC Bogus */ -#define DNS_EDE_SIGNATUREEXPIRED 7 /*%< Signature Expired */ -#define DNS_EDE_SIGNATURENOTYETVALID 8 /*%< Signature Not Yet Valid */ -#define DNS_EDE_DNSKEYMISSING 9 /*%< DNSKEY Missing */ -#define DNS_EDE_RRSIGSMISSING 10 /*%< RRSIGs Missing */ -#define DNS_EDE_NOZONEKEYBITSET 11 /*%< No Zone Key Bit Set */ -#define DNS_EDE_NSECMISSING 12 /*%< NSEC Missing */ -#define DNS_EDE_CACHEDERROR 13 /*%< Cached Error */ -#define DNS_EDE_NOTREADY 14 /*%< Not Ready */ -#define DNS_EDE_BLOCKED 15 /*%< Blocked */ -#define DNS_EDE_CENSORED 16 /*%< Censored */ -#define DNS_EDE_FILTERED 17 /*%< Filtered */ -#define DNS_EDE_PROHIBITED 18 /*%< Prohibited */ -#define DNS_EDE_STALENXANSWER 19 /*%< Stale NXDomain Answer */ -#define DNS_EDE_NOTAUTH 20 /*%< Not Authoritative */ -#define DNS_EDE_NOTSUPPORTED 21 /*%< Not Supported */ -#define DNS_EDE_NOREACHABLEAUTH 22 /*%< No Reachable Authority */ -#define DNS_EDE_NETWORKERROR 23 /*%< Network Error */ -#define DNS_EDE_INVALIDDATA 24 /*%< Invalid Data */ - -#define DNS_EDE_MAX_CODE DNS_EDE_INVALIDDATA +enum { + DNS_EDE_OTHER = 0, /*%< Other Error */ + DNS_EDE_DNSKEYALG = 1, /*%< Unsupported DNSKEY Algorithm */ + DNS_EDE_DSDIGESTTYPE = 2, /*%< Unsupported DS Digest Type */ + DNS_EDE_STALEANSWER = 3, /*%< Stale Answer */ + DNS_EDE_FORGEDANSWER = 4, /*%< Forged Answer */ + DNS_EDE_DNSSECINDETERMINATE = 5, /*%< DNSSEC Indeterminate */ + DNS_EDE_DNSSECBOGUS = 6, /*%< DNSSEC Bogus */ + DNS_EDE_SIGNATUREEXPIRED = 7, /*%< Signature Expired */ + DNS_EDE_SIGNATURENOTYETVALID = 8, /*%< Signature Not Yet Valid */ + DNS_EDE_DNSKEYMISSING = 9, /*%< DNSKEY Missing */ + DNS_EDE_RRSIGSMISSING = 10, /*%< RRSIGs Missing */ + DNS_EDE_NOZONEKEYBITSET = 11, /*%< No Zone Key Bit Set */ + DNS_EDE_NSECMISSING = 12, /*%< NSEC Missing */ + DNS_EDE_CACHEDERROR = 13, /*%< Cached Error */ + DNS_EDE_NOTREADY = 14, /*%< Not Ready */ + DNS_EDE_BLOCKED = 15, /*%< Blocked */ + DNS_EDE_CENSORED = 16, /*%< Censored */ + DNS_EDE_FILTERED = 17, /*%< Filtered */ + DNS_EDE_PROHIBITED = 18, /*%< Prohibited */ + DNS_EDE_STALENXANSWER = 19, /*%< Stale NXDomain Answer */ + DNS_EDE_NOTAUTH = 20, /*%< Not Authoritative */ + DNS_EDE_NOTSUPPORTED = 21, /*%< Not Supported */ + DNS_EDE_NOREACHABLEAUTH = 22, /*%< No Reachable Authority */ + DNS_EDE_NETWORKERROR = 23, /*%< Network Error */ + DNS_EDE_INVALIDDATA = 24, /*%< Invalid Data */ + DNS_EDE_MAX_CODE +}; /* * From RFC 8914: @@ -56,8 +57,6 @@ */ #define DNS_EDE_EXTRATEXT_LEN 64 -#define DNS_EDE_MAX_ERRORS 3 - typedef struct dns_edectx dns_edectx_t; struct dns_edectx { int magic; diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index bfda3fbb56..ef35346cb6 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -24,7 +24,6 @@ #include #include -#include #include #include @@ -90,46 +89,55 @@ * section, move rdata from one section to another, remove rdata, etc. */ -#define DNS_MESSAGEFLAG_QR 0x8000U -#define DNS_MESSAGEFLAG_AA 0x0400U -#define DNS_MESSAGEFLAG_TC 0x0200U -#define DNS_MESSAGEFLAG_RD 0x0100U -#define DNS_MESSAGEFLAG_RA 0x0080U -#define DNS_MESSAGEFLAG_AD 0x0020U -#define DNS_MESSAGEFLAG_CD 0x0010U +enum { + DNS_MESSAGEFLAG_QR = 0x8000U, + DNS_MESSAGEFLAG_AA = 0x0400U, + DNS_MESSAGEFLAG_TC = 0x0200U, + DNS_MESSAGEFLAG_RD = 0x0100U, + DNS_MESSAGEFLAG_RA = 0x0080U, + DNS_MESSAGEFLAG_AD = 0x0020U, + DNS_MESSAGEFLAG_CD = 0x0010U, +}; /*%< EDNS0 extended message flags */ -#define DNS_MESSAGEEXTFLAG_DO 0x8000U /* DNSSEC OK */ -#define DNS_MESSAGEEXTFLAG_CO 0x4000U /* Compact denial of existence OK */ +enum { + DNS_MESSAGEEXTFLAG_DO = 0x8000U, /* DNSSEC OK */ + DNS_MESSAGEEXTFLAG_CO = 0x4000U, /* Compact denial of existence OK */ +}; /*%< EDNS0 extended OPT codes */ -#define DNS_OPT_LLQ 1 /*%< LLQ opt code */ -#define DNS_OPT_UL 2 /*%< UL opt code */ -#define DNS_OPT_NSID 3 /*%< NSID opt code */ -#define DNS_OPT_DAU 5 /*%< DNSSEC algorithm understood */ -#define DNS_OPT_DHU 6 /*%< DNSSEC hash understood */ -#define DNS_OPT_N3U 7 /*%< NSEC3 hash understood */ -#define DNS_OPT_CLIENT_SUBNET 8 /*%< client subnet opt code */ -#define DNS_OPT_EXPIRE 9 /*%< EXPIRE opt code */ -#define DNS_OPT_COOKIE 10 /*%< COOKIE opt code */ -#define DNS_OPT_TCP_KEEPALIVE 11 /*%< TCP keepalive opt code */ -#define DNS_OPT_PAD 12 /*%< PAD opt code */ -#define DNS_OPT_CHAIN 13 /*%< CHAIN opt code */ -#define DNS_OPT_KEY_TAG 14 /*%< Key tag opt code */ -#define DNS_OPT_EDE 15 /*%< Extended DNS Error opt code */ -#define DNS_OPT_CLIENT_TAG 16 /*%< Client tag opt code */ -#define DNS_OPT_SERVER_TAG 17 /*%< Server tag opt code */ -#define DNS_OPT_REPORT_CHANNEL 18 /*%< DNS Reporting Channel */ -#define DNS_OPT_ZONEVERSION 19 /*%< Zoneversion opt code */ +enum { + DNS_OPT_LLQ = 1, /*%< LLQ opt code */ + DNS_OPT_UL = 2, /*%< UL opt code */ + DNS_OPT_NSID = 3, /*%< NSID opt code */ + DNS_OPT_DAU = 5, /*%< DNSSEC algorithm understood */ + DNS_OPT_DHU = 6, /*%< DNSSEC hash understood */ + DNS_OPT_N3U = 7, /*%< NSEC3 hash understood */ + DNS_OPT_CLIENT_SUBNET = 8, /*%< client subnet opt code */ + DNS_OPT_EXPIRE = 9, /*%< EXPIRE opt code */ + DNS_OPT_COOKIE = 10, /*%< COOKIE opt code */ + DNS_OPT_TCP_KEEPALIVE = 11, /*%< TCP keepalive opt code */ + DNS_OPT_PAD = 12, /*%< PAD opt code */ + DNS_OPT_CHAIN = 13, /*%< CHAIN opt code */ + DNS_OPT_KEY_TAG = 14, /*%< Key tag opt code */ + DNS_OPT_EDE = 15, /*%< Extended DNS Error opt code */ + DNS_OPT_CLIENT_TAG = 16, /*%< Client tag opt code */ + DNS_OPT_SERVER_TAG = 17, /*%< Server tag opt code */ + DNS_OPT_REPORT_CHANNEL = 18, /*%< DNS Reporting Channel */ + DNS_OPT_ZONEVERSION = 19, /*%< Zoneversion opt code */ + + DNS_OPT_COUNT = 18, /*%< Number of elements defined in this enum. */ +}; /*%< Experimental options [65001...65534] as per RFC6891 */ /*%< * The maximum number of EDNS options we allow to set. Reserve space for the - * options we know about. Extended DNS Errors may occur multiple times, see - * DNS_EDE_MAX_ERRORS. + * options we know about. Extended DNS Errors may occur multiple times, + * controlled by DNS_EDE_MAX_ERRORS. */ -#define DNS_EDNSOPTIONS 9 + DNS_EDE_MAX_ERRORS +#define DNS_EDE_MAX_ERRORS 3 +#define DNS_EDNS_MAX_OPTIONS DNS_OPT_COUNT + DNS_EDE_MAX_ERRORS #define DNS_MESSAGE_REPLYPRESERVE (DNS_MESSAGEFLAG_RD | DNS_MESSAGEFLAG_CD) #define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO) @@ -143,26 +151,32 @@ * Ordering here matters. DNS_SECTION_ANY must be the lowest and negative, * and DNS_SECTION_MAX must be one greater than the last used section. */ -typedef int dns_section_t; -#define DNS_SECTION_ANY (-1) -#define DNS_SECTION_QUESTION 0 -#define DNS_SECTION_ANSWER 1 -#define DNS_SECTION_AUTHORITY 2 -#define DNS_SECTION_ADDITIONAL 3 -#define DNS_SECTION_MAX 4 +typedef enum { + DNS_SECTION_ANY = -1, + DNS_SECTION_QUESTION = 0, + DNS_SECTION_ZONE = DNS_SECTION_QUESTION, + DNS_SECTION_ANSWER = 1, + DNS_SECTION_PREREQUISITE = DNS_SECTION_ANSWER, + DNS_SECTION_AUTHORITY = 2, + DNS_SECTION_UPDATE = DNS_SECTION_AUTHORITY, + DNS_SECTION_ADDITIONAL = 3, + DNS_SECTION_MAX +} dns_section_t; -typedef int dns_pseudosection_t; -#define DNS_PSEUDOSECTION_ANY (-1) -#define DNS_PSEUDOSECTION_OPT 0 -#define DNS_PSEUDOSECTION_TSIG 1 -#define DNS_PSEUDOSECTION_SIG0 2 -#define DNS_PSEUDOSECTION_MAX 3 +typedef enum { + DNS_PSEUDOSECTION_ANY = -1, + DNS_PSEUDOSECTION_OPT = 0, + DNS_PSEUDOSECTION_TSIG = 1, + DNS_PSEUDOSECTION_SIG0 = 2, + DNS_PSEUDOSECTION_MAX +} dns_pseudosection_t; -typedef int dns_messagetextflag_t; -#define DNS_MESSAGETEXTFLAG_NOCOMMENTS 0x0001 -#define DNS_MESSAGETEXTFLAG_NOHEADERS 0x0002 -#define DNS_MESSAGETEXTFLAG_ONESOA 0x0004 -#define DNS_MESSAGETEXTFLAG_OMITSOA 0x0008 +typedef enum { + DNS_MESSAGETEXTFLAG_NOCOMMENTS = 1 << 0, + DNS_MESSAGETEXTFLAG_NOHEADERS = 1 << 1, + DNS_MESSAGETEXTFLAG_ONESOA = 1 << 2, + DNS_MESSAGETEXTFLAG_OMITSOA = 1 << 3, +} dns_messagetextflag_t; /* * Dynamic update names for these sections. @@ -223,6 +237,12 @@ typedef struct dns_minttl { dns_ttl_t ttl; } dns_minttl_t; +struct dns_ednsopt { + uint16_t code; + uint16_t length; + uint8_t *value; +}; + struct dns_message { /* public from here down */ unsigned int magic; @@ -310,12 +330,15 @@ struct dns_message { dns_indent_t indent; dns_minttl_t minttl[DNS_SECTION_MAX]; -}; -struct dns_ednsopt { - uint16_t code; - uint16_t length; - uint8_t *value; + struct { + dns_ednsopt_t *opts; + uint8_t maxopts; + uint8_t count; + int16_t version; + uint16_t udpsize; + uint32_t flags; + } edns; }; typedef void (*dns_message_cb_t)(void *arg, isc_result_t result); @@ -1383,12 +1406,44 @@ dns_message_logpacketfromto(dns_message_t *message, const char *description, *\li 'mctx' to be a valid memory context. */ -isc_result_t -dns_message_buildopt(dns_message_t *msg, dns_rdataset_t **opt, - unsigned int version, uint16_t udpsize, unsigned int flags, - dns_ednsopt_t *ednsopts, size_t count); +void +dns_message_ednsinit(dns_message_t *msg, int16_t version, uint16_t udpsize, + uint32_t flags, uint8_t maxopts); /*%< - * Built a opt record. + * Initialize the EDNS data in 'msg'. EDNS version is set to 'version', + * UDP size is set to 'udpsize', flags is set to 'flags'; EDNS options + * are cleared, and ready to be added via subsequent calls to + * dns_message_ednsaddopt(). If 'maxopts' is nonzero, space is allocated + * for that many EDNS options; if it is zero, space is allocated for + * DNS_EDNS_MAX_OPTIONS options. + * + * If 'version' is -1, the message has no EDNS, any existing EDNS data + * is cleared, and no OPT record will be rendered. + * + * Requires: + *\li 'msg' be a valid message. + */ + +isc_result_t +dns_message_ednsaddopt(dns_message_t *msg, dns_ednsopt_t *ednsopt); +/*%< + * Add the EDNS option 'ednsopt' to 'msg->edns.opts' and increment + * 'msg->edns.count'. + * + * Requires: + *\li 'msg' to be a valid message. + *\li dns_message_ednsinit() to have been called. + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_NOSPACE + */ + +isc_result_t +dns_message_buildopt(dns_message_t *msg, dns_rdataset_t **opt); + +/*%< + * Build an opt record. * * Requires: *\li msg be a valid message. diff --git a/lib/dns/message.c b/lib/dns/message.c index f0f27a9d73..5951487af4 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -516,6 +516,23 @@ msgresetsigs(dns_message_t *msg, bool replying) { } } +static void +msgresetedns(dns_message_t *msg) { + if (msg->edns.opts != NULL) { + INSIST(msg->edns.maxopts != 0); + for (size_t i = 0; i < msg->edns.count; i++) { + if (msg->edns.opts[i].value != NULL) { + isc_mem_put(msg->mctx, msg->edns.opts[i].value, + msg->edns.opts[i].length); + } + } + isc_mem_cput(msg->mctx, msg->edns.opts, + (size_t)msg->edns.maxopts, sizeof(dns_ednsopt_t)); + } + msg->edns.maxopts = 0; + msg->edns.count = 0; +} + /* * Free all but one (or everything) for this message. This is used by * both dns_message_reset() and dns__message_destroy(). @@ -528,6 +545,7 @@ msgreset(dns_message_t *msg, bool everything) { msgresetnames(msg, 0); msgresetopt(msg); msgresetsigs(msg, false); + msgresetedns(msg); /* * Clean up linked lists. @@ -4062,6 +4080,8 @@ dns_message_pseudosectiontoyaml(dns_message_t *msg, dns_pseudosection_t section, ADD_STRING(target, "\n"); } goto cleanup; + default: + break; } result = ISC_R_UNEXPECTED; @@ -4483,6 +4503,8 @@ dns_message_pseudosectiontotext(dns_message_t *msg, dns_pseudosection_t section, ADD_STRING(target, "\n"); } return result; + default: + break; } result = ISC_R_UNEXPECTED; cleanup: @@ -4825,15 +4847,62 @@ logfmtpacket(dns_message_t *message, const char *description, } } +void +dns_message_ednsinit(dns_message_t *msg, int16_t version, uint16_t udpsize, + uint32_t flags, uint8_t maxopts) { + REQUIRE(DNS_MESSAGE_VALID(msg)); + + /* Clear existing EDNS data */ + msgresetedns(msg); + + msg->edns.version = version; + if (version == -1) { + return; + } + + if (maxopts == 0) { + maxopts = DNS_EDNS_MAX_OPTIONS; + } + + msg->edns.flags = flags; + msg->edns.udpsize = udpsize; + msg->edns.opts = isc_mem_cget(msg->mctx, (size_t)maxopts, + sizeof(dns_ednsopt_t)); + msg->edns.maxopts = maxopts; +} + isc_result_t -dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp, - unsigned int version, uint16_t udpsize, unsigned int flags, - dns_ednsopt_t *ednsopts, size_t count) { +dns_message_ednsaddopt(dns_message_t *msg, dns_ednsopt_t *option) { + REQUIRE(DNS_MESSAGE_VALID(msg)); + REQUIRE(msg->edns.opts != NULL); + + if (msg->edns.count >= msg->edns.maxopts) { + isc_log_write(ISC_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MESSAGE, + ISC_LOG_DEBUG(3), + "dns_message_ednsaddopt: limit of %u EDNS " + "options exceeded", + msg->edns.maxopts); + return ISC_R_NOSPACE; + } + + size_t i = msg->edns.count; + msg->edns.opts[i].code = option->code; + if (option->value != NULL) { + msg->edns.opts[i].value = isc_mem_get(msg->mctx, + option->length); + memmove(msg->edns.opts[i].value, option->value, option->length); + msg->edns.opts[i].length = option->length; + } + msg->edns.count++; + return ISC_R_SUCCESS; +} + +isc_result_t +dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp) { dns_rdataset_t *rdataset = NULL; dns_rdatalist_t *rdatalist = NULL; dns_rdata_t *rdata = NULL; isc_result_t result; - unsigned int len = 0, i; REQUIRE(DNS_MESSAGE_VALID(message)); REQUIRE(rdatasetp != NULL && *rdatasetp == NULL); @@ -4847,22 +4916,24 @@ dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp, /* * Set Maximum UDP buffer size. */ - rdatalist->rdclass = udpsize; + rdatalist->rdclass = message->edns.udpsize; /* * Set EXTENDED-RCODE and Z to 0. */ - rdatalist->ttl = (version << 16); - rdatalist->ttl |= (flags & 0xffff); + rdatalist->ttl = (message->edns.version << 16); + rdatalist->ttl |= (message->edns.flags & 0xffff); /* * Set EDNS options if applicable */ - if (count != 0U) { + if (message->edns.count != 0U) { isc_buffer_t *buf = NULL; bool seenpad = false; - for (i = 0; i < count; i++) { - len += ednsopts[i].length + 4; + size_t len = 0; + + for (size_t i = 0; i < message->edns.count; i++) { + len += message->edns.opts[i].length + 4; } if (len > 0xffffU) { @@ -4872,18 +4943,19 @@ dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp, isc_buffer_allocate(message->mctx, &buf, len); - for (i = 0; i < count; i++) { - if (ednsopts[i].code == DNS_OPT_PAD && - ednsopts[i].length == 0U && !seenpad) + for (size_t i = 0; i < message->edns.count; i++) { + if (message->edns.opts[i].code == DNS_OPT_PAD && + message->edns.opts[i].length == 0U && !seenpad) { seenpad = true; continue; } - isc_buffer_putuint16(buf, ednsopts[i].code); - isc_buffer_putuint16(buf, ednsopts[i].length); - if (ednsopts[i].length != 0) { - isc_buffer_putmem(buf, ednsopts[i].value, - ednsopts[i].length); + isc_buffer_putuint16(buf, message->edns.opts[i].code); + isc_buffer_putuint16(buf, message->edns.opts[i].length); + if (message->edns.opts[i].length != 0) { + isc_buffer_putmem(buf, + message->edns.opts[i].value, + message->edns.opts[i].length); } } diff --git a/lib/dns/rdata.c b/lib/dns/rdata.c index 8ec43e0bd2..5fd872fe3f 100644 --- a/lib/dns/rdata.c +++ b/lib/dns/rdata.c @@ -2443,6 +2443,8 @@ dns_rdata_updateop(dns_rdata_t *rdata, dns_section_t section) { default: return "add"; } + default: + break; } return "invalid"; } diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index c698edf742..86efcb0078 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -1831,20 +1831,6 @@ detach: resquery_detach(&query); } -static isc_result_t -fctx_addopt(dns_message_t *message, unsigned int version, uint16_t udpsize, - dns_ednsopt_t *ednsopts, size_t count) { - dns_rdataset_t *rdataset = NULL; - isc_result_t result; - - result = dns_message_buildopt(message, &rdataset, version, udpsize, - DNS_MESSAGEEXTFLAG_DO, ednsopts, count); - if (result != ISC_R_SUCCESS) { - return result; - } - return dns_message_setopt(message, rdataset); -} - static void fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) { unsigned int seconds, us; @@ -2328,8 +2314,6 @@ resquery_send(resquery_t *query) { dns_compress_t cctx; bool useedns; bool tcp = ((query->options & DNS_FETCHOPT_TCP) != 0); - dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS]; - unsigned int ednsopt = 0; uint16_t hint = 0, udpsize = 0; /* No EDNS */ isc_sockaddr_t localaddr, *la = NULL; #ifdef HAVE_DNSTAP @@ -2480,6 +2464,7 @@ resquery_send(resquery_t *query) { bool tcpkeepalive = false; unsigned char cookie[COOKIE_BUFFER_SIZE]; uint16_t padding = 0; + dns_rdataset_t *rdataset = NULL; /* * Set the default UDP size to what was @@ -2534,43 +2519,57 @@ resquery_send(resquery_t *query) { if (NOCOOKIE(query->addrinfo)) { sendcookie = false; } + + query->ednsversion = version; + dns_message_ednsinit(fctx->qmessage, version, udpsize, + DNS_MESSAGEEXTFLAG_DO, 0); + if (reqnsid) { - INSIST(ednsopt < DNS_EDNSOPTIONS); - ednsopts[ednsopt].code = DNS_OPT_NSID; - ednsopts[ednsopt].length = 0; - ednsopts[ednsopt].value = NULL; - ednsopt++; + dns_ednsopt_t option = { + .code = DNS_OPT_NSID, + }; + result = dns_message_ednsaddopt(fctx->qmessage, + &option); + if (result != ISC_R_SUCCESS) { + goto cleanup_message; + } } if (reqzoneversion) { - INSIST(ednsopt < DNS_EDNSOPTIONS); - ednsopts[ednsopt].code = DNS_OPT_ZONEVERSION; - ednsopts[ednsopt].length = 0; - ednsopts[ednsopt].value = NULL; - ednsopt++; + dns_ednsopt_t option = { + .code = DNS_OPT_ZONEVERSION, + }; + result = dns_message_ednsaddopt(fctx->qmessage, + &option); + if (result != ISC_R_SUCCESS) { + goto cleanup_message; + } } if (sendcookie) { - INSIST(ednsopt < DNS_EDNSOPTIONS); - ednsopts[ednsopt].code = DNS_OPT_COOKIE; - ednsopts[ednsopt].length = - (uint16_t)dns_adb_getcookie( - query->addrinfo, cookie, - sizeof(cookie)); - if (ednsopts[ednsopt].length != 0) { - ednsopts[ednsopt].value = cookie; + dns_ednsopt_t option = { + .code = DNS_OPT_COOKIE, + }; + option.length = (uint16_t)dns_adb_getcookie( + query->addrinfo, cookie, + sizeof(cookie)); + if (option.length != 0) { + option.value = cookie; inc_stats( fctx->res, dns_resstatscounter_cookieout); } else { compute_cc(query, cookie, CLIENT_COOKIE_SIZE); - ednsopts[ednsopt].value = cookie; - ednsopts[ednsopt].length = - CLIENT_COOKIE_SIZE; + option.value = cookie; + option.length = CLIENT_COOKIE_SIZE; inc_stats( fctx->res, dns_resstatscounter_cookienew); } - ednsopt++; + result = dns_message_ednsaddopt(fctx->qmessage, + &option); + if (result != ISC_R_SUCCESS) { + goto cleanup_message; + } } /* Add TCP keepalive option if appropriate */ @@ -2579,11 +2578,14 @@ resquery_send(resquery_t *query) { &tcpkeepalive); } if (tcpkeepalive) { - INSIST(ednsopt < DNS_EDNSOPTIONS); - ednsopts[ednsopt].code = DNS_OPT_TCP_KEEPALIVE; - ednsopts[ednsopt].length = 0; - ednsopts[ednsopt].value = NULL; - ednsopt++; + dns_ednsopt_t option = { + .code = DNS_OPT_TCP_KEEPALIVE, + }; + result = dns_message_ednsaddopt(fctx->qmessage, + &option); + if (result != ISC_R_SUCCESS) { + goto cleanup_message; + } } /* Add PAD for current peer? Require TCP for now @@ -2592,16 +2594,24 @@ resquery_send(resquery_t *query) { (void)dns_peer_getpadding(peer, &padding); } if (padding != 0) { - INSIST(ednsopt < DNS_EDNSOPTIONS); - ednsopts[ednsopt].code = DNS_OPT_PAD; - ednsopts[ednsopt].length = 0; - ednsopt++; + dns_ednsopt_t option = { + .code = DNS_OPT_PAD, + }; + result = dns_message_ednsaddopt(fctx->qmessage, + &option); + if (result != ISC_R_SUCCESS) { + goto cleanup_message; + } dns_message_setpadding(fctx->qmessage, padding); } - query->ednsversion = version; - result = fctx_addopt(fctx->qmessage, version, udpsize, - ednsopts, ednsopt); + result = dns_message_buildopt(fctx->qmessage, + &rdataset); + if (result == ISC_R_SUCCESS) { + result = dns_message_setopt(fctx->qmessage, + rdataset); + } + if (result == ISC_R_SUCCESS) { if (reqnsid) { query->options |= DNS_FETCHOPT_WANTNSID; @@ -2610,7 +2620,7 @@ resquery_send(resquery_t *query) { query->options |= DNS_FETCHOPT_WANTZONEVERSION; } - } else if (result != ISC_R_SUCCESS) { + } else { /* * We couldn't add the OPT, but we'll * press on. We're not using EDNS0, so diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c index e1389f0422..e06b466f28 100644 --- a/lib/dns/xfrin.c +++ b/lib/dns/xfrin.c @@ -1553,26 +1553,26 @@ add_opt(dns_message_t *message, uint16_t udpsize, bool reqnsid, bool reqexpire) { isc_result_t result; dns_rdataset_t *rdataset = NULL; - dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS]; - int count = 0; + + dns_message_ednsinit(message, 0, udpsize, 0, 0); /* Set EDNS options if applicable. */ if (reqnsid) { - INSIST(count < DNS_EDNSOPTIONS); - ednsopts[count].code = DNS_OPT_NSID; - ednsopts[count].length = 0; - ednsopts[count].value = NULL; - count++; + dns_ednsopt_t option = { .code = DNS_OPT_NSID }; + result = dns_message_ednsaddopt(message, &option); + if (result != ISC_R_SUCCESS) { + return result; + } } if (reqexpire) { - INSIST(count < DNS_EDNSOPTIONS); - ednsopts[count].code = DNS_OPT_EXPIRE; - ednsopts[count].length = 0; - ednsopts[count].value = NULL; - count++; + dns_ednsopt_t option = { .code = DNS_OPT_EXPIRE }; + result = dns_message_ednsaddopt(message, &option); + if (result != ISC_R_SUCCESS) { + return result; + } } - result = dns_message_buildopt(message, &rdataset, 0, udpsize, 0, - ednsopts, count); + + result = dns_message_buildopt(message, &rdataset); if (result != ISC_R_SUCCESS) { return result; } diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 7c650805e0..8850844682 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -12863,26 +12863,26 @@ add_opt(dns_message_t *message, uint16_t udpsize, bool reqnsid, bool reqexpire) { isc_result_t result; dns_rdataset_t *rdataset = NULL; - dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS]; - int count = 0; + + dns_message_ednsinit(message, 0, udpsize, 0, 0); /* Set EDNS options if applicable. */ if (reqnsid) { - INSIST(count < DNS_EDNSOPTIONS); - ednsopts[count].code = DNS_OPT_NSID; - ednsopts[count].length = 0; - ednsopts[count].value = NULL; - count++; + dns_ednsopt_t option = { .code = DNS_OPT_NSID }; + result = dns_message_ednsaddopt(message, &option); + if (result != ISC_R_SUCCESS) { + return result; + } } if (reqexpire) { - INSIST(count < DNS_EDNSOPTIONS); - ednsopts[count].code = DNS_OPT_EXPIRE; - ednsopts[count].length = 0; - ednsopts[count].value = NULL; - count++; + dns_ednsopt_t option = { .code = DNS_OPT_EXPIRE }; + result = dns_message_ednsaddopt(message, &option); + if (result != ISC_R_SUCCESS) { + return result; + } } - result = dns_message_buildopt(message, &rdataset, 0, udpsize, 0, - ednsopts, count); + + result = dns_message_buildopt(message, &rdataset); if (result != ISC_R_SUCCESS) { return result; } diff --git a/lib/ns/client.c b/lib/ns/client.c index 0bd85a7c27..054bfc8deb 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -1056,13 +1056,10 @@ isc_result_t ns_client_addopt(ns_client_t *client, dns_message_t *message, dns_rdataset_t **opt) { unsigned char ecs[ECS_SIZE]; - char nsid[_POSIX_HOST_NAME_MAX + 1], *nsidp = NULL; unsigned char cookie[COOKIE_SIZE]; isc_result_t result; dns_view_t *view = NULL; uint16_t udpsize; - dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS]; - int count = 0; unsigned int flags; unsigned char expire[4]; unsigned char advtimo[2]; @@ -1082,26 +1079,33 @@ ns_client_addopt(ns_client_t *client, dns_message_t *message, flags = client->inner.extflags & DNS_MESSAGEEXTFLAG_REPLYPRESERVE; + dns_message_ednsinit(message, 0, udpsize, flags, 0); + /* Set EDNS options if applicable */ if (WANTNSID(client)) { + char nsid[_POSIX_HOST_NAME_MAX + 1]; + char *nsidp = NULL; + if (client->manager->sctx->server_id != NULL) { nsidp = client->manager->sctx->server_id; - } else if (client->manager->sctx->usehostname) { - if (gethostname(nsid, sizeof(nsid)) != 0) { - goto no_nsid; - } + } else if (client->manager->sctx->usehostname && + gethostname(nsid, sizeof(nsid)) == 0) + { nsidp = nsid; - } else { - goto no_nsid; } - - INSIST(count < DNS_EDNSOPTIONS); - ednsopts[count].code = DNS_OPT_NSID; - ednsopts[count].length = (uint16_t)strlen(nsidp); - ednsopts[count].value = (unsigned char *)nsidp; - count++; + if (nsidp != NULL) { + dns_ednsopt_t option = { + .code = DNS_OPT_NSID, + .value = (unsigned char *)nsidp, + .length = (uint16_t)strlen(nsidp), + }; + result = dns_message_ednsaddopt(message, &option); + if (result != ISC_R_SUCCESS) { + return result; + } + } } -no_nsid: + if ((client->inner.attributes & NS_CLIENTATTR_WANTCOOKIE) != 0) { isc_buffer_t buf; isc_stdtime_t now = isc_stdtime_now(); @@ -1111,24 +1115,30 @@ no_nsid: compute_cookie(client, now, client->manager->sctx->secret, &buf); - INSIST(count < DNS_EDNSOPTIONS); - ednsopts[count].code = DNS_OPT_COOKIE; - ednsopts[count].length = COOKIE_SIZE; - ednsopts[count].value = cookie; - count++; + dns_ednsopt_t option = { .code = DNS_OPT_COOKIE, + .length = COOKIE_SIZE, + .value = cookie }; + result = dns_message_ednsaddopt(message, &option); + if (result != ISC_R_SUCCESS) { + return result; + } } + if ((client->inner.attributes & NS_CLIENTATTR_HAVEEXPIRE) != 0) { isc_buffer_t buf; - INSIST(count < DNS_EDNSOPTIONS); - isc_buffer_init(&buf, expire, sizeof(expire)); isc_buffer_putuint32(&buf, client->inner.expire); - ednsopts[count].code = DNS_OPT_EXPIRE; - ednsopts[count].length = 4; - ednsopts[count].value = expire; - count++; + + dns_ednsopt_t option = { .code = DNS_OPT_EXPIRE, + .value = expire, + .length = 4 }; + result = dns_message_ednsaddopt(message, &option); + if (result != ISC_R_SUCCESS) { + return result; + } } + if (((client->inner.attributes & NS_CLIENTATTR_HAVEECS) != 0) && (client->inner.ecs.addr.family == AF_INET || client->inner.ecs.addr.family == AF_INET6 || @@ -1182,24 +1192,30 @@ no_nsid: isc_buffer_putmem(&buf, addr, (unsigned int)addrl); } - ednsopts[count].code = DNS_OPT_CLIENT_SUBNET; - ednsopts[count].length = addrl + 4; - ednsopts[count].value = ecs; - count++; + dns_ednsopt_t option = { .code = DNS_OPT_CLIENT_SUBNET, + .length = addrl + 4, + .value = ecs }; + result = dns_message_ednsaddopt(message, &option); + if (result != ISC_R_SUCCESS) { + return result; + } } - if (TCP_CLIENT(client) && USEKEEPALIVE(client)) { - isc_buffer_t buf; - uint32_t advertised_timeout = isc_nm_getadvertisedtimeout(); - INSIST(count < DNS_EDNSOPTIONS); + if (TCP_CLIENT(client) && USEKEEPALIVE(client)) { + uint32_t advertised_timeout = isc_nm_getadvertisedtimeout(); + isc_buffer_t buf; advertised_timeout /= 100; /* units of 100 milliseconds */ isc_buffer_init(&buf, advtimo, sizeof(advtimo)); isc_buffer_putuint16(&buf, (uint16_t)advertised_timeout); - ednsopts[count].code = DNS_OPT_TCP_KEEPALIVE; - ednsopts[count].length = 2; - ednsopts[count].value = advtimo; - count++; + + dns_ednsopt_t option = { .code = DNS_OPT_TCP_KEEPALIVE, + .length = 2, + .value = advtimo }; + result = dns_message_ednsaddopt(message, &option); + if (result != ISC_R_SUCCESS) { + return result; + } } for (size_t i = 0; i < DNS_EDE_MAX_ERRORS; i++) { @@ -1209,18 +1225,24 @@ no_nsid: break; } - INSIST(count < DNS_EDNSOPTIONS); - ednsopts[count].code = DNS_OPT_EDE; - ednsopts[count].length = ede->length; - ednsopts[count].value = ede->value; - count++; + dns_ednsopt_t option = { .code = DNS_OPT_EDE, + .length = ede->length, + .value = ede->value }; + result = dns_message_ednsaddopt(message, &option); + if (result != ISC_R_SUCCESS) { + return result; + } } if ((client->inner.attributes & NS_CLIENTATTR_HAVEZONEVERSION) != 0) { - INSIST(count < DNS_EDNSOPTIONS); - ednsopts[count].code = DNS_OPT_ZONEVERSION; - ednsopts[count].length = client->inner.zoneversionlength; - ednsopts[count].value = client->inner.zoneversion; - count++; + dns_ednsopt_t option = { + .code = DNS_OPT_ZONEVERSION, + .length = client->inner.zoneversionlength, + .value = client->inner.zoneversion + }; + result = dns_message_ednsaddopt(message, &option); + if (result != ISC_R_SUCCESS) { + return result; + } } if (WANTRC(client)) { @@ -1229,11 +1251,15 @@ no_nsid: rad = &client->inner.rad; } if (rad != NULL && !dns_name_equal(rad, dns_rootname)) { - INSIST(count < DNS_EDNSOPTIONS); - ednsopts[count].code = DNS_OPT_REPORT_CHANNEL; - ednsopts[count].length = rad->length; - ednsopts[count].value = rad->ndata; - count++; + dns_ednsopt_t option = { + .code = DNS_OPT_REPORT_CHANNEL, + .length = rad->length, + .value = rad->ndata, + }; + result = dns_message_ednsaddopt(message, &option); + if (result != ISC_R_SUCCESS) { + return result; + } } } @@ -1249,19 +1275,14 @@ no_nsid: result = dns_acl_match(&netaddr, NULL, view->pad_acl, env, &match, NULL); if (result == ISC_R_SUCCESS && match > 0) { - INSIST(count < DNS_EDNSOPTIONS); - - ednsopts[count].code = DNS_OPT_PAD; - ednsopts[count].length = 0; - ednsopts[count].value = NULL; - count++; - + dns_ednsopt_t option = { .code = DNS_OPT_PAD }; + /* This can fail harmlessly */ + dns_message_ednsaddopt(message, &option); dns_message_setpadding(message, view->padding); } } - result = dns_message_buildopt(message, opt, 0, udpsize, flags, ednsopts, - count); + result = dns_message_buildopt(message, opt); return result; }