Chinaunix首页 | 论坛 | 博客
  • 博客访问: 451043
  • 博文数量: 64
  • 博客积分: 3271
  • 博客等级: 中校
  • 技术积分: 727
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-30 18:42
文章分类

全部博文(64)

文章存档

2013年(1)

2011年(19)

2010年(42)

2009年(2)

分类: LINUX

2010-04-17 12:30:28

.第一个数据包

1)到达PREROUTING

nf_conntrack_in

然后数据包到达G_W所在端口。进入NF_IP_PREROUTING。如图1所示,进入ipv4_conntrack_in钩子函数。

      return (dev_net(), , , );

进而进入nf_conntrack_in函数。

进而

ct = (net, , , , protonum,

                                   l3proto, l4proto, &, &ctinfo);

 

resolve_normal_ct函数中,调用

nf_ct_get_tuple(, (),

                                        , , protonum, &, l3proto,

                                        l4proto))

取得tuple信息。

然后查找是否已经在net->ct.hash中?

h = nf_conntrack_find_get(net, &);

若没有找到,则

h = (net, &, l3proto, l4proto, , );

分配一个。并添加到net->ct.unconfirmed中。

然后由于(h) == ,所以*ctinfo = ;

把这些信息保存到skb数据包中:

    -> = &ct->;

    -> = *ctinfo;

回到nf_conntrack_in中,

    ret = l4proto->(ct, , , ctinfo, , );

由于是UDP,所以,udp_packet(),它做的工作仅仅是

 

之后,由于setreplyresolve_nomal_ct中设置为0,所以if语句不会执行。

ct->[].

                   src:C_W:xx

                   dst:G_W:80

ct->[].

 

                 src: G_W:80

                 dst: C_W:xx

 

==========nf_conntrack_in调用结束。

 

然后进入nf_nat_in

nf_nat_in

先取出了目的地址,然后调用:

    ret = (, , , , );

由于是NF_IP_PREROUTING,所以以下结果:

      enum = ();

maniptype=1;

然后取出ct,ctinfo

     ct = (, &ctinfo);

尝试取出nat

    = (ct);

如果不成功,则添加一个nat扩展。

然后对ctinfo进行判断:

 

case :

                    /* Seen it before?  This can happen for loopback, retrans,

                       or local packets.. */

                    if (!(ct, )) {

                                   unsigned int ;

                                   if ( == )

                                                  /* LOCAL_IN hook doesn't have a chain!  */

                                                  ret = (ct, );

                                   else

                                                  ret = (, , ,

,

                                                                                        ct);

                                   if (ret != ) {

                                                  return ret;

                                   }

没有initialized,并且,hooknum==NF_INET_PREROUTING,所以,进入else,执行ret = (, , , ,ct);

然后此函数执行

ret = (, , , , ->.);

netfilter来执行target.

由于是DNAT,所以会执行

进而:

return (ct, &mr->[0], );

之后

    int = !(ct-> & );

1

之后调用:

    (&curr_tuple,

                                        &ct->[].);

取出ct->tuplehash[IP_CT_DIR_ORIGNAL]?????

                   src:C_W:xx

                   dst:G_W:80

 

notice curr_tuple->dir=ORIG;

 

之后进入:

    (&, &curr_tuple, , ct, );

  此函数中,执行:

    /* 2) Select the least-used / combination in the given

       range. */

    * = *;

    (, , ct, );

用于在range中选择一个最少使用的ip由于maintype=DST,所以

= &->..;

最后* = ->;完成对dst.u3.ip的改变。

find_best返回后,new_tuple=        

                        src:C_W:xx

                     dst:S_L:80

 

;回到后,会执行:

    if (!(&, &curr_tuple)) {

                    struct ;

                    /* Alter conntrack table so will recognize replies. */

                    (&reply, &);

                    (ct, &reply);

                    /* Non-atomic: we own this at the moment. */

                    if ( == )

                                   ct-> |= ;

                    else

                                   ct-> |= ;

    }

因为new_tupleget_unique_tuple中已然改变,所以会进入if分支。invert之后,reply.dir=REPLY 

然后进入(ct, &reply)会执行:

ct->[]. = *;

reply=

      src:S_L:80

      dst:C_W:xx

proto->(, , , ct);

udp_unique_tuple去完成对端口的改变

到此:

ct->tuplehash[IP_CT_DIR_ORIGNAL].tuple=

                                     src:C_W:xx

                                                                   dst:G_W:80

ct->tuplehash[IP_CT_DIR_REPLY].tuple=

                                   src:S_L:80

                                   dst:C_W:xx

之后由于have_to_hash1,所以,进入

    /* Place in source hash if this is the first time. */

    if () {

                    unsigned int ;

                    = (&ct->[].);

                    (&);

                    /* nf_conntrack_alter_reply might re-allocate exntension aera */

                    nat = (ct);

                    nat->ct = ct;

                    hlist_add_head_rcu(&nat->,

                                                     &net->.[]);

                    (&);

    }

对源地址端口进行hash,然后添加到net->ipv4.nat_bysource.

然后执行:

    if ( == )

                    (, &ct->);

至此完成对tuplednat,并且设置了ct->status。并且设置了

 

然后一层层返回到nf_nat_fn进入

                return (ct, ctinfo, , );

这个函数的主要目的就是把数据改变写到skb里面。

先找出dir,mtype

    enum = ();

    unsigned long ;

    enum = ();

当然,dir=ORIGNAL,mtype=DST.所以:

                    statusbit = ;

所以进入:

if (ct-> & statusbit) {

                    struct ;

                    /* We are aiming to look like inverse of other direction. */

                   (&target, &ct->[!dir].);

                    if (!(target.., , 0, &target, ))

                                   return ;

    }

 

ct->[!dir].进行invert,dir=ORIG,

 target =invert(ct->tuplehash[REPLY].tuple)=

                                                                 src:C_W:xx

                                                                   dst:S_L:80

然后进入manip_pkt

    p = (proto);

    if (!p->(, , target, ))

根据协议号来执行p->manip_pkt,udp_manip_pkt

if ( == )

进入else分支:

else {

                     /* Get rid of dst ip and dst pt */

                     = ->;

                     = ->..;

                     = ->.u..;

                     = &->;

}

最后:          * = ;

即把数据包的upd目标端口替换成tuple->dst.u.udp.port.

然后又:

    if ( == ) {

                    (&->, ->, target->..);

                    -> = target->..;

    } else {

                    (&->, ->, target->..);

                    -> = target->..;

    }

进入else分支:

 ip的目标地址换成了target->dst.u3.ipS_L

于是数据包的目标地址,目标ip都替换;内容如下:

                                     src:C_W:xx

                                                                   dst:S_L:80

 

 

 

小结:

      ctinfo  

      ct->status  , ,

      ct->tuplehash[IP_CT_DIR_ORIGNAL].tuple=

                                     src:C_W:xx

                                                                   dst:G_W:80

      ct->tuplehash[IP_CT_DIR_REPLY].tuple=

                                     src:S_L:80

                                     dst:C_W:xx

 

hlist_add_head_rcu(&nat->, &net->.[]);

 

 

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