Iptables/Netfilter系统表(filter,nat,mangle)的疑问

在下今日在学习Iptables/Netfilter相关的知识,作为本科毕设只用。
  但是在学习的过程中遇到了一些疑问,想请教各位大牛,希望能帮助解答:
  读了很多关于数据包在协议栈以及Netfilter当中处理流程的资料
  
下载 (90.38 KB)
2011-01-18 15:24

  像如上资料说的,但是分析这个处理过程,不知Netfilter框架中的三张系统表(filter,nat,mangle表)是在那里起的作用,或者是三张表存在的意义是什么呢?
  到目前为止,我浅薄的理解是:协议栈在每个钩子处交给Netfilter处理,而Netfilter只是将数据包和每个规则相比对(match),比对上了则进行相应的target,没有比对上则进行下一条规则的匹配,直到最后一条位置。如果按照如上思路,和三张表貌似没有太多的关系啊?请大牛解决

作者: kaiserhui   发布时间: 2011-01-18

Iptables 与netfilter的分析(源于LINUX-2.6.34)
                                       
一 Netfilter 提供了一个基于HOOK的框架,基于优先级的。
下面是每个HOOK的描述
struct nf_hook_ops {
    struct list_head list;

    /* User fills in from here down. */
    nf_hookfn *hook;               /*处理函数*/
    struct module *owner;
    u_int8_t pf;
    unsigned int hooknum;           /*hook的在协议栈中的调用位置*/  
    /* Hooks are ordered in ascending priority. */
    int priority;                   /*同一调用位置的优先级*/
};

下面这个是HOOK在协议栈中的调用位置,大致是根据路由前后来制定的。
enum nf_inet_hooks {
    NF_INET_PRE_ROUTING,
    NF_INET_LOCAL_IN,
    NF_INET_FORWARD,
    NF_INET_LOCAL_OUT,
    NF_INET_POST_ROUTING,
    NF_INET_NUMHOOKS
};

同一个切入点比如NF_INET_PRE_ROUTING,提供了优先级,可以看到在同一个协议栈切入点,不同的表的优先级顺序。
enum nf_ip_hook_priorities {
    NF_IP_PRI_FIRST = INT_MIN,
    NF_IP_PRI_CONNTRACK_DEFRAG = -400,
    NF_IP_PRI_RAW = -300,
    NF_IP_PRI_SELINUX_FIRST = -225,
    NF_IP_PRI_CONNTRACK = -200,
    NF_IP_PRI_MANGLE = -150,
    NF_IP_PRI_NAT_DST = -100,
    NF_IP_PRI_FILTER = 0,
    NF_IP_PRI_SECURITY = 50,
    NF_IP_PRI_NAT_SRC = 100,
    NF_IP_PRI_SELINUX_LAST = 225,
    NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
    NF_IP_PRI_LAST = INT_MAX,
};

二 HOOK主要使用对象是 IPTABLES, CONNTRACK
从枚举类型enum nf_ip_hook_priorities  可以看出这一点。

三 iptables向netfilter HOOK的注册
  同一切入点,不同的表因为不同的优先级,所以区别开来。
  同一个表,要向netfilter hook 注册多次,最多的可能下面几个地方都会注册。
NF_INET_PRE_ROUTING,
    NF_INET_LOCAL_IN,
    NF_INET_FORWARD,
    NF_INET_LOCAL_OUT,
    NF_INET_POST_ROUTING,
    NF_INET_NUMHOOKS
   这些点在处理上分别对应各个表的预定义链,这个解释会通过
unsigned int
ipt_do_table(struct sk_buff *skb,
         unsigned int hook,   /* enum nf_inet_hooks ,如值为NF_INET_PRE_ROUTING,
*/
         const struct net_device *in,
         const struct net_device *out,
         struct xt_table *table)

