chg: dev: Assume IPv6 is universally available (on the kernel level)

Instead of various probing, just assume that IPv6 is universally available
and cleanup the various checks and defines that we have accumulated over
the years.

Merge branch 'ondrej/cleanup-IPv6-networking-support' into 'main'

See merge request isc-projects/bind9!9360
This commit is contained in:
Ondřej Surý
2024-11-27 14:23:11 +00:00
3 changed files with 4 additions and 343 deletions

View File

@@ -188,52 +188,23 @@ ISC_LANG_BEGINDECLS
isc_result_t
isc_net_probeipv4(void);
/*%<
* Check if the system's kernel supports IPv4.
* Check if the IPv4 has been disabled.
*
* Returns:
*
*\li #ISC_R_SUCCESS IPv4 is supported.
*\li #ISC_R_NOTFOUND IPv4 is not supported.
*\li #ISC_R_DISABLED IPv4 is disabled.
*\li #ISC_R_UNEXPECTED
*/
isc_result_t
isc_net_probeipv6(void);
/*%<
* Check if the system's kernel supports IPv6.
* Check if the IPv6 has been disabled.
*
* Returns:
*
*\li #ISC_R_SUCCESS IPv6 is supported.
*\li #ISC_R_NOTFOUND IPv6 is not supported.
*\li #ISC_R_DISABLED IPv6 is disabled.
*\li #ISC_R_UNEXPECTED
*/
isc_result_t
isc_net_probe_ipv6only(void);
/*%<
* Check if the system's kernel supports the IPV6_V6ONLY socket option.
*
* Returns:
*
*\li #ISC_R_SUCCESS the option is supported for both TCP and UDP.
*\li #ISC_R_NOTFOUND IPv6 itself or the option is not supported.
*\li #ISC_R_UNEXPECTED
*/
isc_result_t
isc_net_probe_ipv6pktinfo(void);
/*
* Check if the system's kernel supports the IPV6_(RECV)PKTINFO socket option
* for UDP sockets.
*
* Returns:
*
* \li #ISC_R_SUCCESS the option is supported.
* \li #ISC_R_NOTFOUND IPv6 itself or the option is not supported.
* \li #ISC_R_UNEXPECTED
*/
void

View File

