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
donestruct 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