如何正确配置环境编译基于Netfilter Hooks的BPF程序?
问题描述
我在Ubuntu 24.04(Linux内核6.8)上编写了一个BPF程序,目的是丢弃本地进出数据包,只允许转发数据包,计划用bpftool加载。程序代码如下:
#include <linux/bpf.h> #include <bpf/bpf_endian.h> #include <bpf/bpf_helpers.h> #include <linux/netfilter.h> SEC("netfilter") /* hint to BPF loader that this is a netfilter BPF program */ int filter(const struct bpf_nf_ctx *ctx) { const struct nf_hook_state *state = ctx->state; unsigned int routing_decision = state->hook; if (routing_decision == NF_INET_LOCAL_IN || routing_decision == NF_INET_LOCAL_OUT) return NF_DROP; return NF_ACCEPT; } char LICENSE[] SEC("license") = "GPL";
第一次编译错误
执行编译命令:
clang --target=bpf -O2 -Wall -I/usr/include/x86_64-linux-gnu -c filter.c -o filter.bpf.o
得到错误输出:
filter.c:8:27: warning: declaration of 'struct bpf_nf_ctx' will not be visible outside of this function [-Wvisibility] 8 | int filter(const struct bpf_nf_ctx *ctx) { | ^ filter.c:9:42: error: incomplete definition of type 'struct bpf_nf_ctx' 9 | const struct nf_hook_state *state = ctx->state; | ~~~^ filter.c:8:27: note: forward declaration of 'struct bpf_nf_ctx' 8 | int filter(const struct bpf_nf_ctx *ctx) { | ^ filter.c:10:29: error: incomplete definition of type 'struct bpf_nf_ctx' 10 | int routing_decision = ctx->state->hook; | ~~~^ filter.c:8:27: note: forward declaration of 'struct bpf_nf_ctx' 8 | int filter(const struct bpf_nf_ctx *ctx) { | ^ 1 warning and 2 errors generated.
添加头文件后的编译错误
我发现struct bpf_nf_ctx定义在nf_bpf_link.h中,于是添加了#include <net/netfilter/nf_bpf_link.h>,并调整编译命令添加内核头文件路径,但又出现错误:
clang --target=bpf -O2 -Wall -I/usr/include/x86_64-linux-gnu -I/usr/src/linux-headers-6.8.0-48/include -c filter.c -o filter.bpf.o
错误输出:
In file included from filter.c:1: In file included from /usr/src/linux-headers-6.8.0-48/include/linux/bpf.h:8: In file included from /usr/src/linux-headers-6.8.0-48/include/uapi/linux/filter.h:9: /usr/src/linux-headers-6.8.0-48/include/linux/compiler.h:251:10: fatal error: 'asm/rwonce.h' file not found 251 | #include <asm/rwonce.h> | ^~~~~~~~~~~~~~ 1 error generated. make: *** [Makefile:7: all] Error 1
解决方案
针对你的问题,需要从头文件依赖和编译环境配置两方面调整:
1. 修正BPF程序的头文件与逻辑
Netfilter BPF程序不能直接访问内核内部头文件(如nf_bpf_link.h),也不能直接读取bpf_nf_ctx->state,必须使用标准BPF helper函数获取上下文。修改后的程序代码如下:
#include <linux/bpf.h> #include <bpf/bpf_endian.h> #include <bpf/bpf_helpers.h> #include <linux/netfilter.h> #include <bpf/bpf_tracing.h> // 提供bpf_nf_ctx和bpf_get_nf_ctx的定义 SEC("netfilter") int filter(const struct bpf_nf_ctx *ctx) { struct nf_hook_state state; // 通过标准helper函数获取Netfilter hook状态 if (bpf_get_nf_ctx(ctx, &state, sizeof(state)) != 0) return NF_ACCEPT; unsigned int routing_decision = state.hook; if (routing_decision == NF_INET_LOCAL_IN || routing_decision == NF_INET_LOCAL_OUT) return NF_DROP; return NF_ACCEPT; } char LICENSE[] SEC("license") = "GPL";
2. 正确配置编译环境
编译BPF程序无需手动引用完整内核源码头文件,使用libbpf提供的头文件即可,先安装必要依赖:
sudo apt install clang llvm libbpf-dev linux-tools-common linux-tools-$(uname -r)
然后用以下命令编译,无需额外指定内核头文件路径:
clang --target=bpf -O2 -Wall -c filter.c -o filter.bpf.o
3. 加载并验证程序
编译完成后,使用bpftool加载到Netfilter钩子:
# 加载程序到BPF文件系统 sudo bpftool prog load filter.bpf.o /sys/fs/bpf/filter # 挂载到Netfilter各个钩子点 sudo bpftool netfilter add hook input priority 0 prog name filter sudo bpftool netfilter add hook output priority 0 prog name filter sudo bpftool netfilter add hook forward priority 0 prog name filter
内容的提问来源于stack exchange,提问作者Orian
相关产品推荐
相关产品推荐

