├── .clang-format ├── .clang-tidy ├── .github ├── CODEOWNERS ├── fedora-40.Dockerfile ├── fedora-41.Dockerfile ├── fedora-42.Dockerfile ├── ubuntu-24.04.Dockerfile ├── ubuntu-24.10.Dockerfile └── workflows │ └── ci.yaml ├── .gitignore ├── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── COPYING ├── README.md ├── codecov.yml ├── doc ├── CMakeLists.txt ├── Doxyfile.in ├── _static │ ├── benchmarks.html │ ├── demo_dark.gif │ ├── demo_light.gif │ ├── favicon.ico │ ├── logo-dark-mode.png │ └── logo-light-mode.png ├── _templates │ └── page.html ├── benchmarks.html.template ├── benchreport ├── conf.py.in ├── covreport ├── developers │ ├── build.rst │ ├── contributing.rst │ ├── generation.rst │ ├── modules │ │ ├── bpfilter │ │ │ ├── bpfilter.rst │ │ │ └── xlate │ │ │ │ ├── index.rst │ │ │ │ ├── ipt.rst │ │ │ │ └── nft.rst │ │ ├── index.rst │ │ └── libbpfilter │ │ │ └── libbpfilter.rst │ ├── packets_processing.rst │ ├── style.rst │ └── tests.rst ├── external │ ├── benchmarks │ │ └── index.rst │ └── coverage │ │ └── index.rst ├── index.rst └── usage │ ├── bfcli.rst │ ├── daemon.rst │ ├── index.rst │ ├── iptables.rst │ └── nftables.rst ├── src ├── bfcli │ ├── CMakeLists.txt │ ├── chain.c │ ├── chain.h │ ├── helper.c │ ├── helper.h │ ├── lexer.l │ ├── main.c │ ├── opts.c │ ├── opts.h │ ├── parser.y │ ├── print.c │ ├── print.h │ ├── ruleset.c │ └── ruleset.h ├── bpfilter │ ├── CMakeLists.txt │ ├── bpf │ │ ├── log.bpf.c │ │ ├── parse_ipv6_eh.bpf.c │ │ ├── parse_ipv6_nh.bpf.c │ │ └── update_counters.bpf.c │ ├── bpfilter.service.in │ ├── cgen │ │ ├── cgen.c │ │ ├── cgen.h │ │ ├── cgroup.c │ │ ├── cgroup.h │ │ ├── dump.c │ │ ├── dump.h │ │ ├── elfstub.c │ │ ├── elfstub.h │ │ ├── fixup.c │ │ ├── fixup.h │ │ ├── jmp.c │ │ ├── jmp.h │ │ ├── matcher │ │ │ ├── icmp.c │ │ │ ├── icmp.h │ │ │ ├── ip4.c │ │ │ ├── ip4.h │ │ │ ├── ip6.c │ │ │ ├── ip6.h │ │ │ ├── meta.c │ │ │ ├── meta.h │ │ │ ├── set.c │ │ │ ├── set.h │ │ │ ├── tcp.c │ │ │ ├── tcp.h │ │ │ ├── udp.c │ │ │ └── udp.h │ │ ├── nf.c │ │ ├── nf.h │ │ ├── printer.c │ │ ├── printer.h │ │ ├── prog │ │ │ ├── link.c │ │ │ ├── link.h │ │ │ ├── map.c │ │ │ └── map.h │ │ ├── program.c │ │ ├── program.h │ │ ├── runtime.h │ │ ├── stub.c │ │ ├── stub.h │ │ ├── swich.c │ │ ├── swich.h │ │ ├── tc.c │ │ ├── tc.h │ │ ├── xdp.c │ │ └── xdp.h │ ├── ctx.c │ ├── ctx.h │ ├── main.c │ ├── opts.c │ ├── opts.h │ └── xlate │ │ ├── cli.c │ │ ├── front.c │ │ ├── front.h │ │ ├── ipt │ │ ├── dump.c │ │ ├── dump.h │ │ ├── helpers.h │ │ └── ipt.c │ │ └── nft │ │ ├── nfgroup.c │ │ ├── nfgroup.h │ │ ├── nfmsg.c │ │ ├── nfmsg.h │ │ └── nft.c ├── external │ ├── disasm.c │ ├── include │ │ ├── asm-generic │ │ │ ├── bitsperlong.h │ │ │ ├── errno-base.h │ │ │ ├── errno.h │ │ │ ├── int-ll64.h │ │ │ ├── posix_types.h │ │ │ ├── socket.h │ │ │ ├── sockios.h │ │ │ ├── swab.h │ │ │ └── types.h │ │ ├── asm │ │ │ ├── bitsperlong.h │ │ │ ├── byteorder.h │ │ │ ├── errno.h │ │ │ ├── posix_types.h │ │ │ ├── sigcontext.h │ │ │ ├── socket.h │ │ │ ├── sockios.h │ │ │ ├── sve_context.h │ │ │ ├── swab.h │ │ │ └── types.h │ │ ├── disasm.h │ │ ├── filter.h │ │ ├── linux │ │ │ ├── bpf.h │ │ │ ├── bpf_common.h │ │ │ ├── btf.h │ │ │ ├── byteorder │ │ │ │ └── little_endian.h │ │ │ ├── close_range.h │ │ │ ├── const.h │ │ │ ├── errno.h │ │ │ ├── falloc.h │ │ │ ├── genetlink.h │ │ │ ├── hdlc │ │ │ │ └── ioctl.h │ │ │ ├── icmp.h │ │ │ ├── icmpv6.h │ │ │ ├── if.h │ │ │ ├── if_addr.h │ │ │ ├── if_ether.h │ │ │ ├── if_link.h │ │ │ ├── in.h │ │ │ ├── in6.h │ │ │ ├── ip.h │ │ │ ├── ipv6.h │ │ │ ├── kernel.h │ │ │ ├── libc-compat.h │ │ │ ├── limits.h │ │ │ ├── neighbour.h │ │ │ ├── netfilter.h │ │ │ ├── netfilter │ │ │ │ ├── nf_tables.h │ │ │ │ ├── nfnetlink.h │ │ │ │ ├── nfnetlink_compat.h │ │ │ │ ├── x_tables.h │ │ │ │ └── xt_tcpudp.h │ │ │ ├── netfilter_ipv4.h │ │ │ ├── netfilter_ipv4 │ │ │ │ └── ip_tables.h │ │ │ ├── netlink.h │ │ │ ├── pkt_cls.h │ │ │ ├── pkt_sched.h │ │ │ ├── posix_types.h │ │ │ ├── rtnetlink.h │ │ │ ├── sched │ │ │ │ └── types.h │ │ │ ├── socket.h │ │ │ ├── stat.h │ │ │ ├── stddef.h │ │ │ ├── swab.h │ │ │ ├── sysinfo.h │ │ │ ├── tcp.h │ │ │ ├── types.h │ │ │ └── udp.h │ │ └── mpack.h │ └── mpack.c └── libbpfilter │ ├── CMakeLists.txt │ ├── bpf.c │ ├── bpfilter.pc.in │ ├── btf.c │ ├── chain.c │ ├── cli.c │ ├── counter.c │ ├── dump.c │ ├── dynbuf.c │ ├── flavor.c │ ├── front.c │ ├── generic.c │ ├── helper.c │ ├── hook.c │ ├── if.c │ ├── include │ └── bpfilter │ │ ├── bpf.h │ │ ├── bpf_types.h │ │ ├── bpfilter.h │ │ ├── btf.h │ │ ├── chain.h │ │ ├── counter.h │ │ ├── dump.h │ │ ├── dynbuf.h │ │ ├── flavor.h │ │ ├── front.h │ │ ├── generic.h │ │ ├── helper.h │ │ ├── hook.h │ │ ├── if.h │ │ ├── io.h │ │ ├── list.h │ │ ├── logger.h │ │ ├── matcher.h │ │ ├── ns.h │ │ ├── pack.h │ │ ├── request.h │ │ ├── response.h │ │ ├── rule.h │ │ ├── runtime.h │ │ ├── set.h │ │ ├── verdict.h │ │ └── version.h.in │ ├── io.c │ ├── ipt.c │ ├── list.c │ ├── logger.c │ ├── matcher.c │ ├── nft.c │ ├── ns.c │ ├── pack.c │ ├── request.c │ ├── response.c │ ├── rule.c │ ├── set.c │ ├── verdict.c │ └── version.c ├── tests ├── CMakeLists.txt ├── e2e │ ├── CMakeLists.txt │ ├── cli.sh │ ├── e2e.c │ ├── e2e.h │ ├── genpkts.py │ ├── main.c │ ├── opts.c │ ├── opts.h │ ├── rulesets │ │ ├── cgroup_egress.bf │ │ ├── cgroup_ingress.bf │ │ ├── nf_forward.bf │ │ ├── nf_local_in.bf │ │ ├── nf_local_out.bf │ │ ├── nf_post_routing.bf │ │ ├── nf_pre_routing.bf │ │ ├── tc_egress.bf │ │ ├── tc_ingress.bf │ │ └── xdp.bf │ └── setuserns.c ├── harness │ ├── CMakeLists.txt │ ├── daemon.c │ ├── daemon.h │ ├── filters.c │ ├── filters.h │ ├── mock.c │ ├── mock.h │ ├── process.c │ ├── process.h │ ├── prog.c │ ├── prog.h │ ├── test.c │ └── test.h ├── integration │ ├── CMakeLists.txt │ ├── iptables │ │ └── 0001-iptables-add-support-for-bpfilter.patch │ └── nftables │ │ └── 0001-libnftables-add-support-for-bpfilter.patch ├── pedantic │ ├── CMakeLists.txt │ ├── pedantic.c │ └── pedantic.cpp ├── rules.bpfilter └── unit │ ├── CMakeLists.txt │ ├── assert_override.h │ ├── bpfilter │ ├── cgen │ │ ├── cgen.c │ │ ├── jmp.c │ │ ├── printer.c │ │ ├── prog │ │ │ └── map.c │ │ ├── program.c │ │ └── swich.c │ ├── ctx.c │ ├── opts.c │ └── xlate │ │ └── nft │ │ ├── nfgroup.c │ │ ├── nfmsg.c │ │ └── nft.c │ ├── fake.c │ ├── fake.h │ ├── libbpfilter │ ├── btf.c │ ├── chain.c │ ├── flavor.c │ ├── front.c │ ├── helper.c │ ├── hook.c │ ├── list.c │ ├── matcher.c │ ├── rule.c │ ├── set.c │ └── verdict.c │ ├── main.c │ ├── mock.c │ └── mock.h └── tools ├── asroot ├── benchmarks ├── CMakeLists.txt ├── benchmark.cpp ├── benchmark.hpp └── main.cpp ├── checks ├── CMakeLists.txt └── filtersrcs ├── cmake ├── ElfStubs.cmake ├── GitVersion.cmake └── rawstubs.h.in ├── getkhdrs └── perfrec /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @qdeslandes 2 | -------------------------------------------------------------------------------- /.github/fedora-40.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora:40 2 | 3 | RUN dnf --disablerepo=* --enablerepo=fedora,updates --nodocs --setopt=install_weak_deps=False -y install \ 4 | autoconf \ 5 | automake \ 6 | gawk \ 7 | bpftool \ 8 | bison \ 9 | clang \ 10 | clang-tools-extra \ 11 | cmake \ 12 | doxygen \ 13 | flex \ 14 | gcc \ 15 | gcc-c++ \ 16 | git-core \ 17 | google-benchmark-devel \ 18 | iproute \ 19 | iputils \ 20 | jq \ 21 | lcov \ 22 | libbpf-devel \ 23 | libcmocka-devel \ 24 | libgit2-devel \ 25 | libnl3-devel \ 26 | libtool \ 27 | procps-ng \ 28 | python3-breathe \ 29 | python3-dateutil \ 30 | python3-furo \ 31 | python3-GitPython \ 32 | python3-linuxdoc \ 33 | python3-scapy \ 34 | python3-sphinx \ 35 | sed \ 36 | xxd && \ 37 | dnf clean all -y 38 | -------------------------------------------------------------------------------- /.github/fedora-41.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora:41 2 | 3 | RUN dnf --disablerepo=* --enablerepo=fedora,updates --nodocs --setopt=install_weak_deps=False -y install \ 4 | autoconf \ 5 | automake \ 6 | gawk \ 7 | bpftool \ 8 | bison \ 9 | clang \ 10 | clang-tools-extra \ 11 | cmake \ 12 | doxygen \ 13 | flex \ 14 | gcc \ 15 | gcc-c++ \ 16 | git-core \ 17 | google-benchmark-devel \ 18 | iproute \ 19 | iputils \ 20 | jq \ 21 | lcov \ 22 | libbpf-devel \ 23 | libcmocka-devel \ 24 | libgit2-devel \ 25 | libnl3-devel \ 26 | libtool \ 27 | procps-ng \ 28 | python3-breathe \ 29 | python3-dateutil \ 30 | python3-furo \ 31 | python3-GitPython \ 32 | python3-linuxdoc \ 33 | python3-scapy \ 34 | python3-sphinx \ 35 | sed \ 36 | xxd && \ 37 | dnf clean all -y 38 | -------------------------------------------------------------------------------- /.github/fedora-42.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora:42 2 | 3 | RUN dnf --disablerepo=* --enablerepo=fedora,updates --nodocs --setopt=install_weak_deps=False -y install \ 4 | autoconf \ 5 | automake \ 6 | gawk \ 7 | bpftool \ 8 | bison \ 9 | clang \ 10 | clang-tools-extra \ 11 | cmake \ 12 | doxygen \ 13 | flex \ 14 | gcc \ 15 | gcc-c++ \ 16 | git-core \ 17 | google-benchmark-devel \ 18 | iproute \ 19 | iputils \ 20 | jq \ 21 | lcov \ 22 | libbpf-devel \ 23 | libcmocka-devel \ 24 | libgit2-devel \ 25 | libnl3-devel \ 26 | libtool \ 27 | procps-ng \ 28 | python3-breathe \ 29 | python3-dateutil \ 30 | python3-furo \ 31 | python3-GitPython \ 32 | python3-linuxdoc \ 33 | python3-scapy \ 34 | python3-sphinx \ 35 | sed \ 36 | xxd && \ 37 | dnf clean all -y 38 | -------------------------------------------------------------------------------- /.github/ubuntu-24.04.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 2 | 3 | RUN apt-get update && apt-get install --no-install-recommends -y \ 4 | autoconf \ 5 | automake \ 6 | bison \ 7 | clang \ 8 | clang-tidy \ 9 | clang-format \ 10 | cmake \ 11 | doxygen \ 12 | flex \ 13 | furo \ 14 | g++ \ 15 | git \ 16 | iproute2 \ 17 | iputils-ping \ 18 | lcov \ 19 | libbenchmark-dev \ 20 | libbpf-dev \ 21 | libc-dev \ 22 | libcmocka-dev \ 23 | libgit2-dev \ 24 | libnl-3-dev \ 25 | libtool \ 26 | linux-tools-common \ 27 | make \ 28 | pkgconf \ 29 | procps \ 30 | python3-breathe \ 31 | python3-dateutil \ 32 | python3-git \ 33 | python3-pip \ 34 | python3-scapy \ 35 | python3-sphinx \ 36 | sed \ 37 | xxd && \ 38 | rm -rf /var/lib/apt/lists/* 39 | 40 | RUN pip install --break-system-packages linuxdoc 41 | -------------------------------------------------------------------------------- /.github/ubuntu-24.10.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.10 2 | 3 | RUN apt-get update && apt-get install --no-install-recommends -y \ 4 | autoconf \ 5 | automake \ 6 | bison \ 7 | clang \ 8 | clang-tidy \ 9 | clang-format \ 10 | cmake \ 11 | doxygen \ 12 | flex \ 13 | furo \ 14 | g++ \ 15 | git \ 16 | iproute2 \ 17 | iputils-ping \ 18 | lcov \ 19 | libbenchmark-dev \ 20 | libbpf-dev \ 21 | libc-dev \ 22 | libcmocka-dev \ 23 | libgit2-dev \ 24 | libnl-3-dev \ 25 | libtool \ 26 | linux-tools-common \ 27 | make \ 28 | pkgconf \ 29 | procps \ 30 | python3-breathe \ 31 | python3-dateutil \ 32 | python3-git \ 33 | python3-pip \ 34 | python3-scapy \ 35 | python3-setuptools \ 36 | python3-sphinx \ 37 | sed \ 38 | xxd && \ 39 | rm -rf /var/lib/apt/lists/* 40 | 41 | RUN pip install --break-system-packages linuxdoc 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Usual build folder 2 | /build/ 3 | 4 | # IDE configuration folder 5 | .zed 6 | .vscode 7 | 8 | # Cache folders and artifacts 9 | *.pyc 10 | __pycache__ 11 | .cache 12 | .clangd 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 3 | 4 | cmake_minimum_required(VERSION 3.20) 5 | 6 | if (NOT DEFINED DEFAULT_PROJECT_VERSION) 7 | set(DEFAULT_PROJECT_VERSION 0.0.0) 8 | endif () 9 | 10 | project(bpfilter 11 | VERSION ${DEFAULT_PROJECT_VERSION} 12 | DESCRIPTION "BPF-based packet filtering framework" 13 | LANGUAGES C CXX 14 | ) 15 | 16 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/tools/cmake") 17 | 18 | include(GitVersion) 19 | get_version_from_git() 20 | message(NOTICE "bpfilter version ${PROJECT_VERSION}${PROJECT_VERSION_SUFFIX}") 21 | 22 | include(GNUInstallDirs) 23 | 24 | option(NO_DOCS "Disable documentation generation" 0) 25 | option(NO_TESTS "Disable unit, end-to-end, and integration tests" 0) 26 | option(NO_CHECKS "Disable the check target (clang-tidy and clang-format" 0) 27 | option(NO_BENCHMARKS "Disable the benchmark" 0) 28 | 29 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 30 | 31 | set(BF_CONTACT "Quentin Deslandes ") 32 | 33 | if (NOT CMAKE_BUILD_TYPE) 34 | message(STATUS "Setting build type to 'release' as none was specified.") 35 | set(CMAKE_BUILD_TYPE "release" CACHE STRING "Choose the type of build." FORCE) 36 | else () 37 | set(BF_VALID_BUILD_TYPE "debug;release") 38 | string(TOLOWER ${CMAKE_BUILD_TYPE} BF_LOWER_BUILD_TYPE) 39 | list(FIND BF_VALID_BUILD_TYPE ${BF_LOWER_BUILD_TYPE} BF_BUILD_TYPE_INDEX) 40 | if (${BF_BUILD_TYPE_INDEX} EQUAL -1) 41 | message(FATAL_ERROR "CMAKE_BUILD_TYPE must be either 'debug' or 'release' (default), not '${CMAKE_BUILD_TYPE}'") 42 | endif () 43 | endif () 44 | 45 | # Ensure artefacts are moved to a common directory 46 | file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/output/include/bpfilter) 47 | file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/output/lib/pkgconfig) 48 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/lib) 49 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/lib) 50 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/sbin) 51 | 52 | add_library(bf_global_flags INTERFACE) 53 | target_compile_options(bf_global_flags 54 | INTERFACE 55 | -std=gnu17 -Wall -Wextra -fPIC 56 | $<$:-O0 -g3 -ggdb -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined> 57 | $<$:-O2> 58 | ) 59 | target_include_directories(bf_global_flags 60 | INTERFACE 61 | ${CMAKE_SOURCE_DIR}/src/external 62 | ) 63 | target_link_options(bf_global_flags 64 | INTERFACE 65 | $<$:-fsanitize=address -fsanitize=undefined> 66 | ) 67 | 68 | add_subdirectory(src/libbpfilter) 69 | add_subdirectory(src/bfcli) 70 | add_subdirectory(src/bpfilter) 71 | 72 | if (NOT ${NO_DOCS}) 73 | add_subdirectory(doc) 74 | endif () 75 | 76 | if (NOT ${NO_TESTS}) 77 | add_subdirectory(tests) 78 | endif () 79 | 80 | if (NOT ${NO_CHECKS}) 81 | add_subdirectory(tools/checks) 82 | endif () 83 | 84 | if (NOT ${NO_BENCHMARKS}) 85 | add_subdirectory(tools/benchmarks) 86 | endif () 87 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to bpfilter 2 | 3 | We want to make contributing to this project as easy and transparent as possible. 4 | 5 | ## Pull Requests 6 | 7 | We actively welcome your pull requests. 8 | 9 | 1. Fork the repo and create your branch from `main`. 10 | 2. If you've added code that should be tested, add tests. 11 | 3. If you've changed APIs, update the documentation. 12 | 4. Ensure the test suite passes. 13 | 5. If you haven't already, complete the Contributor License Agreement ("CLA"). 14 | 15 | ## Contributor License Agreement ("CLA") 16 | 17 | In order to accept your pull request, you need to submit a CLA. You only need to do this once to work on any of Meta's open source projects. 18 | 19 | Complete your CLA here: 20 | 21 | ## Issues 22 | 23 | We use GitHub issues to track public bugs. Please ensure your description is clear and has sufficient instructions to be able to reproduce the issue. 24 | 25 | Meta has a [bounty program](https://www.facebook.com/whitehat) for the safe disclosure of security bugs. In those cases, please go through the process outlined in that page and do not file a public issue. 26 | 27 | ## License 28 | 29 | By contributing to bpfilter, you agree that your contributions will be licensed under the LICENSE file in the root directory of this source tree. 30 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | # System calls 3 | - src/core/bpf.c 4 | # To test end-to-end using BPF_PROG_TEST_RUN 5 | - src/daemon/cgen/** 6 | # To test using integration tests 7 | - src/daemon/xlate/ipt/** 8 | - src/daemon/xlate/nft/** 9 | -------------------------------------------------------------------------------- /doc/Doxyfile.in: -------------------------------------------------------------------------------- 1 | @INCLUDE = "@CMAKE_CURRENT_BINARY_DIR@/Doxyfile.base" 2 | PROJECT_NAME = "@PROJECT_NAME@" 3 | PROJECT_BRIEF = An eBPF-based packet filtering framework 4 | OUTPUT_DIRECTORY = "@CMAKE_CURRENT_BINARY_DIR@" 5 | STRIP_FROM_PATH = "@CMAKE_SOURCE_DIR@/src" "@CMAKE_SOURCE_DIR@/tests" 6 | STRIP_FROM_INC_PATH = "@CMAKE_SOURCE_DIR@/src" "@CMAKE_SOURCE_DIR@/tests" 7 | OPTIMIZE_OUTPUT_FOR_C = YES 8 | AUTOLINK_SUPPORT = YES 9 | IDL_PROPERTY_SUPPORT = NO 10 | NUM_PROC_THREADS = 0 11 | 12 | #--------------------------------------------------------------------------- 13 | # Build related configuration options 14 | #--------------------------------------------------------------------------- 15 | EXTRACT_ALL = YES 16 | EXTRACT_STATIC = YES 17 | GENERATE_TODOLIST = YES 18 | GENERATE_TESTLIST = YES 19 | GENERATE_BUGLIST = YES 20 | GENERATE_DEPRECATEDLIST = YES 21 | 22 | #--------------------------------------------------------------------------- 23 | # Configuration options related to warning and progress messages 24 | #--------------------------------------------------------------------------- 25 | QUIET = YES 26 | WARN_AS_ERROR = FAIL_ON_WARNINGS_PRINT 27 | 28 | #--------------------------------------------------------------------------- 29 | # Configuration options related to the input files 30 | #--------------------------------------------------------------------------- 31 | INPUT = "@CMAKE_SOURCE_DIR@/src" "@CMAKE_SOURCE_DIR@/tests/harness" 32 | EXCLUDE = "@CMAKE_SOURCE_DIR@/src/external" 33 | EXCLUDE_SYMBOLS = bf_test_mock_declare 34 | FILE_PATTERNS = *.c \ 35 | *.h 36 | RECURSIVE = YES 37 | 38 | #--------------------------------------------------------------------------- 39 | # Configuration options related to the alphabetical class index 40 | #--------------------------------------------------------------------------- 41 | ALPHABETICAL_INDEX = NO 42 | 43 | #--------------------------------------------------------------------------- 44 | # Configuration options related to the output 45 | #--------------------------------------------------------------------------- 46 | GENERATE_HTML = NO 47 | GENERATE_LATEX = NO 48 | GENERATE_MAN = NO 49 | GENERATE_XML = YES 50 | GENERATE_DOCBOOK = NO 51 | GENERATE_AUTOGEN_DEF = NO 52 | GENERATE_SQLITE3 = NO 53 | GENERATE_PERLMOD = NO 54 | 55 | #--------------------------------------------------------------------------- 56 | # Configuration options related to the preprocessor 57 | #--------------------------------------------------------------------------- 58 | INCLUDE_PATH = "@CMAKE_SOURCE_DIR@/src" "@CMAKE_SOURCE_DIR@/tests" 59 | MACRO_EXPANSION = YES 60 | PREDEFINED = bf_aligned(x)= 61 | 62 | #--------------------------------------------------------------------------- 63 | # Configuration options related to diagram generator tools 64 | #--------------------------------------------------------------------------- 65 | HAVE_DOT = NO 66 | -------------------------------------------------------------------------------- /doc/_static/demo_dark.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facebook/bpfilter/23ee3bb87dc28db2358c5445460b495cde43ead3/doc/_static/demo_dark.gif -------------------------------------------------------------------------------- /doc/_static/demo_light.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facebook/bpfilter/23ee3bb87dc28db2358c5445460b495cde43ead3/doc/_static/demo_light.gif -------------------------------------------------------------------------------- /doc/_static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facebook/bpfilter/23ee3bb87dc28db2358c5445460b495cde43ead3/doc/_static/favicon.ico -------------------------------------------------------------------------------- /doc/_static/logo-dark-mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facebook/bpfilter/23ee3bb87dc28db2358c5445460b495cde43ead3/doc/_static/logo-dark-mode.png -------------------------------------------------------------------------------- /doc/_static/logo-light-mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facebook/bpfilter/23ee3bb87dc28db2358c5445460b495cde43ead3/doc/_static/logo-light-mode.png -------------------------------------------------------------------------------- /doc/conf.py.in: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 3 | 4 | # -- Project information ----------------------------------------------------- 5 | project = "@PROJECT_NAME@" 6 | copyright = "2024 Meta Platforms, Inc" 7 | author = "Quentin Deslandes" 8 | 9 | # -- General configuration --------------------------------------------------- 10 | templates_path = ["_templates"] 11 | exclude_patterns = [] 12 | 13 | extensions = ["breathe", "linuxdoc.rstFlatTable"] 14 | breathe_projects = {"@PROJECT_NAME@": "@CMAKE_CURRENT_BINARY_DIR@/xml"} 15 | breathe_default_project = "@PROJECT_NAME@" 16 | breathe_default_members = ("members", "private-members", "undoc-members") 17 | breathe_domain_by_extension = {"h": "c", "c": "c"} 18 | 19 | c_extra_keywords = [ 20 | "alignas", 21 | "alignof", 22 | "bool", 23 | "complex", 24 | "imaginary", 25 | "noreturn", 26 | "thread_local", 27 | ] 28 | 29 | breathe_show_define_initializer = ( 30 | False # Avoid showing badly formatted functions-like macros code. 31 | ) 32 | breathe_show_enumvalue_initializer = True 33 | breathe_show_include = True 34 | breathe_implementation_filename_extensions = [".c"] 35 | 36 | # -- Options for HTML output ------------------------------------------------- 37 | html_theme = "furo" 38 | html_static_path = ["_static"] 39 | html_favicon = "_static/favicon.ico" 40 | html_theme_options = { 41 | "light_logo": "logo-light-mode.png", 42 | "dark_logo": "logo-dark-mode.png", 43 | "sidebar_hide_name": True, 44 | } 45 | -------------------------------------------------------------------------------- /doc/covreport: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import argparse 5 | import shutil 6 | import sys 7 | import subprocess 8 | 9 | def warning(msg: str) -> None: 10 | print('\033[1;93m' + msg + '\033[0m') 11 | 12 | def error(msg: str) -> None: 13 | print('\033[1;31m' + msg + '\033[0m') 14 | 15 | def executable(path: str) -> str: 16 | if not shutil.which(path): 17 | error(f"executable path '{path}' is not found") 18 | raise argparse.ArgumentTypeError 19 | 20 | return path 21 | 22 | def main() -> None: 23 | parser = argparse.ArgumentParser( 24 | prog='covreport', 25 | description='Generate an HTML coverage report from an LCOV tracefile.') 26 | parser.add_argument('-g', '--genhtml', default="genhtml", type=executable, help="genhtml binary") 27 | parser.add_argument('-t', '--tracefile', help="Path to the LCOV tracefile") 28 | parser.add_argument('-o', '--output', required=True, help="Output directory") 29 | args = parser.parse_args() 30 | 31 | verbose = False 32 | if int(os.environ.get('VERBOSE', '0')): 33 | verbose = True 34 | 35 | if not os.path.exists(args.tracefile): 36 | warning(f"Tracefile '{args.tracefile}' not found, ignoring") 37 | sys.exit(0) 38 | 39 | cmd = [ 40 | args.genhtml, 41 | '--output-directory', args.output, 42 | args.tracefile 43 | ] 44 | 45 | output = subprocess.run(cmd, capture_output=True) 46 | if output.returncode != 0: 47 | print(output.stderr.decode("utf-8"), end="\n") 48 | error("failed to generate the coverage report") 49 | sys.exit(-1) 50 | elif verbose: 51 | print(output.stdout.decode("utf-8"), end="\n") 52 | 53 | 54 | if __name__ == '__main__': 55 | main() 56 | -------------------------------------------------------------------------------- /doc/developers/contributing.rst: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | If you want to start contributing to bpfilter, the best way to get to know the codebase would be to start with one of the ``@todo`` available in the code. Most of those tasks are small, self-contained, work trivial enough that they do not deserve their GitHub issue. 5 | 6 | Once you know your way around the structure of the project, feel free to continue with the ``@todo``, or jump on a bigger issue in the `GitHub issues tracker `_. 7 | 8 | You are welcome to reach out to qde@naccy.de if you need help, or have any question! 9 | 10 | 11 | To do 12 | ----- 13 | 14 | * Enforce ``clang-format`` and ``clang-tidy`` on all source files. 15 | * Remove the RPM ``x86_64`` macro `workaround `_ from the Fedora ``bpfilter.spec``. 16 | * Gate the documentation generate in Fedora's ``bpfilter.spec`` with a ``bcond``. 17 | * Add support for CMake 4.0 and ``ninja``. 18 | * Handle extra characters in the lexer (currently, any non-matched token will be printed to ``stdout``). 19 | * Add support for missing matcher operators (e.g. ``meta.l4_proto not``). 20 | * Add a Fedora 43 build in the CI. 21 | 22 | 23 | From the code 24 | ~~~~~~~~~~~~~ 25 | 26 | .. doxygenpage:: todo 27 | -------------------------------------------------------------------------------- /doc/developers/generation.rst: -------------------------------------------------------------------------------- 1 | Programs generation 2 | =================== 3 | 4 | Bytecode generation 5 | ------------------- 6 | 7 | .. doxygenfile:: program.h 8 | 9 | ELF stubs 10 | --------- 11 | 12 | .. doxygenfile:: elfstub.h 13 | 14 | Switch-cases 15 | ------------ 16 | 17 | .. doxygenfile:: swich.h 18 | 19 | Error handling 20 | -------------- 21 | 22 | .. doxygenfile:: jmp.h 23 | 24 | Printing debug messages 25 | ----------------------- 26 | 27 | .. doxygenfile:: printer.h 28 | -------------------------------------------------------------------------------- /doc/developers/modules/bpfilter/bpfilter.rst: -------------------------------------------------------------------------------- 1 | bpfilter 2 | ======== 3 | 4 | .. doxygenfile:: ctx.h 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | :caption: bpfilter 9 | 10 | xlate/index 11 | -------------------------------------------------------------------------------- /doc/developers/modules/bpfilter/xlate/index.rst: -------------------------------------------------------------------------------- 1 | xlate 2 | ===== 3 | 4 | ``xlate`` (``src/bpfilter/xlate``) is the translation layer between a source format (e.g. sent by ``iptables``) to ``bpfilter``'s internal format. That translation is performed by components called "front-end". 5 | 6 | See the documentation for the following front-ends: 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | 11 | ipt 12 | nft 13 | -------------------------------------------------------------------------------- /doc/developers/modules/bpfilter/xlate/ipt.rst: -------------------------------------------------------------------------------- 1 | ``ipt`` 2 | ============ 3 | 4 | .. doxygenfile:: xlate/ipt/ipt.c 5 | -------------------------------------------------------------------------------- /doc/developers/modules/bpfilter/xlate/nft.rst: -------------------------------------------------------------------------------- 1 | ``nft`` 2 | ======= 3 | 4 | Netlink messages 5 | ---------------- 6 | 7 | .. doxygenfile:: nfmsg.h 8 | 9 | Messages groups 10 | --------------- 11 | 12 | .. doxygenfile:: nfgroup.h 13 | -------------------------------------------------------------------------------- /doc/developers/modules/index.rst: -------------------------------------------------------------------------------- 1 | Modules 2 | ======= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Modules 7 | 8 | libbpfilter/libbpfilter 9 | bpfilter/bpfilter 10 | 11 | ``bpfilter`` is composed of multiple modules depending on each other. Splitting the project in different modules allows for the source code to be efficiently reused, be it for ``bfcli``, ``bpfilter``'s daemon, or ``libbpfilter``: 12 | 13 | - ``core``: core definitions used by the daemon, ``bfcli``, and ``libbpfilter``. 14 | - ``bpfilter``: daemon logic, including translation of the front-end (client) data into ``bpfilter``'s internal format, and the BPF bytecode generation logic. 15 | - ``bfcli``: generic client to communicate with the daemon. 16 | - ``libbpfilter``: static and shared library to communicate with the daemon. 17 | - ``external``: non-``bpfilter`` code, imported into the project to provide consistent external definitions. 18 | -------------------------------------------------------------------------------- /doc/developers/modules/libbpfilter/libbpfilter.rst: -------------------------------------------------------------------------------- 1 | libbpfilter 2 | =========== 3 | 4 | .. doxygenfile:: bpfilter/bpfilter.h 5 | 6 | 7 | Namespaces 8 | ---------- 9 | 10 | .. doxygenfile:: ns.h 11 | :sections: briefdescription detaileddescription typedef struct innerclass enum var define func 12 | 13 | 14 | Pack 15 | ---- 16 | 17 | .. doxygenfile:: bpfilter/pack.h 18 | 19 | 20 | Rule 21 | ---- 22 | 23 | .. doxygenfile:: bpfilter/rule.h 24 | -------------------------------------------------------------------------------- /doc/developers/packets_processing.rst: -------------------------------------------------------------------------------- 1 | Packets processing 2 | ================== 3 | 4 | Runtime 5 | ------- 6 | 7 | .. doxygenfile:: cgen/runtime.h 8 | 9 | .. doxygenfile:: bpfilter/runtime.h 10 | 11 | 12 | Matchers 13 | -------- 14 | 15 | .. doxygenfile:: bpfilter/matcher.h 16 | -------------------------------------------------------------------------------- /doc/external/benchmarks/index.rst: -------------------------------------------------------------------------------- 1 | Benchmarks 2 | ========== 3 | 4 | There are no benchmarks (yet). 5 | -------------------------------------------------------------------------------- /doc/external/coverage/index.rst: -------------------------------------------------------------------------------- 1 | Coverage 2 | ======== 3 | 4 | There are no coverage reports (yet). 5 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | 2 | .. toctree:: 3 | :hidden: 4 | :maxdepth: 2 5 | :caption: Users 6 | 7 | Overview 8 | usage/index 9 | 10 | .. toctree:: 11 | :hidden: 12 | :maxdepth: 2 13 | :caption: Developers 14 | 15 | developers/build 16 | developers/contributing 17 | developers/style 18 | developers/modules/index 19 | developers/packets_processing 20 | developers/generation 21 | developers/tests 22 | 23 | .. toctree:: 24 | :hidden: 25 | :caption: External 26 | 27 | GitHub repository 28 | external/benchmarks/index 29 | external/coverage/index 30 | 31 | | 32 | | 33 | 34 | .. raw:: html 35 | 36 |
An eBPF-based packet filtering framework.
37 | 38 | | 39 | 40 | **bpfilter** transforms how you control network traffic by leveraging the power of eBPF technology. This framework elegantly translates filtering rules into optimized BPF programs, bringing unparalleled performance and flexibility to your packet filtering needs. 41 | 42 | | 43 | 44 | .. image:: _static/demo_light.gif 45 | :class: only-light 46 | :align: center 47 | :width: 600 48 | 49 | .. image:: _static/demo_dark.gif 50 | :class: only-dark 51 | :align: center 52 | :width: 600 53 | 54 | | 55 | 56 | .. raw:: html 57 | 58 |
Key features
59 | 60 | - **High performance**: utilizes eBPF's near-native performance capabilities 61 | - **Flexible integration**: use the custom ``iptables`` integration or **bpfilter**'s ``bfcli`` command line for extended functionalities 62 | - **Low overhead**: minimal resource consumption with maximized efficiency 63 | - **Developer-friendly**: clean architecture with clear separation of components 64 | 65 | **bpfilter** combines three components: a CLI that allows users to define filtering rules in human-readable text, a daemon that converts these rules into efficient BPF programs, and a library that facilitates seamless communication between applications and the filtering subsystem. 66 | 67 | Want to know more about **bpfilter**? Check the :doc:`user's guide `, the :doc:`developer documentation `, or watch our talk at `Scale `_! 68 | -------------------------------------------------------------------------------- /doc/usage/daemon.rst: -------------------------------------------------------------------------------- 1 | The daemon 2 | ========== 3 | 4 | The ``bpfilter`` daemon is responsible for creating the BPF program corresponding to the user-provided filtering rules. The daemon will also load and manage the BPF programs on the system. 5 | 6 | It is possible to customize the daemon's behavior using the following command-line flags: 7 | 8 | - ``-t``, ``--transient``: if used, ``bpfilter`` won't pin any BPF program or map, and no data will be serialized to the filesystem. Hence, as soon as the daemon is stopped, the loaded BPF programs and maps will be removed from the system. 9 | - ``--no-cli``: disable ``bfcli`` support. 10 | - ``--no-nftables``: disable ``nftables`` support. 11 | - ``--no-iptables``: disable ``iptables`` support. 12 | - ``--with-bpf-token``: if set, the daemon will associate a BPF token to every ``bpf()`` system call. This is required when the daemon runs in user namespaces. The daemon will create the token from the bpffs mounted at ``--bpffs-path``. The user is responsible for configuring the file system, so a token can be created. Only supported for kernel v6.9+, if the current kernel doesn't support BPF token, the daemon will stop with a non-zero exit code. 13 | - ``--bpffs-path``: use a custom BPF filesystem directory. By default, bpfilter will pin the BPF objects in a ``bpfilter`` directory in ``/sys/fs/bpf``, this option will move the ``bpfilter`` folder into a different directory. The path provided must be a directory on a BPF filesystem. 14 | - ``-v=VERBOSE_FLAG``, ``--verbose=VERBOSE_FLAG``: enable verbose logs for ``VERBOSE_FLAG``. Currently, 3 verbose flags are supported: 15 | 16 | - ``debug``: enable all the debug logs in the application. 17 | - ``bpf``: insert log messages into the BPF programs to log failed kernel function calls. Those messages can be printed with ``bpftool prog tracelog`` or ``cat /sys/kernel/debug/tracing/trace_pipe``. 18 | - ``bytecode``: dump a program's bytecode before loading it. 19 | 20 | - ``--usage``: print a short usage message. 21 | - ``-?``, ``--help``: print the help message. 22 | 23 | 24 | Runtime data 25 | ------------ 26 | 27 | ``bpfilter`` runtime data is located in two different directories: 28 | 29 | - ``/run/bpfilter``: runtime context. Contains the socket used to communicate with the daemon, and the serialized data (except in ``--transient`` mode). 30 | - ``/sys/fs/bpf/bpfilter``: directory used to pin the BPF objects (except in ``--transient`` mode) so they persist across restarts of the daemon. 31 | 32 | .. warning:: 33 | If ``bpfilter`` fails to restore its state after restarting, its data can be cleanup up by removing both those directories. Doing so will remove all your filtering rules. 34 | 35 | Namespaces 36 | ---------- 37 | 38 | ``bpfilter`` supports the network and mount Linux namespaces. The daemon will automatically switch to the client's namespace before attaching a BPF program, so it is guaranteed to have the same view of the system as the client. 39 | 40 | The network namespace will define the available interface indexes to attach the XDP and TC chains, as well as the interface indexes to filter packets on. 41 | 42 | The mount namespace is required to ensure the daemon will attach a CGroup chain to the proper CGroup. 43 | -------------------------------------------------------------------------------- /doc/usage/iptables.rst: -------------------------------------------------------------------------------- 1 | ``iptables`` 2 | ============ 3 | 4 | A custom ``iptables`` binary is required to use with ``bpfilter``, but it can be built directly from the ``bpfilter`` source tree: ``make iptables``. Once you have build ``iptables``, you can force it to communicate with ``bpfilter`` instead of the kernel using ``--bpf``. 5 | 6 | The following filters are supported: 7 | 8 | - Source IPv4 address and mask. 9 | - Destination IPv4 address and mask. 10 | - Layer 4 protocol. 11 | 12 | Filtering rules can be defined for any table, and ``ACCEPT`` and ``DROP`` action are supported. The ruleset can also be fetched back from ``bpfilter``. For example: 13 | 14 | .. code:: shell 15 | 16 | # Start bpfilter daemon 17 | $ sudo bpfilter 18 | 19 | # Add a new rule to block ping requests 20 | $ sudo iptables -I INPUT --bpf -p icmp -j DROP 21 | 22 | # Show the rules and counters after the host was pinged 23 | $ sudo iptables --bpf -nv -L 24 | Chain INPUT (policy ACCEPT 327 packets, 42757 bytes) 25 | pkts bytes target prot opt in out source destination 26 | 2 196 DROP icmp -- * * 0.0.0.0/0 0.0.0.0/0 27 | 28 | Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) 29 | pkts bytes target prot opt in out source destination 30 | 31 | Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) 32 | pkts bytes target prot opt in out source destination 33 | -------------------------------------------------------------------------------- /doc/usage/nftables.rst: -------------------------------------------------------------------------------- 1 | ``nftables`` 2 | ============ 3 | 4 | .. warning:: 5 | 6 | ``nftables`` support is currently broken. Work is in progress to fix it. 7 | -------------------------------------------------------------------------------- /src/bfcli/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 3 | 4 | find_program(BISON_BIN bison REQUIRED) 5 | find_program(FLEX_BIN flex REQUIRED) 6 | 7 | file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/generated) 8 | file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include) 9 | 10 | add_custom_command( 11 | COMMAND 12 | ${BISON_BIN} 13 | --debug 14 | --defines=${CMAKE_CURRENT_BINARY_DIR}/include/parser.h 15 | -o ${CMAKE_CURRENT_BINARY_DIR}/generated/parser.c 16 | ${CMAKE_CURRENT_SOURCE_DIR}/parser.y 17 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/parser.y 18 | OUTPUT 19 | ${CMAKE_CURRENT_BINARY_DIR}/include/parser.h 20 | ${CMAKE_CURRENT_BINARY_DIR}/generated/parser.c 21 | COMMENT "Generate the Bison parser" 22 | ) 23 | 24 | add_custom_target(bfcli_parser 25 | DEPENDS 26 | ${CMAKE_CURRENT_BINARY_DIR}/include/parser.h 27 | ${CMAKE_CURRENT_BINARY_DIR}/generated/parser.c 28 | ) 29 | 30 | add_custom_command( 31 | COMMAND 32 | ${FLEX_BIN} 33 | --header-file=${CMAKE_CURRENT_BINARY_DIR}/include/lexer.h 34 | -o ${CMAKE_CURRENT_BINARY_DIR}/generated/lexer.c 35 | ${CMAKE_CURRENT_SOURCE_DIR}/lexer.l 36 | DEPENDS 37 | ${CMAKE_CURRENT_SOURCE_DIR}/lexer.l 38 | ${CMAKE_CURRENT_BINARY_DIR}/include/parser.h 39 | OUTPUT 40 | ${CMAKE_CURRENT_BINARY_DIR}/include/lexer.h 41 | ${CMAKE_CURRENT_BINARY_DIR}/generated/lexer.c 42 | COMMENT "Generate the Flex lexer" 43 | ) 44 | 45 | add_custom_target(bfcli_lexer 46 | DEPENDS 47 | ${CMAKE_CURRENT_BINARY_DIR}/include/lexer.h 48 | ${CMAKE_CURRENT_BINARY_DIR}/generated/lexer.c 49 | ) 50 | 51 | add_executable(bfcli 52 | ${CMAKE_CURRENT_SOURCE_DIR}/main.c 53 | ${CMAKE_CURRENT_SOURCE_DIR}/chain.h ${CMAKE_CURRENT_SOURCE_DIR}/chain.c 54 | ${CMAKE_CURRENT_SOURCE_DIR}/helper.h ${CMAKE_CURRENT_SOURCE_DIR}/helper.c 55 | ${CMAKE_CURRENT_SOURCE_DIR}/opts.h ${CMAKE_CURRENT_SOURCE_DIR}/opts.c 56 | ${CMAKE_CURRENT_SOURCE_DIR}/print.h ${CMAKE_CURRENT_SOURCE_DIR}/print.c 57 | ${CMAKE_CURRENT_SOURCE_DIR}/ruleset.h ${CMAKE_CURRENT_SOURCE_DIR}/ruleset.c 58 | ${CMAKE_CURRENT_BINARY_DIR}/generated/parser.c ${CMAKE_CURRENT_BINARY_DIR}/include/parser.h 59 | ${CMAKE_CURRENT_BINARY_DIR}/generated/lexer.c ${CMAKE_CURRENT_BINARY_DIR}/include/lexer.h 60 | ) 61 | 62 | target_compile_definitions(bfcli 63 | PRIVATE 64 | BF_CONTACT="${BF_CONTACT}" 65 | "YY_READ_BUF_SIZE=(yy_read_buf_size)" 66 | ) 67 | 68 | target_include_directories(bfcli 69 | PRIVATE 70 | ${CMAKE_CURRENT_SOURCE_DIR} 71 | ${CMAKE_CURRENT_BINARY_DIR}/include 72 | ) 73 | 74 | target_link_libraries(bfcli 75 | PRIVATE 76 | bf_global_flags 77 | libbpfilter 78 | ) 79 | 80 | install(TARGETS bfcli 81 | DESTINATION ${CMAKE_INSTALL_SBINDIR} 82 | ) 83 | -------------------------------------------------------------------------------- /src/bfcli/chain.h: -------------------------------------------------------------------------------- 1 | 2 | /* SPDX-License-Identifier: GPL-2.0-only */ 3 | /* 4 | * Copyright (c) 2025 Meta Platforms, Inc. and affiliates. 5 | */ 6 | 7 | #pragma once 8 | 9 | struct bfc_opts; 10 | 11 | int bfc_chain_set(const struct bfc_opts *opts); 12 | int bfc_chain_get(const struct bfc_opts *opts); 13 | int bfc_chain_logs(const struct bfc_opts *opts); 14 | int bfc_chain_load(const struct bfc_opts *opts); 15 | int bfc_chain_attach(const struct bfc_opts *opts); 16 | int bfc_chain_update(const struct bfc_opts *opts); 17 | int bfc_chain_flush(const struct bfc_opts *opts); 18 | -------------------------------------------------------------------------------- /src/bfcli/helper.c: -------------------------------------------------------------------------------- 1 | 2 | /* SPDX-License-Identifier: GPL-2.0-only */ 3 | /* 4 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 5 | */ 6 | 7 | #include "helper.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include "lexer.h" 16 | #include "parser.h" 17 | 18 | // To speed up parsing very large rulesets, we can increase YY_READ_BUF_SIZE 19 | int yy_read_buf_size; 20 | 21 | #define _BF_LEX_MIN_BUF_POW 14 22 | #define _BF_LEX_MAX_BUF_POW 20 23 | 24 | static int _bf_compute_lexer_buf_size(size_t len) 25 | { 26 | int val = _BF_LEX_MIN_BUF_POW; 27 | 28 | if (len) { 29 | val = (int)sizeof(len) * 8 - __builtin_clzl(len); 30 | val = bf_min(bf_max(val - 3, _BF_LEX_MIN_BUF_POW), _BF_LEX_MAX_BUF_POW); 31 | } 32 | 33 | return 1 << val; 34 | } 35 | 36 | int bfc_parse_file(const char *file, struct bfc_ruleset *ruleset) 37 | { 38 | FILE *rules; 39 | struct stat stt; 40 | int r; 41 | 42 | if (stat(file, &stt) == -1) 43 | return bf_err_r(errno, "failed to stat file %s:", file); 44 | 45 | yy_read_buf_size = _bf_compute_lexer_buf_size(stt.st_size); 46 | bf_dbg("yy_read_buf_size choosen is %d", yy_read_buf_size); 47 | 48 | rules = fopen(file, "r"); 49 | if (!rules) 50 | return bf_err_r(errno, "failed to read rules from %s:", file); 51 | 52 | yyin = rules; 53 | 54 | r = yyparse(ruleset); 55 | if (r == 1) 56 | r = bf_err_r(-EINVAL, "failed to parse rules, invalid syntax"); 57 | else if (r == 2) 58 | r = bf_err_r(-ENOMEM, "failed to parse rules, not enough memory"); 59 | 60 | return r; 61 | } 62 | 63 | int bfc_parse_str(const char *str, struct bfc_ruleset *ruleset) 64 | { 65 | YY_BUFFER_STATE buffer; 66 | unsigned long str_size; 67 | int r; 68 | 69 | str_size = strlen(str); 70 | yy_read_buf_size = _bf_compute_lexer_buf_size(str_size); 71 | bf_dbg("yy_read_buf_size choosen is %d", yy_read_buf_size); 72 | 73 | buffer = yy_scan_string(str); 74 | 75 | r = yyparse(ruleset); 76 | if (r == 1) 77 | r = bf_err_r(-EINVAL, "failed to parse rules, invalid syntax"); 78 | else if (r == 2) 79 | r = bf_err_r(-ENOMEM, "failed to parse rules, not enough memory"); 80 | 81 | yy_delete_buffer(buffer); 82 | 83 | return r; 84 | } 85 | -------------------------------------------------------------------------------- /src/bfcli/helper.h: -------------------------------------------------------------------------------- 1 | 2 | /* SPDX-License-Identifier: GPL-2.0-only */ 3 | /* 4 | * Copyright (c) 2025 Meta Platforms, Inc. and affiliates. 5 | */ 6 | 7 | #pragma once 8 | 9 | struct bfc_ruleset; 10 | 11 | int bfc_parse_file(const char *file, struct bfc_ruleset *ruleset); 12 | int bfc_parse_str(const char *str, struct bfc_ruleset *ruleset); 13 | -------------------------------------------------------------------------------- /src/bfcli/main.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "chain.h" 26 | #include "helper.h" 27 | #include "opts.h" 28 | #include "print.h" 29 | #include "ruleset.h" 30 | 31 | static void _bfc_print_version(FILE *stream, struct argp_state *state) 32 | { 33 | UNUSED(state); 34 | 35 | (void)fprintf(stream, "bfcli version %s, libbpfilter version %s\n", 36 | BF_VERSION, bf_version()); 37 | } 38 | 39 | int main(int argc, char *argv[]) 40 | { 41 | _clean_bfc_opts_ struct bfc_opts opts = bfc_opts_default(); 42 | int r; 43 | 44 | argp_program_version_hook = &_bfc_print_version; 45 | argp_program_bug_address = BF_CONTACT; 46 | 47 | bf_logger_setup(); 48 | 49 | r = bfc_opts_parse(&opts, argc, argv); 50 | if (r < 0) 51 | return r; 52 | 53 | return opts.cmd->cb(&opts); 54 | } 55 | 56 | void yyerror(struct bfc_ruleset *ruleset, const char *fmt, ...) 57 | { 58 | UNUSED(ruleset); 59 | 60 | va_list args; 61 | 62 | va_start(args, fmt); 63 | bf_err_v(fmt, args); 64 | va_end(args); 65 | } 66 | -------------------------------------------------------------------------------- /src/bfcli/opts.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | /** 11 | * @file opts.h 12 | * 13 | * bfcli commands are constructed as `bfcli OBJECT ACTION [OPTIONS...]`, with 14 | * `OBJECT` the type of bpfilter object to manipulate, and `ACTION` the action 15 | * to apply to the object. 16 | * 17 | * This file provides the mechanism to define and parse command line object for 18 | * all the existing commands supported by bfcli. 19 | * 20 | * Two `argp.h` parsers are required to parse bfcli commands. The first parser 21 | * will validate the `OBJECT` and `ACTION`. The second parser is constructed 22 | * based on `OBJECT` and `ACTION` to only parse the options supported by this 23 | * specific command. 24 | */ 25 | 26 | #define _clean_bfc_opts_ __attribute__((__cleanup__(bfc_opts_clean))) 27 | 28 | /** 29 | * @brief Type of objects supported by bfcli 30 | */ 31 | enum bfc_object 32 | { 33 | BFC_OBJECT_RULESET, 34 | BFC_OBJECT_CHAIN, 35 | _BFC_OBJECT_MAX, 36 | }; 37 | 38 | /** 39 | * @brief Type of actions supported by bfcli 40 | */ 41 | enum bfc_action 42 | { 43 | BFC_ACTION_SET, 44 | BFC_ACTION_GET, 45 | BFC_ACTION_LOGS, 46 | BFC_ACTION_LOAD, 47 | BFC_ACTION_ATTACH, 48 | BFC_ACTION_UPDATE, 49 | BFC_ACTION_FLUSH, 50 | _BFC_ACTION_MAX, 51 | }; 52 | 53 | struct bfc_opts_cmd; 54 | 55 | /** 56 | * @brief Command line options configured for bfcli 57 | */ 58 | struct bfc_opts 59 | { 60 | const struct bfc_opts_cmd *cmd; 61 | 62 | enum bfc_object object; 63 | enum bfc_action action; 64 | 65 | uint32_t set_opts; 66 | 67 | const char *from_str; 68 | const char *from_file; 69 | const char *name; 70 | struct bf_hookopts hookopts; 71 | }; 72 | 73 | struct bfc_opts_cmd 74 | { 75 | enum bfc_object object; 76 | enum bfc_action action; 77 | const char *name; 78 | uint32_t valid_opts; 79 | uint32_t required_opts; 80 | const char *doc; 81 | int (*cb)(const struct bfc_opts *opts); 82 | }; 83 | 84 | /** 85 | * @brief Initialize a `bfc_opts` object to default values. 86 | */ 87 | #define bfc_opts_default() \ 88 | {.object = _BFC_OBJECT_MAX, .action = _BFC_ACTION_MAX}; 89 | 90 | void bfc_opts_clean(struct bfc_opts *opts); 91 | int bfc_opts_parse(struct bfc_opts *opts, int argc, char **argv); 92 | -------------------------------------------------------------------------------- /src/bfcli/print.h: -------------------------------------------------------------------------------- 1 | 2 | /* SPDX-License-Identifier: GPL-2.0-only */ 3 | /* 4 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | struct bf_chain; 15 | struct bf_hookopts; 16 | 17 | /** 18 | * Print a single chain. 19 | * 20 | * @param chain Chain to print. Can't be NULL. 21 | * @param hookopts Chain's hook options. If NULL, it is assumed the chain is not 22 | * attached to a hook. 23 | * @param counters List of counters for the chain. This function expects the 24 | * first to entries in the list to be the policy and error counters. 25 | * Then, every rule should have an entry in the list in the order they 26 | * are defined, even if the rule doesn't have counters enabled. 27 | */ 28 | void bfc_chain_dump(struct bf_chain *chain, struct bf_hookopts *hookopts, 29 | bf_list *counters); 30 | 31 | /** 32 | * Print ruleset information and counters to the console. 33 | * 34 | * @param chains List of chains to print. 35 | * @param hookopts List of hookoptions to print. 36 | * @param counters List of counters to print. 37 | */ 38 | int bfc_ruleset_dump(bf_list *chains, bf_list *hookopts, bf_list *counters); 39 | 40 | /** 41 | * @brief Print a logged packet published by a rule. 42 | * 43 | * @pre 44 | * - `log != NULL` 45 | * 46 | * @param log Logged data. 47 | */ 48 | void bfc_print_log(const struct bf_log *log); 49 | -------------------------------------------------------------------------------- /src/bfcli/ruleset.c: -------------------------------------------------------------------------------- 1 | 2 | /* SPDX-License-Identifier: GPL-2.0-only */ 3 | /* 4 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 5 | */ 6 | 7 | #include "ruleset.h" 8 | 9 | #include 10 | 11 | #include "helper.h" 12 | #include "opts.h" 13 | #include "print.h" 14 | 15 | void bfc_ruleset_clean(struct bfc_ruleset *ruleset) 16 | { 17 | bf_assert(ruleset); 18 | 19 | bf_list_clean(&ruleset->chains); 20 | bf_list_clean(&ruleset->hookopts); 21 | bf_list_clean(&ruleset->sets); 22 | } 23 | 24 | int bfc_ruleset_set(const struct bfc_opts *opts) 25 | { 26 | _clean_bfc_ruleset_ struct bfc_ruleset ruleset = bfc_ruleset_default(); 27 | int r; 28 | 29 | if (opts->from_file) 30 | r = bfc_parse_file(opts->from_file, &ruleset); 31 | else 32 | r = bfc_parse_str(opts->from_str, &ruleset); 33 | if (r) 34 | return bf_err_r(r, "failed to parse ruleset"); 35 | 36 | r = bf_ruleset_set(&ruleset.chains, &ruleset.hookopts); 37 | if (r) 38 | bf_err_r(r, "failed to set ruleset"); 39 | 40 | return r; 41 | } 42 | 43 | int bfc_ruleset_get(const struct bfc_opts *opts) 44 | { 45 | UNUSED(opts); 46 | 47 | _clean_bf_list_ bf_list chains = bf_list_default(bf_chain_free, NULL); 48 | _clean_bf_list_ bf_list hookopts = bf_list_default(bf_hookopts_free, NULL); 49 | _clean_bf_list_ bf_list counters = bf_list_default(bf_list_free, NULL); 50 | int r; 51 | 52 | r = bf_ruleset_get(&chains, &hookopts, &counters); 53 | if (r < 0) 54 | return bf_err_r(r, "failed to request ruleset"); 55 | 56 | r = bfc_ruleset_dump(&chains, &hookopts, &counters); 57 | if (r) 58 | return bf_err_r(r, "failed to dump ruleset"); 59 | 60 | return 0; 61 | } 62 | 63 | int bfc_ruleset_flush(const struct bfc_opts *opts) 64 | { 65 | UNUSED(opts); 66 | 67 | return bf_ruleset_flush(); 68 | } 69 | -------------------------------------------------------------------------------- /src/bfcli/ruleset.h: -------------------------------------------------------------------------------- 1 | 2 | /* SPDX-License-Identifier: GPL-2.0-only */ 3 | /* 4 | * Copyright (c) 2025 Meta Platforms, Inc. and affiliates. 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define bfc_ruleset_default() \ 15 | { \ 16 | .chains = bf_list_default(bf_chain_free, bf_chain_pack), \ 17 | .sets = bf_list_default(bf_set_free, bf_set_pack), \ 18 | .hookopts = bf_list_default(bf_hookopts_free, bf_hookopts_pack), \ 19 | } 20 | 21 | #define _clean_bfc_ruleset_ __attribute__((__cleanup__(bfc_ruleset_clean))) 22 | 23 | struct bfc_ruleset 24 | { 25 | bf_list chains; 26 | bf_list sets; 27 | bf_list hookopts; 28 | }; 29 | 30 | struct bfc_opts; 31 | 32 | void bfc_ruleset_clean(struct bfc_ruleset *ruleset); 33 | 34 | int bfc_ruleset_set(const struct bfc_opts *opts); 35 | int bfc_ruleset_get(const struct bfc_opts *opts); 36 | int bfc_ruleset_flush(const struct bfc_opts *opts); 37 | -------------------------------------------------------------------------------- /src/bpfilter/bpf/log.bpf.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "cgen/runtime.h" 13 | 14 | __u8 bf_log(struct bf_runtime *ctx, __u32 rule_idx, __u8 headers, 15 | __u16 l3_proto, __u8 l4_proto) 16 | { 17 | struct bf_log *log; 18 | 19 | log = bpf_ringbuf_reserve(ctx->log_map, sizeof(struct bf_log), 0); 20 | if (!log) { 21 | bpf_printk("failed to reserve %d bytes in ringbuf", 22 | sizeof(struct bf_log)); 23 | return 1; 24 | } 25 | 26 | log->ts = bpf_ktime_get_ns(); 27 | log->rule_id = rule_idx; 28 | log->pkt_size = ctx->pkt_size; 29 | log->req_headers = headers; 30 | log->headers = 0; 31 | log->l3_proto = bpf_ntohs(l3_proto); 32 | log->l4_proto = l4_proto; 33 | 34 | if (headers & (1 << BF_PKTHDR_LINK) && ctx->l2_hdr && 35 | ctx->l2_size <= BF_L2_SLICE_LEN) { 36 | bpf_probe_read_kernel(log->l2hdr, ctx->l2_size, ctx->l2_hdr); 37 | log->headers |= (1 << BF_PKTHDR_LINK); 38 | } 39 | 40 | if (headers & (1 << BF_PKTHDR_INTERNET) && ctx->l3_hdr && 41 | ctx->l3_size <= BF_L3_SLICE_LEN) { 42 | bpf_probe_read_kernel(log->l3hdr, ctx->l3_size, ctx->l3_hdr); 43 | log->headers |= (1 << BF_PKTHDR_INTERNET); 44 | } 45 | 46 | if (headers & (1 << BF_PKTHDR_TRANSPORT) && ctx->l4_hdr && 47 | ctx->l4_size <= BF_L4_SLICE_LEN) { 48 | bpf_probe_read_kernel(log->l4hdr, ctx->l4_size, ctx->l4_hdr); 49 | log->headers |= (1 << BF_PKTHDR_TRANSPORT); 50 | } 51 | 52 | bpf_ringbuf_submit(log, 0); 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /src/bpfilter/bpf/parse_ipv6_eh.bpf.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "cgen/runtime.h" 14 | 15 | #define BF_IPV6_EXT_MAX_CHAIN 6 16 | 17 | __u8 bf_parse_ipv6(struct bf_runtime *ctx) 18 | { 19 | struct ipv6hdr *ip6hdr = ctx->l3_hdr; 20 | __u8 next_hdr_type = ip6hdr->nexthdr; 21 | 22 | ctx->l4_offset = ctx->l3_offset + sizeof(struct ipv6hdr); 23 | 24 | for (int i = 0; i < BF_IPV6_EXT_MAX_CHAIN; ++i) { 25 | struct ipv6_opt_hdr _ext; 26 | struct ipv6_opt_hdr *ext = 27 | bpf_dynptr_slice(&ctx->dynptr, ctx->l4_offset, &_ext, sizeof(_ext)); 28 | if (!ext) 29 | return 0; 30 | 31 | switch (next_hdr_type) { 32 | case IPPROTO_HOPOPTS: 33 | case IPPROTO_DSTOPTS: 34 | case IPPROTO_ROUTING: 35 | case IPPROTO_MH: 36 | next_hdr_type = ext->nexthdr; 37 | ctx->l4_offset += (ext->hdrlen + 1) * 8; 38 | break; 39 | case IPPROTO_AH: 40 | next_hdr_type = ext->nexthdr; 41 | ctx->l4_offset += (ext->hdrlen + 2) * 4; 42 | break; 43 | case IPPROTO_FRAGMENT: 44 | next_hdr_type = ext->nexthdr; 45 | ctx->l4_offset += ext->hdrlen + 8; 46 | break; 47 | default: 48 | return next_hdr_type; 49 | } 50 | } 51 | 52 | return next_hdr_type; 53 | } 54 | -------------------------------------------------------------------------------- /src/bpfilter/bpf/parse_ipv6_nh.bpf.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "cgen/runtime.h" 14 | 15 | #define BF_IPV6_EXT_MAX_CHAIN 6 16 | 17 | #define EH_COMMON_OFFSET 1 18 | #define EH_COMMON_SHIFT 3 19 | #define EH_AH_OFFSET 2 20 | #define EH_AH_SHIFT 2 21 | #define EH_FRAG_OFFSET 8 22 | #define EH_FRAG_SHIFT 0 23 | 24 | /* The following defines are the same of src/bpfilter/cgen/matcher/ip6.c */ 25 | #define BF_IPV6_EH_HOPOPTS(x) ((x) << 0) 26 | #define BF_IPV6_EH_ROUTING(x) ((x) << 1) 27 | #define BF_IPV6_EH_FRAGMENT(x) ((x) << 2) 28 | #define BF_IPV6_EH_AH(x) ((x) << 3) 29 | #define BF_IPV6_EH_DSTOPTS(x) ((x) << 4) 30 | #define BF_IPV6_EH_MH(x) ((x) << 5) 31 | 32 | __u8 bf_parse_ipv6(struct bf_runtime *ctx) 33 | { 34 | struct ipv6hdr *ip6hdr = ctx->l3_hdr; 35 | __u8 next_hdr_type = ip6hdr->nexthdr; 36 | ctx->ipv6_eh = 0; 37 | ctx->l4_offset = ctx->l3_offset + sizeof(struct ipv6hdr); 38 | 39 | for (int i = 0; i < BF_IPV6_EXT_MAX_CHAIN; ++i) { 40 | struct ipv6_opt_hdr _ext; 41 | struct ipv6_opt_hdr *ext = 42 | bpf_dynptr_slice(&ctx->dynptr, ctx->l4_offset, &_ext, sizeof(_ext)); 43 | 44 | if (!ext) 45 | break; 46 | 47 | switch (next_hdr_type) { 48 | case IPPROTO_HOPOPTS: 49 | case IPPROTO_ROUTING: 50 | case IPPROTO_DSTOPTS: 51 | case IPPROTO_FRAGMENT: 52 | case IPPROTO_AH: 53 | case IPPROTO_MH: 54 | break; 55 | default: 56 | return next_hdr_type; 57 | } 58 | 59 | __u8 offset; 60 | __u8 shift; 61 | ctx->ipv6_eh |= 62 | (BF_IPV6_EH_HOPOPTS(next_hdr_type == IPPROTO_HOPOPTS) | 63 | BF_IPV6_EH_ROUTING(next_hdr_type == IPPROTO_ROUTING) | 64 | BF_IPV6_EH_FRAGMENT(next_hdr_type == IPPROTO_FRAGMENT) | 65 | BF_IPV6_EH_AH(next_hdr_type == IPPROTO_AH) | 66 | BF_IPV6_EH_DSTOPTS(next_hdr_type == IPPROTO_DSTOPTS) | 67 | BF_IPV6_EH_MH(next_hdr_type == IPPROTO_MH)); 68 | 69 | if (next_hdr_type == IPPROTO_AH) { 70 | offset = EH_AH_OFFSET; 71 | shift = EH_AH_SHIFT; 72 | } else if (next_hdr_type == IPPROTO_FRAGMENT) { 73 | offset = EH_FRAG_OFFSET; 74 | shift = EH_FRAG_SHIFT; 75 | } else { 76 | offset = EH_COMMON_OFFSET; 77 | shift = EH_COMMON_SHIFT; 78 | } 79 | 80 | ctx->l4_offset += (ext->hdrlen + offset) << shift; 81 | next_hdr_type = ext->nexthdr; 82 | } 83 | 84 | return next_hdr_type; 85 | } 86 | -------------------------------------------------------------------------------- /src/bpfilter/bpf/update_counters.bpf.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "cgen/runtime.h" 14 | 15 | struct bf_counter 16 | { 17 | __u64 packets; 18 | __u64 bytes; 19 | }; 20 | 21 | __u8 bf_update_counters(struct bf_runtime *ctx, void *map, __u64 key) 22 | { 23 | struct bf_counter *counter; 24 | 25 | counter = bpf_map_lookup_elem(map, &key); 26 | if (!counter) { 27 | bpf_printk("failed to fetch the rule's counters"); 28 | return 1; 29 | } 30 | 31 | counter->packets += 1; 32 | counter->bytes += ctx->pkt_size; 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /src/bpfilter/bpfilter.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=BPF-based packet filtering framework 3 | 4 | [Service] 5 | ExecStart=/usr/sbin/bpfilter --no-nftables --no-iptables 6 | Restart=on-failure 7 | 8 | [Install] 9 | WantedBy=multi-user.target 10 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/cgroup.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | extern const struct bf_flavor_ops bf_flavor_ops_cgroup; 11 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/dump.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | /** 9 | * @file dump.h 10 | * 11 | * @ref bf_program_dump_bytecode is defined to pretty-print the BPF bytecode 12 | * from a @ref bf_program structure. The logic used here is inspired by 13 | * bpftool's dumper (https://github.com/libbpf/bpftool) with all the heavy 14 | * lifting performed by Linux @c kernel/bpf/disasm.c . 15 | */ 16 | 17 | struct bf_program; 18 | 19 | void bf_program_dump_bytecode(const struct bf_program *program); 20 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/fixup.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "fixup.h" 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | int bf_fixup_new(struct bf_fixup **fixup, enum bf_fixup_type type, 15 | size_t insn_offset, const union bf_fixup_attr *attr) 16 | { 17 | bf_assert(fixup); 18 | 19 | *fixup = calloc(1, sizeof(struct bf_fixup)); 20 | if (!fixup) 21 | return -ENOMEM; 22 | 23 | (*fixup)->type = type; 24 | (*fixup)->insn = insn_offset; 25 | 26 | if (attr) 27 | (*fixup)->attr = *attr; 28 | 29 | return 0; 30 | } 31 | 32 | void bf_fixup_free(struct bf_fixup **fixup) 33 | { 34 | bf_assert(fixup); 35 | 36 | if (!*fixup) 37 | return; 38 | 39 | freep((void *)fixup); 40 | } 41 | 42 | static const char *_bf_fixup_type_to_str(enum bf_fixup_type type) 43 | { 44 | static const char *str[] = { 45 | [BF_FIXUP_TYPE_JMP_NEXT_RULE] = "BF_FIXUP_TYPE_JMP_NEXT_RULE", 46 | [BF_FIXUP_TYPE_COUNTERS_MAP_FD] = "BF_FIXUP_TYPE_COUNTERS_MAP_FD", 47 | [BF_FIXUP_TYPE_PRINTER_MAP_FD] = "BF_FIXUP_TYPE_PRINTER_MAP_FD", 48 | [BF_FIXUP_TYPE_SET_MAP_FD] = "BF_FIXUP_TYPE_SET_MAP_FD", 49 | [BF_FIXUP_ELFSTUB_CALL] = "BF_FIXUP_ELFSTUB_CALL", 50 | }; 51 | 52 | bf_assert(0 <= type && type < _BF_FIXUP_TYPE_MAX); 53 | static_assert(ARRAY_SIZE(str) == _BF_FIXUP_TYPE_MAX); 54 | 55 | return str[type]; 56 | } 57 | 58 | void bf_fixup_dump(const struct bf_fixup *fixup, prefix_t *prefix) 59 | { 60 | bf_assert(fixup); 61 | bf_assert(prefix); 62 | 63 | DUMP(prefix, "struct bf_fixup at %p", fixup); 64 | 65 | bf_dump_prefix_push(prefix); 66 | 67 | DUMP(prefix, "type: %s", _bf_fixup_type_to_str(fixup->type)); 68 | DUMP(prefix, "insn: %zu", fixup->insn); 69 | 70 | switch (fixup->type) { 71 | case BF_FIXUP_TYPE_JMP_NEXT_RULE: 72 | case BF_FIXUP_TYPE_COUNTERS_MAP_FD: 73 | case BF_FIXUP_TYPE_PRINTER_MAP_FD: 74 | // No specific value to dump 75 | break; 76 | case BF_FIXUP_TYPE_SET_MAP_FD: 77 | DUMP(prefix, "set_index: %lu", fixup->attr.set_index); 78 | break; 79 | default: 80 | DUMP(prefix, "unsupported bf_fixup_type: %d", fixup->type); 81 | break; 82 | }; 83 | 84 | bf_dump_prefix_pop(prefix); 85 | } 86 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/fixup.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include "cgen/elfstub.h" 13 | 14 | /** 15 | * Field to fixup in a @c bpf_insn structure. 16 | */ 17 | enum bf_fixup_insn 18 | { 19 | BF_FIXUP_INSN_OFF, 20 | BF_FIXUP_INSN_IMM, 21 | _BF_FIXUP_INSN_MAX, 22 | }; 23 | 24 | /** 25 | * Type of the fixup. 26 | * 27 | * Defines how a fixup should be processed. 28 | */ 29 | enum bf_fixup_type 30 | { 31 | /// Jump to the beginning of the next rule. 32 | BF_FIXUP_TYPE_JMP_NEXT_RULE, 33 | /// Set the counters map file descriptor in the @c BPF_LD_MAP_FD instruction. 34 | BF_FIXUP_TYPE_COUNTERS_MAP_FD, 35 | /// Set the printer map file descriptor in the @c BPF_LD_MAP_FD instruction. 36 | BF_FIXUP_TYPE_PRINTER_MAP_FD, 37 | /// Set the log map file descriptor in the @c BPF_LD_MAP_FD instruction. 38 | BF_FIXUP_TYPE_LOG_MAP_FD, 39 | /// Set a set map file descriptor in the @c BPF_LD_MAP_FD instruction. 40 | BF_FIXUP_TYPE_SET_MAP_FD, 41 | /// Call an ELF stub. 42 | BF_FIXUP_ELFSTUB_CALL, 43 | _BF_FIXUP_TYPE_MAX 44 | }; 45 | 46 | union bf_fixup_attr 47 | { 48 | size_t set_index; 49 | enum bf_elfstub_id elfstub_id; 50 | }; 51 | 52 | struct bf_fixup 53 | { 54 | enum bf_fixup_type type; 55 | size_t insn; 56 | union bf_fixup_attr attr; 57 | }; 58 | 59 | #define _free_bf_fixup_ __attribute__((cleanup(bf_fixup_free))) 60 | 61 | int bf_fixup_new(struct bf_fixup **fixup, enum bf_fixup_type type, 62 | size_t insn_offset, const union bf_fixup_attr *attr); 63 | void bf_fixup_free(struct bf_fixup **fixup); 64 | void bf_fixup_dump(const struct bf_fixup *fixup, prefix_t *prefix); 65 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/jmp.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "cgen/jmp.h" 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include "cgen/program.h" 17 | 18 | void bf_jmpctx_cleanup(struct bf_jmpctx *ctx) 19 | { 20 | if (ctx->program) { 21 | struct bpf_insn *insn = &ctx->program->img[ctx->insn_idx]; 22 | size_t off = ctx->program->img_size - ctx->insn_idx - 1U; 23 | 24 | if (off > SHRT_MAX) 25 | bf_warn("jump offset overflow: %ld", off); 26 | 27 | insn->off = (int16_t)off; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/jmp.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | /** 11 | * @file jmp.h 12 | * 13 | * @ref bf_jmpctx is a helper structure to manage jump instructions in the 14 | * program. A @ref bf_jmpctx will insert a new jump instruction in the BPF 15 | * program and update its jump offset when the @ref bf_jmpctx is deleted. 16 | * 17 | * Example: 18 | * @code{.c} 19 | * // Within a function body 20 | * { 21 | * _clean_bf_jmpctx_ struct bf_jmpctx ctx = 22 | * bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_2, 0, 0)); 23 | * 24 | * EMIT(program, 25 | * BPF_MOV64_IMM(BPF_REG_0, program->runtime.ops->get_verdict( 26 | * BF_VERDICT_ACCEPT))); 27 | * EMIT(program, BPF_EXIT_INSN()); 28 | * } 29 | * @endcode 30 | * 31 | * @c ctx is a variable local to the scope, marked with @c _clean_bf_jmpctx_ . 32 | * The second argument to @c bf_jmpctx_get is the jump instruction to emit, with 33 | * the correct condition. When the scope is exited, the jump instruction is 34 | * automatically updated to point to the first instruction outside of the scope. 35 | * 36 | * Hence, all the instructions emitted within the scope will be executed if the 37 | * condition is not met. If the condition is met, then the program execution 38 | * will skip the instructions defined in the scope and continue. 39 | */ 40 | 41 | struct bf_program; 42 | 43 | /** 44 | * Cleanup attribute for a @ref bf_jmpctx variable. 45 | */ 46 | #define _clean_bf_jmpctx_ __attribute__((cleanup(bf_jmpctx_cleanup))) 47 | 48 | #define bf_jmpctx_default() {.program = NULL} 49 | 50 | /** 51 | * Create a new @ref bf_jmpctx variable. 52 | * 53 | * @param program The program to emit the jump instruction to. It must be 54 | * non-NULL. 55 | * @param insn The jump instruction to emit. 56 | * @return A new @ref bf_jmpctx variable. 57 | */ 58 | #define bf_jmpctx_get(program, insn) \ 59 | ({ \ 60 | size_t __idx = (program)->img_size; \ 61 | int __r = bf_program_emit((program), (insn)); \ 62 | if (__r < 0) \ 63 | return __r; \ 64 | (struct bf_jmpctx) {.program = (program), .insn_idx = __idx}; \ 65 | }) 66 | 67 | /** 68 | * A helper structure to manage jump instructions in the program. 69 | * 70 | * @var bf_jmpctx::program 71 | * The program to emit the jump instruction to. 72 | * @var bf_jmpctx::insn_idx 73 | * The index of the jump instruction in the program's image. 74 | */ 75 | struct bf_jmpctx 76 | { 77 | struct bf_program *program; 78 | size_t insn_idx; 79 | }; 80 | 81 | /** 82 | * Cleanup function for @ref bf_jmpctx. 83 | * 84 | * @param ctx The @ref bf_jmpctx variable to clean up. 85 | */ 86 | void bf_jmpctx_cleanup(struct bf_jmpctx *ctx); 87 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/matcher/icmp.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | struct bf_matcher; 9 | struct bf_program; 10 | 11 | int bf_matcher_generate_icmp(struct bf_program *program, 12 | const struct bf_matcher *matcher); 13 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/matcher/ip4.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | struct bf_matcher; 9 | struct bf_program; 10 | 11 | /** 12 | * Generate the bytecode for the BF_MATCHER_IP4_* matcher types. 13 | * 14 | * @param program Program to generate the bytecode into. Can't be NULL. 15 | * @param matcher Matcher to generate the bytecode for. Can't be NULL. 16 | * @return 0 on success, negative errno value on failure. 17 | */ 18 | int bf_matcher_generate_ip4(struct bf_program *program, 19 | const struct bf_matcher *matcher); 20 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/matcher/ip6.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | struct bf_matcher; 9 | struct bf_program; 10 | 11 | /** 12 | * Generate the bytecode for the BF_MATCHER_IP6_* matcher types. 13 | * 14 | * @param program Program to generate the bytecode into. Can't be NULL. 15 | * @param matcher Matcher to generate the bytecode for. Can't be NULL. 16 | * @return 0 on success, negative errno value on failure. 17 | */ 18 | int bf_matcher_generate_ip6(struct bf_program *program, 19 | const struct bf_matcher *matcher); 20 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/matcher/meta.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | struct bf_matcher; 9 | struct bf_program; 10 | 11 | int bf_matcher_generate_meta(struct bf_program *program, 12 | const struct bf_matcher *matcher); 13 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/matcher/set.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | struct bf_matcher; 9 | struct bf_program; 10 | 11 | int bf_matcher_generate_set(struct bf_program *program, 12 | const struct bf_matcher *matcher); 13 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/matcher/tcp.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | struct bf_matcher; 9 | struct bf_program; 10 | 11 | int bf_matcher_generate_tcp(struct bf_program *program, 12 | const struct bf_matcher *matcher); 13 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/matcher/udp.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "cgen/matcher/udp.h" 7 | 8 | #include 9 | #include 10 | #include // NOLINT 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | #include "cgen/program.h" 22 | #include "filter.h" 23 | 24 | static int _bf_matcher_generate_udp_port(struct bf_program *program, 25 | const struct bf_matcher *matcher) 26 | { 27 | uint16_t *port = (uint16_t *)bf_matcher_payload(matcher); 28 | size_t offset = bf_matcher_get_type(matcher) == BF_MATCHER_UDP_SPORT ? 29 | offsetof(struct udphdr, source) : 30 | offsetof(struct udphdr, dest); 31 | 32 | EMIT(program, BPF_LDX_MEM(BPF_H, BPF_REG_1, BPF_REG_6, offset)); 33 | 34 | switch (bf_matcher_get_op(matcher)) { 35 | case BF_MATCHER_EQ: 36 | EMIT_FIXUP_JMP_NEXT_RULE(program, 37 | BPF_JMP_IMM(BPF_JNE, BPF_REG_1, *port, 0)); 38 | break; 39 | case BF_MATCHER_NE: 40 | EMIT_FIXUP_JMP_NEXT_RULE(program, 41 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, *port, 0)); 42 | break; 43 | case BF_MATCHER_RANGE: 44 | /* Convert the big-endian value stored in the packet into a 45 | * little-endian value for x86 and arm before comparing it to the 46 | * reference value. This is a JLT/JGT comparison, we need to have the 47 | * MSB where the machine expects then. */ 48 | EMIT(program, BPF_BSWAP(BPF_REG_1, 16)); 49 | EMIT_FIXUP_JMP_NEXT_RULE(program, 50 | BPF_JMP_IMM(BPF_JLT, BPF_REG_1, port[0], 0)); 51 | EMIT_FIXUP_JMP_NEXT_RULE(program, 52 | BPF_JMP_IMM(BPF_JGT, BPF_REG_1, port[1], 0)); 53 | break; 54 | default: 55 | return bf_err_r(-EINVAL, "unknown matcher operator '%s' (%d)", 56 | bf_matcher_op_to_str(bf_matcher_get_op(matcher)), 57 | bf_matcher_get_op(matcher)); 58 | } 59 | 60 | return 0; 61 | } 62 | 63 | int bf_matcher_generate_udp(struct bf_program *program, 64 | const struct bf_matcher *matcher) 65 | { 66 | int r; 67 | 68 | EMIT_FIXUP_JMP_NEXT_RULE(program, 69 | BPF_JMP_IMM(BPF_JNE, BPF_REG_8, IPPROTO_UDP, 0)); 70 | EMIT(program, 71 | BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l4_hdr))); 72 | 73 | switch (bf_matcher_get_type(matcher)) { 74 | case BF_MATCHER_UDP_SPORT: 75 | case BF_MATCHER_UDP_DPORT: 76 | r = _bf_matcher_generate_udp_port(program, matcher); 77 | break; 78 | default: 79 | return bf_err_r(-EINVAL, "unknown matcher type %d", 80 | bf_matcher_get_type(matcher)); 81 | }; 82 | 83 | return r; 84 | } 85 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/matcher/udp.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | struct bf_matcher; 9 | struct bf_program; 10 | 11 | int bf_matcher_generate_udp(struct bf_program *program, 12 | const struct bf_matcher *matcher); 13 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/nf.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | extern const struct bf_flavor_ops bf_flavor_ops_nf; 11 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/tc.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | extern const struct bf_flavor_ops bf_flavor_ops_tc; 11 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/xdp.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "cgen/program.h" 17 | #include "cgen/stub.h" 18 | #include "filter.h" 19 | 20 | /** 21 | * Generate XDP program prologue. 22 | * 23 | * @warning @ref bf_stub_parse_l2_ethhdr will check for L3 protocol. If L3 is 24 | * not IPv4, the program will be terminated. 25 | * 26 | * @param program Program to generate the prologue for. Must not be NULL. 27 | * @return 0 on success, or negative errno value on error. 28 | */ 29 | static int _bf_xdp_gen_inline_prologue(struct bf_program *program) 30 | { 31 | int r; 32 | 33 | bf_assert(program); 34 | 35 | // Calculate the packet size and store it into the runtime context 36 | EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 37 | offsetof(struct xdp_md, data))); 38 | EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, 39 | offsetof(struct xdp_md, data_end))); 40 | EMIT(program, BPF_ALU64_REG(BPF_SUB, BPF_REG_3, BPF_REG_2)); 41 | EMIT(program, 42 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_3, BF_PROG_CTX_OFF(pkt_size))); 43 | 44 | // Store the ingress ifindex into the runtime context 45 | EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 46 | offsetof(struct xdp_md, ingress_ifindex))); 47 | EMIT(program, 48 | BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, BF_PROG_CTX_OFF(ifindex))); 49 | 50 | r = bf_stub_make_ctx_xdp_dynptr(program, BPF_REG_1); 51 | if (r) 52 | return r; 53 | 54 | r = bf_stub_parse_l2_ethhdr(program); 55 | if (r) 56 | return r; 57 | 58 | r = bf_stub_parse_l3_hdr(program); 59 | if (r) 60 | return r; 61 | 62 | r = bf_stub_parse_l4_hdr(program); 63 | if (r) 64 | return r; 65 | 66 | return 0; 67 | } 68 | 69 | static int _bf_xdp_gen_inline_epilogue(struct bf_program *program) 70 | { 71 | UNUSED(program); 72 | 73 | return 0; 74 | } 75 | 76 | static int _bf_xdp_get_verdict(enum bf_verdict verdict) 77 | { 78 | bf_assert(0 <= verdict && verdict < _BF_TERMINAL_VERDICT_MAX); 79 | 80 | static const int verdicts[] = { 81 | [BF_VERDICT_ACCEPT] = XDP_PASS, 82 | [BF_VERDICT_DROP] = XDP_DROP, 83 | }; 84 | 85 | static_assert(ARRAY_SIZE(verdicts) == _BF_TERMINAL_VERDICT_MAX); 86 | 87 | return verdicts[verdict]; 88 | } 89 | 90 | const struct bf_flavor_ops bf_flavor_ops_xdp = { 91 | .gen_inline_prologue = _bf_xdp_gen_inline_prologue, 92 | .gen_inline_epilogue = _bf_xdp_gen_inline_epilogue, 93 | .get_verdict = _bf_xdp_get_verdict, 94 | }; 95 | -------------------------------------------------------------------------------- /src/bpfilter/cgen/xdp.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | extern const struct bf_flavor_ops bf_flavor_ops_xdp; 11 | -------------------------------------------------------------------------------- /src/bpfilter/opts.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include 11 | 12 | enum bf_verbose 13 | { 14 | BF_VERBOSE_DEBUG, 15 | BF_VERBOSE_BPF, 16 | BF_VERBOSE_BYTECODE, 17 | _BF_VERBOSE_MAX, 18 | }; 19 | 20 | int bf_opts_init(int argc, char *argv[]); 21 | bool bf_opts_transient(void); 22 | bool bf_opts_persist(void); 23 | bool bf_opts_is_front_enabled(enum bf_front front); 24 | bool bf_opts_with_bpf_token(void); 25 | const char *bf_opts_bpffs_path(void); 26 | bool bf_opts_is_verbose(enum bf_verbose opt); 27 | void bf_opts_set_verbose(enum bf_verbose opt); 28 | -------------------------------------------------------------------------------- /src/bpfilter/xlate/front.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "xlate/front.h" 7 | 8 | #include 9 | #include 10 | 11 | extern const struct bf_front_ops ipt_front; 12 | extern const struct bf_front_ops nft_front; 13 | extern const struct bf_front_ops cli_front; 14 | 15 | const struct bf_front_ops *bf_front_ops_get(enum bf_front front) 16 | { 17 | bf_assert(0 <= front && front < _BF_FRONT_MAX); 18 | 19 | static const struct bf_front_ops *fronts[] = { 20 | [BF_FRONT_IPT] = &ipt_front, 21 | [BF_FRONT_NFT] = &nft_front, 22 | [BF_FRONT_CLI] = &cli_front, 23 | }; 24 | 25 | // We need to have an entry for each value in `bf_front` enumeration. 26 | static_assert(ARRAY_SIZE(fronts) == _BF_FRONT_MAX, 27 | "missing entries in fronts array"); 28 | 29 | return fronts[front]; 30 | } 31 | -------------------------------------------------------------------------------- /src/bpfilter/xlate/front.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | struct bf_request; 12 | struct bf_response; 13 | 14 | /** 15 | * @struct bf_front_ops 16 | * 17 | * @todo Front should not implement a callback if it's not needed. E.g. 18 | * `BF_FRONT_CLI` defines empty `pack` and `unpack` callbacks. 19 | */ 20 | struct bf_front_ops 21 | { 22 | /// Initialize the front. 23 | int (*setup)(void); 24 | 25 | /// Teardown the front and free resources. 26 | int (*teardown)(void); 27 | 28 | /// Handle an incoming request. 29 | int (*request_handler)(const struct bf_request *request, 30 | struct bf_response **response); 31 | 32 | /// Serialize the front's data to restore it later. 33 | int (*pack)(bf_wpack_t *pack); 34 | 35 | /// Restore the front's data from serialized data. 36 | int (*unpack)(bf_rpack_node_t node); 37 | }; 38 | 39 | /** 40 | * Retrieve the @ref bf_front_ops structure for a specific front. 41 | * 42 | * @param front Front to get the @ref bf_front_ops for. 43 | * @return 44 | */ 45 | const struct bf_front_ops *bf_front_ops_get(enum bf_front front); 46 | -------------------------------------------------------------------------------- /src/bpfilter/xlate/ipt/dump.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | struct ipt_replace; 11 | 12 | /** 13 | * Dump content of bpfilter_ipt_replace structure. 14 | * 15 | * @param ipt iptable's ipt_replace structure. Must be non-NULL. 16 | * @param prefix Prefix to print on each line. 17 | */ 18 | void bf_ipt_dump_replace(const struct ipt_replace *ipt, prefix_t *prefix); 19 | -------------------------------------------------------------------------------- /src/bpfilter/xlate/ipt/helpers.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | /** 11 | * Check whether @p hook is enabled in @p ipt_replace structure. 12 | * 13 | * @param replace @p ipt_replace structure. 14 | * @param hook Hook to test. 15 | * @return 0 if @p hook is not enabled, any value otherwise. 16 | */ 17 | #define ipt_is_hook_enabled(replace, hook) \ 18 | ((replace)->valid_hooks & BF_FLAG(hook)) 19 | 20 | /** 21 | * Get @p ipt_entry's match at @p offset. 22 | * 23 | * @param entry @p ipt_entry structure the get the match from. Must 24 | * be non-NULL. 25 | * @param offset Offset of the match to get. 26 | * @return Pointer to the match at @p offset in @p ipt_entry. 27 | */ 28 | #define ipt_get_match(entry, offset) \ 29 | ((struct ipt_entry_match *)((void *)(entry) + (offset))) 30 | 31 | /** 32 | * Get @p ipt_entry's target. 33 | * 34 | * @param entry @p ipt_entry structure to get the target from. 35 | * @return Pointer to the target assigned to @p ipt_entry. 36 | */ 37 | #define ipt_get_target(entry) \ 38 | (struct ipt_entry_target *)((void *)(entry) + (entry)->target_offset) 39 | 40 | /** 41 | * Get first rule for @p hook in @p ipt_replace. 42 | * 43 | * @param replace @p ipt_replace structure. 44 | * @param hook Hook to get the first rule for. 45 | * @return Pointer to the first rule for @p hook. 46 | */ 47 | #define ipt_get_first_rule(replace, hook) \ 48 | (struct ipt_entry *)((void *)(replace)->entries + \ 49 | (replace)->hook_entry[hook]) 50 | 51 | /** 52 | * Get rule following @p ipt_entry. 53 | * 54 | * @param entry @p ipt_entry structure. 55 | * @return Pointer to the next rule. 56 | */ 57 | #define ipt_get_next_rule(entry) \ 58 | (struct ipt_entry *)((void *)(entry) + (entry)->next_offset) 59 | 60 | /** 61 | * Get last rule for @p hook in @p ipt_replace. 62 | * 63 | * @param replace @p ipt_replace structure. 64 | * @param hook Hook to get the last rule for. 65 | * @return Pointer to the last rule for @p hook. 66 | */ 67 | #define ipt_get_last_rule(replace, hook) \ 68 | (struct ipt_entry *)((void *)(replace)->entries + \ 69 | (replace)->underflow[hook]) 70 | -------------------------------------------------------------------------------- /src/bpfilter/xlate/nft/nft.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "xlate/front.h" 14 | 15 | static int _bf_nft_setup(void) 16 | { 17 | return 0; 18 | } 19 | 20 | static int _bf_nft_teardown(void) 21 | { 22 | return 0; 23 | } 24 | 25 | static int _bf_nft_pack(bf_wpack_t *pack) 26 | { 27 | UNUSED(pack); 28 | 29 | return 0; 30 | } 31 | 32 | static int _bf_nft_unpack(bf_rpack_node_t node) 33 | { 34 | UNUSED(node); 35 | 36 | return 0; 37 | } 38 | 39 | static int _bf_nft_request_handler(const struct bf_request *request, 40 | struct bf_response **response) 41 | { 42 | UNUSED(request); 43 | 44 | bf_assert(response); 45 | 46 | return bf_response_new_failure(response, -ENOTSUP); 47 | } 48 | 49 | const struct bf_front_ops nft_front = { 50 | .setup = _bf_nft_setup, 51 | .teardown = _bf_nft_teardown, 52 | .request_handler = _bf_nft_request_handler, 53 | .pack = _bf_nft_pack, 54 | .unpack = _bf_nft_unpack, 55 | }; 56 | -------------------------------------------------------------------------------- /src/external/include/asm-generic/bitsperlong.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef __ASM_GENERIC_BITS_PER_LONG 3 | #define __ASM_GENERIC_BITS_PER_LONG 4 | 5 | #ifndef __BITS_PER_LONG 6 | /* 7 | * In order to keep safe and avoid regression, only unify uapi 8 | * bitsperlong.h for some archs which are using newer toolchains 9 | * that have the definitions of __CHAR_BIT__ and __SIZEOF_LONG__. 10 | * See the following link for more info: 11 | * https://lore.kernel.org/linux-arch/b9624545-2c80-49a1-ac3c-39264a591f7b@app.fastmail.com/ 12 | */ 13 | #if defined(__CHAR_BIT__) && defined(__SIZEOF_LONG__) 14 | #define __BITS_PER_LONG (__CHAR_BIT__ * __SIZEOF_LONG__) 15 | #else 16 | /* 17 | * There seems to be no way of detecting this automatically from user 18 | * space, so 64 bit architectures should override this in their 19 | * bitsperlong.h. In particular, an architecture that supports 20 | * both 32 and 64 bit user space must not rely on CONFIG_64BIT 21 | * to decide it, but rather check a compiler provided macro. 22 | */ 23 | #define __BITS_PER_LONG 32 24 | #endif 25 | #endif 26 | 27 | #ifndef __BITS_PER_LONG_LONG 28 | #define __BITS_PER_LONG_LONG 64 29 | #endif 30 | 31 | #endif /* __ASM_GENERIC_BITS_PER_LONG */ 32 | -------------------------------------------------------------------------------- /src/external/include/asm-generic/errno-base.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _ASM_GENERIC_ERRNO_BASE_H 3 | #define _ASM_GENERIC_ERRNO_BASE_H 4 | 5 | #define EPERM 1 /* Operation not permitted */ 6 | #define ENOENT 2 /* No such file or directory */ 7 | #define ESRCH 3 /* No such process */ 8 | #define EINTR 4 /* Interrupted system call */ 9 | #define EIO 5 /* I/O error */ 10 | #define ENXIO 6 /* No such device or address */ 11 | #define E2BIG 7 /* Argument list too long */ 12 | #define ENOEXEC 8 /* Exec format error */ 13 | #define EBADF 9 /* Bad file number */ 14 | #define ECHILD 10 /* No child processes */ 15 | #define EAGAIN 11 /* Try again */ 16 | #define ENOMEM 12 /* Out of memory */ 17 | #define EACCES 13 /* Permission denied */ 18 | #define EFAULT 14 /* Bad address */ 19 | #define ENOTBLK 15 /* Block device required */ 20 | #define EBUSY 16 /* Device or resource busy */ 21 | #define EEXIST 17 /* File exists */ 22 | #define EXDEV 18 /* Cross-device link */ 23 | #define ENODEV 19 /* No such device */ 24 | #define ENOTDIR 20 /* Not a directory */ 25 | #define EISDIR 21 /* Is a directory */ 26 | #define EINVAL 22 /* Invalid argument */ 27 | #define ENFILE 23 /* File table overflow */ 28 | #define EMFILE 24 /* Too many open files */ 29 | #define ENOTTY 25 /* Not a typewriter */ 30 | #define ETXTBSY 26 /* Text file busy */ 31 | #define EFBIG 27 /* File too large */ 32 | #define ENOSPC 28 /* No space left on device */ 33 | #define ESPIPE 29 /* Illegal seek */ 34 | #define EROFS 30 /* Read-only file system */ 35 | #define EMLINK 31 /* Too many links */ 36 | #define EPIPE 32 /* Broken pipe */ 37 | #define EDOM 33 /* Math argument out of domain of func */ 38 | #define ERANGE 34 /* Math result not representable */ 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/external/include/asm-generic/int-ll64.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* 3 | * asm-generic/int-ll64.h 4 | * 5 | * Integer declarations for architectures which use "long long" 6 | * for 64-bit types. 7 | */ 8 | 9 | #ifndef _ASM_GENERIC_INT_LL64_H 10 | #define _ASM_GENERIC_INT_LL64_H 11 | 12 | #include 13 | 14 | #ifndef __ASSEMBLY__ 15 | /* 16 | * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the 17 | * header files exported to user space 18 | */ 19 | 20 | typedef __signed__ char __s8; 21 | typedef unsigned char __u8; 22 | 23 | typedef __signed__ short __s16; 24 | typedef unsigned short __u16; 25 | 26 | typedef __signed__ int __s32; 27 | typedef unsigned int __u32; 28 | 29 | #ifdef __GNUC__ 30 | __extension__ typedef __signed__ long long __s64; 31 | __extension__ typedef unsigned long long __u64; 32 | #else 33 | typedef __signed__ long long __s64; 34 | typedef unsigned long long __u64; 35 | #endif 36 | 37 | #endif /* __ASSEMBLY__ */ 38 | 39 | 40 | #endif /* _ASM_GENERIC_INT_LL64_H */ 41 | -------------------------------------------------------------------------------- /src/external/include/asm-generic/posix_types.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef __ASM_GENERIC_POSIX_TYPES_H 3 | #define __ASM_GENERIC_POSIX_TYPES_H 4 | 5 | #include 6 | /* 7 | * This file is generally used by user-level software, so you need to 8 | * be a little careful about namespace pollution etc. 9 | * 10 | * First the types that are often defined in different ways across 11 | * architectures, so that you can override them. 12 | */ 13 | 14 | #ifndef __kernel_long_t 15 | typedef long __kernel_long_t; 16 | typedef unsigned long __kernel_ulong_t; 17 | #endif 18 | 19 | #ifndef __kernel_ino_t 20 | typedef __kernel_ulong_t __kernel_ino_t; 21 | #endif 22 | 23 | #ifndef __kernel_mode_t 24 | typedef unsigned int __kernel_mode_t; 25 | #endif 26 | 27 | #ifndef __kernel_pid_t 28 | typedef int __kernel_pid_t; 29 | #endif 30 | 31 | #ifndef __kernel_ipc_pid_t 32 | typedef int __kernel_ipc_pid_t; 33 | #endif 34 | 35 | #ifndef __kernel_uid_t 36 | typedef unsigned int __kernel_uid_t; 37 | typedef unsigned int __kernel_gid_t; 38 | #endif 39 | 40 | #ifndef __kernel_suseconds_t 41 | typedef __kernel_long_t __kernel_suseconds_t; 42 | #endif 43 | 44 | #ifndef __kernel_daddr_t 45 | typedef int __kernel_daddr_t; 46 | #endif 47 | 48 | #ifndef __kernel_uid32_t 49 | typedef unsigned int __kernel_uid32_t; 50 | typedef unsigned int __kernel_gid32_t; 51 | #endif 52 | 53 | #ifndef __kernel_old_uid_t 54 | typedef __kernel_uid_t __kernel_old_uid_t; 55 | typedef __kernel_gid_t __kernel_old_gid_t; 56 | #endif 57 | 58 | #ifndef __kernel_old_dev_t 59 | typedef unsigned int __kernel_old_dev_t; 60 | #endif 61 | 62 | /* 63 | * Most 32 bit architectures use "unsigned int" size_t, 64 | * and all 64 bit architectures use "unsigned long" size_t. 65 | */ 66 | #ifndef __kernel_size_t 67 | #if __BITS_PER_LONG != 64 68 | typedef unsigned int __kernel_size_t; 69 | typedef int __kernel_ssize_t; 70 | typedef int __kernel_ptrdiff_t; 71 | #else 72 | typedef __kernel_ulong_t __kernel_size_t; 73 | typedef __kernel_long_t __kernel_ssize_t; 74 | typedef __kernel_long_t __kernel_ptrdiff_t; 75 | #endif 76 | #endif 77 | 78 | #ifndef __kernel_fsid_t 79 | typedef struct { 80 | int val[2]; 81 | } __kernel_fsid_t; 82 | #endif 83 | 84 | /* 85 | * anything below here should be completely generic 86 | */ 87 | typedef __kernel_long_t __kernel_off_t; 88 | typedef long long __kernel_loff_t; 89 | typedef __kernel_long_t __kernel_old_time_t; 90 | typedef __kernel_long_t __kernel_time_t; 91 | typedef long long __kernel_time64_t; 92 | typedef __kernel_long_t __kernel_clock_t; 93 | typedef int __kernel_timer_t; 94 | typedef int __kernel_clockid_t; 95 | typedef char * __kernel_caddr_t; 96 | typedef unsigned short __kernel_uid16_t; 97 | typedef unsigned short __kernel_gid16_t; 98 | 99 | #endif /* __ASM_GENERIC_POSIX_TYPES_H */ 100 | -------------------------------------------------------------------------------- /src/external/include/asm-generic/sockios.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef __ASM_GENERIC_SOCKIOS_H 3 | #define __ASM_GENERIC_SOCKIOS_H 4 | 5 | /* Socket-level I/O control calls. */ 6 | #define FIOSETOWN 0x8901 7 | #define SIOCSPGRP 0x8902 8 | #define FIOGETOWN 0x8903 9 | #define SIOCGPGRP 0x8904 10 | #define SIOCATMARK 0x8905 11 | #define SIOCGSTAMP_OLD 0x8906 /* Get stamp (timeval) */ 12 | #define SIOCGSTAMPNS_OLD 0x8907 /* Get stamp (timespec) */ 13 | 14 | #endif /* __ASM_GENERIC_SOCKIOS_H */ 15 | -------------------------------------------------------------------------------- /src/external/include/asm-generic/swab.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _ASM_GENERIC_SWAB_H 3 | #define _ASM_GENERIC_SWAB_H 4 | 5 | #include 6 | 7 | /* 8 | * 32 bit architectures typically (but not always) want to 9 | * set __SWAB_64_THRU_32__. In user space, this is only 10 | * valid if the compiler supports 64 bit data types. 11 | */ 12 | 13 | #if __BITS_PER_LONG == 32 14 | #if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__) 15 | #define __SWAB_64_THRU_32__ 16 | #endif 17 | #endif 18 | 19 | #endif /* _ASM_GENERIC_SWAB_H */ 20 | -------------------------------------------------------------------------------- /src/external/include/asm-generic/types.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _ASM_GENERIC_TYPES_H 3 | #define _ASM_GENERIC_TYPES_H 4 | /* 5 | * int-ll64 is used everywhere now. 6 | */ 7 | #include 8 | 9 | #endif /* _ASM_GENERIC_TYPES_H */ 10 | -------------------------------------------------------------------------------- /src/external/include/asm/bitsperlong.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* 3 | * Copyright (C) 2012 ARM Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef __ASM_BITSPERLONG_H 18 | #define __ASM_BITSPERLONG_H 19 | 20 | #define __BITS_PER_LONG 64 21 | 22 | #include 23 | 24 | #endif /* __ASM_BITSPERLONG_H */ 25 | -------------------------------------------------------------------------------- /src/external/include/asm/byteorder.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* 3 | * Copyright (C) 2012 ARM Ltd. 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License version 2 as 7 | * published by the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef __ASM_BYTEORDER_H 18 | #define __ASM_BYTEORDER_H 19 | 20 | #ifdef __AARCH64EB__ 21 | #include 22 | #else 23 | #include 24 | #endif 25 | 26 | #endif /* __ASM_BYTEORDER_H */ 27 | -------------------------------------------------------------------------------- /src/external/include/asm/errno.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/external/include/asm/posix_types.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef __ASM_POSIX_TYPES_H 3 | #define __ASM_POSIX_TYPES_H 4 | 5 | typedef unsigned short __kernel_old_uid_t; 6 | typedef unsigned short __kernel_old_gid_t; 7 | #define __kernel_old_uid_t __kernel_old_uid_t 8 | 9 | #include 10 | 11 | #endif /* __ASM_POSIX_TYPES_H */ 12 | -------------------------------------------------------------------------------- /src/external/include/asm/socket.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/external/include/asm/sockios.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/external/include/asm/sve_context.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* Copyright (C) 2017-2018 ARM Limited */ 3 | 4 | /* 5 | * For use by other UAPI headers only. 6 | * Do not make direct use of header or its definitions. 7 | */ 8 | 9 | #ifndef __ASM_SVE_CONTEXT_H 10 | #define __ASM_SVE_CONTEXT_H 11 | 12 | #include 13 | 14 | #define __SVE_VQ_BYTES 16 /* number of bytes per quadword */ 15 | 16 | /* 17 | * Yes, __SVE_VQ_MAX is 512 QUADWORDS. 18 | * 19 | * To help ensure forward portability, this is much larger than the 20 | * current maximum value defined by the SVE architecture. While arrays 21 | * or static allocations can be sized based on this value, watch out! 22 | * It will waste a surprisingly large amount of memory. 23 | * 24 | * Dynamic sizing based on the actual runtime vector length is likely to 25 | * be preferable for most purposes. 26 | */ 27 | #define __SVE_VQ_MIN 1 28 | #define __SVE_VQ_MAX 512 29 | 30 | #define __SVE_VL_MIN (__SVE_VQ_MIN * __SVE_VQ_BYTES) 31 | #define __SVE_VL_MAX (__SVE_VQ_MAX * __SVE_VQ_BYTES) 32 | 33 | #define __SVE_NUM_ZREGS 32 34 | #define __SVE_NUM_PREGS 16 35 | 36 | #define __sve_vl_valid(vl) \ 37 | ((vl) % __SVE_VQ_BYTES == 0 && \ 38 | (vl) >= __SVE_VL_MIN && \ 39 | (vl) <= __SVE_VL_MAX) 40 | 41 | #define __sve_vq_from_vl(vl) ((vl) / __SVE_VQ_BYTES) 42 | #define __sve_vl_from_vq(vq) ((vq) * __SVE_VQ_BYTES) 43 | 44 | #define __SVE_ZREG_SIZE(vq) ((__u32)(vq) * __SVE_VQ_BYTES) 45 | #define __SVE_PREG_SIZE(vq) ((__u32)(vq) * (__SVE_VQ_BYTES / 8)) 46 | #define __SVE_FFR_SIZE(vq) __SVE_PREG_SIZE(vq) 47 | 48 | #define __SVE_ZREGS_OFFSET 0 49 | #define __SVE_ZREG_OFFSET(vq, n) \ 50 | (__SVE_ZREGS_OFFSET + __SVE_ZREG_SIZE(vq) * (n)) 51 | #define __SVE_ZREGS_SIZE(vq) \ 52 | (__SVE_ZREG_OFFSET(vq, __SVE_NUM_ZREGS) - __SVE_ZREGS_OFFSET) 53 | 54 | #define __SVE_PREGS_OFFSET(vq) \ 55 | (__SVE_ZREGS_OFFSET + __SVE_ZREGS_SIZE(vq)) 56 | #define __SVE_PREG_OFFSET(vq, n) \ 57 | (__SVE_PREGS_OFFSET(vq) + __SVE_PREG_SIZE(vq) * (n)) 58 | #define __SVE_PREGS_SIZE(vq) \ 59 | (__SVE_PREG_OFFSET(vq, __SVE_NUM_PREGS) - __SVE_PREGS_OFFSET(vq)) 60 | 61 | #define __SVE_FFR_OFFSET(vq) \ 62 | (__SVE_PREGS_OFFSET(vq) + __SVE_PREGS_SIZE(vq)) 63 | 64 | #endif /* ! _UAPI__ASM_SVE_CONTEXT_H */ 65 | -------------------------------------------------------------------------------- /src/external/include/asm/swab.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/external/include/asm/types.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/external/include/disasm.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 | /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com 3 | * Copyright (c) 2016 Facebook 4 | */ 5 | 6 | #ifndef __BPF_DISASM_H__ 7 | #define __BPF_DISASM_H__ 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | typedef void (*bpf_insn_print_t)(void *private_data, 16 | const char *, ...); 17 | typedef const char *(*bpf_insn_revmap_call_t)(void *private_data, 18 | const struct bpf_insn *insn); 19 | typedef const char *(*bpf_insn_print_imm_t)(void *private_data, 20 | const struct bpf_insn *insn, 21 | uint64_t full_imm); 22 | 23 | struct bpf_insn_cbs { 24 | bpf_insn_print_t cb_print; 25 | bpf_insn_revmap_call_t cb_call; 26 | bpf_insn_print_imm_t cb_imm; 27 | void *private_data; 28 | }; 29 | 30 | void print_bpf_insn(const struct bpf_insn_cbs *cbs, 31 | const struct bpf_insn *insn, 32 | bool allow_ptr_leaks); 33 | #endif 34 | -------------------------------------------------------------------------------- /src/external/include/linux/bpf_common.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef __LINUX_BPF_COMMON_H__ 3 | #define __LINUX_BPF_COMMON_H__ 4 | 5 | /* Instruction classes */ 6 | #define BPF_CLASS(code) ((code) & 0x07) 7 | #define BPF_LD 0x00 8 | #define BPF_LDX 0x01 9 | #define BPF_ST 0x02 10 | #define BPF_STX 0x03 11 | #define BPF_ALU 0x04 12 | #define BPF_JMP 0x05 13 | #define BPF_RET 0x06 14 | #define BPF_MISC 0x07 15 | 16 | /* ld/ldx fields */ 17 | #define BPF_SIZE(code) ((code) & 0x18) 18 | #define BPF_W 0x00 /* 32-bit */ 19 | #define BPF_H 0x08 /* 16-bit */ 20 | #define BPF_B 0x10 /* 8-bit */ 21 | /* eBPF BPF_DW 0x18 64-bit */ 22 | #define BPF_MODE(code) ((code) & 0xe0) 23 | #define BPF_IMM 0x00 24 | #define BPF_ABS 0x20 25 | #define BPF_IND 0x40 26 | #define BPF_MEM 0x60 27 | #define BPF_LEN 0x80 28 | #define BPF_MSH 0xa0 29 | 30 | /* alu/jmp fields */ 31 | #define BPF_OP(code) ((code) & 0xf0) 32 | #define BPF_ADD 0x00 33 | #define BPF_SUB 0x10 34 | #define BPF_MUL 0x20 35 | #define BPF_DIV 0x30 36 | #define BPF_OR 0x40 37 | #define BPF_AND 0x50 38 | #define BPF_LSH 0x60 39 | #define BPF_RSH 0x70 40 | #define BPF_NEG 0x80 41 | #define BPF_MOD 0x90 42 | #define BPF_XOR 0xa0 43 | 44 | #define BPF_JA 0x00 45 | #define BPF_JEQ 0x10 46 | #define BPF_JGT 0x20 47 | #define BPF_JGE 0x30 48 | #define BPF_JSET 0x40 49 | #define BPF_SRC(code) ((code) & 0x08) 50 | #define BPF_K 0x00 51 | #define BPF_X 0x08 52 | 53 | #ifndef BPF_MAXINSNS 54 | #define BPF_MAXINSNS 4096 55 | #endif 56 | 57 | #endif /* __LINUX_BPF_COMMON_H__ */ 58 | -------------------------------------------------------------------------------- /src/external/include/linux/close_range.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _LINUX_CLOSE_RANGE_H 3 | #define _LINUX_CLOSE_RANGE_H 4 | 5 | /* Unshare the file descriptor table before closing file descriptors. */ 6 | #define CLOSE_RANGE_UNSHARE (1U << 1) 7 | 8 | /* Set the FD_CLOEXEC bit instead of closing the file descriptor. */ 9 | #define CLOSE_RANGE_CLOEXEC (1U << 2) 10 | 11 | #endif /* _LINUX_CLOSE_RANGE_H */ 12 | 13 | -------------------------------------------------------------------------------- /src/external/include/linux/const.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* const.h: Macros for dealing with constants. */ 3 | 4 | #ifndef _LINUX_CONST_H 5 | #define _LINUX_CONST_H 6 | 7 | /* Some constant macros are used in both assembler and 8 | * C code. Therefore we cannot annotate them always with 9 | * 'UL' and other type specifiers unilaterally. We 10 | * use the following macros to deal with this. 11 | * 12 | * Similarly, _AT() will cast an expression with a type in C, but 13 | * leave it unchanged in asm. 14 | */ 15 | 16 | #ifdef __ASSEMBLY__ 17 | #define _AC(X,Y) X 18 | #define _AT(T,X) X 19 | #else 20 | #define __AC(X,Y) (X##Y) 21 | #define _AC(X,Y) __AC(X,Y) 22 | #define _AT(T,X) ((T)(X)) 23 | #endif 24 | 25 | #define _UL(x) (_AC(x, UL)) 26 | #define _ULL(x) (_AC(x, ULL)) 27 | 28 | #define _BITUL(x) (_UL(1) << (x)) 29 | #define _BITULL(x) (_ULL(1) << (x)) 30 | 31 | #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1) 32 | #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) 33 | 34 | #define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) 35 | 36 | #endif /* _LINUX_CONST_H */ 37 | -------------------------------------------------------------------------------- /src/external/include/linux/errno.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/external/include/linux/genetlink.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef __LINUX_GENERIC_NETLINK_H 3 | #define __LINUX_GENERIC_NETLINK_H 4 | 5 | #include 6 | #include 7 | 8 | #define GENL_NAMSIZ 16 /* length of family name */ 9 | 10 | #define GENL_MIN_ID NLMSG_MIN_TYPE 11 | #define GENL_MAX_ID 1023 12 | 13 | struct genlmsghdr { 14 | __u8 cmd; 15 | __u8 version; 16 | __u16 reserved; 17 | }; 18 | 19 | #define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr)) 20 | 21 | #define GENL_ADMIN_PERM 0x01 22 | #define GENL_CMD_CAP_DO 0x02 23 | #define GENL_CMD_CAP_DUMP 0x04 24 | #define GENL_CMD_CAP_HASPOL 0x08 25 | #define GENL_UNS_ADMIN_PERM 0x10 26 | 27 | /* 28 | * List of reserved static generic netlink identifiers: 29 | */ 30 | #define GENL_ID_CTRL NLMSG_MIN_TYPE 31 | #define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1) 32 | #define GENL_ID_PMCRAID (NLMSG_MIN_TYPE + 2) 33 | /* must be last reserved + 1 */ 34 | #define GENL_START_ALLOC (NLMSG_MIN_TYPE + 3) 35 | 36 | /************************************************************************** 37 | * Controller 38 | **************************************************************************/ 39 | 40 | enum { 41 | CTRL_CMD_UNSPEC, 42 | CTRL_CMD_NEWFAMILY, 43 | CTRL_CMD_DELFAMILY, 44 | CTRL_CMD_GETFAMILY, 45 | CTRL_CMD_NEWOPS, 46 | CTRL_CMD_DELOPS, 47 | CTRL_CMD_GETOPS, 48 | CTRL_CMD_NEWMCAST_GRP, 49 | CTRL_CMD_DELMCAST_GRP, 50 | CTRL_CMD_GETMCAST_GRP, /* unused */ 51 | CTRL_CMD_GETPOLICY, 52 | __CTRL_CMD_MAX, 53 | }; 54 | 55 | #define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1) 56 | 57 | enum { 58 | CTRL_ATTR_UNSPEC, 59 | CTRL_ATTR_FAMILY_ID, 60 | CTRL_ATTR_FAMILY_NAME, 61 | CTRL_ATTR_VERSION, 62 | CTRL_ATTR_HDRSIZE, 63 | CTRL_ATTR_MAXATTR, 64 | CTRL_ATTR_OPS, 65 | CTRL_ATTR_MCAST_GROUPS, 66 | CTRL_ATTR_POLICY, 67 | CTRL_ATTR_OP_POLICY, 68 | CTRL_ATTR_OP, 69 | __CTRL_ATTR_MAX, 70 | }; 71 | 72 | #define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1) 73 | 74 | enum { 75 | CTRL_ATTR_OP_UNSPEC, 76 | CTRL_ATTR_OP_ID, 77 | CTRL_ATTR_OP_FLAGS, 78 | __CTRL_ATTR_OP_MAX, 79 | }; 80 | 81 | #define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1) 82 | 83 | enum { 84 | CTRL_ATTR_MCAST_GRP_UNSPEC, 85 | CTRL_ATTR_MCAST_GRP_NAME, 86 | CTRL_ATTR_MCAST_GRP_ID, 87 | __CTRL_ATTR_MCAST_GRP_MAX, 88 | }; 89 | 90 | #define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1) 91 | 92 | enum { 93 | CTRL_ATTR_POLICY_UNSPEC, 94 | CTRL_ATTR_POLICY_DO, 95 | CTRL_ATTR_POLICY_DUMP, 96 | 97 | __CTRL_ATTR_POLICY_DUMP_MAX, 98 | CTRL_ATTR_POLICY_DUMP_MAX = __CTRL_ATTR_POLICY_DUMP_MAX - 1 99 | }; 100 | 101 | #define CTRL_ATTR_POLICY_MAX (__CTRL_ATTR_POLICY_DUMP_MAX - 1) 102 | 103 | #endif /* __LINUX_GENERIC_NETLINK_H */ 104 | -------------------------------------------------------------------------------- /src/external/include/linux/if_addr.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef __LINUX_IF_ADDR_H 3 | #define __LINUX_IF_ADDR_H 4 | 5 | #include 6 | #include 7 | 8 | struct ifaddrmsg { 9 | __u8 ifa_family; 10 | __u8 ifa_prefixlen; /* The prefix length */ 11 | __u8 ifa_flags; /* Flags */ 12 | __u8 ifa_scope; /* Address scope */ 13 | __u32 ifa_index; /* Link index */ 14 | }; 15 | 16 | /* 17 | * Important comment: 18 | * IFA_ADDRESS is prefix address, rather than local interface address. 19 | * It makes no difference for normally configured broadcast interfaces, 20 | * but for point-to-point IFA_ADDRESS is DESTINATION address, 21 | * local address is supplied in IFA_LOCAL attribute. 22 | * 23 | * IFA_FLAGS is a u32 attribute that extends the u8 field ifa_flags. 24 | * If present, the value from struct ifaddrmsg will be ignored. 25 | */ 26 | enum { 27 | IFA_UNSPEC, 28 | IFA_ADDRESS, 29 | IFA_LOCAL, 30 | IFA_LABEL, 31 | IFA_BROADCAST, 32 | IFA_ANYCAST, 33 | IFA_CACHEINFO, 34 | IFA_MULTICAST, 35 | IFA_FLAGS, 36 | IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */ 37 | IFA_TARGET_NETNSID, 38 | IFA_PROTO, /* u8, address protocol */ 39 | __IFA_MAX, 40 | }; 41 | 42 | #define IFA_MAX (__IFA_MAX - 1) 43 | 44 | /* ifa_flags */ 45 | #define IFA_F_SECONDARY 0x01 46 | #define IFA_F_TEMPORARY IFA_F_SECONDARY 47 | 48 | #define IFA_F_NODAD 0x02 49 | #define IFA_F_OPTIMISTIC 0x04 50 | #define IFA_F_DADFAILED 0x08 51 | #define IFA_F_HOMEADDRESS 0x10 52 | #define IFA_F_DEPRECATED 0x20 53 | #define IFA_F_TENTATIVE 0x40 54 | #define IFA_F_PERMANENT 0x80 55 | #define IFA_F_MANAGETEMPADDR 0x100 56 | #define IFA_F_NOPREFIXROUTE 0x200 57 | #define IFA_F_MCAUTOJOIN 0x400 58 | #define IFA_F_STABLE_PRIVACY 0x800 59 | 60 | struct ifa_cacheinfo { 61 | __u32 ifa_prefered; 62 | __u32 ifa_valid; 63 | __u32 cstamp; /* created timestamp, hundredths of seconds */ 64 | __u32 tstamp; /* updated timestamp, hundredths of seconds */ 65 | }; 66 | 67 | /* backwards compatibility for userspace */ 68 | #define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) 69 | #define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) 70 | 71 | /* ifa_proto */ 72 | #define IFAPROT_UNSPEC 0 73 | #define IFAPROT_KERNEL_LO 1 /* loopback */ 74 | #define IFAPROT_KERNEL_RA 2 /* set by kernel from router announcement */ 75 | #define IFAPROT_KERNEL_LL 3 /* link-local set by kernel */ 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /src/external/include/linux/kernel.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _LINUX_KERNEL_H 3 | #define _LINUX_KERNEL_H 4 | 5 | #include 6 | #include 7 | 8 | #endif /* _LINUX_KERNEL_H */ 9 | -------------------------------------------------------------------------------- /src/external/include/linux/limits.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _LINUX_LIMITS_H 3 | #define _LINUX_LIMITS_H 4 | 5 | #define NR_OPEN 1024 6 | 7 | #define NGROUPS_MAX 65536 /* supplemental group IDs are available */ 8 | #define ARG_MAX 131072 /* # bytes of args + environ for exec() */ 9 | #define LINK_MAX 127 /* # links a file may have */ 10 | #define MAX_CANON 255 /* size of the canonical input queue */ 11 | #define MAX_INPUT 255 /* size of the type-ahead buffer */ 12 | #define NAME_MAX 255 /* # chars in a file name */ 13 | #define PATH_MAX 4096 /* # chars in a path name including nul */ 14 | #define PIPE_BUF 4096 /* # bytes in atomic write to a pipe */ 15 | #define XATTR_NAME_MAX 255 /* # chars in an extended attribute name */ 16 | #define XATTR_SIZE_MAX 65536 /* size of an extended attribute value (64k) */ 17 | #define XATTR_LIST_MAX 65536 /* size of extended attribute namelist (64k) */ 18 | 19 | #define RTSIG_MAX 32 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/external/include/linux/netfilter.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef __LINUX_NETFILTER_H 3 | #define __LINUX_NETFILTER_H 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | /* Responses from hook functions. */ 11 | #define NF_DROP 0 12 | #define NF_ACCEPT 1 13 | #define NF_STOLEN 2 14 | #define NF_QUEUE 3 15 | #define NF_REPEAT 4 16 | #define NF_STOP 5 /* Deprecated, for userspace nf_queue compatibility. */ 17 | #define NF_MAX_VERDICT NF_STOP 18 | 19 | /* we overload the higher bits for encoding auxiliary data such as the queue 20 | * number or errno values. Not nice, but better than additional function 21 | * arguments. */ 22 | #define NF_VERDICT_MASK 0x000000ff 23 | 24 | /* extra verdict flags have mask 0x0000ff00 */ 25 | #define NF_VERDICT_FLAG_QUEUE_BYPASS 0x00008000 26 | 27 | /* queue number (NF_QUEUE) or errno (NF_DROP) */ 28 | #define NF_VERDICT_QMASK 0xffff0000 29 | #define NF_VERDICT_QBITS 16 30 | 31 | #define NF_QUEUE_NR(x) ((((x) << 16) & NF_VERDICT_QMASK) | NF_QUEUE) 32 | 33 | #define NF_DROP_ERR(x) (((-x) << 16) | NF_DROP) 34 | 35 | /* only for userspace compatibility */ 36 | 37 | /* NF_VERDICT_BITS should be 8 now, but userspace might break if this changes */ 38 | #define NF_VERDICT_BITS 16 39 | 40 | enum nf_inet_hooks { 41 | NF_INET_PRE_ROUTING, 42 | NF_INET_LOCAL_IN, 43 | NF_INET_FORWARD, 44 | NF_INET_LOCAL_OUT, 45 | NF_INET_POST_ROUTING, 46 | NF_INET_NUMHOOKS, 47 | NF_INET_INGRESS = NF_INET_NUMHOOKS, 48 | }; 49 | 50 | enum nf_dev_hooks { 51 | NF_NETDEV_INGRESS, 52 | NF_NETDEV_EGRESS, 53 | NF_NETDEV_NUMHOOKS 54 | }; 55 | 56 | enum { 57 | NFPROTO_UNSPEC = 0, 58 | NFPROTO_INET = 1, 59 | NFPROTO_IPV4 = 2, 60 | NFPROTO_ARP = 3, 61 | NFPROTO_NETDEV = 5, 62 | NFPROTO_BRIDGE = 7, 63 | NFPROTO_IPV6 = 10, 64 | NFPROTO_DECNET = 12, 65 | NFPROTO_NUMPROTO, 66 | }; 67 | 68 | union nf_inet_addr { 69 | __u32 all[4]; 70 | __be32 ip; 71 | __be32 ip6[4]; 72 | struct in_addr in; 73 | struct in6_addr in6; 74 | }; 75 | 76 | #endif /* __LINUX_NETFILTER_H */ 77 | -------------------------------------------------------------------------------- /src/external/include/linux/netfilter/nfnetlink.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _NFNETLINK_H 3 | #define _NFNETLINK_H 4 | #include 5 | #include 6 | 7 | enum nfnetlink_groups { 8 | NFNLGRP_NONE, 9 | #define NFNLGRP_NONE NFNLGRP_NONE 10 | NFNLGRP_CONNTRACK_NEW, 11 | #define NFNLGRP_CONNTRACK_NEW NFNLGRP_CONNTRACK_NEW 12 | NFNLGRP_CONNTRACK_UPDATE, 13 | #define NFNLGRP_CONNTRACK_UPDATE NFNLGRP_CONNTRACK_UPDATE 14 | NFNLGRP_CONNTRACK_DESTROY, 15 | #define NFNLGRP_CONNTRACK_DESTROY NFNLGRP_CONNTRACK_DESTROY 16 | NFNLGRP_CONNTRACK_EXP_NEW, 17 | #define NFNLGRP_CONNTRACK_EXP_NEW NFNLGRP_CONNTRACK_EXP_NEW 18 | NFNLGRP_CONNTRACK_EXP_UPDATE, 19 | #define NFNLGRP_CONNTRACK_EXP_UPDATE NFNLGRP_CONNTRACK_EXP_UPDATE 20 | NFNLGRP_CONNTRACK_EXP_DESTROY, 21 | #define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY 22 | NFNLGRP_NFTABLES, 23 | #define NFNLGRP_NFTABLES NFNLGRP_NFTABLES 24 | NFNLGRP_ACCT_QUOTA, 25 | #define NFNLGRP_ACCT_QUOTA NFNLGRP_ACCT_QUOTA 26 | NFNLGRP_NFTRACE, 27 | #define NFNLGRP_NFTRACE NFNLGRP_NFTRACE 28 | __NFNLGRP_MAX, 29 | }; 30 | #define NFNLGRP_MAX (__NFNLGRP_MAX - 1) 31 | 32 | /* General form of address family dependent message. 33 | */ 34 | struct nfgenmsg { 35 | __u8 nfgen_family; /* AF_xxx */ 36 | __u8 version; /* nfnetlink version */ 37 | __be16 res_id; /* resource id */ 38 | }; 39 | 40 | #define NFNETLINK_V0 0 41 | 42 | /* netfilter netlink message types are split in two pieces: 43 | * 8 bit subsystem, 8bit operation. 44 | */ 45 | 46 | #define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8) 47 | #define NFNL_MSG_TYPE(x) (x & 0x00ff) 48 | 49 | /* No enum here, otherwise __stringify() trick of MODULE_ALIAS_NFNL_SUBSYS() 50 | * won't work anymore */ 51 | #define NFNL_SUBSYS_NONE 0 52 | #define NFNL_SUBSYS_CTNETLINK 1 53 | #define NFNL_SUBSYS_CTNETLINK_EXP 2 54 | #define NFNL_SUBSYS_QUEUE 3 55 | #define NFNL_SUBSYS_ULOG 4 56 | #define NFNL_SUBSYS_OSF 5 57 | #define NFNL_SUBSYS_IPSET 6 58 | #define NFNL_SUBSYS_ACCT 7 59 | #define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8 60 | #define NFNL_SUBSYS_CTHELPER 9 61 | #define NFNL_SUBSYS_NFTABLES 10 62 | #define NFNL_SUBSYS_NFT_COMPAT 11 63 | #define NFNL_SUBSYS_HOOK 12 64 | #define NFNL_SUBSYS_COUNT 13 65 | 66 | /* Reserved control nfnetlink messages */ 67 | #define NFNL_MSG_BATCH_BEGIN NLMSG_MIN_TYPE 68 | #define NFNL_MSG_BATCH_END NLMSG_MIN_TYPE+1 69 | 70 | /** 71 | * enum nfnl_batch_attributes - nfnetlink batch netlink attributes 72 | * 73 | * @NFNL_BATCH_GENID: generation ID for this changeset (NLA_U32) 74 | */ 75 | enum nfnl_batch_attributes { 76 | NFNL_BATCH_UNSPEC, 77 | NFNL_BATCH_GENID, 78 | __NFNL_BATCH_MAX 79 | }; 80 | #define NFNL_BATCH_MAX (__NFNL_BATCH_MAX - 1) 81 | 82 | #endif /* _NFNETLINK_H */ 83 | -------------------------------------------------------------------------------- /src/external/include/linux/netfilter/nfnetlink_compat.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _NFNETLINK_COMPAT_H 3 | #define _NFNETLINK_COMPAT_H 4 | 5 | #include 6 | 7 | /* Old nfnetlink macros for userspace */ 8 | 9 | /* nfnetlink groups: Up to 32 maximum */ 10 | #define NF_NETLINK_CONNTRACK_NEW 0x00000001 11 | #define NF_NETLINK_CONNTRACK_UPDATE 0x00000002 12 | #define NF_NETLINK_CONNTRACK_DESTROY 0x00000004 13 | #define NF_NETLINK_CONNTRACK_EXP_NEW 0x00000008 14 | #define NF_NETLINK_CONNTRACK_EXP_UPDATE 0x00000010 15 | #define NF_NETLINK_CONNTRACK_EXP_DESTROY 0x00000020 16 | 17 | /* Generic structure for encapsulation optional netfilter information. 18 | * It is reminiscent of sockaddr, but with sa_family replaced 19 | * with attribute type. 20 | * ! This should someday be put somewhere generic as now rtnetlink and 21 | * ! nfnetlink use the same attributes methods. - J. Schulist. 22 | */ 23 | 24 | struct nfattr { 25 | __u16 nfa_len; 26 | __u16 nfa_type; /* we use 15 bits for the type, and the highest 27 | * bit to indicate whether the payload is nested */ 28 | }; 29 | 30 | /* FIXME: Apart from NFNL_NFA_NESTED shamelessly copy and pasted from 31 | * rtnetlink.h, it's time to put this in a generic file */ 32 | 33 | #define NFNL_NFA_NEST 0x8000 34 | #define NFA_TYPE(attr) ((attr)->nfa_type & 0x7fff) 35 | 36 | #define NFA_ALIGNTO 4 37 | #define NFA_ALIGN(len) (((len) + NFA_ALIGNTO - 1) & ~(NFA_ALIGNTO - 1)) 38 | #define NFA_OK(nfa,len) ((len) > 0 && (nfa)->nfa_len >= sizeof(struct nfattr) \ 39 | && (nfa)->nfa_len <= (len)) 40 | #define NFA_NEXT(nfa,attrlen) ((attrlen) -= NFA_ALIGN((nfa)->nfa_len), \ 41 | (struct nfattr *)(((char *)(nfa)) + NFA_ALIGN((nfa)->nfa_len))) 42 | #define NFA_LENGTH(len) (NFA_ALIGN(sizeof(struct nfattr)) + (len)) 43 | #define NFA_SPACE(len) NFA_ALIGN(NFA_LENGTH(len)) 44 | #define NFA_DATA(nfa) ((void *)(((char *)(nfa)) + NFA_LENGTH(0))) 45 | #define NFA_PAYLOAD(nfa) ((int)((nfa)->nfa_len) - NFA_LENGTH(0)) 46 | #define NFA_NEST(skb, type) \ 47 | ({ struct nfattr *__start = (struct nfattr *)skb_tail_pointer(skb); \ 48 | NFA_PUT(skb, (NFNL_NFA_NEST | type), 0, NULL); \ 49 | __start; }) 50 | #define NFA_NEST_END(skb, start) \ 51 | ({ (start)->nfa_len = skb_tail_pointer(skb) - (unsigned char *)(start); \ 52 | (skb)->len; }) 53 | #define NFA_NEST_CANCEL(skb, start) \ 54 | ({ if (start) \ 55 | skb_trim(skb, (unsigned char *) (start) - (skb)->data); \ 56 | -1; }) 57 | 58 | #define NFM_NFA(n) ((struct nfattr *)(((char *)(n)) \ 59 | + NLMSG_ALIGN(sizeof(struct nfgenmsg)))) 60 | #define NFM_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct nfgenmsg)) 61 | 62 | #endif /* _NFNETLINK_COMPAT_H */ 63 | -------------------------------------------------------------------------------- /src/external/include/linux/netfilter/xt_tcpudp.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _XT_TCPUDP_H 3 | #define _XT_TCPUDP_H 4 | 5 | #include 6 | 7 | /* TCP matching stuff */ 8 | struct xt_tcp { 9 | __u16 spts[2]; /* Source port range. */ 10 | __u16 dpts[2]; /* Destination port range. */ 11 | __u8 option; /* TCP Option iff non-zero*/ 12 | __u8 flg_mask; /* TCP flags mask byte */ 13 | __u8 flg_cmp; /* TCP flags compare byte */ 14 | __u8 invflags; /* Inverse flags */ 15 | }; 16 | 17 | /* Values for "inv" field in struct ipt_tcp. */ 18 | #define XT_TCP_INV_SRCPT 0x01 /* Invert the sense of source ports. */ 19 | #define XT_TCP_INV_DSTPT 0x02 /* Invert the sense of dest ports. */ 20 | #define XT_TCP_INV_FLAGS 0x04 /* Invert the sense of TCP flags. */ 21 | #define XT_TCP_INV_OPTION 0x08 /* Invert the sense of option test. */ 22 | #define XT_TCP_INV_MASK 0x0F /* All possible flags. */ 23 | 24 | /* UDP matching stuff */ 25 | struct xt_udp { 26 | __u16 spts[2]; /* Source port range. */ 27 | __u16 dpts[2]; /* Destination port range. */ 28 | __u8 invflags; /* Inverse flags */ 29 | }; 30 | 31 | /* Values for "invflags" field in struct ipt_udp. */ 32 | #define XT_UDP_INV_SRCPT 0x01 /* Invert the sense of source ports. */ 33 | #define XT_UDP_INV_DSTPT 0x02 /* Invert the sense of dest ports. */ 34 | #define XT_UDP_INV_MASK 0x03 /* All possible flags. */ 35 | 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/external/include/linux/netfilter_ipv4.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | /* IPv4-specific defines for netfilter. 3 | * (C)1998 Rusty Russell -- This code is GPL. 4 | */ 5 | #ifndef __LINUX_IP_NETFILTER_H 6 | #define __LINUX_IP_NETFILTER_H 7 | 8 | 9 | #include 10 | 11 | /* only for userspace compatibility */ 12 | 13 | #include /* for INT_MIN, INT_MAX */ 14 | 15 | /* IP Hooks */ 16 | /* After promisc drops, checksum checks. */ 17 | #define NF_IP_PRE_ROUTING 0 18 | /* If the packet is destined for this box. */ 19 | #define NF_IP_LOCAL_IN 1 20 | /* If the packet is destined for another interface. */ 21 | #define NF_IP_FORWARD 2 22 | /* Packets coming from a local process. */ 23 | #define NF_IP_LOCAL_OUT 3 24 | /* Packets about to hit the wire. */ 25 | #define NF_IP_POST_ROUTING 4 26 | #define NF_IP_NUMHOOKS 5 27 | 28 | enum nf_ip_hook_priorities { 29 | NF_IP_PRI_FIRST = INT_MIN, 30 | NF_IP_PRI_RAW_BEFORE_DEFRAG = -450, 31 | NF_IP_PRI_CONNTRACK_DEFRAG = -400, 32 | NF_IP_PRI_RAW = -300, 33 | NF_IP_PRI_SELINUX_FIRST = -225, 34 | NF_IP_PRI_CONNTRACK = -200, 35 | NF_IP_PRI_MANGLE = -150, 36 | NF_IP_PRI_NAT_DST = -100, 37 | NF_IP_PRI_FILTER = 0, 38 | NF_IP_PRI_SECURITY = 50, 39 | NF_IP_PRI_NAT_SRC = 100, 40 | NF_IP_PRI_SELINUX_LAST = 225, 41 | NF_IP_PRI_CONNTRACK_HELPER = 300, 42 | NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX, 43 | NF_IP_PRI_LAST = INT_MAX, 44 | }; 45 | 46 | /* Arguments for setsockopt SOL_IP: */ 47 | /* 2.0 firewalling went from 64 through 71 (and +256, +512, etc). */ 48 | /* 2.2 firewalling (+ masq) went from 64 through 76 */ 49 | /* 2.4 firewalling went 64 through 67. */ 50 | #define SO_ORIGINAL_DST 80 51 | 52 | 53 | #endif /* __LINUX_IP_NETFILTER_H */ 54 | -------------------------------------------------------------------------------- /src/external/include/linux/posix_types.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _LINUX_POSIX_TYPES_H 3 | #define _LINUX_POSIX_TYPES_H 4 | 5 | #include 6 | 7 | /* 8 | * This allows for 1024 file descriptors: if NR_OPEN is ever grown 9 | * beyond that you'll have to change this too. But 1024 fd's seem to be 10 | * enough even for such "real" unices like OSF/1, so hopefully this is 11 | * one limit that doesn't have to be changed [again]. 12 | * 13 | * Note that POSIX wants the FD_CLEAR(fd,fdsetp) defines to be in 14 | * (and thus ) - but this is a more logical 15 | * place for them. Solved by having dummy defines in . 16 | */ 17 | 18 | /* 19 | * This macro may have been defined in . But we always 20 | * use the one here. 21 | */ 22 | #undef __FD_SETSIZE 23 | #define __FD_SETSIZE 1024 24 | 25 | typedef struct { 26 | unsigned long fds_bits[__FD_SETSIZE / (8 * sizeof(long))]; 27 | } __kernel_fd_set; 28 | 29 | /* Type of a signal handler. */ 30 | typedef void (*__kernel_sighandler_t)(int); 31 | 32 | /* Type of a SYSV IPC key. */ 33 | typedef int __kernel_key_t; 34 | typedef int __kernel_mqd_t; 35 | 36 | #include 37 | 38 | #endif /* _LINUX_POSIX_TYPES_H */ 39 | -------------------------------------------------------------------------------- /src/external/include/linux/socket.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _LINUX_SOCKET_H 3 | #define _LINUX_SOCKET_H 4 | 5 | /* 6 | * Desired design of maximum size and alignment (see RFC2553) 7 | */ 8 | #define _K_SS_MAXSIZE 128 /* Implementation specific max size */ 9 | 10 | typedef unsigned short __kernel_sa_family_t; 11 | 12 | /* 13 | * The definition uses anonymous union and struct in order to control the 14 | * default alignment. 15 | */ 16 | struct __kernel_sockaddr_storage { 17 | union { 18 | struct { 19 | __kernel_sa_family_t ss_family; /* address family */ 20 | /* Following field(s) are implementation specific */ 21 | char __data[_K_SS_MAXSIZE - sizeof(unsigned short)]; 22 | /* space to achieve desired size, */ 23 | /* _SS_MAXSIZE value minus size of ss_family */ 24 | }; 25 | void *__align; /* implementation specific desired alignment */ 26 | }; 27 | }; 28 | 29 | #define SOCK_SNDBUF_LOCK 1 30 | #define SOCK_RCVBUF_LOCK 2 31 | 32 | #define SOCK_BUF_LOCK_MASK (SOCK_SNDBUF_LOCK | SOCK_RCVBUF_LOCK) 33 | 34 | #define SOCK_TXREHASH_DEFAULT 255 35 | #define SOCK_TXREHASH_DISABLED 0 36 | #define SOCK_TXREHASH_ENABLED 1 37 | 38 | #endif /* _LINUX_SOCKET_H */ 39 | -------------------------------------------------------------------------------- /src/external/include/linux/stddef.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _LINUX_STDDEF_H 3 | #define _LINUX_STDDEF_H 4 | 5 | 6 | 7 | #ifndef __always_inline 8 | #define __always_inline __inline__ 9 | #endif 10 | 11 | /** 12 | * __struct_group() - Create a mirrored named and anonyomous struct 13 | * 14 | * @TAG: The tag name for the named sub-struct (usually empty) 15 | * @NAME: The identifier name of the mirrored sub-struct 16 | * @ATTRS: Any struct attributes (usually empty) 17 | * @MEMBERS: The member declarations for the mirrored structs 18 | * 19 | * Used to create an anonymous union of two structs with identical layout 20 | * and size: one anonymous and one named. The former's members can be used 21 | * normally without sub-struct naming, and the latter can be used to 22 | * reason about the start, end, and size of the group of struct members. 23 | * The named struct can also be explicitly tagged for layer reuse, as well 24 | * as both having struct attributes appended. 25 | */ 26 | #define __struct_group(TAG, NAME, ATTRS, MEMBERS...) \ 27 | union { \ 28 | struct { MEMBERS } ATTRS; \ 29 | struct TAG { MEMBERS } ATTRS NAME; \ 30 | } ATTRS 31 | 32 | #ifdef __cplusplus 33 | /* sizeof(struct{}) is 1 in C++, not 0, can't use C version of the macro. */ 34 | #define __DECLARE_FLEX_ARRAY(T, member) \ 35 | T member[0] 36 | #else 37 | /** 38 | * __DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union 39 | * 40 | * @TYPE: The type of each flexible array element 41 | * @NAME: The name of the flexible array member 42 | * 43 | * In order to have a flexible array member in a union or alone in a 44 | * struct, it needs to be wrapped in an anonymous struct with at least 1 45 | * named member, but that member can be empty. 46 | */ 47 | #define __DECLARE_FLEX_ARRAY(TYPE, NAME) \ 48 | struct { \ 49 | struct { } __empty_ ## NAME; \ 50 | TYPE NAME[]; \ 51 | } 52 | #endif 53 | 54 | #ifndef __counted_by 55 | #define __counted_by(m) 56 | #endif 57 | 58 | #endif /* _LINUX_STDDEF_H */ 59 | -------------------------------------------------------------------------------- /src/external/include/linux/sysinfo.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _LINUX_SYSINFO_H 3 | #define _LINUX_SYSINFO_H 4 | 5 | #include 6 | 7 | #define SI_LOAD_SHIFT 16 8 | struct sysinfo { 9 | __kernel_long_t uptime; /* Seconds since boot */ 10 | __kernel_ulong_t loads[3]; /* 1, 5, and 15 minute load averages */ 11 | __kernel_ulong_t totalram; /* Total usable main memory size */ 12 | __kernel_ulong_t freeram; /* Available memory size */ 13 | __kernel_ulong_t sharedram; /* Amount of shared memory */ 14 | __kernel_ulong_t bufferram; /* Memory used by buffers */ 15 | __kernel_ulong_t totalswap; /* Total swap space size */ 16 | __kernel_ulong_t freeswap; /* swap space still available */ 17 | __u16 procs; /* Number of current processes */ 18 | __u16 pad; /* Explicit padding for m68k */ 19 | __kernel_ulong_t totalhigh; /* Total high memory size */ 20 | __kernel_ulong_t freehigh; /* Available high memory size */ 21 | __u32 mem_unit; /* Memory unit size in bytes */ 22 | char _f[20-2*sizeof(__kernel_ulong_t)-sizeof(__u32)]; /* Padding: libc5 uses this.. */ 23 | }; 24 | 25 | #endif /* _LINUX_SYSINFO_H */ 26 | -------------------------------------------------------------------------------- /src/external/include/linux/types.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 | #ifndef _LINUX_TYPES_H 3 | #define _LINUX_TYPES_H 4 | 5 | #include 6 | 7 | #ifndef __ASSEMBLY__ 8 | 9 | #include 10 | 11 | #ifdef __SIZEOF_INT128__ 12 | typedef __signed__ __int128 __s128 __attribute__((aligned(16))); 13 | typedef unsigned __int128 __u128 __attribute__((aligned(16))); 14 | #endif 15 | 16 | /* 17 | * Below are truly Linux-specific types that should never collide with 18 | * any application/library that wants linux/types.h. 19 | */ 20 | 21 | /* sparse defines __CHECKER__; see Documentation/dev-tools/sparse.rst */ 22 | #ifdef __CHECKER__ 23 | #define __bitwise __attribute__((bitwise)) 24 | #else 25 | #define __bitwise 26 | #endif 27 | 28 | /* The kernel doesn't use this legacy form, but user space does */ 29 | #define __bitwise__ __bitwise 30 | 31 | typedef __u16 __bitwise __le16; 32 | typedef __u16 __bitwise __be16; 33 | typedef __u32 __bitwise __le32; 34 | typedef __u32 __bitwise __be32; 35 | typedef __u64 __bitwise __le64; 36 | typedef __u64 __bitwise __be64; 37 | 38 | typedef __u16 __bitwise __sum16; 39 | typedef __u32 __bitwise __wsum; 40 | 41 | /* 42 | * aligned_u64 should be used in defining kernel<->userspace ABIs to avoid 43 | * common 32/64-bit compat problems. 44 | * 64-bit values align to 4-byte boundaries on x86_32 (and possibly other 45 | * architectures) and to 8-byte boundaries on 64-bit architectures. The new 46 | * aligned_64 type enforces 8-byte alignment so that structs containing 47 | * aligned_64 values have the same alignment on 32-bit and 64-bit architectures. 48 | * No conversions are necessary between 32-bit user-space and a 64-bit kernel. 49 | */ 50 | #define __aligned_u64 __u64 __attribute__((aligned(8))) 51 | #define __aligned_be64 __be64 __attribute__((aligned(8))) 52 | #define __aligned_le64 __le64 __attribute__((aligned(8))) 53 | 54 | typedef unsigned __bitwise __poll_t; 55 | 56 | #endif /* __ASSEMBLY__ */ 57 | #endif /* _LINUX_TYPES_H */ 58 | -------------------------------------------------------------------------------- /src/external/include/linux/udp.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ 2 | /* 3 | * INET An implementation of the TCP/IP protocol suite for the LINUX 4 | * operating system. INET is implemented using the BSD Socket 5 | * interface as the means of communication with the user level. 6 | * 7 | * Definitions for the UDP protocol. 8 | * 9 | * Version: @(#)udp.h 1.0.2 04/28/93 10 | * 11 | * Author: Fred N. van Kempen, 12 | * 13 | * This program is free software; you can redistribute it and/or 14 | * modify it under the terms of the GNU General Public License 15 | * as published by the Free Software Foundation; either version 16 | * 2 of the License, or (at your option) any later version. 17 | */ 18 | #ifndef _LINUX_UDP_H 19 | #define _LINUX_UDP_H 20 | 21 | #include 22 | 23 | struct udphdr { 24 | __be16 source; 25 | __be16 dest; 26 | __be16 len; 27 | __sum16 check; 28 | }; 29 | 30 | /* UDP socket options */ 31 | #define UDP_CORK 1 /* Never send partially complete segments */ 32 | #define UDP_ENCAP 100 /* Set the socket to accept encapsulated packets */ 33 | #define UDP_NO_CHECK6_TX 101 /* Disable sending checksum for UDP6X */ 34 | #define UDP_NO_CHECK6_RX 102 /* Disable accpeting checksum for UDP6 */ 35 | #define UDP_SEGMENT 103 /* Set GSO segmentation size */ 36 | #define UDP_GRO 104 /* This socket can receive UDP GRO packets */ 37 | 38 | /* UDP encapsulation types */ 39 | #define UDP_ENCAP_ESPINUDP_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */ 40 | #define UDP_ENCAP_ESPINUDP 2 /* draft-ietf-ipsec-udp-encaps-06 */ 41 | #define UDP_ENCAP_L2TPINUDP 3 /* rfc2661 */ 42 | #define UDP_ENCAP_GTP0 4 /* GSM TS 09.60 */ 43 | #define UDP_ENCAP_GTP1U 5 /* 3GPP TS 29.060 */ 44 | #define UDP_ENCAP_RXRPC 6 45 | #define TCP_ENCAP_ESPINTCP 7 /* Yikes, this is really xfrm encap types. */ 46 | 47 | #endif /* _LINUX_UDP_H */ 48 | -------------------------------------------------------------------------------- /src/libbpfilter/bpfilter.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ 3 | libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ 4 | 5 | Name: bpfilter 6 | Description: BPF-based packet filtering framework 7 | URL: https://github.com/facebook/bpfilter 8 | Version: @PROJECT_VERSION@@PROJECT_VERSION_SUFFIX@ 9 | Cflags: -I${includedir} 10 | Libs: -L${libdir} -lbpfilter 11 | -------------------------------------------------------------------------------- /src/libbpfilter/counter.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | #include "bpfilter/counter.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "bpfilter/helper.h" 13 | 14 | int bf_counter_new(struct bf_counter **counter, uint64_t packets, 15 | uint64_t bytes) 16 | { 17 | _cleanup_free_ struct bf_counter *_counter = NULL; 18 | 19 | bf_assert(counter); 20 | 21 | _counter = malloc(sizeof(*_counter)); 22 | if (!_counter) 23 | return -ENOMEM; 24 | 25 | _counter->bytes = bytes; 26 | _counter->packets = packets; 27 | 28 | *counter = TAKE_PTR(_counter); 29 | 30 | return 0; 31 | } 32 | 33 | int bf_counter_new_from_pack(struct bf_counter **counter, bf_rpack_node_t node) 34 | { 35 | _free_bf_counter_ struct bf_counter *_counter = NULL; 36 | int r; 37 | 38 | bf_assert(counter); 39 | 40 | r = bf_counter_new(&_counter, 0, 0); 41 | if (r) 42 | return r; 43 | 44 | r = bf_rpack_kv_u64(node, "packets", &_counter->packets); 45 | if (r) 46 | return bf_rpack_key_err(r, "bf_counter.packets"); 47 | 48 | r = bf_rpack_kv_u64(node, "bytes", &_counter->bytes); 49 | if (r) 50 | return bf_rpack_key_err(r, "bf_counter.bytes"); 51 | 52 | *counter = TAKE_PTR(_counter); 53 | 54 | return 0; 55 | } 56 | 57 | void bf_counter_free(struct bf_counter **counter) 58 | { 59 | bf_assert(counter); 60 | 61 | if (!*counter) 62 | return; 63 | 64 | freep((void *)counter); 65 | } 66 | 67 | int bf_counter_pack(const struct bf_counter *counter, bf_wpack_t *pack) 68 | { 69 | bf_assert(counter); 70 | bf_assert(pack); 71 | 72 | bf_wpack_kv_u64(pack, "packets", counter->packets); 73 | bf_wpack_kv_u64(pack, "bytes", counter->bytes); 74 | 75 | return bf_wpack_is_valid(pack) ? 0 : -EINVAL; 76 | } 77 | -------------------------------------------------------------------------------- /src/libbpfilter/dump.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "bpfilter/dump.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #define BF_DUMP_HEXDUMP_LEN 8 13 | #define BF_DUMP_TOKEN_LEN 5 14 | 15 | void bf_dump_prefix_push(prefix_t *prefix) 16 | { 17 | char *_prefix = *prefix; 18 | size_t len = strlen(_prefix); 19 | 20 | if (len) { 21 | /* If the prefix string is not empty, then we need to either 22 | * continue the previous branch (with a pipe), or remove 23 | * it altogether if it stopped. */ 24 | strncpy(&_prefix[len - 4], _prefix[len - 4] == '`' ? " " : "| ", 25 | BF_DUMP_TOKEN_LEN); 26 | } 27 | 28 | if (len + BF_DUMP_TOKEN_LEN > DUMP_PREFIX_LEN) 29 | return; 30 | 31 | strncpy(&_prefix[len], "|-- ", BF_DUMP_TOKEN_LEN); 32 | } 33 | 34 | prefix_t *bf_dump_prefix_last(prefix_t *prefix) 35 | { 36 | char *_prefix = *prefix; 37 | size_t len = strlen(_prefix); 38 | 39 | if (len) 40 | strncpy(&_prefix[len - 4], "`-- ", BF_DUMP_TOKEN_LEN); 41 | 42 | return prefix; 43 | } 44 | 45 | void bf_dump_prefix_pop(prefix_t *prefix) 46 | { 47 | char *_prefix = *prefix; 48 | size_t len = strlen(_prefix); 49 | 50 | if (!len) 51 | return; 52 | 53 | _prefix[len - 4] = '\0'; 54 | 55 | // Ensure we have a branch to the next item. 56 | if (len - 4) 57 | strncpy(&_prefix[len - 8], "|-- ", BF_DUMP_TOKEN_LEN); 58 | } 59 | 60 | void bf_dump_hex(prefix_t *prefix, const void *data, size_t len) 61 | { 62 | // 5 characters per byte (0x%02x) + 1 for the null terminator. 63 | char buf[(BF_DUMP_HEXDUMP_LEN * BF_DUMP_TOKEN_LEN) + 1]; 64 | const void *end = data + len; 65 | 66 | while (data < end) { 67 | char *line = buf; 68 | for (size_t i = 0; i < BF_DUMP_HEXDUMP_LEN && data < end; ++i, ++data) 69 | line += sprintf(line, "0x%02x ", *(unsigned char *)data); 70 | 71 | DUMP((data == end ? bf_dump_prefix_last(prefix) : prefix), "%s", buf); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/libbpfilter/dynbuf.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "bpfilter/dynbuf.h" 7 | 8 | #include "bpfilter/helper.h" 9 | #include "bpfilter/logger.h" 10 | 11 | static inline size_t _bf_round_next_power_of_2(size_t value) 12 | { 13 | value--; 14 | value |= value >> 1; 15 | value |= value >> 2; 16 | value |= value >> 4; 17 | value |= value >> 8; 18 | value |= value >> 16; 19 | 20 | return ++value; 21 | } 22 | 23 | void bf_dynbuf_clean(struct bf_dynbuf *buf) 24 | { 25 | bf_assert(buf); 26 | 27 | buf->len = 0; 28 | buf->rem = 0; 29 | freep((void *)&buf->data); 30 | } 31 | 32 | static int _bf_dynbuf_grow(struct bf_dynbuf *buf, size_t req_cap) 33 | { 34 | size_t new_cap; 35 | int r; 36 | 37 | bf_assert(buf); 38 | 39 | if (req_cap == 0) 40 | return 0; 41 | 42 | new_cap = _bf_round_next_power_of_2(buf->len + buf->rem + req_cap); 43 | r = bf_realloc(&buf->data, new_cap); 44 | if (r) 45 | return r; 46 | 47 | buf->rem = new_cap - buf->len; 48 | 49 | return 0; 50 | } 51 | 52 | int bf_dynbuf_write(struct bf_dynbuf *buf, const void *data, size_t data_len) 53 | { 54 | int r; 55 | 56 | bf_assert(buf); 57 | bf_assert(data); 58 | 59 | if (buf->rem < data_len) { 60 | r = _bf_dynbuf_grow(buf, data_len); 61 | if (r) 62 | return r; 63 | } 64 | 65 | memcpy(buf->data + buf->len, data, data_len); 66 | buf->len += data_len; 67 | buf->rem -= data_len; 68 | 69 | return 0; 70 | } 71 | 72 | void *bf_dynbuf_take(struct bf_dynbuf *buf) 73 | { 74 | bf_assert(buf); 75 | 76 | buf->len = 0; 77 | buf->rem = 0; 78 | 79 | return TAKE_PTR(buf->data); 80 | } 81 | -------------------------------------------------------------------------------- /src/libbpfilter/flavor.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "bpfilter/flavor.h" 7 | 8 | #include "bpfilter/helper.h" 9 | 10 | const char *bf_flavor_to_str(enum bf_flavor flavor) 11 | { 12 | static const char *flavor_str[] = { 13 | [BF_FLAVOR_TC] = "BF_FLAVOR_TC", 14 | [BF_FLAVOR_NF] = "BF_FLAVOR_NF", 15 | [BF_FLAVOR_XDP] = "BF_FLAVOR_XDP", 16 | [BF_FLAVOR_CGROUP] = "BF_FLAVOR_CGROUP", 17 | }; 18 | 19 | bf_assert(0 <= flavor && flavor < _BF_FLAVOR_MAX); 20 | static_assert(ARRAY_SIZE(flavor_str) == _BF_FLAVOR_MAX, 21 | "missing entries in flavor_str array"); 22 | 23 | return flavor_str[flavor]; 24 | } 25 | -------------------------------------------------------------------------------- /src/libbpfilter/front.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "bpfilter/front.h" 7 | 8 | #include "bpfilter/helper.h" 9 | 10 | const char *bf_front_to_str(enum bf_front front) 11 | { 12 | bf_assert(front >= 0 && front < _BF_FRONT_MAX); 13 | 14 | static const char * const names[] = { 15 | [BF_FRONT_IPT] = "BF_FRONT_IPT", 16 | [BF_FRONT_NFT] = "BF_FRONT_NFT", 17 | [BF_FRONT_CLI] = "BF_FRONT_CLI", 18 | }; 19 | 20 | static_assert(ARRAY_SIZE(names) == _BF_FRONT_MAX, 21 | "missing fronts in bf_front_to_str()"); 22 | 23 | return names[front]; 24 | } 25 | -------------------------------------------------------------------------------- /src/libbpfilter/generic.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "bpfilter/generic.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "bpfilter/helper.h" 14 | #include "bpfilter/io.h" 15 | #include "bpfilter/logger.h" 16 | 17 | int bf_send(const struct bf_request *request, struct bf_response **response) 18 | { 19 | _cleanup_close_ int fd = -1; 20 | struct sockaddr_un addr = {}; 21 | int r; 22 | 23 | bf_assert(request); 24 | bf_assert(response); 25 | 26 | fd = socket(AF_UNIX, SOCK_STREAM, 0); 27 | if (fd < 0) 28 | return bf_err_r(errno, "bpfilter: can't create socket"); 29 | 30 | addr.sun_family = AF_UNIX; 31 | strncpy(addr.sun_path, BF_SOCKET_PATH, sizeof(addr.sun_path) - 1); 32 | 33 | r = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); 34 | if (r < 0) 35 | return bf_err_r(errno, "bpfilter: failed to connect to socket"); 36 | 37 | r = bf_send_request(fd, request); 38 | if (r < 0) 39 | return bf_err_r(r, "bpfilter: failed to send request to the daemon"); 40 | 41 | r = bf_recv_response(fd, response); 42 | if (r < 0) { 43 | return bf_err_r(r, 44 | "bpfilter: failed to receive response from the daemon"); 45 | } 46 | 47 | return 0; 48 | } 49 | 50 | int bf_send_with_fd(const struct bf_request *request, 51 | struct bf_response **response) 52 | { 53 | bf_assert(request && response); 54 | 55 | _cleanup_close_ int sock_fd = -1; 56 | _cleanup_close_ int fd = -1; 57 | struct sockaddr_un addr = {}; 58 | int r; 59 | 60 | sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); 61 | if (sock_fd < 0) 62 | return bf_err_r(errno, "failed to create socket"); 63 | 64 | addr.sun_family = AF_UNIX; 65 | strncpy(addr.sun_path, BF_SOCKET_PATH, sizeof(addr.sun_path) - 1); 66 | 67 | r = connect(sock_fd, (struct sockaddr *)&addr, sizeof(addr)); 68 | if (r < 0) 69 | return bf_err_r(errno, "failed to connect to socket"); 70 | 71 | r = bf_send_request(sock_fd, request); 72 | if (r < 0) 73 | return bf_err_r(r, "failed to send request to the daemon"); 74 | 75 | fd = bf_recv_fd(sock_fd); 76 | if (fd < 0) 77 | return bf_err_r(fd, "failed to receive file descriptor"); 78 | 79 | r = bf_recv_response(sock_fd, response); 80 | if (r < 0) 81 | return bf_err_r(r, "failed to receive response from the daemon"); 82 | 83 | return TAKE_FD(fd); 84 | } 85 | -------------------------------------------------------------------------------- /src/libbpfilter/if.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | // clang-format off 7 | // Include net/if.h before any kernel header to avoid conflicts. 8 | #include 9 | // clang-format on 10 | 11 | #include "bpfilter/if.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "bpfilter/helper.h" 20 | #include "bpfilter/logger.h" 21 | 22 | static char _bf_if_name[IFNAMSIZ]; 23 | 24 | int bf_if_index_from_name(const char *name) 25 | { 26 | unsigned int r; 27 | 28 | bf_assert(name); 29 | 30 | r = if_nametoindex(name); 31 | if (r == 0) 32 | return -ENOENT; 33 | 34 | if (r > INT_MAX) 35 | return -E2BIG; 36 | 37 | return (int)r; 38 | } 39 | 40 | const char *bf_if_name_from_index(int index) 41 | { 42 | if (!if_indextoname(index, _bf_if_name)) 43 | return NULL; 44 | 45 | return _bf_if_name; 46 | } 47 | 48 | ssize_t bf_if_get_ifaces(struct bf_if_iface **ifaces) 49 | { 50 | _cleanup_free_ struct bf_if_iface *_ifaces = NULL; 51 | struct if_nameindex *if_ni, *it; 52 | ssize_t n_ifaces = 0; 53 | size_t i = 0; 54 | 55 | bf_assert(ifaces); 56 | 57 | if_ni = if_nameindex(); 58 | if (!if_ni) 59 | return bf_err_r(errno, "failed to fetch interfaces details"); 60 | 61 | // Gather the number of interfaces to allocate the memory. 62 | for (it = if_ni; it->if_index != 0 || it->if_name != NULL; ++it) 63 | ++n_ifaces; 64 | 65 | if (n_ifaces == 0) 66 | return 0; 67 | 68 | _ifaces = malloc(n_ifaces * sizeof(*_ifaces)); 69 | if (!_ifaces) { 70 | if_freenameindex(if_ni); 71 | return bf_err_r(-ENOMEM, 72 | "failed to allocate memory for interfaces buffer"); 73 | } 74 | 75 | for (it = if_ni; it->if_index != 0 || it->if_name != NULL; ++it) { 76 | _ifaces[i].index = it->if_index; 77 | 78 | if (it->if_index) 79 | strncpy(_ifaces[i].name, it->if_name, IF_NAMESIZE); 80 | else 81 | bf_warn("interface %d has no name", it->if_index); 82 | 83 | ++i; 84 | } 85 | 86 | *ifaces = TAKE_PTR(_ifaces); 87 | 88 | if_freenameindex(if_ni); 89 | 90 | return n_ifaces; 91 | } 92 | -------------------------------------------------------------------------------- /src/libbpfilter/include/bpfilter/bpf_types.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | enum bf_bpf_cmd 9 | { 10 | BF_BPF_PROG_LOAD = 5, 11 | BF_BPF_MAP_LOOKUP_ELEM = 1, 12 | BF_BPF_OBJ_PIN = 6, 13 | BF_BPF_OBJ_GET = 7, 14 | BF_BPF_PROG_TEST_RUN = 10, 15 | BF_BPF_TOKEN_CREATE = 36, 16 | BF_BPF_BTF_LOAD = 18, 17 | BF_BPF_MAP_CREATE = 0, 18 | BF_BPF_MAP_UPDATE_ELEM = 2, 19 | BF_BPF_MAP_UPDATE_BATCH = 26, 20 | BF_BPF_LINK_CREATE = 28, 21 | BF_BPF_LINK_UPDATE = 29, 22 | BF_BPF_LINK_DETACH = 34, 23 | }; 24 | 25 | enum bf_bpf_prog_type 26 | { 27 | BF_BPF_PROG_TYPE_XDP = 6, 28 | BF_BPF_PROG_TYPE_SCHED_CLS = 3, 29 | BF_BPF_PROG_TYPE_CGROUP_SKB = 8, 30 | BF_BPF_PROG_TYPE_NETFILTER = 32, 31 | }; 32 | 33 | enum bf_bpf_attach_type 34 | { 35 | BF_BPF_XDP = 37, 36 | BF_BPF_NETFILTER = 45, 37 | BF_BPF_TCX_INGRESS = 46, 38 | BF_BPF_TCX_ENGRESS = 47, 39 | BF_BPF_CGROUP_INET_INGRESS = 0, 40 | BF_BPF_CGROUP_INET_EGRESS = 1, 41 | }; 42 | 43 | enum bf_bpf_map_type 44 | { 45 | BF_BPF_MAP_TYPE_HASH = 1, 46 | BF_BPF_MAP_TYPE_ARRAY = 2, 47 | BF_BPF_MAP_TYPE_LPM_TRIE = 11, 48 | BF_BPF_MAP_TYPE_RINGBUF = 27, 49 | }; 50 | -------------------------------------------------------------------------------- /src/libbpfilter/include/bpfilter/btf.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | struct bf_btf 11 | { 12 | struct btf *btf; 13 | uint32_t key_type_id; 14 | uint32_t value_type_id; 15 | int fd; 16 | }; 17 | 18 | /** 19 | * Load current kernel's BTF data. 20 | * 21 | * This function has to be called early, so BPF program generation can access 22 | * kernel's BTF data and use the kfunc's BTF ID. 23 | * 24 | * @return 0 on success, or negative errno value on failure. 25 | */ 26 | int bf_btf_setup(void); 27 | 28 | /** 29 | * Free current kernel's BTF data. 30 | */ 31 | void bf_btf_teardown(void); 32 | 33 | /** 34 | * Get BTF ID of a kernel function. 35 | * 36 | * Linux' BTF data must be loaded with @ref bf_btf_setup before calling this 37 | * function. 38 | * 39 | * @param name Name of the kernel function. 40 | * @return BTF ID on success, or negative errno value on failure. 41 | */ 42 | int bf_btf_get_id(const char *name); 43 | 44 | /** 45 | * Get a type name from a BTF ID from the kernel BTF data. 46 | * 47 | * Linux BTF data must be loaded with @ref bf_btf_setup before calling this 48 | * function. If @c id is invalid, or not part of the kernel's BTF data, @c NULL 49 | * is returned. 50 | * 51 | * @param id Type ID to look for. 52 | * @return Name of the type represented by @c id or @c NULL . 53 | */ 54 | const char *bf_btf_get_name(int id); 55 | 56 | /** 57 | * Check if BPF token is supported by the current system. 58 | * 59 | * Read the kernel's BTF data to check if `prog_token_fd` is a valid field, if 60 | * so it is assume BPF token is supported by the current kernel. 61 | * 62 | * @return 0 on success, or a negative errno value on failure, including: 63 | * - `-ENOENT`: `prog_token_fd` can't be found, meaning BPF token is likely 64 | * unsupported. 65 | */ 66 | int bf_btf_kernel_has_token(void); 67 | 68 | /** 69 | * Get the offset of a field in a kernel structure. 70 | * 71 | * Use Linux' BTF data to find the offset of a specific field in a structure. 72 | * This function will fail if the offset of a bitfield is requested. 73 | * 74 | * @param struct_name Name of the structure to find the offset in. Can't be 75 | * NULL. 76 | * @param field_name Name of the field to get the offset of. Can't be NULL. 77 | * @return Offset of @p field_name if found, negative error value on failure. 78 | */ 79 | int bf_btf_get_field_off(const char *struct_name, const char *field_name); 80 | -------------------------------------------------------------------------------- /src/libbpfilter/include/bpfilter/counter.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | /** 14 | * @struct bf_counter 15 | * 16 | * Counters assigned to each rule. 17 | * 18 | * @var bf_counter::packets 19 | * Number of packets gone through a rule. 20 | * @var bf_counter::bytes 21 | * Number of bytes gone through a rule. 22 | */ 23 | struct bf_counter 24 | { 25 | uint64_t packets; 26 | uint64_t bytes; 27 | }; 28 | 29 | #define _free_bf_counter_ __attribute__((__cleanup__(bf_counter_free))) 30 | 31 | /** 32 | * Create a new @ref bf_counter with the given packets and bytes. 33 | * 34 | * On success, @p counter is set to the newly allocated @ref bf_counter, 35 | * owned by the caller. 36 | * 37 | * @param counter Output pointer for the new @ref bf_counter. Can't be NULL. 38 | * @param packets Initial packet count. 39 | * @param bytes Initial byte count. 40 | * @return 0 on success, negative errno on error. 41 | */ 42 | int bf_counter_new(struct bf_counter **counter, uint64_t packets, 43 | uint64_t bytes); 44 | 45 | /** 46 | * @brief Allocate and initialize a new counter from serialized data. 47 | * 48 | * @param counter Counter object to allocate and initialize from the serialized 49 | * data. The caller will own the object. On failure, `*counter` is 50 | * unchanged. Can't be NULL. 51 | * @param node Node containing the serialized counter. Can't be NULL. 52 | * @return 0 on success, or a negative errno value on failure. 53 | */ 54 | int bf_counter_new_from_pack(struct bf_counter **counter, bf_rpack_node_t node); 55 | 56 | /** 57 | * Free a @ref bf_counter structure. 58 | * 59 | * If @p counter is NULL, nothing is done. 60 | * 61 | * @param counter Counter to free. Can't be NULL. 62 | */ 63 | void bf_counter_free(struct bf_counter **counter); 64 | 65 | /** 66 | * @brief Serialize a counter. 67 | * 68 | * @param counter Counter to serialize. Can't be NULL. 69 | * @param pack `bf_wpack_t` object to serialize the counter into. Can't be NULL. 70 | * @return 0 on success, or a negative error value on failure. 71 | */ 72 | int bf_counter_pack(const struct bf_counter *counter, bf_wpack_t *pack); 73 | -------------------------------------------------------------------------------- /src/libbpfilter/include/bpfilter/dump.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include 11 | 12 | /** 13 | * Dump prefixed-formatted string. 14 | * 15 | * @param p Prefix string. 16 | * @param fmt Log format string. 17 | * @param ... Variadic argument list for @p fmt. 18 | */ 19 | #define DUMP(p, fmt, ...) bf_dbg("%s" fmt, (*p), ##__VA_ARGS__); 20 | 21 | /** 22 | * Split 32 bits IPv4 representation into four 8 bits components. 23 | * 24 | * @param addr 32 bits IPv4 address to split. 25 | */ 26 | #define IP4_SPLIT(addr) \ 27 | ((unsigned char *)&(addr))[0], ((unsigned char *)&(addr))[1], \ 28 | ((unsigned char *)&(addr))[2], ((unsigned char *)&(addr))[3] 29 | 30 | /// Format to use with @ref IP4_SPLIT to print an IPv4. 31 | #define IP4_FMT "%d.%d.%d.%d" 32 | 33 | /** 34 | * Split a byte into 8 characters representing each bit. 35 | * 36 | * @param byte Byte to split. 37 | */ 38 | #define BIN_SPLIT(byte) \ 39 | (((byte) & 0x80) + 0x30), (((byte) & 0x40) + 0x30), \ 40 | (((byte) & 0x20) + 0x30), (((byte) & 0x10) + 0x30), \ 41 | (((byte) & 0x08) + 0x30), (((byte) & 0x04) + 0x30), \ 42 | (((byte) & 0x02) + 0x30), (((byte) & 0x01) + 0x30) 43 | 44 | /// Format to use with BIN_SPLIT() to print a byte as 8 bits. 45 | #define BIN_FMT "%c%c%c%c%c%c%c%c" 46 | 47 | /// Maximum length of the prefix buffer. 48 | #define DUMP_PREFIX_LEN 65 49 | 50 | /// Empty prefix for dump functions 51 | #define EMPTY_PREFIX ((prefix_t[]) {{}}) 52 | 53 | typedef char(prefix_t)[DUMP_PREFIX_LEN]; 54 | 55 | /** 56 | * Add a symbol to the prefix string. 57 | * 58 | * @param prefix Prefix string. 59 | */ 60 | void bf_dump_prefix_push(prefix_t *prefix); 61 | 62 | /** 63 | * Convert previous node to make is the last of the branch. 64 | * 65 | * @param prefix Prefix string. 66 | * @return @p prefix 67 | */ 68 | prefix_t *bf_dump_prefix_last(prefix_t *prefix); 69 | 70 | /** 71 | * Remove rightmost branch from the prefix string. 72 | * 73 | * When a subtree is completed and we backout to a different branch, we need 74 | * to remove the rightmost branch from the prefix to continue. 75 | * 76 | * @param prefix Prefix string. 77 | */ 78 | void bf_dump_prefix_pop(prefix_t *prefix); 79 | 80 | /** 81 | * Dump the data buffer in hexedecimal format. 82 | * 83 | * Each byte in @p data will be printed as 0x%02x, with 8 bytes on each row. 84 | * 85 | * @param prefix Prefix string. 86 | * @param data Data buffer to print. 87 | * @param len Size of the data buffer. 88 | */ 89 | void bf_dump_hex(prefix_t *prefix, const void *data, size_t len); 90 | -------------------------------------------------------------------------------- /src/libbpfilter/include/bpfilter/dynbuf.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | struct bf_dynbuf; 11 | 12 | #define _clean_bf_dynbuf_ __attribute__((cleanup(bf_dynbuf_clean))) 13 | 14 | struct bf_dynbuf 15 | { 16 | size_t len; 17 | size_t rem; 18 | void *data; 19 | }; 20 | 21 | #define bf_dynbuf_default() \ 22 | (struct bf_dynbuf) \ 23 | { \ 24 | .len = 0, .rem = 0, .data = NULL \ 25 | } 26 | 27 | void bf_dynbuf_clean(struct bf_dynbuf *buf); 28 | int bf_dynbuf_write(struct bf_dynbuf *buf, const void *data, size_t data_len); 29 | void *bf_dynbuf_take(struct bf_dynbuf *buf); 30 | -------------------------------------------------------------------------------- /src/libbpfilter/include/bpfilter/front.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | enum bf_front 9 | { 10 | BF_FRONT_IPT, 11 | BF_FRONT_NFT, 12 | BF_FRONT_CLI, 13 | _BF_FRONT_MAX, 14 | }; 15 | 16 | /** 17 | * Get a bpfilter front type as a string. 18 | * 19 | * @param front Valid front type. 20 | * @return String representation of the front type. 21 | */ 22 | const char *bf_front_to_str(enum bf_front front); 23 | -------------------------------------------------------------------------------- /src/libbpfilter/include/bpfilter/generic.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | struct bf_request; 9 | struct bf_response; 10 | 11 | int bf_send(const struct bf_request *request, struct bf_response **response); 12 | 13 | /** 14 | * @brief Send a request to the daemon, receive a file descriptor and a 15 | * response. 16 | * 17 | * Some request types require the daemon to return a file descriptor 18 | * (e.g. `BF_REQ_CHAIN_LOGS_FD`), which the standard `bf_send()` function cant' 19 | * do. 20 | * 21 | * @pre 22 | * - `request` is a valid, non-NULL request 23 | * - `response != NULL` 24 | * 25 | * @param request Request to send to the daemon. 26 | * @param response Response received from the daemon, allocated by 27 | * `bf_send_with_fd()`. 28 | * @return A valid file descriptor, or a negative error value on failure. 29 | * `response` and the returned file descriptor are owned by the caller. 30 | */ 31 | int bf_send_with_fd(const struct bf_request *request, 32 | struct bf_response **response); 33 | -------------------------------------------------------------------------------- /src/libbpfilter/include/bpfilter/if.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | /** 11 | * @file if.h 12 | * 13 | * Header files `net/if.h` and `arpa/inet.h` are incompatible with some kernel 14 | * headers, due to symbols being defined in both. However, the Linux kernel used 15 | * in `bpfilter` are mandatory, we can't do without them. In order to avoid 16 | * further issues due to this incompatibility, `net/if.h` and `arpa/inet/h` are 17 | * now hidden in `if.c`, and `bpfilter`-specific functions have been defined to 18 | * provide the required functionalities. 19 | */ 20 | 21 | #ifndef IFNAMSIZ 22 | #define IFNAMSIZ 16 23 | #endif 24 | 25 | /** 26 | * Local interface details. 27 | */ 28 | struct bf_if_iface 29 | { 30 | /// Index of the interface on the system. 31 | unsigned int index; 32 | /// Name of the interface. 33 | char name[IFNAMSIZ]; 34 | }; 35 | 36 | /** 37 | * Get an interface index from its name. 38 | * 39 | * @param name Name of the interface. Can't be NULL. 40 | * @return Index of the interface. If the interface name is unknown, a 41 | * negative errno value is returned. 42 | */ 43 | int bf_if_index_from_name(const char *name); 44 | 45 | /** 46 | * Get an interface name from its index. 47 | * 48 | * This function copy the interface name into a static buffer, this would 49 | * probably be an issue for multi-threaded application, but thankfully bpfilter 50 | * is a single-threaded daemon. 51 | * 52 | * @param index Index of the interface. 53 | * @return Pointer to a static buffer containing the interface name, or NULL 54 | * if the interface name is not found. 55 | */ 56 | const char *bf_if_name_from_index(int index); 57 | 58 | /** 59 | * Get the index and name of all the interfaces on the host. 60 | * 61 | * @param ifaces Array of @ref bf_if_iface structures. The array will be 62 | * allocated by the function and the caller is responsible for freeing it. 63 | * @return On success, return the number of interfaces contained in @p ifaces . 64 | * On failure, return a negative errno value. 65 | */ 66 | ssize_t bf_if_get_ifaces(struct bf_if_iface **ifaces); 67 | -------------------------------------------------------------------------------- /src/libbpfilter/include/bpfilter/response.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #define _free_bf_response_ __attribute__((cleanup(bf_response_free))) 14 | 15 | struct bf_dynbuf; 16 | struct bf_response; 17 | 18 | /** 19 | * Allocate a response without copying data. 20 | * 21 | * Space will be allocated in the response for @p data_len bytes of data, but 22 | * no data will be copied, nor will the response's data be initialized. 23 | * 24 | * The response's status will be set to 0. 25 | * 26 | * @param response Pointer to the response to allocate. Must be non-NULL. 27 | * @param data_len Size of the data to allocate. 28 | * @return 0 on success, or negative errno code on failure. 29 | */ 30 | int bf_response_new_raw(struct bf_response **response, size_t data_len); 31 | 32 | /** 33 | * Allocate and initialise a new successful response. 34 | * 35 | * @param response Pointer to the response to allocate. Must be non-NULL. 36 | * @param data Client-specific data. 37 | * @param data_len Length of the client-specific data. 38 | * @return 0 on success, or negative errno code on failure. 39 | */ 40 | int bf_response_new_success(struct bf_response **response, const char *data, 41 | size_t data_len); 42 | 43 | int bf_response_new_from_dynbuf(struct bf_response **response, 44 | struct bf_dynbuf *dynbuf); 45 | int bf_response_new_from_pack(struct bf_response **response, bf_wpack_t *pack); 46 | 47 | /** 48 | * Allocate and initialise a new failure response. 49 | * 50 | * @param response Pointer to the response to allocate. Must be non-NULL. 51 | * @param error Error code that store in the response. 52 | * @return 0 on success, or negative errno code on failure. 53 | */ 54 | int bf_response_new_failure(struct bf_response **response, int error); 55 | 56 | /** 57 | * Free a response. 58 | * 59 | * If @p response points to a NULL pointer, this function does nothing. Once the 60 | * function returns, @p response points to a NULL pointer. 61 | * 62 | * @param response Response to free. Can't be NULL. 63 | */ 64 | void bf_response_free(struct bf_response **response); 65 | 66 | /** 67 | * Copy a response. 68 | * 69 | * @param dest The destination response. It will be allocated during the call. 70 | * Can't be NULL. 71 | * @param src The source response, to copy. Can't be NULL. 72 | * @return 0 on success, negative error code on failure. 73 | */ 74 | int bf_response_copy(struct bf_response **dest, const struct bf_response *src); 75 | 76 | int bf_response_status(const struct bf_response *response); 77 | const void *bf_response_data(const struct bf_response *response); 78 | size_t bf_response_data_len(const struct bf_response *response); 79 | 80 | /** 81 | * Get the total size of the response: request structure and data (if any). 82 | * 83 | * @param response Response to get the size of. Can't be NULL. 84 | * @return Total size of the response. 85 | */ 86 | size_t bf_response_size(const struct bf_response *response); 87 | -------------------------------------------------------------------------------- /src/libbpfilter/include/bpfilter/verdict.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | /** 9 | * Verdict to apply for a rule or chain. 10 | * Chains can only use terminal verdicts, rules can use all verdicts. 11 | */ 12 | enum bf_verdict 13 | { 14 | /** Terminal verdicts that stop further packet processing. */ 15 | /** Accept the packet. */ 16 | BF_VERDICT_ACCEPT, 17 | /** Drop the packet. */ 18 | BF_VERDICT_DROP, 19 | /** Non-terminal verdicts that allow further packet processing. */ 20 | /** Continue processing the next rule. */ 21 | BF_VERDICT_CONTINUE, 22 | _BF_VERDICT_MAX, 23 | _BF_TERMINAL_VERDICT_MAX = BF_VERDICT_CONTINUE, 24 | }; 25 | 26 | /** 27 | * Convert a verdict value into a string. 28 | * 29 | * @param verdict The verdict to convert, must be valid. 30 | * @return String representation of the verdict. 31 | */ 32 | const char *bf_verdict_to_str(enum bf_verdict verdict); 33 | 34 | /** 35 | * Convert a string into a verdict value. 36 | * 37 | * @param str String to convert to a verdict. Can't be NULL. 38 | * @param verdict String representation of the verdict. Can't be NULL. 39 | * @return 0 on success, or negative errno value on error. 40 | */ 41 | int bf_verdict_from_str(const char *str, enum bf_verdict *verdict); 42 | -------------------------------------------------------------------------------- /src/libbpfilter/include/bpfilter/version.h.in: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #define BF_VERSION "@PROJECT_VERSION@@PROJECT_VERSION_SUFFIX@" 9 | 10 | const char *bf_version(void); 11 | -------------------------------------------------------------------------------- /src/libbpfilter/nft.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "bpfilter/front.h" 13 | #include "bpfilter/generic.h" 14 | #include "bpfilter/request.h" 15 | #include "bpfilter/response.h" 16 | 17 | int bf_nft_send(const void *data, size_t len) 18 | { 19 | _free_bf_request_ struct bf_request *request = NULL; 20 | _free_bf_response_ struct bf_response *response = NULL; 21 | int r; 22 | 23 | if (!data || !len) 24 | return -EINVAL; 25 | 26 | r = bf_request_new(&request, BF_FRONT_NFT, 0, data, len); 27 | if (r < 0) 28 | return r; 29 | 30 | r = bf_send(request, &response); 31 | if (r < 0) 32 | return r; 33 | 34 | return bf_response_status(response); 35 | } 36 | 37 | int bf_nft_sendrecv(const struct nlmsghdr *req, size_t req_len, 38 | struct nlmsghdr *res, size_t *res_len) 39 | { 40 | _free_bf_request_ struct bf_request *request = NULL; 41 | _free_bf_response_ struct bf_response *response = NULL; 42 | int r; 43 | 44 | if (!req || !req_len || !res || !res_len) 45 | return -EINVAL; 46 | 47 | if (req_len != req->nlmsg_len) 48 | return -EINVAL; 49 | 50 | r = bf_request_new(&request, BF_FRONT_NFT, 0, req, req_len); 51 | if (r < 0) 52 | return r; 53 | 54 | r = bf_send(request, &response); 55 | if (r < 0) 56 | return r; 57 | 58 | if (bf_response_status(response) != 0) 59 | return bf_response_status(response); 60 | 61 | // The response should be a netlink message 62 | if (bf_response_data_len(response) < NLMSG_HDRLEN) 63 | return -EMSGSIZE; 64 | 65 | if (((const struct nlmsghdr *)bf_response_data(response))->nlmsg_len != 66 | bf_response_data_len(response)) 67 | return -EMSGSIZE; 68 | 69 | if (bf_response_data_len(response) > *res_len) { 70 | *res_len = bf_response_data_len(response); 71 | return -EMSGSIZE; 72 | } 73 | 74 | memcpy(res, bf_response_data(response), bf_response_data_len(response)); 75 | *res_len = bf_response_data_len(response); 76 | 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /src/libbpfilter/ns.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #define _GNU_SOURCE 7 | 8 | #include "bpfilter/ns.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "bpfilter/helper.h" 18 | #include "bpfilter/logger.h" 19 | 20 | #define NS_DIR_PATH_LEN 32 21 | 22 | /** 23 | * Initialize a `bf_ns_info` structure for a given namespace. 24 | * 25 | * @param info `bf_ns_info` object to initialise. On failure, this parameter is 26 | * unchanged. Can't be NULL. 27 | * @param name Name of the namespace to open. Can't be NULL. 28 | * @param dir_fd File descriptor of the directory to open the namespace from. 29 | * @return 0 on success, or a negative errno value on failure. 30 | */ 31 | static int _bf_ns_info_init(struct bf_ns_info *info, const char *name, 32 | int dir_fd) 33 | { 34 | _cleanup_close_ int fd = -1; 35 | struct stat stats; 36 | int r; 37 | 38 | bf_assert(info && name); 39 | 40 | fd = openat(dir_fd, name, O_RDONLY, 0); 41 | if (fd < 0) 42 | return -errno; 43 | 44 | r = fstat(fd, &stats); 45 | if (r) 46 | return -errno; 47 | 48 | info->fd = TAKE_FD(fd); 49 | info->inode = stats.st_ino; 50 | 51 | return 0; 52 | } 53 | 54 | int bf_ns_init(struct bf_ns *ns, pid_t pid) 55 | { 56 | _clean_bf_ns_ struct bf_ns _ns = bf_ns_default(); 57 | _cleanup_close_ int dirfd = -1; 58 | char ns_dir_path[NS_DIR_PATH_LEN]; 59 | int r; 60 | 61 | bf_assert(ns); 62 | 63 | /// @todo What if ``/proc`` is not readable? 64 | (void)snprintf(ns_dir_path, NS_DIR_PATH_LEN, "/proc/%d/ns", pid); 65 | dirfd = open(ns_dir_path, O_DIRECTORY, O_RDONLY); 66 | if (dirfd < 0) 67 | return bf_err_r(errno, "failed to open ns directory '%s'", ns_dir_path); 68 | 69 | r = _bf_ns_info_init(&_ns.net, "net", dirfd); 70 | if (r) { 71 | return bf_err_r(r, "failed to read 'net' namespace in '%s'", 72 | ns_dir_path); 73 | } 74 | 75 | r = _bf_ns_info_init(&_ns.mnt, "mnt", dirfd); 76 | if (r) { 77 | return bf_err_r(r, "failed to read 'mnt' namespace in '%s'", 78 | ns_dir_path); 79 | } 80 | 81 | *ns = bf_ns_move(_ns); 82 | 83 | return 0; 84 | } 85 | 86 | void bf_ns_clean(struct bf_ns *ns) 87 | { 88 | bf_assert(ns); 89 | 90 | closep(&ns->net.fd); 91 | closep(&ns->mnt.fd); 92 | } 93 | 94 | int bf_ns_set(const struct bf_ns *ns, const struct bf_ns *oldns) 95 | { 96 | int r; 97 | 98 | if (!oldns || ns->net.inode != oldns->net.inode) { 99 | r = setns(ns->net.fd, CLONE_NEWNET); 100 | if (r) 101 | return bf_err_r(r, "failed to switch to a network namespace"); 102 | } 103 | 104 | if (!oldns || ns->mnt.inode != oldns->mnt.inode) { 105 | r = setns(ns->mnt.fd, CLONE_NEWNS); 106 | if (r) 107 | return bf_err_r(r, "failed to switch to a mount namespace"); 108 | } 109 | 110 | return 0; 111 | } 112 | -------------------------------------------------------------------------------- /src/libbpfilter/verdict.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "bpfilter/verdict.h" 7 | 8 | #include 9 | #include 10 | 11 | #include "bpfilter/helper.h" 12 | 13 | static const char *_bf_verdict_strs[] = { 14 | [BF_VERDICT_ACCEPT] = "ACCEPT", 15 | [BF_VERDICT_DROP] = "DROP", 16 | [BF_VERDICT_CONTINUE] = "CONTINUE", 17 | }; 18 | 19 | static_assert(ARRAY_SIZE(_bf_verdict_strs) == _BF_VERDICT_MAX, 20 | "missing entries in the verdict array"); 21 | 22 | const char *bf_verdict_to_str(enum bf_verdict verdict) 23 | { 24 | bf_assert(0 <= verdict && verdict < _BF_VERDICT_MAX); 25 | 26 | return _bf_verdict_strs[verdict]; 27 | } 28 | 29 | int bf_verdict_from_str(const char *str, enum bf_verdict *verdict) 30 | { 31 | bf_assert(str); 32 | bf_assert(verdict); 33 | 34 | for (size_t i = 0; i < _BF_VERDICT_MAX; ++i) { 35 | if (bf_streq(_bf_verdict_strs[i], str)) { 36 | *verdict = i; 37 | return 0; 38 | } 39 | } 40 | 41 | return -EINVAL; 42 | } 43 | -------------------------------------------------------------------------------- /src/libbpfilter/version.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "bpfilter/version.h" 7 | 8 | const char *bf_version(void) 9 | { 10 | return BF_VERSION; 11 | } 12 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 3 | 4 | add_subdirectory(harness) 5 | 6 | add_subdirectory(unit) 7 | add_subdirectory(e2e) 8 | add_subdirectory(pedantic) 9 | 10 | add_subdirectory(integration) 11 | 12 | add_custom_target(test 13 | COMMAND 14 | ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/unit -- unit 15 | COMMAND 16 | ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/e2e -- e2e 17 | COMMAND 18 | ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/pedantic -- pedantic 19 | COMMENT "Running the test suite" 20 | ) 21 | -------------------------------------------------------------------------------- /tests/e2e/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 3 | 4 | find_package(Python3 COMPONENTS Interpreter) 5 | 6 | add_custom_command( 7 | COMMAND 8 | ${CMAKE_COMMAND} 9 | -E make_directory 10 | ${CMAKE_CURRENT_BINARY_DIR}/include 11 | COMMAND 12 | Python3::Interpreter 13 | ${CMAKE_CURRENT_SOURCE_DIR}/genpkts.py 14 | --output ${CMAKE_CURRENT_BINARY_DIR}/include/packets.h 15 | DEPENDS 16 | ${CMAKE_CURRENT_SOURCE_DIR}/genpkts.py 17 | OUTPUT 18 | ${CMAKE_CURRENT_BINARY_DIR}/include/packets.h 19 | COMMENT "Generating the end-to-end test packets" 20 | ) 21 | 22 | add_executable(e2e_bin EXCLUDE_FROM_ALL 23 | ${CMAKE_CURRENT_SOURCE_DIR}/main.c 24 | ${CMAKE_CURRENT_SOURCE_DIR}/e2e.c ${CMAKE_CURRENT_SOURCE_DIR}/e2e.h 25 | ${CMAKE_CURRENT_SOURCE_DIR}/opts.c ${CMAKE_CURRENT_SOURCE_DIR}/opts.h 26 | ${CMAKE_CURRENT_BINARY_DIR}/include/packets.h 27 | ) 28 | 29 | target_include_directories(e2e_bin 30 | PRIVATE 31 | ${CMAKE_CURRENT_BINARY_DIR}/include 32 | ${CMAKE_SOURCE_DIR}/src/bpfilter 33 | ) 34 | 35 | target_link_libraries(e2e_bin 36 | PRIVATE 37 | harness 38 | libbpfilter 39 | ) 40 | 41 | add_executable(setuserns_bin EXCLUDE_FROM_ALL 42 | ${CMAKE_CURRENT_SOURCE_DIR}/setuserns.c 43 | ) 44 | 45 | target_link_libraries(setuserns_bin 46 | PRIVATE 47 | bf_global_flags 48 | libbpfilter 49 | ) 50 | 51 | add_custom_target(e2e 52 | COMMAND 53 | ${CMAKE_SOURCE_DIR}/tools/asroot 54 | $ 55 | --bpfilter $ 56 | COMMAND 57 | ${CMAKE_SOURCE_DIR}/tools/asroot 58 | ${CMAKE_CURRENT_SOURCE_DIR}/cli.sh 59 | --bpfilter $ 60 | --bfcli $ 61 | --setuserns $ 62 | --rulesets-dir ${CMAKE_CURRENT_SOURCE_DIR}/rulesets 63 | COMMENT "Running end-to-end tests" 64 | ) 65 | -------------------------------------------------------------------------------- /tests/e2e/e2e.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | #include "bpfilter/chain.h" 12 | #include "bpfilter/counter.h" 13 | #include "bpfilter/verdict.h" 14 | #include "packets.h" 15 | 16 | #define BFT_NO_PKTS SIZE_MAX 17 | #define BFT_NO_BYTES SIZE_MAX 18 | 19 | struct bft_counter 20 | { 21 | size_t index; 22 | struct bf_counter counter; 23 | }; 24 | 25 | #define bft_counter_p(idx, npkts, nbytes) \ 26 | (struct bft_counter []) { \ 27 | { \ 28 | .index = (idx), \ 29 | .counter = { \ 30 | .packets = (npkts), \ 31 | .bytes = (nbytes), \ 32 | }, \ 33 | } \ 34 | } 35 | 36 | int bft_e2e_test_with_counter(struct bf_chain *chain, enum bf_verdict expect, 37 | const struct bft_prog_run_args *args, 38 | const struct bft_counter *counter); 39 | int bft_e2e_test(struct bf_chain *chain, enum bf_verdict expect, 40 | const struct bft_prog_run_args *args); 41 | -------------------------------------------------------------------------------- /tests/e2e/opts.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "opts.h" 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include "bpfilter/helper.h" 13 | 14 | static struct 15 | { 16 | char bpfilter_path[PATH_MAX]; 17 | } _bf_opts = { 18 | .bpfilter_path = "bpfilter", 19 | }; 20 | 21 | static struct argp_option _bf_e2e_options[] = { 22 | {"bpfilter", 'b', "BPFILTER", 0, 23 | "Path to the bpfilter daemon binary. Defaults to 'bpfilter' in PATH", 0}, 24 | {0}, 25 | }; 26 | 27 | static error_t _bf_e2e_argp_cb(int key, char *arg, struct argp_state *state) 28 | { 29 | UNUSED(state); 30 | 31 | switch (key) { 32 | case 'b': 33 | bf_strncpy(_bf_opts.bpfilter_path, PATH_MAX, arg); 34 | break; 35 | default: 36 | return ARGP_ERR_UNKNOWN; 37 | } 38 | 39 | return 0; 40 | } 41 | 42 | int bft_e2e_parse_args(int argc, char *argv[]) 43 | { 44 | struct argp argp = { _bf_e2e_options, _bf_e2e_argp_cb, NULL, NULL, 0, NULL, NULL}; 45 | 46 | return -argp_parse(&argp, argc, argv, 0, 0, NULL); 47 | } 48 | 49 | const char *bft_e2e_bpfilter_path(void) 50 | { 51 | return _bf_opts.bpfilter_path; 52 | } 53 | -------------------------------------------------------------------------------- /tests/e2e/opts.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | int bft_e2e_parse_args(int argc, char *argv[]); 9 | const char *bft_e2e_bpfilter_path(void); 10 | -------------------------------------------------------------------------------- /tests/harness/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 3 | 4 | find_package(PkgConfig REQUIRED) 5 | pkg_check_modules(bpf REQUIRED IMPORTED_TARGET libbpf) 6 | pkg_check_modules(cmocka REQUIRED IMPORTED_TARGET cmocka) 7 | pkg_check_modules(nl REQUIRED IMPORTED_TARGET libnl-3.0) 8 | 9 | add_library(harness EXCLUDE_FROM_ALL 10 | STATIC 11 | ${CMAKE_CURRENT_SOURCE_DIR}/daemon.h ${CMAKE_CURRENT_SOURCE_DIR}/daemon.c 12 | ${CMAKE_CURRENT_SOURCE_DIR}/filters.h ${CMAKE_CURRENT_SOURCE_DIR}/filters.c 13 | ${CMAKE_CURRENT_SOURCE_DIR}/mock.h ${CMAKE_CURRENT_SOURCE_DIR}/mock.c 14 | ${CMAKE_CURRENT_SOURCE_DIR}/process.h ${CMAKE_CURRENT_SOURCE_DIR}/process.c 15 | ${CMAKE_CURRENT_SOURCE_DIR}/prog.h ${CMAKE_CURRENT_SOURCE_DIR}/prog.c 16 | ${CMAKE_CURRENT_SOURCE_DIR}/test.h ${CMAKE_CURRENT_SOURCE_DIR}/test.c 17 | ) 18 | 19 | target_include_directories(harness 20 | PRIVATE 21 | ${CMAKE_CURRENT_SOURCE_DIR} 22 | PUBLIC 23 | ${CMAKE_SOURCE_DIR}/tests 24 | ${CMAKE_SOURCE_DIR}/external/include 25 | ) 26 | 27 | target_link_libraries(harness 28 | PUBLIC 29 | bf_global_flags 30 | libbpfilter 31 | PkgConfig::bpf 32 | PkgConfig::cmocka 33 | PkgConfig::nl 34 | ) 35 | -------------------------------------------------------------------------------- /tests/harness/daemon.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | #include "harness/process.h" 12 | 13 | /** 14 | * @file daemon.h 15 | * 16 | * bf_test_daemon represents a handle to manage the `bpfilter` daemon. Based 17 | * on the primitives defined in `harness/process.h`. 18 | */ 19 | 20 | struct bf_test_daemon 21 | { 22 | struct bf_test_process process; 23 | }; 24 | 25 | /** 26 | * Options to configure the daemon. 27 | * 28 | * Not all the options defined for `bpfilter` need to be defined below. 29 | */ 30 | enum bf_test_daemon_option 31 | { 32 | BF_TEST_DAEMON_TRANSIENT = 1 << 0, 33 | BF_TEST_DAEMON_NO_CLI = 1 << 1, 34 | BF_TEST_DAEMON_NO_IPTABLES = 1 << 2, 35 | BF_TEST_DAEMON_NO_NFTABLES = 1 << 3, 36 | _BF_TEST_DAEMON_LAST = BF_TEST_DAEMON_NO_NFTABLES, 37 | }; 38 | 39 | #define _clean_bf_test_daemon_ \ 40 | __attribute__((__cleanup__(bf_test_daemon_clean))) 41 | 42 | #define bft_daemon_default() \ 43 | { \ 44 | .process = bft_process_default(), \ 45 | } 46 | 47 | /** 48 | * Initialize a new daemon object. 49 | * 50 | * @note `bf_test_daemon_init()` assumes none of the options defined in 51 | * `bf_test_daemon_option` require an argument. If this assumption is erroneous, 52 | * the logic used to parse the options need to be modified! 53 | * 54 | * @param daemon The daemon object to initialize. Can't be `NULL`. 55 | * @param path Path to the `bpfilter` binary. If `NULL`, the first `bpfilter` 56 | * binary found in `$PATH` will be used. 57 | * @param options Command line options to start the daemon with. See 58 | * `bf_test_daemon_option` for the list of available options. 59 | * @return 0 on success, or a negative errno value on error. 60 | */ 61 | int bf_test_daemon_init(struct bf_test_daemon *daemon, const char *path, 62 | uint32_t options); 63 | 64 | /** 65 | * Cleanup a daemon object. 66 | * 67 | * @param daemon Daemon object to cleanup. Can't be `NULL`. 68 | */ 69 | void bf_test_daemon_clean(struct bf_test_daemon *daemon); 70 | 71 | /** 72 | * Start a daemon process. 73 | * 74 | * Once the process is started, this function will wait for a specific log 75 | * from the daemon to validate the process is up and running (and didn't exit). 76 | * 77 | * @param daemon Daemon object to start the daemon process for. Can't be `NULL`. 78 | * @return 0 on success, or a negative errno value on error. 79 | */ 80 | int bf_test_daemon_start(struct bf_test_daemon *daemon); 81 | 82 | /** 83 | * Stop a daemon process. 84 | * 85 | * @param daemon Daemon object to stop the daemon process for. Can't be `NULL`. 86 | * @return The return code of the daemon process as an integer >= 0 on success, 87 | * or a negative errno value on error. 88 | */ 89 | int bf_test_daemon_stop(struct bf_test_daemon *daemon); 90 | -------------------------------------------------------------------------------- /tests/harness/mock.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "mock.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "bpfilter/helper.h" 13 | #include "bpfilter/logger.h" 14 | 15 | static const char *_bf_readable_file_content = "Hello, world!"; 16 | 17 | char *bf_test_filepath_new_rw(void) 18 | { 19 | int fd; 20 | size_t len = strlen(_bf_readable_file_content); 21 | char tmppath[] = "/tmp/bpfltr_XXXXXX"; 22 | char *path = NULL; 23 | 24 | fd = mkstemp(tmppath); 25 | if (fd < 0) { 26 | bf_err_r(errno, "failed to create a temporary file path"); 27 | return NULL; 28 | } 29 | 30 | if ((ssize_t)len != write(fd, _bf_readable_file_content, len)) { 31 | bf_err_r(errno, "failed to write to the temporary filepath"); 32 | return NULL; 33 | } 34 | 35 | close(fd); 36 | 37 | path = strdup(tmppath); 38 | if (!path) { 39 | bf_err_r(errno, "failed to allocate memory for the new filepath"); 40 | return NULL; 41 | } 42 | 43 | return path; 44 | } 45 | 46 | void bf_test_filepath_free(char **path) 47 | { 48 | bf_assert(path); 49 | 50 | if (!*path) 51 | return; 52 | 53 | if (unlink(*path) < 0) 54 | bf_err_r(errno, "failed to remove '%s'", *path); 55 | 56 | freep((void *)path); 57 | } 58 | 59 | void bf_test_mock_clean(bf_test_mock *mock) 60 | { 61 | mock->disable(); 62 | } 63 | -------------------------------------------------------------------------------- /tests/harness/prog.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "prog.h" 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "bpfilter/bpfilter.h" 17 | #include "bpfilter/chain.h" 18 | #include "bpfilter/helper.h" 19 | #include "bpfilter/list.h" 20 | #include "bpfilter/logger.h" 21 | 22 | struct bf_test_prog *bf_test_prog_get(struct bf_chain *chain) 23 | { 24 | _clean_bf_list_ bf_list chains = bf_list_default(NULL, NULL); 25 | _clean_bf_list_ bf_list hooks = bf_list_default(NULL, NULL); 26 | _free_bf_test_prog_ struct bf_test_prog *prog = NULL; 27 | int r; 28 | 29 | r = bf_test_prog_new(&prog); 30 | if (r < 0) { 31 | bf_err_r(r, "failed to create a new bf_test_prog"); 32 | return NULL; 33 | } 34 | 35 | r = bf_list_add_tail(&chains, chain); 36 | if (r) { 37 | bf_err_r(r, "failed to add bf_chain to list"); 38 | return NULL; 39 | } 40 | 41 | r = bf_list_add_tail(&hooks, NULL); 42 | if (r) { 43 | bf_err_r(r, "failed to add empty bf_hookopts to list"); 44 | return NULL; 45 | } 46 | 47 | r = bf_ruleset_set(&chains, &hooks); 48 | if (r < 0) { 49 | bf_err_r(r, "failed to create a new chain"); 50 | return NULL; 51 | } 52 | 53 | r = bf_test_prog_open(prog, "bf_prog"); 54 | if (r < 0) { 55 | bf_err_r(r, "failed to open the bf_test_prog's BPF program"); 56 | return NULL; 57 | } 58 | 59 | return TAKE_PTR(prog); 60 | } 61 | 62 | int bf_test_prog_new(struct bf_test_prog **prog) 63 | { 64 | bf_assert(prog); 65 | 66 | *prog = malloc(sizeof(struct bf_test_prog)); 67 | if (!*prog) 68 | return bf_err_r(-ENOMEM, "failed to allocate a new bf_test_prog"); 69 | 70 | (*prog)->fd = -1; 71 | 72 | return 0; 73 | } 74 | 75 | void bf_test_prog_free(struct bf_test_prog **prog) 76 | { 77 | bf_assert(prog); 78 | 79 | if (!*prog) 80 | return; 81 | 82 | closep(&(*prog)->fd); 83 | freep((void *)prog); 84 | } 85 | 86 | int bf_test_prog_open(struct bf_test_prog *prog, const char *name) 87 | { 88 | uint32_t id = 0; 89 | int r; 90 | 91 | while (true) { 92 | uint32_t len = sizeof(struct bpf_prog_info); 93 | struct bpf_prog_info info = {}; 94 | _cleanup_close_ int prog_fd = -1; 95 | 96 | r = bpf_prog_get_next_id(id, &id); 97 | if (r < 0) 98 | return bf_err_r(r, "call to bpf_prog_get_next_id() failed"); 99 | 100 | prog_fd = bpf_prog_get_fd_by_id(id); 101 | if (prog_fd < 0) 102 | return bf_err_r(prog_fd, "call to bpf_prog_get_fd_by_id() failed"); 103 | 104 | r = bpf_obj_get_info_by_fd(prog_fd, &info, &len); 105 | if (r < 0) 106 | return bf_err_r(r, "call to bpf_obj_get_info_by_fd() failed"); 107 | 108 | if (bf_streq(info.name, name)) { 109 | prog->fd = TAKE_FD(prog_fd); 110 | return 0; 111 | } 112 | } 113 | 114 | return -ENOENT; 115 | } 116 | -------------------------------------------------------------------------------- /tests/harness/prog.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | /** 12 | * @file prog.h 13 | * 14 | * This module defines `bf_test_prog` to manipulate a BPF program generated by 15 | * `bpfilter`. 16 | * 17 | * Once a `bf_test_prog` object has been created, use `bf_test_prog_open()` to 18 | * link it to a BPF program attach to the system using the program's name. 19 | */ 20 | 21 | struct bf_chain; 22 | 23 | struct bf_test_packet 24 | { 25 | size_t len; 26 | const void *data; 27 | }; 28 | 29 | #define _free_bf_test_prog_ __attribute__((__cleanup__(bf_test_prog_free))) 30 | 31 | struct bf_test_prog 32 | { 33 | int fd; 34 | }; 35 | 36 | struct bf_test_prog *bf_test_prog_get(struct bf_chain *chain); 37 | 38 | int bf_test_prog_new(struct bf_test_prog **prog); 39 | void bf_test_prog_free(struct bf_test_prog **prog); 40 | int bf_test_prog_open(struct bf_test_prog *prog, const char *name); 41 | -------------------------------------------------------------------------------- /tests/integration/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 3 | 4 | include(ExternalProject) 5 | 6 | #[[ 7 | set(BF_TOOLS_NFT_GIT_TAG v1.0.9) 8 | set(BF_TOOLS_NFT_SOURCE_DIR ${CMAKE_BINARY_DIR}/tools/nftables) 9 | set(BF_TOOLS_NFT_INSTALL_DIR ${CMAKE_BINARY_DIR}/tools/install) 10 | 11 | ExternalProject_Add(nftables 12 | GIT_REPOSITORY https://git.netfilter.org/nftables 13 | GIT_TAG ${BF_TOOLS_NFT_GIT_TAG} 14 | 15 | DEPENDS libbpfilter 16 | BUILD_IN_SOURCE true 17 | EXCLUDE_FROM_ALL true 18 | SOURCE_DIR ${BF_TOOLS_NFT_SOURCE_DIR} 19 | INSTALL_DIR ${BF_TOOLS_NFT_INSTALL_DIR} 20 | 21 | PATCH_COMMAND git reset --hard ${BF_TOOLS_NFT_GIT_TAG} 22 | COMMAND git apply ${CMAKE_CURRENT_SOURCE_DIR}/nftables/0001-libnftables-add-support-for-bpfilter.patch 23 | CONFIGURE_COMMAND ./autogen.sh 24 | COMMAND 25 | ${CMAKE_COMMAND} -E env 26 | LDFLAGS=$<$:-fsanitize=address\ -fsanitize=undefined> 27 | CFLAGS=$<$:-fsanitize=address\ -fsanitize=undefined> 28 | BPFILTER_LIBS=-L${CMAKE_BINARY_DIR}/output/lib\ -lbpfilter\ -Wl,-rpath=${CMAKE_BINARY_DIR}/output/lib 29 | BPFILTER_CFLAGS=-I${CMAKE_BINARY_DIR}/output/include 30 | ./configure 31 | --with-bpfilter 32 | --disable-man-doc 33 | --prefix=${BF_TOOLS_NFT_INSTALL_DIR} 34 | ) 35 | ]] 36 | 37 | set(BF_TOOLS_IPT_GIT_TAG 8bf2bab8) 38 | set(BF_TOOLS_IPT_SOURCE_DIR ${CMAKE_BINARY_DIR}/tools/iptables) 39 | set(BF_TOOLS_IPT_INSTALL_DIR ${CMAKE_BINARY_DIR}/tools/install) 40 | 41 | ExternalProject_Add(iptables 42 | GIT_REPOSITORY https://git.netfilter.org/iptables 43 | GIT_TAG ${BF_TOOLS_IPT_GIT_TAG} 44 | 45 | DEPENDS libbpfilter 46 | BUILD_IN_SOURCE true 47 | EXCLUDE_FROM_ALL true 48 | SOURCE_DIR ${BF_TOOLS_IPT_SOURCE_DIR} 49 | INSTALL_DIR ${BF_TOOLS_IPT_INSTALL_DIR} 50 | 51 | PATCH_COMMAND git reset --hard ${BF_TOOLS_IPT_GIT_TAG} 52 | COMMAND git apply ${CMAKE_CURRENT_SOURCE_DIR}/iptables/0001-iptables-add-support-for-bpfilter.patch 53 | CONFIGURE_COMMAND ./autogen.sh 54 | COMMAND 55 | ${CMAKE_COMMAND} -E env 56 | bpfilter_LIBS=-Wl,-rpath=${CMAKE_BINARY_DIR}/output/lib\ -L${CMAKE_BINARY_DIR}/output/lib\ -lbpfilter\ $<$:-fsanitize=address\ -fsanitize=undefined> 57 | bpfilter_CFLAGS=-I${CMAKE_SOURCE_DIR}/src/libbpfilter/include\ -I${CMAKE_BINARY_DIR}/build/libbpfilter/include\ $<$:-fsanitize=address\ -fsanitize=undefined> 58 | ./configure 59 | --enable-bpfilter 60 | --disable-ipv6 61 | --disable-nftables 62 | --disable-libipq 63 | --prefix=${BF_TOOLS_IPT_INSTALL_DIR} 64 | ) 65 | 66 | # add_custom_target(integration DEPENDS iptables nftables) 67 | 68 | add_custom_target(integration DEPENDS iptables) 69 | -------------------------------------------------------------------------------- /tests/pedantic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 3 | 4 | add_executable(pedantic_c EXCLUDE_FROM_ALL pedantic.c) 5 | 6 | target_compile_options(pedantic_c PRIVATE -pedantic-errors -std=c17) 7 | 8 | target_link_libraries(pedantic_c 9 | PUBLIC 10 | bf_global_flags 11 | libbpfilter 12 | ) 13 | 14 | add_executable(pedantic_cpp EXCLUDE_FROM_ALL pedantic.cpp) 15 | 16 | target_compile_options(pedantic_cpp PRIVATE -pedantic-errors -std=c++17) 17 | 18 | target_link_libraries(pedantic_cpp 19 | PUBLIC 20 | bf_global_flags 21 | libbpfilter 22 | ) 23 | 24 | add_custom_target(pedantic 25 | COMMAND $ 26 | COMMAND $ 27 | COMMENT "Running pedantic tests" 28 | ) 29 | -------------------------------------------------------------------------------- /tests/pedantic/pedantic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | int main(void) 30 | { 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /tests/pedantic/pedantic.cpp: -------------------------------------------------------------------------------- 1 | extern "C" { 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | } 30 | 31 | int main() 32 | { 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /tests/unit/assert_override.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | extern void mock_assert(const int result, const char * const expression, 7 | const char * const file, const int line); 8 | 9 | #ifndef bf_assert 10 | #define bf_assert(expression) \ 11 | mock_assert((int)(!!(expression)), #expression, __FILE__, __LINE__) 12 | #else 13 | #error bf_assert is already defined, it should not 14 | #endif 15 | -------------------------------------------------------------------------------- /tests/unit/bpfilter/cgen/cgen.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "bpfilter/cgen/cgen.c" 7 | 8 | #include "fake.h" 9 | #include "harness/test.h" 10 | #include "mock.h" 11 | 12 | Test(cgen, create_delete_assert) 13 | { 14 | struct bf_chain *no_chain = NULL; 15 | 16 | expect_assert_failure(bf_cgen_new(NULL, BF_FRONT_CLI, NOT_NULL)); 17 | expect_assert_failure(bf_cgen_new(NOT_NULL, BF_FRONT_CLI, NULL)); 18 | expect_assert_failure(bf_cgen_new(NOT_NULL, BF_FRONT_CLI, &no_chain)); 19 | expect_assert_failure(bf_cgen_free(NULL)); 20 | } 21 | 22 | Test(cgen, create_delete) 23 | { 24 | // Rely on the cleanup attribute. 25 | _free_bf_cgen_ struct bf_cgen *cgen0 = NULL; 26 | _free_bf_chain_ struct bf_chain *chain0 = bf_test_chain_quick(); 27 | 28 | assert_success(bf_cgen_new(&cgen0, BF_FRONT_CLI, &chain0)); 29 | assert_non_null(cgen0); 30 | assert_null(chain0); 31 | 32 | // Codegen has the cleanup attribute, but call free() before 33 | _free_bf_cgen_ struct bf_cgen *cgen1 = NULL; 34 | _free_bf_chain_ struct bf_chain *chain1 = bf_test_chain_quick(); 35 | 36 | assert_success(bf_cgen_new(&cgen1, BF_FRONT_CLI, &chain1)); 37 | assert_non_null(cgen1); 38 | assert_null(chain1); 39 | 40 | bf_cgen_free(&cgen1); 41 | assert_null(cgen1); 42 | 43 | // Free the codegen manually 44 | struct bf_cgen *cgen2; 45 | _free_bf_chain_ struct bf_chain *chain2 = bf_test_chain_quick(); 46 | 47 | assert_success(bf_cgen_new(&cgen2, BF_FRONT_CLI, &chain2)); 48 | assert_non_null(cgen2); 49 | assert_null(chain2); 50 | 51 | bf_cgen_free(&cgen2); 52 | assert_null(cgen2); 53 | bf_cgen_free(&cgen2); 54 | } 55 | 56 | Test(cgen, create_delete_no_malloc) 57 | { 58 | _clean_bf_test_mock_ bf_test_mock mock; 59 | struct bf_cgen *cgen; 60 | _free_bf_chain_ struct bf_chain *chain = bf_test_chain_quick(); 61 | 62 | mock = bf_test_mock_get(malloc, NULL); 63 | assert_error(bf_cgen_new(&cgen, BF_FRONT_CLI, &chain)); 64 | } 65 | 66 | Test(cgen, pack_unpack) 67 | { 68 | _free_bf_cgen_ struct bf_cgen *cgen0 = NULL; 69 | _free_bf_cgen_ struct bf_cgen *cgen1 = NULL; 70 | _free_bf_wpack_ bf_wpack_t *wpack = NULL; 71 | _free_bf_rpack_ bf_rpack_t *rpack = NULL; 72 | const void *data; 73 | size_t data_len; 74 | 75 | expect_assert_failure(bf_cgen_pack(NULL, NOT_NULL)); 76 | expect_assert_failure(bf_cgen_pack(NOT_NULL, NULL)); 77 | 78 | assert_non_null(cgen0 = bf_test_cgen(BF_FRONT_CLI, BF_HOOK_XDP, BF_VERDICT_ACCEPT)); 79 | 80 | assert_success(bf_wpack_new(&wpack)); 81 | assert_success(bf_cgen_pack(cgen0, wpack)); 82 | assert_success(bf_wpack_get_data(wpack, &data, &data_len)); 83 | 84 | assert_success(bf_rpack_new(&rpack, data, data_len)); 85 | assert_success(bf_cgen_new_from_pack(&cgen1, bf_rpack_root(rpack))); 86 | } 87 | 88 | Test(cgen, invalid_chain_policy) 89 | { 90 | expect_assert_failure(bf_test_chain(BF_HOOK_XDP, BF_VERDICT_CONTINUE)); 91 | } 92 | -------------------------------------------------------------------------------- /tests/unit/bpfilter/cgen/jmp.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "bpfilter/cgen/jmp.c" 7 | 8 | #include "fake.h" 9 | #include "harness/test.h" 10 | #include "mock.h" 11 | 12 | /** 13 | * Create a context and emit a given number of instructions. 14 | * 15 | * EMIT_*() macros can't be called directly from the test, as they return an 16 | * error code on failure. This function is a workaround to test EMIT_*() macros 17 | * and return a negative value on error. This negative value can then be 18 | * asserted by the tests. 19 | * 20 | * @param program The program to emit the instructions in. 21 | * @param ctx The context to create. 22 | * @param n_insn The number of instructions to emit. 23 | * @return 0 on success, or negative errno value on failure. 24 | */ 25 | static int emit_in_ctx(struct bf_program *program, struct bf_jmpctx *ctx, 26 | size_t n_insn) 27 | { 28 | *ctx = bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_2, 0, 0)); 29 | 30 | for (size_t i = 0; i < n_insn; i++) 31 | EMIT(program, BPF_MOV64_IMM(BPF_REG_0, 0)); 32 | 33 | return 0; 34 | } 35 | 36 | Test(jmp, create_and_close) 37 | { 38 | _free_bf_program_ struct bf_program *program = NULL; 39 | _free_bf_chain_ struct bf_chain *chain = bf_test_chain(BF_HOOK_XDP, BF_VERDICT_ACCEPT); 40 | 41 | assert_success(bf_program_new(&program, chain)); 42 | 43 | { 44 | // Managing context manually 45 | struct bf_jmpctx ctx; 46 | assert_int_equal(emit_in_ctx(program, &ctx, 0), 0); 47 | bf_jmpctx_cleanup(&ctx); 48 | assert_int_equal(program->img[ctx.insn_idx].off, 0); 49 | 50 | assert_int_equal(emit_in_ctx(program, &ctx, 1), 0); 51 | bf_jmpctx_cleanup(&ctx); 52 | assert_int_equal(program->img[ctx.insn_idx].off, 1); 53 | 54 | assert_int_equal(emit_in_ctx(program, &ctx, 2), 0); 55 | bf_jmpctx_cleanup(&ctx); 56 | assert_int_equal(program->img[ctx.insn_idx].off, 2); 57 | } 58 | 59 | { 60 | // Check if the context is automatically cleaned up 61 | size_t idx; 62 | 63 | { 64 | _clean_bf_jmpctx_ struct bf_jmpctx _; 65 | assert_int_equal(emit_in_ctx(program, &_, 0), 0); 66 | idx = _.insn_idx; 67 | } 68 | 69 | assert_int_equal(program->img[idx].off, 0); 70 | 71 | { 72 | _clean_bf_jmpctx_ struct bf_jmpctx _; 73 | assert_int_equal(emit_in_ctx(program, &_, 1), 0); 74 | idx = _.insn_idx; 75 | } 76 | 77 | assert_int_equal(program->img[idx].off, 1); 78 | 79 | { 80 | _clean_bf_jmpctx_ struct bf_jmpctx _; 81 | assert_int_equal(emit_in_ctx(program, &_, 2), 0); 82 | idx = _.insn_idx; 83 | } 84 | 85 | assert_int_equal(program->img[idx].off, 2); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /tests/unit/bpfilter/cgen/program.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "cgen/program.c" 7 | 8 | #include "fake.h" 9 | #include "harness/test.h" 10 | #include "mock.h" 11 | 12 | Test(program, can_get_flavor_from_hook) 13 | { 14 | for (enum bf_flavor flavor = 0; flavor < _BF_FLAVOR_MAX; ++flavor) 15 | assert_non_null(bf_flavor_ops_get(flavor)); 16 | } 17 | -------------------------------------------------------------------------------- /tests/unit/bpfilter/ctx.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "bpfilter/ctx.c" 7 | 8 | #include 9 | 10 | #include "harness/test.h" 11 | #include "fake.h" 12 | #include "mock.h" 13 | 14 | Test(ctx, create_delete_assert) 15 | { 16 | expect_assert_failure(_bf_ctx_new(NULL)); 17 | expect_assert_failure(_bf_ctx_free(NULL)); 18 | } 19 | 20 | Test(ctx, create_delete) 21 | { 22 | _clean_bf_test_mock_ bf_test_mock _ = bf_test_mock_empty(bf_btf_get_id); 23 | bf_test_mock_will_return_always(_, 1); 24 | 25 | // Rely on the cleanup attrubte 26 | _free_bf_ctx_ struct bf_ctx *ctx0 = NULL; 27 | 28 | assert_success(_bf_ctx_new(&ctx0)); 29 | assert_non_null(ctx0); 30 | 31 | // Use the cleanup attribute, but free manually 32 | _free_bf_ctx_ struct bf_ctx *ctx1 = NULL; 33 | 34 | assert_success(_bf_ctx_new(&ctx1)); 35 | assert_non_null(ctx1); 36 | 37 | _bf_ctx_free(&ctx1); 38 | assert_null(ctx1); 39 | 40 | // Free manually 41 | struct bf_ctx *ctx2; 42 | 43 | assert_success(_bf_ctx_new(&ctx2)); 44 | assert_non_null(ctx2); 45 | 46 | _bf_ctx_free(&ctx2); 47 | assert_null(ctx2); 48 | _bf_ctx_free(&ctx2); 49 | } 50 | 51 | Test(ctx, set_get_chain) 52 | { 53 | _clean_bf_test_mock_ bf_test_mock _ = bf_test_mock_empty(bf_btf_get_id); 54 | bf_test_mock_will_return_always(_, 1); 55 | 56 | // Rely on the cleanup attrubte 57 | _free_bf_ctx_ struct bf_ctx *ctx = NULL; 58 | _free_bf_cgen_ struct bf_cgen *cgen0 = bf_test_cgen_quick(); 59 | _free_bf_cgen_ struct bf_cgen *cgen1 = bf_test_cgen_quick(); 60 | _free_bf_cgen_ struct bf_cgen *cgen2 = bf_test_cgen_quick(); 61 | 62 | // Change the name of cgen2 63 | freep(&cgen2->chain->name); 64 | cgen2->chain->name = strdup("hello"); 65 | assert_non_null(cgen2->chain->name); 66 | 67 | assert_success(_bf_ctx_new(&ctx)); 68 | // Do not free cgens, as we keep a reference here 69 | ctx->cgens.ops.free = NULL; 70 | 71 | // Context is empty, add the first cgen 72 | assert_success(_bf_ctx_set_cgen(ctx, cgen0)); 73 | 74 | // Trying to add another cgen with the same name 75 | assert_error(_bf_ctx_set_cgen(ctx, cgen1)); 76 | 77 | // Add another cgen with a different name 78 | assert_success(_bf_ctx_set_cgen(ctx, cgen2)); 79 | 80 | // Get the cgens back 81 | assert_ptr_equal(_bf_ctx_get_cgen(ctx, cgen0->chain->name), cgen0); 82 | assert_ptr_equal(_bf_ctx_get_cgen(ctx, cgen1->chain->name), cgen0); 83 | assert_ptr_equal(_bf_ctx_get_cgen(ctx, cgen2->chain->name), cgen2); 84 | } 85 | -------------------------------------------------------------------------------- /tests/unit/bpfilter/opts.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "bpfilter/opts.c" 7 | 8 | #include "fake.h" 9 | #include "harness/test.h" 10 | #include "mock.h" 11 | 12 | Test(opts, no_nftables) 13 | { 14 | char *opt0[] = {"tests_unit", "--no-nftables"}; 15 | 16 | _bf_opts.fronts = 0xffff; 17 | assert_success(bf_opts_init(ARRAY_SIZE(opt0), opt0)); 18 | assert(0 == (_bf_opts.fronts & BF_FLAG(BF_FRONT_NFT))); 19 | } 20 | -------------------------------------------------------------------------------- /tests/unit/bpfilter/xlate/nft/nft.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "bpfilter/xlate/nft/nft.c" 7 | 8 | #include "fake.h" 9 | #include "harness/test.h" 10 | #include "mock.h" 11 | 12 | Test(nft, check_front_ops) 13 | { 14 | assert_ptr_equal(&nft_front, bf_front_ops_get(BF_FRONT_NFT)); 15 | } 16 | -------------------------------------------------------------------------------- /tests/unit/fake.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "fake.h" 7 | 8 | // clang-format off 9 | #include // NOLINT: required by cmocka.h 10 | #include 11 | // clang-format on 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "bpfilter/cgen/cgen.h" 20 | #include "bpfilter/cgen/program.h" 21 | #include "bpfilter/xlate/nft/nfgroup.h" 22 | #include "bpfilter/chain.h" 23 | #include "bpfilter/front.h" 24 | #include "bpfilter/helper.h" 25 | #include "bpfilter/hook.h" 26 | #include "bpfilter/rule.h" 27 | #include "bpfilter/verdict.h" 28 | 29 | struct nlmsghdr; 30 | 31 | struct bf_chain *bf_test_chain(enum bf_hook hook, enum bf_verdict policy) 32 | { 33 | struct bf_chain *chain; 34 | 35 | assert_int_equal(0, bf_chain_new(&chain, "bf_chain", hook, policy, NULL, NULL)); 36 | 37 | return chain; 38 | } 39 | 40 | struct bf_cgen *bf_test_cgen(enum bf_front front, enum bf_hook hook, 41 | enum bf_verdict verdict) 42 | { 43 | struct bf_cgen *cgen; 44 | struct bf_chain *chain = bf_test_chain(hook, verdict); 45 | 46 | assert_int_equal(0, bf_cgen_new(&cgen, front, &chain)); 47 | 48 | return cgen; 49 | } 50 | 51 | struct bf_rule *bf_test_get_rule(size_t nmatchers) 52 | { 53 | _free_bf_rule_ struct bf_rule *rule = NULL; 54 | 55 | assert_int_equal(0, bf_rule_new(&rule)); 56 | 57 | rule->index = 1; 58 | 59 | for (size_t i = 0; i < nmatchers; ++i) 60 | assert_int_equal( 61 | 0, bf_rule_add_matcher(rule, 0, 0, (void *)&i, sizeof(i))); 62 | 63 | rule->counters = true; 64 | rule->verdict = 1; 65 | 66 | return TAKE_PTR(rule); 67 | } 68 | -------------------------------------------------------------------------------- /tests/unit/fake.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include "bpfilter/front.h" 11 | #include "bpfilter/hook.h" 12 | #include "bpfilter/verdict.h" 13 | 14 | struct bf_cgen; 15 | struct bf_nfgroup; 16 | struct bf_rule; 17 | struct nlmsghdr; 18 | 19 | #define bf_test_chain_quick() bf_test_chain(BF_HOOK_XDP, BF_VERDICT_ACCEPT) 20 | #define bf_test_cgen_quick() \ 21 | bf_test_cgen(BF_FRONT_CLI, BF_HOOK_XDP, BF_VERDICT_ACCEPT) 22 | 23 | struct bf_chain *bf_test_chain(enum bf_hook hook, enum bf_verdict policy); 24 | struct bf_cgen *bf_test_cgen(enum bf_front front, enum bf_hook hook, 25 | enum bf_verdict verdict); 26 | struct bf_rule *bf_test_get_rule(size_t nmatchers); 27 | -------------------------------------------------------------------------------- /tests/unit/libbpfilter/btf.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "libbpfilter/btf.c" 7 | 8 | #include "harness/test.h" 9 | #include "mock.h" 10 | 11 | Test(btf, init) 12 | { 13 | assert_success(bf_btf_setup()); 14 | assert_non_null(_bf_btf); 15 | 16 | bf_btf_teardown(); 17 | assert_null(_bf_btf); 18 | } 19 | 20 | Test(btf, failed_init) 21 | { 22 | _clean_bf_test_mock_ bf_test_mock _ = bf_test_mock_get(btf__load_vmlinux_btf, NULL); 23 | 24 | assert_null(_bf_btf); 25 | assert_error(bf_btf_setup()); 26 | assert_null(_bf_btf); 27 | } 28 | 29 | Test(btf, get_field_offset) 30 | { 31 | assert_success(bf_btf_setup()); 32 | 33 | assert_success(bf_btf_get_field_off("iphdr", "ihl")); 34 | assert_int_equal(9, bf_btf_get_field_off("iphdr", "protocol")); 35 | assert_int_equal(8, bf_btf_get_field_off("bpf_nf_ctx", "skb")); 36 | 37 | // Not a structure 38 | assert_true(bf_btf_get_field_off("long unsigned int", "protocol") < 0); 39 | 40 | // Invalid structure 41 | assert_true(bf_btf_get_field_off("ipheader", "protocol") < 0); 42 | 43 | // Invalid field 44 | assert_true(bf_btf_get_field_off("iphdr", "protocole") < 0); 45 | 46 | bf_btf_teardown(); 47 | } 48 | -------------------------------------------------------------------------------- /tests/unit/libbpfilter/chain.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "libbpfilter/chain.c" 7 | 8 | #include "harness/filters.h" 9 | #include "harness/test.h" 10 | #include "mock.h" 11 | 12 | Test(chain, new_free_assert_failure) 13 | { 14 | expect_assert_failure(bf_chain_new(NULL, NOT_NULL, 0, 0, NULL, NULL)); 15 | expect_assert_failure(bf_chain_new(NOT_NULL, NULL, 0, 0, NULL, NULL)); 16 | expect_assert_failure(bf_chain_new(NOT_NULL, NOT_NULL, 0, _BF_TERMINAL_VERDICT_MAX + 1, NULL, NULL)); 17 | 18 | expect_assert_failure(bf_chain_free(NULL)); 19 | } 20 | 21 | Test(chain, new_free) 22 | { 23 | _free_bf_chain_ struct bf_chain *chain = NULL; 24 | _clean_bf_list_ bf_list rules = bf_list_default(bf_rule_free, NULL); 25 | size_t i; 26 | 27 | assert_success(bf_chain_new(&chain, "name", 0, 0, NULL, NULL)); 28 | bf_chain_free(&chain); 29 | assert_null(chain); 30 | 31 | assert_success(bf_list_add_tail(&rules, bf_rule_get(0, false, 0, bft_fake_matchers))); 32 | assert_success(bf_list_add_tail(&rules, bf_rule_get(0, false, 0, bft_fake_matchers))); 33 | 34 | i = 0; 35 | assert_success(bf_chain_new(&chain, "name", 0, 0, NULL, &rules)); 36 | bf_list_foreach (&chain->rules, rule_node) { 37 | assert_int_equal(i++, ((struct bf_rule *)(bf_list_node_get_data(rule_node)))->index); 38 | } 39 | } 40 | 41 | Test(chain, pack_unpack) 42 | { 43 | _free_bf_chain_ struct bf_chain *chain0 = NULL; 44 | _free_bf_chain_ struct bf_chain *chain1 = NULL; 45 | _free_bf_wpack_ bf_wpack_t *wpack = NULL; 46 | _free_bf_rpack_ bf_rpack_t *rpack = NULL; 47 | const void *data; 48 | size_t data_len; 49 | 50 | expect_assert_failure(bf_chain_pack(NULL, NOT_NULL)); 51 | expect_assert_failure(bf_chain_pack(NOT_NULL, NULL)); 52 | 53 | assert_non_null(chain0 = bf_test_chain_get(0, 0, NULL, bft_fake_rules)); 54 | 55 | assert_success(bf_wpack_new(&wpack)); 56 | assert_success(bf_chain_pack(chain0, wpack)); 57 | assert_success(bf_wpack_get_data(wpack, &data, &data_len)); 58 | 59 | assert_success(bf_rpack_new(&rpack, data, data_len)); 60 | assert_success(bf_chain_new_from_pack(&chain1, bf_rpack_root(rpack))); 61 | 62 | assert_int_equal(bf_list_size(&chain0->rules), bf_list_size(&chain1->rules)); 63 | assert_int_equal(bf_list_size(&chain0->sets), bf_list_size(&chain1->sets)); 64 | 65 | { 66 | struct bf_list_node *n0 = bf_list_get_head(&chain0->rules); 67 | struct bf_list_node *n1 = bf_list_get_head(&chain1->rules); 68 | 69 | while (n0) { 70 | assert_int_equal(((struct bf_rule *)(bf_list_node_get_data(n0)))->index, 71 | ((struct bf_rule *)(bf_list_node_get_data(n1)))->index); 72 | n0 = bf_list_node_next(n0); 73 | n1 = bf_list_node_next(n1); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tests/unit/libbpfilter/flavor.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "libbpfilter/flavor.c" 7 | 8 | #include "harness/test.h" 9 | #include "mock.h" 10 | 11 | Test(flavor, flavor_to_str) 12 | { 13 | for (int i = 0; i < _BF_FLAVOR_MAX; ++i) 14 | assert_non_null(bf_flavor_to_str(i)); 15 | } 16 | -------------------------------------------------------------------------------- /tests/unit/libbpfilter/front.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "libbpfilter/front.c" 7 | 8 | #include "harness/test.h" 9 | #include "mock.h" 10 | 11 | Test(shared_front, front_to_str_assert_failure) 12 | { 13 | expect_assert_failure(bf_front_to_str(-1)); 14 | expect_assert_failure(bf_front_to_str(_BF_FRONT_MAX)); 15 | } 16 | 17 | Test(hook, can_get_str_from_front) 18 | { 19 | for (int i = 0; i < _BF_FRONT_MAX; ++i) 20 | assert_non_null(bf_front_to_str(i)); 21 | } 22 | -------------------------------------------------------------------------------- /tests/unit/libbpfilter/rule.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "libbpfilter/rule.c" 7 | 8 | #include "fake.h" 9 | #include "harness/test.h" 10 | #include "mock.h" 11 | 12 | Test(rule, new_and_free) 13 | { 14 | // Invalid argument 15 | expect_assert_failure(bf_rule_new(NULL)); 16 | expect_assert_failure(bf_rule_free(NULL)); 17 | 18 | // New, free, new again, then cleanup 19 | { 20 | _free_bf_rule_ struct bf_rule *rule = NULL; 21 | 22 | assert_success(bf_rule_new(&rule)); 23 | bf_rule_free(&rule); 24 | assert_null(rule); 25 | bf_rule_free(&rule); 26 | 27 | assert_success(bf_rule_new(&rule)); 28 | } 29 | 30 | // malloc failure 31 | { 32 | _clean_bf_test_mock_ bf_test_mock _ = bf_test_mock_get(calloc, NULL); 33 | struct bf_rule *rule; 34 | 35 | assert_error(bf_rule_new(&rule)); 36 | } 37 | } 38 | 39 | Test(rule, pack_unpack) 40 | { 41 | _free_bf_rule_ struct bf_rule *rule0 = NULL; 42 | _free_bf_rule_ struct bf_rule *rule1 = NULL; 43 | _free_bf_wpack_ bf_wpack_t *wpack = NULL; 44 | _free_bf_rpack_ bf_rpack_t *rpack = NULL; 45 | const void *data; 46 | size_t data_len; 47 | 48 | expect_assert_failure(bf_rule_pack(NULL, NOT_NULL)); 49 | expect_assert_failure(bf_rule_pack(NOT_NULL, NULL)); 50 | 51 | assert_non_null(rule0 = bf_test_get_rule(10)); 52 | 53 | assert_success(bf_wpack_new(&wpack)); 54 | assert_success(bf_rule_pack(rule0, wpack)); 55 | assert_success(bf_wpack_get_data(wpack, &data, &data_len)); 56 | 57 | assert_success(bf_rpack_new(&rpack, data, data_len)); 58 | assert_success(bf_rule_new_from_pack(&rule1, bf_rpack_root(rpack))); 59 | 60 | assert_int_equal(rule0->index, rule1->index); 61 | assert_int_equal(bf_list_size(&rule0->matchers), 62 | bf_list_size(&rule1->matchers)); 63 | assert_int_equal(rule0->counters, rule1->counters); 64 | assert_int_equal(rule0->verdict, rule1->verdict); 65 | } 66 | -------------------------------------------------------------------------------- /tests/unit/libbpfilter/verdict.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "libbpfilter/verdict.c" 7 | 8 | #include "harness/test.h" 9 | #include "mock.h" 10 | 11 | Test(verdict, verdict_to_str_to_verdict) 12 | { 13 | enum bf_verdict verdict; 14 | 15 | expect_assert_failure(bf_verdict_to_str(-1)); 16 | expect_assert_failure(bf_verdict_to_str(_BF_VERDICT_MAX)); 17 | expect_assert_failure(bf_verdict_from_str(NULL, NOT_NULL)); 18 | expect_assert_failure(bf_verdict_from_str(NOT_NULL, NULL)); 19 | 20 | for (int i = 0; i < _BF_VERDICT_MAX; ++i) { 21 | const char *str = bf_verdict_to_str(i); 22 | 23 | assert_non_null(str); 24 | assert_int_not_equal(-1, bf_verdict_from_str(str, &verdict)); 25 | assert_int_equal(verdict, i); 26 | } 27 | 28 | assert_int_not_equal(0, bf_verdict_from_str("", &verdict)); 29 | assert_int_not_equal(0, bf_verdict_from_str("invalid", &verdict)); 30 | } 31 | -------------------------------------------------------------------------------- /tests/unit/mock.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "harness/mock.h" 14 | #include "bpfilter/bpf_types.h" 15 | #include "bpfilter/btf.h" 16 | 17 | struct btf; 18 | struct nl_msg; 19 | struct nlmsghdr; 20 | 21 | bf_test_mock_declare(void *, malloc, (size_t size)); 22 | bf_test_mock_declare(void *, calloc, (size_t nmemb, size_t size)); 23 | bf_test_mock_declare(int, open, (const char *pathname, int flags, mode_t mode)); 24 | bf_test_mock_declare(ssize_t, read, (int fd, void *buf, size_t count)); 25 | bf_test_mock_declare(ssize_t, write, (int fd, const void *buf, size_t count)); 26 | bf_test_mock_declare(struct btf *, btf__load_vmlinux_btf, (void)); 27 | bf_test_mock_declare(struct nl_msg *, nlmsg_alloc, ()); 28 | bf_test_mock_declare(struct nl_msg *, nlmsg_convert, (struct nlmsghdr * nlh)); 29 | bf_test_mock_declare(struct nlmsghdr *, nlmsg_put, 30 | (struct nl_msg * nlmsg, uint32_t pid, uint32_t seq, 31 | int type, int payload, int flags)); 32 | bf_test_mock_declare(int, nlmsg_append, 33 | (struct nl_msg * nlmsg, void *data, size_t len, int pad)); 34 | bf_test_mock_declare(int, bf_bpf_obj_get, (const char *path, int *fd)); 35 | bf_test_mock_declare(int, vsnprintf, 36 | (char *str, size_t size, const char *fmt, va_list args)); 37 | bf_test_mock_declare(int, snprintf, 38 | (char *str, size_t size, const char *fmt, ...)); 39 | bf_test_mock_declare(int, bf_bpf, (enum bf_bpf_cmd cmd, union bpf_attr *attr)); 40 | bf_test_mock_declare(int, bf_ctx_token, (void)); 41 | bf_test_mock_declare(int, bf_btf_get_id, (const char *name)); 42 | bf_test_mock_declare(int, bf_bpf_map_create, (const char *name, enum bf_bpf_map_type type, 43 | size_t key_size, size_t value_size, size_t n_elems, 44 | const struct bf_btf *btf, int token_fd)); 45 | -------------------------------------------------------------------------------- /tools/asroot: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Run a command as root: if the current user is root, run the command directly, 4 | # otherwise prefix it with sudo. 5 | 6 | SUDO='' 7 | if [ "$(id -u)" -ne 0 ] 8 | then 9 | SUDO='sudo' 10 | fi 11 | 12 | $SUDO "$@" 13 | -------------------------------------------------------------------------------- /tools/benchmarks/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 3 | 4 | enable_language(CXX) 5 | 6 | find_package(benchmark REQUIRED) 7 | find_package(PkgConfig REQUIRED) 8 | pkg_check_modules(bpf REQUIRED IMPORTED_TARGET libbpf) 9 | pkg_check_modules(git2 REQUIRED IMPORTED_TARGET libgit2) 10 | 11 | add_executable(benchmark_bin EXCLUDE_FROM_ALL 12 | main.cpp 13 | benchmark.cpp benchmark.hpp 14 | ) 15 | 16 | target_compile_options(benchmark_bin 17 | PRIVATE 18 | -std=c++20 19 | ) 20 | 21 | target_include_directories(benchmark_bin 22 | PRIVATE 23 | ${CMAKE_CURRENT_SOURCE_DIR} 24 | ) 25 | 26 | target_link_libraries(benchmark_bin 27 | PRIVATE 28 | PkgConfig::bpf 29 | PkgConfig::git2 30 | benchmark::benchmark 31 | libbpfilter 32 | ) 33 | 34 | add_custom_target(benchmark 35 | COMMAND 36 | ${CMAKE_COMMAND} 37 | -E make_directory 38 | ${CMAKE_BINARY_DIR}/output/benchmarks 39 | COMMAND 40 | ${CMAKE_SOURCE_DIR}/tools/asroot 41 | $ 42 | --cli $ 43 | --daemon $ 44 | --srcdir ${CMAKE_SOURCE_DIR} 45 | --outfile ${CMAKE_BINARY_DIR}/output/benchmarks/{gitrev}.json 46 | DEPENDS benchmark_bin bfcli bpfilter 47 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 48 | USES_TERMINAL 49 | COMMENT "Running benchmarks" 50 | ) 51 | -------------------------------------------------------------------------------- /tools/checks/filtersrcs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import json 5 | import re 6 | 7 | def main() -> None: 8 | parser = argparse.ArgumentParser( 9 | prog='filtersrcs', 10 | description='Filter bpfilter\'s compile_commands.json to feed it to clang-tidy') 11 | parser.add_argument('--input', help="Input file") 12 | parser.add_argument('--output', help="Output file") 13 | parser.add_argument('-f','--filter', action='append', help='Filter to exclude file path from compile_commands.json', default=[]) 14 | args = parser.parse_args() 15 | 16 | with open(args.input, "r") as f: 17 | data = json.load(f) 18 | 19 | regexes = [ re.compile(x) for x in args.filter ] 20 | fdata = [ 21 | entry for entry in data 22 | if not any([r.match(entry.get("directory", "")) for r in regexes]) 23 | ] 24 | 25 | with open(args.output, "w") as f: 26 | json.dump(fdata, f) 27 | 28 | if __name__ == '__main__': 29 | main() 30 | -------------------------------------------------------------------------------- /tools/cmake/rawstubs.h.in: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | struct bpf_insn; 12 | 13 | @HDR_INC@ 14 | 15 | struct bf_rawstub { 16 | const void *elf; 17 | size_t len; 18 | } _bf_rawstubs[] = { 19 | @HDR_DECL@ 20 | }; 21 | -------------------------------------------------------------------------------- /tools/perfrec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import argparse 4 | import os 5 | import tempfile 6 | import shutil 7 | from subprocess import Popen, run 8 | 9 | 10 | def main() -> None: 11 | parser = argparse.ArgumentParser( 12 | prog="perfrec", 13 | description="perf wrapper to collect bpfilter/bfcli performance data and format them properly", 14 | ) 15 | parser.add_argument( 16 | "--output", 17 | "-o", 18 | type=str, 19 | default="perf.data", 20 | help="Path to the perf output file", 21 | ) 22 | parser.add_argument( 23 | "--target", 24 | "-t", 25 | choices=["firefox"], 26 | default=None, 27 | help="Target tool to format the data for (optional)", 28 | ) 29 | args, remaining_args = parser.parse_known_args() 30 | 31 | tmp_output = tempfile.NamedTemporaryFile() 32 | 33 | process = Popen( 34 | [ 35 | "perf", 36 | "record", 37 | "--output", 38 | tmp_output.name, 39 | "-g", 40 | "-F", 41 | "max", 42 | *remaining_args, 43 | ] 44 | ) 45 | 46 | process.wait() 47 | 48 | if args.target == "firefox": 49 | with open(args.output, "w") as f: 50 | run(["perf", "script", "-i", tmp_output.name, "-F", "+pid"], stdout=f) 51 | else: 52 | shutil.copyfile(tmp_output.name, args.output) 53 | 54 | sudo = os.getenv("SUDO_USER") 55 | if sudo: 56 | print( 57 | f"perfrecord started with 'sudo', changing output file ownership to '{sudo}'" 58 | ) 59 | os.chown(args.output, int(os.getenv("SUDO_UID")), int(os.getenv("SUDO_GID"))) 60 | 61 | 62 | if __name__ == "__main__": 63 | main() 64 | --------------------------------------------------------------------------------