gamemann/XDP-Firewall
GitHub: gamemann/XDP-Firewall
一款基于 Linux XDP 与 eBPF 的高性能无状态防火墙,专注于低延迟流量过滤与 DDoS 缓解。
Stars: 829 | Forks: 132
[](https://github.com/gamemann/XDP-Firewall/actions/workflows/build.yml) [](https://github.com/gamemann/XDP-Firewall/actions/workflows/run.yml)
一个*无状态*的防火墙,使用 Linux 内核中的 [XDP](https://www.iovisor.org/technology/xdp) 钩点,通过 [(e)BPF](https://ebpf.io/) 附加以实现快速数据包处理。
该防火墙设计注重性能与灵活性,提供动态过滤、源 IP 阻断、IP 范围丢弃以及实时数据包计数等功能。这使其成为网络工程师、安全专业人士以及任何对 XDP 或高性能防火墙感兴趣者的强大工具。

我最终希望此工具能帮助现有的网络工程师和程序员利用 XDP,或帮助任何希望进入该领域的人!(D)DoS 保护与缓解是网络安全的重要一部分,理解网络概念以及低至中层的包处理流程无疑将有助于那些在该领域追求职业生涯的人 🙂
## 🚀 功能概览
所有功能均可在构建时配置([`config.h`](./src/common/config.h))或磁盘上的运行时配置中启用或禁用。如果您计划仅使用某些功能(如源 IP 阻断与丢弃),建议禁用其他功能(如动态过滤)以获得最佳性能。
### 🔥 高性能数据包过滤
* **XDP 驱动** - 在网络栈最早点运行,实现**最低延迟**。
* **基于 eBPF** - 使用 BPF Map 进行高效的规则查找与数据包处理。
### 🛑 源 IP 阻断与丢弃
* 立即**丢弃**来自已知恶意 IP 地址的数据包。
* 使用**BPF Map**进行**高效**查找与阻断。
* 可通过 CLI 工具(`xdpfw-add`、`xdpfw-del`)动态管理。
### ⚡ 动态过滤(规则驱动)
* 定义**自定义规则**,基于协议、端口、IP 地址等允许或丢弃数据包!
* 支持通过将 IP 加入阻断列表实现**临时封禁**,可配置封禁时长。
* 支持**TCP、UDP 和 ICMP** 四层协议以及**IPv6**!
* 包含源**流级别**与**IP级别**速率限制!
* 适用于缓解**非伪造 (D)DoS 攻击**。
### 🌍 IP 范围丢弃(CIDR)
* 在 XDP 级别高效阻断整个**IP 子网**。
* 支持**CIDR 格式过滤**(如 `192.168.1.0/24`)。
* 默认禁用,但可在 [`config.h`](./src/common/config.h) 中启用。
### 📊 实时数据包计数器
* 实时追踪**允许、丢弃、通过**的数据包。
* 支持**每秒统计**,便于流量分析。
### 📜 日志系统
* 内置**日志**输出到终端和/或文件。
* 可配置**日志详细级别**以控制输出。
### 📌 固定 BPF Map 与 CLI 工具
* **固定 BPF Map**允许外部程序与防火墙规则交互。
* CLI 工具(`xdpfw-add`、`xdpfw-del`)可实现**动态规则**管理,无需重启防火墙。
* 支持与**用户空间安全系统**集成以增强保护。
## 🛠️ 构建与安装
构建前请确保以下软件包已安装。这些软件包可通过 `apt` 在基于 Debian 的系统(如 Ubuntu)中安装,其他包管理器应有对应名称。
```
# 安装依赖。
sudo apt install -y libconfig-dev llvm clang libelf-dev build-essential
# 安装用于构建 LibXDP 和 LibBPF 的依赖。
sudo apt install -y libpcap-dev m4 gcc-multilib
# 您可能需要针对 Linux 内核的工具,因为需要 BPFTool。
# 如果这不起作用并且您仍然遇到问题,我建议从源代码构建 BPFTool(https://github.com/libbpf/bpftool)。
sudo apt install -y linux-tools-$(uname -r)
```
可使用 `git` 克隆该项目。请务必加上 `--recursive` 参数以下载 XDP Tools 子模块!否则需在克隆仓库目录中执行 `git submodule update --init`。
```
# 通过 Git 克隆仓库。使用递归标志下载 XDP Tools 子模块。
git clone --recursive https://github.com/gamemann/XDP-Firewall.git
# 切换到克隆的仓库目录。
cd XDP-Firewall
```
从此处,您有两种构建并安装防火墙的选项。
### 使用 Bash 脚本
构建并安装防火墙的最简便方式是使用提供的 [`install.sh`](./install.sh) Bash 脚本。该脚本依赖系统中已安装 `sudo`。若没有 sudo,请参考下方步骤在无 Bash 脚本的情况下构建安装。
如果系统尚未安装 LibXDP,建议使用以下命令。
```
./install.sh --libxdp
```
若已安装 LibXDP,可省略 `--libxdp` 参数。
此外,以下是可传递给该脚本的参数列表。
| 名称 | 描述 |
| ---- | ----------- |
| --libxdp | 构建并安装 LibXDP,然后再构建工具。 |
| --no-install | 构建工具或 LibXDP,但不安装。 |
| --clean | 清理工具和 LibXDP 的构建文件。 |
| --no-static | 构建时不静态链接 LibXDP 和 LibBPF 对象文件。这会加快构建速度,但可能需要调整 `LD_LIBRARY_PATH` 环境变量,且要求系统已安装 LibXDP。 |
| --objdump | 使用 [`llvm-objdump`](https://llvm.org/docs/CommandGuide/llvm-objdump.html) 将 XDP/BPF 对象文件反汇编为 `objdump.asm`,用于调试。 |
| --help | 显示帮助信息。 |

### 不使用 Bash 脚本
若不想使用上述 Bash 脚本,可改用 `make` 构建并安装。
```
# 构建 XDP-Tools(LibXDP 和 LibBPF)。
make libxdp
# 将 LibXDP 和 LibBPF 安装到您的系统。
# 警告:此命令必须以 root 身份执行!如果已安装并拥有相应权限,`sudo` 应该可以为您完成此操作。
sudo libxdp_install
# 构建防火墙工具。
make
# 将工具安装到您的系统。
# 警告:此命令必须以 root 身份执行!如果已安装并拥有相应权限,`sudo` 应该可以为您完成此操作。
sudo make install
```

## 💻 CLI 用法
运行防火墙时支持以下命令行参数。
| 名称 | 默认值 | 描述 |
| ---- | ------- | ----------- |
| -c, --config | `/etc/xdpfw/xdpfw.conf` | 配置文件路径。 |
| -o, --offload | N/A | 若设置,尝试以硬件/卸载模式加载 XDP 程序。 |
| -s, --skb | N/A | 若设置,强制使用 SKB 模式而非 DRV 模式加载 XDP 程序。 |
| -t, --time | N/A | 若设置,工具运行指定秒数后退出。例如 `--time 30` 运行 30 秒后退出。 |
| -l, --list | N/A | 若设置,打印当前配置值并退出。 |
| -h, --help | N/A | 打印帮助信息。 |
此外,还可通过命令行覆盖基础配置选项。
| 名称 | 示例 | 描述 |
| ---- | ------- | ----------- |
| -v, --verbose | `-v 3` | 覆盖配置中的详细级别。 |
| --log-file | `--log-file ./test.log` | 覆盖配置中的日志文件路径。 |
| -i, --interface | `-i enp1s0` | 覆盖配置中的首个接口。 |
| -p, --pin-maps | `-p 0` | 覆盖配置中的固定 Map 选项。 |
| -u, --update-time | `-u 30` | 覆盖配置中的更新间隔(秒)。 |
| -n, --no-stats | `-n 1` | 覆盖配置中的不统计选项。 |
| --stats-ps | `--stats-ps 1` | 覆盖配置中的每秒统计选项。 |
| --stdout-ut | `--stdout-ut 500` | 覆盖配置中的 stdout 更新间隔(毫秒)。 |
## ⚙️ 配置
本防火墙提供两种配置方式:
1️⃣ **构建时配置** - 在 [`config.h`](./src/common/config.h) 中修改硬编码常量,通过注释(`//`)或取消注释选项并设置值。由于这些设置在构建时即确定,修改后需重新构建防火墙才能生效。
2️⃣ **运行时配置** - 可通过磁盘上的配置文件调整设置。默认路径为 `/etc/xdpfw/xdpfw.conf`,但可通过 `-c` 或 `--config` CLI 选项指定其他路径。
使用 [`libconfig`](https://hyperrealm.github.io/libconfig/libconfig_manual.html) 库及其语法解析配置文件。
以下是运行时配置的更多细节。
### 主配置
| 名称 | 类型 | 默认值 | 描述 |
| ---- | ---- | ------- | ----------- |
| verbose | int | `2` | 日志详细级别(目前支持 0 - 5)。 |
| log_file | string | `/var/log/xdpfw.log` | 日志文件路径。若为空字符串(`""`),则禁用日志文件。 |
| interface | string \| list of strings | `NULL` | 要附加 XDP 程序的网络接口(通常通过 `ip a` 或 `ifconfig` 获取)。 |
| pin_maps | bool | `true` | 将主 B Map 固定到文件系统的 `/sys/fs/bpf/xdpfw/[map_name]`。 |
| update_time | int | `0` | 从文件系统更新配置与过滤规则的间隔(秒,0 表示禁用)。 |
| no_stats | bool | `false` | 是否启用或禁用数据包计数器。禁用计数器可提升性能,但会降低可见性。 |
| stats_per_second | bool | `false` | 若为真,数据包计数与统计按秒计算。此功能要求 `stdout_update_time` 小于等于 1000。 |
| stdout_update_time | int | `1000` | 显示数据包计数器时更新 stdout 的间隔(毫秒)。 |
| filters | list of filter objects | `()` | 使用的过滤规则列表。 |
| ip_drop_ranges | list of strings | `()` | 若启用了 IP 范围丢弃功能,则包含要丢弃的 IP 范围列表。 |
### 过滤规则对象
| 名称 | 类型 | 默认值 | 描述 |
| ---- | ---- | ------- | ----------- |
| enabled | bool | `true` | 规则是否启用。 |
| log | bool | `false` | 是否记录匹配的数据包。 |
| action | int | `1` | 值为 `0` 表示丢弃/阻断数据包,值为 `1` 表示允许/通过。 |
| block_time | int | `1` | 若匹配则阻断源 IP 的秒数。 |
| ip_pps | int64 | `NULL` | 若源 IP 的每秒数据包数超过此阈值则匹配。 |
| ip_bps | int64 | `NULL` | 若源 IP 的每秒字节数超过此阈值则匹配。 |
| flow_pps | int64 | `NULL` | 若源流(IP 与端口)的每秒数据包数超过此阈值则匹配。 |
| flow_bps | int64 | `NULL` | 若源流(IP 与端口)的每秒字节数超过此阈值则匹配。 |
#### IP 选项
| 名称 | 类型 | 默认值 | 描述 |
| ---- | ---- | ------- | ----------- |
| src_ip | string | `NULL` | 要匹配的源 IPv4 地址(例如 `10.50.0.3`)。也支持 CIDR(如 `10.50.0.0/24`)! |
| dst_ip | string | `NULL` | 要匹配的目标 IPv4 地址(例如 `10.50.0.4`)。也支持 CIDR(如 `10.50.0.0/24`)! |
| src_ip6 | string | `NULL` | 要匹配的源 IPv6 地址(例如 `fe80::18c4:dfff:fe70:d8a6`)。 |
| dst_ip6 | string | `NULL` | 要匹配的目标 IPv6 地址(例如 `fe80::ac21:14ff:fe4b:3a6d`)。 |
| min_ttl | int | `NULL` | 要匹配的最小 TTL(生存时间)。 |
| max_ttl | int | `NULL` | 要匹配的最大 TTL(生存时间)。 |
| min_len | int | `NULL` | 要匹配的最小数据包长度(包括以太网头部与负载)。 |
| max_len | int | `NULL` | 要匹配的最大数据包长度(包括以太网头部与负载)。 |
| tos | int | `NULL` | 要匹配的 ToS(服务类型)。 |
#### TCP 选项
可在过滤规则中指定 TCP 头部选项,名称以 `tcp_` 开头。
| 名称 | 类型 | 默认值 | 描述 |
| ---- | ---- | ------- | ----------- |
| tcp_enabled | bool | `false` | 是否在此规则上启用 TCP。 |
| tcp_sport | int \| string | `NULL` | 要匹配的 TCP 源端口,支持单范围(例如 `"20-22"`)。 |
| tcp_dport | int \| string | `NULL` | 要匹配的 TCP 目标端口,支持单范围(例如 `"20-22"`)。 |
| tcp_syn | bool | `false` | 若 TCP SYN 标志置位则匹配。 |
| tcp_ack | bool | `false` | 若 TCP ACK 标志置位则匹配。 |
| tcp_rst | bool | `false` | 若 TCP RST 标志置位则匹配。 |
| tcp_psh | bool | `false` | 若 TCP PSH 标志置位则匹配。 |
| tcp_urg | bool | `false` | 若 TCP URG 标志置位则匹配。 |
| tcp_fin | bool | `false` | 若 TCP FIN 标志置位则匹配。 |
| tcp_ece | bool | `false` | 若 TCP ECE 标志置位则匹配。 |
| tcp_cwr | bool | `false` | 若 TCP CWR 标志置位则匹配。 |
#### UDP 选项
可在过滤规则中指定 UDP 头部选项,名称以 `udp_` 开头。
| 名称 | 类型 | 默认值 | 描述 |
| ---- | ---- | ------- | ----------- |
| udp_enabled | bool | `false` | 是否在此规则上启用 UDP。 |
| udp_sport | int \| string | `NULL` | 要匹配的 UDP 源端口,支持单范围(例如 `"27000-27015"`)。 |
| udp_dport | int \| string | `NULL` | 要匹配的 UDP 目标端口,支持单范围(例如 `"27000-27015"`)。 |
#### ICMP 选项
可在过滤规则中指定 ICMP 头部选项,名称以 `icmp_` 开头。
| 名称 | 类型 | 默认值 | 描述 |
| ---- | ---- | ------- | ----------- |
| icmp_enabled | bool | `false` | 是否在此规则上启用 ICMP。 |
| icmp_code | int | `NULL` | 要匹配的 ICMP 代码。 |
| icmp_type | int | `NULL` | 要匹配的 ICMP 类型。 |
#### 说明
* 当规则内的设置字段未设置或设为 `-1`(或 `NULL`)时,将使用默认值(参见 [`set_filter_defaults()`](https://github.com/gamemann/XDP-Firewall/blob/master/src/loader/utils/config.c#L1047))。
* 当规则设置项与数据包不匹配时,程序会移至下一条规则。因此,所有已设置的规则项都必须匹配数据包才能执行指定操作。这类似于 `if src_ip == "10.50.0.3" and udp_dport == 27015: action`。
* 目前最多可指定 **1000 条** 动态过滤规则。可通过增大 `src/common/config.h` 中的 `MAX_FILTERS` 常量并重新编译来提升此限制。
* 目前每个端口值支持每条规则单个端口范围。这是因为支持多个端口/范围需要额外循环,会使 BPF 程序更大并影响性能等。
### 运行时配置示例
```
verbose = 5;
log_file = "";
interface = "ens18";
pin_maps = true;
update_time = 15;
no_stats = false;
stats_per_second = true;
filters = (
{
enabled = true,
action = 0,
udp_enabled = true,
udp_dport = 27015
},
{
enabled = true,
action = 1,
tcp_enabled = true,
tcp_syn = true,
tcp_dport = 27015
},
{
enabled = true,
action = 0,
icmp_enabled = true,
icmp_code = 0
},
{
enabled = true,
action = 0,
src_ip = "10.50.0.4"
}
);
ip_drop_ranges = ( "192.168.1.0/24", "10.3.0.0/24" );
```
## 🔧 `xdpfw-add` 与 `xdpfw-del` 工具
当主 BPF Map 被固定到文件系统时(取决于上述运行时 `pin_maps` 选项),可使用 `xdpfw-add` 与 `xdpfw-del` 工具在防火墙运行时添加或删除规则。
### 通用 CLI 用法
这些工具支持以下通用 CLI 参数。
| 名称 | 示例 | 描述 |
| ---- | ------- | ----------- |
| -c, --cfg | `-c ./local/conf` | 配置文件路径(若指定了保存参数或使用动态过滤模式则为必需)。 |
| -s, --save | `-s` | 更新运行时配置文件。 |
| -m, --mode | `-m 1` | 模式(0 = 动态过滤,1 = IP 范围丢弃列表,2 = 源 IP 阻断列表)。 |
| -i, --idx | `-i 3` | 在过滤模式下的索引,用于更新或删除。 |
| -d, --ip | `-d 192.168.1.0/24` | 在 IP 范围丢弃或源 IP 阻断模式下使用的 IP 范围或源 IP。 |
| -v, --v6 | `-v` | 在源 IP 阻断列表模式下解析并添加 IPv6 地址。 |
### `xdpfw-add` 工具
此 CLI 工具允许添加动态规则、IP 范围至丢弃列表以及源 IP 至阻断列表。建议使用 `xdpfw-add -h` 获取更多信息。
#### 额外 CLI 用法
| 名称 | 示例 | 描述 |
| | ------- | ----------- |
| -e, --expires | `-e 60` | 在 IP 阻断列表模式下,源 IP 阻断的过期时间(秒)。 |
| --enabled | `--enabled 0` | 启用或禁用动态过滤。 |
| --action | `--action 1` | 对匹配数据包执行的操作(0 = 丢弃,1 = 允许)。 |
| --log | `--log 1` | 启用或禁用该动态规则的日志记录。 |
| --block-time | `--block-time 60` | 若匹配且操作为丢弃,则阻断源 IP 的时长(秒,0 表示无时长限制)。 |
| --sip | `--sip 192.168.1.0/24` | 要匹配的源 IPv4 地址/范围。 |
| --dip | `--dip 10.90.0.0/24` | 要匹配的目标 IPv4 地址/范围。 |
| --sip6 | `--sip6 192.168.1.0/24` | 要匹配的源 IPv6 地址。 |
| --dip6 | `--dip6 192.168.1.0/24` | 要匹配的目标 IPv6 地址。 |
| --min-ttl | `--min-ttl 0` | 要匹配的 IP 最小 TTL。 |
| --max-ttl | `--max-ttl 6` | 要匹配的 IP 最大 TTL。 |
| --min-len | `--min-len 42` | 要匹配的数据包最小长度。 |
| --max-len | `--max-len 96` | 要匹配的数据包最大长度。 |
| --tos | `--tos 1` | 要匹配的 IP 的 ToS(服务类型)。 |
| --ip-pps | `--ip-pps 10000` | 要匹配的最小 PPS 速率。 |
| --ip-bps | `--ip-bps 126000` | 要匹配的最小 BPS 速率。 |
| --flow-pps | `--flow-pps 3000` | 要匹配的最小流 PPS 速率。 |
| --flow-bps | `--flow-bps 26000` | 要匹配的最小流 BPS 速率。 |
| --tcp | `--tcp 1` | 启用或禁用 TCP 匹配。 |
| --tsport | `--tsport 22` | 要匹配的 TCP 源端口。 |
| --tdport | `--tdport 443` | 要匹配的 TCP 目标端口。 |
| --urg | `--urg 1` | 启用或禁用 TCP URG 标志匹配。 |
| --ack | `--ack 1` | 启用或禁用 TCP ACK 标志匹配。 |
| --rst | `--rst 1` | 启用或禁用 TCP RST 标志匹配。 |
| --psh | `--psh 1` | 启用或禁用 TCP PSH 标志匹配。 |
| --syn | `--syn 1` | 启用或禁用 TCP SYN 标志匹配。 |
| --fin | `--fin 1` | 启用或禁用 TCP FIN 标志匹配。 |
| --ece | `--ece 1` | 启用或禁用 TCP ECE 标志匹配。 |
| --cwr | `--cwr 1` | 启用或禁用 TCP CWR 标志匹配。 |
| --udp | `--udp 1` | 启用或禁用 UDP 匹配。 |
| --usport | `--usport 53` | 要匹配的 UDP 源端口。 |
| --udport | `--udport 27015` | 要匹配的 UDP 目标端口。 |
| --icmp | `--icmp 1` | 启用或禁用 ICMP 匹配。 |
| --code | `--code 1` | 要匹配的 ICMP 代码。 |
| --type | `--type 8` | 要匹配的 ICMP 类型。 |
### `xdpfw-del` 工具
此 CLI 工具允许删除动态规则、IP 范围以及源 IP 阻断列表中的 IP。
该工具无额外 CLI 用法,请参考上方的通用 CLI 用法。
## 📝 注意事项
### XDP 附着模式
默认情况下,防火墙使用 **DRV** 模式(又称原生模式;在 [SKB 创建](http://vger.kernel.org/~davem/skb.html) 之前)附着到 Linux 内核的 XDP 钩点。如果主机的网络配置或网卡(NIC)不支持 DRV 模式,程序将尝试使用 **SKB** 模式(通用模式;在 SKB 创建之后附着,此时 IPTables 和 NFTables 通过 `netfilter` 内核模块处理)附着。您可通过命令行参数强制使用 SKB 或卸载模式。
主机网络配置不支持 XDP DRV 模式的原因可能包括:
* 运行的内核版本过旧,不支持网卡的驱动。
* 网卡驱动尚未支持 XDP。[此处](https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md#xdp)是网卡驱动的 XDP 支持列表。若具备足够的 Linux 内核开发知识,可尝试为不支持的网卡驱动实现 XDP DRV 支持(强烈建议观看[此视频](https://www.youtube.com/watch?v=ayFWnFj5fY8)!)。
* RX/TX 队列不足(例如未启用多队列)或 RX/TX 队列数量不匹配。据我了解,建议每个 CPU 核心/线程配置一个 RX 和 TX 队列。可尝试使用 [ethtool](https://man7.org/linux/man-pages/man8/ethtool.8.html) 并调整网卡的 RX/TX 队列设置([本文](https://www.linode.com/docs/guides/multiqueue-nic/)或许有帮助!)。
#### 卸载信息
将 XDP/BPF 程序卸载到系统网卡可让数据包处理达到最高速度,因为网卡会直接丢弃数据包。但首先,**许多**网卡制造商并不支持此功能;其次,您受限于网卡的内存与处理能力(例如 BPF Map 大小会非常有限)。此外,卸载的 BPF 程序通常有更严格的验证器限制,但您可以尝试联系网卡制造商,看他们是否提供放宽这些限制的特定驱动版本(我曾对某个制造商这样做过)。
截至目前,我尚不清楚有任何网卡制造商能完全卸载此防火墙至网卡,原因在于其 BPF 复杂度。老实说,在当今网络时代,我认为最好将卸载程序限制在 BPF Map 查询和最小包检查。例如,针对恶意源 IP 或端口的 BPF 黑名单 Map 查询。但 XDP 仍非常新,我预计未来几年这些限制会放宽或消除。这就是为何我在此防火墙中加入了卸载模式支持。
### BPF 循环支持与性能注意事项
动态过滤规则特性需要通用循环支持以及 [`bpf_loop()`](https://docs.ebpf.io/linux/helper-function/bpf_loop/) 函数的支持。较旧的内核不支持通用循环,并会输出如下错误。
```
libbpf: load bpf program failed: Invalid argument
libbpf: -- BEGIN DUMP LOG ---
libbpf:
back-edge from insn 113 to 100
libbpf: -- END LOG --
libbpf: failed to load program 'xdp_prog'
libbpf: failed to load object '/etc/xdpfwd/xdp_prog.o'
```
看起来通用 BPF 循环[支持](https://lwn.net/Articles/794934/) 在内核 5.3 中添加。因此,您需要内核 5.3 或更高版本才能让此工具正常运行。
值得一提的是,`bpf_loop()` 函数在内核 `5.17` 中添加,但*可能*仍需 `6.4` 或更高版本以支持开放编码迭代器。若您不想将内核升级至 6.4 或更高,需要在 [`config.h`](./src/common/config.h) 文件中注释掉 `USE_NEW_LOOP` 常量。请注意,若这样做,您将**极度受限**地创建过滤规则(建议最多 60 条)。因此,建议使用 `bpf_loop()`,因为这样可以创建更多过滤规则(超过 1000 条)!
#### 动态过滤的性能与循环
由于在 XDP 程序中使用了处理所有过滤规则的 BPF 数组 Map 的 [`for` 循环](https://github.com/gamemann/XDP-Firewall/blob/master/src/xdp/prog.c#L339),性能会根据配置的过滤规则数量受到影响(最终,防火墙**无法很好地扩展**)。此防火墙旨在提供尽可能灵活的配置,并且在配置为将恶意源 IP 添加到阻断 Map 并在程序开头进行丢弃时效果最佳,以实现最佳性能。
不幸的是,在当前允许的灵活性范围内,我们无法真正消除 `for` 循环,除非创建更多 BPF Map 并插入更多条目(这将消耗大量内存且不理想)。如果我们放弃灵活性,最佳做法是将过滤规则存储在使用数据包目标 IP/端口作为键的哈希 BPF Map 中(在我看来,这将消除针对单个目标 IP 而不带端口的过滤规则所需的多次 BPF Map 查询,从而影响性能)。然而,由于灵活性的大量丧失以及我没有时间开发,目前没有计划切换到此格式。
该防火墙在过滤非伪造攻击方面仍然表现良好,尤其是在指定阻断时间的情况下,这样恶意 IP 会在程序开头被阻断一段时间。
### 速率限制
本防火墙支持源**流级别**(`flow_pps` 和 `flow_bps` 设置)和**级别**(`ip_pps` 和 `ip_bps` 设置)速率限制。然而,默认情况下源 IP 速率限制是禁用的,因为两种方法需要独立计算,若过滤规则中未同时使用两种方法则不理想。我发现大多数用户更倾向于流级别速率限制,因此我决定默认仅启用该功能。
此外,如果您遇到大量伪造数据包,**强烈建议**暂时完全禁用速率限制。这是因为来自不同 IP 和端口的伪造数据包会导致速率限制 BPF Map 快速回收条目,根据伪造数据包的数量和主机硬件,这可能导致极高的 CPU 使用率。
### 过滤日志
本工具使用 `bpf_ringbuf_reserve()` 和 `bpf_ringbuf_submit()` 进行过滤匹配日志记录。目前对可发送的日志消息数量没有速率限制。因此,如果您遇到启用了日志记录的过滤规则匹配伪造攻击,将导致额外的处理与磁盘负载。
我建议目前仅在调试时启用过滤日志。若要完全禁用过滤日志(这会略微提升性能),可以注释掉 [`这里`](https://github.com/gamemann/XDP-Firewall/blob/master/src/common/config.h#L32) 的 `ENABLE_FILTER_LOGGING` 行。
```
//#define ENABLE_FILTER_LOGGING
```
我很可能会在未来实现对 XDP 日志消息的速率限制功能。
### LibBPF 日志
通过 LibXDP/LibBPF 加载 BPF/XDP 程序时,除非将 `verbose` 日志级别设置为 `5` 或更高,否则日志记录将被禁用。
如果工具无法加载或附着 XDP 程序,建议将 `verbose` 设置为 5 或更高,以便 LibXDP 输出具体的警告与错误信息。
## ❓ 常见问题
### 运行程序时收到与加载共享库相关的错误。如何修复?
如果在运行程序时遇到类似以下错误(且使用非静态构建方式),请确保已通过 [XDP Tools](https://github.com/xdp-project/xdp-tools) 将 LibXDP 全局安装到系统。可以执行 `make libxdp && sudo make libxdp_install` 来分别构建并安装 LibXDP 和 LibBPF。
```
./xdpfw: error while loading shared libraries: libxdp.so.1: cannot open shared object file: No such file or directory
```
如果仍遇到问题,请尝试将 `/usr/local/lib` 添加到 `LD_LIBRARY_PATH` 环境变量中,因为这是 LibXDP 安装共享对象的位置。以下是一个示例。
```
export LD_LIBRARY_PATH=/usr/local/lib
sudo xdpfw
```
### 编译时收到与工具链强化相关的错误。如何修复?
如在 issue [#38](https://github.com/gamemann/XDP-Firewall/issues/38) 中 [g00g1](https://github.com/g00g1) 所述,若启用了工具链强化,编译时可能会收到以下错误。
```
error: :0:0: in function xdp_prog_main i32 (ptr): A call to built-in function '__stack_chk_fail' is not supported.
```
为修复此问题,需要在编译 LibBPF 和防火墙本身时向 Clang 传递 `-fno-stack-protector` 标志。需要修改每个项目的 `Makefile` 以添加此标志。相关补丁可在此处找到 [这里](https://github.com/gamemann/XDP-Firewall/issues/38#issuecomment-1547965524)!
### 在 Ubuntu 20.04 上运行防火墙时遇到问题。可能的原因是什么?
如果在 Ubuntu 20.04 或更早版本上遇到问题,请参考[此](https://github.com/gamemann/XDP-Firewall/issues/41#issuecomment-1758701008)问题的回复。
基本上,需要 Clang/LLVM 12 或更高版本,我建议运行 Linux 内核 5.3 或更高版本。
### 是否会实现有状态防火墙?
目前没有计划实现有状态防火墙。可能会创建一个带有基本连接跟踪功能的独立防火墙,但我不确定时间表,也未开始开发。话虽如此,我不能分享七层过滤或完整 TCP 代理(带 SYN Cookie 支持)的代码。
## 🌟 我的其他 XDP 项目
我还想分享其他使用 XDP(或 AF_XDP 套接字)的开源项目,供对此感兴趣的人参考。希望这些项目的代码能帮助那些希望在自己的项目中使用 XDP 的程序员!
### [XDP Proxy](https://github.com/gamemann/XDP-Proxy)
一个*无状态*、高性能的类似 NAT 的代理,使用 Linux 内核中的 [XDP](https://www.iovisor.org/technology/xdp) 钩点,通过 [(e)BPF](https://ebpf.io/) 进行快速数据包处理。
该代理基于可配置规则转发数据包,并执行**源端口映射**,类似于 [IPTables](https://linux.die.net/man/8/iptables) 和 [NFTables](https://wiki.nftables.org/wiki-nftables/index.php/Main_Page)。
### [Kilimanjaro](https://github.com/gamemann/Kilimanjaro)
这是一个复杂的包处理/转发/丢弃项目,我为一个游戏社区创建,使用了 XDP、AF_XDP 和 IPIP 网络协议。我不再维护该项目,但其源代码可能对其他 XDP 开发者很有用,尤其是在处理 XDP 中的数据包等方面。
### [Packet Batch (AF_XDP)](https://github.com/Packet-Batch/PB-AF-XDP)
一个利用高速 [AF_XDP](https://docs.kernel.org/networking/af_xdp.html) Linux 套接字生成和发送网络数据包的应用。这用于包括拒绝服务(DoS)、网络监控在内的渗透测试等!
虽然此应用未使用原生 XDP 或 (e)BPF,但我认为值得在此提及。AF_XDP 套接字非常快,通常与通过 `bpf_redirect_map()` 函数调用的原始 XDP 程序一起使用(也可参考我的 [XDP Stats](https://github.com/gamemann/XDP-Stats) 项目,该项目在原生 XDP 和 AF_XDP 程序中计算统计信息)。
## 🙌 致谢
* [Christian Deacon](https://github.com/gamemann) - 创建者。
* [Phil](https://github.com/Nasty07) - 贡献者。
标签:BPF映射, DDoS防护, Docker镜像, DoS防护, IPv6防火墙, IP范围丢弃, Linux内核, stateless防火墙, XDP钩子, XDP防火墙, 内核旁路, 动态过滤, 实时数据包计数, 客户端加密, 开源防火墙, 性能优化, 数据包过滤, 检测绕过, 源IP屏蔽, 目录遍历, 网络安全, 网络防护, 隐私保护, 高并发网络处理, 高性能防火墙