netfilter中iptables表的实现

本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn

1. 前言

iptables所制定的规则都是和内核中netfilter内的“表(table)”相联系的,缺省情况系统中已经自带了3个表:filter、nat和mangle,iptables命令中的“-t”参数就是用来指定该规则是属于哪个表。和匹配和目标一样,netfilter 也提供了模块化的表功能扩展,用户可以根据需要自己编写新的表。

以下内核代码版本为2.4.26。

2. 表、规则、hook点之间的相互关系

netfilter的架构的基本过滤原理是网络栈中定义5个hook点,在每个hook点进行检查,就是按优先级执行挂接在该点上的所有struct nf_hook_ops结构的处理函数,只有这些函数都返回NF_ACCEPT才表示该数据包允许通过该hook点。

每个表中都要定义一些起效的hook点,这些hook点就对应了iptables规则中的链,如
filter表的起效hook点是NF_IP_LOCAL_IN、 NF_IP_FORWARD和NF_IP_LOCAL_OUT,对应iptables规则filter表中的INPUT、FORWARD和OUTPUT 链,在每个合法hook点都定义一个struct nf_hook_ops结构,每个struct nf_hook_ops结构都有一个基本处理函数,如filter表NF_IP_LOCAL_IN、NF_IP_FORWARD点的是 ipt_hook()函数,这些函数最终都会调用ipt_do_table()函数来进行该链中规则的遍历匹配操作,但要注意的是ipt_hook()等基本处理函数的参数中并没有struct ipt_table结构的参数,所以目前这些表都是静态存在而不支持动态分配。

filter表在net/ipv4/netfilter/iptable_filter.c中定义,nat表在net/ipv4 /netfilter/ip_nat_rule.c中定义,mangle表在net/ipv4/netfilter/iptable_mangle.c中定义.nat表和其他两个
稍有不同,其他两个表结构和hook_ops都在同一个文件中定义了,而nat的hook_ops是在net/ipv4/netfilter/ip_nat_standalone.c中定义的。

3. 数据结构

每个表都需要一个struct ipt_table结构来进行描述,建立一个新表就是要填写这样一个结构:

/* include/linux/netfilter_ipv4/ip_tables.h */

struct ipt_table
{
struct list_head list;
/* A unique name... */
char name[IPT_TABLE_MAXNAMELEN];
/* Seed table: copied in register_table */
struct ipt_replace *table;
/* What hooks you will enter on */
unsigned int valid_hooks;
/* Lock for the curtain */
rwlock_t lock;
/* Man behind the curtain... */
struct ipt_table_info *private;
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me;
};

结构中包括以下参数:
struct list_head list:这是将该结构挂接到table链表中
char name[]:表名称
struct ipt_replace *table:struct ipt_replace结构定义该表基本属性
unsigned int valid_hooks:该表合法的挂接点位置
rwlock_t lock:表操作时的读写锁
struct ipt_table_info *private:这实际上是表中规则项表的索引指针,初始化为NULL
struct module *me:指向模块本身,统计模块是否被使用

其中struct ipt_table_info结构定义为:

/* include/linux/netfilter_ipv4/ip_tables.h */

struct ipt_table_info
{
/* Size per table */
unsigned int size;
/* Number of entries: FIXME. --RR */
unsigned int number;
/* Initial number of entries. Needed for module usage count */
unsigned int initial_entries;
/* Entry points and underflows */
unsigned int hook_entry[NF_IP_NUMHOOKS];
unsigned int underflow[NF_IP_NUMHOOKS];
/* ipt_entry tables: one per CPU */
char entries[0] ____cacheline_aligned;
};

结构参数说明如下:
unsigned int size:表的大小
unsigned int number:规则数量
unsigned int initial_entries:初始化时的规则数
unsigned int hook_entry[NF_IP_NUMHOOKS]:各hook点起始规则的偏移
unsigned int underflow[NF_IP_NUMHOOKS]:各hook点结束规则的偏移
char entries[0]:实际的规则数组

