Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/tools/testing/selftests/bpf/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 10 kB image not shown  

Quelle  xdp_synproxy.c   Sprache: C

 
// SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */

#include <stdnoreturn.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <getopt.h>
#include <signal.h>
#include <sys/types.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <net/if.h>
#include <linux/if_link.h>
#include <linux/limits.h>

static unsigned int ifindex;
static __u32 attached_prog_id;
static bool attached_tc;

static void noreturn cleanup(int sig)
{
 LIBBPF_OPTS(bpf_xdp_attach_opts, opts);
 int prog_fd;
 int err;

 if (attached_prog_id == 0)
  exit(0);

 if (attached_tc) {
  LIBBPF_OPTS(bpf_tc_hook, hook,
       .ifindex = ifindex,
       .attach_point = BPF_TC_INGRESS);

  err = bpf_tc_hook_destroy(&hook);
  if (err < 0) {
   fprintf(stderr, "Error: bpf_tc_hook_destroy: %s\n", strerror(-err));
   fprintf(stderr, "Failed to destroy the TC hook\n");
   exit(1);
  }
  exit(0);
 }

 prog_fd = bpf_prog_get_fd_by_id(attached_prog_id);
 if (prog_fd < 0) {
  fprintf(stderr, "Error: bpf_prog_get_fd_by_id: %s\n", strerror(-prog_fd));
  err = bpf_xdp_attach(ifindex, -1, 0, NULL);
  if (err < 0) {
   fprintf(stderr, "Error: bpf_set_link_xdp_fd: %s\n", strerror(-err));
   fprintf(stderr, "Failed to detach XDP program\n");
   exit(1);
  }
 } else {
  opts.old_prog_fd = prog_fd;
  err = bpf_xdp_attach(ifindex, -1, XDP_FLAGS_REPLACE, &opts);
  close(prog_fd);
  if (err < 0) {
   fprintf(stderr, "Error: bpf_set_link_xdp_fd_opts: %s\n", strerror(-err));
   /* Not an error if already replaced by someone else. */
   if (err != -EEXIST) {
    fprintf(stderr, "Failed to detach XDP program\n");
    exit(1);
   }
  }
 }
 exit(0);
}

static noreturn void usage(const char *progname)
{
 fprintf(stderr, "Usage: %s [--iface |--prog ] [--mss4 --mss6 --wscale --ttl ] [--ports ,,...] [--single] [--tc]\n",
  progname);
 exit(1);
}

static unsigned long parse_arg_ul(const char *progname, const char *arg, unsigned long limit)
{
 unsigned long res;
 char *endptr;

 errno = 0;
 res = strtoul(arg, &endptr, 10);
 if (errno != 0 || *endptr != '\0' || arg[0] == '\0' || res > limit)
  usage(progname);

 return res;
}

static void parse_options(int argc, char *argv[], unsigned int *ifindex, __u32 *prog_id,
     __u64 *tcpipopts, char **ports, bool *single, bool *tc)
{
 static struct option long_options[] = {
  { "help", no_argument, NULL, 'h' },
  { "iface", required_argument, NULL, 'i' },
  { "prog", required_argument, NULL, 'x' },
  { "mss4", required_argument, NULL, 4 },
  { "mss6", required_argument, NULL, 6 },
  { "wscale", required_argument, NULL, 'w' },
  { "ttl", required_argument, NULL, 't' },
  { "ports", required_argument, NULL, 'p' },
  { "single", no_argument, NULL, 's' },
  { "tc", no_argument, NULL, 'c' },
  { NULL, 0, NULL, 0 },
 };
 unsigned long mss4, wscale, ttl;
 unsigned long long mss6;
 unsigned int tcpipopts_mask = 0;

 if (argc < 2)
  usage(argv[0]);

 *ifindex = 0;
 *prog_id = 0;
 *tcpipopts = 0;
 *ports = NULL;
 *single = false;
 *tc = false;

 while (true) {
  int opt;

  opt = getopt_long(argc, argv, "", long_options, NULL);
  if (opt == -1)
   break;

  switch (opt) {
  case 'h':
   usage(argv[0]);
   break;
  case 'i':
   *ifindex = if_nametoindex(optarg);
   if (*ifindex == 0)
    usage(argv[0]);
   break;
  case 'x':
   *prog_id = parse_arg_ul(argv[0], optarg, UINT32_MAX);
   if (*prog_id == 0)
    usage(argv[0]);
   break;
  case 4:
   mss4 = parse_arg_ul(argv[0], optarg, UINT16_MAX);
   tcpipopts_mask |= 1 << 0;
   break;
  case 6:
   mss6 = parse_arg_ul(argv[0], optarg, UINT16_MAX);
   tcpipopts_mask |= 1 << 1;
   break;
  case 'w':
   wscale = parse_arg_ul(argv[0], optarg, 14);
   tcpipopts_mask |= 1 << 2;
   break;
  case 't':
   ttl = parse_arg_ul(argv[0], optarg, UINT8_MAX);
   tcpipopts_mask |= 1 << 3;
   break;
  case 'p':
   *ports = optarg;
   break;
  case 's':
   *single = true;
   break;
  case 'c':
   *tc = true;
   break;
  default:
   usage(argv[0]);
  }
 }
 if (optind < argc)
  usage(argv[0]);

 if (tcpipopts_mask == 0xf) {
  if (mss4 == 0 || mss6 == 0 || wscale == 0 || ttl == 0)
   usage(argv[0]);
  *tcpipopts = (mss6 << 32) | (ttl << 24) | (wscale << 16) | mss4;
 } else if (tcpipopts_mask != 0) {
  usage(argv[0]);
 }

 if (*ifindex != 0 && *prog_id != 0)
  usage(argv[0]);
 if (*ifindex == 0 && *prog_id == 0)
  usage(argv[0]);
}

