~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/prog_tests/sk_assign.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php