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