xref: /linux/tools/testing/selftests/bpf/prog_tests/connect_ping.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
158c449a9SYiFei Zhu // SPDX-License-Identifier: GPL-2.0-only
258c449a9SYiFei Zhu 
358c449a9SYiFei Zhu /*
458c449a9SYiFei Zhu  * Copyright 2022 Google LLC.
558c449a9SYiFei Zhu  */
658c449a9SYiFei Zhu 
758c449a9SYiFei Zhu #define _GNU_SOURCE
858c449a9SYiFei Zhu #include <sys/mount.h>
958c449a9SYiFei Zhu 
1058c449a9SYiFei Zhu #include "test_progs.h"
1158c449a9SYiFei Zhu #include "cgroup_helpers.h"
1258c449a9SYiFei Zhu #include "network_helpers.h"
1358c449a9SYiFei Zhu 
1458c449a9SYiFei Zhu #include "connect_ping.skel.h"
1558c449a9SYiFei Zhu 
1658c449a9SYiFei Zhu /* 2001:db8::1 */
1758c449a9SYiFei Zhu #define BINDADDR_V6 { { { 0x20,0x01,0x0d,0xb8,0,0,0,0,0,0,0,0,0,0,0,1 } } }
1858c449a9SYiFei Zhu static const struct in6_addr bindaddr_v6 = BINDADDR_V6;
1958c449a9SYiFei Zhu 
subtest(int cgroup_fd,struct connect_ping * skel,int family,int do_bind)2058c449a9SYiFei Zhu static void subtest(int cgroup_fd, struct connect_ping *skel,
2158c449a9SYiFei Zhu 		    int family, int do_bind)
2258c449a9SYiFei Zhu {
2358c449a9SYiFei Zhu 	struct sockaddr_in sa4 = {
2458c449a9SYiFei Zhu 		.sin_family = AF_INET,
2558c449a9SYiFei Zhu 		.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
2658c449a9SYiFei Zhu 	};
2758c449a9SYiFei Zhu 	struct sockaddr_in6 sa6 = {
2858c449a9SYiFei Zhu 		.sin6_family = AF_INET6,
2958c449a9SYiFei Zhu 		.sin6_addr = IN6ADDR_LOOPBACK_INIT,
3058c449a9SYiFei Zhu 	};
31*925a0157SAndrii Nakryiko 	struct sockaddr *sa = NULL;
3258c449a9SYiFei Zhu 	socklen_t sa_len;
33*925a0157SAndrii Nakryiko 	int protocol = -1;
3458c449a9SYiFei Zhu 	int sock_fd;
3558c449a9SYiFei Zhu 
3658c449a9SYiFei Zhu 	switch (family) {
3758c449a9SYiFei Zhu 	case AF_INET:
3858c449a9SYiFei Zhu 		sa = (struct sockaddr *)&sa4;
3958c449a9SYiFei Zhu 		sa_len = sizeof(sa4);
4058c449a9SYiFei Zhu 		protocol = IPPROTO_ICMP;
4158c449a9SYiFei Zhu 		break;
4258c449a9SYiFei Zhu 	case AF_INET6:
4358c449a9SYiFei Zhu 		sa = (struct sockaddr *)&sa6;
4458c449a9SYiFei Zhu 		sa_len = sizeof(sa6);
4558c449a9SYiFei Zhu 		protocol = IPPROTO_ICMPV6;
4658c449a9SYiFei Zhu 		break;
4758c449a9SYiFei Zhu 	}
4858c449a9SYiFei Zhu 
4958c449a9SYiFei Zhu 	memset(skel->bss, 0, sizeof(*skel->bss));
5058c449a9SYiFei Zhu 	skel->bss->do_bind = do_bind;
5158c449a9SYiFei Zhu 
5258c449a9SYiFei Zhu 	sock_fd = socket(family, SOCK_DGRAM, protocol);
5358c449a9SYiFei Zhu 	if (!ASSERT_GE(sock_fd, 0, "sock-create"))
5458c449a9SYiFei Zhu 		return;
5558c449a9SYiFei Zhu 
5658c449a9SYiFei Zhu 	if (!ASSERT_OK(connect(sock_fd, sa, sa_len), "connect"))
5758c449a9SYiFei Zhu 		goto close_sock;
5858c449a9SYiFei Zhu 
5958c449a9SYiFei Zhu 	if (!ASSERT_EQ(skel->bss->invocations_v4, family == AF_INET ? 1 : 0,
6058c449a9SYiFei Zhu 		       "invocations_v4"))
6158c449a9SYiFei Zhu 		goto close_sock;
6258c449a9SYiFei Zhu 	if (!ASSERT_EQ(skel->bss->invocations_v6, family == AF_INET6 ? 1 : 0,
6358c449a9SYiFei Zhu 		       "invocations_v6"))
6458c449a9SYiFei Zhu 		goto close_sock;
6558c449a9SYiFei Zhu 	if (!ASSERT_EQ(skel->bss->has_error, 0, "has_error"))
6658c449a9SYiFei Zhu 		goto close_sock;
6758c449a9SYiFei Zhu 
6858c449a9SYiFei Zhu 	if (!ASSERT_OK(getsockname(sock_fd, sa, &sa_len),
6958c449a9SYiFei Zhu 		       "getsockname"))
7058c449a9SYiFei Zhu 		goto close_sock;
7158c449a9SYiFei Zhu 
7258c449a9SYiFei Zhu 	switch (family) {
7358c449a9SYiFei Zhu 	case AF_INET:
7458c449a9SYiFei Zhu 		if (!ASSERT_EQ(sa4.sin_family, family, "sin_family"))
7558c449a9SYiFei Zhu 			goto close_sock;
7658c449a9SYiFei Zhu 		if (!ASSERT_EQ(sa4.sin_addr.s_addr,
7758c449a9SYiFei Zhu 			       htonl(do_bind ? 0x01010101 : INADDR_LOOPBACK),
7858c449a9SYiFei Zhu 			       "sin_addr"))
7958c449a9SYiFei Zhu 			goto close_sock;
8058c449a9SYiFei Zhu 		break;
8158c449a9SYiFei Zhu 	case AF_INET6:
8258c449a9SYiFei Zhu 		if (!ASSERT_EQ(sa6.sin6_family, AF_INET6, "sin6_family"))
8358c449a9SYiFei Zhu 			goto close_sock;
8458c449a9SYiFei Zhu 		if (!ASSERT_EQ(memcmp(&sa6.sin6_addr,
8558c449a9SYiFei Zhu 				      do_bind ? &bindaddr_v6 : &in6addr_loopback,
8658c449a9SYiFei Zhu 				      sizeof(sa6.sin6_addr)),
8758c449a9SYiFei Zhu 			       0, "sin6_addr"))
8858c449a9SYiFei Zhu 			goto close_sock;
8958c449a9SYiFei Zhu 		break;
9058c449a9SYiFei Zhu 	}
9158c449a9SYiFei Zhu 
9258c449a9SYiFei Zhu close_sock:
9358c449a9SYiFei Zhu 	close(sock_fd);
9458c449a9SYiFei Zhu }
9558c449a9SYiFei Zhu 
test_connect_ping(void)9658c449a9SYiFei Zhu void test_connect_ping(void)
9758c449a9SYiFei Zhu {
9858c449a9SYiFei Zhu 	struct connect_ping *skel;
9958c449a9SYiFei Zhu 	int cgroup_fd;
10058c449a9SYiFei Zhu 
10158c449a9SYiFei Zhu 	if (!ASSERT_OK(unshare(CLONE_NEWNET | CLONE_NEWNS), "unshare"))
10258c449a9SYiFei Zhu 		return;
10358c449a9SYiFei Zhu 
10458c449a9SYiFei Zhu 	/* overmount sysfs, and making original sysfs private so overmount
10558c449a9SYiFei Zhu 	 * does not propagate to other mntns.
10658c449a9SYiFei Zhu 	 */
10758c449a9SYiFei Zhu 	if (!ASSERT_OK(mount("none", "/sys", NULL, MS_PRIVATE, NULL),
10858c449a9SYiFei Zhu 		       "remount-private-sys"))
10958c449a9SYiFei Zhu 		return;
11058c449a9SYiFei Zhu 	if (!ASSERT_OK(mount("sysfs", "/sys", "sysfs", 0, NULL),
11158c449a9SYiFei Zhu 		       "mount-sys"))
11258c449a9SYiFei Zhu 		return;
11358c449a9SYiFei Zhu 	if (!ASSERT_OK(mount("bpffs", "/sys/fs/bpf", "bpf", 0, NULL),
11458c449a9SYiFei Zhu 		       "mount-bpf"))
11558c449a9SYiFei Zhu 		goto clean_mount;
11658c449a9SYiFei Zhu 
11758c449a9SYiFei Zhu 	if (!ASSERT_OK(system("ip link set dev lo up"), "lo-up"))
11858c449a9SYiFei Zhu 		goto clean_mount;
11958c449a9SYiFei Zhu 	if (!ASSERT_OK(system("ip addr add 1.1.1.1 dev lo"), "lo-addr-v4"))
12058c449a9SYiFei Zhu 		goto clean_mount;
12158c449a9SYiFei Zhu 	if (!ASSERT_OK(system("ip -6 addr add 2001:db8::1 dev lo"), "lo-addr-v6"))
12258c449a9SYiFei Zhu 		goto clean_mount;
12358c449a9SYiFei Zhu 	if (write_sysctl("/proc/sys/net/ipv4/ping_group_range", "0 0"))
12458c449a9SYiFei Zhu 		goto clean_mount;
12558c449a9SYiFei Zhu 
12658c449a9SYiFei Zhu 	cgroup_fd = test__join_cgroup("/connect_ping");
12758c449a9SYiFei Zhu 	if (!ASSERT_GE(cgroup_fd, 0, "cg-create"))
12858c449a9SYiFei Zhu 		goto clean_mount;
12958c449a9SYiFei Zhu 
13058c449a9SYiFei Zhu 	skel = connect_ping__open_and_load();
13158c449a9SYiFei Zhu 	if (!ASSERT_OK_PTR(skel, "skel-load"))
13258c449a9SYiFei Zhu 		goto close_cgroup;
13358c449a9SYiFei Zhu 	skel->links.connect_v4_prog =
13458c449a9SYiFei Zhu 		bpf_program__attach_cgroup(skel->progs.connect_v4_prog, cgroup_fd);
13558c449a9SYiFei Zhu 	if (!ASSERT_OK_PTR(skel->links.connect_v4_prog, "cg-attach-v4"))
13658c449a9SYiFei Zhu 		goto skel_destroy;
13758c449a9SYiFei Zhu 	skel->links.connect_v6_prog =
13858c449a9SYiFei Zhu 		bpf_program__attach_cgroup(skel->progs.connect_v6_prog, cgroup_fd);
13958c449a9SYiFei Zhu 	if (!ASSERT_OK_PTR(skel->links.connect_v6_prog, "cg-attach-v6"))
14058c449a9SYiFei Zhu 		goto skel_destroy;
14158c449a9SYiFei Zhu 
14258c449a9SYiFei Zhu 	/* Connect a v4 ping socket to localhost, assert that only v4 is called,
14358c449a9SYiFei Zhu 	 * and called exactly once, and that the socket's bound address is
14458c449a9SYiFei Zhu 	 * original loopback address.
14558c449a9SYiFei Zhu 	 */
14658c449a9SYiFei Zhu 	if (test__start_subtest("ipv4"))
14758c449a9SYiFei Zhu 		subtest(cgroup_fd, skel, AF_INET, 0);
14858c449a9SYiFei Zhu 
14958c449a9SYiFei Zhu 	/* Connect a v4 ping socket to localhost, assert that only v4 is called,
15058c449a9SYiFei Zhu 	 * and called exactly once, and that the socket's bound address is
15158c449a9SYiFei Zhu 	 * address we explicitly bound.
15258c449a9SYiFei Zhu 	 */
15358c449a9SYiFei Zhu 	if (test__start_subtest("ipv4-bind"))
15458c449a9SYiFei Zhu 		subtest(cgroup_fd, skel, AF_INET, 1);
15558c449a9SYiFei Zhu 
15658c449a9SYiFei Zhu 	/* Connect a v6 ping socket to localhost, assert that only v6 is called,
15758c449a9SYiFei Zhu 	 * and called exactly once, and that the socket's bound address is
15858c449a9SYiFei Zhu 	 * original loopback address.
15958c449a9SYiFei Zhu 	 */
16058c449a9SYiFei Zhu 	if (test__start_subtest("ipv6"))
16158c449a9SYiFei Zhu 		subtest(cgroup_fd, skel, AF_INET6, 0);
16258c449a9SYiFei Zhu 
16358c449a9SYiFei Zhu 	/* Connect a v6 ping socket to localhost, assert that only v6 is called,
16458c449a9SYiFei Zhu 	 * and called exactly once, and that the socket's bound address is
16558c449a9SYiFei Zhu 	 * address we explicitly bound.
16658c449a9SYiFei Zhu 	 */
16758c449a9SYiFei Zhu 	if (test__start_subtest("ipv6-bind"))
16858c449a9SYiFei Zhu 		subtest(cgroup_fd, skel, AF_INET6, 1);
16958c449a9SYiFei Zhu 
17058c449a9SYiFei Zhu skel_destroy:
17158c449a9SYiFei Zhu 	connect_ping__destroy(skel);
17258c449a9SYiFei Zhu 
17358c449a9SYiFei Zhu close_cgroup:
17458c449a9SYiFei Zhu 	close(cgroup_fd);
17558c449a9SYiFei Zhu 
17658c449a9SYiFei Zhu clean_mount:
17758c449a9SYiFei Zhu 	umount2("/sys", MNT_DETACH);
17858c449a9SYiFei Zhu }
179