git: 0bc0b0c3f738 - main - tests/socket_afinet: extend bind_connected_port_test to cover more cases

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Wed, 01 Jul 2026 05:48:46 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=0bc0b0c3f73812fdcdb89865879c7478bcbc7323

commit 0bc0b0c3f73812fdcdb89865879c7478bcbc7323
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2026-07-01 05:48:06 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2026-07-01 05:48:06 +0000

    tests/socket_afinet: extend bind_connected_port_test to cover more cases
    
    - Test SOCK_DGRAM (UDP) sockets.
    - Test binding to 0:port and to a addr:port in presence of connected socket
      using the port.
    
    Differential Revision:  https://reviews.freebsd.org/D56707
---
 tests/sys/netinet/socket_afinet.c | 137 +++++++++++++++++++++++++++++---------
 1 file changed, 107 insertions(+), 30 deletions(-)

diff --git a/tests/sys/netinet/socket_afinet.c b/tests/sys/netinet/socket_afinet.c
index ddd4f9a6f5da..936e5ada9802 100644
--- a/tests/sys/netinet/socket_afinet.c
+++ b/tests/sys/netinet/socket_afinet.c
@@ -31,6 +31,7 @@
 #include <sys/wait.h>
 
 #include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include <errno.h>
 #include <poll.h>
@@ -516,23 +517,26 @@ ATF_TC_BODY(socket_afinet_multibind, tc)
 	multibind_test(tc, AF_INET6, SOCK_DGRAM);
 }
 
