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_prog_load_attr attr = {
55 		.file = v4 ? "./connect_force_port4.o" :
56 			     "./connect_force_port6.o",
57 	};
58 	struct bpf_program *prog;
59 	struct bpf_object *obj;
60 	int xlate_fd, fd, err;
61 	__u32 duration = 0;
62 
63 	err = bpf_prog_load_xattr(&attr, &obj, &xlate_fd);
64 	if (err) {
65 		log_err("Failed to load BPF object");
66 		return -1;
67 	}
68 
69 	prog = bpf_object__find_program_by_title(obj, v4 ?
70 						 "cgroup/connect4" :
71 						 "cgroup/connect6");
72 	if (CHECK(!prog, "find_prog", "connect prog not found\n")) {
73 		err = -EIO;
74 		goto close_bpf_object;
75 	}
76 
77 	err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, v4 ?
78 			      BPF_CGROUP_INET4_CONNECT :
79 			      BPF_CGROUP_INET6_CONNECT, 0);
80 	if (err) {
81 		log_err("Failed to attach BPF program");
82 		goto close_bpf_object;
83 	}
84 
85 	prog = bpf_object__find_program_by_title(obj, v4 ?
86 						 "cgroup/getpeername4" :
87 						 "cgroup/getpeername6");
88 	if (CHECK(!prog, "find_prog", "getpeername prog not found\n")) {
89 		err = -EIO;
90 		goto close_bpf_object;
91 	}
92 
93 	err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, v4 ?
94 			      BPF_CGROUP_INET4_GETPEERNAME :
95 			      BPF_CGROUP_INET6_GETPEERNAME, 0);
96 	if (err) {
97 		log_err("Failed to attach BPF program");
98 		goto close_bpf_object;
99 	}
100 
101 	prog = bpf_object__find_program_by_title(obj, v4 ?
102 						 "cgroup/getsockname4" :
103 						 "cgroup/getsockname6");
104 	if (CHECK(!prog, "find_prog", "getsockname prog not found\n")) {
105 		err = -EIO;
106 		goto close_bpf_object;
107 	}
108 
109 	err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, v4 ?
110 			      BPF_CGROUP_INET4_GETSOCKNAME :
111 			      BPF_CGROUP_INET6_GETSOCKNAME, 0);
112 	if (err) {
113 		log_err("Failed to attach BPF program");
114 		goto close_bpf_object;
115 	}
116 
117 	fd = connect_to_fd(server_fd, 0);
118 	if (fd < 0) {
119 		err = -1;
120 		goto close_bpf_object;
121 	}
122 
123 	err = verify_ports(family, fd, expected_local_port,
124 			   expected_peer_port);
125 	close(fd);
126 
127 close_bpf_object:
128 	bpf_object__close(obj);
129 	return err;
130 }
131 
132 void test_connect_force_port(void)
133 {
134 	int server_fd, cgroup_fd;
135 
136 	cgroup_fd = test__join_cgroup("/connect_force_port");
137 	if (CHECK_FAIL(cgroup_fd < 0))
138 		return;
139 
140 	server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 60123, 0);
141 	if (CHECK_FAIL(server_fd < 0))
142 		goto close_cgroup_fd;
143 	CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_STREAM));
144 	close(server_fd);
145 
146 	server_fd = start_server(AF_INET6, SOCK_STREAM, NULL, 60124, 0);
147 	if (CHECK_FAIL(server_fd < 0))
148 		goto close_cgroup_fd;
149 	CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_STREAM));
150 	close(server_fd);
151 
152 	server_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 60123, 0);
153 	if (CHECK_FAIL(server_fd < 0))
154 		goto close_cgroup_fd;
155 	CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_DGRAM));
156 	close(server_fd);
157 
158 	server_fd = start_server(AF_INET6, SOCK_DGRAM, NULL, 60124, 0);
159 	if (CHECK_FAIL(server_fd < 0))
160 		goto close_cgroup_fd;
161 	CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_DGRAM));
162 	close(server_fd);
163 
164 close_cgroup_fd:
165 	close(cgroup_fd);
166 }
167