162306a36Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause 262306a36Sopenharmony_ci/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <stdnoreturn.h> 562306a36Sopenharmony_ci#include <stdlib.h> 662306a36Sopenharmony_ci#include <stdio.h> 762306a36Sopenharmony_ci#include <string.h> 862306a36Sopenharmony_ci#include <errno.h> 962306a36Sopenharmony_ci#include <unistd.h> 1062306a36Sopenharmony_ci#include <getopt.h> 1162306a36Sopenharmony_ci#include <signal.h> 1262306a36Sopenharmony_ci#include <sys/types.h> 1362306a36Sopenharmony_ci#include <bpf/bpf.h> 1462306a36Sopenharmony_ci#include <bpf/libbpf.h> 1562306a36Sopenharmony_ci#include <net/if.h> 1662306a36Sopenharmony_ci#include <linux/if_link.h> 1762306a36Sopenharmony_ci#include <linux/limits.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic unsigned int ifindex; 2062306a36Sopenharmony_cistatic __u32 attached_prog_id; 2162306a36Sopenharmony_cistatic bool attached_tc; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic void noreturn cleanup(int sig) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci LIBBPF_OPTS(bpf_xdp_attach_opts, opts); 2662306a36Sopenharmony_ci int prog_fd; 2762306a36Sopenharmony_ci int err; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (attached_prog_id == 0) 3062306a36Sopenharmony_ci exit(0); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (attached_tc) { 3362306a36Sopenharmony_ci LIBBPF_OPTS(bpf_tc_hook, hook, 3462306a36Sopenharmony_ci .ifindex = ifindex, 3562306a36Sopenharmony_ci .attach_point = BPF_TC_INGRESS); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci err = bpf_tc_hook_destroy(&hook); 3862306a36Sopenharmony_ci if (err < 0) { 3962306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_tc_hook_destroy: %s\n", strerror(-err)); 4062306a36Sopenharmony_ci fprintf(stderr, "Failed to destroy the TC hook\n"); 4162306a36Sopenharmony_ci exit(1); 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci exit(0); 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci prog_fd = bpf_prog_get_fd_by_id(attached_prog_id); 4762306a36Sopenharmony_ci if (prog_fd < 0) { 4862306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_prog_get_fd_by_id: %s\n", strerror(-prog_fd)); 4962306a36Sopenharmony_ci err = bpf_xdp_attach(ifindex, -1, 0, NULL); 5062306a36Sopenharmony_ci if (err < 0) { 5162306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_set_link_xdp_fd: %s\n", strerror(-err)); 5262306a36Sopenharmony_ci fprintf(stderr, "Failed to detach XDP program\n"); 5362306a36Sopenharmony_ci exit(1); 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci } else { 5662306a36Sopenharmony_ci opts.old_prog_fd = prog_fd; 5762306a36Sopenharmony_ci err = bpf_xdp_attach(ifindex, -1, XDP_FLAGS_REPLACE, &opts); 5862306a36Sopenharmony_ci close(prog_fd); 5962306a36Sopenharmony_ci if (err < 0) { 6062306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_set_link_xdp_fd_opts: %s\n", strerror(-err)); 6162306a36Sopenharmony_ci /* Not an error if already replaced by someone else. */ 6262306a36Sopenharmony_ci if (err != -EEXIST) { 6362306a36Sopenharmony_ci fprintf(stderr, "Failed to detach XDP program\n"); 6462306a36Sopenharmony_ci exit(1); 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci exit(0); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic noreturn void usage(const char *progname) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci fprintf(stderr, "Usage: %s [--iface <iface>|--prog <prog_id>] [--mss4 <mss ipv4> --mss6 <mss ipv6> --wscale <wscale> --ttl <ttl>] [--ports <port1>,<port2>,...] [--single] [--tc]\n", 7462306a36Sopenharmony_ci progname); 7562306a36Sopenharmony_ci exit(1); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic unsigned long parse_arg_ul(const char *progname, const char *arg, unsigned long limit) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci unsigned long res; 8162306a36Sopenharmony_ci char *endptr; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci errno = 0; 8462306a36Sopenharmony_ci res = strtoul(arg, &endptr, 10); 8562306a36Sopenharmony_ci if (errno != 0 || *endptr != '\0' || arg[0] == '\0' || res > limit) 8662306a36Sopenharmony_ci usage(progname); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return res; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic void parse_options(int argc, char *argv[], unsigned int *ifindex, __u32 *prog_id, 9262306a36Sopenharmony_ci __u64 *tcpipopts, char **ports, bool *single, bool *tc) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci static struct option long_options[] = { 9562306a36Sopenharmony_ci { "help", no_argument, NULL, 'h' }, 9662306a36Sopenharmony_ci { "iface", required_argument, NULL, 'i' }, 9762306a36Sopenharmony_ci { "prog", required_argument, NULL, 'x' }, 9862306a36Sopenharmony_ci { "mss4", required_argument, NULL, 4 }, 9962306a36Sopenharmony_ci { "mss6", required_argument, NULL, 6 }, 10062306a36Sopenharmony_ci { "wscale", required_argument, NULL, 'w' }, 10162306a36Sopenharmony_ci { "ttl", required_argument, NULL, 't' }, 10262306a36Sopenharmony_ci { "ports", required_argument, NULL, 'p' }, 10362306a36Sopenharmony_ci { "single", no_argument, NULL, 's' }, 10462306a36Sopenharmony_ci { "tc", no_argument, NULL, 'c' }, 10562306a36Sopenharmony_ci { NULL, 0, NULL, 0 }, 10662306a36Sopenharmony_ci }; 10762306a36Sopenharmony_ci unsigned long mss4, wscale, ttl; 10862306a36Sopenharmony_ci unsigned long long mss6; 10962306a36Sopenharmony_ci unsigned int tcpipopts_mask = 0; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (argc < 2) 11262306a36Sopenharmony_ci usage(argv[0]); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci *ifindex = 0; 11562306a36Sopenharmony_ci *prog_id = 0; 11662306a36Sopenharmony_ci *tcpipopts = 0; 11762306a36Sopenharmony_ci *ports = NULL; 11862306a36Sopenharmony_ci *single = false; 11962306a36Sopenharmony_ci *tc = false; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci while (true) { 12262306a36Sopenharmony_ci int opt; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci opt = getopt_long(argc, argv, "", long_options, NULL); 12562306a36Sopenharmony_ci if (opt == -1) 12662306a36Sopenharmony_ci break; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci switch (opt) { 12962306a36Sopenharmony_ci case 'h': 13062306a36Sopenharmony_ci usage(argv[0]); 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci case 'i': 13362306a36Sopenharmony_ci *ifindex = if_nametoindex(optarg); 13462306a36Sopenharmony_ci if (*ifindex == 0) 13562306a36Sopenharmony_ci usage(argv[0]); 13662306a36Sopenharmony_ci break; 13762306a36Sopenharmony_ci case 'x': 13862306a36Sopenharmony_ci *prog_id = parse_arg_ul(argv[0], optarg, UINT32_MAX); 13962306a36Sopenharmony_ci if (*prog_id == 0) 14062306a36Sopenharmony_ci usage(argv[0]); 14162306a36Sopenharmony_ci break; 14262306a36Sopenharmony_ci case 4: 14362306a36Sopenharmony_ci mss4 = parse_arg_ul(argv[0], optarg, UINT16_MAX); 14462306a36Sopenharmony_ci tcpipopts_mask |= 1 << 0; 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci case 6: 14762306a36Sopenharmony_ci mss6 = parse_arg_ul(argv[0], optarg, UINT16_MAX); 14862306a36Sopenharmony_ci tcpipopts_mask |= 1 << 1; 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci case 'w': 15162306a36Sopenharmony_ci wscale = parse_arg_ul(argv[0], optarg, 14); 15262306a36Sopenharmony_ci tcpipopts_mask |= 1 << 2; 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci case 't': 15562306a36Sopenharmony_ci ttl = parse_arg_ul(argv[0], optarg, UINT8_MAX); 15662306a36Sopenharmony_ci tcpipopts_mask |= 1 << 3; 15762306a36Sopenharmony_ci break; 15862306a36Sopenharmony_ci case 'p': 15962306a36Sopenharmony_ci *ports = optarg; 16062306a36Sopenharmony_ci break; 16162306a36Sopenharmony_ci case 's': 16262306a36Sopenharmony_ci *single = true; 16362306a36Sopenharmony_ci break; 16462306a36Sopenharmony_ci case 'c': 16562306a36Sopenharmony_ci *tc = true; 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci default: 16862306a36Sopenharmony_ci usage(argv[0]); 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci if (optind < argc) 17262306a36Sopenharmony_ci usage(argv[0]); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (tcpipopts_mask == 0xf) { 17562306a36Sopenharmony_ci if (mss4 == 0 || mss6 == 0 || wscale == 0 || ttl == 0) 17662306a36Sopenharmony_ci usage(argv[0]); 17762306a36Sopenharmony_ci *tcpipopts = (mss6 << 32) | (ttl << 24) | (wscale << 16) | mss4; 17862306a36Sopenharmony_ci } else if (tcpipopts_mask != 0) { 17962306a36Sopenharmony_ci usage(argv[0]); 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (*ifindex != 0 && *prog_id != 0) 18362306a36Sopenharmony_ci usage(argv[0]); 18462306a36Sopenharmony_ci if (*ifindex == 0 && *prog_id == 0) 18562306a36Sopenharmony_ci usage(argv[0]); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int syncookie_attach(const char *argv0, unsigned int ifindex, bool tc) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct bpf_prog_info info = {}; 19162306a36Sopenharmony_ci __u32 info_len = sizeof(info); 19262306a36Sopenharmony_ci char xdp_filename[PATH_MAX]; 19362306a36Sopenharmony_ci struct bpf_program *prog; 19462306a36Sopenharmony_ci struct bpf_object *obj; 19562306a36Sopenharmony_ci int prog_fd; 19662306a36Sopenharmony_ci int err; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci snprintf(xdp_filename, sizeof(xdp_filename), "%s_kern.bpf.o", argv0); 19962306a36Sopenharmony_ci obj = bpf_object__open_file(xdp_filename, NULL); 20062306a36Sopenharmony_ci err = libbpf_get_error(obj); 20162306a36Sopenharmony_ci if (err < 0) { 20262306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_object__open_file: %s\n", strerror(-err)); 20362306a36Sopenharmony_ci return err; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci err = bpf_object__load(obj); 20762306a36Sopenharmony_ci if (err < 0) { 20862306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_object__open_file: %s\n", strerror(-err)); 20962306a36Sopenharmony_ci return err; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci prog = bpf_object__find_program_by_name(obj, tc ? "syncookie_tc" : "syncookie_xdp"); 21362306a36Sopenharmony_ci if (!prog) { 21462306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_object__find_program_by_name: program was not found\n"); 21562306a36Sopenharmony_ci return -ENOENT; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci prog_fd = bpf_program__fd(prog); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len); 22162306a36Sopenharmony_ci if (err < 0) { 22262306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_prog_get_info_by_fd: %s\n", 22362306a36Sopenharmony_ci strerror(-err)); 22462306a36Sopenharmony_ci goto out; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci attached_tc = tc; 22762306a36Sopenharmony_ci attached_prog_id = info.id; 22862306a36Sopenharmony_ci signal(SIGINT, cleanup); 22962306a36Sopenharmony_ci signal(SIGTERM, cleanup); 23062306a36Sopenharmony_ci if (tc) { 23162306a36Sopenharmony_ci LIBBPF_OPTS(bpf_tc_hook, hook, 23262306a36Sopenharmony_ci .ifindex = ifindex, 23362306a36Sopenharmony_ci .attach_point = BPF_TC_INGRESS); 23462306a36Sopenharmony_ci LIBBPF_OPTS(bpf_tc_opts, opts, 23562306a36Sopenharmony_ci .handle = 1, 23662306a36Sopenharmony_ci .priority = 1, 23762306a36Sopenharmony_ci .prog_fd = prog_fd); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci err = bpf_tc_hook_create(&hook); 24062306a36Sopenharmony_ci if (err < 0) { 24162306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_tc_hook_create: %s\n", 24262306a36Sopenharmony_ci strerror(-err)); 24362306a36Sopenharmony_ci goto fail; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci err = bpf_tc_attach(&hook, &opts); 24662306a36Sopenharmony_ci if (err < 0) { 24762306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_tc_attach: %s\n", 24862306a36Sopenharmony_ci strerror(-err)); 24962306a36Sopenharmony_ci goto fail; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci } else { 25362306a36Sopenharmony_ci err = bpf_xdp_attach(ifindex, prog_fd, 25462306a36Sopenharmony_ci XDP_FLAGS_UPDATE_IF_NOEXIST, NULL); 25562306a36Sopenharmony_ci if (err < 0) { 25662306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_set_link_xdp_fd: %s\n", 25762306a36Sopenharmony_ci strerror(-err)); 25862306a36Sopenharmony_ci goto fail; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci err = 0; 26262306a36Sopenharmony_ciout: 26362306a36Sopenharmony_ci bpf_object__close(obj); 26462306a36Sopenharmony_ci return err; 26562306a36Sopenharmony_cifail: 26662306a36Sopenharmony_ci signal(SIGINT, SIG_DFL); 26762306a36Sopenharmony_ci signal(SIGTERM, SIG_DFL); 26862306a36Sopenharmony_ci attached_prog_id = 0; 26962306a36Sopenharmony_ci goto out; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic int syncookie_open_bpf_maps(__u32 prog_id, int *values_map_fd, int *ports_map_fd) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct bpf_prog_info prog_info; 27562306a36Sopenharmony_ci __u32 map_ids[8]; 27662306a36Sopenharmony_ci __u32 info_len; 27762306a36Sopenharmony_ci int prog_fd; 27862306a36Sopenharmony_ci int err; 27962306a36Sopenharmony_ci int i; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci *values_map_fd = -1; 28262306a36Sopenharmony_ci *ports_map_fd = -1; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci prog_fd = bpf_prog_get_fd_by_id(prog_id); 28562306a36Sopenharmony_ci if (prog_fd < 0) { 28662306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_prog_get_fd_by_id: %s\n", strerror(-prog_fd)); 28762306a36Sopenharmony_ci return prog_fd; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci prog_info = (struct bpf_prog_info) { 29162306a36Sopenharmony_ci .nr_map_ids = 8, 29262306a36Sopenharmony_ci .map_ids = (__u64)(unsigned long)map_ids, 29362306a36Sopenharmony_ci }; 29462306a36Sopenharmony_ci info_len = sizeof(prog_info); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci err = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &info_len); 29762306a36Sopenharmony_ci if (err != 0) { 29862306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_prog_get_info_by_fd: %s\n", 29962306a36Sopenharmony_ci strerror(-err)); 30062306a36Sopenharmony_ci goto out; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (prog_info.nr_map_ids < 2) { 30462306a36Sopenharmony_ci fprintf(stderr, "Error: Found %u BPF maps, expected at least 2\n", 30562306a36Sopenharmony_ci prog_info.nr_map_ids); 30662306a36Sopenharmony_ci err = -ENOENT; 30762306a36Sopenharmony_ci goto out; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci for (i = 0; i < prog_info.nr_map_ids; i++) { 31162306a36Sopenharmony_ci struct bpf_map_info map_info = {}; 31262306a36Sopenharmony_ci int map_fd; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci err = bpf_map_get_fd_by_id(map_ids[i]); 31562306a36Sopenharmony_ci if (err < 0) { 31662306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_map_get_fd_by_id: %s\n", strerror(-err)); 31762306a36Sopenharmony_ci goto err_close_map_fds; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci map_fd = err; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci info_len = sizeof(map_info); 32262306a36Sopenharmony_ci err = bpf_map_get_info_by_fd(map_fd, &map_info, &info_len); 32362306a36Sopenharmony_ci if (err != 0) { 32462306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_map_get_info_by_fd: %s\n", 32562306a36Sopenharmony_ci strerror(-err)); 32662306a36Sopenharmony_ci close(map_fd); 32762306a36Sopenharmony_ci goto err_close_map_fds; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci if (strcmp(map_info.name, "values") == 0) { 33062306a36Sopenharmony_ci *values_map_fd = map_fd; 33162306a36Sopenharmony_ci continue; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci if (strcmp(map_info.name, "allowed_ports") == 0) { 33462306a36Sopenharmony_ci *ports_map_fd = map_fd; 33562306a36Sopenharmony_ci continue; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci close(map_fd); 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (*values_map_fd != -1 && *ports_map_fd != -1) { 34162306a36Sopenharmony_ci err = 0; 34262306a36Sopenharmony_ci goto out; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci err = -ENOENT; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cierr_close_map_fds: 34862306a36Sopenharmony_ci if (*values_map_fd != -1) 34962306a36Sopenharmony_ci close(*values_map_fd); 35062306a36Sopenharmony_ci if (*ports_map_fd != -1) 35162306a36Sopenharmony_ci close(*ports_map_fd); 35262306a36Sopenharmony_ci *values_map_fd = -1; 35362306a36Sopenharmony_ci *ports_map_fd = -1; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ciout: 35662306a36Sopenharmony_ci close(prog_fd); 35762306a36Sopenharmony_ci return err; 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ciint main(int argc, char *argv[]) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci int values_map_fd, ports_map_fd; 36362306a36Sopenharmony_ci __u64 tcpipopts; 36462306a36Sopenharmony_ci bool firstiter; 36562306a36Sopenharmony_ci __u64 prevcnt; 36662306a36Sopenharmony_ci __u32 prog_id; 36762306a36Sopenharmony_ci char *ports; 36862306a36Sopenharmony_ci bool single; 36962306a36Sopenharmony_ci int err = 0; 37062306a36Sopenharmony_ci bool tc; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci parse_options(argc, argv, &ifindex, &prog_id, &tcpipopts, &ports, 37362306a36Sopenharmony_ci &single, &tc); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (prog_id == 0) { 37662306a36Sopenharmony_ci if (!tc) { 37762306a36Sopenharmony_ci err = bpf_xdp_query_id(ifindex, 0, &prog_id); 37862306a36Sopenharmony_ci if (err < 0) { 37962306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_get_link_xdp_id: %s\n", 38062306a36Sopenharmony_ci strerror(-err)); 38162306a36Sopenharmony_ci goto out; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci if (prog_id == 0) { 38562306a36Sopenharmony_ci err = syncookie_attach(argv[0], ifindex, tc); 38662306a36Sopenharmony_ci if (err < 0) 38762306a36Sopenharmony_ci goto out; 38862306a36Sopenharmony_ci prog_id = attached_prog_id; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci err = syncookie_open_bpf_maps(prog_id, &values_map_fd, &ports_map_fd); 39362306a36Sopenharmony_ci if (err < 0) 39462306a36Sopenharmony_ci goto out; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (ports) { 39762306a36Sopenharmony_ci __u16 port_last = 0; 39862306a36Sopenharmony_ci __u32 port_idx = 0; 39962306a36Sopenharmony_ci char *p = ports; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci fprintf(stderr, "Replacing allowed ports\n"); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci while (p && *p != '\0') { 40462306a36Sopenharmony_ci char *token = strsep(&p, ","); 40562306a36Sopenharmony_ci __u16 port; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci port = parse_arg_ul(argv[0], token, UINT16_MAX); 40862306a36Sopenharmony_ci err = bpf_map_update_elem(ports_map_fd, &port_idx, &port, BPF_ANY); 40962306a36Sopenharmony_ci if (err != 0) { 41062306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_map_update_elem: %s\n", strerror(-err)); 41162306a36Sopenharmony_ci fprintf(stderr, "Failed to add port %u (index %u)\n", 41262306a36Sopenharmony_ci port, port_idx); 41362306a36Sopenharmony_ci goto out_close_maps; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci fprintf(stderr, "Added port %u\n", port); 41662306a36Sopenharmony_ci port_idx++; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci err = bpf_map_update_elem(ports_map_fd, &port_idx, &port_last, BPF_ANY); 41962306a36Sopenharmony_ci if (err != 0) { 42062306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_map_update_elem: %s\n", strerror(-err)); 42162306a36Sopenharmony_ci fprintf(stderr, "Failed to add the terminator value 0 (index %u)\n", 42262306a36Sopenharmony_ci port_idx); 42362306a36Sopenharmony_ci goto out_close_maps; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (tcpipopts) { 42862306a36Sopenharmony_ci __u32 key = 0; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci fprintf(stderr, "Replacing TCP/IP options\n"); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci err = bpf_map_update_elem(values_map_fd, &key, &tcpipopts, BPF_ANY); 43362306a36Sopenharmony_ci if (err != 0) { 43462306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_map_update_elem: %s\n", strerror(-err)); 43562306a36Sopenharmony_ci goto out_close_maps; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if ((ports || tcpipopts) && attached_prog_id == 0 && !single) 44062306a36Sopenharmony_ci goto out_close_maps; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci prevcnt = 0; 44362306a36Sopenharmony_ci firstiter = true; 44462306a36Sopenharmony_ci while (true) { 44562306a36Sopenharmony_ci __u32 key = 1; 44662306a36Sopenharmony_ci __u64 value; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci err = bpf_map_lookup_elem(values_map_fd, &key, &value); 44962306a36Sopenharmony_ci if (err != 0) { 45062306a36Sopenharmony_ci fprintf(stderr, "Error: bpf_map_lookup_elem: %s\n", strerror(-err)); 45162306a36Sopenharmony_ci goto out_close_maps; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci if (firstiter) { 45462306a36Sopenharmony_ci prevcnt = value; 45562306a36Sopenharmony_ci firstiter = false; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci if (single) { 45862306a36Sopenharmony_ci printf("Total SYNACKs generated: %llu\n", value); 45962306a36Sopenharmony_ci break; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci printf("SYNACKs generated: %llu (total %llu)\n", value - prevcnt, value); 46262306a36Sopenharmony_ci prevcnt = value; 46362306a36Sopenharmony_ci sleep(1); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ciout_close_maps: 46762306a36Sopenharmony_ci close(values_map_fd); 46862306a36Sopenharmony_ci close(ports_map_fd); 46962306a36Sopenharmony_ciout: 47062306a36Sopenharmony_ci return err == 0 ? 0 : 1; 47162306a36Sopenharmony_ci} 472