1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018 Facebook
3 // Copyright (c) 2019 Cloudflare
4 // Copyright (c) 2020 Isovalent, Inc.
5 /*
6  * Test that the socket assign program is able to redirect traffic towards a
7  * socket, regardless of whether the port or address destination of the traffic
8  * matches the port.
9  */
10 
11 #define _GNU_SOURCE
12 #include <fcntl.h>
13 #include <signal.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 
17 #include "test_progs.h"
18 
19 #define BIND_PORT 1234
20 #define CONNECT_PORT 4321
21 #define TEST_DADDR (0xC0A80203)
22 #define NS_SELF "/proc/self/ns/net"
23 #define SERVER_MAP_PATH "/sys/fs/bpf/tc/globals/server_map"
24 
25 static const struct timeval timeo_sec = { .tv_sec = 3 };
26 static const size_t timeo_optlen = sizeof(timeo_sec);
27 static int stop, duration;
28 
29 static bool
30 configure_stack(void)
31 {
32 	char tc_cmd[BUFSIZ];
33 
34 	/* Move to a new networking namespace */
35 	if (CHECK_FAIL(unshare(CLONE_NEWNET)))
36 		return false;
37 
38 	/* Configure necessary links, routes */
39 	if (CHECK_FAIL(system("ip link set dev lo up")))
40 		return false;
41 	if (CHECK_FAIL(system("ip route add local default dev lo")))
42 		return false;
43 	if (CHECK_FAIL(system("ip -6 route add local default dev lo")))
44 		return false;
45 
46 	/* Load qdisc, BPF program */
47 	if (CHECK_FAIL(system("tc qdisc add dev lo clsact")))
48 		return false;
49 	sprintf(tc_cmd, "%s %s %s %s", "tc filter add dev lo ingress bpf",
50 		       "direct-action object-file ./test_sk_assign.o",
51 		       "section classifier/sk_assign_test",
52 		       (env.verbosity < VERBOSE_VERY) ? " 2>/dev/null" : "verbose");
53 	if (CHECK(system(tc_cmd), "BPF load failed;",
54 		  "run with -vv for more info\n"))
55 		return false;
56 
57 	return true;
58 }
59 
60 static int
61 start_server(const struct sockaddr *addr, socklen_t len, int type)
62 {
63 	int fd;
64 
65 	fd = socket(addr->sa_family, type, 0);
66 	if (CHECK_FAIL(fd == -1))
67 		goto out;
68 	if (CHECK_FAIL(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo_sec,
69 				  timeo_optlen)))
70 		goto close_out;
71 	if (CHECK_FAIL(bind(fd, addr, len) == -1))
72 		goto close_out;
73 	if (type == SOCK_STREAM && CHECK_FAIL(listen(fd, 128) == -1))
74 		goto close_out;
75 
76 	goto out;
77 close_out:
78 	close(fd);
79 	fd = -1;
80 out:
81 	return fd;
82 }
83 
84 static int
85 connect_to_server(const struct sockaddr *addr, socklen_t len, int type)
86 {
87 	int fd = -1;
88 
89 	fd = socket(addr->sa_family, type, 0);
90 	if (CHECK_FAIL(fd == -1))
91 		goto out;
92 	if (CHECK_FAIL(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo_sec,
93 				  timeo_optlen)))
94 		goto close_out;
95 	if (CHECK_FAIL(connect(fd, addr, len)))
96 		goto close_out;
97 
98 	goto out;
99 close_out:
100 	close(fd);
101 	fd = -1;
102 out:
103 	return fd;
104 }
105 
106 static in_port_t
107 get_port(int fd)
108 {
109 	struct sockaddr_storage ss;
110 	socklen_t slen = sizeof(ss);
111 	in_port_t port = 0;
112 
113 	if (CHECK_FAIL(getsockname(fd, (struct sockaddr *)&ss, &slen)))
114 		return port;
115 
116 	switch (ss.ss_family) {
117 	case AF_INET:
118 		port = ((struct sockaddr_in *)&ss)->sin_port;
119 		break;
120 	case AF_INET6:
121 		port = ((struct sockaddr_in6 *)&ss)->sin6_port;
122 		break;
123 	default:
124 		CHECK(1, "Invalid address family", "%d\n", ss.ss_family);
125 	}
126 	return port;
127 }
128 
129 static ssize_t
130 rcv_msg(int srv_client, int type)
131 {
132 	struct sockaddr_storage ss;
133 	char buf[BUFSIZ];
134 	socklen_t slen;
135 
136 	if (type == SOCK_STREAM)
137 		return read(srv_client, &buf, sizeof(buf));
138 	else
139 		return recvfrom(srv_client, &buf, sizeof(buf), 0,
140 				(struct sockaddr *)&ss, &slen);
141 }
142 
143 static int
144 run_test(int server_fd, const struct sockaddr *addr, socklen_t len, int type)
145 {
146 	int client = -1, srv_client = -1;
147 	char buf[] = "testing";
148 	in_port_t port;
149 	int ret = 1;
150 
151 	client = connect_to_server(addr, len, type);
152 	if (client == -1) {
153 		perror("Cannot connect to server");
154 		goto out;
155 	}
156 
157 	if (type == SOCK_STREAM) {
158 		srv_client = accept(server_fd, NULL, NULL);
159 		if (CHECK_FAIL(srv_client == -1)) {
160 			perror("Can't accept connection");
161 			goto out;
162 		}
163 	} else {
164 		srv_client = server_fd;
165 	}
166 	if (CHECK_FAIL(write(client, buf, sizeof(buf)) != sizeof(buf))) {
167 		perror("Can't write on client");
168 		goto out;
169 	}
170 	if (CHECK_FAIL(rcv_msg(srv_client, type) != sizeof(buf))) {
171 		perror("Can't read on server");
172 		goto out;
173 	}
174 
175 	port = get_port(srv_client);
176 	if (CHECK_FAIL(!port))
177 		goto out;
178 	/* SOCK_STREAM is connected via accept(), so the server's local address
179 	 * will be the CONNECT_PORT rather than the BIND port that corresponds
180 	 * to the listen socket. SOCK_DGRAM on the other hand is connectionless
181 	 * so we can't really do the same check there; the server doesn't ever
182 	 * create a socket with CONNECT_PORT.
183 	 */
184 	if (type == SOCK_STREAM &&
185 	    CHECK(port != htons(CONNECT_PORT), "Expected", "port %u but got %u",
186 		  CONNECT_PORT, ntohs(port)))
187 		goto out;
188 	else if (type == SOCK_DGRAM &&
189 		 CHECK(port != htons(BIND_PORT), "Expected",
190 		       "port %u but got %u", BIND_PORT, ntohs(port)))
191 		goto out;
192 
193 	ret = 0;
194 out:
195 	close(client);
196 	if (srv_client != server_fd)
197 		close(srv_client);
198 	if (ret)
199 		WRITE_ONCE(stop, 1);
200 	return ret;
201 }
202 
203 static void
204 prepare_addr(struct sockaddr *addr, int family, __u16 port, bool rewrite_addr)
205 {
206 	struct sockaddr_in *addr4;
207 	struct sockaddr_in6 *addr6;
208 
209 	switch (family) {
210 	case AF_INET:
211 		addr4 = (struct sockaddr_in *)addr;
212 		memset(addr4, 0, sizeof(*addr4));
213 		addr4->sin_family = family;
214 		addr4->sin_port = htons(port);
215 		if (rewrite_addr)
216 			addr4->sin_addr.s_addr = htonl(TEST_DADDR);
217 		else
218 			addr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
219 		break;
220 	case AF_INET6:
221 		addr6 = (struct sockaddr_in6 *)addr;
222 		memset(addr6, 0, sizeof(*addr6));
223 		addr6->sin6_family = family;
224 		addr6->sin6_port = htons(port);
225 		addr6->sin6_addr = in6addr_loopback;
226 		if (rewrite_addr)
227 			addr6->sin6_addr.s6_addr32[3] = htonl(TEST_DADDR);
228 		break;
229 	default:
230 		fprintf(stderr, "Invalid family %d", family);
231 	}
232 }
233 
234 struct test_sk_cfg {
235 	const char *name;
236 	int family;
237 	struct sockaddr *addr;
238 	socklen_t len;
239 	int type;
240 	bool rewrite_addr;
241 };
242 
243 #define TEST(NAME, FAMILY, TYPE, REWRITE)				\
244 {									\
245 	.name = NAME,							\
246 	.family = FAMILY,						\
247 	.addr = (FAMILY == AF_INET) ? (struct sockaddr *)&addr4		\
248 				    : (struct sockaddr *)&addr6,	\
249 	.len = (FAMILY == AF_INET) ? sizeof(addr4) : sizeof(addr6),	\
250 	.type = TYPE,							\
251 	.rewrite_addr = REWRITE,					\
252 }
253 
254 void test_sk_assign(void)
255 {
256 	struct sockaddr_in addr4;
257 	struct sockaddr_in6 addr6;
258 	struct test_sk_cfg tests[] = {
259 		TEST("ipv4 tcp port redir", AF_INET, SOCK_STREAM, false),
260 		TEST("ipv4 tcp addr redir", AF_INET, SOCK_STREAM, true),
261 		TEST("ipv6 tcp port redir", AF_INET6, SOCK_STREAM, false),
262 		TEST("ipv6 tcp addr redir", AF_INET6, SOCK_STREAM, true),
263 		TEST("ipv4 udp port redir", AF_INET, SOCK_DGRAM, false),
264 		TEST("ipv4 udp addr redir", AF_INET, SOCK_DGRAM, true),
265 		TEST("ipv6 udp port redir", AF_INET6, SOCK_DGRAM, false),
266 		TEST("ipv6 udp addr redir", AF_INET6, SOCK_DGRAM, true),
267 	};
268 	__s64 server = -1;
269 	int server_map;
270 	int self_net;
271 	int i;
272 
273 	self_net = open(NS_SELF, O_RDONLY);
274 	if (CHECK_FAIL(self_net < 0)) {
275 		perror("Unable to open "NS_SELF);
276 		return;
277 	}
278 
279 	if (!configure_stack()) {
280 		perror("configure_stack");
281 		goto cleanup;
282 	}
283 
284 	server_map = bpf_obj_get(SERVER_MAP_PATH);
285 	if (CHECK_FAIL(server_map < 0)) {
286 		perror("Unable to open " SERVER_MAP_PATH);
287 		goto cleanup;
288 	}
289 
290 	for (i = 0; i < ARRAY_SIZE(tests) && !READ_ONCE(stop); i++) {
291 		struct test_sk_cfg *test = &tests[i];
292 		const struct sockaddr *addr;
293 		const int zero = 0;
294 		int err;
295 
296 		if (!test__start_subtest(test->name))
297 			continue;
298 		prepare_addr(test->addr, test->family, BIND_PORT, false);
299 		addr = (const struct sockaddr *)test->addr;
300 		server = start_server(addr, test->len, test->type);
301 		if (server == -1)
302 			goto close;
303 
304 		err = bpf_map_update_elem(server_map, &zero, &server, BPF_ANY);
305 		if (CHECK_FAIL(err)) {
306 			perror("Unable to update server_map");
307 			goto close;
308 		}
309 
310 		/* connect to unbound ports */
311 		prepare_addr(test->addr, test->family, CONNECT_PORT,
312 			     test->rewrite_addr);
313 		if (run_test(server, addr, test->len, test->type))
314 			goto close;
315 
316 		close(server);
317 		server = -1;
318 	}
319 
320 close:
321 	close(server);
322 	close(server_map);
323 cleanup:
324 	if (CHECK_FAIL(unlink(SERVER_MAP_PATH)))
325 		perror("Unable to unlink " SERVER_MAP_PATH);
326 	if (CHECK_FAIL(setns(self_net, CLONE_NEWNET)))
327 		perror("Failed to setns("NS_SELF")");
328 	close(self_net);
329 }
330