四 iptables的组织结构
Iptables 由链组成,链内由零或多条规则组成。链分为:预定义链和自定义链。
预定义链
是netfilter HOOK调用后的切入点。预定义链中的规则可以跳到自定义链继续遍历规则,直到匹配。
自定义链
也可以再跳转到其他自定义链,但自定义链里面的规则不能跳转到预定义链,但是可以返回调用链。

不同表之间不能直接跳转,不同表之间可以自定义同名的链。

表这个概念存在的意义
    规则,规则链足以描述策略
    hook调用后直接跳向的是链,即使不存在表这个概念仍然也是行的通的。但是表的存在的确是有好处的。
表的存在提高了功能的抽象,同一功能的不同链归为一个表的域内,比如nat功能表,几个预定义链分布在不同HOOK点,NF_INET_PRE_ROUTING时候 做目的nat,NF_INET_POST_ROUTING, 时候做源nat。filter表主要用来做过滤用,mangle表主要用来设置一下标志用,当然这个并不是死板的。
表的存在可以减少预定义链的命名,使得易于记忆,不同的表里面都可以叫FORWARD链名
表的存在可以隔离自定义链,减少命名冲突。

规则,链,表在内核中的数据结构
   Iptables 中链,规则不是明显的使用链表来组织的。可能因为规则总是顺序遍历的原因。
只有规则和表的结构,不存在链的结构。一个表直接由一块规则的内存区组成。
不用链表做优点:从用户空间传递到内核空间的时候,内核空间不需要再把传进来的数据用链表化,使用便宜量,这样也即节省了代码,又节省操作了时间。缺点不太利于阅读理解。用户空间在整合各个链表,以及自定义链表到内存区的时候,要不停的计算便宜量,一不小心容易出错,稍微比较麻烦点。

struct ipt_entry {
    struct ipt_ip ip;

    /* Mark with fields that we care about. */
    unsigned int nfcache;

    /* Size of ipt_entry + matches */
    u_int16_t target_offset;
    /* Size of ipt_entry + matches + target */
    u_int16_t next_offset;      /*我们只需要记住下一条的偏移量,相当于next指针*/

    /* Back pointer */
    unsigned int comefrom;     /*返回调用链用*/

    /* Packet and byte counters. */
    struct xt_counters counters;

    /* The matches (if any), then the target. */
    unsigned char elems[0];
};

Table表结构
/* The table itself */
struct xt_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_INET_NUMHOOKS]; /*预定义链在表中的偏移量*/
    unsigned int underflow[NF_INET_NUMHOOKS]; /*从预定义链返回的偏移量*/

    /* ipt_entry tables: one per CPU */
    /* Note : this field MUST be the last one, see XT_TABLE_INFO_SZ */
    void *entries[1];
};

思考:
  对于预定义链:空链情况下也会占有一个ipt_entry,  hook_entry[]  underflow[]中的值是相等的,都指向该ipt_entry,该规则target必须是 drop或者accept,来表示默认处理方式。

  对于自定义链:
  头规则是
struct ipt_error {
    struct ipt_entry entry;
    struct ipt_error_target target;
};
struct ipt_error_target {
    struct ipt_entry_target target;                   /*user.name 为“ERROR”*/
    char errorname[IPT_FUNCTION_MAXNAMELEN];  /*这里存放表名称*/
};

作者: tuibo   发布时间: 2011-01-18

规则-表-链 这三者的关系你要搞清楚。
规则是存储在表中的。
iptables -t tables
这个命令是要指定使用哪张表的,不同的表具有不同的功能。
我们通常写规则,没有带这个 -t 选项,是因为默认表是 filter。

作者: Godbach   发布时间: 2011-01-18



QUOTE:
规则-表-链 这三者的关系你要搞清楚。
规则是存储在表中的。
iptables -t tables
这个命令是要指定使用 ...
Godbach 发表于 2011-01-18 16:00



谢谢哥德巴赫大牛,再次受教了~

作者: kaiserhui   发布时间: 2011-01-18