diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index c7ebf49591..e8ea327ba0 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -125,10 +125,10 @@ /*%< * 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). + * options we know about. Extended DNS Errors may occur multiple times, see + * DNS_EDE_MAX_ERRORS. */ -#define DNS_EDNSOPTIONS 9 +#define DNS_EDNSOPTIONS 8 + DNS_EDE_MAX_ERRORS /*%< EDNS0 extended DNS errors */ #define DNS_EDE_OTHER 0 /*%< Other Error */ @@ -176,6 +176,8 @@ typedef ISC_LIST(dns_ede_t) dns_edelist_t; */ #define DNS_EDE_EXTRATEXT_LEN 64 +#define DNS_EDE_MAX_ERRORS 3 + #define DNS_MESSAGE_REPLYPRESERVE (DNS_MESSAGEFLAG_RD | DNS_MESSAGEFLAG_CD) #define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO) diff --git a/lib/dns/message.c b/lib/dns/message.c index c7441071a8..28b3de2387 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -5088,19 +5088,9 @@ dns_ede_append(isc_mem_t *mctx, dns_edelist_t *list, uint16_t info_code, }; if (extra_text) { - size_t len = strlen(extra_text); - - if (len >= DNS_EDE_EXTRATEXT_LEN) { - isc_log_write(DNS_LOGCATEGORY_GENERAL, - DNS_LOGMODULE_MESSAGE, ISC_LOG_PRINTTIME, - "truncate EDE code %hu text: %s", - info_code, extra_text); - len = DNS_EDE_EXTRATEXT_LEN - 1; - } - - ede->extra_text = isc_mem_allocate(mctx, len + 1); - strncpy(ede->extra_text, extra_text, len); - ede->extra_text[len] = '\0'; + ede->extra_text = isc_mem_allocate(mctx, + strlen(extra_text) + 1); + strcpy(ede->extra_text, extra_text); } ISC_LIST_APPEND(*list, ede, link); diff --git a/lib/ns/client.c b/lib/ns/client.c index b1502dee48..a330f663cb 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -220,27 +220,54 @@ ns_client_settimeout(ns_client_t *client, unsigned int seconds) { static void client_extendederror_reset(ns_client_t *client) { - if (client->ede == NULL) { - return; + for (size_t i = 0; i < DNS_EDE_MAX_ERRORS; i++) { + if (client->ede[i]) { + dns_ednsopt_t *ede = client->ede[i]; + + isc_mem_put(client->manager->mctx, ede->value, + ede->length); + isc_mem_put(client->manager->mctx, ede, sizeof(*ede)); + client->ede[i] = NULL; + } } - isc_mem_put(client->manager->mctx, client->ede->value, - client->ede->length); - isc_mem_put(client->manager->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); + const uint16_t codelen = sizeof(code); + uint16_t textlen = 0; + size_t pos = 0; + unsigned char *ede = NULL; + dns_ednsopt_t *edns = NULL; REQUIRE(NS_CLIENT_VALID(client)); - if (client->ede != NULL) { + /* + * As ede will be directly put in the DNS message we need to make sure + * the code is in big-endian format + */ + code = htobe16(code); + + for (pos = 0; pos < DNS_EDE_MAX_ERRORS; pos++) { + edns = client->ede[pos]; + + if (edns == NULL) { + break; + } + + if (memcmp(&code, edns->value, sizeof(code)) == 0) { + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), + "ignoring duplicate ede %u %s", code, + text == NULL ? "(null)" : text); + return; + } + } + + if (pos >= DNS_EDE_MAX_ERRORS) { ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), - "already have ede, ignoring %u %s", code, + "too many ede, ignoring %u %s", code, text == NULL ? "(null)" : text); return; } @@ -249,24 +276,31 @@ ns_client_extendederror(ns_client_t *client, uint16_t code, const char *text) { 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 { + textlen = strlen(text); + + if (textlen > DNS_EDE_EXTRATEXT_LEN) { ns_client_log(client, NS_LOGCATEGORY_CLIENT, - NS_LOGMODULE_CLIENT, ISC_LOG_WARNING, - "ede extra-text too long, ignoring"); + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), + "truncate EDE code %hu text: %s", code, + text); + textlen = DNS_EDE_EXTRATEXT_LEN; } } - client->ede = isc_mem_get(client->manager->mctx, sizeof(dns_ednsopt_t)); - client->ede->code = DNS_OPT_EDE; - client->ede->length = len; - client->ede->value = isc_mem_get(client->manager->mctx, len); - memmove(client->ede->value, ede, len); + ede = isc_mem_get(client->manager->mctx, codelen + textlen); + + memcpy(ede, &code, sizeof(code)); + if (textlen > 0) { + memcpy(ede + codelen, text, textlen); + } + + edns = isc_mem_get(client->manager->mctx, sizeof(*edns)); + *edns = (dns_ednsopt_t){ .code = DNS_OPT_EDE, + .length = codelen + textlen, + .value = ede }; + + client->ede[pos] = edns; } static void @@ -1231,11 +1265,17 @@ no_nsid: count++; } - if (client->ede != NULL) { + for (size_t i = 0; i < DNS_EDE_MAX_ERRORS; i++) { + dns_ednsopt_t *ede = client->ede[i]; + + if (ede == NULL) { + break; + } + INSIST(count < DNS_EDNSOPTIONS); ednsopts[count].code = DNS_OPT_EDE; - ednsopts[count].length = client->ede->length; - ednsopts[count].value = client->ede->value; + ednsopts[count].length = ede->length; + ednsopts[count].value = ede->value; count++; } @@ -2034,7 +2074,6 @@ 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 2c516de3b8..96f10665e1 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -180,7 +180,7 @@ struct ns_client { size_t tcpbuf_size; dns_message_t *message; dns_rdataset_t *opt; - dns_ednsopt_t *ede; + dns_ednsopt_t *ede[DNS_EDE_MAX_ERRORS]; uint16_t udpsize; uint16_t extflags; int16_t ednsversion; /* -1 noedns */ diff --git a/lib/ns/query.c b/lib/ns/query.c index 8464e782d9..ff75978b13 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -899,6 +899,7 @@ ns_query_init(ns_client_t *client) { ISC_LIST_INIT(client->query.namebufs); ISC_LIST_INIT(client->query.activeversions); ISC_LIST_INIT(client->query.freeversions); + memset(client->ede, 0, sizeof(dns_ednsopt_t *) * DNS_EDE_MAX_ERRORS); /* * This mutex is destroyed when the client is destroyed in * exit_check().