enum nf_ct_ext_id { NF_CT_EXT_HELPER, NF_CT_EXT_NAT, NF_CT_EXT_ACCT, NF_CT_EXT_ECACHE, NF_CT_EXT_NUM, };
第二:
Linux为何把extend写的那么死呢?当我突然感到这是合理的时候,我就三缄其口了,后面我会说到,数据结构需要可以自解释,即自己解释自己。虽然人可以看到一个结构体马上说出它的含义,但是程序却很难将一堆数据对应到一个结构体!自解释,如果不知道自解释,那就说明你根本就TM就不懂计算机!虽然你可能很精通编程...
struct nf_conn_counter { u_int64_t packets; u_int64_t bytes; };我希望它成为下面的样子:
struct nf_conn_counter { u_int64_t packets; u_int64_t bytes; unsigned char *info; };但是我又不能改变结构体的定义,所以我采用下面等价的办法:
struct conn_info_extends_nf_conn_counter { struct nf_conn_counter base; char *info; }info是最关键的。我需要做的仅仅就是在为nf_conn_counter分配空间的时候为其多加一个指针的空间即可,至于这个指针指向什么,自有调用者解释。在我的需求中,它可能就是一个字符串,存在info信息。acct_extend原始定义为(之所以选择对acct开刀,是因为它足够简单,在字面上里面,其表示统计信息,加入一个info也无可厚非):
static struct nf_ct_ext_type acct_extend __read_mostly = { .len = sizeof(struct nf_conn_counter[IP_CT_DIR_MAX]), .align = __alignof__(struct nf_conn_counter[IP_CT_DIR_MAX]), .id = NF_CT_EXT_ACCT, };
struct info_compat { struct nf_conn_counter nc[IP_CT_DIR_MAX]; unsigned char * info; }; static struct nf_ct_ext_type acct_extend __read_mostly = { .len = sizeof(struct info_compat), .align = __alignof__(struct info_compat), .id = NF_CT_EXT_ACCT, };
#include <linux/ip.h> #include <linux/module.h> #include <linux/skbuff.h> #include <linux/version.h> #include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack_acct.h> MODULE_AUTHOR("xtt"); MODULE_DESCRIPTION("gll"); MODULE_LICENSE("GPL"); MODULE_ALIAS("XTT and GLL"); struct nf_info { struct nf_conn_counter nc[IP_CT_DIR_MAX]; char *info; }; static unsigned int ipv4_conntrack_info (unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { u32 addr = ip_hdr(skb)->daddr; // 测试我家的路由器的地址192.168.1.1 if (addr == 0x0101a8c0) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; struct nf_conn_counter *acct; struct nf_info *info; unsigned char *cn = NULL; ct = nf_ct_get(skb, &ctinfo); if (!ct || ct == &nf_conntrack_untracked) return NF_ACCEPT; acct = nf_conn_acct_find(ct); if (acct) { info = (struct nf_info *)acct; info->info = (unsigned char*) kzalloc(32, GFP_ATOMIC); if (!info->info) { return NF_ACCEPT; } // 测试将1234567890作为字符串设置到conntrack memcpy(info->info, "1234567890", min(32, strlen("1234567890"))); } } return NF_ACCEPT; } static struct nf_hook_ops ipv4_conn_info __read_mostly = { .hook = ipv4_conntrack_info, .owner = THIS_MODULE, .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_CONNTRACK + 1, }; static int __init test_info_init(void) { int err; err = nf_register_hook(&ipv4_conn_info); if (err) { return err; } return err; } static void __exit test_info_exit(void) { nf_unregister_hook(&ipv4_conn_info); } module_init(test_info_init); module_exit(test_info_exit);
if (seq_printf(s, "use=%u ", atomic_read(&ct->ct_general.use))) goto release; { struct nf_info { struct nf_conn_counter acct[2]; char *info; }; struct nf_conn_counter *acct; struct nf_info *info; acct = nf_conn_acct_find(ct); if (acct) { info = (struct nf_info *)acct; if (info->info) { if (seq_printf(s, "info=%s\n", info->info)) { goto release; } } } }