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)\n",
 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\n");
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\n");
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.\n");
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\n",
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钩子函数;

猜你喜欢

转载自www.cnblogs.com/wanpengcoder/p/11755688.html
今日推荐