-static void
-bind_connected_port_test(const atf_tc_t *tc, int domain)
+/*
+ * Test operation of bind(2) in presence of a connected inpcb using the
+ * same local port.
+ */
+static enum bind_res
+bind_connected_port_test(const atf_tc_t *tc, int domain, int type, bool wild,
+    bool unpriv)
 {
 	struct sockaddr_in sin;
 	struct sockaddr_in6 sin6;
 	struct sockaddr *sinp;
 	socklen_t slen;
-	int error, sd[3], tmp;
+	int error, ss, cs, as;
 	enum bind_res res;
 
 	/*
 	 * Create a connected socket pair.
 	 */
-	sd[0] = socket(domain, SOCK_STREAM, 0);
-	ATF_REQUIRE_MSG(sd[0] >= 0, "socket failed: %s", strerror(errno));
-	sd[1] = socket(domain, SOCK_STREAM, 0);
-	ATF_REQUIRE_MSG(sd[1] >= 0, "socket failed: %s", strerror(errno));
+	ss = socket(domain, type, 0);
+	ATF_REQUIRE_MSG(ss >= 0, "socket failed: %s", strerror(errno));
 	if (domain == PF_INET) {
 		memset(&sin, 0, sizeof(sin));
 		sin.sin_family = AF_INET;
@@ -550,28 +554,61 @@ bind_connected_port_test(const atf_tc_t *tc, int domain)
 		sinp = (struct sockaddr *)&sin6;
 	}
 
-	error = bind(sd[0], sinp, sinp->sa_len);
+	error = bind(ss, sinp, sinp->sa_len);
 	ATF_REQUIRE_MSG(error == 0, "bind failed: %s", strerror(errno));
-	error = listen(sd[0], 1);
-	ATF_REQUIRE_MSG(error == 0, "listen failed: %s", strerror(errno));
-
-	error = getsockname(sd[0], sinp, &(socklen_t){ sinp->sa_len });
-	ATF_REQUIRE_MSG(error == 0, "getsockname failed: %s", strerror(errno));
-	if (domain == PF_INET)
-		sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-	else
-		sin6.sin6_addr = in6addr_loopback;
-	error = connect(sd[1], sinp, sinp->sa_len);
-	ATF_REQUIRE_MSG(error == 0, "connect failed: %s", strerror(errno));
-	slen = sinp->sa_len;
-	tmp = accept(sd[0], sinp, &slen);
-	ATF_REQUIRE_MSG(tmp >= 0, "accept failed: %s", strerror(errno));
-
-	/* bind() should succeed even from an unprivileged user. */
-	res = child_bind_priv(tc, SOCK_STREAM, sinp, SO_REUSEADDR);
-	ATF_REQUIRE(res == BIND_REUSE_SUCCESS);
-	res = child_bind_unpriv(tc, SOCK_STREAM, sinp, SO_REUSEADDR);
-	ATF_REQUIRE(res == BIND_REUSE_SUCCESS);
+
+	if (type == SOCK_STREAM) {
+		error = getsockname(ss, sinp, &(socklen_t){ sinp->sa_len });
+		ATF_REQUIRE_MSG(error == 0, "getsockname failed: %s",
+		    strerror(errno));
+		error = listen(ss, 1);
+		ATF_REQUIRE_MSG(error == 0,
+		    "listen failed: %s", strerror(errno));
+		cs = socket(domain, type, 0);
+		ATF_REQUIRE_MSG(cs >= 0, "socket failed: %s", strerror(errno));
+		if (domain == PF_INET)
+			sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+		else
+			sin6.sin6_addr = in6addr_loopback;
+		error = connect(cs, sinp, sinp->sa_len);
+		ATF_REQUIRE_MSG(error == 0,
+		    "connect failed: %s", strerror(errno));
+		slen = sinp->sa_len;
+		as = accept(ss, sinp, &slen);
+		ATF_REQUIRE_MSG(as >= 0, "accept failed: %s", strerror(errno));
+	} else {
+		ATF_REQUIRE(type == SOCK_DGRAM);
+		if (domain == PF_INET) {
+			sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+			sin.sin_port = htons(6666);
+		} else {
+			sin6.sin6_addr = in6addr_loopback;
+			sin6.sin6_port = htons(6666);
+		}
+		error = connect(ss, sinp, sinp->sa_len);
+		ATF_REQUIRE_MSG(error == 0,
+		    "connect failed: %s", strerror(errno));
+		error = getsockname(ss, sinp, &(socklen_t){ sinp->sa_len });
+		ATF_REQUIRE_MSG(error == 0, "getsockname failed: %s",
+		    strerror(errno));
+	}
+
+	if (wild) {
+		if (domain == PF_INET)
+			sin.sin_addr.s_addr = htonl(INADDR_ANY);
+		else
+			sin6.sin6_addr = in6addr_any;
+	}
+
+	res = child_bind(tc, type, sinp, SO_REUSEADDR, unpriv);
+
+	if (type == SOCK_STREAM) {
+		ATF_REQUIRE(close(as) == 0);
+		ATF_REQUIRE(close(cs) == 0);
+	}
+	ATF_REQUIRE(close(ss) == 0);
+
+	return (res);
 }
 
 /*
@@ -587,8 +624,48 @@ ATF_TC_HEAD(socket_afinet_bind_connected_port, tc)
 }
 ATF_TC_BODY(socket_afinet_bind_connected_port, tc)
 {
-	bind_connected_port_test(tc, AF_INET);
-	bind_connected_port_test(tc, AF_INET6);
+	struct socket_afinet_bind_connected_port_res {
+		int domain;
+		int type;
+		bool wild;
+		bool unpriv;
+		enum bind_res result;
+	} tests[] = {
+#define	x true
+#define	o false
+				     /* W  U */
+	    { AF_INET,	SOCK_STREAM,	x, x, BIND_REUSE_SUCCESS },
+	    { AF_INET,	SOCK_STREAM,	o, x, BIND_REUSE_SUCCESS },
+	    { AF_INET,	SOCK_STREAM,	x, o, BIND_REUSE_SUCCESS },
+	    { AF_INET,	SOCK_STREAM,	o, o, BIND_REUSE_SUCCESS },
+	    { AF_INET6,	SOCK_STREAM,	x, x, BIND_REUSE_SUCCESS },
+	    { AF_INET6,	SOCK_STREAM,	o, x, BIND_REUSE_SUCCESS },
+	    { AF_INET6,	SOCK_STREAM,	x, o, BIND_REUSE_SUCCESS },
+	    { AF_INET6,	SOCK_STREAM,	o, o, BIND_REUSE_SUCCESS },
+	    { AF_INET,	SOCK_DGRAM,	x, x, BIND_FAILED },
+	    { AF_INET,	SOCK_DGRAM,	o, x, BIND_FAILED },
+	    { AF_INET,	SOCK_DGRAM,	x, o, BIND_REUSE_SUCCESS },
+	    { AF_INET,	SOCK_DGRAM,	o, o, BIND_REUSE_SUCCESS },
+	    { AF_INET6,	SOCK_DGRAM,	x, x, BIND_FAILED },
+	    { AF_INET6,	SOCK_DGRAM,	o, x, BIND_FAILED },
+	    { AF_INET6,	SOCK_DGRAM,	x, o, BIND_REUSE_SUCCESS },
+	    { AF_INET6,	SOCK_DGRAM,	o, o, BIND_REUSE_SUCCESS },
+#undef x
+#undef o
+	};
+
+	for (u_int i = 0; i < nitems(tests); i++) {
+		enum bind_res res;
+
+		res = bind_connected_port_test(tc, tests[i].domain,
+		    tests[i].type, tests[i].wild, tests[i].unpriv);
+		ATF_REQUIRE_MSG(res == tests[i].result, "test #%u: "
+		    "domain %u type %u%s %sprivileged: result %u (expected %u)",
+		    i, tests[i].domain, tests[i].type,
+		    tests[i].wild ? " wild" : "",
+		    tests[i].unpriv ? "un" : "",
+		    res, tests[i].result);
+	}
 }
 
 ATF_TP_ADD_TCS(tp)