diff --git a/src/basic/meson.build b/src/basic/meson.build index 37ef434542..60ef801a25 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -235,6 +235,8 @@ basic_sources = files(''' strv.h strxcpyx.c strxcpyx.h + sysctl-util.c + sysctl-util.h syslog-util.c syslog-util.h terminal-util.c diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 06387bdfd6..fc90161745 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -31,6 +31,7 @@ #include "string-table.h" #include "string-util.h" #include "strv.h" +#include "sysctl-util.h" #include "user-util.h" #include "utf8.h" @@ -277,10 +278,48 @@ const char* socket_address_get_path(const SocketAddress *a) { } bool socket_ipv6_is_supported(void) { - if (access("/proc/net/if_inet6", F_OK) != 0) + static int cached = -1; + + if (cached < 0) { + + if (access("/proc/net/if_inet6", F_OK) < 0) { + + if (errno != ENOENT) { + log_debug_errno(errno, "Unexpected error when checking whether /proc/net/if_inet6 exists: %m"); + return false; + } + + cached = false; + } else + cached = true; + } + + return cached; +} + +bool socket_ipv6_is_enabled(void) { + _cleanup_free_ char *v; + int r; + + /* Much like socket_ipv6_is_supported(), but also checks that the sysctl that disables IPv6 on all + * interfaces isn't turned on */ + + if (!socket_ipv6_is_supported()) return false; - return true; + r = sysctl_read_ip_property(AF_INET6, "all", "disable_ipv6", &v); + if (r < 0) { + log_debug_errno(r, "Unexpected error reading 'net.ipv6.conf.all.disable_ipv6' sysctl: %m"); + return true; + } + + r = parse_boolean(v); + if (r < 0) { + log_debug_errno(r, "Failed to pare 'net.ipv6.conf.all.disable_ipv6' sysctl: %m"); + return true; + } + + return !r; } bool socket_address_matches_fd(const SocketAddress *a, int fd) { diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 2c98283cd3..507a599d7c 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -101,6 +101,7 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) _pure_ const char* socket_address_get_path(const SocketAddress *a); bool socket_ipv6_is_supported(void); +bool socket_ipv6_is_enabled(void); int sockaddr_port(const struct sockaddr *_sa, unsigned *port); const union in_addr_union *sockaddr_in_addr(const struct sockaddr *sa); diff --git a/src/shared/sysctl-util.c b/src/basic/sysctl-util.c similarity index 94% rename from src/shared/sysctl-util.c rename to src/basic/sysctl-util.c index a835a8bd0a..c96b5cd77f 100644 --- a/src/shared/sysctl-util.c +++ b/src/basic/sysctl-util.c @@ -96,14 +96,14 @@ int sysctl_write_ip_property(int af, const char *ifname, const char *property, c return write_string_file(p, value, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER); } -int sysctl_read(const char *property, char **content) { +int sysctl_read(const char *property, char **ret) { char *p; assert(property); - assert(content); + assert(ret); p = strjoina("/proc/sys/", property); - return read_full_file(p, content, NULL); + return read_full_virtual_file(p, ret, NULL); } int sysctl_read_ip_property(int af, const char *ifname, const char *property, char **ret) { @@ -118,7 +118,7 @@ int sysctl_read_ip_property(int af, const char *ifname, const char *property, ch ifname ? "/conf/" : "", strempty(ifname), property[0] == '/' ? "" : "/", property); - r = read_one_line_file(p, &value); + r = read_full_virtual_file(p, &value, NULL); if (r < 0) return r; diff --git a/src/shared/sysctl-util.h b/src/basic/sysctl-util.h similarity index 100% rename from src/shared/sysctl-util.h rename to src/basic/sysctl-util.h diff --git a/src/resolve/resolved-dns-synthesize.c b/src/resolve/resolved-dns-synthesize.c index 23c9ba14a9..d4a4be71b0 100644 --- a/src/resolve/resolved-dns-synthesize.c +++ b/src/resolve/resolved-dns-synthesize.c @@ -81,7 +81,7 @@ static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int if return r; } - if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) { + if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY) && socket_ipv6_is_enabled()) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, dns_resource_key_name(key)); @@ -234,7 +234,7 @@ static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key, .address.in.s_addr = htobe32(0x7F000002), }; - if (IN_SET(af, AF_INET6, AF_UNSPEC)) + if (IN_SET(af, AF_INET6, AF_UNSPEC) && socket_ipv6_is_enabled()) buffer[n++] = (struct local_address) { .family = AF_INET6, .ifindex = dns_synthesize_ifindex(ifindex), diff --git a/src/shared/meson.build b/src/shared/meson.build index 940345c495..a2e4958fdc 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -244,8 +244,6 @@ shared_sources = files(''' specifier.h switch-root.c switch-root.h - sysctl-util.c - sysctl-util.h tmpfile-util-label.c tmpfile-util-label.h tomoyo-util.c diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index 4ff7d714f8..584253c2fc 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -504,6 +504,11 @@ static void test_flush_accept(void) { assert_se(flush_accept(listen_seqpacket) >= 0); } +static void test_ipv6_enabled(void) { + log_info("IPv6 supported: %s", yes_no(socket_ipv6_is_supported())); + log_info("IPv6 enabled: %s", yes_no(socket_ipv6_is_enabled())); +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); @@ -519,6 +524,7 @@ int main(int argc, char *argv[]) { test_send_nodata_nofd(); test_send_emptydata(); test_flush_accept(); + test_ipv6_enabled(); return 0; }