红联Linux门户
Linux帮助

【Linux调试经验】局域网内数据传输不经过路由

发布时间:2017-03-13 10:29:29来源:linux网站作者:arvik
问题/发现:
本人在为一款路由器写一个统计局域网互传流量的Linux内核模块的时候,发现如下问题:
局域网内的一台设备和该局域网内另一台设备进行通信时,我在路由器的netfilter链表处设下钩子,以捕获数据。后来发现这些数据没有经过netfliter,而是直接投递到对方网卡上的。
设备物理连接图如下:
【Linux调试经验】局域网内数据传输不经过路由
 
解释:
看似 个人手机 和 个人PC 这两台设备交换数据时 数据包“经由”了路由器,实际上,数据包如下图所示:
【Linux调试经验】局域网内数据传输不经过路由
当设备 个人手机 想发送数据到 个人PC时,流程如下:
1.个人手机 发送数据,数据无线传输到路由器 2.4GWiFi
2.数据向 个人PC 和 路由器br0网卡 各投递一份
3.1.路由器br0网卡 对比数据包MAC字段,发现该数据包不是发往自己的,丢弃
3.2.个人PC 收到数据包,对比数据包MAC字段,发现和自己MAC匹配,送往内部。
流程如上所述,而我在路由器netfilter链设下“埋伏”想捕获数据的做法无异于海底捞月。
 
验证:
抓包分析如下图所示,个人手机 数据包目的地址直接是 个人PC 的MAC地址,而不是 路由器br0网卡 的MAC地址,所以在路由器端是捕获不到这些数据包的。
【Linux调试经验】局域网内数据传输不经过路由
 
最终解决:
经过几日的思索,arvik最终一步步解决了问题。
解决思路:
局域网设备数据包互传是不经过路由器的,那怎么才能统计这些流量呢? 由上面的解释可知,数据包没有进入路由器br0网卡,所以关键问题就是让这些非本地的数据包能进入网卡。
实际上网卡是有这个功能的!
网卡一般有四种模式:
广播方式:该模式下的网卡能够接收网络中的广播信息。
组播方式:设置在该模式下的网卡能够接收组播数据。
直接方式:在这种模式下,只有目的网卡才能接收该数据。
混杂模式:在这种模式下的网卡能够接收一切通过它的数据,而不管该数据是否
是传给它的。
将网卡设置为混杂模式即可,如下:
将eth0设置成混杂模式
ifconfig br0 promisc
取消混杂命令如下:
ifconfig br0 -promisc
此时,局域网所有数据包都能进入路由器br0网卡。但是我们在netfilter还是不能统计,需将这些数据包引入netfilter结构,此时就需要稍微更改Linux内核代码了。更改如下:
在Linux内核源代码 /net/ipv4/ip_input.c文件中,第383,384行左右,有如下代码:
if (skb->pkt_type == PACKET_OTHERHOST)
goto drop;
注释掉,如下:
//if (skb->pkt_type == PACKET_OTHERHOST)  //noted by arvik 20160314
//  goto drop;
重新编译即可。
此时需要注意了,大量的非本地的数据包也会流经路由器netfilter链,我们只是对这些做一些统计,记住:统计完一定要把这些非本地的数据包丢弃掉,否则会给整个系统增加额外的负担,直接现象就是CPU占用率暴增,网络卡顿!
且你的netfilter的钩子函数一定要尽量靠前,最好在pre_routing节点,且优先级比其他钩子函数优先级都要高,这样才能尽量减少系统的的额外负担。
在做完统计后做如下检测:
if(skb->pkt_type == PACKET_OTHERHOST) //this packet is belong to other host, drop it!
return NF_DROP;
此时在路由器本地也可用netfilter钩子统计局域网其他设备互访的流量了!
 
本文永久更新地址:http://www.linuxdiyf.com/linux/29132.html