Merge branch '2790-properly-handle-oversized-messages-in-isc_nm_send-v9_16' into 'v9_16'

Handle `UV_EMSGSIZE` in the uv_udp_send() callback (v9.16)

See merge request isc-projects/bind9!5226
This commit is contained in:
Ondřej Surý
2021-06-23 16:27:35 +00:00
5 changed files with 52 additions and 28 deletions

View File

@@ -1,3 +1,9 @@
5664. [func] Handle a UDP sending error on UDP messages larger
than the path MTU; in such a case an empty response is
sent back with the TC (TrunCated) bit set. Re-enable
setting the DF (Don't Fragment) flag on outgoing
UDP sockets. [GL #2790]
5662. [bug] Views with recursion disabled are now configured with a
default cache size of 2 MB, unless "max-cache-size" is
explicitly set. This prevents cache RBT hash tables from

View File

@@ -34,7 +34,10 @@ Removed Features
Feature Changes
~~~~~~~~~~~~~~~
- None.
- IP fragmentation on outgoing UDP sockets has been disabled. Errors from
sending DNS messages larger than the specified path MTU are properly handled;
``named`` now sends back empty DNS messages with the TC (TrunCated) bit set,
forcing the DNS client to fall back to TCP. :gl:`#2790`
Bug Fixes
~~~~~~~~~

View File

@@ -2944,22 +2944,14 @@ isc__nm_socket_dontfrag(uv_os_sock_t fd, sa_family_t sa_family) {
*/
if (sa_family == AF_INET6) {
#if defined(IPV6_DONTFRAG)
if (setsockopt_off(fd, IPPROTO_IPV6, IPV6_DONTFRAG) == -1) {
if (setsockopt_on(fd, IPPROTO_IPV6, IPV6_DONTFRAG) == -1) {
return (ISC_R_FAILURE);
} else {
return (ISC_R_SUCCESS);
}
#elif defined(IPV6_MTU_DISCOVER) && defined(IP_PMTUDISC_OMIT)
#elif defined(IPV6_MTU_DISCOVER)
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
&(int){ IP_PMTUDISC_OMIT }, sizeof(int)) == -1)
{
return (ISC_R_FAILURE);
} else {
return (ISC_R_SUCCESS);
}
#elif defined(IPV6_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
&(int){ IP_PMTUDISC_DONT }, sizeof(int)) == -1)
&(int){ IP_PMTUDISC_DO }, sizeof(int)) == -1)
{
return (ISC_R_FAILURE);
} else {
@@ -2970,22 +2962,14 @@ isc__nm_socket_dontfrag(uv_os_sock_t fd, sa_family_t sa_family) {
#endif
} else if (sa_family == AF_INET) {
#if defined(IP_DONTFRAG)
if (setsockopt_off(fd, IPPROTO_IP, IP_DONTFRAG) == -1) {
if (setsockopt_on(fd, IPPROTO_IP, IP_DONTFRAG) == -1) {
return (ISC_R_FAILURE);
} else {
return (ISC_R_SUCCESS);
}
#elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_OMIT)
#elif defined(IP_MTU_DISCOVER)
if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER,
&(int){ IP_PMTUDISC_OMIT }, sizeof(int)) == -1)
{
return (ISC_R_FAILURE);
} else {
return (ISC_R_SUCCESS);
}
#elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER,
&(int){ IP_PMTUDISC_DONT }, sizeof(int)) == -1)
&(int){ IP_PMTUDISC_DO }, sizeof(int)) == -1)
{
return (ISC_R_FAILURE);
} else {

View File

@@ -85,6 +85,8 @@ isc___nm_uverr2result(int uverr, bool dolog, const char *file,
return (ISC_R_CANCELED);
case UV_EOF:
return (ISC_R_EOF);
case UV_EMSGSIZE:
return (ISC_R_MAXSIZE);
default:
if (dolog) {
UNEXPECTED_ERROR(

View File

@@ -279,13 +279,33 @@ client_senddone(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
REQUIRE(client->sendhandle == handle);
CTRACE("senddone");
/*
* Set sendhandle to NULL, but don't detach it immediately, in
* case we need to retry the send. If we do resend, then
* sendhandle will be reattached. Whether or not we resend,
* we will then detach the handle from *this* send by detaching
* 'handle' directly below.
*/
client->sendhandle = NULL;
if (result != ISC_R_SUCCESS) {
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
"send failed: %s", isc_result_totext(result));
if (!TCP_CLIENT(client) && result == ISC_R_MAXSIZE) {
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
"send exceeded maximum size: truncating");
client->query.attributes &= ~NS_QUERYATTR_ANSWERED;
client->rcode_override = dns_rcode_noerror;
ns_client_error(client, ISC_R_MAXSIZE);
} else {
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
"send failed: %s",
isc_result_totext(result));
}
}
isc_nmhandle_detach(&client->sendhandle);
isc_nmhandle_detach(&handle);
}
static void
@@ -721,8 +741,9 @@ ns_client_dropport(in_port_t port) {
void
ns_client_error(ns_client_t *client, isc_result_t result) {
dns_message_t *message = NULL;
dns_rcode_t rcode;
dns_message_t *message;
bool trunc = false;
REQUIRE(NS_CLIENT_VALID(client));
@@ -736,6 +757,10 @@ ns_client_error(ns_client_t *client, isc_result_t result) {
rcode = (dns_rcode_t)(client->rcode_override & 0xfff);
}
if (result == ISC_R_MAXSIZE) {
trunc = true;
}
#if NS_CLIENT_DROPPORT
/*
* Don't send FORMERR to ports on the drop port list.
@@ -832,7 +857,11 @@ ns_client_error(ns_client_t *client, isc_result_t result) {
return;
}
}
message->rcode = rcode;
if (trunc) {
message->flags |= DNS_MESSAGEFLAG_TC;
}
if (rcode == dns_rcode_formerr) {
/*