214 lines · c
1// SPDX-License-Identifier: GPL-2.02// Copyright (c) 2018 Facebook3// Copyright (c) 2019 Cloudflare4 5#include <limits.h>6#include <string.h>7#include <stdlib.h>8#include <unistd.h>9 10#include <arpa/inet.h>11#include <netinet/in.h>12#include <sys/types.h>13#include <sys/socket.h>14 15#include <bpf/bpf.h>16#include <bpf/libbpf.h>17 18#include "cgroup_helpers.h"19#include "network_helpers.h"20 21static int get_map_fd_by_prog_id(int prog_id, bool *xdp)22{23 struct bpf_prog_info info = {};24 __u32 info_len = sizeof(info);25 __u32 map_ids[1];26 int prog_fd = -1;27 int map_fd = -1;28 29 prog_fd = bpf_prog_get_fd_by_id(prog_id);30 if (prog_fd < 0) {31 log_err("Failed to get fd by prog id %d", prog_id);32 goto err;33 }34 35 info.nr_map_ids = 1;36 info.map_ids = (__u64)(unsigned long)map_ids;37 38 if (bpf_prog_get_info_by_fd(prog_fd, &info, &info_len)) {39 log_err("Failed to get info by prog fd %d", prog_fd);40 goto err;41 }42 43 if (!info.nr_map_ids) {44 log_err("No maps found for prog fd %d", prog_fd);45 goto err;46 }47 48 *xdp = info.type == BPF_PROG_TYPE_XDP;49 50 map_fd = bpf_map_get_fd_by_id(map_ids[0]);51 if (map_fd < 0)52 log_err("Failed to get fd by map id %d", map_ids[0]);53err:54 if (prog_fd >= 0)55 close(prog_fd);56 return map_fd;57}58 59static int run_test(int server_fd, int results_fd, bool xdp)60{61 int client = -1, srv_client = -1;62 int ret = 0;63 __u32 key = 0;64 __u32 key_gen = 1;65 __u32 key_mss = 2;66 __u32 value = 0;67 __u32 value_gen = 0;68 __u32 value_mss = 0;69 70 if (bpf_map_update_elem(results_fd, &key, &value, 0) < 0) {71 log_err("Can't clear results");72 goto err;73 }74 75 if (bpf_map_update_elem(results_fd, &key_gen, &value_gen, 0) < 0) {76 log_err("Can't clear results");77 goto err;78 }79 80 if (bpf_map_update_elem(results_fd, &key_mss, &value_mss, 0) < 0) {81 log_err("Can't clear results");82 goto err;83 }84 85 client = connect_to_fd(server_fd, 0);86 if (client == -1)87 goto err;88 89 srv_client = accept(server_fd, NULL, 0);90 if (srv_client == -1) {91 log_err("Can't accept connection");92 goto err;93 }94 95 if (bpf_map_lookup_elem(results_fd, &key, &value) < 0) {96 log_err("Can't lookup result");97 goto err;98 }99 100 if (value == 0) {101 log_err("Didn't match syncookie: %u", value);102 goto err;103 }104 105 if (bpf_map_lookup_elem(results_fd, &key_gen, &value_gen) < 0) {106 log_err("Can't lookup result");107 goto err;108 }109 110 if (xdp && value_gen == 0) {111 // SYN packets do not get passed through generic XDP, skip the112 // rest of the test.113 printf("Skipping XDP cookie check\n");114 goto out;115 }116 117 if (bpf_map_lookup_elem(results_fd, &key_mss, &value_mss) < 0) {118 log_err("Can't lookup result");119 goto err;120 }121 122 if (value != value_gen) {123 log_err("BPF generated cookie does not match kernel one");124 goto err;125 }126 127 if (value_mss < 536 || value_mss > USHRT_MAX) {128 log_err("Unexpected MSS retrieved");129 goto err;130 }131 132 goto out;133 134err:135 ret = 1;136out:137 close(client);138 close(srv_client);139 return ret;140}141 142static int v6only_true(int fd, void *opts)143{144 int mode = true;145 146 return setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &mode, sizeof(mode));147}148 149static int v6only_false(int fd, void *opts)150{151 int mode = false;152 153 return setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &mode, sizeof(mode));154}155 156int main(int argc, char **argv)157{158 struct network_helper_opts opts = { 0 };159 int server = -1;160 int server_v6 = -1;161 int server_dual = -1;162 int results = -1;163 int err = 0;164 bool xdp;165 166 if (argc < 2) {167 fprintf(stderr, "Usage: %s prog_id\n", argv[0]);168 exit(1);169 }170 171 /* Use libbpf 1.0 API mode */172 libbpf_set_strict_mode(LIBBPF_STRICT_ALL);173 174 results = get_map_fd_by_prog_id(atoi(argv[1]), &xdp);175 if (results < 0) {176 log_err("Can't get map");177 goto err;178 }179 180 server = start_server_str(AF_INET, SOCK_STREAM, "127.0.0.1", 0, NULL);181 if (server == -1)182 goto err;183 184 opts.post_socket_cb = v6only_true;185 server_v6 = start_server_str(AF_INET6, SOCK_STREAM, "::1", 0, &opts);186 if (server_v6 == -1)187 goto err;188 189 opts.post_socket_cb = v6only_false;190 server_dual = start_server_str(AF_INET6, SOCK_STREAM, "::0", 0, &opts);191 if (server_dual == -1)192 goto err;193 194 if (run_test(server, results, xdp))195 goto err;196 197 if (run_test(server_v6, results, xdp))198 goto err;199 200 if (run_test(server_dual, results, xdp))201 goto err;202 203 printf("ok\n");204 goto out;205err:206 err = 1;207out:208 close(server);209 close(server_v6);210 close(server_dual);211 close(results);212 return err;213}214