邢彬 /* XingBin.net */
XING Bin, a Coder, Geek, Railfan, and Outdoors Fan
face

实验室内网络流量统计系统设计与实现

发布 / 2014-12-11 15:39   于 / Channel 8   文 / XingBin   浏览 / 4798  

在校园网内访问外网时,信息中心会根据IP地址所产生的流量进行计费。因此,当实验室内使用路由器进行上网时,实验室内多人的流量会进行累计统计。根据校园网的计费策略,20元的套餐包含15G的下行流量,超出部分每1G计费4元。因此,如果实验室内有人从校外下载文件或观看视频产生了大量的流量,会使得实验室的网费飙升造成上网账号停用,而且还不知道是谁干的,这怎么行……

所以,需要一套流量统计系统,能够较为精确地统计实验室内每个人的上网流量,同时能够直观地显示出来。

因此,本流量统计系统共包括3个部分。一是流量统计程序,二是流量统计数据库,三是流量查询程序。为了方面,上述三部分都部署在实验室的出口路由器(软路由,Linux系统,iptables实现IPv4 NAT,brctl+ebtables实现IPv6透传)中,流量统计程序和流量查询程序通过流量统计数据库耦合在一起。

一、流量统计程序

流量统计程序的作用是抓取经过网卡的每个数据包,判断是否需要进行流量统计,在对应地将流量记录到相应的数据库中。流程图如下。

流量统计原理.png

第一步,抓取数据包。

在流量统计程序中,首先确认数据包的来源。根据需要,只在连接局域网的网卡上进行统计(如eth0)。这是因为:1、路由器本身产生外网访问流量并不大,或者说不需要统计;2、路由器可能具有多WAN口,需要分别统计也是一个麻烦的事情;3、由于路由器做了NAT,在WAN口统计到的数据包的IP不会是内网IP,无法进行区分。

抓取数据包最常用的方法就是利用libpcap库。通过pcap_open_live函数打开eth0接口,然后通过pcap_compile和pcap_setfilter设置第一步的过滤规则。这里设置了一条规则:

dst net 192.168.1.0 mask 255.255.255.0

规则的含义是,经过eth0的数据包中,如果包的目的地址是192.168.1.0/24,那么才进行进一步处理,否则直接忽略。这是因为,在eth0统计数据包时会统计流入和流出双向的数据包(可以参考WireShark的抓包结果)。而校园网的流量统计规则中,上传是不计流量的,只有下载统计流量。因此,这条过滤规则直接将上行数据包全部忽略掉。

然后,通过pcap_loop设置回调函数,将抓取得到的数据包交由回调函数处理即可。

第二步,分析数据包并统计流量。

第一步中抓取到的数据包会全部作为参数传入回调函数。这时需要在回调函数中进行进一步的分析处理。

首先,先进行初始判断,如果传进来的参数是NULL,那就可以直接返回了。(天知道传进来的参数是什么样子,稳妥一点比较好。)

然后,对Ethernet帧的头部进行分析,拿到type字段的值。如果type值不为0x0800(注意字节序和网络序),说明不是IPv4包,这里可以将其直接忽略。不同的帧其type位置不一定一致。对于10/100/1000Mbps的局域网而言,其帧应该是Ethernet II标准,其头部应包括8字节报头(但捕获的包不包括这部分),6字节目标MAC,6字节源MAC,2字节type,其后是有效载荷,那么此时type的offset应该为12字节。

接下来,拿到IP报文部分的源和目的IP地址,再判断源IP地址是否在免记流量的地址段内。例如,来源IP地址来属于校园网的IP时,不计流量。来源IP地址属于局域网的IP时,也不计流量。将这部分包同样忽略。IPv4的报文中,源和目的IP地址的offset分别为12和16字节。

最后,剩下的就属于来自于校外的数据包了。从包头部中拿到该IP包的长度(struct pcap_pkthdr的len成员),计入数据库即可。

需要注意的是,该程序需要做成守护程序,并在系统中创建相应的服务。否则,运行该程序的用户注销时,程序将退出,无法持续统计流量。

关于libpacp编程和守护进程的实现,请查阅文后的参考文献。

二、流量统计数据库

流量统计数据库的作用是记录每个IP所对应的流量。在绝大多数情况下,并不需要统计每个IP具体访问了哪些网站,传输了什么数据,只需要记录数据包的大小。因此,推荐使用NOSQL型的Redis数据库。该数据库的优点是更加轻量,属于key-value操作。当得到数据包的大小后,将值以增量的形式添加到IP对应的key上即可,如Redis中的INCRBY命令。

为了编程使用Redis数据库更加方便,可以安装hiredis-devel库,以便在用C语言编写的流量统计程序中访问Redis数据库更新数据。还可以安装php-pecl-devel库,以便在用php语言编写的页面中访问Redis数据库查询数据。

显然,用内存进行存储更快,但是会遇到以下两个问题。1、查询操作不方便;2、程序万一bug或被kill了数据就丢了。当然也可以周期性地写到文件中,但是还得自行处理好麻烦。于是就将该工作直接交给Redis了。Redis数据在内存中存储,但是也会根据配置文件的设置周期性地写入文件中。如果服务器挂了,已经写入的数据是不会丢失的。

注意,最好不要用MYSQL等数据库,在性能不高的软路由上进行I/O,性能真的不敢恭维。千万不要尝试将每个包都写入数据库中,否则几天后做一次集合查询就可能需要花费10余分钟。(当然,如果I/O好,CPU好,数据库做了优化除外。)

关于hiredis-devel、php-pecl-devel编程,请查阅文后的参考文献。

三、流量查询程序

为了便于流量查询,可以在web服务器中增加一个php页面。根据Key查询到某IP对应的流量,显示出来即可。为了更加直观,还可以在jpgraph库和gd库的支持下进行绘图。

QQ图片20141211153833.png

根据测试运行的结果,统计的流量与学校计费系统所计算的流量存在一定偏差,但是偏差不超过4.2%。分析原因可能有以下几方面。

1、免流量IP地址不全。目前免流量IP地址只统计了学校教育网的IP段,没有统计学校的其他IP段。但是,学校除了教育网的IP段外,还有一部分电信通和移动的IP段。由于后面这部分IP段较为琐碎,为了提高性能没有进行统计。此外,可能还有一部分未知的不计流量的IP段。

2、如果计费网关掉线,那么访问校外任何页面时会被重定向到10.10.43.3。但是重定向的页面显示来源IP依然是之前校外网站的IP,这部分流量将会被错误地记录下来。

3、其他未知情况。

目前,实验室内的各位被统计流量的小伙伴们纷纷表示情绪稳定。

参考文献

[1] Programming with pcap. http://www.tcpdump.org/pcap.html

[2] Packet Capture With libpcap and other Low Level Network Tricks. http://eecs.wsu.edu/~sshaikot/docs/lbpcap/libpcap-tutorial.pdf

[3] Hiredis Readme. https://github.com/redis/hiredis/blob/master/README.md

[4] PhpRedis Readme. https://github.com/nicolasff/phpredis/#readme

[5] 创建自定义自启动LINUX服务service. http://blog.csdn.net/q191201771/article/details/6134512

请登录后留言

LOGIN
FOLLOW ME
CATEGORIES
COPYRIGHT
Creative Commons License
除特殊声明的页面外,本站作品采用 知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议 进行许可。