我不知道該怎麼給自己的模塊命令,我的英文狠爛,老婆很忙又不肯幫我,又不能起一個中文名字,因此我只能使用XXX這種讓人遐想的名字,我不會使用aaa,abc這種,這樣會讓人覺得我不負責任,有點玩世不恭或者太草率等所有你能想到,並且,真實地,我也因為這種草率埃過領導的批評以及同道人的嘲諷。接受了教訓之後,我就使用XXX。
/* * "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); }
/* * xt_xxx - kernel module to drop and re-NEW CONNTRACK to * fit NAT * * Original author: Wangran <[email protected]> */ #include <linux/module.h> #include <linux/netfilter/x_tables.h> #include <net/netfilter/nf_queue.h> #include "compat_xtables.h" MODULE_AUTHOR("Wanagran <[email protected]>"); 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 int xxx_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