diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index 864306b783..9fd979a7c3 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -112,8 +112,49 @@ /*%< 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) diff --git a/lib/ns/client.c b/lib/ns/client.c index 233a9dfade..a35f06a131 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -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. diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index 685be677d3..01eb8e212a 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -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 and EXTRA-TEXT . + */ + void ns_client_drop(ns_client_t *client, isc_result_t result); /*%<