针对网络流量的病毒

针对网络流量的病毒过滤,应该有很多方式,这里提出的是使用NetFilter_Queue这种方式。
 
[前提]
如果想使用这种方式应该满足以下前提:
1.         希望针对网卡接口,流入流出流向进行过滤
2.         需要针对协议和端口进行过滤
3.         希望仅扫描部分数据包数据,如数据报前100个字节
4.         病毒引擎是用户态的
5.         实现起来简单
6.         对于性能不苛求
 
[背景]
在linux-2.6.1*版本的内核中nfnetlink正式纳入了官方发布版本中,nfnetlink通过使用子系统nfnetlink_queue扩展了原来的ip_queue的功能。
 
nfnetlink_queue子系统可以通过设置iptables的 NFQUEUE选项将某些特定规则的网络流量放置到一个队列中,这些放置在队列中的数据包需要用户态的某个程序进行检查后才能放行,用户态程序通过 libnetfilter_queue库来对这个这个队列中的数据包进行操作,如设置NF_ACCEPT标志则放行这个数据包,如果设置了NF_DROP 则就就丢弃该数据包。病毒引擎在这里就作为一个仲裁者了。当然libnetfilter_queue库也可以对数据报进行修改转发, NF_REPEAT标志就发挥了作用。nfnetlink_queue子系统在理论上可以提供65536个队列,来提供65536个调用 libnetfilter_queue库的应用程序使用,也就是说每个应用程序来控制一个队列。
 
[实现]
1.         首先确保linux内核是否提供nfnetlink接口
当运行过使用libnetfilter_queue库的应用程序后,nfnetlink_queue模块会被导入。
可以通过lsmod | grep nfnetlink命令证实这一点
 
[root@localhost ~]# lsmod | grep nfnetlink
nfnetlink_queue         16001 0
nfnetlink               10713 2 nfnetlink_queue,ip_conntrack
 
2.编译libnfnetlink和libnetfilter_queue
注意libnetfilter_queue的编译方式:
LIBNFNETLINK_CFLAGS=-I/usr/local/include/libnfnetlink     LIBNFNETLINK_LIBS=/user/local/lib ./configure
make
make install
 
3.                       libnetfilter_queue库的使用
libnetfilter_queue库的使用还是比解简单的。
libnetfilter_queue-0.0.13/utils/nfqnl_test.c 就是很好的例子
 
当然习惯使用KDevelop,需要设置如下:
-I/usr/local/include
-L/usr/local/lib -lnetfilter_queue -lnfnetlink
 
函数调用次序:
nfq_open 打开库
 
nfq_unbind_pf 解除nf_queue绑定
 
nfq_bind_pf    绑定nf_queue
 
nfq_create_queue 选择处理队列号和设置处理函数
参数2 队列号
参数3 处理函数指针
         
 
nfq_set_mode 设置netlink处理方式
设置NFQNL_COPY_PACKET参数表示返回数据包
 
nfq_nfnlh,nfnl_fd 结构转换
 
recv 此处循环,将接收的队列数据报,调用nfq_handle_packet来处理接收到的数据,nfq_handle_packet再会调用 nfq_create_queue时设置的处理函数处理数据包,这里可以通过设置recv接收缓冲区的大小,来实现扫描部分数据包的目的(第三个参数)
 
nfq_destroy_queue 关闭队列处理
 
nfq_close 关闭库
 
 
对于队列数据包放行与否的判断,都在nfq_create_queue 的处理函数中实现
这个处理函数的原型为
    typedef int nfq_callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
         struct nfq_data *nfad, void *data);
 
处理函数中重要的函数调用
nfq_get_payload      获取数据包负载,病毒扫描时这就是需要传入的缓存区
nfq_get_msg_packet_hdr              获取包头,这里可以判断数据包的协议
nfq_get_indev         获取数据包的流入设备
(可以在iptables设置时就进行设置,也就不需要判断了)
nfq_get_outdev       获取数据包的流出设备(同上)
nfq_set_verdict       最重要的函数华丽的登场了
                            根据病毒扫描的结果,来设置数据包的生杀大权
                            NF_ACCEPT 放行
                            NF_DROP      丢弃
 
[测试]
 
createchian.sh脚本的作用
将所有流出的tcp协议(-p tcp)进行队列( -j NFQUEU),设置队列号为0(--queue-num 0, 默认就是0)。Netfilter的层次设在最初的mangle这层。
 
# createchian.sh
#! /bin/sh
 
iptables -t mangle -N NF_QUEUE_CHAIN
iptables -t mangle -A NF_QUEUE_CHAIN -m mark --mark 0 -p tcp -j NFQUEUE --queue-num 0
iptables -t mangle -A NF_QUEUE_CHAIN -j MARK --set-mark 0
iptables -t mangle -I OUTPUT -j NF_QUEUE_CHAIN
 
 
运行createchian.sh脚本,启动病毒过滤程序(上面那个程序,我并没有实现病毒检查,虽然身边有个商用病毒引擎的SDK)进行病毒过滤。
 
停止病毒过滤程序,执行removechain.sh脚本删除iptables的队列策略
 
# removechain.sh
#! /bin/sh
 
iptables -t mangle -D PREROUTING -j NF_QUEUE_CHAIN
iptables -t mangle -D OUTPUT -j NF_QUEUE_CHAIN
iptables -t mangle -F NF_QUEUE_CHAIN
iptables -t mangle -X NF_QUEUE_CHAIN
 
 
 
[弱点]
 
性能应该是这种方式最大的问题
数据包队列和用户态病毒扫描处理发生的延时
数据包通过netlink的传送应该会发生数据拷贝(这一点未确认)
 
解决这些问题的方法:
1.         尽可以将需要过滤的数据报进行筛选,比如仅针对流入数据,TCP协议,开发服务的端口。
2.         扫描部分的数据包
3.         使用多个队列对数据包进行判定,当然这可能要求病毒引擎是可重入的(这个应该不会有什么问题)
4.         不使用这种方式,采用硬件过滤的方式。
 
 
当然网络流量的病毒过滤本身就有很多问题
1.         对于性能的影响
2.         误报率比较高
 
[参考]
libnetfilter_queue man     Brad Fisher
用netfilter_queue 在用户态修改网络数据包的例子程序 hellwolf
从ip_queue到nfnetlink_queue(上) 独孤阁
从ip_queue到nfnetlink_queue(下) 独孤阁
nfnetlink的子系统 独孤阁

nfnetlinkip_queue 独孤阁 

[后记]

强烈建议不要使用这种方式,snort_inline就是使用QUEUE这种方式,经测试snort_inline根本撑不住大流量,在ThreadEx测试下,造成netlink数据溢出,前台程序根本来不及处理队列数据。估计10M流量就是极限了。

你可能感兴趣的:(Shell编程)