├── .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 │ ├── generation.rst │ ├── modules │ │ ├── bpfilter.rst │ │ ├── core.rst │ │ ├── index.rst │ │ ├── lib.rst │ │ └── xlate │ │ │ ├── index.rst │ │ │ ├── ipt.rst │ │ │ └── nft.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 │ ├── bpfilter.service.in │ ├── cgen │ │ ├── cgen.c │ │ ├── cgen.h │ │ ├── cgroup.c │ │ ├── cgroup.h │ │ ├── dump.c │ │ ├── dump.h │ │ ├── fixup.c │ │ ├── fixup.h │ │ ├── jmp.c │ │ ├── jmp.h │ │ ├── matcher │ │ │ ├── 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 │ │ ├── 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 ├── core │ ├── CMakeLists.txt │ ├── bpf.c │ ├── bpf.h │ ├── btf.c │ ├── btf.h │ ├── chain.c │ ├── chain.h │ ├── counter.c │ ├── counter.h │ ├── dump.c │ ├── dump.h │ ├── flavor.c │ ├── flavor.h │ ├── front.c │ ├── front.h │ ├── helper.c │ ├── helper.h │ ├── hook.c │ ├── hook.h │ ├── if.c │ ├── if.h │ ├── io.c │ ├── io.h │ ├── list.c │ ├── list.h │ ├── logger.c │ ├── logger.h │ ├── marsh.c │ ├── marsh.h │ ├── matcher.c │ ├── matcher.h │ ├── ns.c │ ├── ns.h │ ├── request.c │ ├── request.h │ ├── response.c │ ├── response.h │ ├── rule.c │ ├── rule.h │ ├── set.c │ ├── set.h │ ├── verdict.c │ └── verdict.h ├── external │ ├── 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.c │ ├── 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 │ ├── murmur3.c │ └── murmur3.h ├── libbpfilter │ ├── CMakeLists.txt │ ├── bpfilter.h │ ├── bpfilter.pc.in │ ├── cli.c │ ├── generic.c │ ├── generic.h │ ├── ipt.c │ ├── nft.c │ └── version.c └── version.h.in ├── tests ├── e2e │ ├── CMakeLists.txt │ ├── cli.sh │ ├── e2e.c │ ├── e2e.h │ ├── genpkts.py │ ├── main.c │ ├── opts.c │ ├── opts.h │ └── 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 ├── 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 │ ├── core │ ├── btf.c │ ├── chain.c │ ├── flavor.c │ ├── front.c │ ├── helper.c │ ├── hook.c │ ├── list.c │ ├── marsh.c │ ├── matcher.c │ ├── rule.c │ └── verdict.c │ ├── fake.c │ ├── fake.h │ ├── main.c │ ├── mock.c │ └── mock.h └── tools ├── asroot ├── benchmarks ├── CMakeLists.txt ├── benchmark.cpp ├── benchmark.hpp └── main.cpp ├── checks ├── CMakeLists.txt └── filtersrcs ├── cmake └── GitVersion.cmake ├── 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-tools-extra \ 10 | cmake \ 11 | doxygen \ 12 | flex \ 13 | gcc \ 14 | gcc-c++ \ 15 | git-core \ 16 | google-benchmark-devel \ 17 | iproute \ 18 | iputils \ 19 | jq \ 20 | lcov \ 21 | libbpf-devel \ 22 | libcmocka-devel \ 23 | libgit2-devel \ 24 | libnl3-devel \ 25 | libtool \ 26 | procps-ng \ 27 | python3-breathe \ 28 | python3-dateutil \ 29 | python3-furo \ 30 | python3-GitPython \ 31 | python3-linuxdoc \ 32 | python3-scapy \ 33 | python3-sphinx && \ 34 | dnf clean all -y 35 | -------------------------------------------------------------------------------- /.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-tools-extra \ 10 | cmake \ 11 | doxygen \ 12 | flex \ 13 | gcc \ 14 | gcc-c++ \ 15 | git-core \ 16 | google-benchmark-devel \ 17 | iproute \ 18 | iputils \ 19 | jq \ 20 | lcov \ 21 | libbpf-devel \ 22 | libcmocka-devel \ 23 | libgit2-devel \ 24 | libnl3-devel \ 25 | libtool \ 26 | procps-ng \ 27 | python3-breathe \ 28 | python3-dateutil \ 29 | python3-furo \ 30 | python3-GitPython \ 31 | python3-linuxdoc \ 32 | python3-scapy \ 33 | python3-sphinx && \ 34 | dnf clean all -y 35 | -------------------------------------------------------------------------------- /.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-tools-extra \ 10 | cmake \ 11 | doxygen \ 12 | flex \ 13 | gcc \ 14 | gcc-c++ \ 15 | git-core \ 16 | google-benchmark-devel \ 17 | iproute \ 18 | iputils \ 19 | jq \ 20 | lcov \ 21 | libbpf-devel \ 22 | libcmocka-devel \ 23 | libgit2-devel \ 24 | libnl3-devel \ 25 | libtool \ 26 | procps-ng \ 27 | python3-breathe \ 28 | python3-dateutil \ 29 | python3-furo \ 30 | python3-GitPython \ 31 | python3-linuxdoc \ 32 | python3-scapy \ 33 | python3-sphinx && \ 34 | dnf clean all -y 35 | -------------------------------------------------------------------------------- /.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-tidy \ 8 | clang-format \ 9 | cmake \ 10 | doxygen \ 11 | flex \ 12 | furo \ 13 | g++ \ 14 | git \ 15 | iproute2 \ 16 | iputils-ping \ 17 | lcov \ 18 | libbenchmark-dev \ 19 | libbpf-dev \ 20 | libc-dev \ 21 | libcmocka-dev \ 22 | libgit2-dev \ 23 | libnl-3-dev \ 24 | libtool \ 25 | linux-tools-common \ 26 | make \ 27 | pkgconf \ 28 | procps \ 29 | python3-breathe \ 30 | python3-dateutil \ 31 | python3-git \ 32 | python3-pip \ 33 | python3-scapy \ 34 | python3-sphinx && \ 35 | rm -rf /var/lib/apt/lists/* 36 | 37 | RUN pip install --break-system-packages linuxdoc 38 | -------------------------------------------------------------------------------- /.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-tidy \ 8 | clang-format \ 9 | cmake \ 10 | doxygen \ 11 | flex \ 12 | furo \ 13 | g++ \ 14 | git \ 15 | iproute2 \ 16 | iputils-ping \ 17 | lcov \ 18 | libbenchmark-dev \ 19 | libbpf-dev \ 20 | libc-dev \ 21 | libcmocka-dev \ 22 | libgit2-dev \ 23 | libnl-3-dev \ 24 | libtool \ 25 | linux-tools-common \ 26 | make \ 27 | pkgconf \ 28 | procps \ 29 | python3-breathe \ 30 | python3-dateutil \ 31 | python3-git \ 32 | python3-pip \ 33 | python3-scapy \ 34 | python3-setuptools \ 35 | python3-sphinx && \ 36 | rm -rf /var/lib/apt/lists/* 37 | 38 | RUN pip install --break-system-packages linuxdoc 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Usual build folder 2 | build/ 3 | # VSCode configuration folder 4 | .vscode 5 | *.pyc 6 | __pycache__ 7 | -------------------------------------------------------------------------------- /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 = NO 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/dc4b1a841e277c4819fd7fc987e24fcc70ac77e0/doc/_static/demo_dark.gif -------------------------------------------------------------------------------- /doc/_static/demo_light.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facebook/bpfilter/dc4b1a841e277c4819fd7fc987e24fcc70ac77e0/doc/_static/demo_light.gif -------------------------------------------------------------------------------- /doc/_static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facebook/bpfilter/dc4b1a841e277c4819fd7fc987e24fcc70ac77e0/doc/_static/favicon.ico -------------------------------------------------------------------------------- /doc/_static/logo-dark-mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facebook/bpfilter/dc4b1a841e277c4819fd7fc987e24fcc70ac77e0/doc/_static/logo-dark-mode.png -------------------------------------------------------------------------------- /doc/_static/logo-light-mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/facebook/bpfilter/dc4b1a841e277c4819fd7fc987e24fcc70ac77e0/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", "sphinx.ext.autosectionlabel"] 14 | breathe_projects = { 15 | "@PROJECT_NAME@": "@CMAKE_CURRENT_BINARY_DIR@/xml" 16 | } 17 | breathe_default_project = "@PROJECT_NAME@" 18 | breathe_default_members = ("members", "private-members", "undoc-members") 19 | breathe_domain_by_extension = { 20 | "h": "c", 21 | "c": "c" 22 | } 23 | 24 | breathe_show_define_initializer = False # Avoid showing badly formatted functions-like macros code. 25 | breathe_show_enumvalue_initializer = True 26 | breathe_show_include = True 27 | breathe_implementation_filename_extensions = [".c"] 28 | 29 | # -- Options for HTML output ------------------------------------------------- 30 | html_theme = "furo" 31 | html_static_path = ["_static"] 32 | html_favicon = "_static/favicon.ico" 33 | html_theme_options = { 34 | "light_logo": "logo-light-mode.png", 35 | "dark_logo": "logo-dark-mode.png", 36 | "sidebar_hide_name": True, 37 | } 38 | -------------------------------------------------------------------------------- /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/build.rst: -------------------------------------------------------------------------------- 1 | Build from sources 2 | ================== 3 | 4 | This document describes the process to build ``bpfilter`` from sources. While ``bpfilter`` can be built on most systems, a recent (6.6+) Linux kernel is required with ``libbpf`` 1.2+ to run the ``bpfilter`` daemon. ``bpfilter`` officially supports Fedora 40+, CentOS Stream 9+, and Ubuntu 24.04+. 5 | 6 | If you want to perform a full build of ``bpfilter`` (including all test tests, code check, benchmarks, and documentation), the following dependencies are required: 7 | 8 | .. code-block:: shell 9 | 10 | # Fedora 40+ 11 | sudo dnf -y install \ 12 | autoconf \ 13 | automake \ 14 | gawk \ 15 | bpftool \ 16 | bison \ 17 | clang-tools-extra \ 18 | cmake \ 19 | doxygen \ 20 | flex \ 21 | gcc \ 22 | gcc-c++ \ 23 | git-core \ 24 | google-benchmark-devel \ 25 | iproute \ 26 | iputils \ 27 | jq \ 28 | lcov \ 29 | libbpf-devel \ 30 | libcmocka-devel \ 31 | libgit2-devel \ 32 | libnl3-devel \ 33 | libtool \ 34 | procps-ng \ 35 | python3-breathe \ 36 | python3-dateutil \ 37 | python3-furo \ 38 | python3-GitPython \ 39 | python3-linuxdoc \ 40 | python3-scapy \ 41 | python3-sphinx 42 | 43 | # Ubuntu 24.04+ 44 | sudo apt-get install -y \ 45 | autoconf \ 46 | automake \ 47 | bison \ 48 | clang-tidy \ 49 | clang-format \ 50 | cmake \ 51 | doxygen \ 52 | flex \ 53 | furo \ 54 | g++ \ 55 | git \ 56 | iproute2 \ 57 | iputils-ping \ 58 | lcov \ 59 | libbenchmark-dev \ 60 | libbpf-dev \ 61 | libc-dev \ 62 | libcmocka-dev \ 63 | libgit2-dev \ 64 | libnl-3-dev \ 65 | libtool \ 66 | linux-tools-common \ 67 | make \ 68 | pkgconf \ 69 | procps \ 70 | python3-breathe \ 71 | python3-dateutil \ 72 | python3-git \ 73 | python3-pip \ 74 | python3-scapy \ 75 | python3-sphinx 76 | 77 | You can then use CMake to generate the build system: 78 | 79 | .. code-block:: shell 80 | 81 | cmake -S $BPFILTER_SOURCE -B $BUILD_DIRECTORY 82 | 83 | The usual CMake options are allowed (e.g. ``CMAKE_BUILD_TYPE``, ``CMAKE_INSTALL_PREFIX``...). The build configuration is modular, so you're free to enable/disable some parts of the projects according to your needs: 84 | 85 | - ``-DNO_DOCS``: disable the documentation, including the coverage and benchmarks report. 86 | - ``-DNO_TESTS``: disable unit tests, end-to-end tests, and integration tests. 87 | - ``-DNO_CHECKS``: disable style check and static analyzer. 88 | - ``-DNO_BENCHMARKS``: disable benchmarks. 89 | 90 | A full configuration (without any part disabled) will provide the following targets: 91 | 92 | - ``core``, ``bpfilter``, ``libbpfilter``, ``bfcli``: the ``bpfilter`` binaries. 93 | - ``test``, ``e2e``, ``integration``: the test suits. See :doc:`tests` for more information. 94 | - ``check``: run ``clang-tidy`` and ``clang-format`` against the source files. 95 | - ``benchmarks``: run the benchmarks on ``bpfilter``. 96 | 97 | The build artifacts are located in ``$BUILD_DIRECTORY/output``. 98 | -------------------------------------------------------------------------------- /doc/developers/generation.rst: -------------------------------------------------------------------------------- 1 | Programs generation 2 | =================== 3 | 4 | Bytecode generation 5 | ------------------- 6 | 7 | .. doxygenfile:: program.h 8 | 9 | Switch-cases 10 | ------------ 11 | 12 | .. doxygenfile:: swich.h 13 | 14 | Error handling 15 | -------------- 16 | 17 | .. doxygenfile:: jmp.h 18 | 19 | Printing debug messages 20 | ----------------------- 21 | 22 | .. doxygenfile:: printer.h 23 | -------------------------------------------------------------------------------- /doc/developers/modules/bpfilter.rst: -------------------------------------------------------------------------------- 1 | bpfilter 2 | ======== 3 | 4 | .. doxygenfile:: ctx.h 5 | -------------------------------------------------------------------------------- /doc/developers/modules/core.rst: -------------------------------------------------------------------------------- 1 | core 2 | ==== 3 | 4 | Namespaces 5 | ---------- 6 | 7 | .. doxygenfile:: ns.h 8 | :sections: briefdescription detaileddescription typedef struct innerclass enum var define func 9 | -------------------------------------------------------------------------------- /doc/developers/modules/index.rst: -------------------------------------------------------------------------------- 1 | Modules 2 | ======= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Modules 7 | 8 | core 9 | bpfilter 10 | xlate/index 11 | lib 12 | 13 | ``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``: 14 | 15 | - ``core``: core definitions used by the daemon, ``bfcli``, and ``libbpfilter``. 16 | - ``bpfilter``: daemon logic, including translation of the front-end (client) data into ``bpfilter``'s internal format, and the BPF bytecode generation logic. 17 | - ``bfcli``: generic client to communicate with the daemon. 18 | - ``libbpfilter``: static and shared library to communicate with the daemon. 19 | - ``external``: non-``bpfilter`` code, imported into the project to provide consistent external definitions. 20 | -------------------------------------------------------------------------------- /doc/developers/modules/lib.rst: -------------------------------------------------------------------------------- 1 | libbpfilter 2 | =========== 3 | 4 | .. doxygenfile:: bpfilter.h 5 | -------------------------------------------------------------------------------- /doc/developers/modules/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/xlate/ipt.rst: -------------------------------------------------------------------------------- 1 | ``ipt`` 2 | ============ 3 | 4 | .. doxygenfile:: xlate/ipt/ipt.c 5 | -------------------------------------------------------------------------------- /doc/developers/modules/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/packets_processing.rst: -------------------------------------------------------------------------------- 1 | Packets processing 2 | ================== 3 | 4 | Matchers 5 | -------- 6 | 7 | .. doxygenfile:: matcher.h 8 | -------------------------------------------------------------------------------- /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/style 17 | developers/tests 18 | developers/packets_processing 19 | developers/generation 20 | developers/modules/index 21 | 22 | .. toctree:: 23 | :hidden: 24 | :caption: External 25 | 26 | GitHub repository 27 | external/benchmarks/index 28 | external/coverage/index 29 | 30 | | 31 | | 32 | 33 | .. raw:: html 34 | 35 |
An eBPF-based packet filtering framework.
36 | 37 | | 38 | 39 | **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. 40 | 41 | | 42 | 43 | .. image:: _static/demo_light.gif 44 | :class: only-light 45 | :align: center 46 | :width: 600 47 | 48 | .. image:: _static/demo_dark.gif 49 | :class: only-dark 50 | :align: center 51 | :width: 600 52 | 53 | | 54 | 55 | .. raw:: html 56 | 57 |
Key features
58 | 59 | - **High performance**: utilizes eBPF's near-native performance capabilities 60 | - **Flexible integration**: use the custom ``iptables`` integration or **bpfilter**'s ``bfcli`` command line for extended functionalities 61 | - **Low overhead**: minimal resource consumption with maximized efficiency 62 | - **Developer-friendly**: clean architecture with clear separation of components 63 | 64 | **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. 65 | 66 | Want to know more about **bpfilter**? Check the :doc:`user's guide `, the :doc:`developer documentation `, or watch our talk at `Scale `_! 67 | -------------------------------------------------------------------------------- /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/bfcli) 8 | file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/generated/include/bfcli) 9 | 10 | add_custom_command( 11 | COMMAND 12 | ${BISON_BIN} 13 | --debug 14 | --defines=${CMAKE_CURRENT_BINARY_DIR}/generated/include/bfcli/parser.h 15 | -o ${CMAKE_CURRENT_BINARY_DIR}/generated/bfcli/parser.c 16 | ${CMAKE_CURRENT_SOURCE_DIR}/parser.y 17 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/parser.y 18 | OUTPUT 19 | ${CMAKE_CURRENT_BINARY_DIR}/generated/include/bfcli/parser.h 20 | ${CMAKE_CURRENT_BINARY_DIR}/generated/bfcli/parser.c 21 | COMMENT "Generate the Bison parser" 22 | ) 23 | 24 | add_custom_target(bfcli_parser 25 | DEPENDS 26 | ${CMAKE_CURRENT_BINARY_DIR}/generated/include/bfcli/parser.h 27 | ${CMAKE_CURRENT_BINARY_DIR}/generated/bfcli/parser.c 28 | ) 29 | 30 | add_custom_command( 31 | COMMAND 32 | ${FLEX_BIN} 33 | --header-file=${CMAKE_CURRENT_BINARY_DIR}/generated/include/bfcli/lexer.h 34 | -o ${CMAKE_CURRENT_BINARY_DIR}/generated/bfcli/lexer.c 35 | ${CMAKE_CURRENT_SOURCE_DIR}/lexer.l 36 | DEPENDS 37 | ${CMAKE_CURRENT_SOURCE_DIR}/lexer.l 38 | ${CMAKE_CURRENT_BINARY_DIR}/generated/include/bfcli/parser.h 39 | OUTPUT 40 | ${CMAKE_CURRENT_BINARY_DIR}/generated/include/bfcli/lexer.h 41 | ${CMAKE_CURRENT_BINARY_DIR}/generated/bfcli/lexer.c 42 | COMMENT "Generate the Flex lexer" 43 | ) 44 | 45 | add_custom_target(bfcli_lexer 46 | DEPENDS 47 | ${CMAKE_CURRENT_BINARY_DIR}/generated/include/bfcli/lexer.h 48 | ${CMAKE_CURRENT_BINARY_DIR}/generated/bfcli/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_BINARY_DIR}/include/version.h 59 | ${CMAKE_CURRENT_BINARY_DIR}/generated/include/bfcli/parser.h 60 | ${CMAKE_CURRENT_BINARY_DIR}/generated/bfcli/parser.c 61 | ${CMAKE_CURRENT_BINARY_DIR}/generated/include/bfcli/lexer.h 62 | ${CMAKE_CURRENT_BINARY_DIR}/generated/bfcli/lexer.c 63 | ) 64 | 65 | target_compile_definitions(bfcli 66 | PRIVATE 67 | BF_CONTACT="${BF_CONTACT}" 68 | "YY_READ_BUF_SIZE=(yy_read_buf_size)" 69 | ) 70 | 71 | target_include_directories(bfcli 72 | PRIVATE 73 | ${CMAKE_SOURCE_DIR}/src 74 | ${CMAKE_BINARY_DIR}/include 75 | ${CMAKE_CURRENT_BINARY_DIR}/generated/include 76 | ${CMAKE_CURRENT_BINARY_DIR}/generated/include/bfcli 77 | ) 78 | 79 | target_link_libraries(bfcli 80 | PRIVATE 81 | bf_global_flags 82 | core 83 | libbpfilter 84 | ) 85 | 86 | install(TARGETS bfcli 87 | DESTINATION ${CMAKE_INSTALL_SBINDIR} 88 | ) 89 | -------------------------------------------------------------------------------- /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_load(const struct bfc_opts *opts); 14 | int bfc_chain_attach(const struct bfc_opts *opts); 15 | int bfc_chain_update(const struct bfc_opts *opts); 16 | int bfc_chain_flush(const struct bfc_opts *opts); 17 | -------------------------------------------------------------------------------- /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 "bfcli/helper.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "bfcli/lexer.h" 14 | #include "bfcli/parser.h" 15 | #include "core/logger.h" 16 | 17 | // To speed up parsing very large rulesets, we can increase YY_READ_BUF_SIZE 18 | int yy_read_buf_size; 19 | 20 | #define _BF_LEX_MIN_BUF_POW 14 21 | #define _BF_LEX_MAX_BUF_POW 20 22 | 23 | static int _bf_compute_lexer_buf_size(size_t len) 24 | { 25 | int val = _BF_LEX_MIN_BUF_POW; 26 | 27 | if (len) { 28 | val = (int)sizeof(len) * 8 - __builtin_clzl(len); 29 | val = bf_min(bf_max(val - 3, _BF_LEX_MIN_BUF_POW), _BF_LEX_MAX_BUF_POW); 30 | } 31 | 32 | return 1 << val; 33 | } 34 | 35 | int bfc_parse_file(const char *file, struct bfc_ruleset *ruleset) 36 | { 37 | FILE *rules; 38 | struct stat stt; 39 | int r; 40 | 41 | if (stat(file, &stt) == -1) 42 | return bf_err_r(errno, "failed to stat file %s:", file); 43 | 44 | yy_read_buf_size = _bf_compute_lexer_buf_size(stt.st_size); 45 | bf_dbg("yy_read_buf_size choosen is %d", yy_read_buf_size); 46 | 47 | rules = fopen(file, "r"); 48 | if (!rules) 49 | return bf_err_r(errno, "failed to read rules from %s:", file); 50 | 51 | yyin = rules; 52 | 53 | r = yyparse(ruleset); 54 | if (r == 1) 55 | r = bf_err_r(-EINVAL, "failed to parse rules, invalid syntax"); 56 | else if (r == 2) 57 | r = bf_err_r(-ENOMEM, "failed to parse rules, not enough memory"); 58 | 59 | return r; 60 | } 61 | 62 | int bfc_parse_str(const char *str, struct bfc_ruleset *ruleset) 63 | { 64 | YY_BUFFER_STATE buffer; 65 | unsigned long str_size; 66 | int r; 67 | 68 | str_size = strlen(str); 69 | yy_read_buf_size = _bf_compute_lexer_buf_size(str_size); 70 | bf_dbg("yy_read_buf_size choosen is %d", yy_read_buf_size); 71 | 72 | buffer = yy_scan_string(str); 73 | 74 | r = yyparse(ruleset); 75 | if (r == 1) 76 | r = bf_err_r(-EINVAL, "failed to parse rules, invalid syntax"); 77 | else if (r == 2) 78 | r = bf_err_r(-ENOMEM, "failed to parse rules, not enough memory"); 79 | 80 | yy_delete_buffer(buffer); 81 | 82 | return r; 83 | } 84 | -------------------------------------------------------------------------------- /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 | #include "core/list.h" 10 | 11 | struct bfc_ruleset; 12 | 13 | int bfc_parse_file(const char *file, struct bfc_ruleset *ruleset); 14 | int bfc_parse_str(const char *str, struct bfc_ruleset *ruleset); 15 | -------------------------------------------------------------------------------- /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 "bfcli/chain.h" 15 | #include "bfcli/helper.h" 16 | #include "bfcli/opts.h" 17 | #include "bfcli/print.h" 18 | #include "bfcli/ruleset.h" 19 | #include "core/chain.h" 20 | #include "core/helper.h" 21 | #include "core/hook.h" 22 | #include "core/list.h" 23 | #include "core/logger.h" 24 | #include "core/request.h" 25 | #include "core/response.h" 26 | #include "core/set.h" 27 | #include "libbpfilter/bpfilter.h" 28 | #include "version.h" 29 | 30 | static void _bfc_print_version(FILE *stream, struct argp_state *state) 31 | { 32 | UNUSED(state); 33 | 34 | (void)fprintf(stream, "bfcli version %s, libbpfilter version %s\n", 35 | BF_VERSION, bf_version()); 36 | } 37 | 38 | int main(int argc, char *argv[]) 39 | { 40 | _clean_bfc_opts_ struct bfc_opts opts = bfc_opts_default(); 41 | int r; 42 | 43 | argp_program_version_hook = &_bfc_print_version; 44 | argp_program_bug_address = BF_CONTACT; 45 | 46 | r = bfc_opts_parse(&opts, argc, argv); 47 | if (r < 0) 48 | return r; 49 | 50 | return opts.cmd->cb(&opts); 51 | } 52 | 53 | void yyerror(struct bfc_ruleset *ruleset, const char *fmt, ...) 54 | { 55 | UNUSED(ruleset); 56 | 57 | va_list args; 58 | 59 | va_start(args, fmt); 60 | bf_err_v(fmt, args); 61 | va_end(args); 62 | } 63 | -------------------------------------------------------------------------------- /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 "core/hook.h" 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_LOAD, 46 | BFC_ACTION_ATTACH, 47 | BFC_ACTION_UPDATE, 48 | BFC_ACTION_FLUSH, 49 | _BFC_ACTION_MAX, 50 | }; 51 | 52 | struct bfc_opts_cmd; 53 | 54 | /** 55 | * @brief Command line options configured for bfcli 56 | */ 57 | struct bfc_opts 58 | { 59 | const struct bfc_opts_cmd *cmd; 60 | 61 | enum bfc_object object; 62 | enum bfc_action action; 63 | 64 | const char *from_str; 65 | const char *from_file; 66 | const char *name; 67 | struct bf_hookopts hookopts; 68 | }; 69 | 70 | struct bfc_opts_cmd 71 | { 72 | enum bfc_object object; 73 | enum bfc_action action; 74 | const char *name; 75 | int valid_opts; 76 | const char *doc; 77 | int (*cb)(const struct bfc_opts *opts); 78 | }; 79 | 80 | /** 81 | * @brief Initialize a `bfc_opts` object to default values. 82 | */ 83 | #define bfc_opts_default() \ 84 | {.object = _BFC_OBJECT_MAX, .action = _BFC_ACTION_MAX}; 85 | 86 | void bfc_opts_clean(struct bfc_opts *opts); 87 | int bfc_opts_parse(struct bfc_opts *opts, int argc, char **argv); 88 | -------------------------------------------------------------------------------- /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 "core/list.h" 12 | 13 | struct bf_chain; 14 | struct bf_hookopts; 15 | 16 | /** 17 | * Print a single chain. 18 | * 19 | * @param chain Chain to print. Can't be NULL. 20 | * @param hookopts Chain's hook options. If NULL, it is assumed the chain is not 21 | * attached to a hook. 22 | * @param counters List of counters for the chain. This function expects the 23 | * first to entries in the list to be the policy and error counters. 24 | * Then, every rule should have an entry in the list in the order they 25 | * are defined, even if the rule doesn't have counters enabled. 26 | */ 27 | void bfc_chain_dump(struct bf_chain *chain, struct bf_hookopts *hookopts, 28 | bf_list *counters); 29 | 30 | /** 31 | * Print ruleset information and counters to the console. 32 | * 33 | * @param chains List of chains to print. 34 | * @param hookopts List of hookoptions to print. 35 | * @param counters List of counters to print. 36 | */ 37 | int bfc_ruleset_dump(bf_list *chains, bf_list *hookopts, bf_list *counters); 38 | -------------------------------------------------------------------------------- /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 "bfcli/ruleset.h" 8 | 9 | #include "bfcli/helper.h" 10 | #include "bfcli/opts.h" 11 | #include "bfcli/print.h" 12 | #include "libbpfilter/bpfilter.h" 13 | 14 | void bfc_ruleset_clean(struct bfc_ruleset *ruleset) 15 | { 16 | bf_assert(ruleset); 17 | 18 | bf_list_clean(&ruleset->chains); 19 | bf_list_clean(&ruleset->hookopts); 20 | bf_list_clean(&ruleset->sets); 21 | } 22 | 23 | int bfc_ruleset_set(const struct bfc_opts *opts) 24 | { 25 | _clean_bfc_ruleset_ struct bfc_ruleset ruleset = bfc_ruleset_default(); 26 | int r; 27 | 28 | if (opts->from_file) 29 | r = bfc_parse_file(opts->from_file, &ruleset); 30 | else 31 | r = bfc_parse_str(opts->from_str, &ruleset); 32 | if (r) 33 | bf_err_r(r, "failed to parse ruleset"); 34 | 35 | r = bf_ruleset_set(&ruleset.chains, &ruleset.hookopts); 36 | if (r) 37 | bf_err_r(r, "failed to set ruleset"); 38 | 39 | return r; 40 | } 41 | 42 | int bfc_ruleset_get(const struct bfc_opts *opts) 43 | { 44 | UNUSED(opts); 45 | 46 | _clean_bf_list_ bf_list chains = bf_list_default(bf_chain_free, NULL); 47 | _clean_bf_list_ bf_list hookopts = bf_list_default(bf_hookopts_free, NULL); 48 | _clean_bf_list_ bf_list counters = bf_list_default(bf_list_free, NULL); 49 | int r; 50 | 51 | r = bf_ruleset_get(&chains, &hookopts, &counters); 52 | if (r < 0) 53 | return bf_err_r(r, "failed to request ruleset"); 54 | 55 | r = bfc_ruleset_dump(&chains, &hookopts, &counters); 56 | if (r) 57 | return bf_err_r(r, "failed to dump ruleset"); 58 | 59 | return 0; 60 | } 61 | 62 | int bfc_ruleset_flush(const struct bfc_opts *opts) 63 | { 64 | UNUSED(opts); 65 | 66 | return bf_ruleset_flush(); 67 | } 68 | -------------------------------------------------------------------------------- /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 "core/chain.h" 10 | #include "core/hook.h" 11 | #include "core/list.h" 12 | #include "core/set.h" 13 | 14 | #define bfc_ruleset_default() \ 15 | { \ 16 | .chains = bf_list_default(bf_chain_free, bf_chain_marsh), \ 17 | .sets = bf_list_default(bf_set_free, bf_set_marsh), \ 18 | .hookopts = bf_list_default(bf_hookopts_free, bf_hookopts_marsh), \ 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/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 "core/flavor.h" 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 "core/dump.h" 12 | #include "core/helper.h" 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_TYPE_FUNC_CALL] = "BF_FIXUP_TYPE_FUNC_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 | static const char *_bf_fixup_func_to_str(enum bf_fixup_func func) 59 | { 60 | static const char *str[] = { 61 | [BF_FIXUP_FUNC_UPDATE_COUNTERS] = "BF_FIXUP_FUNC_UPDATE_COUNTERS", 62 | }; 63 | 64 | bf_assert(0 <= func && func < _BF_FIXUP_FUNC_MAX); 65 | static_assert(ARRAY_SIZE(str) == _BF_FIXUP_FUNC_MAX); 66 | 67 | return str[func]; 68 | } 69 | 70 | void bf_fixup_dump(const struct bf_fixup *fixup, prefix_t *prefix) 71 | { 72 | bf_assert(fixup); 73 | bf_assert(prefix); 74 | 75 | DUMP(prefix, "struct bf_fixup at %p", fixup); 76 | 77 | bf_dump_prefix_push(prefix); 78 | 79 | DUMP(prefix, "type: %s", _bf_fixup_type_to_str(fixup->type)); 80 | DUMP(prefix, "insn: %zu", fixup->insn); 81 | 82 | switch (fixup->type) { 83 | case BF_FIXUP_TYPE_JMP_NEXT_RULE: 84 | case BF_FIXUP_TYPE_COUNTERS_MAP_FD: 85 | case BF_FIXUP_TYPE_PRINTER_MAP_FD: 86 | // No specific value to dump 87 | break; 88 | case BF_FIXUP_TYPE_SET_MAP_FD: 89 | DUMP(prefix, "set_index: %lu", fixup->attr.set_index); 90 | break; 91 | case BF_FIXUP_TYPE_FUNC_CALL: 92 | DUMP(prefix, "function: %s", 93 | _bf_fixup_func_to_str(fixup->attr.function)); 94 | break; 95 | default: 96 | DUMP(prefix, "unsupported bf_fixup_type: %d", fixup->type); 97 | break; 98 | }; 99 | 100 | bf_dump_prefix_pop(prefix); 101 | } 102 | -------------------------------------------------------------------------------- /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 "core/dump.h" 11 | 12 | /** 13 | * Field to fixup in a @c bpf_insn structure. 14 | */ 15 | enum bf_fixup_insn 16 | { 17 | BF_FIXUP_INSN_OFF, 18 | BF_FIXUP_INSN_IMM, 19 | _BF_FIXUP_INSN_MAX, 20 | }; 21 | 22 | /** 23 | * Custom function to call. 24 | * 25 | * A fixup can be used to jump to a custom function defined later in the 26 | * BPF program. This enum contains the list of functions available. 27 | */ 28 | enum bf_fixup_func 29 | { 30 | BF_FIXUP_FUNC_UPDATE_COUNTERS, 31 | _BF_FIXUP_FUNC_MAX, 32 | }; 33 | 34 | /** 35 | * Type of the fixup. 36 | * 37 | * Defines how a fixup should be processed. 38 | */ 39 | enum bf_fixup_type 40 | { 41 | /// Jump to the beginning of the next rule. 42 | BF_FIXUP_TYPE_JMP_NEXT_RULE, 43 | /// Set the counters map file descriptor in the @c BPF_LD_MAP_FD instruction. 44 | BF_FIXUP_TYPE_COUNTERS_MAP_FD, 45 | /// Set the printer map file descriptor in the @c BPF_LD_MAP_FD instruction. 46 | BF_FIXUP_TYPE_PRINTER_MAP_FD, 47 | /// Set a set map file descriptor in the @c BPF_LD_MAP_FD instruction. 48 | BF_FIXUP_TYPE_SET_MAP_FD, 49 | /// Jump to a custom function. 50 | BF_FIXUP_TYPE_FUNC_CALL, 51 | _BF_FIXUP_TYPE_MAX 52 | }; 53 | 54 | union bf_fixup_attr 55 | { 56 | size_t set_index; 57 | enum bf_fixup_func function; 58 | }; 59 | 60 | struct bf_fixup 61 | { 62 | enum bf_fixup_type type; 63 | size_t insn; 64 | union bf_fixup_attr attr; 65 | }; 66 | 67 | #define _free_bf_fixup_ __attribute__((cleanup(bf_fixup_free))) 68 | 69 | int bf_fixup_new(struct bf_fixup **fixup, enum bf_fixup_type type, 70 | size_t insn_offset, const union bf_fixup_attr *attr); 71 | void bf_fixup_free(struct bf_fixup **fixup); 72 | void bf_fixup_dump(const struct bf_fixup *fixup, prefix_t *prefix); 73 | -------------------------------------------------------------------------------- /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 "bpfilter/cgen/jmp.h" 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "bpfilter/cgen/program.h" 15 | #include "core/logger.h" 16 | 17 | void bf_jmpctx_cleanup(struct bf_jmpctx *ctx) 18 | { 19 | if (ctx->program) { 20 | struct bpf_insn *insn = &ctx->program->img[ctx->insn_idx]; 21 | size_t off = ctx->program->img_size - ctx->insn_idx - 1U; 22 | 23 | if (off > SHRT_MAX) 24 | bf_warn("jump offset overflow: %ld", off); 25 | 26 | insn->off = (int16_t)off; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /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/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 | /** 12 | * Generate the bytecode for the BF_MATCHER_SET_* 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, or a negative errno value on failure. 17 | */ 18 | int bf_matcher_generate_set(struct bf_program *program, 19 | const struct bf_matcher *matcher); 20 | -------------------------------------------------------------------------------- /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 "bpfilter/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 "bpfilter/cgen/program.h" 19 | #include "core/logger.h" 20 | #include "core/matcher.h" 21 | 22 | #include "external/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 *)&matcher->payload; 28 | size_t offset = matcher->type == 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 (matcher->op) { 35 | case BF_MATCHER_EQ: 36 | EMIT_FIXUP_JMP_NEXT_RULE( 37 | program, BPF_JMP_IMM(BPF_JNE, BPF_REG_1, htobe16(*port), 0)); 38 | break; 39 | case BF_MATCHER_NE: 40 | EMIT_FIXUP_JMP_NEXT_RULE( 41 | program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, htobe16(*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(matcher->op), matcher->op); 57 | } 58 | 59 | return 0; 60 | } 61 | 62 | int bf_matcher_generate_udp(struct bf_program *program, 63 | const struct bf_matcher *matcher) 64 | { 65 | int r; 66 | 67 | EMIT_FIXUP_JMP_NEXT_RULE(program, 68 | BPF_JMP_IMM(BPF_JNE, BPF_REG_8, IPPROTO_UDP, 0)); 69 | EMIT(program, 70 | BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l4_hdr))); 71 | 72 | switch (matcher->type) { 73 | case BF_MATCHER_UDP_SPORT: 74 | case BF_MATCHER_UDP_DPORT: 75 | r = _bf_matcher_generate_udp_port(program, matcher); 76 | break; 77 | default: 78 | return bf_err_r(-EINVAL, "unknown matcher type %d", matcher->type); 79 | }; 80 | 81 | return r; 82 | } 83 | -------------------------------------------------------------------------------- /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 "core/flavor.h" 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 "core/flavor.h" 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 "bpfilter/cgen/program.h" 13 | #include "bpfilter/cgen/stub.h" 14 | #include "core/flavor.h" 15 | #include "core/helper.h" 16 | #include "core/verdict.h" 17 | 18 | #include "external/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 "core/flavor.h" 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 "core/front.h" 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 "bpfilter/xlate/front.h" 7 | 8 | #include "core/front.h" 9 | #include "core/helper.h" 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 "core/front.h" 9 | 10 | struct bf_request; 11 | struct bf_response; 12 | struct bf_marsh; 13 | 14 | /** 15 | * @struct bf_front_ops 16 | * 17 | * @todo Make bf_front_ops.request_handler take a const struct bf_request. 18 | * 19 | * @var bf_front_ops::setup 20 | * Setup the front. 21 | * @var bf_front_ops::teardown 22 | * Teardown the front. 23 | * @var bf_front_ops::request_handler 24 | * Handle a request. 25 | */ 26 | struct bf_front_ops 27 | { 28 | int (*setup)(void); 29 | int (*teardown)(void); 30 | int (*request_handler)(struct bf_request *request, 31 | struct bf_response **response); 32 | int (*marsh)(struct bf_marsh **marsh); 33 | int (*unmarsh)(struct bf_marsh *marsh); 34 | }; 35 | 36 | /** 37 | * Retrieve the @ref bf_front_ops structure for a specific front. 38 | * 39 | * @param front Front to get the @ref bf_front_ops for. 40 | * @return 41 | */ 42 | const struct bf_front_ops *bf_front_ops_get(enum bf_front front); 43 | -------------------------------------------------------------------------------- /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 "core/dump.h" 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(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 "bpfilter/xlate/front.h" 9 | #include "core/helper.h" 10 | #include "core/marsh.h" 11 | #include "core/request.h" 12 | #include "core/response.h" 13 | 14 | static int _bf_nft_setup(void) 15 | { 16 | return 0; 17 | } 18 | 19 | static int _bf_nft_teardown(void) 20 | { 21 | return 0; 22 | } 23 | 24 | static int _bf_nft_marsh(struct bf_marsh **marsh) 25 | { 26 | UNUSED(marsh); 27 | 28 | return 0; 29 | } 30 | 31 | static int _bf_nft_unmarsh(struct bf_marsh *marsh) 32 | { 33 | UNUSED(marsh); 34 | 35 | return 0; 36 | } 37 | 38 | static int _bf_nft_request_handler(struct bf_request *request, 39 | struct bf_response **response) 40 | { 41 | UNUSED(request); 42 | 43 | bf_assert(response); 44 | 45 | return bf_response_new_failure(response, -ENOTSUP); 46 | } 47 | 48 | const struct bf_front_ops nft_front = { 49 | .setup = _bf_nft_setup, 50 | .teardown = _bf_nft_teardown, 51 | .request_handler = _bf_nft_request_handler, 52 | .marsh = _bf_nft_marsh, 53 | .unmarsh = _bf_nft_unmarsh, 54 | }; 55 | -------------------------------------------------------------------------------- /src/core/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 | 7 | set(core_srcs 8 | ${CMAKE_BINARY_DIR}/include/version.h 9 | ${CMAKE_CURRENT_SOURCE_DIR}/bpf.h ${CMAKE_CURRENT_SOURCE_DIR}/bpf.c 10 | ${CMAKE_CURRENT_SOURCE_DIR}/btf.h ${CMAKE_CURRENT_SOURCE_DIR}/btf.c 11 | ${CMAKE_CURRENT_SOURCE_DIR}/chain.h ${CMAKE_CURRENT_SOURCE_DIR}/chain.c 12 | ${CMAKE_CURRENT_SOURCE_DIR}/counter.h ${CMAKE_CURRENT_SOURCE_DIR}/counter.c 13 | ${CMAKE_CURRENT_SOURCE_DIR}/dump.h ${CMAKE_CURRENT_SOURCE_DIR}/dump.c 14 | ${CMAKE_CURRENT_SOURCE_DIR}/flavor.h ${CMAKE_CURRENT_SOURCE_DIR}/flavor.c 15 | ${CMAKE_CURRENT_SOURCE_DIR}/front.h ${CMAKE_CURRENT_SOURCE_DIR}/front.c 16 | ${CMAKE_CURRENT_SOURCE_DIR}/helper.h ${CMAKE_CURRENT_SOURCE_DIR}/helper.c 17 | ${CMAKE_CURRENT_SOURCE_DIR}/hook.h ${CMAKE_CURRENT_SOURCE_DIR}/hook.c 18 | ${CMAKE_CURRENT_SOURCE_DIR}/if.h ${CMAKE_CURRENT_SOURCE_DIR}/if.c 19 | ${CMAKE_CURRENT_SOURCE_DIR}/io.h ${CMAKE_CURRENT_SOURCE_DIR}/io.c 20 | ${CMAKE_CURRENT_SOURCE_DIR}/list.h ${CMAKE_CURRENT_SOURCE_DIR}/list.c 21 | ${CMAKE_CURRENT_SOURCE_DIR}/logger.h ${CMAKE_CURRENT_SOURCE_DIR}/logger.c 22 | ${CMAKE_CURRENT_SOURCE_DIR}/marsh.h ${CMAKE_CURRENT_SOURCE_DIR}/marsh.c 23 | ${CMAKE_CURRENT_SOURCE_DIR}/matcher.h ${CMAKE_CURRENT_SOURCE_DIR}/matcher.c 24 | ${CMAKE_CURRENT_SOURCE_DIR}/ns.h ${CMAKE_CURRENT_SOURCE_DIR}/ns.c 25 | ${CMAKE_CURRENT_SOURCE_DIR}/request.h ${CMAKE_CURRENT_SOURCE_DIR}/request.c 26 | ${CMAKE_CURRENT_SOURCE_DIR}/response.h ${CMAKE_CURRENT_SOURCE_DIR}/response.c 27 | ${CMAKE_CURRENT_SOURCE_DIR}/rule.h ${CMAKE_CURRENT_SOURCE_DIR}/rule.c 28 | ${CMAKE_CURRENT_SOURCE_DIR}/set.h ${CMAKE_CURRENT_SOURCE_DIR}/set.c 29 | ${CMAKE_CURRENT_SOURCE_DIR}/verdict.h ${CMAKE_CURRENT_SOURCE_DIR}/verdict.c 30 | ) 31 | 32 | add_library(core 33 | OBJECT 34 | ${core_srcs} 35 | ) 36 | 37 | target_include_directories(core 38 | PUBLIC 39 | ${CMAKE_SOURCE_DIR}/src 40 | ${CMAKE_BINARY_DIR}/include 41 | ) 42 | 43 | target_link_libraries(core 44 | PUBLIC 45 | bf_global_flags 46 | PkgConfig::bpf 47 | ) 48 | -------------------------------------------------------------------------------- /src/core/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 | /** 9 | * Load current kernel's BTF data. 10 | * 11 | * This function has to be called early, so BPF program generation can access 12 | * kernel's BTF data and use the kfunc's BTF ID. 13 | * 14 | * @return 0 on success, or negative errno value on failure. 15 | */ 16 | int bf_btf_setup(void); 17 | 18 | /** 19 | * Free current kernel's BTF data. 20 | */ 21 | void bf_btf_teardown(void); 22 | 23 | /** 24 | * Get BTF ID of a kernel function. 25 | * 26 | * Linux' BTF data must be loaded with @ref bf_btf_setup before calling this 27 | * function. 28 | * 29 | * @param name Name of the kernel function. 30 | * @return BTF ID on success, or negative errno value on failure. 31 | */ 32 | int bf_btf_get_id(const char *name); 33 | 34 | /** 35 | * Get a type name from a BTF ID from the kernel BTF data. 36 | * 37 | * Linux BTF data must be loaded with @ref bf_btf_setup before calling this 38 | * function. If @c id is invalid, or not part of the kernel's BTF data, @c NULL 39 | * is returned. 40 | * 41 | * @param id Type ID to look for. 42 | * @return Name of the type represented by @c id or @c NULL . 43 | */ 44 | const char *bf_btf_get_name(int id); 45 | 46 | /** 47 | * Check if BPF token is supported by the current system. 48 | * 49 | * Read the kernel's BTF data to check if `prog_token_fd` is a valid field, if 50 | * so it is assume BPF token is supported by the current kernel. 51 | * 52 | * @return 0 on success, or a negative errno value on failure, including: 53 | * - `-ENOENT`: `prog_token_fd` can't be found, meaning BPF token is likely 54 | * unsupported. 55 | */ 56 | int bf_btf_kernel_has_token(void); 57 | 58 | /** 59 | * Get the offset of a field in a kernel structure. 60 | * 61 | * Use Linux' BTF data to find the offset of a specific field in a structure. 62 | * This function will fail if the offset of a bitfield is requested. 63 | * 64 | * @param struct_name Name of the structure to find the offset in. Can't be 65 | * NULL. 66 | * @param field_name Name of the field to get the offset of. Can't be NULL. 67 | * @return Offset of @p field_name if found, negative error value on failure. 68 | */ 69 | int bf_btf_get_field_off(const char *struct_name, const char *field_name); 70 | -------------------------------------------------------------------------------- /src/core/counter.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | #include "core/counter.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "core/helper.h" 13 | #include "core/marsh.h" 14 | 15 | int bf_counter_new(struct bf_counter **counter, uint64_t packets, 16 | uint64_t bytes) 17 | { 18 | _cleanup_free_ struct bf_counter *_counter = NULL; 19 | 20 | bf_assert(counter); 21 | 22 | _counter = malloc(sizeof(*_counter)); 23 | if (!_counter) 24 | return -ENOMEM; 25 | 26 | _counter->bytes = bytes; 27 | _counter->packets = packets; 28 | 29 | *counter = TAKE_PTR(_counter); 30 | 31 | return 0; 32 | } 33 | 34 | int bf_counter_new_from_marsh(struct bf_counter **counter, 35 | const struct bf_marsh *marsh) 36 | { 37 | _free_bf_counter_ struct bf_counter *_counter = NULL; 38 | struct bf_marsh *elem = NULL; 39 | 40 | bf_assert(counter && marsh); 41 | 42 | _counter = malloc(sizeof(*_counter)); 43 | if (!_counter) 44 | return -ENOMEM; 45 | 46 | if (!(elem = bf_marsh_next_child(marsh, elem))) 47 | return -EINVAL; 48 | memcpy(&_counter->packets, elem->data, sizeof(_counter->packets)); 49 | 50 | if (!(elem = bf_marsh_next_child(marsh, elem))) 51 | return -EINVAL; 52 | memcpy(&_counter->bytes, elem->data, sizeof(_counter->bytes)); 53 | 54 | *counter = TAKE_PTR(_counter); 55 | 56 | return 0; 57 | } 58 | 59 | void bf_counter_free(struct bf_counter **counter) 60 | { 61 | bf_assert(counter); 62 | 63 | if (!*counter) 64 | return; 65 | 66 | freep((void *)counter); 67 | } 68 | 69 | int bf_counter_marsh(const struct bf_counter *counter, struct bf_marsh **marsh) 70 | { 71 | _free_bf_marsh_ struct bf_marsh *_marsh = NULL; 72 | int r; 73 | 74 | bf_assert(counter && marsh); 75 | 76 | r = bf_marsh_new(&_marsh, NULL, 0); 77 | if (r < 0) 78 | return r; 79 | 80 | r = bf_marsh_add_child_raw(&_marsh, &counter->packets, 81 | sizeof(counter->packets)); 82 | if (r < 0) 83 | return r; 84 | 85 | r = bf_marsh_add_child_raw(&_marsh, &counter->bytes, 86 | sizeof(counter->bytes)); 87 | if (r < 0) 88 | return r; 89 | 90 | *marsh = TAKE_PTR(_marsh); 91 | 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /src/core/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 "core/helper.h" 11 | #include "core/marsh.h" 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 | } bf_packed; 28 | 29 | #define _free_bf_counter_ __attribute__((__cleanup__(bf_counter_free))) 30 | 31 | /** 32 | * Free a @ref bf_counter structure. 33 | * 34 | * If @p counter is NULL, nothing is done. 35 | * 36 | * @param counter Counter to free. Can't be NULL. 37 | */ 38 | void bf_counter_free(struct bf_counter **counter); 39 | 40 | /** 41 | * Create a new @ref bf_counter with the given packets and bytes. 42 | * 43 | * On success, @p counter is set to the newly allocated @ref bf_counter, 44 | * owned by the caller. 45 | * 46 | * @param counter Output pointer for the new @ref bf_counter. Can't be NULL. 47 | * @param packets Initial packet count. 48 | * @param bytes Initial byte count. 49 | * @return 0 on success, negative errno on error. 50 | */ 51 | int bf_counter_new(struct bf_counter **counter, uint64_t packets, 52 | uint64_t bytes); 53 | 54 | /** 55 | * Marshal a @ref bf_counter into a @ref bf_marsh object. 56 | * 57 | * The resulting marsh contains two children: @c packets and @c bytes. 58 | * On success, @p marsh is set to the new @ref bf_marsh, owned by the caller. 59 | * 60 | * @param counter Counter to marshal. Can't be NULL. 61 | * @param marsh Output pointer for the @ref bf_marsh. Can't be NULL. 62 | * @return 0 on success, negative errno on error. 63 | */ 64 | int bf_counter_marsh(const struct bf_counter *counter, struct bf_marsh **marsh); 65 | 66 | /** 67 | * Create a @ref bf_counter from a @ref bf_marsh. 68 | * 69 | * Reads two children (for @c packets and @c bytes). On success, @p counter 70 | * is set to the new @ref bf_counter, owned by the caller. 71 | * 72 | * @param counter Output pointer for the new @ref bf_counter. Can't be NULL. 73 | * @param marsh Marsh containing the @c packets and @c bytes. Can't be NULL. 74 | * @return 0 on success, negative errno on error. 75 | */ 76 | int bf_counter_new_from_marsh(struct bf_counter **counter, 77 | const struct bf_marsh *marsh); 78 | -------------------------------------------------------------------------------- /src/core/dump.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "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/core/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 "core/logger.h" 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/core/flavor.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "core/flavor.h" 7 | 8 | #include "core/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_GROUP", 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/core/flavor.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 "core/verdict.h" 9 | 10 | struct bf_program; 11 | 12 | /** 13 | * @file flavor.h 14 | * 15 | * "Flavor" as defined by bpfilter are types of BPF program, characterized by 16 | * the prototype of the main function, the valid returns values, and the 17 | * way they are attached to the kernel. 18 | * 19 | * A flavor is used to defines specific part of the BPF program for a 20 | * codegen. For example: access to the packet's data, return value... 21 | */ 22 | 23 | /** 24 | * @enum bf_flavor 25 | * 26 | * Define a valid BPF flavor type for bpfilter. 27 | * 28 | * @var bf_flavor::BF_FLAVOR_TC 29 | * TC flavor. 30 | * @var bf_flavor::BF_FLAVOR_NF 31 | * For BPF_PROG_TYPE_NETFILTER programs. Expects a struct bpf_nf_ctx argument. 32 | */ 33 | enum bf_flavor 34 | { 35 | BF_FLAVOR_TC, 36 | BF_FLAVOR_NF, 37 | BF_FLAVOR_XDP, 38 | 39 | /** cgroup BPF programs are a middle ground between TC and BPF_NETFILTER 40 | * programs: 41 | * - Input: struct __sk_buff 42 | * - Headers available: from L3 43 | * - Return code: 0 to drop, 1 to accept 44 | */ 45 | BF_FLAVOR_CGROUP, 46 | _BF_FLAVOR_MAX, 47 | }; 48 | 49 | /** 50 | * @struct bf_flavor_ops 51 | * 52 | * Define a set of operations that can be performed for a specific BPF flavor. 53 | * 54 | * @var bf_flavor_ops::gen_inline_epilogue 55 | * Generate the epilogue of the BPF program. 56 | */ 57 | struct bf_flavor_ops 58 | { 59 | /** 60 | * Generate the flavor-specific prologue of the BPF program. 61 | * 62 | * When this callback is called during the program generation, @c BPF_REG_1 63 | * contains the program's argument. It must then: 64 | * - Calculate and store the packet's size into the runtime context 65 | * - Store the input interface index into the runtime context 66 | * - If L2 is not available, set the L3 protocol ID into @c BPF_REG_7 and 67 | * set @c l3_offset in the runtime context to 0. 68 | * - Call @ref bf_stub_parse_l2_ethhdr, @ref bf_stub_parse_l3_hdr, and 69 | * @ref bf_stub_parse_l4_hdr depending on which headers are available. 70 | */ 71 | int (*gen_inline_prologue)(struct bf_program *program); 72 | 73 | int (*gen_inline_epilogue)(struct bf_program *program); 74 | 75 | /** 76 | * Generates a flavor-specific return code corresponding to the verdict. 77 | * 78 | * Note this function only needs to handle terminal verdicts - verdicts that 79 | * stop further packet processing. Non-terminal verdicts do not need return 80 | * codes and therefore do not need to be handled by get_verdict(). 81 | */ 82 | int (*get_verdict)(enum bf_verdict verdict); 83 | }; 84 | 85 | /** 86 | * Convert a bpfilter flavor to a string. 87 | * 88 | * @param flavor Flavor to convert. Must be valid. 89 | * @return String representation of @p flavor. 90 | */ 91 | const char *bf_flavor_to_str(enum bf_flavor flavor); 92 | -------------------------------------------------------------------------------- /src/core/front.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "core/front.h" 7 | 8 | #include "core/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/core/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/core/helper.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "core/helper.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "core/logger.h" 17 | 18 | #define OPEN_MODE_644 (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) 19 | 20 | void closep(int *fd) 21 | { 22 | if (*fd == -1) 23 | return; 24 | 25 | if (close(*fd)) 26 | bf_warn_r(errno, "failed to close fd %d, assuming file is closed", *fd); 27 | 28 | *fd = -1; 29 | } 30 | 31 | int bf_strncpy(char *dst, size_t len, const char *src) 32 | { 33 | size_t src_len; 34 | size_t copy_len; 35 | 36 | bf_assert(dst && src); 37 | bf_assert(len); 38 | 39 | src_len = strlen(src); 40 | copy_len = bf_min(src_len, len - 1); 41 | 42 | memcpy(dst, src, copy_len); 43 | dst[copy_len] = '\0'; 44 | 45 | return copy_len != src_len ? -E2BIG : 0; 46 | } 47 | 48 | int bf_read_file(const char *path, void **buf, size_t *len) 49 | { 50 | _cleanup_close_ int fd = -1; 51 | _cleanup_free_ void *_buf = NULL; 52 | size_t _len; 53 | ssize_t r; 54 | 55 | bf_assert(path); 56 | bf_assert(buf); 57 | bf_assert(len); 58 | 59 | fd = open(path, O_RDONLY); 60 | if (fd < 0) 61 | return bf_err_r(errno, "failed to open %s", path); 62 | 63 | _len = lseek(fd, 0, SEEK_END); 64 | lseek(fd, 0, SEEK_SET); 65 | 66 | _buf = malloc(_len); 67 | if (!_buf) 68 | return bf_err_r(errno, "failed to allocate memory"); 69 | 70 | r = read(fd, _buf, _len); 71 | if (r < 0) 72 | return bf_err_r(errno, "failed to read serialized data"); 73 | if ((size_t)r != _len) 74 | return bf_err_r(EIO, "can't read full serialized data"); 75 | 76 | closep(&fd); 77 | 78 | *buf = TAKE_PTR(_buf); 79 | *len = _len; 80 | 81 | return 0; 82 | } 83 | 84 | int bf_write_file(const char *path, const void *buf, size_t len) 85 | { 86 | _cleanup_close_ int fd = -1; 87 | ssize_t r; 88 | 89 | bf_assert(path); 90 | bf_assert(buf); 91 | 92 | fd = open(path, O_TRUNC | O_CREAT | O_WRONLY, OPEN_MODE_644); 93 | if (fd < 0) 94 | return bf_err_r(errno, "failed to open %s", path); 95 | 96 | r = write(fd, buf, len); 97 | if (r < 0) 98 | return bf_err_r(errno, "failed to write to %s", path); 99 | if ((size_t)r != len) 100 | return bf_err_r(EIO, "can't write full data to %s", path); 101 | 102 | closep(&fd); 103 | 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /src/core/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 "core/if.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "core/helper.h" 20 | #include "core/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 bf_err_r(errno, "failed to get ifindex for interface '%s'", 33 | name); 34 | } 35 | 36 | if (r > INT_MAX) 37 | return bf_err_r(-E2BIG, "ifindex is too big: %d", r); 38 | 39 | return (int)r; 40 | } 41 | 42 | const char *bf_if_name_from_index(int index) 43 | { 44 | if (!if_indextoname(index, _bf_if_name)) { 45 | bf_warn_r(errno, "failed to get ifname for interface '%d'", index); 46 | strncpy(_bf_if_name, "", IFNAMSIZ); 47 | } 48 | 49 | return _bf_if_name; 50 | } 51 | 52 | ssize_t bf_if_get_ifaces(struct bf_if_iface **ifaces) 53 | { 54 | _cleanup_free_ struct bf_if_iface *_ifaces = NULL; 55 | struct if_nameindex *if_ni, *it; 56 | ssize_t n_ifaces = 0; 57 | size_t i = 0; 58 | 59 | bf_assert(ifaces); 60 | 61 | if_ni = if_nameindex(); 62 | if (!if_ni) 63 | return bf_err_r(errno, "failed to fetch interfaces details"); 64 | 65 | // Gather the number of interfaces to allocate the memory. 66 | for (it = if_ni; it->if_index != 0 || it->if_name != NULL; ++it) 67 | ++n_ifaces; 68 | 69 | if (n_ifaces == 0) 70 | return 0; 71 | 72 | _ifaces = malloc(n_ifaces * sizeof(*_ifaces)); 73 | if (!_ifaces) { 74 | if_freenameindex(if_ni); 75 | return bf_err_r(-ENOMEM, 76 | "failed to allocate memory for interfaces buffer"); 77 | } 78 | 79 | for (it = if_ni; it->if_index != 0 || it->if_name != NULL; ++it) { 80 | _ifaces[i].index = it->if_index; 81 | 82 | if (it->if_index) 83 | strncpy(_ifaces[i].name, it->if_name, IF_NAMESIZE); 84 | else 85 | bf_warn("interface %d has no name", it->if_index); 86 | 87 | ++i; 88 | } 89 | 90 | *ifaces = TAKE_PTR(_ifaces); 91 | 92 | if_freenameindex(if_ni); 93 | 94 | return n_ifaces; 95 | } 96 | -------------------------------------------------------------------------------- /src/core/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 | #include 11 | 12 | /** 13 | * @file if.h 14 | * 15 | * Header files `net/if.h` and `arpa/inet.h` are incompatible with some kernel 16 | * headers, due to symbols being defined in both. However, the Linux kernel used 17 | * in `bpfilter` are mandatory, we can't do without them. In order to avoid 18 | * further issues due to this incompatibility, `net/if.h` and `arpa/inet/h` are 19 | * now hidden in `if.c`, and `bpfilter`-specific functions have been defined to 20 | * provide the required functionalities. 21 | */ 22 | 23 | /** 24 | * Local interface details. 25 | */ 26 | struct bf_if_iface 27 | { 28 | /// Index of the interface on the system. 29 | unsigned int index; 30 | /// Name of the interface. 31 | char name[IFNAMSIZ]; 32 | }; 33 | 34 | /** 35 | * Get an interface index from its name. 36 | * 37 | * @param name Name of the interface. Can't be NULL. 38 | * @return Index of the interface. If the interface name is unknown, a 39 | * negative errno value is returned. 40 | */ 41 | int bf_if_index_from_name(const char *name); 42 | 43 | /** 44 | * Get an interface name from its index. 45 | * 46 | * If the interface index is invalid, or not found, @p buf is filled with 47 | * "". 48 | * 49 | * This function copy the interface name into a static buffer, this would 50 | * probably be an issue for multi-threaded application, but thankfully bpfilter 51 | * is a single-threaded daemon. 52 | * 53 | * @param index Index of the interface. 54 | * @return Pointer to a static buffer containing the interface name. 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/core/marsh.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "core/marsh.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "core/helper.h" 13 | 14 | int bf_marsh_new(struct bf_marsh **marsh, const void *data, size_t data_len) 15 | { 16 | struct bf_marsh *_marsh = NULL; 17 | 18 | bf_assert(marsh); 19 | bf_assert(!data ? !data_len : 1); 20 | 21 | _marsh = malloc(sizeof(struct bf_marsh) + data_len); 22 | if (!_marsh) 23 | return -ENOMEM; 24 | 25 | _marsh->data_len = data_len; 26 | bf_memcpy(_marsh->data, data, data_len); 27 | 28 | *marsh = TAKE_PTR(_marsh); 29 | 30 | return 0; 31 | } 32 | 33 | void bf_marsh_free(struct bf_marsh **marsh) 34 | { 35 | bf_assert(marsh); 36 | 37 | if (!*marsh) 38 | return; 39 | 40 | free(*marsh); 41 | *marsh = NULL; 42 | } 43 | 44 | int bf_marsh_add_child_obj(struct bf_marsh **marsh, const struct bf_marsh *obj) 45 | { 46 | _free_bf_marsh_ struct bf_marsh *new = NULL; 47 | size_t new_data_len; 48 | 49 | bf_assert(marsh && *marsh); 50 | bf_assert(obj); 51 | 52 | new_data_len = (*marsh)->data_len + bf_marsh_size(obj); 53 | 54 | new = malloc(sizeof(struct bf_marsh) + new_data_len); 55 | if (!new) 56 | return -ENOMEM; 57 | 58 | memcpy(new->data, (*marsh)->data, (*marsh)->data_len); 59 | memcpy(new->data + (*marsh)->data_len, obj, bf_marsh_size(obj)); 60 | new->data_len = new_data_len; 61 | 62 | bf_marsh_free(marsh); 63 | *marsh = TAKE_PTR(new); 64 | 65 | return 0; 66 | } 67 | 68 | int bf_marsh_add_child_raw(struct bf_marsh **marsh, const void *data, 69 | size_t data_len) 70 | { 71 | _free_bf_marsh_ struct bf_marsh *child = NULL; 72 | int r; 73 | 74 | bf_assert(marsh && *marsh); 75 | bf_assert(!data ? !data_len : 1); 76 | 77 | r = bf_marsh_new(&child, data, data_len); 78 | if (r < 0) 79 | return r; 80 | 81 | r = bf_marsh_add_child_obj(marsh, child); 82 | if (r < 0) 83 | return r; 84 | 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /src/core/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 "core/ns.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "core/helper.h" 18 | #include "core/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 | (void)snprintf(ns_dir_path, NS_DIR_PATH_LEN, "/proc/%d/ns", pid); 64 | dirfd = open(ns_dir_path, O_DIRECTORY, O_RDONLY); 65 | if (dirfd < 0) 66 | return bf_err_r(errno, "failed to open ns directory '%s'", ns_dir_path); 67 | 68 | r = _bf_ns_info_init(&_ns.net, "net", dirfd); 69 | if (r) { 70 | return bf_err_r(r, "failed to read 'net' namespace in '%s'", 71 | ns_dir_path); 72 | } 73 | 74 | r = _bf_ns_info_init(&_ns.mnt, "mnt", dirfd); 75 | if (r) { 76 | return bf_err_r(r, "failed to read 'mnt' namespace in '%s'", 77 | ns_dir_path); 78 | } 79 | 80 | *ns = bf_ns_move(_ns); 81 | 82 | return 0; 83 | } 84 | 85 | void bf_ns_clean(struct bf_ns *ns) 86 | { 87 | bf_assert(ns); 88 | 89 | closep(&ns->net.fd); 90 | closep(&ns->mnt.fd); 91 | } 92 | 93 | int bf_ns_set(const struct bf_ns *ns, const struct bf_ns *oldns) 94 | { 95 | int r; 96 | 97 | if (!oldns || ns->net.inode != oldns->net.inode) { 98 | r = setns(ns->net.fd, CLONE_NEWNET); 99 | if (r) 100 | return bf_err_r(r, "failed to switch to a network namespace"); 101 | } 102 | 103 | if (!oldns || ns->mnt.inode != oldns->mnt.inode) { 104 | r = setns(ns->mnt.fd, CLONE_NEWNS); 105 | if (r) 106 | return bf_err_r(r, "failed to switch to a mount namespace"); 107 | } 108 | 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /src/core/request.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "core/request.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "core/helper.h" 15 | 16 | int bf_request_new(struct bf_request **request, const void *data, 17 | size_t data_len) 18 | { 19 | _free_bf_request_ struct bf_request *_request = NULL; 20 | 21 | bf_assert(request); 22 | bf_assert(!(!!data ^ !!data_len)); 23 | 24 | _request = calloc(1, sizeof(*_request) + data_len); 25 | if (!_request) 26 | return -ENOMEM; 27 | 28 | if (data) { 29 | memcpy(_request->data, data, data_len); 30 | _request->data_len = data_len; 31 | } 32 | 33 | *request = TAKE_PTR(_request); 34 | 35 | return 0; 36 | } 37 | 38 | int bf_request_copy(struct bf_request **dest, const struct bf_request *src) 39 | { 40 | _free_bf_request_ struct bf_request *_request = NULL; 41 | 42 | bf_assert(dest); 43 | bf_assert(src); 44 | 45 | _request = bf_memdup(src, bf_request_size(src)); 46 | if (!_request) 47 | return -ENOMEM; 48 | 49 | *dest = TAKE_PTR(_request); 50 | 51 | return 0; 52 | } 53 | 54 | void bf_request_free(struct bf_request **request) 55 | { 56 | free(*request); 57 | *request = NULL; 58 | } 59 | 60 | const char *bf_request_cmd_to_str(enum bf_request_cmd cmd) 61 | { 62 | static const char *cmd_strs[] = { 63 | [BF_REQ_RULESET_FLUSH] = "BF_REQ_RULESET_FLUSH", 64 | [BF_REQ_RULESET_GET] = "BF_REQ_RULESET_GET", 65 | [BF_REQ_RULESET_SET] = "BF_REQ_RULESET_SET", 66 | [BF_REQ_CHAIN_SET] = "BF_REQ_CHAIN_SET", 67 | [BF_REQ_CHAIN_GET] = "BF_REQ_CHAIN_GET", 68 | [BF_REQ_CHAIN_LOAD] = "BF_REQ_CHAIN_LOAD", 69 | [BF_REQ_CHAIN_ATTACH] = "BF_REQ_CHAIN_ATTACH", 70 | [BF_REQ_CHAIN_UPDATE] = "BF_REQ_CHAIN_UPDATE", 71 | [BF_REQ_CHAIN_FLUSH] = "BF_REQ_CHAIN_FLUSH", 72 | [BF_REQ_COUNTERS_SET] = "BF_REQ_COUNTERS_SET", 73 | [BF_REQ_COUNTERS_GET] = "BF_REQ_COUNTERS_GET", 74 | [BF_REQ_CUSTOM] = "BF_REQ_CUSTOM", 75 | }; 76 | 77 | static_assert(ARRAY_SIZE(cmd_strs) == _BF_REQ_CMD_MAX, 78 | "missing entries in bf_request_cmd array"); 79 | 80 | return cmd_strs[cmd]; 81 | } 82 | -------------------------------------------------------------------------------- /src/core/response.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "core/response.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "core/helper.h" 14 | 15 | int bf_response_new_raw(struct bf_response **response, size_t data_len) 16 | { 17 | bf_assert(response); 18 | 19 | *response = malloc(sizeof(**response) + data_len); 20 | if (!*response) 21 | return -ENOMEM; 22 | 23 | (*response)->type = BF_RES_SUCCESS; 24 | 25 | return 0; 26 | } 27 | 28 | int bf_response_new_success(struct bf_response **response, const char *data, 29 | size_t data_len) 30 | { 31 | _free_bf_response_ struct bf_response *_response = NULL; 32 | 33 | bf_assert(response); 34 | bf_assert(!(!!data ^ !!data_len)); 35 | 36 | _response = calloc(1, sizeof(*_response) + data_len); 37 | if (!_response) 38 | return -ENOMEM; 39 | 40 | _response->type = BF_RES_SUCCESS; 41 | _response->data_len = data_len; 42 | bf_memcpy(_response->data, data, data_len); 43 | 44 | *response = TAKE_PTR(_response); 45 | 46 | return 0; 47 | } 48 | 49 | int bf_response_new_failure(struct bf_response **response, int error) 50 | { 51 | _free_bf_response_ struct bf_response *_response = NULL; 52 | 53 | bf_assert(response); 54 | 55 | _response = calloc(1, sizeof(*_response)); 56 | if (!_response) 57 | return -ENOMEM; 58 | 59 | _response->type = BF_RES_FAILURE; 60 | _response->error = error; 61 | 62 | *response = TAKE_PTR(_response); 63 | 64 | return 0; 65 | } 66 | 67 | void bf_response_free(struct bf_response **response) 68 | { 69 | free(*response); 70 | *response = NULL; 71 | } 72 | 73 | int bf_response_copy(struct bf_response **dest, const struct bf_response *src) 74 | { 75 | _free_bf_response_ struct bf_response *_response = NULL; 76 | 77 | bf_assert(dest); 78 | bf_assert(src); 79 | 80 | _response = bf_memdup(src, bf_response_size(src)); 81 | if (!_response) 82 | return -ENOMEM; 83 | 84 | *dest = TAKE_PTR(_response); 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /src/core/set.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 "core/dump.h" 11 | #include "core/list.h" 12 | 13 | /** 14 | * @file set.h 15 | * 16 | * A set represent a set of data of the same type. They allow bpfilter to 17 | * perform O(1) lookup in large pools of data of the same type. 18 | * 19 | * For example, a set would be useful to match a network packet against many 20 | * different IP addresses. Instead of create a different rule for each IP 21 | * address, they could be added into a set and the BPF program would comparing 22 | * the packet's IP address to the whole set a once. 23 | * 24 | * Sets are implemented as BPF hash maps, allowing for O(1) lookup for a given 25 | * key. @ref bf_set_type is used to define the set type and represent the type 26 | * of values contained in the set. 27 | * 28 | * From a BPF bytecode perspective, the set type affects how the packet's 29 | * data is processed to form the key to lookup into the BPF map. See @ref 30 | * bf_set_type for more details. 31 | */ 32 | 33 | struct bf_marsh; 34 | 35 | #define _free_bf_set_ __attribute__((__cleanup__(bf_set_free))) 36 | 37 | /** 38 | * Convenience macro to initialize a list of @ref bf_set . 39 | * 40 | * @return An initialized @ref bf_list that can contain @ref bf_set objects. 41 | */ 42 | #define bf_set_list() \ 43 | ((bf_list) {.ops = {.free = (bf_list_ops_free)bf_set_free, \ 44 | .marsh = (bf_list_ops_marsh)bf_set_marsh}}) 45 | 46 | /** 47 | * Supported set types. 48 | * 49 | * The set's type define the size of the elements in the set, as well as how 50 | * the packet should be processed to generate the key to lookup for in the map. 51 | */ 52 | enum bf_set_type 53 | { 54 | /// Keys are IPv4 addresses (4 bytes). 55 | BF_SET_IP4, 56 | /// Keys are (source IPv6 address, source port) (18 bytes). 57 | BF_SET_SRCIP6PORT, 58 | /// Keys are IPv6 addresses (16 bytes). 59 | BF_SET_SRCIP6, 60 | _BF_SET_MAX, 61 | }; 62 | 63 | struct bf_set 64 | { 65 | enum bf_set_type type; 66 | size_t elem_size; 67 | bf_list elems; 68 | }; 69 | 70 | int bf_set_new(struct bf_set **set, enum bf_set_type type); 71 | int bf_set_new_from_marsh(struct bf_set **set, const struct bf_marsh *marsh); 72 | void bf_set_free(struct bf_set **set); 73 | int bf_set_marsh(const struct bf_set *set, struct bf_marsh **marsh); 74 | void bf_set_dump(const struct bf_set *set, prefix_t *prefix); 75 | 76 | int bf_set_add_elem(struct bf_set *set, void *elem); 77 | 78 | const char *bf_set_type_to_str(enum bf_set_type type); 79 | int bf_set_type_from_str(const char *str, enum bf_set_type *type); 80 | -------------------------------------------------------------------------------- /src/core/verdict.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "core/verdict.h" 7 | 8 | #include 9 | #include 10 | 11 | #include "core/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/core/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/external/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/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/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/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/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/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/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/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/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/asm/errno.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/external/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/asm/socket.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/external/asm/sockios.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/external/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/asm/swab.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/external/asm/types.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/external/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/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/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/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/linux/errno.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/external/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/external/murmur3.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // MurmurHash3 was written by Austin Appleby, and is placed in the 3 | // public domain. The author hereby disclaims copyright to this source 4 | // code. 5 | // 6 | // Implemented by @PeterScott https://github.com/PeterScott/murmur3 7 | 8 | #pragma once 9 | 10 | #include 11 | 12 | void murmur3_x86_32(const void *key, int len, uint32_t seed, void *out); 13 | void murmur3_x86_128(const void *key, int len, uint32_t seed, void *out); 14 | void murmur3_x64_128(const void *key, int len, uint32_t seed, void *out); 15 | -------------------------------------------------------------------------------- /src/libbpfilter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 3 | 4 | set(libbpfilter_srcs 5 | ${CMAKE_CURRENT_SOURCE_DIR}/bpfilter.h 6 | ${CMAKE_CURRENT_SOURCE_DIR}/cli.c 7 | ${CMAKE_CURRENT_SOURCE_DIR}/generic.h ${CMAKE_CURRENT_SOURCE_DIR}/generic.c 8 | ${CMAKE_CURRENT_SOURCE_DIR}/ipt.c 9 | ${CMAKE_CURRENT_SOURCE_DIR}/nft.c 10 | ${CMAKE_BINARY_DIR}/include/version.h ${CMAKE_CURRENT_SOURCE_DIR}/version.c 11 | ) 12 | 13 | configure_file( 14 | ${CMAKE_SOURCE_DIR}/src/libbpfilter/bpfilter.h 15 | ${CMAKE_BINARY_DIR}/output/include/bpfilter/bpfilter.h 16 | ) 17 | 18 | configure_file( 19 | ${CMAKE_SOURCE_DIR}/src/libbpfilter/bpfilter.pc.in 20 | ${CMAKE_BINARY_DIR}/output/lib/pkgconfig/bpfilter.pc 21 | @ONLY 22 | ) 23 | 24 | add_library(libbpfilter SHARED 25 | ${libbpfilter_srcs} 26 | ) 27 | 28 | set_target_properties(libbpfilter PROPERTIES OUTPUT_NAME bpfilter) 29 | 30 | target_include_directories(libbpfilter 31 | PRIVATE 32 | ${CMAKE_SOURCE_DIR}/src 33 | ${CMAKE_BINARY_DIR}/include 34 | ) 35 | 36 | target_link_libraries(libbpfilter 37 | PRIVATE 38 | bf_global_flags 39 | core 40 | ) 41 | 42 | set_target_properties(libbpfilter PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}) 43 | 44 | install(TARGETS libbpfilter) 45 | 46 | install( 47 | FILES ${CMAKE_SOURCE_DIR}/src/libbpfilter/bpfilter.h 48 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/bpfilter 49 | ) 50 | 51 | install( 52 | FILES ${CMAKE_BINARY_DIR}/output/lib/pkgconfig/bpfilter.pc 53 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig 54 | ) 55 | -------------------------------------------------------------------------------- /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/generic.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "libbpfilter/generic.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "core/helper.h" 14 | #include "core/io.h" 15 | #include "core/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 | -------------------------------------------------------------------------------- /src/libbpfilter/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 | -------------------------------------------------------------------------------- /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 "core/front.h" 13 | #include "core/request.h" 14 | #include "core/response.h" 15 | #include "libbpfilter/generic.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, data, len); 27 | if (r < 0) 28 | return r; 29 | 30 | request->front = BF_FRONT_NFT; 31 | 32 | r = bf_send(request, &response); 33 | if (r < 0) 34 | return r; 35 | 36 | return response->type == BF_RES_FAILURE ? response->error : 0; 37 | } 38 | 39 | int bf_nft_sendrecv(const struct nlmsghdr *req, size_t req_len, 40 | struct nlmsghdr *res, size_t *res_len) 41 | { 42 | _free_bf_request_ struct bf_request *request = NULL; 43 | _free_bf_response_ struct bf_response *response = NULL; 44 | int r; 45 | 46 | if (!req || !req_len || !res || !res_len) 47 | return -EINVAL; 48 | 49 | if (req_len != req->nlmsg_len) 50 | return -EINVAL; 51 | 52 | r = bf_request_new(&request, req, req_len); 53 | if (r < 0) 54 | return r; 55 | 56 | request->front = BF_FRONT_NFT; 57 | 58 | r = bf_send(request, &response); 59 | if (r < 0) 60 | return r; 61 | 62 | if (response->type == BF_RES_FAILURE) 63 | return response->error; 64 | 65 | // The response should be a netlink message 66 | if (response->data_len < NLMSG_HDRLEN) 67 | return -EMSGSIZE; 68 | 69 | if (((struct nlmsghdr *)response->data)->nlmsg_len != response->data_len) 70 | return -EMSGSIZE; 71 | 72 | if (response->data_len > *res_len) { 73 | *res_len = response->data_len; 74 | return -EMSGSIZE; 75 | } 76 | 77 | memcpy(res, response->data, response->data_len); 78 | *res_len = response->data_len; 79 | 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /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 "version.h" 7 | 8 | const char *bf_version(void) 9 | { 10 | return BF_VERSION; 11 | } 12 | -------------------------------------------------------------------------------- /src/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 | -------------------------------------------------------------------------------- /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/libbpfilter 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 | core 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 | DEPENDS 63 | bpfilter 64 | bfcli 65 | e2e_bin 66 | setuserns_bin 67 | COMMENT "Running end-to-end tests" 68 | ) 69 | -------------------------------------------------------------------------------- /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 "core/chain.h" 12 | #include "core/counter.h" 13 | #include "core/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 "core/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 | PUBLIC 21 | ${CMAKE_SOURCE_DIR}/tests 22 | ) 23 | 24 | target_link_libraries(harness 25 | PUBLIC 26 | bf_global_flags 27 | core 28 | PkgConfig::bpf 29 | PkgConfig::cmocka 30 | PkgConfig::nl 31 | ) 32 | -------------------------------------------------------------------------------- /tests/harness/daemon.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "harness/daemon.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "core/helper.h" 20 | #include "core/logger.h" 21 | #include "harness/process.h" 22 | 23 | #define _BF_DAEMON_START_TIMEOUT 5 24 | #define _BF_DAEMON_START_SLEEP 100000 25 | 26 | int bf_test_daemon_init(struct bf_test_daemon *daemon, const char *path, 27 | uint32_t options) 28 | { 29 | char *args[__builtin_ctz(_BF_TEST_DAEMON_LAST) + 1] = {}; 30 | size_t nargs = 0; 31 | 32 | bf_assert(daemon); 33 | 34 | if (options & BF_TEST_DAEMON_TRANSIENT) 35 | args[nargs++] = "--transient"; 36 | if (options & BF_TEST_DAEMON_NO_CLI) 37 | args[nargs++] = "--no-cli"; 38 | if (options & BF_TEST_DAEMON_NO_IPTABLES) 39 | args[nargs++] = "--no-iptables"; 40 | if (options & BF_TEST_DAEMON_NO_NFTABLES) 41 | args[nargs++] = "--no-nftables"; 42 | 43 | return bf_test_process_init(&daemon->process, path, args, nargs); 44 | } 45 | 46 | void bf_test_daemon_clean(struct bf_test_daemon *daemon) 47 | { 48 | bf_assert(daemon); 49 | 50 | bf_test_process_clean(&daemon->process); 51 | } 52 | 53 | int bf_test_daemon_start(struct bf_test_daemon *daemon) 54 | { 55 | clock_t begin; 56 | int r; 57 | 58 | bf_assert(daemon); 59 | 60 | r = bf_test_process_start(&daemon->process); 61 | if (r < 0) 62 | return bf_err_r(r, "failed to start bpfilter daemon"); 63 | 64 | begin = clock(); 65 | while (true) { 66 | _cleanup_free_ const char *err_buf = NULL; 67 | int status; 68 | 69 | r = waitpid(daemon->process.pid, &status, WNOHANG); 70 | if (r < 0) 71 | return bf_err_r(r, "waitpid() failed on bpfilter process"); 72 | if (r != 0) { 73 | err_buf = bf_test_process_stderr(&daemon->process); 74 | return bf_err_r(-ENOENT, "bpfilter process seems to be dead:\n%s\n", 75 | err_buf); 76 | } 77 | 78 | err_buf = bf_test_process_stderr(&daemon->process); 79 | if (err_buf && strstr(err_buf, "waiting for requests...")) 80 | break; 81 | 82 | if ((clock() - begin) / CLOCKS_PER_SEC > _BF_DAEMON_START_TIMEOUT) { 83 | kill(daemon->process.pid, SIGKILL); 84 | return bf_err_r( 85 | -EIO, "daemon is not showing up after %d seconds, aborting", 86 | _BF_DAEMON_START_TIMEOUT); 87 | } 88 | 89 | // Wait a bit for the daemon to be ready 90 | usleep(_BF_DAEMON_START_SLEEP); 91 | } 92 | 93 | return 0; 94 | } 95 | 96 | int bf_test_daemon_stop(struct bf_test_daemon *daemon) 97 | { 98 | int r; 99 | 100 | bf_assert(daemon); 101 | 102 | r = bf_test_process_stop(&daemon->process); 103 | if (r < 0) 104 | return bf_err_r(r, "failed to stop bpfilter daemon"); 105 | 106 | return r; 107 | } 108 | -------------------------------------------------------------------------------- /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 "harness/mock.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "core/helper.h" 13 | #include "core/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 "harness/prog.h" 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "core/chain.h" 17 | #include "core/helper.h" 18 | #include "core/list.h" 19 | #include "core/logger.h" 20 | #include "libbpfilter/bpfilter.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_BINARY_DIR}/output/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/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, marsh_unmarsh_assert) 67 | { 68 | expect_assert_failure(bf_cgen_new_from_marsh(NULL, NOT_NULL)); 69 | expect_assert_failure(bf_cgen_new_from_marsh(NOT_NULL, NULL)); 70 | expect_assert_failure(bf_cgen_marsh(NULL, NOT_NULL)); 71 | expect_assert_failure(bf_cgen_marsh(NOT_NULL, NULL)); 72 | } 73 | 74 | Test(cgen, marsh_unmarsh) 75 | { 76 | _free_bf_cgen_ struct bf_cgen *cgen0 = NULL; 77 | _free_bf_cgen_ struct bf_cgen *cgen1 = NULL; 78 | _free_bf_marsh_ struct bf_marsh *marsh = NULL; 79 | 80 | /* Create a codegen without any program, other bf_program_unmarsh() 81 | * will try to open the pinned BPF objects. 82 | */ 83 | cgen0 = bf_test_cgen(BF_FRONT_CLI, BF_HOOK_XDP, BF_VERDICT_ACCEPT); 84 | 85 | assert_success(bf_cgen_marsh(cgen0, &marsh)); 86 | assert_success(bf_cgen_new_from_marsh(&cgen1, marsh)); 87 | assert_non_null(cgen1); 88 | } 89 | 90 | Test(cgen, invalid_chain_policy) 91 | { 92 | expect_assert_failure(bf_test_chain(BF_HOOK_XDP, BF_VERDICT_CONTINUE)); 93 | } 94 | -------------------------------------------------------------------------------- /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 "bpfilter/cgen/program.c" 7 | 8 | #include "fake.h" 9 | #include "harness/test.h" 10 | #include "mock.h" 11 | 12 | Test(program, emit_fixup_call) 13 | { 14 | _free_bf_chain_ struct bf_chain *chain = bf_test_chain_quick(); 15 | 16 | expect_assert_failure(bf_program_emit_fixup_call( 17 | NULL, BF_FIXUP_FUNC_UPDATE_COUNTERS)); 18 | 19 | { 20 | // Instructions buffer should grow 21 | _free_bf_program_ struct bf_program *program = NULL; 22 | size_t start_cap; 23 | 24 | assert_success(bf_program_new(&program, chain)); 25 | 26 | start_cap = program->img_cap; 27 | 28 | // Instructions buffer is empty after initialisation, ensure it grows. 29 | assert_int_equal(0, 30 | bf_program_emit_fixup_call( 31 | program, BF_FIXUP_FUNC_UPDATE_COUNTERS)); 32 | assert_int_not_equal(program->img_cap, start_cap); 33 | } 34 | } 35 | 36 | Test(program, can_get_flavor_from_hook) 37 | { 38 | for (enum bf_flavor flavor = 0; flavor < _BF_FLAVOR_MAX; ++flavor) 39 | assert_non_null(bf_flavor_ops_get(flavor)); 40 | } 41 | -------------------------------------------------------------------------------- /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 | // Rely on the cleanup attrubte 23 | _free_bf_ctx_ struct bf_ctx *ctx0 = NULL; 24 | 25 | assert_success(_bf_ctx_new(&ctx0)); 26 | assert_non_null(ctx0); 27 | 28 | // Use the cleanup attribute, but free manually 29 | _free_bf_ctx_ struct bf_ctx *ctx1 = NULL; 30 | 31 | assert_success(_bf_ctx_new(&ctx1)); 32 | assert_non_null(ctx1); 33 | 34 | _bf_ctx_free(&ctx1); 35 | assert_null(ctx1); 36 | 37 | // Free manually 38 | struct bf_ctx *ctx2; 39 | 40 | assert_success(_bf_ctx_new(&ctx2)); 41 | assert_non_null(ctx2); 42 | 43 | _bf_ctx_free(&ctx2); 44 | assert_null(ctx2); 45 | _bf_ctx_free(&ctx2); 46 | } 47 | 48 | Test(ctx, set_get_chain) 49 | { 50 | // Rely on the cleanup attrubte 51 | _free_bf_ctx_ struct bf_ctx *ctx = NULL; 52 | _free_bf_cgen_ struct bf_cgen *cgen0 = bf_test_cgen_quick(); 53 | _free_bf_cgen_ struct bf_cgen *cgen1 = bf_test_cgen_quick(); 54 | _free_bf_cgen_ struct bf_cgen *cgen2 = bf_test_cgen_quick(); 55 | 56 | // Change the name of cgen2 57 | freep(&cgen2->chain->name); 58 | cgen2->chain->name = strdup("hello"); 59 | assert_non_null(cgen2->chain->name); 60 | 61 | assert_success(_bf_ctx_new(&ctx)); 62 | // Do not free cgens, as we keep a reference here 63 | ctx->cgens.ops.free = NULL; 64 | 65 | // Context is empty, add the first cgen 66 | assert_success(_bf_ctx_set_cgen(ctx, cgen0)); 67 | 68 | // Trying to add another cgen with the same name 69 | assert_error(_bf_ctx_set_cgen(ctx, cgen1)); 70 | 71 | // Add another cgen with a different name 72 | assert_success(_bf_ctx_set_cgen(ctx, cgen2)); 73 | 74 | // Get the cgens back 75 | assert_ptr_equal(_bf_ctx_get_cgen(ctx, cgen0->chain->name), cgen0); 76 | assert_ptr_equal(_bf_ctx_get_cgen(ctx, cgen1->chain->name), cgen0); 77 | assert_ptr_equal(_bf_ctx_get_cgen(ctx, cgen2->chain->name), cgen2); 78 | } 79 | -------------------------------------------------------------------------------- /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/core/btf.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "core/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/core/chain.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "core/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(false, 0, bft_fake_matchers))); 32 | assert_success(bf_list_add_tail(&rules, bf_rule_get(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 | #include "core/dump.h" 42 | 43 | Test(chain, marsh_unmarsh) 44 | { 45 | _free_bf_chain_ struct bf_chain *chain0 = NULL; 46 | _free_bf_chain_ struct bf_chain *chain1 = NULL; 47 | _free_bf_marsh_ struct bf_marsh *marsh = NULL; 48 | 49 | assert_non_null(chain0 = bf_test_chain_get(0, 0, NULL, bft_fake_rules)); 50 | 51 | assert_success(bf_chain_marsh(chain0, &marsh)); 52 | assert_success(bf_chain_new_from_marsh(&chain1, marsh)); 53 | 54 | assert_int_equal(bf_list_size(&chain0->rules), bf_list_size(&chain1->rules)); 55 | assert_int_equal(bf_list_size(&chain0->sets), bf_list_size(&chain1->sets)); 56 | 57 | { 58 | struct bf_list_node *n0 = bf_list_get_head(&chain0->rules); 59 | struct bf_list_node *n1 = bf_list_get_head(&chain1->rules); 60 | 61 | while (n0) { 62 | assert_int_equal(((struct bf_rule *)(bf_list_node_get_data(n0)))->index, 63 | ((struct bf_rule *)(bf_list_node_get_data(n1)))->index); 64 | n0 = bf_list_node_next(n0); 65 | n1 = bf_list_node_next(n1); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tests/unit/core/flavor.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "core/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/core/front.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "core/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/core/rule.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "core/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, marsh_unmarsh) 40 | { 41 | expect_assert_failure(bf_rule_marsh(NULL, NOT_NULL)); 42 | expect_assert_failure(bf_rule_marsh(NOT_NULL, NULL)); 43 | expect_assert_failure(bf_rule_unmarsh(NULL, NOT_NULL)); 44 | expect_assert_failure(bf_rule_unmarsh(NOT_NULL, NULL)); 45 | 46 | // All good 47 | { 48 | _free_bf_rule_ struct bf_rule *rule0 = bf_test_get_rule(10); 49 | _free_bf_rule_ struct bf_rule *rule1 = NULL; 50 | _free_bf_marsh_ struct bf_marsh *marsh = NULL; 51 | 52 | assert_non_null(rule0); 53 | assert_int_equal(0, bf_rule_marsh(rule0, &marsh)); 54 | assert_int_equal(0, bf_rule_unmarsh(marsh, &rule1)); 55 | 56 | assert_int_equal(rule0->index, rule1->index); 57 | assert_int_equal(bf_list_size(&rule0->matchers), 58 | bf_list_size(&rule1->matchers)); 59 | assert_int_equal(rule0->counters, rule1->counters); 60 | assert_int_equal(rule0->verdict, rule1->verdict); 61 | } 62 | 63 | // Failed serialisation 64 | { 65 | _free_bf_rule_ struct bf_rule *rule = bf_test_get_rule(10); 66 | _free_bf_marsh_ struct bf_marsh *marsh = NULL; 67 | 68 | assert_non_null(rule); 69 | 70 | _clean_bf_test_mock_ bf_test_mock _ = bf_test_mock_get(malloc, NULL); 71 | assert_error(bf_rule_marsh(rule, &marsh)); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /tests/unit/core/verdict.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. 4 | */ 5 | 6 | #include "core/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/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 "core/front.h" 11 | #include "core/hook.h" 12 | #include "core/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 nlmsghdr *bf_test_get_nlmsghdr(size_t nmsg, size_t *len); 27 | struct bf_nfgroup *bf_test_get_nfgroup(size_t nmsg, size_t *len); 28 | struct bf_rule *bf_test_get_rule(size_t nmatchers); 29 | -------------------------------------------------------------------------------- /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 | 15 | struct btf; 16 | struct nl_msg; 17 | struct nlmsghdr; 18 | 19 | bf_test_mock_declare(void *, malloc, (size_t size)); 20 | bf_test_mock_declare(void *, calloc, (size_t nmemb, size_t size)); 21 | bf_test_mock_declare(int, open, (const char *pathname, int flags, mode_t mode)); 22 | bf_test_mock_declare(ssize_t, read, (int fd, void *buf, size_t count)); 23 | bf_test_mock_declare(ssize_t, write, (int fd, const void *buf, size_t count)); 24 | bf_test_mock_declare(struct btf *, btf__load_vmlinux_btf, (void)); 25 | bf_test_mock_declare(struct nl_msg *, nlmsg_alloc, ()); 26 | bf_test_mock_declare(struct nl_msg *, nlmsg_convert, (struct nlmsghdr * nlh)); 27 | bf_test_mock_declare(struct nlmsghdr *, nlmsg_put, 28 | (struct nl_msg * nlmsg, uint32_t pid, uint32_t seq, 29 | int type, int payload, int flags)); 30 | bf_test_mock_declare(int, nlmsg_append, 31 | (struct nl_msg * nlmsg, void *data, size_t len, int pad)); 32 | bf_test_mock_declare(int, bf_bpf_obj_get, (const char *path, int *fd)); 33 | bf_test_mock_declare(int, vsnprintf, 34 | (char *str, size_t size, const char *fmt, va_list args)); 35 | bf_test_mock_declare(int, snprintf, 36 | (char *str, size_t size, const char *fmt, ...)); 37 | bf_test_mock_declare(int, bf_bpf, (enum bpf_cmd cmd, union bpf_attr *attr)); 38 | bf_test_mock_declare(int, bf_ctx_token, (void)); 39 | -------------------------------------------------------------------------------- /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 | ) 32 | 33 | add_custom_target(benchmark 34 | COMMAND 35 | ${CMAKE_COMMAND} 36 | -E make_directory 37 | ${CMAKE_BINARY_DIR}/output/benchmarks 38 | COMMAND 39 | ${CMAKE_SOURCE_DIR}/tools/asroot 40 | $ 41 | --cli $ 42 | --daemon $ 43 | --srcdir ${CMAKE_SOURCE_DIR} 44 | --outfile ${CMAKE_BINARY_DIR}/output/benchmarks/{gitrev}.json 45 | DEPENDS benchmark_bin bfcli bpfilter 46 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 47 | USES_TERMINAL 48 | COMMENT "Running benchmarks" 49 | ) 50 | -------------------------------------------------------------------------------- /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/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 | --------------------------------------------------------------------------------