1 // SPDX-License-Identifier: GPL-2.0-only 2 3 /* 4 * Copyright 2022 Google LLC. 5 */ 6 7 #define _GNU_SOURCE 8 #include <sys/mount.h> 9 10 #include "test_progs.h" 11 #include "cgroup_helpers.h" 12 #include "network_helpers.h" 13 14 #include "connect_ping.skel.h" 15 16 /* 2001:db8::1 */ 17 #define BINDADDR_V6 { { { 0x20,0x01,0x0d,0xb8,0,0,0,0,0,0,0,0,0,0,0,1 } } } 18 static const struct in6_addr bindaddr_v6 = BINDADDR_V6; 19 20 static void subtest(int cgroup_fd, struct connect_ping *skel, 21 int family, int do_bind) 22 { 23 struct sockaddr_in sa4 = { 24 .sin_family = AF_INET, 25 .sin_addr.s_addr = htonl(INADDR_LOOPBACK), 26 }; 27 struct sockaddr_in6 sa6 = { 28 .sin6_family = AF_INET6, 29 .sin6_addr = IN6ADDR_LOOPBACK_INIT, 30 }; 31 struct sockaddr *sa; 32 socklen_t sa_len; 33 int protocol; 34 int sock_fd; 35 36 switch (family) { 37 case AF_INET: 38 sa = (struct sockaddr *)&sa4; 39 sa_len = sizeof(sa4); 40 protocol = IPPROTO_ICMP; 41 break; 42 case AF_INET6: 43 sa = (struct sockaddr *)&sa6; 44 sa_len = sizeof(sa6); 45 protocol = IPPROTO_ICMPV6; 46 break; 47 } 48 49 memset(skel->bss, 0, sizeof(*skel->bss)); 50 skel->bss->do_bind = do_bind; 51 52 sock_fd = socket(family, SOCK_DGRAM, protocol); 53 if (!ASSERT_GE(sock_fd, 0, "sock-create")) 54 return; 55 56 if (!ASSERT_OK(connect(sock_fd, sa, sa_len), "connect")) 57 goto close_sock; 58 59 if (!ASSERT_EQ(skel->bss->invocations_v4, family == AF_INET ? 1 : 0, 60 "invocations_v4")) 61 goto close_sock; 62 if (!ASSERT_EQ(skel->bss->invocations_v6, family == AF_INET6 ? 1 : 0, 63 "invocations_v6")) 64 goto close_sock; 65 if (!ASSERT_EQ(skel->bss->has_error, 0, "has_error")) 66 goto close_sock; 67 68 if (!ASSERT_OK(getsockname(sock_fd, sa, &sa_len), 69 "getsockname")) 70 goto close_sock; 71 72 switch (family) { 73 case AF_INET: 74 if (!ASSERT_EQ(sa4.sin_family, family, "sin_family")) 75 goto close_sock; 76 if (!ASSERT_EQ(sa4.sin_addr.s_addr, 77 htonl(do_bind ? 0x01010101 : INADDR_LOOPBACK), 78 "sin_addr")) 79 goto close_sock; 80 break; 81 case AF_INET6: 82 if (!ASSERT_EQ(sa6.sin6_family, AF_INET6, "sin6_family")) 83 goto close_sock; 84 if (!ASSERT_EQ(memcmp(&sa6.sin6_addr, 85 do_bind ? &bindaddr_v6 : &in6addr_loopback, 86 sizeof(sa6.sin6_addr)), 87 0, "sin6_addr")) 88 goto close_sock; 89 break; 90 } 91 92 close_sock: 93 close(sock_fd); 94 } 95 96 void test_connect_ping(void) 97 { 98 struct connect_ping *skel; 99 int cgroup_fd; 100 101 if (!ASSERT_OK(unshare(CLONE_NEWNET | CLONE_NEWNS), "unshare")) 102 return; 103 104 /* overmount sysfs, and making original sysfs private so overmount 105 * does not propagate to other mntns. 106 */ 107 if (!ASSERT_OK(mount("none", "/sys", NULL, MS_PRIVATE, NULL), 108 "remount-private-sys")) 109 return; 110 if (!ASSERT_OK(mount("sysfs", "/sys", "sysfs", 0, NULL), 111 "mount-sys")) 112 return; 113 if (!ASSERT_OK(mount("bpffs", "/sys/fs/bpf", "bpf", 0, NULL), 114 "mount-bpf")) 115 goto clean_mount; 116 117 if (!ASSERT_OK(system("ip link set dev lo up"), "lo-up")) 118 goto clean_mount; 119 if (!ASSERT_OK(system("ip addr add 1.1.1.1 dev lo"), "lo-addr-v4")) 120 goto clean_mount; 121 if (!ASSERT_OK(system("ip -6 addr add 2001:db8::1 dev lo"), "lo-addr-v6")) 122 goto clean_mount; 123 if (write_sysctl("/proc/sys/net/ipv4/ping_group_range", "0 0")) 124 goto clean_mount; 125 126 cgroup_fd = test__join_cgroup("/connect_ping"); 127 if (!ASSERT_GE(cgroup_fd, 0, "cg-create")) 128 goto clean_mount; 129 130 skel = connect_ping__open_and_load(); 131 if (!ASSERT_OK_PTR(skel, "skel-load")) 132 goto close_cgroup; 133 skel->links.connect_v4_prog = 134 bpf_program__attach_cgroup(skel->progs.connect_v4_prog, cgroup_fd); 135 if (!ASSERT_OK_PTR(skel->links.connect_v4_prog, "cg-attach-v4")) 136 goto skel_destroy; 137 skel->links.connect_v6_prog = 138 bpf_program__attach_cgroup(skel->progs.connect_v6_prog, cgroup_fd); 139 if (!ASSERT_OK_PTR(skel->links.connect_v6_prog, "cg-attach-v6")) 140 goto skel_destroy; 141 142 /* Connect a v4 ping socket to localhost, assert that only v4 is called, 143 * and called exactly once, and that the socket's bound address is 144 * original loopback address. 145 */ 146 if (test__start_subtest("ipv4")) 147 subtest(cgroup_fd, skel, AF_INET, 0); 148 149 /* Connect a v4 ping socket to localhost, assert that only v4 is called, 150 * and called exactly once, and that the socket's bound address is 151 * address we explicitly bound. 152 */ 153 if (test__start_subtest("ipv4-bind")) 154 subtest(cgroup_fd, skel, AF_INET, 1); 155 156 /* Connect a v6 ping socket to localhost, assert that only v6 is called, 157 * and called exactly once, and that the socket's bound address is 158 * original loopback address. 159 */ 160 if (test__start_subtest("ipv6")) 161 subtest(cgroup_fd, skel, AF_INET6, 0); 162 163 /* Connect a v6 ping socket to localhost, assert that only v6 is called, 164 * and called exactly once, and that the socket's bound address is 165 * address we explicitly bound. 166 */ 167 if (test__start_subtest("ipv6-bind")) 168 subtest(cgroup_fd, skel, AF_INET6, 1); 169 170 skel_destroy: 171 connect_ping__destroy(skel); 172 173 close_cgroup: 174 close(cgroup_fd); 175 176 clean_mount: 177 umount2("/sys", MNT_DETACH); 178 } 179