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=GdP74qZy; dkim-atps=neutral Received: from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3]) by passt.top (Postfix) with ESMTPS id 83EA35A0BB6 for ; Wed, 19 Nov 2025 06:23:07 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202510; t=1763529779; bh=5fjmCAiYuElXibBfnkwiJ2oudB4lLB+zCWxs3eBlXOU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GdP74qZyDgbGzebbx7eB3AreNuRK0vUbGSie4R/T5FKEe/4dFUhvLYCDiLho1dV7O lkRhqJG/SsjAx1N88pB9ugYopVtbtPwhCFrfNbroilvPs0tAv+Auj4MjytsoMuah8J 9akLQ9zr2EYc7QDmk8o2SAyktfT8QNKKM/oPfx4xFSrWEYC8qZqXJqTbwgFC5kXXUs fc7QJWcYHPiehnBnhelyMyZSMWk+LHQC2yUXsUcwC7eic9RYOmpjqgFXReM4eCHYGu WL6wAoVYQDcsl4RqtdS5ON+QesfcjY+pfHxp42s2ENkp5+DkmNOoJW8SQQBpvs3lcP QQarHpp5BDUDg== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4dB8yC4Xhhz4wH2; Wed, 19 Nov 2025 16:22:59 +1100 (AEDT) From: David Gibson To: Stefano Brivio , passt-dev@passt.top Subject: [PATCH v4 7/9] util: Fix setting of IPV6_V6ONLY socket option Date: Wed, 19 Nov 2025 16:22:55 +1100 Message-ID: <20251119052257.3004500-8-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20251119052257.3004500-1-david@gibson.dropbear.id.au> References: <20251119052257.3004500-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: MBHGKYFBTGYJDZCPMGG6Y3VJX5KP3NPV X-Message-ID-Hash: MBHGKYFBTGYJDZCPMGG6Y3VJX5KP3NPV 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 1108a1da..82491326 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); @@ -180,7 +184,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); } /** @@ -203,6 +216,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.51.1