From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202510 header.b=jaXCGxCg; dkim-atps=neutral Received: from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3]) by passt.top (Postfix) with ESMTPS id 6B9F35A0BCA for ; Tue, 02 Dec 2025 05:02:26 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202510; t=1764648138; bh=w+LnsPtOMCA2bJHjG+5WKXF5J4In8XFGwCkMF4nSSNw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jaXCGxCgK1MWHWRvRarHy4+wM1pxv9YQ90ryuyZGVNCCTpv7m/8OiZ0AhyIFebieF +5Knb8yXFO3ESxhdqFG+krDV6uNGHZn0Sj+bkrNrtMlu97QWpLjBkyJeM4W4ag7DE8 uLUOF4uHtgljAzfML4RqF52NAYWAqSCIprIAyRVMkJMN5U5e4Imxwgp36d2TgmCRd3 x7ovPCM0aU3YZxT5IWwJAO2KJVqhbWmM9DSxDifxTKw6JqDqu8bTZAfmg0Y6DkHdTo R8esQDDkfAM43EFjyx+LAxW1cEf8jotHCNSJaqKUAHbz17EYeQBlM/S+KbfUuFeA7C FaRyaZrGHcVwA== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4dL6Y61Phhz4wQc; Tue, 02 Dec 2025 15:02:18 +1100 (AEDT) From: David Gibson To: Stefano Brivio , passt-dev@passt.top Subject: [PATCH v5 10/15] util: Fix setting of IPV6_V6ONLY socket option Date: Tue, 2 Dec 2025 15:02:10 +1100 Message-ID: <20251202040215.2351792-11-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20251202040215.2351792-1-david@gibson.dropbear.id.au> References: <20251202040215.2351792-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: EETIADZTBYGLUYQPPCSUCBMXGFSEWSET X-Message-ID-Hash: EETIADZTBYGLUYQPPCSUCBMXGFSEWSET X-MailFrom: dgibson@gandalf.ozlabs.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: David Gibson X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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 --- util.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/util.c b/util.c index ee369614..853c35a3 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); } -- 2.52.0