0%

rp_filter反向路由过滤

Reverse Path Filtering,Linux 内核对接收到的数据包的反向路由校验过滤,主要用于防止 IP 地址欺骗攻击。本文主要介绍该校验机制、系统配置方式以及过滤包查看方法。

反向路由校验机制

反向路由校验,即在网卡收到数据包后,校验该数据包的反向路由是否匹配,如不匹配,则丢弃该包。具体流程如下:

  1. 对于网卡收到的数据包,Linux 内核会检查该数据包的源 IP
  2. 参照当前的路由表,判断如以该数据包的源 IP 作为目的 IP,返回路径的路由选择是否与当前接收接口一致
  3. 如不一致,则认为该数据包可能是伪造的,丢弃该数据包

如下图,eth1 网卡开启了严格的 rp_filter 检查,此时 eth1 网卡收到源 IP 为 172.16.19.24 的包,rp_filter 检查如果以 172.16.19.24 为目的 IP,根据路由表,匹配的网卡应该为 eth0,而不是收到包的 eth1,因此判断该数据包可能伪造源 IP,丢弃该包。

image-20241124140220970

Linux 内核参数

net.ipv4.conf.XXX.rp_filter

Linux 内核参数详解

rp_filter 为 Linux 用于设置反向路由校验机制的内核参数,共有三种可配置值 0、1、2,

  • rp_filter = 0:关闭反向路由校验。
  • rp_filter = 1:开启严格的反向路由校验。如果反向路由不是最佳路由,则丢弃该包。
  • rp_filter = 2:开启松散的反向路由校验。对于收到的数据包,只检查其源 IP 是否可达,即反向路由是否可通(任意网卡均可),如果反向路径不通,则丢弃该包。

rp_filter 分为三类:alldefault、特定网卡。

  • default 用于生成网卡时设置默认的 rp_filter 值
  • 每张网卡的 rp_filter 取 conf/{all,interface}/rp_filter 中的最大值

如下面配置,eth0 的 rp_filter 为 1(取 all 和 eth0 中的最大值),eth1 的 rp_filter 为 2(取 all 和 eth1 中的最大值)

1
2
3
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 0
net.ipv4.conf.eth1.rp_filter = 2

查看 rp_filter

1
2
3
4
5
6
7
root@ubuntu2404:~# sysctl -a | grep rp_filter
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2
net.ipv4.conf.ens160.rp_filter = 2
net.ipv4.conf.ens256.rp_filter = 2
net.ipv4.conf.lo.rp_filter = 0
...

设置 rp_filter

临时设置(重启后失效)

1
2
root@ubuntu2404:~# sysctl -w net.ipv4.conf.ens160.rp_filter=1
net.ipv4.conf.ens160.rp_filter = 1

tcpdump 与 rp_filter

tcpdump 依旧可以抓到被 rp_filter 过滤掉的包。

下图的五层网络分层模型中,收包是从下到上,发包是从上到下。

image-20241125012534947

tcpdump 运行在链路层的网络设备层,而 rp_filter 运行在协议栈的网络层,对于收包流程来说,tcpdump 先于 rp_filter 进行,所以即使数据包会被 rp_filter 过滤掉,依旧可以通过 tcpdump 抓到该数据包。

image-20241125013945101

rp_filter 日志

默认情况下,内核并不会记录被 rp_filter 过滤掉的包,但可以通过 iptables 添加日志规则,模拟和预测哪些包会被 rp_filter 丢弃。

添加 iptables 日志规则(如需删除,则把其中的 -A 改成 -D

1
iptables -t raw -A PREROUTING -m rpfilter --invert -j LOG --log-prefix "RP_FILTER_DROP: "

查看添加的 iptables 日志规则

1
2
3
4
root@ubuntu2404:~# iptables -t raw -L PREROUTING -v
Chain PREROUTING (policy ACCEPT 299 packets, 20976 bytes)
pkts bytes target prot opt in out source destination
299 20976 LOG all -- any any anywhere anywhere rpfilter invert LOG level warn prefix "RP_FILTER_DROP: "

查看内核日志

1
dmesg -T | grep "RP_FILTER_DROP"
1
2
3
4
root@ubuntu2404:~# dmesg -T | grep "RP_FILTER_DROP" | tail -20
[Sun Nov 24 18:27:49 2024] RP_FILTER_DROP: IN=ens256 OUT= MAC=00:0c:29:48:8d:03:ae:07:75:50:39:65:08:00 SRC=172.16.19.1 DST=172.16.19.129 LEN=88 TOS=0x0A PREC=0x40 TTL=64 ID=0 DF PROTO=TCP SPT=60402 DPT=22 WINDOW=2048 RES=0x00 ACK PSH URGP=0
[Sun Nov 24 18:27:49 2024] RP_FILTER_DROP: IN=ens256 OUT= MAC=00:0c:29:48:8d:03:ae:07:75:50:39:65:08:00 SRC=172.16.19.1 DST=172.16.19.129 LEN=52 TOS=0x08 PREC=0x40 TTL=64 ID=0 DF PROTO=TCP SPT=60402 DPT=22 WINDOW=2047 RES=0x00 ACK URGP=0
[Sun Nov 24 18:27:49 2024] RP_FILTER_DROP: IN=ens256 OUT= MAC=00:0c:29:48:8d:03:ae:07:75:50:39:65:08:00 SRC=172.16.19.1 DST=172.16.19.129 LEN=88 TOS=0x0A PREC=0x40 TTL=64 ID=0 DF PROTO=TCP SPT=60402 DPT=22 WINDOW=2048 RES=0x00 ACK PSH URGP=0