// SPDX-License-Identifier: GPL-2.0
|
|
#include <test_progs.h>
|
#include "cgroup_helpers.h"
|
#include "network_helpers.h"
|
|
static int verify_ports(int family, int fd,
|
__u16 expected_local, __u16 expected_peer)
|
{
|
struct sockaddr_storage addr;
|
socklen_t len = sizeof(addr);
|
__u16 port;
|
|
if (getsockname(fd, (struct sockaddr *)&addr, &len)) {
|
log_err("Failed to get server addr");
|
return -1;
|
}
|
|
if (family == AF_INET)
|
port = ((struct sockaddr_in *)&addr)->sin_port;
|
else
|
port = ((struct sockaddr_in6 *)&addr)->sin6_port;
|
|
if (ntohs(port) != expected_local) {
|
log_err("Unexpected local port %d, expected %d", ntohs(port),
|
expected_local);
|
return -1;
|
}
|
|
if (getpeername(fd, (struct sockaddr *)&addr, &len)) {
|
log_err("Failed to get peer addr");
|
return -1;
|
}
|
|
if (family == AF_INET)
|
port = ((struct sockaddr_in *)&addr)->sin_port;
|
else
|
port = ((struct sockaddr_in6 *)&addr)->sin6_port;
|
|
if (ntohs(port) != expected_peer) {
|
log_err("Unexpected peer port %d, expected %d", ntohs(port),
|
expected_peer);
|
return -1;
|
}
|
|
return 0;
|
}
|
|
static int run_test(int cgroup_fd, int server_fd, int family, int type)
|
{
|
bool v4 = family == AF_INET;
|
__u16 expected_local_port = v4 ? 22222 : 22223;
|
__u16 expected_peer_port = 60000;
|
struct bpf_prog_load_attr attr = {
|
.file = v4 ? "./connect_force_port4.o" :
|
"./connect_force_port6.o",
|
};
|
struct bpf_program *prog;
|
struct bpf_object *obj;
|
int xlate_fd, fd, err;
|
__u32 duration = 0;
|
|
err = bpf_prog_load_xattr(&attr, &obj, &xlate_fd);
|
if (err) {
|
log_err("Failed to load BPF object");
|
return -1;
|
}
|
|
prog = bpf_object__find_program_by_title(obj, v4 ?
|
"cgroup/connect4" :
|
"cgroup/connect6");
|
if (CHECK(!prog, "find_prog", "connect prog not found\n")) {
|
err = -EIO;
|
goto close_bpf_object;
|
}
|
|
err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, v4 ?
|
BPF_CGROUP_INET4_CONNECT :
|
BPF_CGROUP_INET6_CONNECT, 0);
|
if (err) {
|
log_err("Failed to attach BPF program");
|
goto close_bpf_object;
|
}
|
|
prog = bpf_object__find_program_by_title(obj, v4 ?
|
"cgroup/getpeername4" :
|
"cgroup/getpeername6");
|
if (CHECK(!prog, "find_prog", "getpeername prog not found\n")) {
|
err = -EIO;
|
goto close_bpf_object;
|
}
|
|
err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, v4 ?
|
BPF_CGROUP_INET4_GETPEERNAME :
|
BPF_CGROUP_INET6_GETPEERNAME, 0);
|
if (err) {
|
log_err("Failed to attach BPF program");
|
goto close_bpf_object;
|
}
|
|
prog = bpf_object__find_program_by_title(obj, v4 ?
|
"cgroup/getsockname4" :
|
"cgroup/getsockname6");
|
if (CHECK(!prog, "find_prog", "getsockname prog not found\n")) {
|
err = -EIO;
|
goto close_bpf_object;
|
}
|
|
err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, v4 ?
|
BPF_CGROUP_INET4_GETSOCKNAME :
|
BPF_CGROUP_INET6_GETSOCKNAME, 0);
|
if (err) {
|
log_err("Failed to attach BPF program");
|
goto close_bpf_object;
|
}
|
|
fd = connect_to_fd(server_fd, 0);
|
if (fd < 0) {
|
err = -1;
|
goto close_bpf_object;
|
}
|
|
err = verify_ports(family, fd, expected_local_port,
|
expected_peer_port);
|
close(fd);
|
|
close_bpf_object:
|
bpf_object__close(obj);
|
return err;
|
}
|
|
void test_connect_force_port(void)
|
{
|
int server_fd, cgroup_fd;
|
|
cgroup_fd = test__join_cgroup("/connect_force_port");
|
if (CHECK_FAIL(cgroup_fd < 0))
|
return;
|
|
server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 60123, 0);
|
if (CHECK_FAIL(server_fd < 0))
|
goto close_cgroup_fd;
|
CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_STREAM));
|
close(server_fd);
|
|
server_fd = start_server(AF_INET6, SOCK_STREAM, NULL, 60124, 0);
|
if (CHECK_FAIL(server_fd < 0))
|
goto close_cgroup_fd;
|
CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_STREAM));
|
close(server_fd);
|
|
server_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 60123, 0);
|
if (CHECK_FAIL(server_fd < 0))
|
goto close_cgroup_fd;
|
CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_DGRAM));
|
close(server_fd);
|
|
server_fd = start_server(AF_INET6, SOCK_DGRAM, NULL, 60124, 0);
|
if (CHECK_FAIL(server_fd < 0))
|
goto close_cgroup_fd;
|
CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_DGRAM));
|
close(server_fd);
|
|
close_cgroup_fd:
|
close(cgroup_fd);
|
}
|