我是靠谱客的博主 俏皮枕头,这篇文章主要介绍linux内核协议栈 netfilter 之连接跟踪子系统初始化1 连接跟踪模块概述2 核心初始化入口 module_init(nf_conntrack_standalone_init);3 核心初始化 nf_conntrack_init(),现在分享给大家,希望可以做个参考。
目录
1 连接跟踪模块概述
2 核心初始化入口 module_init(nf_conntrack_standalone_init);
2.1 创建/proc/net/nf_conntrack只读文件 nf_conntrack_standalone_init_proc()
2.2 注册 /proc/sys/ 下相关文件
3 核心初始化 nf_conntrack_init()
3.1 hash表大小计算、L3L4协议栈模块、helper模块初始化
3.1.1 L3L4协议栈模块初始化
3.1.2 helper 模块初始化
3.2 hash表初始化、期望连接子模块初始化
3.2.1 期望连接子模块初始化
1 连接跟踪模块概述
连接跟踪模块的初始化过程分别在三个地方进行:
- 一个用于创建连接跟踪项与期望连接项相关的slab缓存;
- 一个用于注册连接跟踪模块相关的hook回调函数;
- 一个用于注册连接跟踪中协议相关的变量。
连接跟踪模块的意义:
- 连接跟踪模块的helper结构能够实现期望连接的建立以及相关协议的ALG功能。
- 连接跟踪为NAT或者状态防火墙的实现提供了依据
2 核心初始化入口 module_init(nf_conntrack_standalone_init);
nf_conntrack_standalone_init() 除了在/proc文件系统下面创建一些节点外,核心的初始化过程都是调用nf_conntrack_init()完成的。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51static int nf_conntrack_net_init(struct net *net) { int ret; //连接跟踪子系统的核心初始化过程 ret = nf_conntrack_init(net); if (ret < 0) goto out_init; ret = nf_conntrack_standalone_init_proc(net); if (ret < 0) goto out_proc; net->ct.sysctl_checksum = 1; net->ct.sysctl_log_invalid = 0; ret = nf_conntrack_standalone_init_sysctl(net); if (ret < 0) goto out_sysctl; return 0; out_sysctl: nf_conntrack_standalone_fini_proc(net); out_proc: nf_conntrack_cleanup(net); out_init: return ret; } static void nf_conntrack_net_exit(struct net *net) { nf_conntrack_standalone_fini_sysctl(net); nf_conntrack_standalone_fini_proc(net); nf_conntrack_cleanup(net); } static struct pernet_operations nf_conntrack_net_ops = { .init = nf_conntrack_net_init, .exit = nf_conntrack_net_exit, }; static int __init nf_conntrack_standalone_init(void) { return register_pernet_subsys(&nf_conntrack_net_ops); } static void __exit nf_conntrack_standalone_fini(void) { unregister_pernet_subsys(&nf_conntrack_net_ops); } module_init(nf_conntrack_standalone_init); module_exit(nf_conntrack_standalone_fini);
2.1 创建/proc/net/nf_conntrack只读文件 nf_conntrack_standalone_init_proc()
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22static int nf_conntrack_standalone_init_proc(struct net *net) { struct proc_dir_entry *pde; //创建/proc/net/nf_conntrack文件,该文件只读, //读取该文件可以获取当前内核中跟踪的所有连接的信息 pde = proc_net_fops_create(net, "nf_conntrack", 0440, &ct_file_ops); if (!pde) goto out_nf_conntrack; //创建/proc/net/stat/nf_conntrack文件,获取连接跟踪子系统的统计信息 pde = proc_create("nf_conntrack", S_IRUGO, net->proc_net_stat, &ct_cpu_seq_fops); if (!pde) goto out_stat_nf_conntrack; return 0; out_stat_nf_conntrack: proc_net_remove(net, "nf_conntrack"); out_nf_conntrack: return -ENOMEM; }
2.2 注册 /proc/sys/ 下相关文件
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37static int nf_conntrack_standalone_init_sysctl(struct net *net) { struct ctl_table *table; //在/proc/sys/net/netfilter子目录,暴露一部分内核变量给用户态 if (net_eq(net, &init_net)) { nf_ct_netfilter_header = register_sysctl_paths(nf_ct_path, nf_ct_netfilter_table); if (!nf_ct_netfilter_header) goto out; } table = kmemdup(nf_ct_sysctl_table, sizeof(nf_ct_sysctl_table), GFP_KERNEL); if (!table) goto out_kmemdup; table[1].data = &net->ct.count; table[3].data = &net->ct.sysctl_checksum; table[4].data = &net->ct.sysctl_log_invalid; net->ct.sysctl_header = register_net_sysctl_table(net, nf_net_netfilter_sysctl_path, table); if (!net->ct.sysctl_header) goto out_unregister_netfilter; return 0; out_unregister_netfilter: kfree(table); out_kmemdup: if (net_eq(net, &init_net)) unregister_sysctl_table(nf_ct_netfilter_header); out: printk("nf_conntrack: can't register to sysctl.n"); return -ENOMEM; }
3 核心初始化 nf_conntrack_init()
该接口的核心功能:
- 设置nf_conntrack_htable_size、nf_conntrack_max的值;
- 为 nf_conntrack_hash 申请内存并初始化;
- 为连接跟踪项与期望连接跟踪项创建slab缓存。
- 初始化协议栈管理子模块、期望连接子模块、helper子模块
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26int nf_conntrack_init(struct net *net) { int ret; if (net_eq(net, &init_net)) { ret = nf_conntrack_init_init_net(); if (ret < 0) goto out_init_net; } ret = nf_conntrack_init_net(net); if (ret < 0) goto out_net; if (net_eq(net, &init_net)) { /* For use by REJECT target */ rcu_assign_pointer(ip_ct_attach, nf_conntrack_attach); rcu_assign_pointer(nf_ct_destroy, destroy_conntrack); } return 0; out_net: if (net_eq(net, &init_net)) nf_conntrack_cleanup_init_net(); out_init_net: return ret; }
3.1 hash表大小计算、L3L4协议栈模块、helper模块初始化
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54static int nf_conntrack_init_init_net(void) { int max_factor = 8; int ret; /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB * machine has 512 buckets. >= 1GB machines have 16384 buckets. */ /* 当nf_conntrack_htable_size的值没有设置时,则在内存小于1GB时, 使用内存的1/16384作为hash数组的最大值;在内存大于1GB时 则最大hash数组的值为8192*/ if (!nf_conntrack_htable_size) { nf_conntrack_htable_size = (((num_physpages << PAGE_SHIFT) / 16384) / sizeof(struct hlist_head)); if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) nf_conntrack_htable_size = 16384; if (nf_conntrack_htable_size < 32) nf_conntrack_htable_size = 32; /* Use a max. factor of four by default to get the same max as * with the old struct list_heads. When a table size is given * we use the old value of 8 to avoid reducing the max. * entries. */ max_factor = 4; } /* 设置nf_conntrack_max的值,即连接跟踪项的最大值。 该值取决于nf_conntrack_hash[]数组的最大值,即为 nf_conntrack_htable_size的8倍。*/ nf_conntrack_max = max_factor * nf_conntrack_htable_size; ... //为连接跟踪信息块struct nf_conn创建高速缓存 nf_conntrack_cachep = kmem_cache_create("nf_conntrack", sizeof(struct nf_conn), 0, 0, NULL); if (!nf_conntrack_cachep) { printk(KERN_ERR "Unable to create nf_conn slab cachen"); ret = -ENOMEM; goto err_cache; } //初始化协议管理子模块 ret = nf_conntrack_proto_init(); if (ret < 0) goto err_proto; //初始化helper子模块 ret = nf_conntrack_helper_init(); if (ret < 0) goto err_helper; return 0; ... }
3.1.1 L3L4协议栈模块初始化
参见xxx
3.1.2 helper 模块初始化
参见xxxx
3.2 hash表初始化、期望连接子模块初始化
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43static int nf_conntrack_init_net(struct net *net) { int ret; atomic_set(&net->ct.count, 0); INIT_HLIST_HEAD(&net->ct.unconfirmed); net->ct.stat = alloc_percpu(struct ip_conntrack_stat); if (!net->ct.stat) { ret = -ENOMEM; goto err_stat; } ret = nf_conntrack_ecache_init(net); if (ret < 0) goto err_ecache; //hash链表的初始化,申请 nf_conntrack_htable_size 个hash链表 net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, &net->ct.hash_vmalloc); if (!net->ct.hash) { ret = -ENOMEM; printk(KERN_ERR "Unable to create nf_conntrack_hashn"); goto err_hash; } //初始化期望连接子模块 ret = nf_conntrack_expect_init(net); if (ret < 0) goto err_expect; ret = nf_conntrack_acct_init(net); if (ret < 0) goto err_acct; /* Set up fake conntrack: - to never be deleted, not in any hashes */ #ifdef CONFIG_NET_NS nf_conntrack_untracked.ct_net = &init_net; #endif atomic_set(&nf_conntrack_untracked.ct_general.use, 1); /* - and look it like as a confirmed connection */ set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status); return 0; .... }
3.2.1 期望连接子模块初始化
参见xxx
最后
以上就是俏皮枕头最近收集整理的关于linux内核协议栈 netfilter 之连接跟踪子系统初始化1 连接跟踪模块概述2 核心初始化入口 module_init(nf_conntrack_standalone_init);3 核心初始化 nf_conntrack_init()的全部内容,更多相关linux内核协议栈内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复