bpfilter
bpfilter copied to clipboard
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?
That sounds like a cool idea!
It's not currently possible to get the generated program from bpfilter
. I thought about it a few months ago but there was no usecase, but thanks to you it's different now!
I'll work on this in the coming days, to see how I can integrate this nicely, and come back to this issue to share the progress and a way for you to try it!
Is that ok for you?
@qdeslandes this sounds excellent. before i send you too deep on implementation (but by all means, feel free if you are excited!), i do still need to verify two other requirements:
- that there is a way to push an nftables config into bpfilter
- that uBPF can evaluate the bytcode which we pull out of bptilter
maybe you know the answer to the first, and i can dig into uBPF to understand its capabilities.
@khimaros After some more thought, I think this feature is more complicated than it seems, and there are some constraints which are difficult to overcome. However, I might have a solution for you anyway.
Firstly, my understanding is that you want to evaluate/validate one or more of nftables
's filtering rules. To do so, you might proceed the following way:
- Create one or more filtering rules using
nft
. - Get the corresponding BPF program from
bpfilter
. - Run the program in uBPF with a fake network packet as argument.
- Check the program's return value.
To provide more context, here's how bpfilter
current supports nftables
:
-
nft
will process the arguments received on the command line and convert those into Netfilter VM bytecode. - Due to
nft
's--bpf
option (not available upstream yet, but I've got a fork for it), this bytecode is not sent to the kernel using Netlink, but tobpfilter
. -
bpfilter
will convert the bytecode into its internal format, before generating the corresponding BPF bytecode.
It's important to mention that nftables
is stateful in that situation, meaning each new rule is added to an existing ruleset. During normal operation (without bpfilter
), the kernel is responsible for storing the existing ruleset, which is used by nftables
for each modification of the filtering rules. If bpfilter
is used, then bpfilter
is responsible for it.
1. Use nft
as a way to create/insert the rules
This solution would use bpfilter
as it currently works: each filtering rule added through the nft
command will update the existing ruleset, meaning bpfilter
will generate a new program on each call and attach it to the kernel.
However, there would be not way to get this program from the nft
command, or to prevent bpfilter
from inserting the program into the kernel: this would require me to modify how nft
behaves to pass or retrieve extra information, and the purpose of bpfilter
is to support nftables
as transparently as possible.
Assuming bpfilter
could provide a way to return the generated BPF program, there would still be an issue: each program generated by bpfilter
has its own map containing metadata, and the bytecode inserted into the kernel contain the map ID. Hence, to use the program in uBPF, you would have to re-create the map, and update the instructions in the program to fetch the map with the correct ID.
TL;DR: this solution doesn't work.
2. Create a custom client to control bpfilter
daemon
This involves creation a new client for bpfilter
instead of relying exclusively on nft
or iptables-legacy
commands. It's actually something I have on my roadmap.
I could imagine a way for this interface to be able to receive nft
-style commands. However, bpfilter
is not able to understand nft
command, unless they are converted to Netfilter bytecode, so if those commands have to go through the nft
binary, we're back to solution #1, with the same issues.
TL;DR: this solution doesn't work.
3. Use BPF directly instead of uBPF
Otherwise, you could use bpfilter
as expected, with nftables
, and let it attach BPF program to virtual interfaces! Basically, here how I see it:
- Create a (pair of) virtual interface(s)
- Start
bpfilter
with support for only the virtual interface- I would need to add this feature, e.g.
--restrict veth0
to ensurebpfilter
will only attach BPF programs toveth0
.
- I would need to add this feature, e.g.
- Use
nft --bpf
to create filtering rules and send fake traffic to it.
You would then be able to check how your rules behave by either:
- Checking a rule's counters (number of packets and number of bytes matched by a specific rule).
- Checking a rule's logs
- This is not supported yet, but a rule could definitely log a message when a packet is matched.
This is actually a workflow I've been working on for integration tests: nft
's binary will behave exactly as it would if it had to insert rules into the kernel, the rules can be validated through counters or logs, and the system won't be affected by your tests (thanks to the virtual interface).
Another benefit of this solution is that it doesn't depend on uBPF and the BPF features it might or might not support, compared to the actual BPF subsystem.
This answer was long that I expected! This answer is based on your requirement as I understand them, please feel free to correct any misunderstanding.
This issue hasn't been updated since my last comment, let's close it!