]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add method to set extended DNS error
authorMatthijs Mekking <matthijs@isc.org>
Sat, 6 Mar 2021 14:43:00 +0000 (15:43 +0100)
committerMatthijs Mekking <matthijs@isc.org>
Fri, 19 Nov 2021 08:44:28 +0000 (09:44 +0100)
Add a new parameter to 'ns_client_t' to store potential extended DNS
error. Reset when the client request ends, or is put back.

Add defines for all well-known info-codes.

Update the number of DNS_EDNSOPTIONS that we are willing to set.

Create a new function to set the extended error for a client reply.

lib/dns/include/dns/message.h
lib/ns/client.c
lib/ns/include/ns/client.h

index 864306b78310519ee61bd47ff0d6ffcd1f11f6a4..9fd979a7c3025259ebb68730d5af54dedaa85175 100644 (file)
 
 /*%< Experimental options [65001...65534] as per RFC6891 */
 
-/*%< The number of EDNS options we know about. */
-#define DNS_EDNSOPTIONS 7
+/*%<
+ * 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, but we
+ * will set only one per message (for now).
+ */
+#define DNS_EDNSOPTIONS 8
+
+/*%< 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 */
+
+/*
+ * From RFC 8914:
+ * Because long EXTRA-TEXT fields may trigger truncation (which is undesirable
+ * given the supplemental nature of EDE), implementers and operators creating
+ * EDE options SHOULD avoid lengthy EXTRA-TEXT contents.
+ *
+ * Following this advice we limit the EXTRA-TEXT length to 64 characters.
+ */
+#define DNS_EDE_EXTRATEXT_LEN 64
 
 #define DNS_MESSAGE_REPLYPRESERVE       (DNS_MESSAGEFLAG_RD | DNS_MESSAGEFLAG_CD)
 #define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO)
index 233a9dfade161192bbce61fcfe41e2519e907f10..a35f06a13120069db0c3416af677ae75016f7a9d 100644 (file)
@@ -163,6 +163,56 @@ ns_client_settimeout(ns_client_t *client, unsigned int seconds) {
        /* XXXWPK TODO use netmgr to set timeout */
 }
 
+static void
+client_extendederror_reset(ns_client_t *client) {
+       if (client->ede == NULL) {
+               return;
+       }
+       isc_mem_put(client->mctx, client->ede->value, client->ede->length);
+       isc_mem_put(client->mctx, client->ede, sizeof(dns_ednsopt_t));
+       client->ede = NULL;
+}
+
+void
+ns_client_extendederror(ns_client_t *client, uint16_t code, const char *text) {
+       unsigned char ede[DNS_EDE_EXTRATEXT_LEN + 2];
+       isc_buffer_t buf;
+       uint16_t len = sizeof(uint16_t);
+
+       REQUIRE(NS_CLIENT_VALID(client));
+
+       if (client->ede != NULL) {
+               ns_client_log(client, NS_LOGCATEGORY_CLIENT,
+                             NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
+                             "already have ede, ignoring %u %s", code,
+                             text == NULL ? "(null)" : text);
+               return;
+       }
+
+       ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT,
+                     ISC_LOG_DEBUG(1), "set ede: info-code %u extra-text %s",
+                     code, text == NULL ? "(null)" : text);
+
+       isc_buffer_init(&buf, ede, sizeof(ede));
+       isc_buffer_putuint16(&buf, code);
+       if (text != NULL && strlen(text) > 0) {
+               if (strlen(text) < DNS_EDE_EXTRATEXT_LEN) {
+                       isc_buffer_putstr(&buf, text);
+                       len += (uint16_t)(strlen(text));
+               } else {
+                       ns_client_log(client, NS_LOGCATEGORY_CLIENT,
+                                     NS_LOGMODULE_CLIENT, ISC_LOG_WARNING,
+                                     "ede extra-text too long, ignoring");
+               }
+       }
+
+       client->ede = isc_mem_get(client->mctx, sizeof(dns_ednsopt_t));
+       client->ede->code = DNS_OPT_EDE;
+       client->ede->length = len;
+       client->ede->value = isc_mem_get(client->mctx, len);
+       memmove(client->ede->value, ede, len);
+};
+
 static void
 ns_client_endrequest(ns_client_t *client) {
        INSIST(client->nupdates == 0);
@@ -200,6 +250,7 @@ ns_client_endrequest(ns_client_t *client) {
                dns_message_puttemprdataset(client->message, &client->opt);
        }
 
+       client_extendederror_reset(client);
        client->signer = NULL;
        client->udpsize = 512;
        client->extflags = 0;
@@ -1062,6 +1113,14 @@ no_nsid:
                count++;
        }
 
+       if (client->ede != NULL) {
+               INSIST(count < DNS_EDNSOPTIONS);
+               ednsopts[count].code = DNS_OPT_EDE;
+               ednsopts[count].length = client->ede->length;
+               ednsopts[count].value = client->ede->value;
+               count++;
+       }
+
        /* Padding must be added last */
        if ((view != NULL) && (view->padding > 0) && WANTPAD(client) &&
            (TCP_CLIENT(client) ||
@@ -1607,6 +1666,7 @@ ns__client_put_cb(void *client0) {
                dns_rdataset_disassociate(client->opt);
                dns_message_puttemprdataset(client->message, &client->opt);
        }
+       client_extendederror_reset(client);
 
        dns_message_detach(&client->message);
 
@@ -1877,6 +1937,7 @@ ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult,
        }
 
        client->message->rcode = dns_rcode_noerror;
+       client->ede = NULL;
 
        /*
         * Deal with EDNS.
index 685be677d3f8780a28dfb357a3b034ecdbb08b0d..01eb8e212a017913bc8572498ff371697326e82f 100644 (file)
@@ -190,6 +190,7 @@ struct ns_client {
        dns_message_t  *message;
        unsigned char  *sendbuf;
        dns_rdataset_t *opt;
+       dns_ednsopt_t  *ede;
        uint16_t        udpsize;
        uint16_t        extflags;
        int16_t         ednsversion; /* -1 noedns */
@@ -311,6 +312,12 @@ ns_client_error(ns_client_t *client, isc_result_t result);
  * will have an RCODE determined by 'result'.
  */
 
+void
+ns_client_extendederror(ns_client_t *client, uint16_t code, const char *text);
+/*%<
+ * Set extended error with INFO-CODE <code> and EXTRA-TEXT <text>.
+ */
+
 void
 ns_client_drop(ns_client_t *client, isc_result_t result);
 /*%<