/*%< 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)
/* 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);
dns_message_puttemprdataset(client->message, &client->opt);
}
+ client_extendederror_reset(client);
client->signer = NULL;
client->udpsize = 512;
client->extflags = 0;
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) ||
dns_rdataset_disassociate(client->opt);
dns_message_puttemprdataset(client->message, &client->opt);
}
+ client_extendederror_reset(client);
dns_message_detach(&client->message);
}
client->message->rcode = dns_rcode_noerror;
+ client->ede = NULL;
/*
* Deal with EDNS.