An eBPF-based packet filtering framework.
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.
Key features • Quick start • Documentation
- High performance: utilizes eBPF's near-native performance capabilities
- Flexible integration: use the custom
iptables
integration or bpfilter'sbfcli
command line for extended functionalities - Low overhead: minimal resource consumption with maximized efficiency
- Developer-friendly: clean architecture with clear separation of components
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.
Want to know more about bpfilter? Check the user's guide, the developer documentation, or watch our latest public talk!
bpfilter is packaged for Fedora 40+, EPEL 9+ and supports Fedora 40+, CentOS Stream 9+, and Ubuntu 24.04+. The examples below uses Fedora 41.
# Fedora 40+ or CentOS Stream 9+ (with EPEL)
sudo dnf install -y bpfilter bpfilter-devel
# Essential build requirements
sudo dnf install -y cmake gcc libbpf-devel libnl3-devel bison flex
# Configure the project and build bpfilter
cmake -S $SOURCES_DIR -B $BUILD_DIR -DNO_DOCS=ON -DNO_TESTS=ON -DNO_CHECKS=ON -DNO_BENCHMARKS=ON
make -C $BUILD_DIR install
# Start the daemon
sudo $BUILD_DIR/output/sbin/bpfilter
# Count the number of ping coming to interface #2
sudo $BUILD_DIR/output/sbin/bfcli ruleset set --str "chain BF_HOOK_XDP{ifindex=2} policy ACCEPT rule ip4.proto icmp counter ACCEPT"
The complete documentation is available on bpfilter.io.
bpfilter is licensed under GPLv2. You can find the licensing details in the COPYING file.
bpfilter was initially designed by Alexei Starovoitov with help from David S. Miller and Daniel Borkmann as a Linux kernel usermode helper, and later improved by Dmitrii Banshchikov.
bpfilter's People
Forkers
ishan-siddiqui qdeslandes fatihusta rphibel fieryswampshire x-oss-byte thecodeofmontecristo jpmondet daandemeyer pspglb jordalgo vincentmli muthuramanataya hubways ikruglov amitdhanani2012 glitched-w0rld orangepanda83 k0rv1n relicfrog yangdengyuan luigidematteis jamestiotio ryantimwilson amscanne liudf0716 ryanbsull tommy-u adelavegaf corentinmre skohtvbpfilter's Issues
Filter IP addresses (v4 and v6) using longest prefix match
Sets are used to filter a multiple IP addresses in constant time. Each IP address to filter it inserted into a BPF map, and the program performs a lookup of the packet's IP into the map. This behaviour doesn't work well with subnets filtering: all the IP addresses of the subnet should be inserted into the set for the program to be able to filter the subnet.
# IPs to filter
192.168.1.1
192.168.1.2
192.168.2.0/24
# IPs in the set
192.168.1.1
192.168.1.2
192.168.2.0
192.168.2.1
[...]
192.168.2.254
192.168.2.255
An alternative is to implement subnets filtering using the Longest Prefix Match algorithm. Thankfully, BPF supports BPF_MAP_TYPE_LPM_TRIE
maps.
End-to-end testing of matchers
More and more matchers are added to bpfilter
(15 and counting!), each of them supporting different operators and interacting differently which each BPF flavour (XDP, TC, BPF_NETFILTER, CGroup).
All the matchers are manually tested, but as the number of matchers grows, it's becoming more and more difficult to avoid issues when the code generation logic is modified. Thus, we need an easy-to-use, deterministic way of testing all the matchers.
A solution would be to reuse the logic implemented in the benchmark, minus the numerous iterations of BPF_PROG_TEST_RUN
:
- Start the daemon
- Use
bfcli
to create the filtering chain, using a specific matcher - Use
BPF_PROG_TEST_RUN
once and validate the result of the program
Use all hooks and matchers in `rules.bpfilter`
tests/rules.bpfilter
contains a ruleset to test bfcli
and bpfilter
. This ruleset only contains a subset of the available hooks and matchers.
Complete the ruleset by defining chains for each hook and using every existing matcher.
Support traffic rate limiting
This issue is defined to keep track of the investigation, feasibility, and progress on rate limit traffic using
bpfilter
. Design work is required before any implementation.
Allow users to rate limit specific packets, such as ip6tables -A INPUT -p icmpv6 -m limit --limit 20/m --limit-burst 3 -j ACCEPT
with iptables
.
Allow fetching rules and counters via bfcli
bpfilter daemon keeps a list of active rules and it also writes counters to BPF maps. Sure, we can access the rules/counters via bpftool - counter maps are named bf_cmap_XXX - but it is more convenient to use an API.
$ sudo bpftool map dump name bf_cmap_000201
[{
"key": 0,
"value": {
"packets": 71220,
"bytes": 112981553
}
},{
"key": 1,
"value": {
"packets": 71288,
"bytes": 112993982
}
}
To do this, we need to implement the BF_REQ_GET_RULES and BF_REQ_GET_RULES APIs in bpfilter backend and fetch the results via bfcli.
bfcli API could look like (where chain/rule are optional):
$ bfcli get-rules <chain> <rule>
$ bfcli get-counters <chain> <rule>
Note bfcli
would need to introduce subcommands as bfcli
is only used for setting rules now.
Create, package, and install a `systemd` service file
Define a systemd
service file for the bpfilter
daemon, which should be deployed with the daemon and the command line interface.
Support sets of `(IPv6, port)`
Add support for sets containing (IPv6, port)
keys to filter on.
This change is straightforward: add a new key type to set.h
and the corresponding key size in set.c
.
Support ICMP packets filtering
Allow users to filter on ICMP (v4) type and code:
Support all the `bfcli` matchers in the `nft` front-end
Update the nft
front-end to reach feature parity with bfcli
. This task only impacts the nft
bytecode parsing logic.
See the bfcli
documentation for the list of matchers to implement in the nft
front-end.
The nftables
documentation should be updated with the list of supported matchers, and they should be tested in end-to-end tests.
error: ‘BPF_NETFILTER’ - build bpfilter in Ubuntu 22 and enable the hadware enablement (HWE) stack.
Hi everyone,
I am trying to build bpfilter in my current infrastructure which uses the Ubuntu 22.04 OS.
I enabled the HWE and upgraded the kernel to version 6.5, but there is an error when I hit make -C $BUILD_DIR
for building the bpfilter. Here are some information:
## Upgrade kernal
sudo apt-get install --install-recommends linux-generic-hwe-22.04
root@com-glb-168:~/bpfilter# uname -r
6.5.0-45-generic
## Error log from make output
root@com-glb-168:~/bpfilter# make -C $BUILD_DIR
make: Entering directory '/root/bpfilter'
make[1]: Entering directory '/root/bpfilter'
make[2]: Entering directory '/root/bpfilter'
Consolidate compiler generated dependencies of target bpfilter
make[2]: Leaving directory '/root/bpfilter'
make[2]: Entering directory '/root/bpfilter'
[ 1%] Building C object src/CMakeFiles/bpfilter.dir/core/bpf.c.o
/root/bpfilter/src/core/bpf.c: In function ‘bf_bpf_nf_link_create’:
/root/bpfilter/src/core/bpf.c:169:36: error: ‘BPF_NETFILTER’ undeclared (first use in this function); did you mean ‘IP_MSFILTER’?
169 | attr.link_create.attach_type = BPF_NETFILTER;
| ^~~~~~~~~~~~~
| IP_MSFILTER
/root/bpfilter/src/core/bpf.c:169:36: note: each undeclared identifier is reported only once for each function it appears in
/root/bpfilter/src/core/bpf.c:170:21: error: ‘struct <anonymous>’ has no member named ‘netfilter’
170 | attr.link_create.netfilter.pf = NFPROTO_IPV4;
| ^
/root/bpfilter/src/core/bpf.c:171:21: error: ‘struct <anonymous>’ has no member named ‘netfilter’
171 | attr.link_create.netfilter.hooknum = bf_hook_to_nf_hook(hook);
| ^
/root/bpfilter/src/core/bpf.c:172:21: error: ‘struct <anonymous>’ has no member named ‘netfilter’
172 | attr.link_create.netfilter.priority = priority;
| ^
make[2]: *** [src/CMakeFiles/bpfilter.dir/build.make:104: src/CMakeFiles/bpfilter.dir/core/bpf.c.o] Error 1
make[2]: Leaving directory '/root/bpfilter'
make[1]: *** [CMakeFiles/Makefile2:237: src/CMakeFiles/bpfilter.dir/all] Error 2
make[1]: Leaving directory '/root/bpfilter'
make: *** [Makefile:136: all] Error 2
make: Leaving directory '/root/bpfilter'
I think the error is related to BPF_NETFILTER
kernel module, so do I need to do something to enable it?
Publish `bpfilter`'s RPM package
Package bpfilter
into an RPM package and publish it to official repositories for Fedora and CentOS.
does bpfilter support redirect?
I’m currently developing an open-source project, apfree-wifidog, which relies on nftables to handle HTTP and HTTPS redirection for network control purposes. I'm interested in using bpfilter to potentially accelerate performance. However, a key requirement is that bpfilter needs to support HTTP and HTTPS redirection functionality similar to what nftables offers. Does bpfilter currently support such redirection features? And if not, are there recommended workarounds or upcoming features that might facilitate this?
the nft rule like this:
nft add rule inet fw4 dstnat_wifidogx_unknown tcp dport 80 redirect to 2060
compiling error in Ubuntu 22.04.2 LTS
/home/liudf/work/bpfilter/src/core/bpf.c: In function ‘bf_bpf_nf_link_create’:
/home/liudf/work/bpfilter/src/core/bpf.c:187:36: error: ‘BPF_NETFILTER’ undeclared (first use in this function); did you mean ‘IP_MSFILTER’?
187 | attr.link_create.attach_type = BPF_NETFILTER;
| ^~~~~~~~~~~~~
| IP_MSFILTER
/home/liudf/work/bpfilter/src/core/bpf.c:187:36: note: each undeclared identifier is reported only once for each function it appears in
/home/liudf/work/bpfilter/src/core/bpf.c:188:21: error: ‘struct <anonymous>’ has no member named ‘netfilter’
188 | attr.link_create.netfilter.pf = NFPROTO_IPV4;
| ^
/home/liudf/work/bpfilter/src/core/bpf.c:189:21: error: ‘struct <anonymous>’ has no member named ‘netfilter’
189 | attr.link_create.netfilter.hooknum = bf_hook_to_nf_hook(hook);
| ^
/home/liudf/work/bpfilter/src/core/bpf.c:190:21: error: ‘struct <anonymous>’ has no member named ‘netfilter’
190 | attr.link_create.netfilter.priority = priority;
| ^
make[2]: *** [src/core/CMakeFiles/core.dir/build.make:76: src/core/CMakeFiles/core.dir/bpf.c.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:291: src/core/CMakeFiles/core.dir/all] Error 2
make: *** [Makefile:136: all] Error 2
does bpfilter only support compiling on >= ubuntu 24.04?
Allow filtering unsupported protocols
r7
and r8
are used to store the L3 protocol ID (e.g. ETH_P_IP
) and the L4 protocol ID (e.g. IPPROTO_TCP
). During the L3 and L4 parsing logic, if the protocol is not supported, the register is set to 0 to prevent falsely relying on this header later on:
# Parsing L3 header
if (r7 == ETH_P_IP)
l3_size = sizeof(struct iphdr);
else if (r7 == ETH_P_IPV6)
l3_size = sizeof(struct ipv6hdr);
else
r7 = 0
# Parse the L3 header
...
However, such behaviour prevents filtering on non-supported protocol: r7
does not contain the ID of unsupported protocols, so meta.l3_proto
only works for IPv4 and IPv6.
Prevent the header parsing functions in stub.c
from resetting the protocol ID to 0.
Make test coverage reporting optional for packaging
For packaging, it's useful to run tests, but coverage reporting is not important (we just care that tests provided by developers pass). It would be useful to be able to disable coverage reporting, and not have a dependency on lcov.
Support IPv6 next header filtering
Filter packets based on the "next header" content of the IPv6 header:
rule
ipv6.nexthdr eq frag
DROP
rule
ipv6.nexthdr in {route, prot}
counter
DROP
Create a CONTINUE verdict
With the existing verdicts, it's not possible to forward a packet to the next rule: it is either accepted or dropped. In both cases, the chain won't process the remaining rules.
A CONTINUE
verdict would allow packets to continue going through the filtering rules. Currently, the main interest of such a target would be to count the packets matching specific criteria. For example, this is not currently possible
# Counter the number of IPv6 packets and TCP packets going through the hook
rule
meta.l3_proto ip6
counter
ACCEPT
rule
meta.l4_proto tcp
counter
ACCEPT
IPv6 TCP packets would be counted towards rule #1 counter, as every IPv6 packet would be matched by rule #1 and accepted, stopping the processing. However, with a CONTINUE
verdict:
# Counter the number of IPv6 packets and TCP packets going through the hook
rule
meta.l3_proto ip6
counter
CONTINUE
rule
meta.l4_proto tcp
counter
CONTINUE
IPv6 TCP packet would be processed by rule #1 and counted, then processing would continue with rule #2 and they would be counted again.
Publish `bpfilter`'s DEB package
Package bpfilter
into a DEB package and publish it to official repositories for Ubuntu.
Support ICMPv6 packet filtering
Allow users to filter on ICMP (v6) type and code:
Replace self-hosted CI runners with GitHub-hosted ones
The CI uses self-hosted runners because when the CI workflow was created, GitHub-hosted runner didn't comply with the following requirements:
- Run on Linux 6.4+: only Ubuntu 22.04 was available, running on an old Linux kernel.
- Support
arm64
runners: while GitHub has providedarm64
runners for some time now, they run on Apple Silicon, which doesn't allow for nested virtualization, thus preventing Docker from being used.
Lately, GitHub fixed both of those blockers as it provides arm64
runners on Ubuntu 24.04 for Team and Enterprise Cloud plans, which makes those available to bpfilter
through the Facebook org.
Self-hosted runners come with some maintenance that we should avoid if we can, and bpfilter
's CI should be modified to use the GitHub runners instead of the self-hosted ones.
Tests have been conducted to validate the viability of the self-hosted runners, especially when it comes to the usage of BPF_PROG_TEST_RUN
(see better_ci
branch). To benefit from the arm64
Ubuntu runners, the development, and tests must be performed on the main repository, meaning people without writing rights can't contribute to this task.
"shift/reduce conflicts" warning when building `parser.y`
When Bison builds parser.y
for bfcli
, the following warning appears:
[ 57%] [BISON][bfcli_parser] Building parser with bison 3.8.2
/home/quentin/Projects/bpfilter/src/bfcli/parser.y: warning: 2 shift/reduce conflicts [-Wconflicts-sr]
/home/quentin/Projects/bpfilter/src/bfcli/parser.y: note: rerun with option '-Wcounterexamples' to generate conflict counterexamples
This warning is due to conflicting rules, which could generate unexpected output.
Support IPv6 "next header" field
An IPv6 "next header" field can contain one of the following information:
- Transport layer protocol
- Extension header identifier
In the first case, the IPv6 header is followed by the transport layer header. This is properly supported by bpfilter.
In the second case, the IPv6 header is followed by an extension header of variable length. This extension header contains a "next header" field to identify the next header, which can be a transport layer header or another extension header. Extensions header are not supported by bpfilter
: the BPF program will read the "next header" field of the IPv6 header and use it as the transport layer protocol.
If the packet contains an IPv6 extension header, the BPF program should read it to access the next header, until the transport layer header is found.
Log packets going through a rule
Allow users to log the packet matched by a rule.
Overview
A new keyword must be introduced to allow users to specify if a rule should log matched packets:
chain [...]
rule
meta.l3 ipv4
log l3 l4
DROP
The log
keyword can have the following arguments:
- No argument, or
l3 l4
: logs L3 and L4 headers l3
orl4
: log the specified header
The L2 (Ethernet) header is only available for some hooks, it can be skipped for now and supported later.
The logging flags will be carried as part of the chain definition. The generated BPF program will then write the requested headers into a BPF ring buffer. bpf_printk()
is not a viable solution as it would be slower than a ring buffer, and bpfilter
would have to log each packet according to its protocol and fields. Write the headers to the ring buffer allow the user to read them and log them as they want to. The headers will be logged to the ring buffer as logged_packet
structures (see below) of variable size (depending on the logged layers).
At runtime, the packet will be logged to the ring buffer using a custom function, similarly to the counters update.
Eventually, bfcli
could introduce chain log
or rule log
command to print the logs of a chain or rule. This is out of the scope of this feature.
Implementation
- [core] Store the logging flag(s) in
struct bf_rule
, update thebf_rule_...()
functions accordingly. - [bfcli] Add support for
log [l3] [l4]
to the parser and lexer. Use thecounter
keyword as an example. Update the documentation. - [cgen] Add support for the ring buffer map. No need to worry about the map's BTF data for now.
- [cgen]
bf_program
should contain a reference to the new logging map. It should only be allocated if the chain requires logging. - [cgen] Store L3 and L4 header size into the program's runtime context. The header sizes are calculated in
bf_stub_parse_l3_hdr()
andbf_stub_parse_l4_hdr()
, it should then be stored in the runtime context (e.g.BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_x, BF_PROG_CTX_OFF(lx_size))
). If the protocol is not supported, store the size of its header as 0. - [cgen] Define the new logging function as a
fixup
(also here). - [cgen] Similarly to
update_counters
function, implement thelog
function to:- Fill a
struct logged_packet
on the stack (see below) to write to the ring buffer, such that for the protocol at layer X:lX_proto
is the protocol ID, or 0 if this layer should not be logged.lX_size
is the size of the header for layer X, or 0 if the protocol is not supported, or if the layer should not be logged.
- Call
bpf_ringbuf_output()
kfunc - Handle errors properly (update the error counter if needed)
- Fill a
struct logged_packet
{
uint32_t rule_index;
uint8_t l3_proto;
uint16_t l3_size;
uint16_t l4_proto;
uint16_t l4_size;
uint8_t l3_data[l3_size];
uint8_t l4_data[l4_size];
};
Provide examples of `nftables` and `iptables` usage with `bpfilter`
Update the documentation to include usage examples of nftables
and iptables
with bpfilter
. Show common commands: create rules, list rules, delete ruleset... Show the same commands (with output) with nftables
, iptables
, and bfcli
.
Filter prefixed IPv6 addresses
ip6.saddr
and ip6.daddr
should allow users to specific a prefix length to filter on a network address:
[...]
rule
ip6.saddr 2001:db8:abcd:0012::0/64
DROP
rule
ip6.daddr 2001:db8:abcd:0012::0/112
ACCEPT
[...]
Some logic is already implemented, but it should be validated with end-to-end tests and fixed if necessary.
Document minimum-known linux kernel version requirement
Potentially pairs with the new README.md note about libbpf 1.0 requirement.
This could also simply be a listing of the the earliest known-working/developer-tested version(s) of the kernel.
As of PR #12 I can't build on my kernel 5.15.x-based system. It seems the bpf_dynptr was introduced to bpf-next in May 2022. Guessing that puts a minimum kernel for dynptr somewhere around 5.18 or 5.19, which is past that of stock Ubuntu, RHEL, and SLE/SUSE releases according to wikipedia. libbpf 1.0.0 was August 22, 2022, so if libbpf and kernel need to move in-step, perhaps the required kernel is 6.0 or newer?
Totally understand if maintainers want to focus on current kernel releases rather than optional configs and work-around for old kernels, but might help avoid further "issue" reports to document a known minimum.
LAB testing
Hi , I install it but when i use iptables with option i have error iptables v1.8.9 (nf_tables): unknown option "--bpf".
How to install it correctly and using it?
i already start it @bpfilter/build/src# ./bpfilter
info : restored new codegen at 0x8006f0
info : restored new codegen at 0x800bb0
info : restored new codegen at 0x801070
info : cache already initialised, skipping initialisation
info : waiting for requests...
reserved identifier violation
👀 I would like to point out that identifiers like “_bf_opts_parser
” and “_stop_received
” do eventually not fit to the expected naming convention of the C language standard.
💭 Would you like to adjust your selection for unique names?
Integrate user-defined BPF (sub)programs
Allow users to provide pre-compiled BPF programs to perform filtering in-place of a rule in the generated BPF program.
For example:
chain ...
rule
ip6.addr ::1
ACCEPT
rule
meta.program ~/bpf/test.o
counter
DROP
The custom BPF program would be called when the rule is processed and returned whether it matches the packet's data, the program would apply (or not) the verdict.
extract eBPF from bpfilter
Hi there,
Is it possible to get the eBPF code from a bpfilter ruleset? I am would like to use Klee to do symbolic execution on the firewall to extract a formula that defines its semantics. To do this, I make the input packet "symbolic" in Klee, and then collect the execution paths from Klee, and conjunct them together to get a single SMT formula that describes the firewall. Then I can compare two rulesets and give a formal proof that they are (or are not) equivalent. I am imagining this could be useful for checking that a refactor does not change the semantics (but might improve performance or code organization for example).
We (with @Jeffery2008) were working with this idea using iptables but it looks like bpfilters might be better. We were trying to verify migrations of iptables code to eBPF, but it seems like rather than manually migrating, it is better to just use the iptables support here. A user could just take their iptables-save and use it with the iptables system provided by this tool and get the benefits of running eBPF rather than iptables.
Also, if this doesn't make sense, would love some feedback. I am more of a program verification person than a networking person so apologies if we are missing some key point here.
Thank you!
Create a `REDIRECT` verdict
Generic UDP and TCP ports filtering
bpfilter
can filter on TCP or UDP source and destination port with tcp.sport
, tcp.dport
, udp.sport
and udp.dport
. However, matching a given port for both TCP and UDP requires two rules:
rule
tcp.dport 22
DROP
rule
udp.dport 22
DROP
On the other hand, nftables
can filter on port TCP and UDP ports using a single rule:
nft add rule filter input meta l4proto { tcp, udp } th dport 53 accept
A new matcher should be implemented to allow users to match on both TCP and UDP port (source or destination) using a single matcher, e.g.:
rule
meta.sport 22
DROP
feasible to use bpfilter with uBPF to evaluate/test nftables rulesets in userspace?
i have a dream, where all nftables rules are tested statically before insertion into the kernel.
reading the bpfilter documentation, it seems that the daemon can be used (transparently?) as a backend for nftables userspace tools. did i understand that correctly?
if that's possible, i'd like to pull the generated BPF bytecode from bpfilter and pass it through uBPF in order to perform analysis against simulated packets.
does this seem like something that would work well with bpfilter as currently implemented?
Suggestion: update README with what is currently working for iptables/nftables & examples with iptables/nftables
Hello,
Thank you for this project ! I Saw your presentations and I'm interested in this project as this seems to bridge the gap between sysadmins/netadmins (I am) and Software engineers who brings more performance for Linux filtering !
I'm currently trying to reproduce an example with some rules and it's not working and I'm not sure if this is because that is not (yet) implemented or if my build setup is wrong.
Would it be possible to add a section on the README file with what is working and not working for iptables/nftables ?
Also an example of an iptables/nftables rule add/suppression would be greatly appreciated for starters :)
Thank you.
Compiled bpfilter doesn't load: No such file or directory
Hello @qdeslandes,
I have just compiled the bpfilter module on both the linux-6.1.14 branch and the bpf-next branch, both times I get the following output in dmesg:
[ 4.619942] bpfilter: Loaded bpfilter_umh pid 971
[ 4.622811] bpfilter: generate forward packet assessment
[ 4.622823] bpfilter: generate forward packet assessment
[ 4.625250] bpfilter: failed to create TC hook: No such file or directory
[ 4.625348] bpfilter: failed to load chain INPUT in table filter: processed 73 insns (limit 1000000) max_states_per_insn 0 total_states 4 peak_states 4 mark_read 3
[ 4.625455] bpfilter: failed to install new table 'filter': No such file or directory
[ 4.625578] bpfilter: failed to created filter table: No such file or directory
[ 4.625807] bpfilter: read fail 0
Would you happen to know if I did something wrong?
Thanks a lot,
Mr. Hax
SIGSEGV on starting bpfilter
Hello,
I was starting with bpfilter, and I built it from source with v0.1.0 tag.
Here is the debug log I got (both release and debug mode it crashed immediately on startup):
info : generating BF_FLAVOR_NF program for BF_FRONT_IPT::BF_HOOK_NF_LOCAL_IN
info : generating BF_FLAVOR_NF program for BF_FRONT_IPT::BF_HOOK_NF_FORWARD
info : generating BF_FLAVOR_NF program for BF_FRONT_IPT::BF_HOOK_NF_LOCAL_OUT
==596886==ERROR: AddressSanitizer: heap-use-after-free on address 0x603000000040 at pc 0x7fa6f2c4814b bp 0x7ffd66cb3e90 sp 0x7ffd66cb3640
READ of size 4 at 0x603000000040 thread T0
#0 0x7fa6f2c4814a in __interceptor_memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827
#1 0x56413c29824d in bf_memcpy /home/zy/src/bpfilter/src/core/helper.h:176
#2 0x56413c2985b6 in bf_marsh_new /home/zy/src/bpfilter/src/core/marsh.c:26
#3 0x56413c2992e5 in bf_marsh_add_child_raw /home/zy/src/bpfilter/src/core/marsh.c:77
#4 0x56413c21d6f9 in bf_cgen_marsh /home/zy/src/bpfilter/src/bpfilter/cgen/cgen.c:113
#5 0x56413c296222 in bf_list_marsh /home/zy/src/bpfilter/src/core/list.c:127
#6 0x56413c25987a in _bf_ctx_marsh /home/zy/src/bpfilter/src/bpfilter/ctx.c:275
#7 0x56413c25aa5d in bf_ctx_save /home/zy/src/bpfilter/src/bpfilter/ctx.c:349
#8 0x56413c218c96 in _bf_save /home/zy/src/bpfilter/src/bpfilter/main.c:210
#9 0x56413c219f3e in _bf_init /home/zy/src/bpfilter/src/bpfilter/main.c:313
#10 0x56413c21bca6 in main /home/zy/src/bpfilter/src/bpfilter/main.c:476
#11 0x7fa6f20461c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#12 0x7fa6f2046284 in __libc_start_main_impl ../csu/libc-start.c:360
#13 0x56413c216b80 in _start (/home/zy/src/bpfilter/build/output/sbin/bpfilter+0xc0b80)
0x603000000040 is located 0 bytes inside of 24-byte region [0x603000000040,0x603000000058)
freed by thread T0 here:
#0 0x7fa6f2cb76a8 in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:52
#1 0x56413c21d4df in bf_cgen_free /home/zy/src/bpfilter/src/bpfilter/cgen/cgen.c:97
#2 0x56413c2675fb in _bf_ipt_set_rules_handler /home/zy/src/bpfilter/src/bpfilter/xlate/ipt/ipt.c:474
#3 0x56413c269c05 in _bf_ipt_setup /home/zy/src/bpfilter/src/bpfilter/xlate/ipt/ipt.c:660
#4 0x56413c219cf1 in _bf_init /home/zy/src/bpfilter/src/bpfilter/main.c:303
#5 0x56413c21bca6 in main /home/zy/src/bpfilter/src/bpfilter/main.c:476
#6 0x7fa6f20461c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
previously allocated by thread T0 here:
#0 0x7fa6f2cb89cf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x56413c21c5be in bf_cgen_new /home/zy/src/bpfilter/src/bpfilter/cgen/cgen.c:32
#2 0x56413c26629d in _bf_ipt_xlate_set_rules /home/zy/src/bpfilter/src/bpfilter/xlate/ipt/ipt.c:430
#3 0x56413c266856 in _bf_ipt_set_rules_handler /home/zy/src/bpfilter/src/bpfilter/xlate/ipt/ipt.c:461
#4 0x56413c269c05 in _bf_ipt_setup /home/zy/src/bpfilter/src/bpfilter/xlate/ipt/ipt.c:660
#5 0x56413c219cf1 in _bf_init /home/zy/src/bpfilter/src/bpfilter/main.c:303
#6 0x56413c21bca6 in main /home/zy/src/bpfilter/src/bpfilter/main.c:476
#7 0x7fa6f20461c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
SUMMARY: AddressSanitizer: heap-use-after-free ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827 in __interceptor_memcpy
Shadow bytes around the buggy address:
0x0c067fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c067fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c067fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c067fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c067fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c067fff8000: fa fa 00 00 00 fa fa fa[fd]fd fd fa fa fa fd fd
0x0c067fff8010: fd fa fa fa fd fd fd fa fa fa fd fd fd fa fa fa
0x0c067fff8020: fd fd fd fa fa fa fd fd fd fa fa fa fd fd fd fa
0x0c067fff8030: fa fa fd fd fd fa fa fa fd fd fd fa fa fa fd fd
0x0c067fff8040: fd fa fa fa fd fd fd fa fa fa fd fd fd fa fa fa
0x0c067fff8050: fd fd fd fa fa fa fd fd fd fa fa fa fd fd fd fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==596886==ABORTING
In addition, if I run with "bpfilter -t" then it does not immediately. The segfault happened after I ctrl-C to send a SIGINT to the daemon. With very similar debug log. The difference is: when I run without -t, the BPF programs and maps were still pinned under /sys/fs/bpf/, with these names:
bf_cmap_030000 bf_cmap_040000 bf_cmap_070000 bf_pmap_030000 bf_pmap_040000 bf_pmap_070000 bf_prog_030000 bf_prog_040000 bf_prog_070000
/run/bpfilter/daemon.sock is not there. If I run with -t and SIGINT, then BPF objects were not pinned, /run/bpfilter/daemon.sock will remain undeleted.
For compiling from source we were using:
gcc 12.2.0
clang 18.1.5
libbpf 1.5.0
The platform we run were debian bookworm. The daemon segfault the same with both 6.12.12 kernel with Intel(R) Xeon(R) CPU E5-2650 v3, and 6.6.62 kernel with AMD EPYC 9684X. libc6 version is 2.36-9+deb12u9.
Appreciate if someone could help look into this issue. I can provide additional information or instrument the source for more information.
thanks
Yan
On-the-fly sets update
Sets are currently created and filled once: when the corresponding BPF program is loaded into the kernel. If a set is modified in the ruleset, the whole BPF program is regenerated and the set is re-created, even if none of the rules changed.
bpfilter
should be able to update a set without re-creating the corresponding BPF program.
Cannot restart bpfilter daemon after a first stop
Hello,
I'm working on an Ubuntu 24.04 server, compilation is OK, the first launch of bpfilter is successful:
user@ubuntu-2404-32go:~$ sudo bpfilter_build/src/bpfilter
[sudo] password for user:
info : failed test access to context file: /run/bpfilter/data.bin: No such file or directory
info : generating BF_FLAVOR_NF program for BF_FRONT_IPT::BF_HOOK_IPT_LOCAL_IN::ens18
info : generating BF_FLAVOR_NF program for BF_FRONT_IPT::BF_HOOK_IPT_FORWARD::ens18
info : generating BF_FLAVOR_NF program for BF_FRONT_IPT::BF_HOOK_IPT_LOCAL_OUT::ens18
info : waiting for requests...
but when exiting with Ctrl+C and relaunching bpfilter it does not work
user@ubuntu-2404-32go:~$ sudo bpfilter_build/src/bpfilter
[sudo] password for user:
info : failed test access to context file: /run/bpfilter/data.bin: No such file or directory
info : generating BF_FLAVOR_NF program for BF_FRONT_IPT::BF_HOOK_IPT_LOCAL_IN::ens18
info : generating BF_FLAVOR_NF program for BF_FRONT_IPT::BF_HOOK_IPT_FORWARD::ens18
info : generating BF_FLAVOR_NF program for BF_FRONT_IPT::BF_HOOK_IPT_LOCAL_OUT::ens18
info : waiting for requests...
^Cinfo : received stop signal, exiting...
user@ubuntu-2404-32go:~$ sudo bpfilter_build/src/bpfilter
error : failed to pin strings map: File exists
error : failed to initialise messages map: File exists
error : failed to initialize bpfilter: File exists
user@ubuntu-2404-32go:~$
I can make it work by rebooting my VM so I think there should be some files which are not cleaned with a ctrl+c ?
Thank you for your help.
Run the CI in a custom container
The CI jobs run in Docker containers, depending on the distribution the project needs to be built/tested on. Installing the dependencies and configuring the build container is long and account for most of the CI duration.
The CI duration could be reduced by using a container that already provides the required dependencies. We could also run each major step (build, test…) in a separate container to provide more granular check status on PRs.
Using a custom container, the workflow could be the following:
- Build the containers (Ubuntu, Fedora,
x64
,arm64
…) - Push the container to the repository's register(GHCR)
- Run the build step in a container
- Run the test step in a container
- More check…
See better_ci
for a PoC.
Avoid conflicting XDP programs
bpfilter
will attach XDP programs using a BPF link tied to a specific interface index. If a BPF program is already attached to the interface, the link creation will fail and no packet filtering will be performed.
There is no solution at the moment to attach multiple XDP BPF programs to a single interface, except using a loader from user-space (e.g. xdp-loader
). This solution works well if a user-space process is used as a proxy to manage XDP programs, but not so much with XDP programs loaded from different processes.
@ryanbsull has submitted a patch to support multi-prog for XDP BPF program. This appears to be the correct approach and should be supported by bpfilter
.
Refactor `nft` front-end to properly parse bytecode
Plenty of new features have been introduced during H2 2024 which are supported by bfcli
. The nft
front-end hasn't progressed at the same speed due to many limitations with its current implementation, making bpfilter
unusable with nftables
.
The front-end's logic is the following:
nftables
CLI binary parse the user-define rules and converts them intonft
bytecodelibbpfilter
(linked tonftables
) send the bytecode to thebpfilter
daemon using Netlink messages- The
nft
front-end in the daemon parses the Netlink messages to extract thenft
bytecode, and converts the bytecode into its internal format (shared by all the front-ends)
The current implementation of the bytecode parsing logic can't be scalable to understand more complex filtering rules and only works with simple "filter IP xxx.xxx.xxx.xxx" rules. It must be refactored to provide a generic framework to properly parse the bytecode and allow for more matchers and rules to be supported in the future.
Some exploration is required to understand nft
bytecode format, investigate if a similar tool or library already exists, and suggest possible solutions for this issue.
The purpose of this task is to define, document, and implement a scalable framework to parse nft
bytecode, not to reach feature parity between nftables
and bfcli
.
Collect error metrics
Generated BPF programs call kfunc
s and BPF helpers for various purposes, and those call might fail. In this situation, the program will return with a default verdict. There is currently no way to know if such an error occurred during the program's lifetime, except for reading /sys/kernel/debug/tracing/trace_pipe
if bpfilter
is running in debug mode (--debug
).
An error/failure counter would bring more visibility to this situation and help to understand the program's behavior.
Support output interface filtering
bpfilter
supports meta.ifindex
to filter on a network interface, which is effectively filtering on the input network interface. Similarly, add support for meta.oifindex
to filter on an output network interface.
Clarify the documentation related to meta.ifindex
to specific it filters on the input interface.
Clear the ruleset using `bfcli`
Add a new command to clear the whole ruleset (for a specific front-end) and add support for it into bfcli
.
Provide usage examples in README.md to confirm operation
The original kernel introduction of bpfilter includes a series of usage examples via iptables
ping
and bpftool
. A similar example set of commands (and perhaps expected log output from the bpfilter
daemon) would be a huge help in confirming things are hooked in properly after building/loading the binary.
Refactor the `nftables` patch and validate usability
Refactor the custom nftables
patch to support the latest nft
tool release. Validate the modified version of nftables
for supported matchers and common operation (create a ruleset, fetch rules and counters, backup/restore...).
Once the patch is validated, it would be worth gathering feedback from the Netfilter mailing list.
Support generic sets
Sets keys are defined statically: set.h
contains an enumeration of valid keys, and each set type has its logic supported in the source code.
This behaviour makes sets very rigid and even useless for some users: either your key type is supported, or you need to rely on slower rules processed sequentially.
Users should be able to define set keys themselves using one or more matcher keys, for example:
chain BF_HOOK_XDP{ifindex=2} policy ACCEPT
set
name test_set
key ip4.saddr ip4.dport
values { 192.168.1.1, 22 }, { 192.168.1.1, 53 }
rule
[...]
Failed to create a `BF_HOOK_NF_PRE_ROUTING` chain
Using the following chain:
chain BF_HOOK_NF_PRE_ROUTING policy ACCEPT
rule
meta.l4_proto eq icmpv6
counter
DROP
bfcli
returns an error: error : failed to set chain for 'BF_HOOK_NF_PRE_ROUTING', skipping remaining chains
with the following logs from bpfilter
:
info : generating BF_FLAVOR_NF program for BF_FRONT_CLI::BF_HOOK_NF_PRE_ROUTING
error : failed to load BPF program (143 bytes):
�.
: Invalid argument
error : failed to load new bf_program: Invalid argument
error : failed to generate and load new program: Invalid argument
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.