// SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2018 Facebook // Copyright (c) 2019 Cloudflare // Copyright (c) 2020 Isovalent, Inc. /* * Test that the socket assign program is able to redirect traffic towards a * socket, regardless of whether the port or address destination of the traffic * matches the port.
*/
/* Check whether tc is built with libbpf. */
tc = popen("tc -V", "r"); if (CHECK_FAIL(!tc)) returnfalse; if (CHECK_FAIL(!fgets(tc_version, sizeof(tc_version), tc))) {
pclose(tc); returnfalse;
} if (strstr(tc_version, ", libbpf "))
prog = "test_sk_assign_libbpf.bpf.o"; else
prog = "test_sk_assign.bpf.o"; if (CHECK_FAIL(pclose(tc))) returnfalse;
/* Move to a new networking namespace */ if (CHECK_FAIL(unshare(CLONE_NEWNET))) returnfalse;
/* Configure necessary links, routes */ if (CHECK_FAIL(system("ip link set dev lo up"))) returnfalse; if (CHECK_FAIL(system("ip route add local default dev lo"))) returnfalse; if (CHECK_FAIL(system("ip -6 route add local default dev lo"))) returnfalse;
/* Load qdisc, BPF program */ if (CHECK_FAIL(system("tc qdisc add dev lo clsact"))) returnfalse;
sprintf(tc_cmd, "%s %s %s %s %s", "tc filter add dev lo ingress bpf", "direct-action object-file", prog, "section tc",
(env.verbosity < VERBOSE_VERY) ? " 2>/dev/null" : "verbose"); if (CHECK(system(tc_cmd), "BPF load failed;", "run with -vv for more info\n")) returnfalse;
staticint
run_test(int server_fd, conststruct sockaddr *addr, socklen_t len, int type)
{ int client = -1, srv_client = -1; char buf[] = "testing";
in_port_t port; int ret = 1;
client = connect_to_addr(type, (struct sockaddr_storage *)addr, len, NULL); if (client == -1) {
perror("Cannot connect to server"); goto out;
}
if (type == SOCK_STREAM) {
srv_client = accept(server_fd, NULL, NULL); if (CHECK_FAIL(srv_client == -1)) {
perror("Can't accept connection"); goto out;
}
} else {
srv_client = server_fd;
} if (CHECK_FAIL(write(client, buf, sizeof(buf)) != sizeof(buf))) {
perror("Can't write on client"); goto out;
} if (CHECK_FAIL(rcv_msg(srv_client, type) != sizeof(buf))) {
perror("Can't read on server"); goto out;
}
port = get_port(srv_client); if (CHECK_FAIL(!port)) goto out; /* SOCK_STREAM is connected via accept(), so the server's local address * will be the CONNECT_PORT rather than the BIND port that corresponds * to the listen socket. SOCK_DGRAM on the other hand is connectionless * so we can't really do the same check there; the server doesn't ever * create a socket with CONNECT_PORT.
*/ if (type == SOCK_STREAM &&
CHECK(port != htons(CONNECT_PORT), "Expected", "port %u but got %u",
CONNECT_PORT, ntohs(port))) goto out; elseif (type == SOCK_DGRAM &&
CHECK(port != htons(BIND_PORT), "Expected", "port %u but got %u", BIND_PORT, ntohs(port))) goto out;
ret = 0;
out:
close(client); if (srv_client != server_fd)
close(srv_client); if (ret)
WRITE_ONCE(stop, 1); return ret;
}
self_net = open(NS_SELF, O_RDONLY); if (CHECK_FAIL(self_net < 0)) {
perror("Unable to open "NS_SELF); return;
}
if (!configure_stack()) {
perror("configure_stack"); goto cleanup;
}
server_map = bpf_obj_get(SERVER_MAP_PATH); if (CHECK_FAIL(server_map < 0)) {
perror("Unable to open " SERVER_MAP_PATH); goto cleanup;
}
for (i = 0; i < ARRAY_SIZE(tests) && !READ_ONCE(stop); i++) { struct test_sk_cfg *test = &tests[i]; conststruct sockaddr *addr; constint zero = 0; int err;
if (!test__start_subtest(test->name)) continue;
prepare_addr(test->addr, test->family, BIND_PORT, false);
addr = (conststruct sockaddr *)test->addr;
server = start_server_addr(test->type,
(conststruct sockaddr_storage *)addr,
test->len, NULL); if (server == -1) goto close;
err = bpf_map_update_elem(server_map, &zero, &server, BPF_ANY); if (CHECK_FAIL(err)) {
perror("Unable to update server_map"); goto close;
}
/* connect to unbound ports */
prepare_addr(test->addr, test->family, CONNECT_PORT,
test->rewrite_addr); if (run_test(server, addr, test->len, test->type)) goto close;
close(server);
server = -1;
}
close:
close(server);
close(server_map);
cleanup: if (CHECK_FAIL(unlink(SERVER_MAP_PATH)))
perror("Unable to unlink " SERVER_MAP_PATH); if (CHECK_FAIL(setns(self_net, CLONE_NEWNET)))
perror("Failed to setns("NS_SELF")");
close(self_net);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.