1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include <net/if.h>
4 #include <linux/netfilter.h>
5 #include <network_helpers.h>
6 #include "ip_check_defrag.skel.h"
7 #include "ip_check_defrag_frags.h"
8
9 /*
10 * This selftest spins up a client and an echo server, each in their own
11 * network namespace. The client will send a fragmented message to the server.
12 * The prog attached to the server will shoot down any fragments. Thus, if
13 * the server is able to correctly echo back the message to the client, we will
14 * have verified that netfilter is reassembling packets for us.
15 *
16 * Topology:
17 * =========
18 * NS0 | NS1
19 * |
20 * client | server
21 * ---------- | ----------
22 * | veth0 | --------- | veth1 |
23 * ---------- peer ----------
24 * |
25 * | with bpf
26 */
27
28 #define NS0 "defrag_ns0"
29 #define NS1 "defrag_ns1"
30 #define VETH0 "veth0"
31 #define VETH1 "veth1"
32 #define VETH0_ADDR "172.16.1.100"
33 #define VETH0_ADDR6 "fc00::100"
34 /* The following constants must stay in sync with `generate_udp_fragments.py` */
35 #define VETH1_ADDR "172.16.1.200"
36 #define VETH1_ADDR6 "fc00::200"
37 #define CLIENT_PORT 48878
38 #define SERVER_PORT 48879
39 #define MAGIC_MESSAGE "THIS IS THE ORIGINAL MESSAGE, PLEASE REASSEMBLE ME"
40
setup_topology(bool ipv6)41 static int setup_topology(bool ipv6)
42 {
43 bool up;
44 int i;
45
46 SYS(fail, "ip netns add " NS0);
47 SYS(fail, "ip netns add " NS1);
48 SYS(fail, "ip link add " VETH0 " netns " NS0 " type veth peer name " VETH1 " netns " NS1);
49 if (ipv6) {
50 SYS(fail, "ip -6 -net " NS0 " addr add " VETH0_ADDR6 "/64 dev " VETH0 " nodad");
51 SYS(fail, "ip -6 -net " NS1 " addr add " VETH1_ADDR6 "/64 dev " VETH1 " nodad");
52 } else {
53 SYS(fail, "ip -net " NS0 " addr add " VETH0_ADDR "/24 dev " VETH0);
54 SYS(fail, "ip -net " NS1 " addr add " VETH1_ADDR "/24 dev " VETH1);
55 }
56 SYS(fail, "ip -net " NS0 " link set dev " VETH0 " up");
57 SYS(fail, "ip -net " NS1 " link set dev " VETH1 " up");
58
59 /* Wait for up to 5s for links to come up */
60 for (i = 0; i < 5; ++i) {
61 if (ipv6)
62 up = !system("ip netns exec " NS0 " ping -6 -c 1 -W 1 " VETH1_ADDR6 " &>/dev/null");
63 else
64 up = !system("ip netns exec " NS0 " ping -c 1 -W 1 " VETH1_ADDR " &>/dev/null");
65
66 if (up)
67 break;
68 }
69
70 return 0;
71 fail:
72 return -1;
73 }
74
cleanup_topology(void)75 static void cleanup_topology(void)
76 {
77 SYS_NOFAIL("test -f /var/run/netns/" NS0 " && ip netns delete " NS0);
78 SYS_NOFAIL("test -f /var/run/netns/" NS1 " && ip netns delete " NS1);
79 }
80
attach(struct ip_check_defrag * skel,bool ipv6)81 static int attach(struct ip_check_defrag *skel, bool ipv6)
82 {
83 LIBBPF_OPTS(bpf_netfilter_opts, opts,
84 .pf = ipv6 ? NFPROTO_IPV6 : NFPROTO_IPV4,
85 .priority = 42,
86 .flags = BPF_F_NETFILTER_IP_DEFRAG);
87 struct nstoken *nstoken;
88 int err = -1;
89
90 nstoken = open_netns(NS1);
91
92 skel->links.defrag = bpf_program__attach_netfilter(skel->progs.defrag, &opts);
93 if (!ASSERT_OK_PTR(skel->links.defrag, "program attach"))
94 goto out;
95
96 err = 0;
97 out:
98 close_netns(nstoken);
99 return err;
100 }
101
send_frags(int client)102 static int send_frags(int client)
103 {
104 struct sockaddr_storage saddr;
105 struct sockaddr *saddr_p;
106 socklen_t saddr_len;
107 int err;
108
109 saddr_p = (struct sockaddr *)&saddr;
110 err = make_sockaddr(AF_INET, VETH1_ADDR, SERVER_PORT, &saddr, &saddr_len);
111 if (!ASSERT_OK(err, "make_sockaddr"))
112 return -1;
113
114 err = sendto(client, frag_0, sizeof(frag_0), 0, saddr_p, saddr_len);
115 if (!ASSERT_GE(err, 0, "sendto frag_0"))
116 return -1;
117
118 err = sendto(client, frag_1, sizeof(frag_1), 0, saddr_p, saddr_len);
119 if (!ASSERT_GE(err, 0, "sendto frag_1"))
120 return -1;
121
122 err = sendto(client, frag_2, sizeof(frag_2), 0, saddr_p, saddr_len);
123 if (!ASSERT_GE(err, 0, "sendto frag_2"))
124 return -1;
125
126 return 0;
127 }
128
send_frags6(int client)129 static int send_frags6(int client)
130 {
131 struct sockaddr_storage saddr;
132 struct sockaddr *saddr_p;
133 socklen_t saddr_len;
134 int err;
135
136 saddr_p = (struct sockaddr *)&saddr;
137 /* Port needs to be set to 0 for raw ipv6 socket for some reason */
138 err = make_sockaddr(AF_INET6, VETH1_ADDR6, 0, &saddr, &saddr_len);
139 if (!ASSERT_OK(err, "make_sockaddr"))
140 return -1;
141
142 err = sendto(client, frag6_0, sizeof(frag6_0), 0, saddr_p, saddr_len);
143 if (!ASSERT_GE(err, 0, "sendto frag6_0"))
144 return -1;
145
146 err = sendto(client, frag6_1, sizeof(frag6_1), 0, saddr_p, saddr_len);
147 if (!ASSERT_GE(err, 0, "sendto frag6_1"))
148 return -1;
149
150 err = sendto(client, frag6_2, sizeof(frag6_2), 0, saddr_p, saddr_len);
151 if (!ASSERT_GE(err, 0, "sendto frag6_2"))
152 return -1;
153
154 return 0;
155 }
156
test_bpf_ip_check_defrag_ok(bool ipv6)157 void test_bpf_ip_check_defrag_ok(bool ipv6)
158 {
159 struct network_helper_opts rx_opts = {
160 .timeout_ms = 1000,
161 .noconnect = true,
162 };
163 struct network_helper_opts tx_ops = {
164 .timeout_ms = 1000,
165 .type = SOCK_RAW,
166 .proto = IPPROTO_RAW,
167 .noconnect = true,
168 };
169 struct sockaddr_storage caddr;
170 struct ip_check_defrag *skel;
171 struct nstoken *nstoken;
172 int client_tx_fd = -1;
173 int client_rx_fd = -1;
174 socklen_t caddr_len;
175 int srv_fd = -1;
176 char buf[1024];
177 int len, err;
178
179 skel = ip_check_defrag__open_and_load();
180 if (!ASSERT_OK_PTR(skel, "skel_open"))
181 return;
182
183 if (!ASSERT_OK(setup_topology(ipv6), "setup_topology"))
184 goto out;
185
186 if (!ASSERT_OK(attach(skel, ipv6), "attach"))
187 goto out;
188
189 /* Start server in ns1 */
190 nstoken = open_netns(NS1);
191 if (!ASSERT_OK_PTR(nstoken, "setns ns1"))
192 goto out;
193 srv_fd = start_server(ipv6 ? AF_INET6 : AF_INET, SOCK_DGRAM, NULL, SERVER_PORT, 0);
194 close_netns(nstoken);
195 if (!ASSERT_GE(srv_fd, 0, "start_server"))
196 goto out;
197
198 /* Open tx raw socket in ns0 */
199 nstoken = open_netns(NS0);
200 if (!ASSERT_OK_PTR(nstoken, "setns ns0"))
201 goto out;
202 client_tx_fd = connect_to_fd_opts(srv_fd, &tx_ops);
203 close_netns(nstoken);
204 if (!ASSERT_GE(client_tx_fd, 0, "connect_to_fd_opts"))
205 goto out;
206
207 /* Open rx socket in ns0 */
208 nstoken = open_netns(NS0);
209 if (!ASSERT_OK_PTR(nstoken, "setns ns0"))
210 goto out;
211 client_rx_fd = connect_to_fd_opts(srv_fd, &rx_opts);
212 close_netns(nstoken);
213 if (!ASSERT_GE(client_rx_fd, 0, "connect_to_fd_opts"))
214 goto out;
215
216 /* Bind rx socket to a premeditated port */
217 memset(&caddr, 0, sizeof(caddr));
218 nstoken = open_netns(NS0);
219 if (!ASSERT_OK_PTR(nstoken, "setns ns0"))
220 goto out;
221 if (ipv6) {
222 struct sockaddr_in6 *c = (struct sockaddr_in6 *)&caddr;
223
224 c->sin6_family = AF_INET6;
225 inet_pton(AF_INET6, VETH0_ADDR6, &c->sin6_addr);
226 c->sin6_port = htons(CLIENT_PORT);
227 err = bind(client_rx_fd, (struct sockaddr *)c, sizeof(*c));
228 } else {
229 struct sockaddr_in *c = (struct sockaddr_in *)&caddr;
230
231 c->sin_family = AF_INET;
232 inet_pton(AF_INET, VETH0_ADDR, &c->sin_addr);
233 c->sin_port = htons(CLIENT_PORT);
234 err = bind(client_rx_fd, (struct sockaddr *)c, sizeof(*c));
235 }
236 close_netns(nstoken);
237 if (!ASSERT_OK(err, "bind"))
238 goto out;
239
240 /* Send message in fragments */
241 if (ipv6) {
242 if (!ASSERT_OK(send_frags6(client_tx_fd), "send_frags6"))
243 goto out;
244 } else {
245 if (!ASSERT_OK(send_frags(client_tx_fd), "send_frags"))
246 goto out;
247 }
248
249 if (!ASSERT_EQ(skel->bss->shootdowns, 0, "shootdowns"))
250 goto out;
251
252 /* Receive reassembled msg on server and echo back to client */
253 caddr_len = sizeof(caddr);
254 len = recvfrom(srv_fd, buf, sizeof(buf), 0, (struct sockaddr *)&caddr, &caddr_len);
255 if (!ASSERT_GE(len, 0, "server recvfrom"))
256 goto out;
257 len = sendto(srv_fd, buf, len, 0, (struct sockaddr *)&caddr, caddr_len);
258 if (!ASSERT_GE(len, 0, "server sendto"))
259 goto out;
260
261 /* Expect reassembed message to be echoed back */
262 len = recvfrom(client_rx_fd, buf, sizeof(buf), 0, NULL, NULL);
263 if (!ASSERT_EQ(len, sizeof(MAGIC_MESSAGE) - 1, "client short read"))
264 goto out;
265
266 out:
267 if (client_rx_fd != -1)
268 close(client_rx_fd);
269 if (client_tx_fd != -1)
270 close(client_tx_fd);
271 if (srv_fd != -1)
272 close(srv_fd);
273 cleanup_topology();
274 ip_check_defrag__destroy(skel);
275 }
276
test_bpf_ip_check_defrag(void)277 void test_bpf_ip_check_defrag(void)
278 {
279 if (test__start_subtest("v4"))
280 test_bpf_ip_check_defrag_ok(false);
281 if (test__start_subtest("v6"))
282 test_bpf_ip_check_defrag_ok(true);
283 }
284