Linux connection tracking and NAT

Linux 的connection tracking和NAT都是通过netfilter框架实现的。connection tracking模块实现了防火墙的状态检测功能,包括单连接和多连接的(FTP)。NAT模块依赖于connection tracking建立的connection,在此基础上进行地址和端口的匹配和转换。


PREROUTING:            ip_conntrack_defrag

ip_conntrack_in              //init conn and bind helper orexecute expectation

ip_nat_in                            //DNAT

 

POSTROUTING:   ip_nat_out                                 //SNAT

                                         ip_conntrack_help                      //execute helper andgenerate expectation

                                         ip_nat_adjust                             //adjust tcp seq

                                         ip_confirm                                //establish conn

 

1.1       UDP: SNAT

1.    ip_conntrack_in():

resolve_normal_ct()->

  init_conntrack()-> //malloc and init conn, helper, expecation.

  protocol->new() // proto special handling:udp_new()

proto->packet()->

 ip_ct_refresh_acct() //refresh timer, doaccounting and send event

2.    ip_nat_in():

ip_nat_fn()->//the following seems uncessary

  alloc_null_binding()->

  ip_nat_setup_info()

3.    ip_nat_out():

ip_nat_fn()->

 ip_nat_rule_find()->

  ipt_do_table()->

  ipt_snat_target()-> //Match & Targetsystem

    ip_nat_setup_info()-> //setup snat andwill also alter dnat info

     invert_tuplepr() ->      //just to get original tuple

                    ip_ct_invert_tuple()-> 

                    protocol->invert_tuple//proto special handling

     get_unique_tuple()->  //install nat info into conn

  find_best_ips_proto() // ip nat

  proto->unique_tuple // proto specialhandling, e.g, udp_unique_tuple

  ip_nat_packet ()->

   manip_pkt()->   //mangle packet based on the conn info

    proto->manip_pkt // proto specialhandling: port nat

4.    ip_confirm():

__ip_conntrack_confirm()//insert conn, add timer and send conn & helper & nat event

 

1.2       UDP: DNAT

1.   ip_conntrack_in():

resolve_normal_ct()->

proto->packet()->

  ip_ct_refresh_acct() //refresh timer, doaccounting and send event

2.   ip_nat_in():

ip_nat_fn()->

ip_nat_packet ()->

  manip_pkt()->   //mangle packet based on the conn info

  proto->manip_pkt // proto specialhandling: port nat

3.   ip_nat_out(): //

ip_nat_fn()->

ip_nat_packet ()->// the following seems unnecessary

  manip_pkt()->   //mangle packet based on the conn info

  proto->manip_pkt // proto specialhandling: port nat

5.    ip_confirm()://do nothing

 

1.3       TCP/HTTP: SNAT

1.    ip_conntrack_in():

resolve_normal_ct()->

  init_conntrack()-> //malloc and init conn, helper, expecation.

  protocol->new() // tcp_new(), fill conn->proto->tcp structure

proto->packet() -> //tcp_packet(),change the conn state and timer

  ip_ct_refresh_acct() //refresh timer, doaccounting and send event

 

1.4      TCP/HTTP: DNAT

1.    ip_conntrack_in():

resolve_normal_ct()->

proto->packet() -> //tcp_packet(),change the conn state and timer

  ip_ct_refresh_acct() //refresh timer, doaccounting and send event

 

1.5       TCP/FTP: SNAT

1.    ip_conntrack_in():

resolve_normal_ct()->

  init_conntrack()-> //mallocand init conn, helper, expecation.

  protocol->new() // tcp_new(), fill conn->proto->tcp structure

proto->packet() -> //tcp_packet(),change the conn state and timer

  ip_ct_refresh_acct() //refresh timer, doaccounting and send event

 

1.6      TCP/FTP: DNAT

1.    ip_conntrack_in():

resolve_normal_ct()->

proto->packet() -> //tcp_packet(),change the conn state and timer

  ip_ct_refresh_acct() //refresh timer, doaccounting and send event

 

1.7       TCP/FTP(PORT Command): SNAT+ helper

1.      ip_conntrack_help():

  ct->helper->help()-> //protocol specialhandling: init related expectation

    ip_nat_ftp() ->

     ip_conntrack_expect_related() // registerexpectation

      mangle_rfc959_packet()->  // mangle the packet

       ip_nat_mangle_tcp_packet()->

         mangle_contents()

         adjust_tcp_sequence()

          ip_conntrack_tcp_update()

    update_nl_seq()

2.      ip_nat_adjust():

 ip_nat_seq_adjust() //adjust tcp seq

 

1.8      TCP/FTP(PORT Command): DNAT+ helper

1.      

ip_conntrack_help():

  ct->helper->help()->//protocol special handling: init related expectation

    ip_nat_ftp() ->

    update_nl_seq()

2.      

ip_nat_adjust():

 ip_nat_seq_adjust() //adjust tcp seq

 

1.9      TCP/FTP: DNAT + Expectation

1.      

ip_conntrack_in():

resolve_normal_ct()->

 init_conntrack()-> //malloc and init conn, helper, expecation.

  exp->expectfn() // ip_nat_follow_master()

   ip_nat_setup_info() // snat ???

   ip_nat_setup_info() // dnat will alter snat

  protocol->new() // proto special handling:udp_new()

proto->packet()->

 ip_ct_refresh_acct() //refresh timer, doaccounting and send event

 

