Chinaunix首页 | 论坛 | 博客
  • 博客访问: 94725
  • 博文数量: 19
  • 博客积分: 1471
  • 博客等级: 上尉
  • 技术积分: 272
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-09 19:48
文章分类

全部博文(19)

文章存档

2011年(2)

2010年(17)

分类: LINUX

2010-07-09 20:00:45

            Iptables 与netfilter的分析(源于LINUX-2.6.34)
                                      Msn: mewmaker@163.com
一 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];  /*这里存放表名称*/
};
阅读(1670) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:RCU锁原理分析

给主人留下些什么吧!~~