Chinaunix首页 | 论坛 | 博客
  • 博客访问: 251508
  • 博文数量: 90
  • 博客积分: 2775
  • 博客等级: 少校
  • 技术积分: 645
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-13 17:04
文章分类

全部博文(90)

文章存档

2015年(30)

2013年(4)

2012年(4)

2011年(12)

2010年(4)

2009年(36)

我的朋友

分类: LINUX

2015-06-09 10:18:04

上面分析了tablechainrule的存储结构,现在我们来看一看ipv4 Netfilter是怎么根据这些配置处理报文的。

 

报文被hook函数拦截,开始在相应的表中进行rule的遍历,如果匹配上了一条rule,就由该rule中的target来进行处理。根据target的返回值来决定报文的命运。

 

首先我们来看看Ipv4 Netfilter中实现的表遍历函数 ipt_do_table的处理流程。该函数是处理报文的核心函数。

函数流程图的几点说明:

1、假设从chain1 goto到 user chain时,遍历完user chain中的rule后,如果报文没有被匹配处理,就使用chain1 中的默认rule来处理报文。

如果rule配置时使用的是-j user chain,跳到user chain开始遍历,如果没有被匹配处理,就会返回 chain1中下一条rule继续执行。

以上两种情况,back记录的返回指针不一样。

 

2、如果rule中的target执行结果返回return,就使用chain中默认的rule来处理报文。


net/ipv4/netfilter/ip_tables.c
unsigned int ipt_do_table(struct sk_buff *skb,
    unsigned int hook,
    const struct net_device *in,
    const struct net_device *out,
    struct xt_table *table)
{
#define tb_comefrom ((struct ipt_entry *)table_base)->comefrom

    static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
    const struct iphdr *ip;
    bool hotdrop = false;
    /* Initializing verdict to NF_DROP keeps gcc happy. */
    unsigned int verdict = NF_DROP;
    const char *indev, *outdev;
    void *table_base;
    struct ipt_entry *e, *back;
    struct xt_table_info *private;
    struct xt_match_param mtpar;
    struct xt_target_param tgpar;

    /* Initialization */
    /*根据报文来记录match和target使用的参数*/
    ip = ip_hdr(skb);
    indev = in ? in->name : nulldevname;
    outdev = out ? out->name : nulldevname;
      
    mtpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
    mtpar.thoff   = ip_hdrlen(skb);
    mtpar.hotdrop = &hotdrop;
    mtpar.in      = tgpar.in  = in;
    mtpar.out     = tgpar.out = out;
    mtpar.family  = tgpar.family = NFPROTO_IPV4;
    mtpar.hooknum = tgpar.hooknum = hook;


    IP_NF_ASSERT(table->valid_hooks & (1 << hook));
    //加锁,现在各个cpu使用的存储区是独立的,所以不存在多个cpu锁竞争
    xt_info_rdlock_bh();
    private = table->private;
    table_base = private->entries[smp_processor_id()];


    e = get_entry(table_base, private->hook_entry[hook]);
    /* For return from builtin chain */
    back = get_entry(table_base, private->underflow[hook]);

    /*循环遍历表的rule*/
    do {
        struct ipt_entry_target *t;
        IP_NF_ASSERT(e);
        IP_NF_ASSERT(back);
        if (!ip_packet_match(ip, indev, outdev,
                             &e->ip, mtpar.fragoff) ||
            IPT_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0)//遍历匹配match
        {
            e = ipt_next_entry(e);
            continue;
        }
        ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
        /*取得target*/
        t = ipt_get_target(e);
        IP_NF_ASSERT(t->u.kernel.target);

        /* Standard target? */
        /*如果是标准Target*/
        if (!t->u.kernel.target->target)
        {
            int v;
            v = ((struct ipt_standard_target *)t)->verdict;
            /*如果v大于0,记录是跳转偏移量,小于0,是标准target*/
            if (v < 0)
            {
                /* Pop from stack? */
                /*如果不等于return,直接返回*/
                if (v != IPT_RETURN) {
                    verdict = (unsigned)(-v) - 1;
                    break;
                }
                /*如果是return,执行chain中默认rule处理报文*/
                e = back;
                back = get_entry(table_base, back->comefrom);
                continue;
            }
           if (table_base + v != ipt_next_entry(e)//跳转到下一条rule不是紧挨着的这个rule*/
               && !(e->ip.flags & IPT_F_GOTO))
            {
                /* Save old back ptr in next entry */
                struct ipt_entry *next = ipt_next_entry(e);
                next->comefrom = (void *)back - table_base;
                /* set back pointer to next entry */
                back = next;
            }
            /*根据verdict的偏移量找到跳转的rule*/
             e = get_entry(table_base, v);
            continue;
        }

        /* Targets which reenter must return abs. verdicts */
        /*如果是扩展target,就执行扩展targe的target处理函数*/
        tgpar.target   = t->u.kernel.target;
        tgpar.targinfo = t->data;

        verdict = t->u.kernel.target->target(skb, &tgpar);

        /* Target might have changed stuff. */
        ip = ip_hdr(skb);
        if (verdict == IPT_CONTINUE)
            e = ipt_next_entry(e);
        else
            /* Verdict */
            break;
    } while (!hotdrop);
    //释放锁
    xt_info_rdunlock_bh();


    #ifdef DEBUG_ALLOW_ALL
    return NF_ACCEPT;
    #else
    if (hotdrop)
        return NF_DROP;
    else return verdict;
    #endif
#undef tb_comefrom
}

(未完待续)

阅读(426) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~