git: 0bc0b0c3f738 - main - tests/socket_afinet: extend bind_connected_port_test to cover more cases
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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)