Netfilter分析(2)

950阅读 0评论2015-12-02 qxhgd
分类:LINUX

(接Netfilter分析1)(由于出去做实验,耽误了Netfilter的分析进度。。。)
    调用HOOK的包筛选函数必须返回特定的值,这些值以宏的形式定义于头文件include/linux/netfilter.h中(Line15),分别为:

4.HOOK的注册和注销
    HOOK的注册和注销分别是通过nf_register_hook()函数和nf_unregister_hook()函数(分别位于net/core/netfilter.c,Line60,76)实现的,其参数均为一个nf_hook_ops结构,二者的实现也非常简单。
    nf_register_hook()的工作是首先由HOOK的优先级确定在HOOK链表中的位置,然后根据优先级将该HOOK的nf_hook_ops加入链表;
    nf_unregister_hook()的工作更加简单,其实就是将该HOOK的nf_hook_ops从链表中删除。

五、IPTables系统

1.表-规则系统
    IPTables是基于Netfilter基本架构实现的一个可扩展的数据报高级管理系统,利用table、chain、rule三级来存储数据报的各种规则。系统预定义了三个table:
    监听NF_IP_LOCAL_IN、NF_IP_FORWARD和NF_IP_LOCAL_OUT三个HOOK,作用是在所有数据报传递的关键点上对其进行过滤。
    监听NF_IP_PRE_ROUTING、NF_IP_POST_ROUTING和NF_IP_LOCAL_OUT三个HOOK,作用是当新连接的第一个数据报经过时,在nat表中决定对其的转换操作;而后面的其它数据报都将根据第一个数据报的结果进行相同的转换处理。
        监听NF_IP_PRE_ROUTING和NF_IP_LOCAL_OUT两个HOOK,作用是修改数据报报头中的一些值。

2.表的实现
    表的基本数据结构是ipt_table(位于include/linux/netfilter_ipv4/ip_tables.h,Line413):
struct ipt_table
{
    struct list_head list;
    char name[IPT_TABLE_MAXNAMELEN];
    struct ipt_replace *table;                //表初始化时的“种子表”
    unsigned int valid_hooks;              //表所监听的HOOK
    rwlock_t lock;
    struct ipt_table_info *private;       //表所存储的数据信息
    struct module *me;           //如果是模块,那么取THIS_MODULE,否则取NULL
};
    上文所提到的filter、nat和mangle表分别是这个数据结构的三个实例:packet_filter(位于net/ipv4/netfilter/iptable_filter.c,Line84)、nat_table(位于net/ipv4/netfilter/ip_nat_rule.c,Line104)以及packet_mangle(位于net/ipv4/netfilter/iptable_mangle.c,Line117)

struct ipt_table_info
{
    unsigned int size;
    unsigned int number;                //表项的数目
    unsigned int initial_entries;      //初始表项数目
    unsigned int hook_entry[NF_IP_NUMHOOKS];     //所影响HOOK的规则入口
    unsigned int underflow[NF_IP_NUMHOOKS];      //规则表的最大下界
    char entries[0] ____cacheline_aligned; //规则表入口,即真正的规则存储结构                    //ipt_entry组成块的起始地址,每个CPU对应一个这样的块
};
3. 规则的实现
    IPTables中的规则表可以在用户空间中使用,但它所采用的数据结构与内核空间中的是一样的,只不过有些成员不会在用户空间中使用。
    一个完整的规则由三个数据结构共同实现,分别是:
    下面将依次对这三个数据结构进行分析:
i.存储规则整体的结构ipt_entry,其形式是一个链表(位于include/linux/netfilter_ipv4/ip_tables.h,Line122):
struct ipt_entry
{
    struct ipt_ip ip;
    unsigned int nfcache;                         
    u_int16_t target_offset;                        
    u_int16_t next_offset;                          
    unsigned int comefrom;
    struct ipt_counters counters;
    unsigned char elems[0];
};
    其成员如下:
