1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <test_progs.h> 4 #include "cgroup_helpers.h" 5 #include "network_helpers.h" 6 7 static int verify_ports(int family, int fd, 8 __u16 expected_local, __u16 expected_peer) 9 { 10 struct sockaddr_storage addr; 11 socklen_t len = sizeof(addr); 12 __u16 port; 13 14 if (getsockname(fd, (struct sockaddr *)&addr, &len)) { 15 log_err("Failed to get server addr"); 16 return -1; 17 } 18 19 if (family == AF_INET) 20 port = ((struct sockaddr_in *)&addr)->sin_port; 21 else 22 port = ((struct sockaddr_in6 *)&addr)->sin6_port; 23 24 if (ntohs(port) != expected_local) { 25 log_err("Unexpected local port %d, expected %d", ntohs(port), 26 expected_local); 27 return -1; 28 } 29 30 if (getpeername(fd, (struct sockaddr *)&addr, &len)) { 31 log_err("Failed to get peer addr"); 32 return -1; 33 } 34 35 if (family == AF_INET) 36 port = ((struct sockaddr_in *)&addr)->sin_port; 37 else 38 port = ((struct sockaddr_in6 *)&addr)->sin6_port; 39 40 if (ntohs(port) != expected_peer) { 41 log_err("Unexpected peer port %d, expected %d", ntohs(port), 42 expected_peer); 43 return -1; 44 } 45 46 return 0; 47 } 48 49 static int run_test(int cgroup_fd, int server_fd, int family, int type) 50 { 51 bool v4 = family == AF_INET; 52 __u16 expected_local_port = v4 ? 22222 : 22223; 53 __u16 expected_peer_port = 60000; 54 struct bpf_program *prog; 55 struct bpf_object *obj; 56 struct bpf_map *map; 57 __u16 *port_ptr; 58 size_t port_size; 59 const char *obj_file = v4 ? "connect_force_port4.bpf.o" : "connect_force_port6.bpf.o"; 60 int fd, err; 61 __u32 duration = 0; 62 63 obj = bpf_object__open_file(obj_file, NULL); 64 if (!ASSERT_OK_PTR(obj, "bpf_obj_open")) 65 return -1; 66 67 map = bpf_object__find_map_by_name(obj, ".bss"); 68 if (!ASSERT_OK_PTR(map, "find bss map")) { 69 err = -EIO; 70 goto close_bpf_object; 71 } 72 73 port_ptr = bpf_map__initial_value(map, &port_size); 74 if (!ASSERT_OK_PTR(port_ptr, "get bss initial value")) { 75 err = -EIO; 76 goto close_bpf_object; 77 } 78 79 /* Auto assigns the port according to availability */ 80 *port_ptr = ntohs(get_socket_local_port(server_fd)); 81 82 err = bpf_object__load(obj); 83 if (!ASSERT_OK(err, "bpf_obj_load")) { 84 err = -EIO; 85 goto close_bpf_object; 86 } 87 88 prog = bpf_object__find_program_by_name(obj, v4 ? 89 "connect4" : 90 "connect6"); 91 if (CHECK(!prog, "find_prog", "connect prog not found\n")) { 92 err = -EIO; 93 goto close_bpf_object; 94 } 95 96 err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, v4 ? 97 BPF_CGROUP_INET4_CONNECT : 98 BPF_CGROUP_INET6_CONNECT, 0); 99 if (err) { 100 log_err("Failed to attach BPF program"); 101 goto close_bpf_object; 102 } 103 104 prog = bpf_object__find_program_by_name(obj, v4 ? 105 "getpeername4" : 106 "getpeername6"); 107 if (CHECK(!prog, "find_prog", "getpeername prog not found\n")) { 108 err = -EIO; 109 goto close_bpf_object; 110 } 111 112 err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, v4 ? 113 BPF_CGROUP_INET4_GETPEERNAME : 114 BPF_CGROUP_INET6_GETPEERNAME, 0); 115 if (err) { 116 log_err("Failed to attach BPF program"); 117 goto close_bpf_object; 118 } 119 120 prog = bpf_object__find_program_by_name(obj, v4 ? 121 "getsockname4" : 122 "getsockname6"); 123 if (CHECK(!prog, "find_prog", "getsockname prog not found\n")) { 124 err = -EIO; 125 goto close_bpf_object; 126 } 127 128 err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, v4 ? 129 BPF_CGROUP_INET4_GETSOCKNAME : 130 BPF_CGROUP_INET6_GETSOCKNAME, 0); 131 if (err) { 132 log_err("Failed to attach BPF program"); 133 goto close_bpf_object; 134 } 135 136 fd = connect_to_fd(server_fd, 0); 137 if (fd < 0) { 138 err = -1; 139 goto close_bpf_object; 140 } 141 142 err = verify_ports(family, fd, expected_local_port, 143 expected_peer_port); 144 close(fd); 145 146 close_bpf_object: 147 bpf_object__close(obj); 148 return err; 149 } 150 151 void test_connect_force_port(void) 152 { 153 int server_fd, cgroup_fd; 154 155 cgroup_fd = test__join_cgroup("/connect_force_port"); 156 if (CHECK_FAIL(cgroup_fd < 0)) 157 return; 158 159 server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0); 160 if (CHECK_FAIL(server_fd < 0)) 161 goto close_cgroup_fd; 162 CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_STREAM)); 163 close(server_fd); 164 165 server_fd = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0); 166 if (CHECK_FAIL(server_fd < 0)) 167 goto close_cgroup_fd; 168 CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_STREAM)); 169 close(server_fd); 170 171 server_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 0, 0); 172 if (CHECK_FAIL(server_fd < 0)) 173 goto close_cgroup_fd; 174 CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_DGRAM)); 175 close(server_fd); 176 177 server_fd = start_server(AF_INET6, SOCK_DGRAM, NULL, 0, 0); 178 if (CHECK_FAIL(server_fd < 0)) 179 goto close_cgroup_fd; 180 CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_DGRAM)); 181 close(server_fd); 182 183 close_cgroup_fd: 184 close(cgroup_fd); 185 } 186