其中struct ipt_replace结构定义为:

/* include/linux/netfilter_ipv4/ip_tables.h */
struct ipt_replace
{
/* Which table. */
char name[IPT_TABLE_MAXNAMELEN];
/* Which hook entry points are valid: bitmask. You can't
change this. */
unsigned int valid_hooks;
/* Number of entries */
unsigned int num_entries;
/* Total size of new entries */
unsigned int size;
/* Hook entry points. */
unsigned int hook_entry[NF_IP_NUMHOOKS];
/* Underflow points. */
unsigned int underflow[NF_IP_NUMHOOKS];
/* Information about old entries: */
/* Number of counters (must be equal to current number of entries). */
unsigned int num_counters;
/* The old entries' counters. */
struct ipt_counters *counters;
/* The entries (hang off end: not really an array). */
struct ipt_entry entries[0];
};

结构参数说明如下:

char name[IPT_TABLE_MAXNAMELEN]:表名称
unsigned int valid_hooks:有效hook点
unsigned int num_entries:规则数
unsigned int size:规则大小
unsigned int hook_entry[NF_IP_NUMHOOKS]:各hook点起始规则的偏移
unsigned int underflow[NF_IP_NUMHOOKS]:各hook点结束规则的偏移
unsigned int num_counters:计数器的数量,各规则都有一个
struct ipt_counters *counters:计数器
struct ipt_entry entries[0]:规则入口

规则的存储是相当于数组方式存储的,只是数组大小会动态修改,每个表的所有规则都形成一个数组,而且是按hook点的顺序存储,如对于 filter表,数组开始是INPUT链的规则,后面是FORWARD链规则,然后是OUTPUT链的规则,最后是处理错误的规则,这就是 iptables规则使用“-L -v -v”时看到的实际的规则存储方式。各个hook点的规则起始和结束规则是靠struct ipt_table_info结构中的hook_entry[]和underflow[]来确定的。按数组方式实现在遍历处理时会比较快,但编辑时就比较麻烦了,会伴随大量的内存重分配和拷贝操作。

在具体实现表时,在初始化ipt_table结构的struct ipt_replace结构参数时,除了struct ipt_replace结构本身的参数外,还自动添加描述各条链的缺省动作的规则,也就是说制定iptables规则时用“-P”定义的链的缺省动作也是靠规则来实现的,如对于filter表的定义如下:

/* net/ipv4/netfilter/iptable_filter.c */

struct ipt_standard
{
struct ipt_entry entry;
struct ipt_standard_target target;
};
struct ipt_error_target
{
struct ipt_entry_target target;
char errorname[IPT_FUNCTION_MAXNAMELEN];
};
struct ipt_error
{
struct ipt_entry entry;
struct ipt_error_target target;
};
static struct
{
struct ipt_replace repl;
struct ipt_standard entries[3]; // 3个hook点,各自一条缺省规则
struct ipt_error term; // 错误处理规则
} initial_table __initdata

4. 相关函数

表的处理函数相对比较少,使用函数 int ipt_register_table(struct ipt_table *)来登记表使之生效,而使用void ipt_unregister_table(struct ipt_table *)取消表的登记。在登记时,会初始化数据中的struct ipt_replace结构的数据转化到struct ipt_table_info结构中。登记后用iptables规则就可以用“-t table_name”来配置新表中的规则了。

每个表通过ipt_do_table()函数(net/ipv4/netfilter/ip_tables.c)来进行表中的规则匹配最终确定对数据包的动作。

5. 结论

netfilter的表处理也可以模块化实现,新表的添加可以以当前系统自带的表为蓝本来编写,只是要确定好各个hook点处理函数的优先级来确定相对其他表的执行顺序。一般情况下不需要添加新表,但在某些特殊功能,如实现虚拟系统,多个表分开过滤会更方便处理一些。

后记:本文初稿在基本写完时突然掉电,没存,这是第二版了,内容少了一些。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值