Linux-2.6.32内核编译流量计数器nfacct

把Linux- 3.17的功能移植到Linux-0.01上!

我的时间为我掌控,这是我最大的财富!早上9点多到公司,一直到下班,这段时间有偿的坐班,我不会估计自己的事情,下班到家直到家人睡去,这段 时间有偿的 坐班,我不会顾及自己的事情,之后就是急促的喘息的夜,我的愿望刻在上帝的喉咙,希望通过推翻身边的拿人性做抵押的否认之墙,来从容面对恐惧(这是形容死 亡金属的)!

好了!受虐自是开端!且看且珍惜:

Netfilter早在xtables-addons-1.46(更早的版本我没有亲自试验,因此不便述说)中就内置了一个ACCOUNT模块,用来在iptables的框架内支持流量计数,它的用法如下:

iptables -A XXX (any matches) -j ACCOUNT  --addr 0.0.0.0/0  --tname $acctname

作用是凡是匹配any matches的流量均计入acctname这个计数器。可以通过:

iptaccount -l $acctname

来 显示流量信息。但是它有一个缺点,那就是ACCOUNT作为iptables的一个target存在,这就是说流量统计之外,一条iptables规则不 能再做别的了。有时候,你总是希望流量计数是作为一个“额外”的动作而存在,比如在DROP的同时记录一下,或者在NAT的同时记录一下等。将流量计数作 为match会更好,因为match可以有多个!另外,ipset-6.23也支持流量计数,但是本文不谈那个。本文谈的是nfacct。

nfacct是Netfilter的一个项目。我不得不再次怒发冲冠!Netfilter上的凄凉项目不少,nfacct真不算凄凉,但是起码 它在 Linux 2.6.32上是不能用的,事实上,由于nfacct项目根本就没有内置kernel模块,也就是说,Netfilter如今只负责用户态的模块,至于 kernel那部分,只好等Linux kernel的trunk树给与支持了,而我查了资料后,发现在3.3以及之后的版本才给了nfacct内核态的支持。至于nfacct用户态的代码,例 行的configure/make install就可以直接编译通过并安装,给人一种它已经可用的假象,但是当你使用nfacct add test的时候,便会报错:错误的参数!

2.6.32根本就没有nfacct内核部分的支持,所以netlink报错。接下来的事就是移植3.3版本的nfnetlink_acct内 核模块到 2.6.32版本内核了。我选择3.3版本是因为它是离2.6.32版本最近的支持nfacct的内核,虽然内核API可能发生变化,但是起码移植工作量 可以最小化。

在开工之前,我给出我编译环境的目录树结构:

|-- iptables-1.4.21.tar.bz2

|-- kernel

|  |-- net

|  |  `-- netfilter

|  |      |-- Makefile

|  |      |-- nfnetlink_acct.c

|  |      |-- nfnetlinkacct.h

|  |      |-- nfnetlink.c

|  |      |-- nfnetlink.h

|  |      |-- xt_nfacct.c

|  |      `-- xt_nfacct.h

|  `-- README

|-- libnetfilter_acct-1.0.2.tar.bz2

`-- nfacct-1.0.1.tar.bz2

iptables- 1.4.21.tar.bz2是目前最新的iptables版本,2.6.32直接可以编译安装,nfacct-1.0.1.tar.bz2是 nfacct的用户态部分,依赖libnetfilter_acct-1.0.2.tar.bz2,这两者均可以成功编译安装,剩下的就是内核态的工作 了,置于我新建的kernel目录,其中的文件来自Linux 3.3内核:

nfnetlink_acct.c:cp $3.3/net/netfilter/nfnetlink_acct.c net/netfilter/nfnetlink_acct.c

此文件需要修改的地方有:

1.将include文件nfnetlink.h绝对路径改为相对路径,即本目录。

2.将include文件nfnetlink_acct.h绝对路径改为相对路径,即本目录的nfnetlinkacct.h

3.将kfree_rcu改为kfree,或者重新定义kfree_rcu

nfnetlinkacct.h:cp $3.3/include/linux/netfilter/nfnetlink_acct.h net/netfilter/nfnetlinkacct.h

nfnetlink.c:cp /lib/modules/`uname -r`/build/net/netfilter/nfnetlink.c net/netfilter/nfnetlink.c

此文件需要修改的地方有:

1.将include文件nfnetlink.h绝对路径改为相对路径,即本目录。

nfnetlink.h:cp /lib/modules/`uname -r`/build/include/linux/netfilter/nfnetlink.h net/netfilter/nfnetlink.h

此文件需要修改的地方有:

1.定义新的netlink子系统:

#define NFNL_SUBSYS_IPSET              6

#define NFNL_SUBSYS_ACCT                7

#define NFNL_SUBSYS_COUNT              8

注意,移植此文件到当前编译目录的目的是为了不影响系统头文件,要知道,由于nfnetlink模块要重新编译,我将nfnetlink也移了过来,它们都是2.6.32内核的文件。

xt_nfacct.c:cp $3.3/net/netfilter/xt_nfacct.c net/netfilter/xt_nfacct.c

此文件需要修改的地方有:

1.定义xt_action_param:

#define xt_action_param xt_match_param

这是因为2.6.32中match和target在接口上是分开的,不像3.X内核上将其作为union封装进xt_action_param结构体。2.改变checkentry的返回值:

/* 万分注意!从3.x移植过来的checkentry的返回值是int,0为成功,非0为失败,

* 然则2.6.32的对应返回值是bool,0为失败,非0为成功。

* 完全相反的API规范,弄反了就panic吧 :(

**/

static int

nfacct_mt_checkentry(const struct xt_mtchk_param *par)

{

struct xt_nfacct_match_info *info = par->matchinfo;

struct nf_acct *nfacct;

nfacct = nfnl_acct_find_get(info->name);

if (nfacct == NULL) {

pr_info("xt_nfacct: accounting object with name `%s‘ "

"does not exists\n", info->name);

return 0;

}

info->nfacct = nfacct;

return 1;

}

xt_nfacct.h:cp $3.3/include/linux/netfilter/xt_nfacct.h net/netfilter/xt_nfacct.h

至此,移植空间完成,Makefile的内容为:

obj-m  += nfnetlink_acct.o

obj-m  += nfnetlink.o

obj-m  += xt_nfacct.o

进入net/netfilter目录,通过下面的命令编译:

make -C /lib/modules/`uname -r`/build SUBDIRS=`pwd` modules

然后依次加载nfnetlink.ko,nfnetlink_acct.ko,xt_acct.ko如此,再次执行nfacct命令试一下吧:

nfacct add testiptables -A INPUT -s 192.168.0.0/24 -m nfacct --nfacct-name test -j ACCEPT

停顿片刻,保持网络传输,查看流量计数器:

nfacct get test{ pkts = 00000000000000188016, bytes = 00000000000250825515 } = aa;

OK了!当然,你也可以将结果保存为xml文件的格式,在必要时也可以reset计数器的数值为0。

Ubuntu13.10 (Saucy Salamander) 内核已升级至 Linux Kernel 3.10 RC5
 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。