brintos

brintos / linux-shallow public Read only

0
0
Text · 7.7 KiB · 4ddb8a5 Raw
284 lines · c
1// SPDX-License-Identifier: GPL-2.02#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 own11 * 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, if13 * the server is able to correctly echo back the message to the client, we will14 * have verified that netfilter is reassembling packets for us.15 *16 * Topology:17 * =========18 *           NS0         |         NS119 *                       |20 *         client        |       server21 *       ----------      |     ----------22 *       |  veth0  | --------- |  veth1  |23 *       ----------    peer    ----------24 *                       |25 *                       |       with bpf26 */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	4887838#define SERVER_PORT	4887939#define MAGIC_MESSAGE	"THIS IS THE ORIGINAL MESSAGE, PLEASE REASSEMBLE ME"40 41static 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		else64			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;71fail:72	return -1;73}74 75static 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 81static 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;99out:100	close_netns(nstoken);101	return err;102}103 104static 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 131static 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 159void test_bpf_ip_check_defrag_ok(bool ipv6)160{161	int family = ipv6 ? AF_INET6 : AF_INET;162	struct network_helper_opts rx_opts = {163		.timeout_ms = 1000,164	};165	struct network_helper_opts tx_ops = {166		.timeout_ms = 1000,167		.proto = IPPROTO_RAW,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(family, 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 = client_socket(family, SOCK_RAW, &tx_ops);203	close_netns(nstoken);204	if (!ASSERT_GE(client_tx_fd, 0, "client_socket"))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 = client_socket(family, SOCK_DGRAM, &rx_opts);212	close_netns(nstoken);213	if (!ASSERT_GE(client_rx_fd, 0, "client_socket"))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 266out: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 277void 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