zoukankan      html  css  js  c++  java
  • Netfilter 之 连接跟踪初始化

    基础参数初始化

    nf_conntrack_init_start函数完成连接跟踪基础参数的初始化,包括了hash,slab,扩展项,GC任务等;

      1 int nf_conntrack_init_start(void)
      2 {
      3     int max_factor = 8;
      4     int ret = -ENOMEM;
      5     int i;
      6 
      7     /* struct nf_ct_ext uses u8 to store offsets/size */
      8     BUILD_BUG_ON(total_extension_size() > 255u);
      9 
     10     seqcount_init(&nf_conntrack_generation);
     11 
     12     for (i = 0; i < CONNTRACK_LOCKS; i++)
     13         spin_lock_init(&nf_conntrack_locks[i]);
     14 
     15     /* 根据内存大小,初始化htable_size */
     16     if (!nf_conntrack_htable_size) {
     17         /* Idea from tcp.c: use 1/16384 of memory.
     18          * On i386: 32MB machine has 512 buckets.
     19          * >= 1GB machines have 16384 buckets.
     20          * >= 4GB machines have 65536 buckets.
     21          */
     22         nf_conntrack_htable_size
     23             = (((totalram_pages << PAGE_SHIFT) / 16384)
     24                / sizeof(struct hlist_head));
     25         if (totalram_pages > (4 * (1024 * 1024 * 1024 / PAGE_SIZE)))
     26             nf_conntrack_htable_size = 65536;
     27         else if (totalram_pages > (1024 * 1024 * 1024 / PAGE_SIZE))
     28             nf_conntrack_htable_size = 16384;
     29         if (nf_conntrack_htable_size < 32)
     30             nf_conntrack_htable_size = 32;
     31 
     32         /* Use a max. factor of four by default to get the same max as
     33          * with the old struct list_heads. When a table size is given
     34          * we use the old value of 8 to avoid reducing the max.
     35          * entries. */
     36         max_factor = 4;
     37     }
     38 
     39     /* 分配hash */
     40     nf_conntrack_hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, 1);
     41     if (!nf_conntrack_hash)
     42         return -ENOMEM;
     43 
     44     /* 设置连接跟踪项的最大值 */
     45     nf_conntrack_max = max_factor * nf_conntrack_htable_size;
     46 
     47     /* 创建nf_conn连接跟踪slab */
     48     nf_conntrack_cachep = kmem_cache_create("nf_conntrack",
     49                         sizeof(struct nf_conn),
     50                         NFCT_INFOMASK + 1,
     51                         SLAB_TYPESAFE_BY_RCU | SLAB_HWCACHE_ALIGN, NULL);
     52     if (!nf_conntrack_cachep)
     53         goto err_cachep;
     54 
     55     printk(KERN_INFO "nf_conntrack version %s (%u buckets, %d max)
    ",
     56            NF_CONNTRACK_VERSION, nf_conntrack_htable_size,
     57            nf_conntrack_max);
     58 
     59     /* 各个扩展项的初始化 */
     60     ret = nf_conntrack_expect_init();
     61     if (ret < 0)
     62         goto err_expect;
     63 
     64     ret = nf_conntrack_acct_init();
     65     if (ret < 0)
     66         goto err_acct;
     67 
     68     ret = nf_conntrack_tstamp_init();
     69     if (ret < 0)
     70         goto err_tstamp;
     71 
     72     ret = nf_conntrack_ecache_init();
     73     if (ret < 0)
     74         goto err_ecache;
     75 
     76     ret = nf_conntrack_timeout_init();
     77     if (ret < 0)
     78         goto err_timeout;
     79 
     80     ret = nf_conntrack_helper_init();
     81     if (ret < 0)
     82         goto err_helper;
     83 
     84     ret = nf_conntrack_labels_init();
     85     if (ret < 0)
     86         goto err_labels;
     87 
     88     ret = nf_conntrack_seqadj_init();
     89     if (ret < 0)
     90         goto err_seqadj;
     91 
     92     /* 初始化nf_ct_l3protos[]初始化为nf_conntrack_l3proto_generic */
     93     ret = nf_conntrack_proto_init();
     94     if (ret < 0)
     95         goto err_proto;
     96 
     97     /* 初始化连接跟踪gc任务 */
     98     conntrack_gc_work_init(&conntrack_gc_work);
     99     queue_delayed_work(system_long_wq, &conntrack_gc_work.dwork, HZ);
    100 
    101     return 0;
    102 
    103 err_proto:
    104     nf_conntrack_seqadj_fini();
    105 err_seqadj:
    106     nf_conntrack_labels_fini();
    107 err_labels:
    108     nf_conntrack_helper_fini();
    109 err_helper:
    110     nf_conntrack_timeout_fini();
    111 err_timeout:
    112     nf_conntrack_ecache_fini();
    113 err_ecache:
    114     nf_conntrack_tstamp_fini();
    115 err_tstamp:
    116     nf_conntrack_acct_fini();
    117 err_acct:
    118     nf_conntrack_expect_fini();
    119 err_expect:
    120     kmem_cache_destroy(nf_conntrack_cachep);
    121 err_cachep:
    122     nf_ct_free_hashtable(nf_conntrack_hash, nf_conntrack_htable_size);
    123     return ret;
    124 }
    协议与tuple操作初始化

    nf_conntrack_l3proto_ipv4_init函数完成了协议和tuple操作函数相关的初始化;

     1 static int __init nf_conntrack_l3proto_ipv4_init(void)
     2 {
     3     int ret = 0;
     4 
     5     need_conntrack();
     6 
     7     ret = nf_register_sockopt(&so_getorigdst);
     8     if (ret < 0) {
     9         pr_err("Unable to register netfilter socket option
    ");
    10         return ret;
    11     }
    12 
    13     ret = register_pernet_subsys(&ipv4_net_ops);
    14     if (ret < 0) {
    15         pr_err("nf_conntrack_ipv4: can't register pernet ops
    ");
    16         goto cleanup_sockopt;
    17     }
    18 
    19     /* nf_conntrack_l4proto相关初始化 */
    20     ret = nf_ct_l4proto_register(builtin_l4proto4,
    21                      ARRAY_SIZE(builtin_l4proto4));
    22     if (ret < 0)
    23         goto cleanup_pernet;
    24 
    25     /* nf_conntrack_l3proto相关初始化 */
    26     ret = nf_ct_l3proto_register(&nf_conntrack_l3proto_ipv4);
    27     if (ret < 0) {
    28         pr_err("nf_conntrack_ipv4: can't register ipv4 proto.
    ");
    29         goto cleanup_l4proto;
    30     }
    31 
    32     return ret;
    33 cleanup_l4proto:
    34     nf_ct_l4proto_unregister(builtin_l4proto4,
    35                  ARRAY_SIZE(builtin_l4proto4));
    36  cleanup_pernet:
    37     unregister_pernet_subsys(&ipv4_net_ops);
    38  cleanup_sockopt:
    39     nf_unregister_sockopt(&so_getorigdst);
    40     return ret;
    41 }
    nf_conntrack_l3proto_ipv4

    nf_conntrack_l3proto_ipv4 结构成员初始化包括了基础信息,tuple的相关操作,钩子函数的注册,注销等,每个函数的作用如下;

     1 struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = {
     2     .l3proto     = PF_INET,
     3     .name         = "ipv4",
     4     .pkt_to_tuple     = ipv4_pkt_to_tuple,
     5     .invert_tuple     = ipv4_invert_tuple,
     6     .print_tuple     = ipv4_print_tuple,
     7     .get_l4proto     = ipv4_get_l4proto,
     8 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
     9     .tuple_to_nlattr = ipv4_tuple_to_nlattr,
    10     .nlattr_tuple_size = ipv4_nlattr_tuple_size,
    11     .nlattr_to_tuple = ipv4_nlattr_to_tuple,
    12     .nla_policy     = ipv4_nla_policy,
    13 #endif
    14     .net_ns_get     = ipv4_hooks_register,
    15     .net_ns_put     = ipv4_hooks_unregister,
    16     .me         = THIS_MODULE,
    17 };
    tuple相关操作
     1 /* 从ip头中获取源目的地址,存入tuple */
     2 static bool ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
     3                   struct nf_conntrack_tuple *tuple)
     4 {
     5     const __be32 *ap;
     6     __be32 _addrs[2];
     7     ap = skb_header_pointer(skb, nhoff + offsetof(struct iphdr, saddr),
     8                 sizeof(u_int32_t) * 2, _addrs);
     9     if (ap == NULL)
    10         return false;
    11 
    12     tuple->src.u3.ip = ap[0];
    13     tuple->dst.u3.ip = ap[1];
    14 
    15     return true;
    16 }
    17 
    18 /* 根据原tuple地址设置新tuple,源目的地址均相反 */
    19 static bool ipv4_invert_tuple(struct nf_conntrack_tuple *tuple,
    20                   const struct nf_conntrack_tuple *orig)
    21 {
    22     tuple->src.u3.ip = orig->dst.u3.ip;
    23     tuple->dst.u3.ip = orig->src.u3.ip;
    24 
    25     return true;
    26 }
    27 
    28 /* 打印tuple的源目的地址 */
    29 static void ipv4_print_tuple(struct seq_file *s,
    30                 const struct nf_conntrack_tuple *tuple)
    31 {
    32     seq_printf(s, "src=%pI4 dst=%pI4 ",
    33            &tuple->src.u3.ip, &tuple->dst.u3.ip);
    34 }
    35 
    36 /* 获取ip头中的协议 */
    37 static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
    38                 unsigned int *dataoff, u_int8_t *protonum)
    39 {
    40     const struct iphdr *iph;
    41     struct iphdr _iph;
    42 
    43     
    44     iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
    45     if (iph == NULL)
    46         return -NF_ACCEPT;
    47 
    48     /* Conntrack defragments packets, we might still see fragments
    49      * inside ICMP packets though. */
    50     if (iph->frag_off & htons(IP_OFFSET))
    51         return -NF_ACCEPT;
    52 
    53     *dataoff = nhoff + (iph->ihl << 2);
    54     *protonum = iph->protocol;
    55 
    56     /* Check bogus IP headers */
    57     if (*dataoff > skb->len) {
    58         pr_debug("nf_conntrack_ipv4: bogus IPv4 packet: "
    59              "nhoff %u, ihl %u, skblen %u
    ",
    60              nhoff, iph->ihl << 2, skb->len);
    61         return -NF_ACCEPT;
    62     }
    63 
    64     return NF_ACCEPT;
    65 }
    netlink与tuple之间的操作
     1 /* 填充tuple的源目的地址到netlink */
     2 static int ipv4_tuple_to_nlattr(struct sk_buff *skb,
     3                 const struct nf_conntrack_tuple *tuple)
     4 {
     5     if (nla_put_in_addr(skb, CTA_IP_V4_SRC, tuple->src.u3.ip) ||
     6         nla_put_in_addr(skb, CTA_IP_V4_DST, tuple->dst.u3.ip))
     7         goto nla_put_failure;
     8     return 0;
     9 
    10 nla_put_failure:
    11     return -1;
    12 }
    13 
    14 static const struct nla_policy ipv4_nla_policy[CTA_IP_MAX+1] = {
    15     [CTA_IP_V4_SRC]    = { .type = NLA_U32 },
    16     [CTA_IP_V4_DST]    = { .type = NLA_U32 },
    17 };
    18 
    19 /* 将netlink中的源目的地址填充到tuple */
    20 static int ipv4_nlattr_to_tuple(struct nlattr *tb[],
    21                 struct nf_conntrack_tuple *t)
    22 {
    23     if (!tb[CTA_IP_V4_SRC] || !tb[CTA_IP_V4_DST])
    24         return -EINVAL;
    25 
    26     t->src.u3.ip = nla_get_in_addr(tb[CTA_IP_V4_SRC]);
    27     t->dst.u3.ip = nla_get_in_addr(tb[CTA_IP_V4_DST]);
    28 
    29     return 0;
    30 }
    31 
    32 /* 获取netlink中的tuple大小 */
    33 static int ipv4_nlattr_tuple_size(void)
    34 {
    35     return nla_policy_len(ipv4_nla_policy, CTA_IP_MAX + 1);
    36 }
    钩子函数的注册

    ipv4_hooks_register钩子函数注册回调,其中分为两步,defrag钩子注册和其他钩子注册;

     1 static int ipv4_hooks_register(struct net *net)
     2 {
     3     struct conntrack4_net *cnet = net_generic(net, conntrack4_net_id);
     4     int err = 0;
     5 
     6     mutex_lock(&register_ipv4_hooks);
     7 
     8     cnet->users++;
     9     if (cnet->users > 1)
    10         goto out_unlock;
    11 
    12     /* defrag钩子函数注册 */
    13     err = nf_defrag_ipv4_enable(net);
    14     if (err) {
    15         cnet->users = 0;
    16         goto out_unlock;
    17     }
    18 
    19     /* 注册netfilter钩子函数 */
    20     err = nf_register_net_hooks(net, ipv4_conntrack_ops,
    21                     ARRAY_SIZE(ipv4_conntrack_ops));
    22 
    23     if (err)
    24         cnet->users = 0;
    25  out_unlock:
    26     mutex_unlock(&register_ipv4_hooks);
    27     return err;
    28 }

    nf_defrag_ipv4_enable为defrag钩子注册流程;

     1 int nf_defrag_ipv4_enable(struct net *net)
     2 {
     3     int err = 0;
     4 
     5     might_sleep();
     6 
     7     if (net->nf.defrag_ipv4)
     8         return 0;
     9 
    10     mutex_lock(&defrag4_mutex);
    11     if (net->nf.defrag_ipv4)
    12         goto out_unlock;
    13 
    14     err = nf_register_net_hooks(net, ipv4_defrag_ops,
    15                     ARRAY_SIZE(ipv4_defrag_ops));
    16     if (err == 0)
    17         net->nf.defrag_ipv4 = true;
    18 
    19  out_unlock:
    20     mutex_unlock(&defrag4_mutex);
    21     return err;
    22 }

    defrag钩子函数;

     1 static struct nf_hook_ops ipv4_defrag_ops[] = {
     2     {
     3         .hook        = ipv4_conntrack_defrag,
     4         .pf        = NFPROTO_IPV4,
     5         .hooknum    = NF_INET_PRE_ROUTING,
     6         .priority    = NF_IP_PRI_CONNTRACK_DEFRAG,
     7     },
     8     {
     9         .hook           = ipv4_conntrack_defrag,
    10         .pf             = NFPROTO_IPV4,
    11         .hooknum        = NF_INET_LOCAL_OUT,
    12         .priority       = NF_IP_PRI_CONNTRACK_DEFRAG,
    13     },
    14 };

    conntrack_in,helper,confirm钩子函数;

  • 相关阅读:
    Ajax技术应用方面
    关于tomcat环境配置的疑惑(tomcat未进行任何环境配置仍成功显示welcome页面)
    jsp中动态include与静态include的区别
    简单说说tomcat7.0的配置
    传统开发模式与Ajax开发模式的区别
    认识Ajax
    tomcat与jdk的关系
    org.hibernate.TransactionException: nested transactions not supported
    解读Tomcat7.0的startup.bat批处理命令
    forward和redirect的区别
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/11755688.html
Copyright © 2011-2022 走看看