事情是这样的,我用路由器中继一个上层wifi上网,然而这个wifi很混乱,各种攻击,之前用arptables 这个老的防火墙效果挺不错,但是arptables没有日志功能。最近更新了openwrt 23.05.0,想整个重定向,发现openwrt现在主推nftables这个新的强大的防火墙。
nftables自带了arp过滤功能,但是这个网上资料太少了,我就对着机器翻译过来的wiki琢磨了一下,发现语法也没多难,只是有点繁杂,功能太多了。
下面是我的脚本代码,并且用我粗浅的表达能力做了简单的注释,这并不是nftables的教学,只是一个nftables的示例,主打一个改改就能用,给同样需要的人一个参考,抛砖引玉。原理就是简单粗暴的用nftables保证主机只和网关arp来往。
#!/bin/sh
dev='phy1-sta0'
# 这句是把设备名称也就是nftables要关注那个网卡的arp写死,我的环境是中继的WiFi,不用担心br-lan有人捣乱,只关注上级WiFi局域网内有人arp攻击;
wgw_ip=$(route | grep -w 'default' | awk '{print $2}')
# 这个是获取phy1-sta0所在网段的网关IP地址,如果获取有错,可以根据实际情况调整命令和方法;
wgw_mac=$(cat /proc/net/arp | grep -w ${wgw_ip} | awk '{print $4}')
# 这句是获取网关的mac地址;
nft delete table arp myarp 2>/dev/null
# 正片开始,这句是把之前可能已经设置好的arp表,链,规则全部删除了,如果不删的话,你继续添加不会覆盖相同的规则,会建立一条重复的规则,
# 如果不存在表,会回显一条错误提醒,我用2>/dev/null给屏蔽了;
nft add table arp myarp
# 这句是建立一个属于arp簇的表myarp,这个簇我的粗暴理解是表的属性分类,有ip,ipv6,inet,arp,nat等;
nft 'add chain arp myarp ipt { type filter hook input priority 0 ; policy accept; }'
# 给表myarp添加一个ipt链,链的类型是filter,挂到input勾子上,优先级是0(默认优先级吧,数字越小优先级越大,可以是负数),默认动作是accept,
# 这里默认动作如果设置成drop,会把所有接口的arp进入流量给禁止了,要注意哈;
nft 'add chain arp myarp opt { type filter hook output priority 0 ; policy accept; }'
# 和上一条类似,这句是给myarp表添加一天output链,我的简单理解是nftables的基本链 这个hook勾子最重要,决定了链的最终属性;
nft add rule arp myarp ipt iifname ${dev} arp saddr ip ${wgw_ip} arp saddr ether ${wgw_mac} counter accept\;
# 这句是关键了,给myarp表的ipt链添加关键规则,放行phy1-sta0的网关,iifname ${dev},规定了接口是phy1-sta0,不影响其他接口的arp,
# arp saddr ip ${wgw_ip}规定了进入的ip必须是网关ip,arp saddr ether ${wgw_mac}规定了mac必须是你指定的网关mac,这样可以阻止中间人
# 攻击,counter accept是两个动作,counter是计数,你可以大致知道有多少流量,适配了这条规则;
nft add rule arp myarp ipt iifname "${dev}" counter drop\;
# 这句是把从phy1-sta0 进入的arp流量drop掉,这个和iptables类似,也是逐条匹配规则的,如果上一条没有匹配会进入下一条,所以,这里
# 把不是网关的arp全部丢弃,保证只和网关通信;
nft add rule arp myarp opt oifname ${dev} arp daddr ip ${wgw_ip} arp daddr ether ${wgw_mac} counter accept\;
# 这条和上一条类似,是保证phy1-sta0的出口arp流量只和网关通信的,我不知道这么设置有没有意义,但是这么设置以后,arp缓存里面的全0mac没有了,
# 大概能够防御有人 网关arp泛洪;
# nft add rule arp myarp opt oifname "${dev}" log\; 这句我给注释了,作用是在丢弃arp包之前写入系统日志,这样就可以在系统日志看到详情,
# 但无奈这玩意儿太详细了,开启后整个系统日志全是这个,调试的时候开开可以,其他时候还是关了吧,太乱了。
nft add rule arp myarp opt oifname "${dev}" counter drop\;
echo
echo "Arptables initialization works done..."
echo
exit 0
脚本运行以后,在终端用 nft -an list table arp myarp 命令大概可以看到以下效果:
然后用其他同样连接上层wifi的设备,搞一些arping,ping之类的动作,可以看到tcpdump抓包在跑,但是arp缓存纹丝不动,并且已经drop了很多条!
那句,丢弃包之前的写入日志的功能,开启后大概如下:
最后,不建议把脚本放入 /etc/rc.local 里面开机运行,一旦出错,设备可能无法进入!
如果在终端运行脚本后出现连不上设备等问题,拔掉电源再插上重启就可以了,因为
openwrt 重启以后nftables 就恢复到默认状态了!
好了,祝好运,另外,折腾有风险!谨慎尝试!