Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F162304301
D58085.id181458.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D58085.id181458.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D58085: tests/netinet/socket_afinet: unroll multibind test into a table
Attached
Detach File
Event Timeline
Log In to Comment