知识屋:更实用的电脑技术知识网站
所在位置:首页 > 操作系统 > linux

终于搞定Linux的NAT即时生效问题

发布时间:2014-09-05 13:31:36作者:知识屋

引:超长的前言

Linux的NAT不能及时生效,因为它是基于ip_conntrack的,如果在NAT的iptables规则添加之前,此流的数据包已经绑定了一个ip_conntrack,那么该NAT规则就不会生效,直到此ip_conntrack过期,如果一直有数据在鲁莽地尝试传输,那么就会陷入僵持状态。
说明:命名与思路

我不知道该怎么给自己的模块命令,我的英文狠烂,老婆很忙又不肯帮我,又不能起一个中文名字,因此我只能使用XXX这种让人遐想的名字,我不会使用aaa,abc这种,这样会让人觉得我不负责任,有点玩世不恭或者太草率等所有你能想到,并且,真实地,我也因为这种草率埃过领导的批评以及同道人的嘲讽。接受了教训之后,我就使用XXX。

第一部分:iptables模块文件libxt_XXX.c

/* *      "XXX" target extension for iptables! 其中就是一个幌子,为了使用iptables而已! * *      This program is free software; you can redistribute it and/or *      modify it under the terms of the GNU General Public License; either *      version 2 of the License, or any later version, as published by the *      Free Software Foundation. */#include <stdio.h>#include <xtables.h>#include "compat_user.h"static void xxx_tg_help(void){        printf("XXX takes no options/n/n");}static int xxx_tg_parse(int c, char **argv, int invert, unsigned int *flags,                         const void *entry, struct xt_entry_target **target){        return 0;}static void xxx_tg_check(unsigned int flags){}static struct xtables_target xxx_tg_reg = {        .version       = XTABLES_VERSION,        .name          = "XXX",        .revision      = 1,        .family     = NFPROTO_IPV4,        .help          = xxx_tg_help,        .parse         = xxx_tg_parse,};static __attribute__((constructor)) void xxx_tg_ldr(void){        xtables_register_target(&xxx_tg_reg);}

iptables -t mangle -A PREROUTING ... -j XXX
第二部分:内核模块xt_XXX.c
/* *      xt_xxx - kernel module to drop and re-NEW CONNTRACK to *              fit NAT * *      Original author: Wangran <marywangran@126.com> */#include <linux/module.h>#include <linux/netfilter/x_tables.h>#include <net/netfilter/nf_queue.h>#include "compat_xtables.h"MODULE_AUTHOR("Wanagran <marywangran@126.com>");MODULE_DESCRIPTION("Xtables: xxx match module");MODULE_LICENSE("GPL");MODULE_ALIAS("ipt_xxx");/* * queue handler捕获数据包,然后重新注入,区别在于: * 1:如果本身是NOTRACK的数据包,直接注回去; * 2:如果本身没有绑定任何conntrack,直接注回去; * 3:如果本身有conntrack,删掉该conntrack后,注回去 * 3.1.不是注回原来的位置,而是注回PREROUTING最开始的位置。 * 注意:虽然TAGEGET本身已经阻止了1,2的情况,还是判断了一下, *       因为虽然我知道这一点,但是resetct_queue并不清楚... */static int resetct_queue(struct nf_queue_entry *entry, unsigned queue_num){        struct sk_buff *skb = entry->skb;        struct nf_conn *ct = NULL;        enum ip_conntrack_info ctinfo;        if (nf_ct_is_untracked(skb))                goto reinject;        else if (!(ct = nf_ct_get(skb, &ctinfo)))                goto reinject;        else {                // 为了重新初始化conntrack,使之状态变为可做NAT的NEW!                struct list_head *elem = &nf_hooks[entry->pf][entry->hook];                nf_reset(skb);                nf_ct_kill(ct);                entry->elem = list_entry(elem, struct nf_hook_ops, list);        }reinject:        nf_reinject(entry, NF_ACCEPT);        return 0;}/* * XXX的执行TARGET,旨在针对以下的一类数据包进行queue处理: * 本身是NEW状态,且已经被confirm了,这种数据包在其conntrack * 过期之前,无疑已经不会再去匹配任何NAT规则了! */static unsigned intxxx_tg4(struct sk_buff **skb, const struct xt_action_param *par){        struct nf_conn *ct;        enum ip_conntrack_info ctinfo;        ct = nf_ct_get(*skb, &ctinfo);        if (!ct || ct == &nf_conntrack_untracked) {                return XT_CONTINUE;        }        // 仅仅处理正向数据包,否则...        if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {                return XT_CONTINUE;        }        if (ctinfo == IP_CT_NEW && !nf_ct_is_confirmed(ct)) {                return XT_CONTINUE;        }        return NF_QUEUE;}static struct nf_queue_handler xxxqh = {        .name  = "resetct",        .outfn = resetct_queue,};static struct xt_target xxx_tg_reg[] __read_mostly = {        {                .name           = "XXX",                .revision       = 1,                .family         = NFPROTO_IPV4,                .table          = "mangle",                .hooks          = 1 << NF_INET_PRE_ROUTING,                .target         = xxx_tg4,                .me             = THIS_MODULE,        },};static int __init xt_xxx_target_init(void){        int status = 0;        status = nf_register_queue_handler(NFPROTO_IPV4, &xxxqh);        if (status < 0) {                printk("XXX: register queue handler error/n");                goto err;        }        status = xt_register_targets(xxx_tg_reg, ARRAY_SIZE(xxx_tg_reg));        if (status < 0) {                printk("XXX: register target error/n");                goto err;        }err:        return status;}static void __exit xt_xxx_target_exit(void){        nf_unregister_queue_handlers(&xxxqh);        return xt_unregister_targets(xxx_tg_reg, ARRAY_SIZE(xxx_tg_reg));}module_init(xt_xxx_target_init);module_exit(xt_xxx_target_exit);

第三部分:关于使用

一般而言,你可以使用下面的命令:

iptables -t mangle -A PREROUTING -j XXX

这样的话,所有进来的数据包都会执行下面的逻辑:

 


/

如果这样,相当于架空了整个ip_conntrack的优化,这种鲁莽的做法并不是我的目的,我希望它和其它的match比如mark,condition一起使用,这样就可以把不相关的数据包过滤掉而不触及,依旧执行往常的逻辑,这就是我为何一直坚持使用iptables的原因而不是使用其它的用户态/内核态通信的方式。就想之前我提到的基于ip_conntrack的快速/慢速匹配方式那样,这个NAT及时匹配也可以使用类似的逻辑:

iptables -t mangle -A PREROUTING -m condition --condition slow ... -j XXX
(免责声明:文章内容如涉及作品内容、版权和其它问题,请及时与我们联系,我们将在第一时间删除内容,文章内容仅供参考)
收藏
  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