0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #define _GNU_SOURCE
0012 #include <fcntl.h>
0013 #include <signal.h>
0014 #include <stdlib.h>
0015 #include <unistd.h>
0016
0017 #include "test_progs.h"
0018
0019 #define BIND_PORT 1234
0020 #define CONNECT_PORT 4321
0021 #define TEST_DADDR (0xC0A80203)
0022 #define NS_SELF "/proc/self/ns/net"
0023 #define SERVER_MAP_PATH "/sys/fs/bpf/tc/globals/server_map"
0024
0025 static const struct timeval timeo_sec = { .tv_sec = 3 };
0026 static const size_t timeo_optlen = sizeof(timeo_sec);
0027 static int stop, duration;
0028
0029 static bool
0030 configure_stack(void)
0031 {
0032 char tc_cmd[BUFSIZ];
0033
0034
0035 if (CHECK_FAIL(unshare(CLONE_NEWNET)))
0036 return false;
0037
0038
0039 if (CHECK_FAIL(system("ip link set dev lo up")))
0040 return false;
0041 if (CHECK_FAIL(system("ip route add local default dev lo")))
0042 return false;
0043 if (CHECK_FAIL(system("ip -6 route add local default dev lo")))
0044 return false;
0045
0046
0047 if (CHECK_FAIL(system("tc qdisc add dev lo clsact")))
0048 return false;
0049 sprintf(tc_cmd, "%s %s %s %s", "tc filter add dev lo ingress bpf",
0050 "direct-action object-file ./test_sk_assign.o",
0051 "section tc",
0052 (env.verbosity < VERBOSE_VERY) ? " 2>/dev/null" : "verbose");
0053 if (CHECK(system(tc_cmd), "BPF load failed;",
0054 "run with -vv for more info\n"))
0055 return false;
0056
0057 return true;
0058 }
0059
0060 static int
0061 start_server(const struct sockaddr *addr, socklen_t len, int type)
0062 {
0063 int fd;
0064
0065 fd = socket(addr->sa_family, type, 0);
0066 if (CHECK_FAIL(fd == -1))
0067 goto out;
0068 if (CHECK_FAIL(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo_sec,
0069 timeo_optlen)))
0070 goto close_out;
0071 if (CHECK_FAIL(bind(fd, addr, len) == -1))
0072 goto close_out;
0073 if (type == SOCK_STREAM && CHECK_FAIL(listen(fd, 128) == -1))
0074 goto close_out;
0075
0076 goto out;
0077 close_out:
0078 close(fd);
0079 fd = -1;
0080 out:
0081 return fd;
0082 }
0083
0084 static int
0085 connect_to_server(const struct sockaddr *addr, socklen_t len, int type)
0086 {
0087 int fd = -1;
0088
0089 fd = socket(addr->sa_family, type, 0);
0090 if (CHECK_FAIL(fd == -1))
0091 goto out;
0092 if (CHECK_FAIL(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo_sec,
0093 timeo_optlen)))
0094 goto close_out;
0095 if (CHECK_FAIL(connect(fd, addr, len)))
0096 goto close_out;
0097
0098 goto out;
0099 close_out:
0100 close(fd);
0101 fd = -1;
0102 out:
0103 return fd;
0104 }
0105
0106 static in_port_t
0107 get_port(int fd)
0108 {
0109 struct sockaddr_storage ss;
0110 socklen_t slen = sizeof(ss);
0111 in_port_t port = 0;
0112
0113 if (CHECK_FAIL(getsockname(fd, (struct sockaddr *)&ss, &slen)))
0114 return port;
0115
0116 switch (ss.ss_family) {
0117 case AF_INET:
0118 port = ((struct sockaddr_in *)&ss)->sin_port;
0119 break;
0120 case AF_INET6:
0121 port = ((struct sockaddr_in6 *)&ss)->sin6_port;
0122 break;
0123 default:
0124 CHECK(1, "Invalid address family", "%d\n", ss.ss_family);
0125 }
0126 return port;
0127 }
0128
0129 static ssize_t
0130 rcv_msg(int srv_client, int type)
0131 {
0132 struct sockaddr_storage ss;
0133 char buf[BUFSIZ];
0134 socklen_t slen;
0135
0136 if (type == SOCK_STREAM)
0137 return read(srv_client, &buf, sizeof(buf));
0138 else
0139 return recvfrom(srv_client, &buf, sizeof(buf), 0,
0140 (struct sockaddr *)&ss, &slen);
0141 }
0142
0143 static int
0144 run_test(int server_fd, const struct sockaddr *addr, socklen_t len, int type)
0145 {
0146 int client = -1, srv_client = -1;
0147 char buf[] = "testing";
0148 in_port_t port;
0149 int ret = 1;
0150
0151 client = connect_to_server(addr, len, type);
0152 if (client == -1) {
0153 perror("Cannot connect to server");
0154 goto out;
0155 }
0156
0157 if (type == SOCK_STREAM) {
0158 srv_client = accept(server_fd, NULL, NULL);
0159 if (CHECK_FAIL(srv_client == -1)) {
0160 perror("Can't accept connection");
0161 goto out;
0162 }
0163 } else {
0164 srv_client = server_fd;
0165 }
0166 if (CHECK_FAIL(write(client, buf, sizeof(buf)) != sizeof(buf))) {
0167 perror("Can't write on client");
0168 goto out;
0169 }
0170 if (CHECK_FAIL(rcv_msg(srv_client, type) != sizeof(buf))) {
0171 perror("Can't read on server");
0172 goto out;
0173 }
0174
0175 port = get_port(srv_client);
0176 if (CHECK_FAIL(!port))
0177 goto out;
0178
0179
0180
0181
0182
0183
0184 if (type == SOCK_STREAM &&
0185 CHECK(port != htons(CONNECT_PORT), "Expected", "port %u but got %u",
0186 CONNECT_PORT, ntohs(port)))
0187 goto out;
0188 else if (type == SOCK_DGRAM &&
0189 CHECK(port != htons(BIND_PORT), "Expected",
0190 "port %u but got %u", BIND_PORT, ntohs(port)))
0191 goto out;
0192
0193 ret = 0;
0194 out:
0195 close(client);
0196 if (srv_client != server_fd)
0197 close(srv_client);
0198 if (ret)
0199 WRITE_ONCE(stop, 1);
0200 return ret;
0201 }
0202
0203 static void
0204 prepare_addr(struct sockaddr *addr, int family, __u16 port, bool rewrite_addr)
0205 {
0206 struct sockaddr_in *addr4;
0207 struct sockaddr_in6 *addr6;
0208
0209 switch (family) {
0210 case AF_INET:
0211 addr4 = (struct sockaddr_in *)addr;
0212 memset(addr4, 0, sizeof(*addr4));
0213 addr4->sin_family = family;
0214 addr4->sin_port = htons(port);
0215 if (rewrite_addr)
0216 addr4->sin_addr.s_addr = htonl(TEST_DADDR);
0217 else
0218 addr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
0219 break;
0220 case AF_INET6:
0221 addr6 = (struct sockaddr_in6 *)addr;
0222 memset(addr6, 0, sizeof(*addr6));
0223 addr6->sin6_family = family;
0224 addr6->sin6_port = htons(port);
0225 addr6->sin6_addr = in6addr_loopback;
0226 if (rewrite_addr)
0227 addr6->sin6_addr.s6_addr32[3] = htonl(TEST_DADDR);
0228 break;
0229 default:
0230 fprintf(stderr, "Invalid family %d", family);
0231 }
0232 }
0233
0234 struct test_sk_cfg {
0235 const char *name;
0236 int family;
0237 struct sockaddr *addr;
0238 socklen_t len;
0239 int type;
0240 bool rewrite_addr;
0241 };
0242
0243 #define TEST(NAME, FAMILY, TYPE, REWRITE) \
0244 { \
0245 .name = NAME, \
0246 .family = FAMILY, \
0247 .addr = (FAMILY == AF_INET) ? (struct sockaddr *)&addr4 \
0248 : (struct sockaddr *)&addr6, \
0249 .len = (FAMILY == AF_INET) ? sizeof(addr4) : sizeof(addr6), \
0250 .type = TYPE, \
0251 .rewrite_addr = REWRITE, \
0252 }
0253
0254 void test_sk_assign(void)
0255 {
0256 struct sockaddr_in addr4;
0257 struct sockaddr_in6 addr6;
0258 struct test_sk_cfg tests[] = {
0259 TEST("ipv4 tcp port redir", AF_INET, SOCK_STREAM, false),
0260 TEST("ipv4 tcp addr redir", AF_INET, SOCK_STREAM, true),
0261 TEST("ipv6 tcp port redir", AF_INET6, SOCK_STREAM, false),
0262 TEST("ipv6 tcp addr redir", AF_INET6, SOCK_STREAM, true),
0263 TEST("ipv4 udp port redir", AF_INET, SOCK_DGRAM, false),
0264 TEST("ipv4 udp addr redir", AF_INET, SOCK_DGRAM, true),
0265 TEST("ipv6 udp port redir", AF_INET6, SOCK_DGRAM, false),
0266 TEST("ipv6 udp addr redir", AF_INET6, SOCK_DGRAM, true),
0267 };
0268 __s64 server = -1;
0269 int server_map;
0270 int self_net;
0271 int i;
0272
0273 self_net = open(NS_SELF, O_RDONLY);
0274 if (CHECK_FAIL(self_net < 0)) {
0275 perror("Unable to open "NS_SELF);
0276 return;
0277 }
0278
0279 if (!configure_stack()) {
0280 perror("configure_stack");
0281 goto cleanup;
0282 }
0283
0284 server_map = bpf_obj_get(SERVER_MAP_PATH);
0285 if (CHECK_FAIL(server_map < 0)) {
0286 perror("Unable to open " SERVER_MAP_PATH);
0287 goto cleanup;
0288 }
0289
0290 for (i = 0; i < ARRAY_SIZE(tests) && !READ_ONCE(stop); i++) {
0291 struct test_sk_cfg *test = &tests[i];
0292 const struct sockaddr *addr;
0293 const int zero = 0;
0294 int err;
0295
0296 if (!test__start_subtest(test->name))
0297 continue;
0298 prepare_addr(test->addr, test->family, BIND_PORT, false);
0299 addr = (const struct sockaddr *)test->addr;
0300 server = start_server(addr, test->len, test->type);
0301 if (server == -1)
0302 goto close;
0303
0304 err = bpf_map_update_elem(server_map, &zero, &server, BPF_ANY);
0305 if (CHECK_FAIL(err)) {
0306 perror("Unable to update server_map");
0307 goto close;
0308 }
0309
0310
0311 prepare_addr(test->addr, test->family, CONNECT_PORT,
0312 test->rewrite_addr);
0313 if (run_test(server, addr, test->len, test->type))
0314 goto close;
0315
0316 close(server);
0317 server = -1;
0318 }
0319
0320 close:
0321 close(server);
0322 close(server_map);
0323 cleanup:
0324 if (CHECK_FAIL(unlink(SERVER_MAP_PATH)))
0325 perror("Unable to unlink " SERVER_MAP_PATH);
0326 if (CHECK_FAIL(setns(self_net, CLONE_NEWNET)))
0327 perror("Failed to setns("NS_SELF")");
0328 close(self_net);
0329 }