2018年(21)
分类: LINUX
2018-09-19 15:47:52
第一节我们已经大概的分析了一下在Netfilter 中对规则(rule)的组织结构,这里我们来看一下具体实现。
table->chain->rule(match:target)
从上图所示,在内核空间,每个CPU上维护了一份rule的拷贝。这样做是为了减少锁的使用及增加硬件L1 cache的命中次数,以空间换时间
include/linux/netfilter/x_table.h
struct xt_table
{
struct list_head list;
unsigned int valid_hooks; /*该表中有效的hook点位图*/
struct xt_table_info *private; //指向真正存储rule的结构体
struct module *me;
u_int8_t af; /* address/protocol family */
const char name[XT_TABLE_MAXNAMELEN];//表名字
};
struct xt_table_info
{
unsigned int size; //表的大小
unsigned int number; //表中存的rule个数
unsigned int initial_entries;//初始化表时创建的默认rule个数
unsigned int hook_entry[NF_INET_NUMHOOKS];
unsigned int underflow[NF_INET_NUMHOOKS];
void *entries[1];
};
表的注册:
每个网络命名空间管理自己Netfilter中创建的table。并把这些表链接到相应的协议族链表里。
这样就可以通过用户空间传下来的表名查找到相应的表了。
struct net
{
struct netns_xt xt;
}
struct netns_xt
{
struct list_head tables[NFPROTO_NUMPROTO];
#if defined(CONFIG_BRIDGE_NF_EBTABLES) || \
defined(CONFIG_BRIDGE_NF_EBTABLES_MODULE)
struct ebt_table *broute_table;
struct ebt_table *frame_filter;
struct ebt_table *frame_nat;
#endif
};
struct xt_table *xt_register_table(struct net *net,
const struct xt_table *input_table,
struct xt_table_info *bootstrap,
struct xt_table_info *newinfo)
{
int ret;
struct xt_table_info *private;
struct xt_table *t, *table;
/*申请x_table内存*/
table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL);
if (!table) {
ret = -ENOMEM;
goto out;
}
ret = mutex_lock_interruptible(&xt[table->af].mutex);
if (ret != 0)
goto out_free;
/* 在命名空间里查找是否有相同名字的表 */
list_for_each_entry(t, &net->xt.tables[table->af], list) {
if (strcmp(t->name, table->name) == 0) {
ret = -EEXIST;
goto unlock;
}
}
/* 初始化table_private*/
table->private = bootstrap;
if (!xt_replace_table(table, 0, newinfo, &ret))
goto unlock;
private = table->private;
/* save number of initial entries */
private->initial_entries = private->number;
//把表挂到对应网络命名空间管理的链表上
list_add(&table->list, &net->xt.tables[table->af]);
mutex_unlock(&xt[table->af].mutex);
return table;
mutex_unlock(&xt[table->af].mutex);
out_free:
kfree(table);
out:
return ERR_PTR(ret);
}
不同的协议族定义的rule不同。为了通用,netfilter把各个协议族的一些共性的数据结构提取出来单独定义,各个协议族再自己定义自己独有的数据结构,并包含netfilter提供的通用数据结构。
我们以IPv4为例来看一下,通过用户空间的iptables所配置到内核中的每条rule是怎么存储的。
如图,ip_entry 是标准的匹配规则,ipt_entry_match是扩展的匹配规则,是可选项。每个rule最后带一个target。Traget有系统自带的,也有扩展的。
1、标准的匹配规则
struct ipt_entry
{
struct ipt_ip ip; //五元组,ipv4报文通用的匹配元素
/* Mark with fields that we care about. */
unsigned int nfcache;
/*详见上图,rule首地址到target的偏移量*/
/* Size of ipt_entry + matches */
u_int16_t target_offset;
/* Size of ipt_entry + matches + target */
u_int16_t next_offset;
/* Back pointer */
unsigned int comefrom;
/* Packet and byte counters. */
struct xt_counters counters;
/* The matches (if any), then the target. */
unsigned char elems[0];
};
ipv4报文通用的匹配元素,源/目的ip地址/掩码,源/目的接口名/接口名掩码,传输层协议类型
struct ipt_ip
{
/* Source and destination IP addr */
struct in_addr src, dst;
/* Mask for src and dest IP addr */
struct in_addr smsk, dmsk;
char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
/* Protocol, 0 = ANY */
u_int16_t proto;
/* Flags word */
u_int8_t flags;
/* Inverse flags */
u_int8_t invflags;
};
1、大蓝图
2、table(表)
//各个hook(chain)在表中的偏移量
//各个hook(chain)中默认规则在表中的偏移量
//数组,存储各个cpu上自己rule拷贝的内存首地址
unlock:
3、rule在内核中的定义和存储
/*下一条rule的偏移量*/
/*命中报文的统计计数*/
//位图,每一位代表以上匹配元素配置时是否是带!符号(取反)
(未完待续)