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:
@@ -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
|
||||
|
||||
238
lib/isc/net.c
238
lib/isc/net.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user