#define NFC_ALTERED 0x8000                     //已改变
#define NFC_UNKNOWN 0x4000                  //不确定
        另一个可能值是0,即没有改变。
ii.扩展match的存储结构ipt_entry_match,位于include/linux/netfilter_ipv4/ip_tables.h,Line48:
struct ipt_entry_match
{
    union {
        struct {
            u_int16_t match_size;
            char name[IPT_FUNCTION_MAXNAMELEN];
        } user;
        struct {
            u_int16_t match_size;
            struct ipt_match *match;
        } kernel;
        u_int16_t match_size;                             //总长度
    } u;
    unsigned char data[0];
};
    其中描述match大小的`u_int16_t match_size;`,从涉及这个变量的源码看来,在使用的时候需要注意使用一个宏IPT_ALIGN(位于include/linux/netfilter_ipv4/ip_tables.h,Line445)来进行对齐处理,这应该是由于match、target扩展后大小的不确定性决定的。
    在结构中,用户空间与内核空间为不同的实现,内核空间中的描述拥有更多的信息。在用户空间中存放的仅仅是match的名称,而在内核空间中存放的则是一个指向ipt_match结构的指针
    结构ipt_match位于include/linux/netfilter_ipv4/ip_tables.h,Line342:
struct ipt_match
{
    struct list_head list;
    const char name[IPT_FUNCTION_MAXNAMELEN];
    int (*match)(const struct sk_buff *skb,
             const struct net_device *in,
             const struct net_device *out,
             const void *matchinfo,
             int offset,
             const void *hdr,
             u_int16_t datalen,
             int *hotdrop);
    int (*checkentry)(const char *tablename,
              const struct ipt_ip *ip,
              void *matchinfo,
              unsigned int matchinfosize,
              unsigned int hook_mask);
    void (*destroy)(void *matchinfo, unsigned int matchinfosize);
    struct module *me;
};
    其中几个重要成员:
iii.扩展target的存储结构ipt_entry_target,位于include/linux/netfilter_ipv4/ip_tables.h,Line71,这个结构与ipt_entry_match结构类似,同时其中描述内核空间target的结构ipt_target(位于include/linux/netfilter_ipv4/ip_tables.h,Line375)也与ipt_match类似,只不过其中的target()函数返回值不是0/1,而是verdict,并且其只对非标准的target起作用。对于标准的target,有一个结构ipt_standard_target专门来描述,位于include/linux/netfilter_ipv4/ip_tables.h,Line94,实际上就是一个ipt_entry_target加一个verdict。

    那么总之呢,表和规则的实现如图06-11-20所示

    从图06-11-20中不难发现,match的定位如下:
    target的定位则为:
    这些对于理解match以及target相关函数的实现是很有必要明确的。

    include/linux/netfilter_ipv4/ip_tables.h中提供了三个“helper functions”,可用于使对于entry、tartget和match的操作变得方便,分别是:
3. 规则的使用
    当一个特定的HOOK被激活时,数据报就开始进入Netfilter/IPTables系统进行遍历,首先检查`struct ipt_ip ip`,然后数据报将依次遍历各个match,也就是`struct ipt_entry_match`,并执行相应的match函数,即ipt_match结构中的*match所指向的函数。当match函数匹配不成功时返回0,或者hotdrop被置为1时,遍历将会停止。
    对match的遍历完成后,会开始检查`struct ipt_entry_target`,其中如果是一个标准的target,那么会检查`struct ipt_standard_target`中的verdict,如果verdict值是正的而偏移却指向不正确的位置,那么ipt_entry中的comefrom成员就有了用武之地——数据报返回所经历的上一个规则。对于非标准的target呢,就会调用target()函数,然后根据其返回值进行后面的处理。
4. 规则的扩展
    且听下回分解^_^
上一篇:Netfilter分析
下一篇:Netfilter分析(1)