static int syncookie_attach(const char *argv0, unsigned int ifindex, bool tc)
{
 struct bpf_prog_info info = {};
 __u32 info_len = sizeof(info);
 char xdp_filename[PATH_MAX];
 struct bpf_program *prog;
 struct bpf_object *obj;
 int prog_fd;
 int err;

 snprintf(xdp_filename, sizeof(xdp_filename), "%s_kern.bpf.o", argv0);
 obj = bpf_object__open_file(xdp_filename, NULL);
 err = libbpf_get_error(obj);
 if (err < 0) {
  fprintf(stderr, "Error: bpf_object__open_file: %s\n", strerror(-err));
  return err;
 }

 err = bpf_object__load(obj);
 if (err < 0) {
  fprintf(stderr, "Error: bpf_object__open_file: %s\n", strerror(-err));
  return err;
 }

 prog = bpf_object__find_program_by_name(obj, tc ? "syncookie_tc" : "syncookie_xdp");
 if (!prog) {
  fprintf(stderr, "Error: bpf_object__find_program_by_name: program was not found\n");
  return -ENOENT;
 }

 prog_fd = bpf_program__fd(prog);

 err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);
 if (err < 0) {
  fprintf(stderr, "Error: bpf_prog_get_info_by_fd: %s\n",
   strerror(-err));
  goto out;
 }
 attached_tc = tc;
 attached_prog_id = info.id;
 signal(SIGINT, cleanup);
 signal(SIGTERM, cleanup);
 if (tc) {
  LIBBPF_OPTS(bpf_tc_hook, hook,
       .ifindex = ifindex,
       .attach_point = BPF_TC_INGRESS);
  LIBBPF_OPTS(bpf_tc_opts, opts,
       .handle = 1,
       .priority = 1,
       .prog_fd = prog_fd);

  err = bpf_tc_hook_create(&hook);
  if (err < 0) {
   fprintf(stderr, "Error: bpf_tc_hook_create: %s\n",
    strerror(-err));
   goto fail;
  }
  err = bpf_tc_attach(&hook, &opts);
  if (err < 0) {
   fprintf(stderr, "Error: bpf_tc_attach: %s\n",
    strerror(-err));
   goto fail;
  }

 } else {
  err = bpf_xdp_attach(ifindex, prog_fd,
         XDP_FLAGS_UPDATE_IF_NOEXIST, NULL);
  if (err < 0) {
   fprintf(stderr, "Error: bpf_set_link_xdp_fd: %s\n",
    strerror(-err));
   goto fail;
  }
 }
 err = 0;
out:
 bpf_object__close(obj);
 return err;
fail:
 signal(SIGINT, SIG_DFL);
 signal(SIGTERM, SIG_DFL);
 attached_prog_id = 0;
 goto out;
}

static int syncookie_open_bpf_maps(__u32 prog_id, int *values_map_fd, int *ports_map_fd)
{
 struct bpf_prog_info prog_info;
 __u32 map_ids[8];
 __u32 info_len;
 int prog_fd;
 int err;
 int i;

 *values_map_fd = -1;
 *ports_map_fd = -1;

 prog_fd = bpf_prog_get_fd_by_id(prog_id);
 if (prog_fd < 0) {
  fprintf(stderr, "Error: bpf_prog_get_fd_by_id: %s\n", strerror(-prog_fd));
  return prog_fd;
 }

 prog_info = (struct bpf_prog_info) {
  .nr_map_ids = 8,
  .map_ids = (__u64)(unsigned long)map_ids,
 };
 info_len = sizeof(prog_info);

 err = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &info_len);
 if (err != 0) {
  fprintf(stderr, "Error: bpf_prog_get_info_by_fd: %s\n",
   strerror(-err));
  goto out;
 }

 if (prog_info.nr_map_ids < 2) {
  fprintf(stderr, "Error: Found %u BPF maps, expected at least 2\n",
   prog_info.nr_map_ids);
  err = -ENOENT;
  goto out;
 }

 for (i = 0; i < prog_info.nr_map_ids; i++) {
  struct bpf_map_info map_info = {};
  int map_fd;

  err = bpf_map_get_fd_by_id(map_ids[i]);
  if (err < 0) {
   fprintf(stderr, "Error: bpf_map_get_fd_by_id: %s\n", strerror(-err));
   goto err_close_map_fds;
  }
  map_fd = err;

  info_len = sizeof(map_info);
  err = bpf_map_get_info_by_fd(map_fd, &map_info, &info_len);
  if (err != 0) {
   fprintf(stderr, "Error: bpf_map_get_info_by_fd: %s\n",
    strerror(-err));
   close(map_fd);
   goto err_close_map_fds;
  }
  if (strcmp(map_info.name, "values") == 0) {
   *values_map_fd = map_fd;
   continue;
  }
  if (strcmp(map_info.name, "allowed_ports") == 0) {
   *ports_map_fd = map_fd;
   continue;
  }
  close(map_fd);
 }

 if (*values_map_fd != -1 && *ports_map_fd != -1) {
  err = 0;
  goto out;
 }

 err = -ENOENT;

