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 = !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 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 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 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 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 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 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