在分析LINUX2.4.x网络安全的实现之前先简单介绍一下它里面包含的几个重要概念:netfilter、iptables、match、target、nf_sockopt_ops、网络安全功能点的实现。
3. iptables
iptables实现对规则的管理和访问。它里面有几个重要的数据结构ipt_entry,ipt_match,ipt_target,ipt_table,用于构造规则表。还有一个重要的函数ipt_do_table,用于遍历规则表并处理规则表上的结构。
ipt_entry是规则的数据结构,如下:
struct ipt_entry
{
struct ipt_ip ip;
unsigned int nfcache;
u_int16_t target_offset;/* target在规则中的偏移 */
u_int16_t next_offset;/* 下一条规则的偏移 */
unsigned int comefrom;
struct ipt_counters counters;/* 匹配规则的数据包的统计计数 */
unsigned char elems[0];
};
|
在ipt_entry中ipt_ip是一个基本的match,它是固定的,用于匹配数据包的源地址/源端口、目的地址/目的端口、协议等。其他的match按需要添加,个数并不固定,所以在ipt_entry有一个变长的字符数组保存规则中match的指针,这些指针指向系统中注册的match。每个规则有一个target,决定数据包完全匹配规则后怎样处理这个数据包,它也是一个指向系统注册的target的指针,并且也放在前面提到的变长字符数组中。ipt_entry中的target_offset是target在规则中的偏移,偏移是从规则的起始地址到target所在位置的长度,还有一个变量next_offset指示下一条规则偏移,它其实就是本条规则的长度。
前面提到在iptables中沿用了LINUX2.2.x中的chain和rule的概念,那么在ipt_entry中如何区分chain和rule的哪?
我们知道chain是某个检查点上检查的规则的集合。除了默认的chain外,还可以创建新的chain。在iptables中,同一个chain里的规则是连续存放的。默认的chain的最后一条规则的target是chain的policy。用户创建的chain的最后一条规则的target的调用返回值是NF_RETURN,遍历过程将返回原来的chain。规则中的target也可以指定跳转到某个用户创建的chain上,这时它的target是ipt_stardard_target,并且这个target的verdict值大于0。如果在用户创建的chain上没有找到匹配的规则,遍历过程将返回到原来chain的下一条规则上。
ipt_match用于匹配数据包的参数,如TCP数据包中的标志位,ICMP协议中的类型等,每个match所感兴趣的参数都不一样,所以一条规则可能有多个match。ipt_target决定在数据包完全匹配规则后应做什么样的处理。这两个在使用之间都必须先注册到系统的链表中才能被规则引用。对这两个数据结构不做过多分析,读者可以自行参考源代码。
ipt_table是规则表的数据结构,如下:
struct ipt_table
{
struct list_head list;
char name[IPT_TABLE_MAXNAMELEN];
struct ipt_replace table;/* 用户空间传递的规则表 */
unsigned int valid_hooks;/* 有效的检查点置位*/
rwlock_t lock;
struct ipt_table_info private;/* 规则表在内核中的存储结构 */
struct module *me;
};
|
在ipt_table中,ipt_replace是用户空间配置程序传递给内核的规则表,这个规则表不能直接使用,必须先根据它里面包含的match和target的名称将match和target转换成在内核注册的match和target的指针,还有一项重要的工作是检查规则表中是否有循环,如果有循环,要给用户空间的配置程序报告错误。转换之后的规则表存储在ipt_table_info中。valid_hooks指示与这个表相关的检查点,并把相应的位置为1。一个table中可以有多个chain,chain分为系统默认的chain(与table注册的检查点对应)和用户创建的。