1.10   ICMP: SNAT

 

The firewall set the NEW state once gets a request packet, it’s,then sets ESTABLISHED once gets related reply packets, and then deletes thisconn.

 

icmp_invert_tuple()

icmp_manip_pkt()

 

1.11    ICMP/Error: DNAT

1.      ip_conntrack_in():

                       proto->error()  // icmp_error()

             icmp_error_message()

2.      ip_nat_out()

 ip_nat_fn()->

  ip_nat_icmp_reply_translation()->

  

1.12    Port Translation

 

不论是SNAT还是MASQ,如果有冲突,kernel都会做Port Translation

iptables-t nat -A POSTROUTING -s 172.19.0.200/32 -j SNAT --to 172.18.0.2-172.18.0.3

iptables-t nat -A PREROUTING -i eif1 -p tcp --dport 80 -j DNAT --to 172.19.0.200

 

iptables-t nat -A POSTROUTING -o eif1 -j MASQUERADE

iptables-A FORWARD -i eif1 -o eif2 -m state --state ESTABLISHED,RELATED -j ACCEPT

iptables-A FORWARD -i eif2 -o eif1 -j ACCEPT

 

get_unique_tuple(structip_conntrack_tuple *tuple,

            const struct ip_conntrack_tuple *orig_tuple,

            const struct ip_nat_range *range,

            struct ip_conntrack *conntrack,

            enum ip_nat_manip_type maniptype)

{

       struct ip_nat_protocol *proto;

 

       /* 1) If this srcip/proto/src-proto-partis currently mapped,

         and that same mapping gives a unique tuple within the given

         range, use that.

 

         This is only required for source (ie. NAT/masq) mappings.

         So far, we don't do local source mappings, so multiple

         manips not an issue.  */

       if (maniptype == IP_NAT_MANIP_SRC) {

           if (find_appropriate_src(orig_tuple,tuple, range)) {

                       DEBUGP("get_unique_tuple:Found current src map\n");

                       if (!(range->flags& IP_NAT_RANGE_PROTO_RANDOM))

                                   if(!ip_nat_used_tuple(tuple, conntrack))

                                               return;

           }

       }

 

       /* 2) Select the least-used IP/protocombination in the given

         range. */

       *tuple = *orig_tuple;

       find_best_ips_proto(tuple, range,conntrack, maniptype);

 

       /* 3) The per-protocol part of the manipis made to map into

         the range to make a unique tuple. */

 

       rcu_read_lock();

       proto =__ip_nat_proto_find(orig_tuple->dst.protonum);

 

       /* 如果range有random标志,则通过特定proto随即取一个*/

       /* Change protocol info to have somerandomization */

       if (range->flags &IP_NAT_RANGE_PROTO_RANDOM) {

           proto->unique_tuple(tuple, range,maniptype, conntrack);

           goto out;

       }

 

       /* 如果没有指定端口,并且当前报文中的端口没有被用,那就不需要PortTranslation */

       /* Only bother mapping if it's notalready in range and unique */

       if ((!(range->flags &IP_NAT_RANGE_PROTO_SPECIFIED)

           || proto->in_range(tuple, maniptype, &range->min,&range->max))

          && !ip_nat_used_tuple(tuple, conntrack))

           goto out;

 

       /* 不管了,做了PortTranslation 先*/

       /* Last change: get protocol to try toobtain unique tuple. */

       proto->unique_tuple(tuple, range,maniptype, conntrack);

out:

       rcu_read_unlock();

}

 

/*具体到proto特定的函数就很直观了,如果有指定范围,从指定范围中选。如果没有指定范围,小于512的从1~511选一个未被占用的,小于1024的从600到1023选一个未被占用的,大于1024的从1024~65535- 1024 + 1选一个未被占用的。如果有random标志,在其基础上random一下*/

 

staticint

udp_unique_tuple(structip_conntrack_tuple *tuple,

            const struct ip_nat_range *range,

            enum ip_nat_manip_type maniptype,

            const struct ip_conntrack *conntrack)

{

       static u_int16_t port;

       __be16 *portptr;

       unsigned int range_size, min, i;

 

       if (maniptype == IP_NAT_MANIP_SRC)

           portptr =&tuple->src.u.udp.port;

       else

           portptr =&tuple->dst.u.udp.port;

 

       /* If no range specified... */

       if (!(range->flags &IP_NAT_RANGE_PROTO_SPECIFIED)) {

           /* If it's dst rewrite, can't changeport */

           if (maniptype == IP_NAT_MANIP_DST)

                       return 0;

 

           if (ntohs(*portptr) < 1024) {

                       /* Loose convention:>> 512 is credential passing */

                       if(ntohs(*portptr)<512) {

                                   min = 1;

                                   range_size =511 - min + 1;

                       } else {

                                   min = 600;

                                   range_size =1023 - min + 1;

                       }

           } else {

                       min = 1024;

                       range_size = 65535 - 1024+ 1;

           }

       } else {

           min = ntohs(range->min.udp.port);

           range_size =ntohs(range->max.udp.port) - min + 1;

       }

 

       /* Start from random port to avoidprediction */

       if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)

           port = net_random();

 

       for (i = 0; i < range_size; i++,port++) {

           *portptr = htons(min + port %range_size);

           if (!ip_nat_used_tuple(tuple,conntrack))

                       return 1;

       }

       return 0;

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值