Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feasible to use bpfilter with uBPF to evaluate/test nftables rulesets in userspace? #56

Open
khimaros opened this issue Mar 6, 2024 · 3 comments

Comments

@khimaros
Copy link

khimaros commented Mar 6, 2024

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?

@qdeslandes
Copy link
Contributor

qdeslandes commented Mar 9, 2024

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?

@khimaros
Copy link
Author

khimaros commented Mar 12, 2024

@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:

  1. that there is a way to push an nftables config into bpfilter
  2. 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.

@qdeslandes
Copy link
Contributor

qdeslandes commented Mar 18, 2024

@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 to bpfilter.
  • 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 ensure bpfilter will only attach BPF programs to veth0.
  • 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants