北极星6号 2020-03-19 14:09 采纳率: 33.3%
浏览 477
已采纳

iptables -A INPUT -f -j DROP 丢弃碎片规则无效

练习iptables的攻击规则,发现如下的命令无效。
iptabled -A INPUT -f -j DROP

测试
win10: 192.168.0.2
linux: 192.168.0.5

测试1:无分片的报文
win10# ping 192.168.0.5 -->可以ping通 

测试2:带分片的报文
win10# ping 192.168.0.5 -l 3000 -->可以ping通 

测试3:linux过滤分片的报文
linux# iptables -A INPUT -f -j DROP
win10# ping 192.168.0.5 -l 3000 -->依旧可以ping通 

linux# iptables -nvL
Chain INPUT (policy ACCEPT 6729 packets, 8666K bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 DROP       all  -f  *      *       0.0.0.0/0            0.0.0.0/0

可以发现,规则没有匹配到任何一个报文。

网上找到关于 -f 分片的说明:

iptables -A INPUT -f
Dropping IP fragments is probably obsolete advice: the Linux kernel can and will automatically re-assemble and sanity-check all fragments as needed anyway. This happens before packets are handled by iptables connection tracking, so it is likely this rule may never match anything.

找到kernel 对于碎片整理的代码

p_input.c
ip_rcv()
{
    return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,
               net, NULL, skb, dev, NULL,
               ip_rcv_finish);
}

net/ipv4/netfilter/nf_defrag_ipv4.c
static struct nf_hook_ops ipv4_defrag_ops[] = {
    {
        .hook       = ipv4_conntrack_defrag,
        .pf     = NFPROTO_IPV4,
        .hooknum    = NF_INET_PRE_ROUTING,          #注册的链
        .priority   = NF_IP_PRI_CONNTRACK_DEFRAG,   #优先级
    }

发现defrag(碎片整理) 在PRE_ROUTING chain处理的,优先于INPUT chain 处理。
猜想可能是defrag导致 iptables -f无效,于是在ubuntu上做如下验证。

猜想验证:
linux
#kernel配置文件
/usr/src/linux-headers-4.4.0-148-generic/.config
CONFIG_NF_DEFRAG_IPV4=m

lsmod|grep nf_defrag_ipv4 #确认没有加载此模块

win10:
win10# ping 192.168.0.5 -l 3000 -->依旧可以ping通


Linux# iptables -nvL #发现依旧匹配没有匹配到数据包

验证结论:与defrag 功能无关。

计划:
看iptables -f 在netfilter 处理逻辑的,代码是否调用到相关的函数。

问题:
请问大家,相关的背景,原理。
针对测试,有相关的解决解决方案。

2020/03/20 更新

测试环境变更
win10: 192.168.0.2
Getway: 10.110.14.5
Dest_IP:10.110.14.16

分析:
1.报文分析
win10# ping xxx -l 3000 -n 1
一共发出三个报文,wireshark 抓到信息
No1 tcp ip.len=1500 flag=0x2000
No2 tcp ip.len=1500 flag=0x2000
No3 icmp ip.len=68 flag=0x0x72

2.linux调试
kernel/net/ip_input.c
int ip_rcv()
{
    ...
    if((iph->protocol == 1) && ip_is_fragment(iph)){
        printk("xxx find icmp frag len=%d id=%x s%x d%x\n",ntohs(iph->tot_len),ntohs(iph->id),
                ntohs(iph->saddr),ntohs(iph->daddr));
    }
}
可以打印出这个三个报文。

3.验证1:iptables 是否能匹配到这三个报文。
在iptables PREROUTING, INPUT添加如下规则
iptables -t mangle -A PREROUTING  -s 192.168.0.2 -d 10.110.14.16 -j LOG --log-prefix "11 mangle"
iptables -t mangle -A PREROUTING  -s 192.168.0.2 -d 10.110.14.16 -f -j LOG --log-prefix "12 mangle"
iptables -t nat -A PREROUTING  -s 192.168.0.2 -d 10.110.14.16 -j LOG --log-prefix "22 nat"
iptables  -I INPUT 10 -s 192.168.0.2 -d 10.110.14.16 -j LOG --log-prefix "33 filt"

dmesg 打印log:
[ 3188.325756] 11 mangleIN=BR_LAN OUT= MAC=d8:6c:a1:2f:37:a7:e8:4e:06:66:93:50:08:00 SRC=192.168.0.2 DST=10.110.14.16 LEN=3028 TOS=0x00 PREC=0x00 TTL=128 ID=22063 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=2847
[ 3188.343275] 22 natIN=BR_LAN OUT= MAC=d8:6c:a1:2f:37:a7:e8:4e:06:66:93:50:08:00 SRC=192.168.0.2 DST=10.110.14.16 LEN=3028 TOS=0x00 PREC=0x00 TTL=128 ID=22063 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=2847

验证结论:
1.对比第1,2条规则:
  1.ID=22063(分片报文标志MF 0x2000)说明分片报文。
  2.-f 无法匹配ip报文MF标志位。
  3.defrag的优先级是高于mangle PREROUTING的,此处LEN=3028应该是完整报文(待验证)。但No1,No2两个分片报文确认没有匹配。
2.对比第1,4规则:
  1.此处验证有误,由于是getway,需要在FORWARD中匹配。

4.验证2:直接在ip_rcv中丢弃报文
kernel/net/ip_input.c
int ip_rcv()
{
    ...
    if((iph->protocol == 1) && ip_is_fragment(iph)){
        printk("xxx find icmp frag len=%d id=%x s%x d%x\n",ntohs(iph->tot_len),ntohs(iph->id),
                ntohs(iph->saddr),ntohs(iph->daddr));
+       goto drop;
    }
}

win10# ping xxx -l 3000 -n 1
结果:ping failed



验证结论:
1.使用ip_is_fragment() 判断可行。

计划:
1.此处修改不符合规范,暂定使用iptable 新增模块来实现。
2.很好奇-f 到底是如何匹配报文,暂未找到代码实现。

2020/03/24 更新
解决方法

echo 0 > /proc/sys/net/ipv4/ipfrag_low_thresh
echo 0 > /proc/sys/net/ipv4/ipfrag_high_thresh

Change fragments buffer to 0. Drop fragments packages.

  • 写回答

1条回答 默认 最新

  • 北极星6号 2021-11-18 13:47
    关注

    解决方案:

    echo 0 > /proc/sys/net/ipv4/ipfrag_low_thresh
    echo 0 > /proc/sys/net/ipv4/ipfrag_high_thresh

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 已采纳回答 11月18日

悬赏问题

  • ¥15 安装svn网络有问题怎么办
  • ¥15 Python爬取指定微博话题下的内容,保存为txt
  • ¥15 vue2登录调用后端接口如何实现
  • ¥65 永磁型步进电机PID算法
  • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
  • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
  • ¥15 如何处理复杂数据表格的除法运算
  • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)
  • ¥15 有兄弟姐妹会用word插图功能制作类似citespace的图片吗?
  • ¥15 latex怎么处理论文引理引用参考文献