aboutgitcodebugslistschat
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2025-12-02 15:02:10 +1100
committerStefano Brivio <sbrivio@redhat.com>2025-12-02 23:07:28 +0100
commite6f6eb24b1945f3c271f0b49fd60b9944e85439d (patch)
tree9964552751dccde8731d94ace17821ad48fe130f
parent74e6f12f0a55c9ee6c1cad6de25ad69ebfc4f3af (diff)
downloadpasst-e6f6eb24b1945f3c271f0b49fd60b9944e85439d.tar
passt-e6f6eb24b1945f3c271f0b49fd60b9944e85439d.tar.gz
passt-e6f6eb24b1945f3c271f0b49fd60b9944e85439d.tar.bz2
passt-e6f6eb24b1945f3c271f0b49fd60b9944e85439d.tar.lz
passt-e6f6eb24b1945f3c271f0b49fd60b9944e85439d.tar.xz
passt-e6f6eb24b1945f3c271f0b49fd60b9944e85439d.tar.zst
passt-e6f6eb24b1945f3c271f0b49fd60b9944e85439d.zip
util: Fix setting of IPV6_V6ONLY socket option
Currently we only call setsockopt() on IPV6_V6ONLY when we want to set it to 1, which we typically do on all IPv6 sockets except those explicitly for dual stack listening. That's not quite right in two ways: * Although IPV6_V6ONLY==0 is normally the default on Linux, that can be changed with the net.ipv6.bindv6only sysctl. It may also have different defaults on other OSes if we ever support them. We know we need it off for dual stack sockets, so explicitly set it to 0 in that case. * At the same time setting IPV6_V6ONLY to 1 for IPv6 sockets bound to a specific address is harmless but pointless. Don't set the option at all in this case, saving a syscall. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r--util.c29
1 files changed, 23 insertions, 6 deletions
diff --git a/util.c b/util.c
index 6cb1d38..491e7ff 100644
--- a/util.c
+++ b/util.c
@@ -45,13 +45,13 @@
* @type: epoll type
* @sa: Socket address to bind to
* @ifname: Interface for binding, NULL for any
- * @v6only: Set IPV6_V6ONLY socket option
+ * @v6only: If >= 0, set IPV6_V6ONLY socket option to this value
*
* Return: newly created socket, negative error code on failure
*/
static int sock_l4_(const struct ctx *c, enum epoll_type type,
const union sockaddr_inany *sa, const char *ifname,
- bool v6only)
+ int v6only)
{
sa_family_t af = sa->sa_family;
bool freebind = false;
@@ -95,9 +95,13 @@ static int sock_l4_(const struct ctx *c, enum epoll_type type,
return -EBADF;
}
- if (v6only)
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &y, sizeof(y)))
- debug("Failed to set IPV6_V6ONLY on socket %i", fd);
+ if (v6only >= 0) {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
+ &v6only, sizeof(v6only))) {
+ debug("Failed to set IPV6_V6ONLY to %d on socket %i",
+ v6only, fd);
+ }
+ }
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(y)))
debug("Failed to set SO_REUSEADDR on socket %i", fd);
@@ -181,7 +185,16 @@ static int sock_l4_(const struct ctx *c, enum epoll_type type,
int sock_l4(const struct ctx *c, enum epoll_type type,
const union sockaddr_inany *sa, const char *ifname)
{
- return sock_l4_(c, type, sa, ifname, sa->sa_family == AF_INET6);
+ int v6only = -1;
+
+ /* The option doesn't exist for IPv4 sockets, and we don't care about it
+ * for IPv6 sockets with a non-wildcard address.
+ */
+ if (sa->sa_family == AF_INET6 &&
+ IN6_IS_ADDR_UNSPECIFIED(&sa->sa6.sin6_addr))
+ v6only = 1;
+
+ return sock_l4_(c, type, sa, ifname, v6only);
}
/**
@@ -204,6 +217,10 @@ int sock_l4_dualstack(const struct ctx *c, enum epoll_type type,
.sa6.sin6_port = htons(port),
};
+ /* Dual stack sockets require IPV6_V6ONLY == 0. Usually that's the
+ * default, but sysctl net.ipv6.bindv6only can change that, so set the
+ * sockopt explicitly.
+ */
return sock_l4_(c, type, &sa, ifname, 0);
}