Page MenuHomeFreeBSD

D58085.id181458.diff
No OneTemporary

D58085.id181458.diff

diff --git a/tests/sys/netinet/socket_afinet.c b/tests/sys/netinet/socket_afinet.c
--- a/tests/sys/netinet/socket_afinet.c
+++ b/tests/sys/netinet/socket_afinet.c
@@ -346,7 +346,7 @@
BIND_REUSE_SUCCESS = 6,
BIND_BADERR2 = 7,
}
-child_bind(const atf_tc_t *tc, int type, struct sockaddr *sa, int opt,
+child_bind(const atf_tc_t *tc, int type, const struct sockaddr *sa, int opt,
bool unpriv)
{
const char *user;
@@ -400,109 +400,6 @@
}
}
-static enum bind_res
-child_bind_priv(const atf_tc_t *tc, int type, struct sockaddr *sa, int opt)
-{
- return (child_bind(tc, type, sa, opt, false));
-}
-
-static enum bind_res
-child_bind_unpriv(const atf_tc_t *tc, int type, struct sockaddr *sa, int opt)
-{
- return (child_bind(tc, type, sa, opt, true));
-}
-
-static int
-bind_socket(int domain, int type, int opt, bool unspec, struct sockaddr *sa)
-{
- socklen_t slen;
- int s;
-
- s = socket(domain, type, 0);
- ATF_REQUIRE(s >= 0);
-
- if (domain == AF_INET) {
- struct sockaddr_in sin;
-
- bzero(&sin, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_len = sizeof(sin);
- sin.sin_addr.s_addr = htonl(unspec ?
- INADDR_ANY : INADDR_LOOPBACK);
- sin.sin_port = htons(0);
- ATF_REQUIRE(bind(s, (struct sockaddr *)&sin, sizeof(sin)) == 0);
-
- slen = sizeof(sin);
- } else /* if (domain == AF_INET6) */ {
- struct sockaddr_in6 sin6;
-
- bzero(&sin6, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_len = sizeof(sin6);
- sin6.sin6_addr = unspec ? in6addr_any : in6addr_loopback;
- sin6.sin6_port = htons(0);
- ATF_REQUIRE(bind(s, (struct sockaddr *)&sin6, sizeof(sin6)) == 0);
-
- slen = sizeof(sin6);
- }
-
- if (opt != 0) {
- ATF_REQUIRE(setsockopt(s, SOL_SOCKET, opt, &(int){1},
- sizeof(int)) == 0);
- }
-
- ATF_REQUIRE(getsockname(s, sa, &slen) == 0);
-
- return (s);
-}
-
-static void
-multibind_test(const atf_tc_t *tc, int domain, int type)
-{
- struct sockaddr_storage ss;
- int opts[4] = { 0, SO_REUSEADDR, SO_REUSEPORT, SO_REUSEPORT_LB };
- int s;
- bool flags[2] = { false, true };
- enum bind_res res;
-
- for (size_t flagi = 0; flagi < nitems(flags); flagi++) {
- for (size_t opti = 0; opti < nitems(opts); opti++) {
- s = bind_socket(domain, type, opts[opti], flags[flagi],
- (struct sockaddr *)&ss);
- for (size_t optj = 0; optj < nitems(opts); optj++) {
- int opt;
-
- opt = opts[optj];
- res = child_bind_priv(tc, type,
- (struct sockaddr *)&ss, opt);
- /*
- * Multi-binding is only allowed when both
- * sockets have SO_REUSEPORT or SO_REUSEPORT_LB
- * set.
- */
- if (opts[opti] != 0 &&
- opts[opti] != SO_REUSEADDR && opti == optj)
- ATF_REQUIRE(res == BIND_REUSE_SUCCESS);
- else
- ATF_REQUIRE(res == BIND_FAILED);
-
- res = child_bind_unpriv(tc, type,
- (struct sockaddr *)&ss, opt);
- /*
- * Multi-binding is only allowed when both
- * sockets have the same owner.
- */
- ATF_REQUIRE_MSG(res == BIND_FAILED,
- "domain %u type %u opts %u:%u: "
- "result %u (expected %u)",
- domain, type, opts[opti], opts[optj],
- res, BIND_FAILED);
- }
- ATF_REQUIRE(close(s) == 0);
- }
- }
-}
-
/*
* Try to bind two sockets to the same address/port tuple. Under some
* conditions this is permitted.
@@ -513,12 +410,172 @@
atf_tc_set_md_var(tc, "require.user", "root");
atf_tc_set_md_var(tc, "require.config", "unprivileged_user");
}
+
ATF_TC_BODY(multibind, tc)
{
- multibind_test(tc, AF_INET, SOCK_STREAM);
- multibind_test(tc, AF_INET, SOCK_DGRAM);
- multibind_test(tc, AF_INET6, SOCK_STREAM);
- multibind_test(tc, AF_INET6, SOCK_DGRAM);
+ const struct {
+ int type;
+ int opt1;
+ bool wild1;
+ int opt2;
+ bool wild2; /* not exercised yet, uses getsockname() rv */
+ enum bind_res priv_res;
+ enum bind_res unpriv_res;
+ } tests[] = {
+#define ADDR SO_REUSEADDR
+#define PORT SO_REUSEPORT
+#define LB SO_REUSEPORT_LB
+#define x true
+#define o false
+#define F BIND_FAILED
+#define R BIND_REUSE_SUCCESS
+ /* p u */
+ { SOCK_STREAM, 0, o, 0, o, F, F },
+ { SOCK_STREAM, 0, o, ADDR, o, F, F },
+ { SOCK_STREAM, 0, o, PORT, o, F, F },
+ { SOCK_STREAM, 0, o, LB, o, F, F },
+ { SOCK_STREAM, ADDR, o, 0, o, F, F },
+ { SOCK_STREAM, ADDR, o, ADDR, o, F, F },
+ { SOCK_STREAM, ADDR, o, PORT, o, F, F },
+ { SOCK_STREAM, ADDR, o, LB, o, F, F },
+ { SOCK_STREAM, PORT, o, 0, o, F, F },
+ { SOCK_STREAM, PORT, o, ADDR, o, F, F },
+ { SOCK_STREAM, PORT, o, PORT, o, R, F },
+ { SOCK_STREAM, PORT, o, LB, o, F, F },
+ { SOCK_STREAM, LB, o, 0, o, F, F },
+ { SOCK_STREAM, LB, o, ADDR, o, F, F },
+ { SOCK_STREAM, LB, o, PORT, o, F, F },
+ { SOCK_STREAM, LB, o, LB, o, R, F },
+ /*
+ * ATM, expected result with wildcard first bind(2) is the same
+ * as the result for the specified first bind(2). Thus, the
+ * below block is copy-and-paste of the above with wild1 set.
+ */
+ { SOCK_STREAM, 0, x, 0, o, F, F },
+ { SOCK_STREAM, 0, x, ADDR, o, F, F },
+ { SOCK_STREAM, 0, x, PORT, o, F, F },
+ { SOCK_STREAM, 0, x, LB, o, F, F },
+ { SOCK_STREAM, ADDR, x, 0, o, F, F },
+ { SOCK_STREAM, ADDR, x, ADDR, o, F, F },
+ { SOCK_STREAM, ADDR, x, PORT, o, F, F },
+ { SOCK_STREAM, ADDR, x, LB, o, F, F },
+ { SOCK_STREAM, PORT, x, 0, o, F, F },
+ { SOCK_STREAM, PORT, x, ADDR, o, F, F },
+ { SOCK_STREAM, PORT, x, PORT, o, R, F },
+ { SOCK_STREAM, PORT, x, LB, o, F, F },
+ { SOCK_STREAM, LB, x, 0, o, F, F },
+ { SOCK_STREAM, LB, x, ADDR, o, F, F },
+ { SOCK_STREAM, LB, x, PORT, o, F, F },
+ { SOCK_STREAM, LB, x, LB, o, R, F },
+ /*
+ * ATM, expected result for SOCK_DGRAM is the same as for
+ * SOCK_STREAM. Thus the below is copy-and-paste of the above.
+ */
+ { SOCK_DGRAM, 0, o, 0, o, F, F },
+ { SOCK_DGRAM, 0, o, ADDR, o, F, F },
+ { SOCK_DGRAM, 0, o, PORT, o, F, F },
+ { SOCK_DGRAM, 0, o, LB, o, F, F },
+ { SOCK_DGRAM, ADDR, o, 0, o, F, F },
+ { SOCK_DGRAM, ADDR, o, ADDR, o, F, F },
+ { SOCK_DGRAM, ADDR, o, PORT, o, F, F },
+ { SOCK_DGRAM, ADDR, o, LB, o, F, F },
+ { SOCK_DGRAM, PORT, o, 0, o, F, F },
+ { SOCK_DGRAM, PORT, o, ADDR, o, F, F },
+ { SOCK_DGRAM, PORT, o, PORT, o, R, F },
+ { SOCK_DGRAM, PORT, o, LB, o, F, F },
+ { SOCK_DGRAM, LB, o, 0, o, F, F },
+ { SOCK_DGRAM, LB, o, ADDR, o, F, F },
+ { SOCK_DGRAM, LB, o, PORT, o, F, F },
+ { SOCK_DGRAM, LB, o, LB, o, R, F },
+ /* wild1 -> true */
+ { SOCK_DGRAM, 0, x, 0, o, F, F },
+ { SOCK_DGRAM, 0, x, ADDR, o, F, F },
+ { SOCK_DGRAM, 0, x, PORT, o, F, F },
+ { SOCK_DGRAM, 0, x, LB, o, F, F },
+ { SOCK_DGRAM, ADDR, x, 0, o, F, F },
+ { SOCK_DGRAM, ADDR, x, ADDR, o, F, F },
+ { SOCK_DGRAM, ADDR, x, PORT, o, F, F },
+ { SOCK_DGRAM, ADDR, x, LB, o, F, F },
+ { SOCK_DGRAM, PORT, x, 0, o, F, F },
+ { SOCK_DGRAM, PORT, x, ADDR, o, F, F },
+ { SOCK_DGRAM, PORT, x, PORT, o, R, F },
+ { SOCK_DGRAM, PORT, x, LB, o, F, F },
+ { SOCK_DGRAM, LB, x, 0, o, F, F },
+ { SOCK_DGRAM, LB, x, ADDR, o, F, F },
+ { SOCK_DGRAM, LB, x, PORT, o, F, F },
+ { SOCK_DGRAM, LB, x, LB, o, R, F },
+#undef F
+#undef R
+#undef x
+#undef o
+#undef ADDR
+#undef PORT
+#undef LB
+ };
+ /*
+ * Expected results for IPv4 and IPv6 shall always be the same, so
+ * this dimension is implemented as a cycle rather than table entry.
+ */
+ const union sockaddr_union {
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct sockaddr sa;
+ } wild[] = {
+ {
+ .sin.sin_family = AF_INET,
+ .sin.sin_len = sizeof(struct sockaddr_in),
+ },
+ {
+ .sin6.sin6_family = AF_INET6,
+ .sin6.sin6_len = sizeof(struct sockaddr_in6),
+ },
+ }, loop[] = {
+ {
+ .sin.sin_family = AF_INET,
+ .sin.sin_len = sizeof(struct sockaddr_in),
+ .sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
+ },
+ {
+ .sin6.sin6_family = AF_INET6,
+ .sin6.sin6_len = sizeof(struct sockaddr_in6),
+ .sin6.sin6_addr = in6addr_loopback,
+ },
+ };
+
+ _Static_assert(nitems(wild) == nitems(loop), "EDOOFUS");
+ for (u_int af = 0; af < nitems(wild); af++) {
+ for (u_int i = 0; i < nitems(tests); i++) {
+ const struct sockaddr *sa;
+ union sockaddr_union su;
+ socklen_t slen;
+ enum bind_res res;
+ int s;
+
+ s = socket(wild[af].sa.sa_family, tests[i].type, 0);
+ ATF_REQUIRE(s >= 0);
+ sa = tests[i].wild1 ? &wild[af].sa : &loop[af].sa;
+ slen = sa->sa_len;
+ ATF_REQUIRE(bind(s, sa, slen) == 0);
+ if (tests[i].opt1 != 0)
+ ATF_REQUIRE(setsockopt(s, SOL_SOCKET,
+ tests[i].opt1, &(int){1}, sizeof(int)) ==
+ 0);
+ ATF_REQUIRE(getsockname(s, &su.sa, &slen) == 0);
+
+ sa = &su.sa;
+ res = child_bind(tc, tests[i].type, sa, tests[i].opt2,
+ false);
+ ATF_REQUIRE_MSG(tests[i].priv_res == res,
+ "af %d test #%d (priv) failed", sa->sa_family, i);
+
+ res = child_bind(tc, tests[i].type, sa, tests[i].opt2,
+ true);
+ ATF_REQUIRE_MSG(tests[i].unpriv_res == res,
+ "af %d test #%d (unpriv) failed", sa->sa_family, i);
+
+ ATF_REQUIRE(close(s) == 0);
+ }
+ }
}
/*

File Metadata

Mime Type
text/plain
Expires
Sun, Jul 12, 9:17 PM (12 h, 35 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34851952
Default Alt Text
D58085.id181458.diff (8 KB)

Event Timeline