基于eBPF/XDP实现防火墙功能
概述
互联网服务常常需要预防DDoS攻击,希望尽早丢弃攻击流量减少服务器资源的浪费。从概念上分析,防火墙是抵御DDoS的有效手段,但是实际基于NetFilter的IpTables并不能解决该问题,因为其处理报文的位置已分配SKB,大量无效SKB会耗尽内存资源,拖垮服务器。但基于eBPF/XDP实现的防火墙能够更早处理攻击流量而不消耗CPU和内存资源,更高效,更安全。
当然,仅靠eBPF/XDP防火墙是不能解决DDoS问题,防火墙只是手段,还需网络流分析系统识别流量特征并对其下发指令。
文本提供一个基于eBPF/XDP实现防火墙的思路和程序设计实现,码字不易,劳烦一键三连,感谢
环境配置 Ubuntu >= 20.10
- 安装依赖库 elf & zlib
apt install -y libelf1 libelf-dev
apt install -y zlib1g zlib1g-dev apt install -y libcap2 libcap-dev
- 安装编译器g++ & g++ & cmake & git
apt install -y git cmake g++ gcc pkg-config
gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
g++ --version
g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
git --version
git version 2.25.1
cmake --version
cmake version 3.16.3
pkg-config --version
0.29.1
- 源码安装libbpf
git clone https://github.com/libbpf/libbpf.git
cd libbpf/src
make
make install
必备工具bpftool
uname -r //查看内核版本
5.15.8-200.fc35.x86_64
wget https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-`uname -r|awk -F '-' '{print $1}'`.tar.gz //下载内核源代码
tar -zxf linux-5.15.8.tar.gz
cd linux-5.15.8/tools/bpf/bpftool/
make
mv bpftool /usr/bin/
bpftool --version
bpftool v5.15.8
bpffs 持久化
mount | grep bpf
none on /sys/fs/bpf type bpf (rw,nosuid,nodev,noexec,relatime,mode=700)
如果不存在则创建 bpffs
mount bpffs/sys/fs/bpf -t bpf
设计与实现
基于 eBPF/XDP 实现防火墙功能,支持四层网络,可以接受或者丢弃 IP+Port,或 IP/Mask+Port/Mask 的组合。DDoS 以大量无效报 文来浪费 CPU 资源来达到攻击目的。所以在数据路径上,越早处理 越安全。该服务在 XDP 位置挂载 eBPF 程序,在执行效率上明显高于 IPTables。
在程序设计方面,使用 eBPF LPM Map 在 eBPF 程序和用户态程 序共享储存。用户态程序将防火墙规则构造成 bitmap 数据结构并存 储到 map 中,eBPF 程序在数据路径上读取 map 数据并进行数据包过 滤,将满足条件的数据报文放行,否则丢包拒绝。防火墙规则如 下:
| 协议 | 源IP | 源端口 | 目的IP | 目的端口 | 动作 |
|---|
| 属性 | 示例 |
|---|---|
| 协议 | TCP UDP ICMP GRE |
| 源IP | 101.101.102.0/24 10.10.10.10/32 |
| 源端口 | 1-65535 22-444 |
| 目的IP | 101.101.102.0/24 10.10.10.10/32 |
| 目的端口 | 1-65535 22-444 |
| 动作 | accept drop |
若在匹配规则进行串型匹配,就会从走IPTables O(n)复杂度的老路,为了更高效的处理报文, 为了数据面尽可能的精简和高效,将复杂的规则映射到bitmap 这种高效的数据结构中, 控制面将规则生成对应的数据结构。构造 bitmap 需要 O(n),查询需要 O(logn)。
| 索引 | 协议 | 源IP | 源端口 | 目的IP | 目的端口 | 动作 |
|---|---|---|---|---|---|---|
| #1 | tcp | 10.10.2.5 | 1-65535 | 10.10.2.4 | 22 | accept |
| #2 | tcp | 10.10.2.5 | 1-65535 | 10.10.2.4 | 80 | accept |
| #3 | udp | 10.10.2.6 | 4000 | 10.10.2.4 | 3389 | accept |
核心思路将规则生成6张表的bitmap索引。1 表示该规则有该属性,0表示该规则无该属性
| 协议表 | bitmap |
|---|---|
| tcp | 110 |
| udp | 001 |
| 源IP表 | bitmap |
|---|---|
| 10.10.2.5 | 110 |
| 10.10.2.6 | 001 |
| 目的IP表 | bitmap |
|---|---|
| 10.10.2.4 | 111 |
| 源端口表 | bitmap |
|---|---|
| 1-65535 | 110 |
| 4000 | 001 |
| 目的端口表 | bitmap |
|---|---|
| 22 | 100 |
| 80 | 010 |
| 3389 | 001 |
| 动作表 | bitmap |
|---|---|
| accept | 111 |
-
udp 10.10.2.6 4000 10.10.2.4 3389
b=001&001&001&001&111&111=001 ✅ -
udp 10.10.2.6 4000 10.10.2.4 3389
b=001&001&001&001&111&111=001 ✅ -
udp 10.10.2.6 4001 10.10.2.4 3389
b=001&001&000&111&001&111=000 ❌ -
tcp 10.10.2.5 4001 10.10.2.4 3 81
b=110&110&110&000&111&111=000 ❌
防火墙程序
安装程序
dpkg-i fw-0.1.0-0-x86_64.deb
systemctl start fw
systemctl stop fw
dpkg-rfw
接口指南
- UpdateFirewall
POST http://192.168.56.4:3333
{
"action":"UpdateFirewall",
"traceId":"86475a74-c5a3-4632-9214-20bca82d433d",
"version": 10,
"rules":[
{
"protocol":"tcp",
"srcIp":"119.119.119.119/32",
"srcPort":"4000-5000",
"dstIp":"10.10.2.1/24",
"dstPort":"22-100",
"action":"accept"
},
{
"protocol":"icmp",
"srcIp":"10.10.2.1/24",
"dstIp":"10.10.2.1/24",
"action":"accept"
}
]
}
- QueryFirewall
POST http://192.168.56.4:3333
{
"action":"QueryFirewall",
"traceId":"b7be689f-0a1b-481b-bbb1-2cc987d3e809"
}
错误码表
| 错误码 | 错误信息 | 错误含义 | 解决方式 |
|---|---|---|---|
| 1000 | read request body error | 读取请求错误 | 重试 |
| 1100 | json format error | 请求参数格式错误 | 检查请求发送格式 JSON |
| 1101 | not support action error | 请求参数错误 | 检查接口拼写 |
| 1200 | update firewall error | 更新防火墙失败 | 权限不足 需要 ROOT 用户启动 |
| 1201 | query firewall error | 查询防火墙失败 | 权限不足 需要 ROOT 用户启动 |
加载eBPF程序
unlink /sys/fs/bpf/fw
bpftool prog load /usr/local/fw/xdp/fw.bpf.o /sys/fs/bpf/fw \
map name metadata pinned /sys/fs/bpf/metadata \
map name ipv4_proto pinned /sys/fs/bpf/ipv4_proto \
map name ipv4_nw_src pinned /sys/fs/bpf/ipv4_nw_src \
map name ipv4_nw_dst pinned /sys/fs/bpf/ipv4_nw_dst \
map name ipv4_tp_src pinned /sys/fs/bpf/ipv4_tp_src \
map name ipv4_tp_dst pinned /sys/fs/bpf/ipv4_tp_dst \
map name ipv4_action pinned /sys/fs/bpf/ipv4_action
bpftool prog show pinned /sys/fs/bpf/fw
359: xdp name xpd_handle_fw tag 5b2d17efc34ca615 gpl
loaded_at 2022-01-02T16:20:17+0800 uid 0
xlated 5336B jited 2982B memlock 8192B map_ids 35,5,10,15,20,25,30
btf_id 235
网卡设备关联eBPF
enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:f0:1e:41 brd ff:ff:ff:ff:ff:ff
inet 10.10.2.4/24 brd 10.10.2.255 scope global dynamic enp0s3
valid_lft 415sec preferred_lft 415sec
inet6 fe80::a00:27ff:fef0:1e41/64 scope link
valid_lft forever preferred_lft forever
ip link set dev enp0s3 xdp pinned /sys/fs/bpf/fw
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdpgeneric/id:359 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:f0:1e:41 brd ff:ff:ff:ff:ff:ff
inet 10.10.2.4/24 brd 10.10.2.255 scope global dynamic enp0s3
valid_lft 371sec preferred_lft 371sec
inet6 fe80::a00:27ff:fef0:1e41/64 scope link
valid_lft forever preferred_lft forever

参考
[1]: https://facebookmicrosites.github.io/bpf/blog/2018/08/31 /object-lifetime.html
[2]: https://ebpf.io/what-is-ebpf
4538

被折叠的 条评论
为什么被折叠?



