新的流量控制框架tctable

1780阅读 0评论2010-05-26 qtdszws
分类:LINUX

1.引言

上一篇文章中演示如何在conntrak中增加包数和字节数的简单统计功能。如果想实现比较完善的统计功能,比如区分内网数据包流动的两个方向(接收和发送)来单独统计,在此基础上增加流量控制,限制某个内网ip的连接数,包速和字节速,能够在客户端控制网关的流量控制功能,查看某个ip的统计信息以及属于该ip连接的更详细信息,并能增加,修改,删除流量控制规则,甚至增加验证上网功能等等,则显然不能使用前面的方法,因为这样会对原有代码修改很大,可能会引入错误,没有扩展性,结构不清晰。需要重新设计一套框架,姑且叫做tc table,

2.应用环境

外网<----->[eth0 linux网关  eth1]<----------->内网

linux 网关启用nat

3.为何不使用链路层tc

linux链路层tc功能已经很好很强大,但是不能满足该应用环境和应用需求。

4.框架

tc table显然需要依赖于netfilter框架.依赖于conntrack和nat,为了简化只考虑ipv4.
在v2.4.0的内核中,netfilter框架如下






现在考虑一下可能的钩子注册点,比较合理的有三个地方,forward,local in,local out.
因为在prerouting和postrouting处很难搞清数据的流向,是从内到外还是从外到内,从外到本机还是本机到外,本机到本机等等?经过rout后,数据的方向基本确定。在forward处控制内外之间的流量,在local in和local out处控制本机收发流量。

5.钩子优先级
钩子的优先级决定了钩子在处理数据的先后顺序。

在forward中,tctable钩子安排在filter.forward后
在local in中,tctable钩子安排在filter.input后
在local out中,tctable钩子安排在filter.output后

这样做好的好处是数据包有可能被filter过滤,这样的数据包就不需要被tctable处理.

filter的三个钩子优先级都是NF_IP_PRI_FILTER=0,因此可以定义tctable的钩子优先级为NF_IP_PRI_FILTER+10

6.基本代码框架
套用iptable_filter.c的代码,形成如下的最简单的框架
tctable_filter.c

#include
#include
#include
#include

static void dump(const char * msg, struct iphdr * iph)
{
        printk("%s:%u.%u.%u.%u->%u.%u.%u.%u %u\n",
               msg,
               NIPQUAD(iph->saddr),
               NIPQUAD(iph->daddr),
               iph->protocol
               );
}

static unsigned int
tct_forward_hook(unsigned int hook,
     struct sk_buff **pskb,
     const struct net_device *in,
     const struct net_device *out,
     int (*okfn)(struct sk_buff *))
{
    dump("tct_forward_hook",(*pskb)->nh.iph);   
    return NF_ACCEPT;
}

static unsigned int
tct_local_in_hook(unsigned int hook,
     struct sk_buff **pskb,
     const struct net_device *in,
     const struct net_device *out,
     int (*okfn)(struct sk_buff *))
{
   
    dump("tct_local_in_hook",(*pskb)->nh.iph);   
    return NF_ACCEPT;
}

static unsigned int
tct_local_out_hook(unsigned int hook,
           struct sk_buff **pskb,
           const struct net_device *in,
           const struct net_device *out,
           int (*okfn)(struct sk_buff *))
{
    /* root is playing with raw sockets. */
    if ((*pskb)->len < sizeof(struct iphdr)
        || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
        if (net_ratelimit())
            printk("ipt_hook: happy cracking.\n");
        return NF_ACCEPT;
    }

    dump("tct_local_out_hook",(*pskb)->nh.iph);   
    return NF_ACCEPT;
}

static struct nf_hook_ops tct_ops[]
= { { { NULL, NULL }, tct_local_in_hook, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_FILTER+10 },
    { { NULL, NULL }, tct_forward_hook, PF_INET, NF_IP_FORWARD, NF_IP_PRI_FILTER+10 },
    { { NULL, NULL }, tct_local_out_hook, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_FILTER+10 }
};

static int __init init(void)
{
    int ret;

    /* Register hooks */
    ret = nf_register_hook(&tct_ops[0]);
    if (ret < 0)
        return ret;

    ret = nf_register_hook(&tct_ops[1]);
    if (ret < 0)
        goto cleanup_hook0;

    ret = nf_register_hook(&tct_ops[2]);
    if (ret < 0)
        goto cleanup_hook1;

    return ret;

 cleanup_hook1:
    nf_unregister_hook(&tct_ops[1]);
 cleanup_hook0:
    nf_unregister_hook(&tct_ops[0]);

    return ret;
}

static void __exit fini(void)
{
    unsigned int i;

    for (i = 0; i < sizeof(tct_ops)/sizeof(struct nf_hook_ops); i++)
        nf_unregister_hook(&tct_ops[i]);
}

module_init(init);
module_exit(fini);

7.编译,测试
在net/ipv4/netfilter/Makefile中,增加一行

obj-m += tctable_filter.o

然后make modules
make modules_install

tctable_filter是一个模块,不需要make这么复杂,在第一次make时,截取编译命令
 gcc -D__KERNEL__ -I/usr/src/linux-2.4.7-10/include -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -Wno-unused -pipe -mpreferred-stack-boundary=2 -march=i686 -DMODULE -DMODVERSIONS -include /usr/src/linux-2.4.7-10/include/linux/modversions.h   -c -o tctable_filter.o tctable_filter.c

以后有修改用这个编译就行了

然后手工执行
cp tctable_filter.o /lib/modules/2.4.7-10custom/kernel/net/ipv4/netfilter/

最后insmod tctable_filter

dmseg看看可有输出。

tct_local_out_hook:10.1.9.30->10.1.9.45 6
tct_local_in_hook:10.1.9.45->10.1.9.30 6
tct_local_out_hook:10.1.9.30->10.1.9.45 6
tct_local_in_hook:10.1.9.45->10.1.9.30 6
tct_local_out_hook:10.1.9.30->10.1.9.45 6
tct_local_in_hook:10.1.9.45->10.1.9.30 6
tct_local_out_hook:10.1.9.30->10.1.9.45 6


上一篇:在conntrack中增加包数和字节数统计
下一篇:在新框架下实现conntrack中增加包数和字节数统计