err_close_map_fds:
 if (*values_map_fd != -1)
  close(*values_map_fd);
 if (*ports_map_fd != -1)
  close(*ports_map_fd);
 *values_map_fd = -1;
 *ports_map_fd = -1;

out:
 close(prog_fd);
 return err;
}

int main(int argc, char *argv[])
{
 int values_map_fd, ports_map_fd;
 __u64 tcpipopts;
 bool firstiter;
 __u64 prevcnt;
 __u32 prog_id;
 char *ports;
 bool single;
 int err = 0;
 bool tc;

 parse_options(argc, argv, &ifindex, &prog_id, &tcpipopts, &ports,
        &single, &tc);

 if (prog_id == 0) {
  if (!tc) {
   err = bpf_xdp_query_id(ifindex, 0, &prog_id);
   if (err < 0) {
    fprintf(stderr, "Error: bpf_get_link_xdp_id: %s\n",
     strerror(-err));
    goto out;
   }
  }
  if (prog_id == 0) {
   err = syncookie_attach(argv[0], ifindex, tc);
   if (err < 0)
    goto out;
   prog_id = attached_prog_id;
  }
 }

 err = syncookie_open_bpf_maps(prog_id, &values_map_fd, &ports_map_fd);
 if (err < 0)
  goto out;

 if (ports) {
  __u16 port_last = 0;
  __u32 port_idx = 0;
  char *p = ports;

  fprintf(stderr, "Replacing allowed ports\n");

  while (p && *p != '\0') {
   char *token = strsep(&p, ",");
   __u16 port;

   port = parse_arg_ul(argv[0], token, UINT16_MAX);
   err = bpf_map_update_elem(ports_map_fd, &port_idx, &port, BPF_ANY);
   if (err != 0) {
    fprintf(stderr, "Error: bpf_map_update_elem: %s\n", strerror(-err));
    fprintf(stderr, "Failed to add port %u (index %u)\n",
     port, port_idx);
    goto out_close_maps;
   }
   fprintf(stderr, "Added port %u\n", port);
   port_idx++;
  }
  err = bpf_map_update_elem(ports_map_fd, &port_idx, &port_last, BPF_ANY);
  if (err != 0) {
   fprintf(stderr, "Error: bpf_map_update_elem: %s\n", strerror(-err));
   fprintf(stderr, "Failed to add the terminator value 0 (index %u)\n",
    port_idx);
   goto out_close_maps;
  }
 }

 if (tcpipopts) {
  __u32 key = 0;

  fprintf(stderr, "Replacing TCP/IP options\n");

  err = bpf_map_update_elem(values_map_fd, &key, &tcpipopts, BPF_ANY);
  if (err != 0) {
   fprintf(stderr, "Error: bpf_map_update_elem: %s\n", strerror(-err));
   goto out_close_maps;
  }
 }

 if ((ports || tcpipopts) && attached_prog_id == 0 && !single)
  goto out_close_maps;

 prevcnt = 0;
 firstiter = true;
 while (true) {
  __u32 key = 1;
  __u64 value;

  err = bpf_map_lookup_elem(values_map_fd, &key, &value);
  if (err != 0) {
   fprintf(stderr, "Error: bpf_map_lookup_elem: %s\n", strerror(-err));
   goto out_close_maps;
  }
  if (firstiter) {
   prevcnt = value;
   firstiter = false;
  }
  if (single) {
   printf("Total SYNACKs generated: %llu\n", value);
   break;
  }
  printf("SYNACKs generated: %llu (total %llu)\n", value - prevcnt, value);
  prevcnt = value;
  sleep(1);
 }

out_close_maps:
 close(values_map_fd);
 close(ports_map_fd);
out:
 return err == 0 ? 0 : 1;
}

Messung V0.5
C=98 H=92 G=94

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.