]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
add dns_message API to add EDNS options
authorEvan Hunt <each@isc.org>
Wed, 19 Nov 2025 07:29:12 +0000 (23:29 -0800)
committerEvan Hunt <each@isc.org>
Fri, 21 Nov 2025 19:13:18 +0000 (11:13 -0800)
The new dns_message_ednsinit() and dns_message_ednsaddopt() functions
allow EDNS options to be added to a message one at a time; it is no
longer necessary to construct a full array of EDNS options and set
them all at once.

This allows us to simplify EDNS option handling code, and in the
future it wlil allow plugins to add EDNS options to existing
messages.

14 files changed:
bin/delv/delv.c
bin/dig/dighost.c
bin/dig/nslookup.c
bin/nsupdate/nsupdate.c
bin/tools/mdig.c
lib/dns/ede.c
lib/dns/include/dns/ede.h
lib/dns/include/dns/message.h
lib/dns/message.c
lib/dns/rdata.c
lib/dns/resolver.c
lib/dns/xfrin.c
lib/dns/zone.c
lib/ns/client.c

index f462a13c1656611e9dae8e0f74f716d7b9f3b7b0..a4c262b53e3e1c36a16e0ded04d719b0158d296f 100644 (file)
@@ -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,
index 12209c8e6a76d4bf545e67696722d511469593b6..1499761f789e4f5eba13f6f30c0d7d02ea38e516 100644 (file)
@@ -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,
index d5ec48464d03d5fc2682b6585daaf096aa664de1..177cdeba6d4dbdc1ebe395b6598285dd2c7eff27 100644 (file)
@@ -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();
                }
        }
 
index 4ceff5646617fa7db4646101a84dcc0cb092d8c9..f0f1a613a94f4f90bab165629e8cf75f824973f5 100644 (file)
@@ -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 (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");
+       if (!lease_set) {
+               return;
        }
+
+       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
index ddfddee46debdcb3e4f8e772e525af4c7c513e9a..2f4e79b20e3c22a07f9df5554b3c7c2470c5f163 100644 (file)
@@ -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) {
index af7cc0b57f7c6b4c842bb3619a93525b900face7..48fc153188696647bc901b18b122f645d7410b02 100644 (file)
@@ -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;
index 37194dd5ef08fdb58c40d00734f4b19ef687515b..a9470306cb6e496dd795153ff0b76df092c0f30a 100644 (file)
 #include <dns/message.h>
 
 /*%< 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;
index bfda3fbb56c7c96d5d882e94d356e57462a8b63d..ef35346cb6f75e5ac7643302c59b064274724a89 100644 (file)
@@ -24,7 +24,6 @@
 #include <isc/refcount.h>
 
 #include <dns/compress.h>
-#include <dns/ede.h>
 #include <dns/masterdump.h>
 #include <dns/types.h>
 
  * 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)
  * 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 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 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_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 enum {
+       DNS_PSEUDOSECTION_ANY = -1,
+       DNS_PSEUDOSECTION_OPT = 0,
+       DNS_PSEUDOSECTION_TSIG = 1,
+       DNS_PSEUDOSECTION_SIG0 = 2,
+       DNS_PSEUDOSECTION_MAX
+} dns_pseudosection_t;
+
+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.
  */
 
+void
+dns_message_ednsinit(dns_message_t *msg, int16_t version, uint16_t udpsize,
+                    uint32_t flags, uint8_t maxopts);
+/*%<
+ * 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,
-                    unsigned int version, uint16_t udpsize, unsigned int flags,
-                    dns_ednsopt_t *ednsopts, size_t count);
+dns_message_buildopt(dns_message_t *msg, dns_rdataset_t **opt);
+
 /*%<
- * Built a opt record.
+ * Build an opt record.
  *
  * Requires:
  *\li  msg be a valid message.
index f0f27a9d73335b70145b63dd31be2dd3bde9866f..5951487af49b9b807f38d59f1b528e7a21a075c3 100644 (file)
@@ -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);
                        }
                }
 
index 8ec43e0bd28c6a2704c8133b077f5f54f2311c26..5fd872fe3f8d13f5543cd83630004bbfc2effe37 100644 (file)
@@ -2443,6 +2443,8 @@ dns_rdata_updateop(dns_rdata_t *rdata, dns_section_t section) {
                default:
                        return "add";
                }
+       default:
+               break;
        }
        return "invalid";
 }
index c698edf742b77244d3c7549aa7ad1d9768b65b70..86efcb0078626f8b9ad521350ed2a676f877d8ac 100644 (file)
@@ -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
index e1389f0422dee76d55c9de3a1e6d6bcc8a10d7e9..e06b466f28f6234f107dec5a1102ec7871b93c5d 100644 (file)
@@ -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++;
-       }
-       result = dns_message_buildopt(message, &rdataset, 0, udpsize, 0,
-                                     ednsopts, 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);
        if (result != ISC_R_SUCCESS) {
                return result;
        }
index 7c650805e02555239db3f4751644a4660b3166d2..8850844682a60d0c549e6d5d06bb0d540cd0c4e1 100644 (file)
@@ -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;
        }
index 0bd85a7c278bdd3af388279264224365438d31c5..054bfc8deb4b42fe5cc9bb885fa120f62d0ab5ae 100644 (file)
@@ -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);
+               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;
 }