resolv: Enable full ICMP errors for UDP DNS sockets [BZ #24047]

The Linux kernel suppresses some ICMP error messages by default for
UDP sockets.  This commit enables full ICMP error reporting,
hopefully resulting in faster failover to working name servers.
This commit is contained in:
Florian Weimer 2019-03-12 11:40:47 +01:00
parent 5fbcd76351
commit 08504de718
5 changed files with 66 additions and 1 deletions

View file

@ -1,3 +1,13 @@
2019-03-12 Florian Weimer <fweimer@redhat.com>
[BZ #24047]
resolv: Enable full ICMP errors for UDP DNS sockets
* resolv/res_enable_icmp.c: New file.
* resolv/Makefile (libresolv-routines): Add res_enable_icmp.
* resolv/resolv-internal.h (__res_enable_icmp): Declare.
* resolv/res_send.c (reopen): Call __res_enable_icmp on new
socket.
2019-03-11 Mao Han <han_mao@c-sky.com>
* elf/elf.h (EF_CSKY_ABIMASK, EF_CSKY_OTHER, EF_CSKY_PROCESSOR)

View file

@ -105,7 +105,7 @@ libresolv-routines := res_comp res_debug \
res_data res_mkquery res_query res_send \
inet_net_ntop inet_net_pton inet_neta base64 \
ns_parse ns_name ns_netint ns_ttl ns_print \
ns_samedomain ns_date \
ns_samedomain ns_date res_enable_icmp \
compat-hooks compat-gethnamaddr
libanl-routines := gai_cancel gai_error gai_misc gai_notify gai_suspend \

37
resolv/res_enable_icmp.c Normal file
View file

@ -0,0 +1,37 @@
/* Enable full ICMP errors on a socket.
Copyright (C) 2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
int
__res_enable_icmp (int family, int fd)
{
int one = 1;
switch (family)
{
case AF_INET:
return setsockopt (fd, SOL_IP, IP_RECVERR, &one, sizeof (one));
case AF_INET6:
return setsockopt (fd, SOL_IPV6, IPV6_RECVERR, &one, sizeof (one));
default:
__set_errno (EAFNOSUPPORT);
return -1;
}
}

View file

@ -943,6 +943,18 @@ reopen (res_state statp, int *terrno, int ns)
return (-1);
}
/* Enable full ICMP error reporting for this
socket. */
if (__res_enable_icmp (nsap->sa_family,
EXT (statp).nssocks[ns]) < 0)
{
int saved_errno = errno;
__res_iclose (statp, false);
__set_errno (saved_errno);
*terrno = saved_errno;
return -1;
}
/*
* On a 4.3BSD+ machine (client and server,
* actually), sending to a nameserver datagram

View file

@ -100,4 +100,10 @@ libc_hidden_proto (__inet_pton_length)
/* Called as part of the thread shutdown sequence. */
void __res_thread_freeres (void) attribute_hidden;
/* The Linux kernel does not enable all ICMP messages on a UDP socket
by default. A call this function enables full error reporting for
the socket FD. FAMILY must be AF_INET or AF_INET6. Returns 0 on
success, -1 on failure. */
int __res_enable_icmp (int family, int fd) attribute_hidden;
#endif /* _RESOLV_INTERNAL_H */