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 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 = !SYS_NOFAIL("ip netns exec " NS0 " ping -6 -c 1 -W 1 " VETH1_ADDR6); 63 else 64 up = !SYS_NOFAIL("ip netns exec " NS0 " ping -c 1 -W 1 " VETH1_ADDR); 65 66 if (up) 67 break; 68 } 69 70 return 0; 71 fail: 72 return -1; 73 } 74 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 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 if (!ASSERT_OK_PTR(nstoken, "setns")) 92 goto out; 93 94 skel->links.defrag = bpf_program__attach_netfilter(skel->progs.defrag, &opts); 95 if (!ASSERT_OK_PTR(skel->links.defrag, "program attach")) 96 goto out; 97 98 err = 0; 99 out: 100 close_netns(nstoken); 101 return err; 102 } 103 104 static int send_frags(int client) 105 { 106 struct sockaddr_storage saddr; 107 struct sockaddr *saddr_p; 108 socklen_t saddr_len; 109 int err; 110 111 saddr_p = (struct sockaddr *)&saddr; 112 err = make_sockaddr(AF_INET, VETH1_ADDR, SERVER_PORT, &saddr, &saddr_len); 113 if (!ASSERT_OK(err, "make_sockaddr")) 114 return -1; 115 116 err = sendto(client, frag_0, sizeof(frag_0), 0, saddr_p, saddr_len); 117 if (!ASSERT_GE(err, 0, "sendto frag_0")) 118 return -1; 119 120 err = sendto(client, frag_1, sizeof(frag_1), 0, saddr_p, saddr_len); 121 if (!ASSERT_GE(err, 0, "sendto frag_1")) 122 return -1; 123 124 err = sendto(client, frag_2, sizeof(frag_2), 0, saddr_p, saddr_len); 125 if (!ASSERT_GE(err, 0, "sendto frag_2")) 126 return -1; 127 128 return 0; 129 } 130 131 static int send_frags6(int client) 132 { 133 struct sockaddr_storage saddr; 134 struct sockaddr *saddr_p; 135 socklen_t saddr_len; 136 int err; 137 138 saddr_p = (struct sockaddr *)&saddr; 139 /* Port needs to be set to 0 for raw ipv6 socket for some reason */ 140 err = make_sockaddr(AF_INET6, VETH1_ADDR6, 0, &saddr, &saddr_len); 141 if (!ASSERT_OK(err, "make_sockaddr")) 142 return -1; 143 144 err = sendto(client, frag6_0, sizeof(frag6_0), 0, saddr_p, saddr_len); 145 if (!ASSERT_GE(err, 0, "sendto frag6_0")) 146 return -1; 147 148 err = sendto(client, frag6_1, sizeof(frag6_1), 0, saddr_p, saddr_len); 149 if (!ASSERT_GE(err, 0, "sendto frag6_1")) 150 return -1; 151 152 err = sendto(client, frag6_2, sizeof(frag6_2), 0, saddr_p, saddr_len); 153 if (!ASSERT_GE(err, 0, "sendto frag6_2")) 154 return -1; 155 156 return 0; 157 } 158 159 void test_bpf_ip_check_defrag_ok(bool ipv6) 160 { 161 struct network_helper_opts rx_opts = { 162 .timeout_ms = 1000, 163 .noconnect = true, 164 }; 165 struct network_helper_opts tx_ops = { 166 .timeout_ms = 1000, 167 .type = SOCK_RAW, 168 .proto = IPPROTO_RAW, 169 .noconnect = true, 170 }; 171 struct sockaddr_storage caddr; 172 struct ip_check_defrag *skel; 173 struct nstoken *nstoken; 174 int client_tx_fd = -1; 175 int client_rx_fd = -1; 176 socklen_t caddr_len; 177 int srv_fd = -1; 178 char buf[1024]; 179 int len, err; 180 181 skel = ip_check_defrag__open_and_load(); 182 if (!ASSERT_OK_PTR(skel, "skel_open")) 183 return; 184 185 if (!ASSERT_OK(setup_topology(ipv6), "setup_topology")) 186 goto out; 187 188 if (!ASSERT_OK(attach(skel, ipv6), "attach")) 189 goto out; 190 191 /* Start server in ns1 */ 192 nstoken = open_netns(NS1); 193 if (!ASSERT_OK_PTR(nstoken, "setns ns1")) 194 goto out; 195 srv_fd = start_server(ipv6 ? AF_INET6 : AF_INET, SOCK_DGRAM, NULL, SERVER_PORT, 0); 196 close_netns(nstoken); 197 if (!ASSERT_GE(srv_fd, 0, "start_server")) 198 goto out; 199 200 /* Open tx raw socket in ns0 */ 201 nstoken = open_netns(NS0); 202 if (!ASSERT_OK_PTR(nstoken, "setns ns0")) 203 goto out; 204 client_tx_fd = connect_to_fd_opts(srv_fd, &tx_ops); 205 close_netns(nstoken); 206 if (!ASSERT_GE(client_tx_fd, 0, "connect_to_fd_opts")) 207 goto out; 208 209 /* Open rx socket in ns0 */ 210 nstoken = open_netns(NS0); 211 if (!ASSERT_OK_PTR(nstoken, "setns ns0")) 212 goto out; 213 client_rx_fd = connect_to_fd_opts(srv_fd, &rx_opts); 214 close_netns(nstoken); 215 if (!ASSERT_GE(client_rx_fd, 0, "connect_to_fd_opts")) 216 goto out; 217 218 /* Bind rx socket to a premeditated port */ 219 memset(&caddr, 0, sizeof(caddr)); 220 nstoken = open_netns(NS0); 221 if (!ASSERT_OK_PTR(nstoken, "setns ns0")) 222 goto out; 223 if (ipv6) { 224 struct sockaddr_in6 *c = (struct sockaddr_in6 *)&caddr; 225 226 c->sin6_family = AF_INET6; 227 inet_pton(AF_INET6, VETH0_ADDR6, &c->sin6_addr); 228 c->sin6_port = htons(CLIENT_PORT); 229 err = bind(client_rx_fd, (struct sockaddr *)c, sizeof(*c)); 230 } else { 231 struct sockaddr_in *c = (struct sockaddr_in *)&caddr; 232 233 c->sin_family = AF_INET; 234 inet_pton(AF_INET, VETH0_ADDR, &c->sin_addr); 235 c->sin_port = htons(CLIENT_PORT); 236 err = bind(client_rx_fd, (struct sockaddr *)c, sizeof(*c)); 237 } 238 close_netns(nstoken); 239 if (!ASSERT_OK(err, "bind")) 240 goto out; 241 242 /* Send message in fragments */ 243 if (ipv6) { 244 if (!ASSERT_OK(send_frags6(client_tx_fd), "send_frags6")) 245 goto out; 246 } else { 247 if (!ASSERT_OK(send_frags(client_tx_fd), "send_frags")) 248 goto out; 249 } 250 251 if (!ASSERT_EQ(skel->bss->shootdowns, 0, "shootdowns")) 252 goto out; 253 254 /* Receive reassembled msg on server and echo back to client */ 255 caddr_len = sizeof(caddr); 256 len = recvfrom(srv_fd, buf, sizeof(buf), 0, (struct sockaddr *)&caddr, &caddr_len); 257 if (!ASSERT_GE(len, 0, "server recvfrom")) 258 goto out; 259 len = sendto(srv_fd, buf, len, 0, (struct sockaddr *)&caddr, caddr_len); 260 if (!ASSERT_GE(len, 0, "server sendto")) 261 goto out; 262 263 /* Expect reassembed message to be echoed back */ 264 len = recvfrom(client_rx_fd, buf, sizeof(buf), 0, NULL, NULL); 265 if (!ASSERT_EQ(len, sizeof(MAGIC_MESSAGE) - 1, "client short read")) 266 goto out; 267 268 out: 269 if (client_rx_fd != -1) 270 close(client_rx_fd); 271 if (client_tx_fd != -1) 272 close(client_tx_fd); 273 if (srv_fd != -1) 274 close(srv_fd); 275 cleanup_topology(); 276 ip_check_defrag__destroy(skel); 277 } 278 279 void test_bpf_ip_check_defrag(void) 280 { 281 if (test__start_subtest("v4")) 282 test_bpf_ip_check_defrag_ok(false); 283 if (test__start_subtest("v6")) 284 test_bpf_ip_check_defrag_ok(true); 285 } 286