在使用iptables过程中,经常会提到table、rule、match和target,这些在内核都有对应的数据结构(rule并没有对应结构体),在理解内核的逻辑代码之前,非常有必要先熟悉这些数据结构,以及内核到底是如何组织它们的。
这篇笔记记录了内核对这些对象的定义,下一篇笔记记录了内核是如何管理这些数据结构的。这篇笔记涉及的核心文件有:
代码路径 | 说明 |
---|---|
/net/netfilter/x_tables.h | netfilter框架对table、match、target的定义 |
1. struct xt_table
这是框架对table的定义:
struct xt_table
{
struct list_head list;
//table名字,如"filter", "nat"
const char name[XT_TABLE_MAXNAMELEN];
//按bit使用,表示该table保存了哪些HOOK点的规则
unsigned int valid_hooks;
//这把锁保护的是table中private指针指向内容
rwlock_t lock;
//实际上指向的是struct xt_table_info对象,其定义见下方
void *private;
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me;
//该table属于哪个协议族
int af; /* address/protocol family */
};
可见,struct xt_table仅仅是对table的基本描述,并没有保存table中的规则,更多的table内容都在其private成员中,该成员指向的结构是struct xt_talble_info对象,其定义如下。
1.1 struct xt_table_info
struct xt_table_info
{
//table中所有规则占用的内存大小
unsigned int size;
//table中当前保存的规则数目
unsigned int number;
//初始注册时,table中规则的数量
/* Initial number of entries. Needed for module usage count */
unsigned int initial_entries;
//每个table可以保存多个HOOK点的规则(由table的valid_hook决定),
//从某个HOOK点进入后,检查规则时应该只检查该HOOK点上的规则,因此
//为了给table中的规则按照HOOK点定界,有了下面两个成员:
//hook_entry[]记录了各个HOOK点第一条规则距离entries的偏移;
//underflow[]记录了各个HOOK点最后一条规则距离entries的偏移
unsigned int hook_entry[NF_INET_NUMHOOKS];
unsigned int underflow[NF_INET_NUMHOOKS];
//table中的规则实际上是每个CPU都有一份拷贝,这是为了避免多CPU之间的互斥操作,
//所以实际分配时entries是按照CPU个数分配的。比如有两个CPU,那么就分配2个char指针
//的空间,分别用CPU ID进行索引
char *entries[1];
};
//下面这个辅助宏用于计算struct xt_table_info对象的内存大小,
//注意已经根据CPU个数调整entries的大小
#define XT_TABLE_INFO_SZ (offsetof(struct xt_table_info, entries) \
+ nr_cpu_ids * sizeof(char *))
如上图,rule1~ruleN为table中第一个HOOK点上所有的规则,那么hook_entries[0]就指向rule1(实际上是偏移量而不是指针),underflow[0]指向的就是ruleN,类似的,hook_entries[1]和underflow[1]分别指向ruleN+1和ruleM。更详细的信息见下一篇笔记中对table的分配函数的分析。
下面先来看match和target,再来看规则rule,因为规则是由match和target拼成的。
2. match
match即匹配,看match的数据结构要分两个角度来看:一是match本身,二是构成规则时,match又是如何表示的,下面先看match本身,再看规则中的match。
PS:要注意的是,下面介绍的match都是扩展match,标准match的结构见下面的rule介绍。
2.1 struct xt_match
在内核中,match都是以模块的形式存在的,内核用struct xt_match来表示一种支持的match。
struct xt_match
{
struct list_head list;
//每个match都有一个唯一的名字
const char name[XT_FUNCTION_MAXNAMELEN-1];
/* Return true or false: return FALSE and set *hotdrop = 1 to
force immediate packet drop. */
//判断skb是否匹配该match,匹配返回true,不匹配返回false
bool (*match)(const struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, const struct xt_match *match,
const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop);
/* Called when user tries to insert an entry of this type. */
/* Should return true or false. */
//在添加规则时,如果规则中有该match,那么调用该回调检查该match的参数是否正确
bool (*checkentry)(const char *tablename, const void *ip, const struct xt_match *match,
void *matchinfo, unsigned int hook_mask);
/* Called when entry of this type deleted. */
void (*destroy)(const struct xt_match *match, void *matchinfo);
/* Called when userspace align differs from kernel space one */
void (*compat_from_user)(void *dst, void *src);
int (*compat_to_user)(void __user *dst, void *src);
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me;
/* Free to use by each match */
unsigned long data;
const char *table;
unsigned int matchsize;
unsigned int compatsize;
unsigned int hooks;
unsigned short proto;
//match所属协议族
unsigned short family;
u_int8_t revision;
};
2.2 struct xt_entry_match
一旦match组成规则时,还涉及struct xt_entry_match,该结构才是真正在规则中保存的match。
struct xt_entry_match
{
union {
struct {
u_int16_t match_size;
/* Used by userspace */
char name[XT_FUNCTION_MAXNAMELEN-1];
u_int8_t revision;
} user;
struct {
u_int16_t match_size;
/* Used inside the kernel */
struct xt_match *match;
} kernel;
/* Total length */
u_int16_t match_size;
} u;
unsigned char data[0];
};
该结构是由用户空间和内核空间共享的,二者的公共结构是match_size和data字段,match_size表示整个match占用的内存空间。在配置规则时,用户空间指定了name,内核根据name查找系统中已注册的match,然后将match指针指向系统中已注册的struct match对象,从而建立起了规则中的match和match本身两个结构之间的联系。
3 target
和match类似,target本身的定义和在规则中的定义不同。
3.1 struct xt_target
这是target本身,内核中的target模块需要向内核注册一个struct xt_target对象。
struct xt_target
{
struct list_head list;
const char name[XT_FUNCTION_MAXNAMELEN-1];
/* Returns verdict. Argument order changed since 2.6.9, as this
must now handle non-linear skbs, using skb_copy_bits and
skb_ip_make_writable. */
unsigned int (*target)(struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, unsigned int hooknum,
const struct xt_target *target, const void *targinfo);
/* Called when user tries to insert an entry of this type:
hook_mask is a bitmask of hooks from which it can be called. */
/* Should return true or false. */
bool (*checkentry)(const char *tablename, const void *entry,
const struct xt_target *target, void *targinfo, unsigned int hook_mask);
/* Called when entry of this type deleted. */
void (*destroy)(const struct xt_target *target, void *targinfo);
/* Called when userspace align differs from kernel space one */
void (*compat_from_user)(void *dst, void *src);
int (*compat_to_user)(void __user *dst, void *src);
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me;
const char *table;
unsigned int targetsize;
unsigned int compatsize;
unsigned int hooks;
unsigned short proto;
unsigned short family;
u_int8_t revision;
};
所有成员的含义和match基本一致,不在赘述。
3.2 struct xt_entry_target
struct xt_entry_target
{
union {
struct {
u_int16_t target_size;
/* Used by userspace */
char name[XT_FUNCTION_MAXNAMELEN-1];
u_int8_t revision;
} user;
struct {
u_int16_t target_size;
/* Used inside the kernel */
struct xt_target *target;
} kernel;
/* Total length */
u_int16_t target_size;
} u;
unsigned char data[0];
};
设计思想和struct xt_entry_match基本一致,不同点在于标准target也会有一个struct xt_entry_target结构对应,只不过其target指针为空。对于扩展target,该结构的target指针指向对应的struct xt_target对象。
4. rule
下面来看看规则的表示,首先要牢记:规则是由0个或多个match+1个target组成,当没有match时,认为是匹配所有,直接执行target。