| // 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); |
| } |