@@ -31,10 +31,6 @@
#include <isc/string.h>
#include <isc/util.h>
#ifndef socklen_t
#define socklen_t unsigned int
#endif /* ifndef socklen_t */
/*%
* Definitions about UDP port range specification. This is a total mess of
* portability variants: some use sysctl (but the sysctl names vary), some use
@@ -89,245 +85,19 @@
#endif /* HAVE_SYSCTLBYNAME */
static isc_once_t once_ipv6only = ISC_ONCE_INIT;
#ifdef __notyet__
static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT;
#endif /* ifdef __notyet__ */
#ifndef ISC_CMSG_IP_TOS
#ifdef __APPLE__
#define ISC_CMSG_IP_TOS 0 /* As of 10.8.2. */
#else /* ! __APPLE__ */
#define ISC_CMSG_IP_TOS 1
#endif /* ! __APPLE__ */
#endif /* ! ISC_CMSG_IP_TOS */
static isc_once_t once = ISC_ONCE_INIT;
static isc_result_t ipv4_result = ISC_R_NOTFOUND;
static isc_result_t ipv6_result = ISC_R_NOTFOUND;
static isc_result_t ipv6only_result = ISC_R_NOTFOUND;
static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND;
static isc_result_t
try_proto(int domain) {
int s;
isc_result_t result = ISC_R_SUCCESS;
s = socket(domain, SOCK_STREAM, 0);
if (s == -1) {
switch (errno) {
#ifdef EAFNOSUPPORT
case EAFNOSUPPORT:
#endif /* ifdef EAFNOSUPPORT */
#ifdef EPFNOSUPPORT
case EPFNOSUPPORT:
#endif /* ifdef EPFNOSUPPORT */
#ifdef EPROTONOSUPPORT
case EPROTONOSUPPORT:
#endif /* ifdef EPROTONOSUPPORT */
#ifdef EINVAL
case EINVAL:
#endif /* ifdef EINVAL */
return ISC_R_NOTFOUND;
default:
UNEXPECTED_SYSERROR(errno, "socket()");
return ISC_R_UNEXPECTED;
}
}
if (domain == PF_INET6) {
struct sockaddr_in6 sin6;
unsigned int len;
/*
* Check to see if IPv6 is broken, as is common on Linux.
*/
len = sizeof(sin6);
if (getsockname(s, (struct sockaddr *)&sin6, (void *)&len) < 0)
{
isc_log_write(ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
"retrieving the address of an IPv6 "
"socket from the kernel failed.");
isc_log_write(ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
"IPv6 is not supported.");
result = ISC_R_NOTFOUND;
} else {
if (len == sizeof(struct sockaddr_in6)) {
result = ISC_R_SUCCESS;
} else {
isc_log_write(ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_SOCKET,
ISC_LOG_ERROR,
"IPv6 structures in kernel and "
"user space do not match.");
isc_log_write(ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_SOCKET,
ISC_LOG_ERROR,
"IPv6 is not supported.");
result = ISC_R_NOTFOUND;
}
}
}
(void)close(s);
return result;
}
static void
initialize_action(void) {
ipv4_result = try_proto(PF_INET);
ipv6_result = try_proto(PF_INET6);
}
static void
initialize(void) {
isc_once_do(&once, initialize_action);
}
static isc_result_t ipv4_result = ISC_R_SUCCESS;
static isc_result_t ipv6_result = ISC_R_SUCCESS;
isc_result_t
isc_net_probeipv4(void) {
initialize();
return ipv4_result;
}
isc_result_t
isc_net_probeipv6(void) {
initialize();
return ipv6_result;
}
static void
try_ipv6only(void) {
#ifdef IPV6_V6ONLY
int s, on;
#endif /* ifdef IPV6_V6ONLY */
isc_result_t result;
result = isc_net_probeipv6();
if (result != ISC_R_SUCCESS) {
ipv6only_result = result;
return;
}
#ifndef IPV6_V6ONLY
ipv6only_result = ISC_R_NOTFOUND;
return;
#else /* ifndef IPV6_V6ONLY */
/* check for TCP sockets */
s = socket(PF_INET6, SOCK_STREAM, 0);
if (s == -1) {
UNEXPECTED_SYSERROR(errno, "socket()");
ipv6only_result = ISC_R_UNEXPECTED;
return;
}
on = 1;
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
ipv6only_result = ISC_R_NOTFOUND;
goto close;
}
close(s);
/* check for UDP sockets */
s = socket(PF_INET6, SOCK_DGRAM, 0);
if (s == -1) {
UNEXPECTED_SYSERROR(errno, "socket()");
ipv6only_result = ISC_R_UNEXPECTED;
return;
}
on = 1;
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
ipv6only_result = ISC_R_NOTFOUND;
goto close;
}
ipv6only_result = ISC_R_SUCCESS;
close:
close(s);
return;
#endif /* IPV6_V6ONLY */
}
static void
initialize_ipv6only(void) {
isc_once_do(&once_ipv6only, try_ipv6only);
}
#ifdef __notyet__
static void
try_ipv6pktinfo(void) {
int s, on;
isc_result_t result;
int optname;
result = isc_net_probeipv6();
if (result != ISC_R_SUCCESS) {
ipv6pktinfo_result = result;
return;
}
/* we only use this for UDP sockets */
s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (s == -1) {
UNEXPECTED_SYSERROR(errno, "socket()");
ipv6pktinfo_result = ISC_R_UNEXPECTED;
return;
}
#ifdef IPV6_RECVPKTINFO
optname = IPV6_RECVPKTINFO;
#else /* ifdef IPV6_RECVPKTINFO */
optname = IPV6_PKTINFO;
#endif /* ifdef IPV6_RECVPKTINFO */
on = 1;
if (setsockopt(s, IPPROTO_IPV6, optname, &on, sizeof(on)) < 0) {
ipv6pktinfo_result = ISC_R_NOTFOUND;
goto close;
}
ipv6pktinfo_result = ISC_R_SUCCESS;
close:
close(s);
return;
}
static void
initialize_ipv6pktinfo(void) {
isc_once_do(&once_ipv6pktinfo, try_ipv6pktinfo);
}
#endif /* ifdef __notyet__ */
isc_result_t
isc_net_probe_ipv6only(void) {
initialize_ipv6only();
return ipv6only_result;
}
isc_result_t
isc_net_probe_ipv6pktinfo(void) {
/*
* XXXWPK if pktinfo were supported then we could listen on :: for ipv6 and get
* the information about the destination address from pktinfo structure passed
* in recvmsg but this method is not portable and libuv doesn't support it - so
* we need to listen on all interfaces.
* We should verify that this doesn't impact performance (we already do it for
* ipv4) and either remove all the ipv6pktinfo detection code from above
* or think of fixing libuv.
*/
#ifdef __notyet__
initialize_ipv6pktinfo();
#endif /* ifdef __notyet__ */
return ipv6pktinfo_result;
}
#if defined(USE_SYSCTL_PORTRANGE)
#if defined(HAVE_SYSCTLBYNAME)
static isc_result_t
@@ -450,7 +220,6 @@ isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) {
void
isc_net_disableipv4(void) {
initialize();
if (ipv4_result == ISC_R_SUCCESS) {
ipv4_result = ISC_R_DISABLED;
}
@@ -458,7 +227,6 @@ isc_net_disableipv4(void) {
void
isc_net_disableipv6(void) {
initialize();
if (ipv6_result == ISC_R_SUCCESS) {
ipv6_result = ISC_R_DISABLED;
}
@@ -466,7 +234,6 @@ isc_net_disableipv6(void) {
void
isc_net_enableipv4(void) {
initialize();
if (ipv4_result == ISC_R_DISABLED) {
ipv4_result = ISC_R_SUCCESS;
}
@@ -474,7 +241,6 @@ isc_net_enableipv4(void) {
void
isc_net_enableipv6(void) {
initialize();
if (ipv6_result == ISC_R_DISABLED) {
ipv6_result = ISC_R_SUCCESS;
}

View File

@@ -1085,12 +1085,9 @@ do_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) {
isc_interfaceiter_t *iter = NULL;
bool scan_ipv4 = false;
bool scan_ipv6 = false;
bool ipv6only = true;
bool ipv6pktinfo = true;
isc_result_t result;
isc_netaddr_t zero_address, zero_address6;
ns_listenelt_t *le = NULL;
isc_sockaddr_t listen_addr;
ns_interface_t *ifp = NULL;
bool log_explicit = false;
bool dolistenon;
@@ -1116,64 +1113,6 @@ do_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) {
"no IPv4 interfaces found");
}
/*
* A special, but typical case; listen-on-v6 { any; }.
* When we can make the socket IPv6-only, open a single wildcard
* socket for IPv6 communication. Otherwise, make separate
* socket for each IPv6 address in order to avoid accepting IPv4
* packets as the form of mapped addresses unintentionally
* unless explicitly allowed.
*/
if (scan_ipv6 && isc_net_probe_ipv6only() != ISC_R_SUCCESS) {
ipv6only = false;
log_explicit = true;
}
if (scan_ipv6 && isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) {
ipv6pktinfo = false;
log_explicit = true;
}
if (scan_ipv6 && ipv6only && ipv6pktinfo) {
for (le = ISC_LIST_HEAD(mgr->listenon6->elts); le != NULL;
le = ISC_LIST_NEXT(le, link))
{
struct in6_addr in6a;
if (!listenon_is_ip6_any(le)) {
continue;
}
in6a = in6addr_any;
isc_sockaddr_fromin6(&listen_addr, &in6a, le->port);
ifp = find_matching_interface(mgr, &listen_addr);
if (ifp != NULL) {
bool cont = interface_update_or_shutdown(
mgr, ifp, le, config);
if (cont) {
continue;
}
}
isc_log_write(NS_LOGCATEGORY_NETWORK,
NS_LOGMODULE_INTERFACEMGR, ISC_LOG_INFO,
"listening on IPv6 "
"interfaces, port %u",
le->port);
result = interface_setup(mgr, &listen_addr, "<any>",
&ifp, le, NULL);
if (result == ISC_R_SUCCESS) {
ifp->flags |= NS_INTERFACEFLAG_ANYADDR;
} else {
isc_log_write(NS_LOGCATEGORY_NETWORK,
NS_LOGMODULE_INTERFACEMGR,
ISC_LOG_ERROR,
"listening on all IPv6 "
"interfaces failed");
}
/* Continue. */
}
}
isc_netaddr_any(&zero_address);
isc_netaddr_any6(&zero_address6);
@@ -1253,7 +1192,6 @@ do_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) {
{
int match;
bool addr_in_use = false;
bool ipv6_wildcard = false;
isc_sockaddr_t listen_sockaddr;
isc_sockaddr_fromnetaddr(&listen_sockaddr,
@@ -1279,16 +1217,6 @@ do_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) {
dolistenon = false;
}
/*
* The case of "any" IPv6 address will require
* special considerations later, so remember it.
*/
if (family == AF_INET6 && ipv6only && ipv6pktinfo &&
listenon_is_ip6_any(le))
{
ipv6_wildcard = true;
}
ifp = find_matching_interface(mgr, &listen_sockaddr);
if (ifp != NULL) {
bool cont = interface_update_or_shutdown(
@@ -1298,10 +1226,6 @@ do_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) {
}
}
if (ipv6_wildcard) {
continue;
}
if (log_explicit && family == AF_INET6 &&
listenon_is_ip6_any(le))
{