目录
1.碎片整理测试
【需求】
路由器过滤greptap 接口上的碎片报文,添加规则·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
测试结论:
可以发现,Chain INPUT 链没有匹配到任何一个报文。
即iptables -f 的规则无效。
iptabled -A INPUT -f -j DROP
2.iptables -f 不生效原因
原文:
Why command "iptables -f" no use ?
Dropping IP fragments is obsolete advice. 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.
3.报文碎片 丢弃的功能调试过程
测试1.内核协议栈分析
kernel/net/ip_input.c int ip_rcv() { ... //打印 icmp 碎片报文 if((iph->protocol == 1) && ip_is_fragment(iph)){ printk("xxxx find icmp frag len=%d id=%x \n",ntohs(iph->tot_len),ntohs(iph->id), ntohs(iph->saddr),ntohs(iph->daddr)); } }
Log 打印:
xxxx find icmp frag len=1500 id=6f4e
xxxx find icmp frag len=1500 id=654e
xxxx find icmp frag len=68 id=654e
→ 即ping -l 3000 被分成3个报文,符合预期
测试结论1:
在协议栈 ip_rcv()函数中,匹配到3个分片报文。
测试2:尝试在netfilter中匹配分片报文
通过iptables s_ip d_ip 匹配
iptables -t mangle -A PREROUTING -s 192.168.0.2 -d 192.168.0.5 -j LOG --log-prefix "11 mangle"
iptables -t nat -A PREROUTING -s 192.168.0.2 -d 192.168.0.5 -j LOG --log-prefix "22 nat"
Log:
[ 3188.] 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=192.168.0.5 LEN=3028 TOS=0x00 PREC=0x00 TTL=128 ID=22063 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=2847
[ 3188.] 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=192.168.0.5 LEN=3028 TOS=0x00 PREC=0x00 TTL=128 ID=22063 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=2847
-->此处应该打印三个记录,实际只打印一条记录,即分片报文已经重组
测试结论2:
在PREROUTING链的报文长度为3028,
即分片报文在 到达netfilter 的 PREROUTING链之前,已经进行重组。
Linux 网络协议栈 和 netfilter 处理流程图
代码分析1:
ip_rcv() { /* 1. 经过PRE_ROUTING钩子点 */ return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, net, NULL, skb, dev, NULL, ip_rcv_finish); } /* 2.碎片重组功能 注册在 PRE_ROUTING hook 上*/ 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,//mininum -400 }, ipv4_conntrack_defrag() -nf_ct_ipv4_gather_frags() --ip_defrage()
分析结论3:
从代码上,确认ip_rcv() 处理在 PREROUTING链 之前。
代码分析2
/* 3.碎片重组 缓冲区 参数*/
ip_defrage() static struct ctl_table ip4_frags_ns_ctl_table[] = { { .procname = "ipfrag_high_thresh", .data = &init_net.ipv4.frags.high_thresh, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &init_net.ipv4.frags.low_thresh }, { .procname = "ipfrag_low_thresh", .data = &init_net.ipv4.frags.low_thresh, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &zero, .extra2 = &init_net.ipv4.frags.high_thresh }, }
low_thresh high_thresh的作用,具体看代码。
尝试清除碎片缓存分区,参数对应的proc 节点
Set init_net.ipv4.frags.high_thresh to 0.
Set init_net.ipv4.frags.low_thresh to 0.
echo 0 > /proc/sys/net/ipv4/ipfrag_low_thresh
echo 0 > /proc/sys/net/ipv4/ipfrag_high_thresh
ping 192.168.0.5 -l 3000
Result: time out . --符合预期,ping失败。
测试总结4:
修改sys 节点,即可实现碎片报文的丢弃功能
/proc/sys/net/ipv4/ipfrag_low_thresh
/proc/sys/net/ipv4/ipfrag_high_thresh
4.小结
对ip协议栈的处理和netfilter之间的流程关系,理解的更深刻。
一开始并没有使用/proc/sys 节点实现,而是在函数之中
1.判断为碎片报文,直接丢弃。-->修改内核代码,无扩展性,丢弃。
2.将defrag的buffer修改为0,准备创建sys节点,将buffer 大小参数传递到用户空间修改,在编写的过程中,参照ipv4 sys节点的实现时,发现这两个节点
-->1.运气。 2.内核通过配置提供功能,机制。通过参数适配不同功能需。可适配,可调节。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/96177.html