struct result_node { uint32 network; uint32 netmask; void *action; };以上这个思想多亏了路由查找中的“最长前缀匹配”原则,该原则是隐式的,但是该原则保证了最精确的匹配。
/* * 以下结构体指示一个“路由节点”,它可以携带一个extra_data * 你可以任意定义它,比如可以如下定义: * struct my_extra { * char info[INFO_SIZE]; * int policy; // NF_ACCEPT,NF_DROP或者其它? * // .... extra of extra ?? * }; * 它带来了无限的扩展性,你可以使用这个“路由”节点存储任何数据。 */ struct nf_fib_node { struct hlist_node nf_fn_hash; u_int32_t fn_key; int len; // extra_len指示你传入的extra data的长度 int extra_len; // 0长度数组,你可以任意定义它 char extra[0]; };
i=1; # 添加巨量的iptables规则 for ((; i < 255; i++)); do j=1; for ((; j < 255; j++)); do iptables -A FORWARD -s 192.168.$i.$j -j DROP; done done
struct my_extra { // 替换iptables中的matches struct list_head matches_list; // 替换iptables的target int policy; // NF_ACCEPT,NF_DROP或者其它? };
static unsigned int ipv4_confirm(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { ... out: /* We‘ve seen it coming out the other side: confirm it */ ret = nf_conntrack_confirm(skb); if (ret == NF_ACCEPT) { #include "nf_conntrack_info.h" #define MAX_LEN 128 struct nf_conn_priv { struct nf_conn_counter ncc[IP_CT_DIR_MAX]; char *info; }; struct nf_conn_priv *ncp; struct nf_conn_counter *acct; acct = nf_conn_acct_find(ct); if (acct) { char buf[MAX_LEN] = {0}; int len = MAX_LEN; struct iphdr *iph = ip_hdr(skb); // 查询“路由表”,获取结果 int rv = nf_route_table_search(iph->saddr, buf, &len); if (!rv) { ncp = (struct nf_conn_priv *)acct; if (ncp->info == NULL) { ncp->info = (char *)kcalloc(1, len+1, GFP_ATOMIC); } // 拷贝获取的结果到conntrack memcpy(ncp->info, buf, len); } } } return ret; }
#include <linux/types.h> #include <linux/list.h> #define SIZE 128 struct nf_fn_zone { struct nf_fn_zone *fz_next; /* Next not empty zone */ struct hlist_head *fz_hash; /* Hash table pointer */ int fz_nent; /* Number of entries */ int fz_divisor; /* Hash divisor */ u32 fz_hashmask; /* (fz_divisor - 1) */ #define FZ_HASHMASK(fz) ((fz)->fz_hashmask) int fz_order; /* Zone order */ u_int32_t fz_mask; #define FZ_MASK(fz) ((fz)->fz_mask) }; struct nf_fn_hash { struct nf_fn_zone *nf_fn_zones[33]; struct nf_fn_zone *nf_fn_zone_list; }; /* * 以下结构体指示一个“路由节点”,它可以携带一个extra_data * 你可以任意定义它,比如可以如下定义: * struct my_extra { * char info[128]; * int policy; // NF_ACCEPT,NF_DROP或者其它? * // .... extra of extra ?? * }; * 它带来了无限的扩展性,你可以使用这个“路由”节点存储任何数据。 */ struct nf_fib_node { struct hlist_node nf_fn_hash; u_int32_t fn_key; int len; // extra_len指示你传入的extra data的长度 int extra_len; // 0长度数组,你可以任意定义它 char extra[0]; }; // 查找接口 int nf_route_table_search(const u_int32_t dst, void *res, int *res_len); // 添加接口 int nf_route_table_add( u_int32_t network, u_int32_t netmask, void *extra, int extra_len); // 节点删除接口 int nf_route_table_delete(u_int32_t network, u_int32_t mask); // 清除接口 void nf_route_table_clear(void);
#include <linux/types.h> #include <linux/inetdevice.h> #include <linux/slab.h> #include <linux/kernel.h> #include "nf_conntrack_info.h" #ifndef NULL #define NULL 0 #endif // 使用lock总是安全的。内核编程两要素:1.安全;2.高效 static DEFINE_RWLOCK(nf_hash_lock); struct nf_fn_hash *route_table = NULL; static inline u_int32_t nf_fz_key(u_int32_t dst, struct nf_fn_zone *fz) { return dst & FZ_MASK(fz); } static inline u32 nf_fn_hash(u_int32_t key, struct nf_fn_zone *fz) { u32 h = key>>(32 - fz->fz_order); h ^= (h>>20); h ^= (h>>10); h ^= (h>>5); h &= FZ_HASHMASK(fz); return h; } static struct hlist_head *fz_hash_alloc(int divisor) { unsigned long size = divisor * sizeof(struct hlist_head); return kcalloc(1, size, GFP_ATOMIC); } static struct nf_fn_zone * fn_new_zone(struct nf_fn_hash *table, int z) { int i; struct nf_fn_zone *fz = kcalloc(1, sizeof(struct nf_fn_zone), GFP_ATOMIC); if (!fz) return NULL; if (z) { fz->fz_divisor = 16; } else { fz->fz_divisor = 1; } fz->fz_hashmask = (fz->fz_divisor - 1); fz->fz_hash = fz_hash_alloc(fz->fz_divisor); if (!fz->fz_hash) { kfree(fz); return NULL; } fz->fz_order = z; fz->fz_mask = inet_make_mask(z); /* Find the first not empty zone with more specific mask */ for (i=z+1; i<=32; i++) if (table->nf_fn_zones[i]) break; write_lock_bh(&nf_hash_lock); if (i>32) { /* No more specific masks, we are the first. */ fz->fz_next = table->nf_fn_zone_list; table->nf_fn_zone_list = fz; } else { fz->fz_next = table->nf_fn_zones[i]->fz_next; table->nf_fn_zones[i]->fz_next = fz; } table->nf_fn_zones[z] = fz; write_unlock_bh(&nf_hash_lock); return fz; } // 路由表操作接口:1.查找;2.删除。参数过于多,类似Win32 API,风格不好,但使用方便 int nf_route_table_opt(const u_int32_t dst, const u_int32_t mask, int del_option, void *res, int *res_len) { int rv = 1; struct nf_fn_zone *fz; struct nf_fib_node *del_node = NULL; if (NULL == route_table) { printk(""); return 1; } read_lock(&nf_hash_lock); for (fz = route_table->nf_fn_zone_list; fz; fz = fz->fz_next) { struct hlist_head *head; struct hlist_node *node; struct nf_fib_node *f; u_int32_t k = nf_fz_key(dst, fz); head = &fz->fz_hash[nf_fn_hash(k, fz)]; hlist_for_each_entry(f, node, head, nf_fn_hash) { if (f->fn_key == k){ if ( 1 == del_option && mask == FZ_MASK(fz)){ del_node = f; } else if (0 == del_option){ // 将用户传入的extra数据拷贝给调用者。 memcpy(res, (const void *)(f->extra), f->extra_len); *res_len = f->extra_len; } rv=0; goto out; } } } rv = 1; out: read_lock(&nf_hash_lock); if (del_node) { write_lock_bh(&nf_hash_lock); __hlist_del(&del_node->nf_fn_hash); kfree(del_node); write_unlock_bh(&nf_hash_lock); } return rv; } static inline void fib_insert_node(struct nf_fn_zone *fz, struct nf_fib_node *f) { struct hlist_head *head = &fz->fz_hash[nf_fn_hash(f->fn_key, fz)]; hlist_add_head(&f->nf_fn_hash, head); } int nf_route_table_search(u_int32_t dst, void *res, int *res_len) { return nf_route_table_opt(dst, 32, 0, res, res_len); } int nf_route_table_delete(u_int32_t network, u_int32_t mask) { return nf_route_table_opt(network, mask, 1, NULL, NULL); } int nf_route_table_add(u_int32_t network, u_int32_t netmask, void *extra, int extra_len) { struct nf_fib_node *new_f; struct nf_fn_zone *fz; new_f = kcalloc(1, sizeof(struct nf_fib_node) + extra_len, GFP_ATOMIC); new_f->len = inet_mask_len(netmask); new_f->extra_len = extra_len; new_f->fn_key = network; memcpy(new_f->extra, extra, extra_len); if (new_f->len > 32) { return -1; } INIT_HLIST_NODE(&new_f->nf_fn_hash); if ( NULL == route_table){ route_table = kcalloc(1, sizeof(struct nf_fn_hash), GFP_ATOMIC); fz = fn_new_zone(route_table,new_f->len); } else { fz = route_table->nf_fn_zones[new_f->len]; } if (!fz && !(fz = fn_new_zone(route_table,new_f->len))) { return -1; } fib_insert_node(fz, new_f); return 0; } void nf_route_table_clear( void ) { struct nf_fn_zone *fz,*old; if (NULL == route_table) { printk(""); return; } write_lock_bh(&nf_hash_lock); for (fz = route_table->nf_fn_zone_list; fz; ) { if (fz != NULL){ kfree(fz->fz_hash); fz->fz_hash=NULL; old = fz; fz = fz->fz_next; kfree(old); old=NULL; } } kfree(route_table); route_table=NULL; write_unlock_bh(&nf_hash_lock); return; }
nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o nf_conntrack_info.o然后编译即可,出来的nf_conntrack_ipv4.ko就已经加入自己的扩展了。
Linux路由表的抽象扩展应用于nf_conntrack,布布扣,bubuko.com
原文:http://blog.csdn.net/dog250/article/details/24102455