Blame view
net/netfilter/nf_conntrack_core.c
50.2 KB
9fb9cbb10 [NETFILTER]: Add ... |
1 2 3 4 5 |
/* Connection state tracking for netfilter. This is separated from, but required by, the NAT layer; it can also be used by an iptables extension. */ /* (C) 1999-2001 Paul `Rusty' Russell |
dc808fe28 [NETFILTER] nf_co... |
6 |
* (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> |
9fb9cbb10 [NETFILTER]: Add ... |
7 |
* (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org> |
f229f6ce4 netfilter: add my... |
8 |
* (C) 2005-2012 Patrick McHardy <kaber@trash.net> |
9fb9cbb10 [NETFILTER]: Add ... |
9 10 11 12 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. |
9fb9cbb10 [NETFILTER]: Add ... |
13 |
*/ |
ccd63c20f netfilter: nf_con... |
14 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
9fb9cbb10 [NETFILTER]: Add ... |
15 16 17 |
#include <linux/types.h> #include <linux/netfilter.h> #include <linux/module.h> |
d43c36dc6 headers: remove s... |
18 |
#include <linux/sched.h> |
9fb9cbb10 [NETFILTER]: Add ... |
19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include <linux/skbuff.h> #include <linux/proc_fs.h> #include <linux/vmalloc.h> #include <linux/stddef.h> #include <linux/slab.h> #include <linux/random.h> #include <linux/jhash.h> #include <linux/err.h> #include <linux/percpu.h> #include <linux/moduleparam.h> #include <linux/notifier.h> #include <linux/kernel.h> #include <linux/netdevice.h> #include <linux/socket.h> |
d7fe0f241 [PATCH] severing ... |
33 |
#include <linux/mm.h> |
d696c7bda netfilter: nf_con... |
34 |
#include <linux/nsproxy.h> |
ea781f197 netfilter: nf_con... |
35 |
#include <linux/rculist_nulls.h> |
9fb9cbb10 [NETFILTER]: Add ... |
36 |
|
9fb9cbb10 [NETFILTER]: Add ... |
37 38 |
#include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack_l3proto.h> |
605dcad6c [NETFILTER]: nf_c... |
39 |
#include <net/netfilter/nf_conntrack_l4proto.h> |
77ab9cff0 [NETFILTER]: nf_c... |
40 |
#include <net/netfilter/nf_conntrack_expect.h> |
9fb9cbb10 [NETFILTER]: Add ... |
41 |
#include <net/netfilter/nf_conntrack_helper.h> |
41d73ec05 netfilter: nf_con... |
42 |
#include <net/netfilter/nf_conntrack_seqadj.h> |
9fb9cbb10 [NETFILTER]: Add ... |
43 |
#include <net/netfilter/nf_conntrack_core.h> |
ecfab2c9f [NETFILTER]: nf_c... |
44 |
#include <net/netfilter/nf_conntrack_extend.h> |
584015727 netfilter: accoun... |
45 |
#include <net/netfilter/nf_conntrack_acct.h> |
a0891aa6a netfilter: conntr... |
46 |
#include <net/netfilter/nf_conntrack_ecache.h> |
5d0aa2ccd netfilter: nf_con... |
47 |
#include <net/netfilter/nf_conntrack_zones.h> |
a992ca2a0 netfilter: nf_con... |
48 |
#include <net/netfilter/nf_conntrack_timestamp.h> |
dd7050724 netfilter: nf_ct_... |
49 |
#include <net/netfilter/nf_conntrack_timeout.h> |
c539f0171 netfilter: add co... |
50 |
#include <net/netfilter/nf_conntrack_labels.h> |
48b1de4c1 netfilter: add SY... |
51 |
#include <net/netfilter/nf_conntrack_synproxy.h> |
e6a7d3c04 netfilter: ctnetl... |
52 |
#include <net/netfilter/nf_nat.h> |
e17b666a4 netfilter: nf_con... |
53 |
#include <net/netfilter/nf_nat_core.h> |
493763684 netfilter: nf_con... |
54 |
#include <net/netfilter/nf_nat_helper.h> |
1b8c8a9f6 netfilter: conntr... |
55 |
#include <net/netns/hash.h> |
9fb9cbb10 [NETFILTER]: Add ... |
56 |
|
dc808fe28 [NETFILTER] nf_co... |
57 |
#define NF_CONNTRACK_VERSION "0.5.0" |
9fb9cbb10 [NETFILTER]: Add ... |
58 |
|
e17b666a4 netfilter: nf_con... |
59 60 |
int (*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct, enum nf_nat_manip_type manip, |
399383246 netfilter: nfnetl... |
61 |
const struct nlattr *attr) __read_mostly; |
e6a7d3c04 netfilter: ctnetl... |
62 |
EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook); |
93bb0ceb7 netfilter: conntr... |
63 64 |
__cacheline_aligned_in_smp spinlock_t nf_conntrack_locks[CONNTRACK_LOCKS]; EXPORT_SYMBOL_GPL(nf_conntrack_locks); |
9fb9cbb10 [NETFILTER]: Add ... |
65 |
|
ca7433df3 netfilter: conntr... |
66 67 |
__cacheline_aligned_in_smp DEFINE_SPINLOCK(nf_conntrack_expect_lock); EXPORT_SYMBOL_GPL(nf_conntrack_expect_lock); |
56d52d489 netfilter: conntr... |
68 69 |
struct hlist_nulls_head *nf_conntrack_hash __read_mostly; EXPORT_SYMBOL_GPL(nf_conntrack_hash); |
0c5366b3a netfilter: conntr... |
70 |
static __read_mostly struct kmem_cache *nf_conntrack_cachep; |
b16c29191 netfilter: nf_con... |
71 |
static __read_mostly spinlock_t nf_conntrack_locks_all_lock; |
a3efd8120 netfilter: conntr... |
72 |
static __read_mostly seqcount_t nf_conntrack_generation; |
70d72b7e0 netfilter: conntr... |
73 |
static __read_mostly DEFINE_SPINLOCK(nf_conntrack_locks_all_lock); |
b16c29191 netfilter: nf_con... |
74 75 76 77 78 79 80 |
static __read_mostly bool nf_conntrack_locks_all; void nf_conntrack_lock(spinlock_t *lock) __acquires(lock) { spin_lock(lock); while (unlikely(nf_conntrack_locks_all)) { spin_unlock(lock); |
e39365be0 netfilter: nf_con... |
81 |
spin_unlock_wait(&nf_conntrack_locks_all_lock); |
b16c29191 netfilter: nf_con... |
82 83 84 85 |
spin_lock(lock); } } EXPORT_SYMBOL_GPL(nf_conntrack_lock); |
93bb0ceb7 netfilter: conntr... |
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
static void nf_conntrack_double_unlock(unsigned int h1, unsigned int h2) { h1 %= CONNTRACK_LOCKS; h2 %= CONNTRACK_LOCKS; spin_unlock(&nf_conntrack_locks[h1]); if (h1 != h2) spin_unlock(&nf_conntrack_locks[h2]); } /* return true if we need to recompute hashes (in case hash table was resized) */ static bool nf_conntrack_double_lock(struct net *net, unsigned int h1, unsigned int h2, unsigned int sequence) { h1 %= CONNTRACK_LOCKS; h2 %= CONNTRACK_LOCKS; if (h1 <= h2) { |
b16c29191 netfilter: nf_con... |
102 |
nf_conntrack_lock(&nf_conntrack_locks[h1]); |
93bb0ceb7 netfilter: conntr... |
103 104 105 106 |
if (h1 != h2) spin_lock_nested(&nf_conntrack_locks[h2], SINGLE_DEPTH_NESTING); } else { |
b16c29191 netfilter: nf_con... |
107 |
nf_conntrack_lock(&nf_conntrack_locks[h2]); |
93bb0ceb7 netfilter: conntr... |
108 109 110 |
spin_lock_nested(&nf_conntrack_locks[h1], SINGLE_DEPTH_NESTING); } |
a3efd8120 netfilter: conntr... |
111 |
if (read_seqcount_retry(&nf_conntrack_generation, sequence)) { |
93bb0ceb7 netfilter: conntr... |
112 113 114 115 116 117 118 119 120 |
nf_conntrack_double_unlock(h1, h2); return true; } return false; } static void nf_conntrack_all_lock(void) { int i; |
b16c29191 netfilter: nf_con... |
121 122 123 124 |
spin_lock(&nf_conntrack_locks_all_lock); nf_conntrack_locks_all = true; for (i = 0; i < CONNTRACK_LOCKS; i++) { |
e39365be0 netfilter: nf_con... |
125 |
spin_unlock_wait(&nf_conntrack_locks[i]); |
b16c29191 netfilter: nf_con... |
126 |
} |
93bb0ceb7 netfilter: conntr... |
127 128 129 130 |
} static void nf_conntrack_all_unlock(void) { |
b16c29191 netfilter: nf_con... |
131 132 |
nf_conntrack_locks_all = false; spin_unlock(&nf_conntrack_locks_all_lock); |
93bb0ceb7 netfilter: conntr... |
133 |
} |
e2b7606cd [NETFILTER]: More... |
134 |
unsigned int nf_conntrack_htable_size __read_mostly; |
13b183391 [NETFILTER]: nf_c... |
135 |
EXPORT_SYMBOL_GPL(nf_conntrack_htable_size); |
e478075c6 netfilter: nf_con... |
136 |
unsigned int nf_conntrack_max __read_mostly; |
a999e6837 [NETFILTER]: nf_c... |
137 |
EXPORT_SYMBOL_GPL(nf_conntrack_max); |
13b183391 [NETFILTER]: nf_c... |
138 |
|
b3c5163fe netfilter: nf_con... |
139 140 |
DEFINE_PER_CPU(struct nf_conn, nf_conntrack_untracked); EXPORT_PER_CPU_SYMBOL(nf_conntrack_untracked); |
13b183391 [NETFILTER]: nf_c... |
141 |
|
141658fb0 netfilter: conntr... |
142 |
static unsigned int nf_conntrack_hash_rnd __read_mostly; |
9fb9cbb10 [NETFILTER]: Add ... |
143 |
|
1b8c8a9f6 netfilter: conntr... |
144 145 |
static u32 hash_conntrack_raw(const struct nf_conntrack_tuple *tuple, const struct net *net) |
9fb9cbb10 [NETFILTER]: Add ... |
146 |
{ |
0794935e2 [NETFILTER]: nf_c... |
147 |
unsigned int n; |
1b8c8a9f6 netfilter: conntr... |
148 |
u32 seed; |
0794935e2 [NETFILTER]: nf_c... |
149 |
|
141658fb0 netfilter: conntr... |
150 |
get_random_once(&nf_conntrack_hash_rnd, sizeof(nf_conntrack_hash_rnd)); |
0794935e2 [NETFILTER]: nf_c... |
151 152 153 154 |
/* The direction must be ignored, so we hash everything up to the * destination ports (which is a multiple of 4) and treat the last * three bytes manually. */ |
1b8c8a9f6 netfilter: conntr... |
155 |
seed = nf_conntrack_hash_rnd ^ net_hash_mix(net); |
0794935e2 [NETFILTER]: nf_c... |
156 |
n = (sizeof(tuple->src) + sizeof(tuple->dst.u3)) / sizeof(u32); |
1b8c8a9f6 netfilter: conntr... |
157 |
return jhash2((u32 *)tuple, n, seed ^ |
99f07e91b netfilter: save t... |
158 159 160 |
(((__force __u16)tuple->dst.u.all << 16) | tuple->dst.protonum)); } |
56d52d489 netfilter: conntr... |
161 |
static u32 scale_hash(u32 hash) |
99f07e91b netfilter: save t... |
162 |
{ |
56d52d489 netfilter: conntr... |
163 |
return reciprocal_scale(hash, nf_conntrack_htable_size); |
99f07e91b netfilter: save t... |
164 |
} |
0794935e2 [NETFILTER]: nf_c... |
165 |
|
1b8c8a9f6 netfilter: conntr... |
166 167 168 |
static u32 __hash_conntrack(const struct net *net, const struct nf_conntrack_tuple *tuple, unsigned int size) |
99f07e91b netfilter: save t... |
169 |
{ |
1b8c8a9f6 netfilter: conntr... |
170 |
return reciprocal_scale(hash_conntrack_raw(tuple, net), size); |
9fb9cbb10 [NETFILTER]: Add ... |
171 |
} |
1b8c8a9f6 netfilter: conntr... |
172 173 |
static u32 hash_conntrack(const struct net *net, const struct nf_conntrack_tuple *tuple) |
9fb9cbb10 [NETFILTER]: Add ... |
174 |
{ |
56d52d489 netfilter: conntr... |
175 |
return scale_hash(hash_conntrack_raw(tuple, net)); |
9fb9cbb10 [NETFILTER]: Add ... |
176 |
} |
5f2b4c900 [NETFILTER]: nf_c... |
177 |
bool |
9fb9cbb10 [NETFILTER]: Add ... |
178 179 180 181 182 |
nf_ct_get_tuple(const struct sk_buff *skb, unsigned int nhoff, unsigned int dataoff, u_int16_t l3num, u_int8_t protonum, |
a31f1adc0 netfilter: nf_con... |
183 |
struct net *net, |
9fb9cbb10 [NETFILTER]: Add ... |
184 185 |
struct nf_conntrack_tuple *tuple, const struct nf_conntrack_l3proto *l3proto, |
605dcad6c [NETFILTER]: nf_c... |
186 |
const struct nf_conntrack_l4proto *l4proto) |
9fb9cbb10 [NETFILTER]: Add ... |
187 |
{ |
443a70d50 netfilter: nf_con... |
188 |
memset(tuple, 0, sizeof(*tuple)); |
9fb9cbb10 [NETFILTER]: Add ... |
189 190 191 |
tuple->src.l3num = l3num; if (l3proto->pkt_to_tuple(skb, nhoff, tuple) == 0) |
5f2b4c900 [NETFILTER]: nf_c... |
192 |
return false; |
9fb9cbb10 [NETFILTER]: Add ... |
193 194 195 |
tuple->dst.protonum = protonum; tuple->dst.dir = IP_CT_DIR_ORIGINAL; |
a31f1adc0 netfilter: nf_con... |
196 |
return l4proto->pkt_to_tuple(skb, dataoff, net, tuple); |
9fb9cbb10 [NETFILTER]: Add ... |
197 |
} |
13b183391 [NETFILTER]: nf_c... |
198 |
EXPORT_SYMBOL_GPL(nf_ct_get_tuple); |
9fb9cbb10 [NETFILTER]: Add ... |
199 |
|
5f2b4c900 [NETFILTER]: nf_c... |
200 |
bool nf_ct_get_tuplepr(const struct sk_buff *skb, unsigned int nhoff, |
a31f1adc0 netfilter: nf_con... |
201 202 |
u_int16_t l3num, struct net *net, struct nf_conntrack_tuple *tuple) |
e2a3123fb [NETFILTER]: nf_c... |
203 204 205 206 207 208 209 210 211 212 213 214 215 |
{ struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l4proto *l4proto; unsigned int protoff; u_int8_t protonum; int ret; rcu_read_lock(); l3proto = __nf_ct_l3proto_find(l3num); ret = l3proto->get_l4proto(skb, nhoff, &protoff, &protonum); if (ret != NF_ACCEPT) { rcu_read_unlock(); |
5f2b4c900 [NETFILTER]: nf_c... |
216 |
return false; |
e2a3123fb [NETFILTER]: nf_c... |
217 218 219 |
} l4proto = __nf_ct_l4proto_find(l3num, protonum); |
a31f1adc0 netfilter: nf_con... |
220 |
ret = nf_ct_get_tuple(skb, nhoff, protoff, l3num, protonum, net, tuple, |
e2a3123fb [NETFILTER]: nf_c... |
221 222 223 224 225 226 |
l3proto, l4proto); rcu_read_unlock(); return ret; } EXPORT_SYMBOL_GPL(nf_ct_get_tuplepr); |
5f2b4c900 [NETFILTER]: nf_c... |
227 |
bool |
9fb9cbb10 [NETFILTER]: Add ... |
228 229 230 |
nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, const struct nf_conntrack_tuple *orig, const struct nf_conntrack_l3proto *l3proto, |
605dcad6c [NETFILTER]: nf_c... |
231 |
const struct nf_conntrack_l4proto *l4proto) |
9fb9cbb10 [NETFILTER]: Add ... |
232 |
{ |
443a70d50 netfilter: nf_con... |
233 |
memset(inverse, 0, sizeof(*inverse)); |
9fb9cbb10 [NETFILTER]: Add ... |
234 235 236 |
inverse->src.l3num = orig->src.l3num; if (l3proto->invert_tuple(inverse, orig) == 0) |
5f2b4c900 [NETFILTER]: nf_c... |
237 |
return false; |
9fb9cbb10 [NETFILTER]: Add ... |
238 239 240 241 |
inverse->dst.dir = !orig->dst.dir; inverse->dst.protonum = orig->dst.protonum; |
605dcad6c [NETFILTER]: nf_c... |
242 |
return l4proto->invert_tuple(inverse, orig); |
9fb9cbb10 [NETFILTER]: Add ... |
243 |
} |
13b183391 [NETFILTER]: nf_c... |
244 |
EXPORT_SYMBOL_GPL(nf_ct_invert_tuple); |
9fb9cbb10 [NETFILTER]: Add ... |
245 |
|
9fb9cbb10 [NETFILTER]: Add ... |
246 247 248 |
static void clean_from_lists(struct nf_conn *ct) { |
0d53778e8 [NETFILTER]: Conv... |
249 250 |
pr_debug("clean_from_lists(%p) ", ct); |
ea781f197 netfilter: nf_con... |
251 252 |
hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode); |
9fb9cbb10 [NETFILTER]: Add ... |
253 254 |
/* Destroy all pending expectations */ |
c1d10adb4 [NETFILTER]: Add ... |
255 |
nf_ct_remove_expectations(ct); |
9fb9cbb10 [NETFILTER]: Add ... |
256 |
} |
b7779d06f netfilter: conntr... |
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
/* must be called with local_bh_disable */ static void nf_ct_add_to_dying_list(struct nf_conn *ct) { struct ct_pcpu *pcpu; /* add this conntrack to the (per cpu) dying list */ ct->cpu = smp_processor_id(); pcpu = per_cpu_ptr(nf_ct_net(ct)->ct.pcpu_lists, ct->cpu); spin_lock(&pcpu->lock); hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, &pcpu->dying); spin_unlock(&pcpu->lock); } /* must be called with local_bh_disable */ static void nf_ct_add_to_unconfirmed_list(struct nf_conn *ct) { struct ct_pcpu *pcpu; /* add this conntrack to the (per cpu) unconfirmed list */ ct->cpu = smp_processor_id(); pcpu = per_cpu_ptr(nf_ct_net(ct)->ct.pcpu_lists, ct->cpu); spin_lock(&pcpu->lock); hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, &pcpu->unconfirmed); spin_unlock(&pcpu->lock); } /* must be called with local_bh_disable */ static void nf_ct_del_from_dying_or_unconfirmed_list(struct nf_conn *ct) { struct ct_pcpu *pcpu; /* We overload first tuple to link into unconfirmed or dying list.*/ pcpu = per_cpu_ptr(nf_ct_net(ct)->ct.pcpu_lists, ct->cpu); spin_lock(&pcpu->lock); BUG_ON(hlist_nulls_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode)); hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); spin_unlock(&pcpu->lock); } |
0838aa7fc netfilter: fix ne... |
300 |
/* Released via destroy_conntrack() */ |
308ac9143 netfilter: nf_con... |
301 302 303 |
struct nf_conn *nf_ct_tmpl_alloc(struct net *net, const struct nf_conntrack_zone *zone, gfp_t flags) |
0838aa7fc netfilter: fix ne... |
304 305 |
{ struct nf_conn *tmpl; |
f58e5aa7b netfilter: conntr... |
306 |
tmpl = kzalloc(sizeof(*tmpl), flags); |
0838aa7fc netfilter: fix ne... |
307 308 309 310 311 |
if (tmpl == NULL) return NULL; tmpl->status = IPS_TEMPLATE; write_pnet(&tmpl->ct_net, net); |
6c8dee984 netfilter: move z... |
312 |
nf_ct_zone_add(tmpl, zone); |
0838aa7fc netfilter: fix ne... |
313 314 315 |
atomic_set(&tmpl->ct_general.use, 0); return tmpl; |
0838aa7fc netfilter: fix ne... |
316 317 |
} EXPORT_SYMBOL_GPL(nf_ct_tmpl_alloc); |
9cf94eab8 netfilter: conntr... |
318 |
void nf_ct_tmpl_free(struct nf_conn *tmpl) |
0838aa7fc netfilter: fix ne... |
319 320 321 322 323 |
{ nf_ct_ext_destroy(tmpl); nf_ct_ext_free(tmpl); kfree(tmpl); } |
9cf94eab8 netfilter: conntr... |
324 |
EXPORT_SYMBOL_GPL(nf_ct_tmpl_free); |
0838aa7fc netfilter: fix ne... |
325 |
|
9fb9cbb10 [NETFILTER]: Add ... |
326 327 328 329 |
static void destroy_conntrack(struct nf_conntrack *nfct) { struct nf_conn *ct = (struct nf_conn *)nfct; |
0d55af879 netfilter: netns ... |
330 |
struct net *net = nf_ct_net(ct); |
605dcad6c [NETFILTER]: nf_c... |
331 |
struct nf_conntrack_l4proto *l4proto; |
9fb9cbb10 [NETFILTER]: Add ... |
332 |
|
0d53778e8 [NETFILTER]: Conv... |
333 334 |
pr_debug("destroy_conntrack(%p) ", ct); |
9fb9cbb10 [NETFILTER]: Add ... |
335 336 |
NF_CT_ASSERT(atomic_read(&nfct->use) == 0); NF_CT_ASSERT(!timer_pending(&ct->timeout)); |
0838aa7fc netfilter: fix ne... |
337 338 339 340 |
if (unlikely(nf_ct_is_template(ct))) { nf_ct_tmpl_free(ct); return; } |
923f4902f [NETFILTER]: nf_c... |
341 |
rcu_read_lock(); |
5e8fbe2ac [NETFILTER]: nf_c... |
342 |
l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); |
4b4ceb9db netfilter: conntr... |
343 |
if (l4proto->destroy) |
605dcad6c [NETFILTER]: nf_c... |
344 |
l4proto->destroy(ct); |
9fb9cbb10 [NETFILTER]: Add ... |
345 |
|
982d9a9ce [NETFILTER]: nf_c... |
346 |
rcu_read_unlock(); |
9fb9cbb10 [NETFILTER]: Add ... |
347 |
|
ca7433df3 netfilter: conntr... |
348 |
local_bh_disable(); |
9fb9cbb10 [NETFILTER]: Add ... |
349 350 351 |
/* Expectations will have been removed in clean_from_lists, * except TFTP can create an expectation on the first packet, * before connection is in the list, so we need to clean here, |
ca7433df3 netfilter: conntr... |
352 353 |
* too. */ |
c1d10adb4 [NETFILTER]: Add ... |
354 |
nf_ct_remove_expectations(ct); |
9fb9cbb10 [NETFILTER]: Add ... |
355 |
|
b7779d06f netfilter: conntr... |
356 |
nf_ct_del_from_dying_or_unconfirmed_list(ct); |
9fb9cbb10 [NETFILTER]: Add ... |
357 |
|
0d55af879 netfilter: netns ... |
358 |
NF_CT_STAT_INC(net, delete); |
ca7433df3 netfilter: conntr... |
359 |
local_bh_enable(); |
9fb9cbb10 [NETFILTER]: Add ... |
360 361 362 |
if (ct->master) nf_ct_put(ct->master); |
0d53778e8 [NETFILTER]: Conv... |
363 364 |
pr_debug("destroy_conntrack: returning ct=%p to slab ", ct); |
9fb9cbb10 [NETFILTER]: Add ... |
365 366 |
nf_conntrack_free(ct); } |
02982c27b netfilter: nf_con... |
367 |
static void nf_ct_delete_from_lists(struct nf_conn *ct) |
9fb9cbb10 [NETFILTER]: Add ... |
368 |
{ |
0d55af879 netfilter: netns ... |
369 |
struct net *net = nf_ct_net(ct); |
93bb0ceb7 netfilter: conntr... |
370 |
unsigned int hash, reply_hash; |
93bb0ceb7 netfilter: conntr... |
371 |
unsigned int sequence; |
9fb9cbb10 [NETFILTER]: Add ... |
372 |
|
9858a3ae1 netfilter: conntr... |
373 |
nf_ct_helper_destroy(ct); |
93bb0ceb7 netfilter: conntr... |
374 375 376 |
local_bh_disable(); do { |
a3efd8120 netfilter: conntr... |
377 |
sequence = read_seqcount_begin(&nf_conntrack_generation); |
deedb5903 netfilter: nf_con... |
378 |
hash = hash_conntrack(net, |
93bb0ceb7 netfilter: conntr... |
379 |
&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); |
deedb5903 netfilter: nf_con... |
380 |
reply_hash = hash_conntrack(net, |
93bb0ceb7 netfilter: conntr... |
381 382 |
&ct->tuplehash[IP_CT_DIR_REPLY].tuple); } while (nf_conntrack_double_lock(net, hash, reply_hash, sequence)); |
9fb9cbb10 [NETFILTER]: Add ... |
383 |
clean_from_lists(ct); |
93bb0ceb7 netfilter: conntr... |
384 |
nf_conntrack_double_unlock(hash, reply_hash); |
b7779d06f netfilter: conntr... |
385 |
nf_ct_add_to_dying_list(ct); |
93bb0ceb7 netfilter: conntr... |
386 387 388 |
NF_CT_STAT_INC(net, delete_list); local_bh_enable(); |
dd7669a92 netfilter: conntr... |
389 |
} |
dd7669a92 netfilter: conntr... |
390 |
|
02982c27b netfilter: nf_con... |
391 |
bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report) |
dd7669a92 netfilter: conntr... |
392 |
{ |
a992ca2a0 netfilter: nf_con... |
393 394 395 396 |
struct nf_conn_tstamp *tstamp; tstamp = nf_conn_tstamp_find(ct); if (tstamp && tstamp->stop == 0) |
d2de875c6 net: use ktime_ge... |
397 |
tstamp->stop = ktime_get_real_ns(); |
dd7669a92 netfilter: conntr... |
398 |
|
9500507c6 netfilter: conntr... |
399 400 401 402 403 |
if (nf_ct_is_dying(ct)) goto delete; if (nf_conntrack_event_report(IPCT_DESTROY, ct, portid, report) < 0) { |
dd7669a92 netfilter: conntr... |
404 405 |
/* destroy event was not delivered */ nf_ct_delete_from_lists(ct); |
9500507c6 netfilter: conntr... |
406 |
nf_conntrack_ecache_delayed_work(nf_ct_net(ct)); |
02982c27b netfilter: nf_con... |
407 |
return false; |
dd7669a92 netfilter: conntr... |
408 |
} |
9500507c6 netfilter: conntr... |
409 410 |
nf_conntrack_ecache_work(nf_ct_net(ct)); |
dd7669a92 netfilter: conntr... |
411 |
set_bit(IPS_DYING_BIT, &ct->status); |
9500507c6 netfilter: conntr... |
412 |
delete: |
dd7669a92 netfilter: conntr... |
413 |
nf_ct_delete_from_lists(ct); |
9fb9cbb10 [NETFILTER]: Add ... |
414 |
nf_ct_put(ct); |
02982c27b netfilter: nf_con... |
415 416 417 418 419 420 421 |
return true; } EXPORT_SYMBOL_GPL(nf_ct_delete); static void death_by_timeout(unsigned long ul_conntrack) { nf_ct_delete((struct nf_conn *)ul_conntrack, 0, 0); |
9fb9cbb10 [NETFILTER]: Add ... |
422 |
} |
c6825c097 netfilter: nf_con... |
423 424 |
static inline bool nf_ct_key_equal(struct nf_conntrack_tuple_hash *h, |
308ac9143 netfilter: nf_con... |
425 |
const struct nf_conntrack_tuple *tuple, |
e0c7d4722 netfilter: conntr... |
426 427 |
const struct nf_conntrack_zone *zone, const struct net *net) |
c6825c097 netfilter: nf_con... |
428 429 430 431 432 433 434 |
{ struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); /* A conntrack can be recreated with the equal tuple, * so we need to check that the conntrack is confirmed */ return nf_ct_tuple_equal(tuple, &h->tuple) && |
deedb5903 netfilter: nf_con... |
435 |
nf_ct_zone_equal(ct, zone, NF_CT_DIRECTION(h)) && |
e0c7d4722 netfilter: conntr... |
436 437 |
nf_ct_is_confirmed(ct) && net_eq(net, nf_ct_net(ct)); |
c6825c097 netfilter: nf_con... |
438 |
} |
64b87639c netfilter: conntr... |
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 |
/* must be called with rcu read lock held */ void nf_conntrack_get_ht(struct hlist_nulls_head **hash, unsigned int *hsize) { struct hlist_nulls_head *hptr; unsigned int sequence, hsz; do { sequence = read_seqcount_begin(&nf_conntrack_generation); hsz = nf_conntrack_htable_size; hptr = nf_conntrack_hash; } while (read_seqcount_retry(&nf_conntrack_generation, sequence)); *hash = hptr; *hsize = hsz; } EXPORT_SYMBOL_GPL(nf_conntrack_get_ht); |
ea781f197 netfilter: nf_con... |
455 456 457 458 |
/* * Warning : * - Caller must take a reference on returned object * and recheck nf_ct_tuple_equal(tuple, &h->tuple) |
ea781f197 netfilter: nf_con... |
459 |
*/ |
99f07e91b netfilter: save t... |
460 |
static struct nf_conntrack_tuple_hash * |
308ac9143 netfilter: nf_con... |
461 |
____nf_conntrack_find(struct net *net, const struct nf_conntrack_zone *zone, |
99f07e91b netfilter: save t... |
462 |
const struct nf_conntrack_tuple *tuple, u32 hash) |
9fb9cbb10 [NETFILTER]: Add ... |
463 464 |
{ struct nf_conntrack_tuple_hash *h; |
5e3c61f98 netfilter: conntr... |
465 |
struct hlist_nulls_head *ct_hash; |
ea781f197 netfilter: nf_con... |
466 |
struct hlist_nulls_node *n; |
5e3c61f98 netfilter: conntr... |
467 |
unsigned int bucket, sequence; |
9fb9cbb10 [NETFILTER]: Add ... |
468 |
|
ea781f197 netfilter: nf_con... |
469 |
begin: |
5e3c61f98 netfilter: conntr... |
470 471 |
do { sequence = read_seqcount_begin(&nf_conntrack_generation); |
56d52d489 netfilter: conntr... |
472 473 |
bucket = scale_hash(hash); ct_hash = nf_conntrack_hash; |
5e3c61f98 netfilter: conntr... |
474 475 476 |
} while (read_seqcount_retry(&nf_conntrack_generation, sequence)); hlist_nulls_for_each_entry_rcu(h, n, &ct_hash[bucket], hnnode) { |
e0c7d4722 netfilter: conntr... |
477 |
if (nf_ct_key_equal(h, tuple, zone, net)) { |
2cf123480 netfilter: conntr... |
478 |
NF_CT_STAT_INC_ATOMIC(net, found); |
9fb9cbb10 [NETFILTER]: Add ... |
479 480 |
return h; } |
2cf123480 netfilter: conntr... |
481 |
NF_CT_STAT_INC_ATOMIC(net, searched); |
9fb9cbb10 [NETFILTER]: Add ... |
482 |
} |
ea781f197 netfilter: nf_con... |
483 484 485 486 487 |
/* * if the nulls value we got at the end of this lookup is * not the expected one, we must restart lookup. * We probably met an item that was moved to another chain. */ |
99f07e91b netfilter: save t... |
488 |
if (get_nulls_value(n) != bucket) { |
2cf123480 netfilter: conntr... |
489 |
NF_CT_STAT_INC_ATOMIC(net, search_restart); |
ea781f197 netfilter: nf_con... |
490 |
goto begin; |
af740b2c8 netfilter: nf_con... |
491 |
} |
9fb9cbb10 [NETFILTER]: Add ... |
492 493 494 |
return NULL; } |
99f07e91b netfilter: save t... |
495 |
|
9fb9cbb10 [NETFILTER]: Add ... |
496 |
/* Find a connection corresponding to a tuple. */ |
99f07e91b netfilter: save t... |
497 |
static struct nf_conntrack_tuple_hash * |
308ac9143 netfilter: nf_con... |
498 |
__nf_conntrack_find_get(struct net *net, const struct nf_conntrack_zone *zone, |
99f07e91b netfilter: save t... |
499 |
const struct nf_conntrack_tuple *tuple, u32 hash) |
9fb9cbb10 [NETFILTER]: Add ... |
500 501 |
{ struct nf_conntrack_tuple_hash *h; |
76507f69c [NETFILTER]: nf_c... |
502 |
struct nf_conn *ct; |
9fb9cbb10 [NETFILTER]: Add ... |
503 |
|
76507f69c [NETFILTER]: nf_c... |
504 |
rcu_read_lock(); |
ea781f197 netfilter: nf_con... |
505 |
begin: |
99f07e91b netfilter: save t... |
506 |
h = ____nf_conntrack_find(net, zone, tuple, hash); |
76507f69c [NETFILTER]: nf_c... |
507 508 |
if (h) { ct = nf_ct_tuplehash_to_ctrack(h); |
8d8890b77 netfilter: nf_con... |
509 510 |
if (unlikely(nf_ct_is_dying(ct) || !atomic_inc_not_zero(&ct->ct_general.use))) |
76507f69c [NETFILTER]: nf_c... |
511 |
h = NULL; |
ea781f197 netfilter: nf_con... |
512 |
else { |
e0c7d4722 netfilter: conntr... |
513 |
if (unlikely(!nf_ct_key_equal(h, tuple, zone, net))) { |
ea781f197 netfilter: nf_con... |
514 515 516 517 |
nf_ct_put(ct); goto begin; } } |
76507f69c [NETFILTER]: nf_c... |
518 519 |
} rcu_read_unlock(); |
9fb9cbb10 [NETFILTER]: Add ... |
520 521 522 |
return h; } |
99f07e91b netfilter: save t... |
523 524 |
struct nf_conntrack_tuple_hash * |
308ac9143 netfilter: nf_con... |
525 |
nf_conntrack_find_get(struct net *net, const struct nf_conntrack_zone *zone, |
99f07e91b netfilter: save t... |
526 527 528 |
const struct nf_conntrack_tuple *tuple) { return __nf_conntrack_find_get(net, zone, tuple, |
1b8c8a9f6 netfilter: conntr... |
529 |
hash_conntrack_raw(tuple, net)); |
99f07e91b netfilter: save t... |
530 |
} |
13b183391 [NETFILTER]: nf_c... |
531 |
EXPORT_SYMBOL_GPL(nf_conntrack_find_get); |
9fb9cbb10 [NETFILTER]: Add ... |
532 |
|
c1d10adb4 [NETFILTER]: Add ... |
533 534 |
static void __nf_conntrack_hash_insert(struct nf_conn *ct, unsigned int hash, |
b476b72a0 netfilter: trivia... |
535 |
unsigned int reply_hash) |
c1d10adb4 [NETFILTER]: Add ... |
536 |
{ |
ea781f197 netfilter: nf_con... |
537 |
hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, |
56d52d489 netfilter: conntr... |
538 |
&nf_conntrack_hash[hash]); |
ea781f197 netfilter: nf_con... |
539 |
hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode, |
56d52d489 netfilter: conntr... |
540 |
&nf_conntrack_hash[reply_hash]); |
c1d10adb4 [NETFILTER]: Add ... |
541 |
} |
7d367e066 netfilter: ctnetl... |
542 543 |
int nf_conntrack_hash_check_insert(struct nf_conn *ct) |
c1d10adb4 [NETFILTER]: Add ... |
544 |
{ |
308ac9143 netfilter: nf_con... |
545 |
const struct nf_conntrack_zone *zone; |
d696c7bda netfilter: nf_con... |
546 |
struct net *net = nf_ct_net(ct); |
b476b72a0 netfilter: trivia... |
547 |
unsigned int hash, reply_hash; |
7d367e066 netfilter: ctnetl... |
548 549 |
struct nf_conntrack_tuple_hash *h; struct hlist_nulls_node *n; |
93bb0ceb7 netfilter: conntr... |
550 |
unsigned int sequence; |
c1d10adb4 [NETFILTER]: Add ... |
551 |
|
5d0aa2ccd netfilter: nf_con... |
552 |
zone = nf_ct_zone(ct); |
7d367e066 netfilter: ctnetl... |
553 |
|
93bb0ceb7 netfilter: conntr... |
554 555 |
local_bh_disable(); do { |
a3efd8120 netfilter: conntr... |
556 |
sequence = read_seqcount_begin(&nf_conntrack_generation); |
deedb5903 netfilter: nf_con... |
557 |
hash = hash_conntrack(net, |
93bb0ceb7 netfilter: conntr... |
558 |
&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); |
deedb5903 netfilter: nf_con... |
559 |
reply_hash = hash_conntrack(net, |
93bb0ceb7 netfilter: conntr... |
560 561 |
&ct->tuplehash[IP_CT_DIR_REPLY].tuple); } while (nf_conntrack_double_lock(net, hash, reply_hash, sequence)); |
7d367e066 netfilter: ctnetl... |
562 563 |
/* See if there's one in the list already, including reverse */ |
56d52d489 netfilter: conntr... |
564 |
hlist_nulls_for_each_entry(h, n, &nf_conntrack_hash[hash], hnnode) |
868043485 netfilter: conntr... |
565 |
if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
e0c7d4722 netfilter: conntr... |
566 |
zone, net)) |
7d367e066 netfilter: ctnetl... |
567 |
goto out; |
868043485 netfilter: conntr... |
568 |
|
56d52d489 netfilter: conntr... |
569 |
hlist_nulls_for_each_entry(h, n, &nf_conntrack_hash[reply_hash], hnnode) |
868043485 netfilter: conntr... |
570 |
if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, |
e0c7d4722 netfilter: conntr... |
571 |
zone, net)) |
7d367e066 netfilter: ctnetl... |
572 |
goto out; |
c1d10adb4 [NETFILTER]: Add ... |
573 |
|
7d367e066 netfilter: ctnetl... |
574 |
add_timer(&ct->timeout); |
e53376bef netfilter: nf_con... |
575 576 577 |
smp_wmb(); /* The caller holds a reference to this object */ atomic_set(&ct->ct_general.use, 2); |
b476b72a0 netfilter: trivia... |
578 |
__nf_conntrack_hash_insert(ct, hash, reply_hash); |
93bb0ceb7 netfilter: conntr... |
579 |
nf_conntrack_double_unlock(hash, reply_hash); |
7d367e066 netfilter: ctnetl... |
580 |
NF_CT_STAT_INC(net, insert); |
93bb0ceb7 netfilter: conntr... |
581 |
local_bh_enable(); |
7d367e066 netfilter: ctnetl... |
582 583 584 |
return 0; out: |
93bb0ceb7 netfilter: conntr... |
585 |
nf_conntrack_double_unlock(hash, reply_hash); |
7d367e066 netfilter: ctnetl... |
586 |
NF_CT_STAT_INC(net, insert_failed); |
93bb0ceb7 netfilter: conntr... |
587 |
local_bh_enable(); |
7d367e066 netfilter: ctnetl... |
588 |
return -EEXIST; |
c1d10adb4 [NETFILTER]: Add ... |
589 |
} |
7d367e066 netfilter: ctnetl... |
590 |
EXPORT_SYMBOL_GPL(nf_conntrack_hash_check_insert); |
c1d10adb4 [NETFILTER]: Add ... |
591 |
|
ba76738c0 netfilter: conntr... |
592 593 594 595 596 597 598 599 600 601 602 603 604 605 |
static inline void nf_ct_acct_update(struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned int len) { struct nf_conn_acct *acct; acct = nf_conn_acct_find(ct); if (acct) { struct nf_conn_counter *counter = acct->counter; atomic64_inc(&counter[CTINFO2DIR(ctinfo)].packets); atomic64_add(len, &counter[CTINFO2DIR(ctinfo)].bytes); } } |
71d8c47fc netfilter: conntr... |
606 607 608 609 610 611 612 613 |
static void nf_ct_acct_merge(struct nf_conn *ct, enum ip_conntrack_info ctinfo, const struct nf_conn *loser_ct) { struct nf_conn_acct *acct; acct = nf_conn_acct_find(loser_ct); if (acct) { struct nf_conn_counter *counter = acct->counter; |
71d8c47fc netfilter: conntr... |
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 |
unsigned int bytes; /* u32 should be fine since we must have seen one packet. */ bytes = atomic64_read(&counter[CTINFO2DIR(ctinfo)].bytes); nf_ct_acct_update(ct, ctinfo, bytes); } } /* Resolve race on insertion if this protocol allows this. */ static int nf_ct_resolve_clash(struct net *net, struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conntrack_tuple_hash *h) { /* This is the conntrack entry already in hashes that won race. */ struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); struct nf_conntrack_l4proto *l4proto; l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); if (l4proto->allow_clash && !nf_ct_is_dying(ct) && atomic_inc_not_zero(&ct->ct_general.use)) { nf_ct_acct_merge(ct, ctinfo, (struct nf_conn *)skb->nfct); nf_conntrack_put(skb->nfct); /* Assign conntrack already in hashes to this skbuff. Don't * modify skb->nfctinfo to ensure consistent stateful filtering. */ skb->nfct = &ct->ct_general; return NF_ACCEPT; } NF_CT_STAT_INC(net, drop); return NF_DROP; } |
9fb9cbb10 [NETFILTER]: Add ... |
646 647 |
/* Confirm a connection given skb; places it in hash table */ int |
3db05fea5 [NETFILTER]: Repl... |
648 |
__nf_conntrack_confirm(struct sk_buff *skb) |
9fb9cbb10 [NETFILTER]: Add ... |
649 |
{ |
308ac9143 netfilter: nf_con... |
650 |
const struct nf_conntrack_zone *zone; |
b476b72a0 netfilter: trivia... |
651 |
unsigned int hash, reply_hash; |
df0933dcb [NETFILTER]: kill... |
652 |
struct nf_conntrack_tuple_hash *h; |
9fb9cbb10 [NETFILTER]: Add ... |
653 |
struct nf_conn *ct; |
df0933dcb [NETFILTER]: kill... |
654 |
struct nf_conn_help *help; |
a992ca2a0 netfilter: nf_con... |
655 |
struct nf_conn_tstamp *tstamp; |
ea781f197 netfilter: nf_con... |
656 |
struct hlist_nulls_node *n; |
9fb9cbb10 [NETFILTER]: Add ... |
657 |
enum ip_conntrack_info ctinfo; |
400dad39d netfilter: netns ... |
658 |
struct net *net; |
93bb0ceb7 netfilter: conntr... |
659 |
unsigned int sequence; |
71d8c47fc netfilter: conntr... |
660 |
int ret = NF_DROP; |
9fb9cbb10 [NETFILTER]: Add ... |
661 |
|
3db05fea5 [NETFILTER]: Repl... |
662 |
ct = nf_ct_get(skb, &ctinfo); |
400dad39d netfilter: netns ... |
663 |
net = nf_ct_net(ct); |
9fb9cbb10 [NETFILTER]: Add ... |
664 665 666 667 668 669 670 |
/* ipt_REJECT uses nf_conntrack_attach to attach related ICMP/TCP RST packets in other direction. Actual packet which created connection will be IP_CT_NEW or for an expected connection, IP_CT_RELATED. */ if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) return NF_ACCEPT; |
5d0aa2ccd netfilter: nf_con... |
671 |
zone = nf_ct_zone(ct); |
93bb0ceb7 netfilter: conntr... |
672 673 674 |
local_bh_disable(); do { |
a3efd8120 netfilter: conntr... |
675 |
sequence = read_seqcount_begin(&nf_conntrack_generation); |
93bb0ceb7 netfilter: conntr... |
676 677 |
/* reuse the hash saved before */ hash = *(unsigned long *)&ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev; |
56d52d489 netfilter: conntr... |
678 |
hash = scale_hash(hash); |
deedb5903 netfilter: nf_con... |
679 |
reply_hash = hash_conntrack(net, |
93bb0ceb7 netfilter: conntr... |
680 681 682 |
&ct->tuplehash[IP_CT_DIR_REPLY].tuple); } while (nf_conntrack_double_lock(net, hash, reply_hash, sequence)); |
9fb9cbb10 [NETFILTER]: Add ... |
683 684 |
/* We're not in hash table, and we refuse to set up related |
93bb0ceb7 netfilter: conntr... |
685 686 687 |
* connections for unconfirmed conns. But packet copies and * REJECT will give spurious warnings here. */ |
9fb9cbb10 [NETFILTER]: Add ... |
688 |
/* NF_CT_ASSERT(atomic_read(&ct->ct_general.use) == 1); */ |
25985edce Fix common misspe... |
689 |
/* No external references means no one else could have |
93bb0ceb7 netfilter: conntr... |
690 691 |
* confirmed us. */ |
9fb9cbb10 [NETFILTER]: Add ... |
692 |
NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); |
0d53778e8 [NETFILTER]: Conv... |
693 694 |
pr_debug("Confirming conntrack %p ", ct); |
8ca3f5e97 netfilter: conntr... |
695 696 697 698 699 700 |
/* We have to check the DYING flag after unlink to prevent * a race against nf_ct_get_next_corpse() possibly called from * user context, else we insert an already 'dead' hash, blocking * further use of that particular connection -JM. */ nf_ct_del_from_dying_or_unconfirmed_list(ct); |
71d8c47fc netfilter: conntr... |
701 702 703 704 |
if (unlikely(nf_ct_is_dying(ct))) { nf_ct_add_to_dying_list(ct); goto dying; } |
fc350777c netfilter: nf_con... |
705 |
|
9fb9cbb10 [NETFILTER]: Add ... |
706 707 708 |
/* See if there's one in the list already, including reverse: NAT could have grabbed it without realizing, since we're not in the hash. If there is, we lost race. */ |
56d52d489 netfilter: conntr... |
709 |
hlist_nulls_for_each_entry(h, n, &nf_conntrack_hash[hash], hnnode) |
868043485 netfilter: conntr... |
710 |
if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
e0c7d4722 netfilter: conntr... |
711 |
zone, net)) |
df0933dcb [NETFILTER]: kill... |
712 |
goto out; |
868043485 netfilter: conntr... |
713 |
|
56d52d489 netfilter: conntr... |
714 |
hlist_nulls_for_each_entry(h, n, &nf_conntrack_hash[reply_hash], hnnode) |
868043485 netfilter: conntr... |
715 |
if (nf_ct_key_equal(h, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, |
e0c7d4722 netfilter: conntr... |
716 |
zone, net)) |
df0933dcb [NETFILTER]: kill... |
717 |
goto out; |
9fb9cbb10 [NETFILTER]: Add ... |
718 |
|
df0933dcb [NETFILTER]: kill... |
719 720 721 722 723 724 |
/* Timer relative to confirmation time, not original setting time, otherwise we'd get timer wrap in weird delay cases. */ ct->timeout.expires += jiffies; add_timer(&ct->timeout); atomic_inc(&ct->ct_general.use); |
45eec3419 netfilter: nf_con... |
725 |
ct->status |= IPS_CONFIRMED; |
5c8ec910e netfilter: nf_con... |
726 |
|
a992ca2a0 netfilter: nf_con... |
727 728 729 730 |
/* set conntrack timestamp, if enabled. */ tstamp = nf_conn_tstamp_find(ct); if (tstamp) { if (skb->tstamp.tv64 == 0) |
e3192690a net: Remove casts... |
731 |
__net_timestamp(skb); |
a992ca2a0 netfilter: nf_con... |
732 733 734 |
tstamp->start = ktime_to_ns(skb->tstamp); } |
5c8ec910e netfilter: nf_con... |
735 736 737 738 739 |
/* Since the lookup is lockless, hash insertion must be done after * starting the timer and setting the CONFIRMED bit. The RCU barriers * guarantee that no other CPU can find the conntrack before the above * stores are visible. */ |
b476b72a0 netfilter: trivia... |
740 |
__nf_conntrack_hash_insert(ct, hash, reply_hash); |
93bb0ceb7 netfilter: conntr... |
741 |
nf_conntrack_double_unlock(hash, reply_hash); |
0d55af879 netfilter: netns ... |
742 |
NF_CT_STAT_INC(net, insert); |
93bb0ceb7 netfilter: conntr... |
743 |
local_bh_enable(); |
5c8ec910e netfilter: nf_con... |
744 |
|
df0933dcb [NETFILTER]: kill... |
745 746 |
help = nfct_help(ct); if (help && help->helper) |
a71996fcc netfilter: netns ... |
747 |
nf_conntrack_event_cache(IPCT_HELPER, ct); |
17e6e4eac netfilter: conntr... |
748 |
|
df0933dcb [NETFILTER]: kill... |
749 |
nf_conntrack_event_cache(master_ct(ct) ? |
a71996fcc netfilter: netns ... |
750 |
IPCT_RELATED : IPCT_NEW, ct); |
df0933dcb [NETFILTER]: kill... |
751 |
return NF_ACCEPT; |
9fb9cbb10 [NETFILTER]: Add ... |
752 |
|
df0933dcb [NETFILTER]: kill... |
753 |
out: |
8ca3f5e97 netfilter: conntr... |
754 |
nf_ct_add_to_dying_list(ct); |
71d8c47fc netfilter: conntr... |
755 756 |
ret = nf_ct_resolve_clash(net, skb, ctinfo, h); dying: |
93bb0ceb7 netfilter: conntr... |
757 |
nf_conntrack_double_unlock(hash, reply_hash); |
0d55af879 netfilter: netns ... |
758 |
NF_CT_STAT_INC(net, insert_failed); |
93bb0ceb7 netfilter: conntr... |
759 |
local_bh_enable(); |
71d8c47fc netfilter: conntr... |
760 |
return ret; |
9fb9cbb10 [NETFILTER]: Add ... |
761 |
} |
13b183391 [NETFILTER]: nf_c... |
762 |
EXPORT_SYMBOL_GPL(__nf_conntrack_confirm); |
9fb9cbb10 [NETFILTER]: Add ... |
763 764 765 766 767 768 769 |
/* Returns true if a connection correspondings to the tuple (required for NAT). */ int nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple, const struct nf_conn *ignored_conntrack) { |
400dad39d netfilter: netns ... |
770 |
struct net *net = nf_ct_net(ignored_conntrack); |
308ac9143 netfilter: nf_con... |
771 |
const struct nf_conntrack_zone *zone; |
9fb9cbb10 [NETFILTER]: Add ... |
772 |
struct nf_conntrack_tuple_hash *h; |
5e3c61f98 netfilter: conntr... |
773 774 |
struct hlist_nulls_head *ct_hash; unsigned int hash, sequence; |
ea781f197 netfilter: nf_con... |
775 |
struct hlist_nulls_node *n; |
5d0aa2ccd netfilter: nf_con... |
776 |
struct nf_conn *ct; |
308ac9143 netfilter: nf_con... |
777 778 |
zone = nf_ct_zone(ignored_conntrack); |
9fb9cbb10 [NETFILTER]: Add ... |
779 |
|
2cf123480 netfilter: conntr... |
780 |
rcu_read_lock(); |
5e3c61f98 netfilter: conntr... |
781 782 783 |
do { sequence = read_seqcount_begin(&nf_conntrack_generation); hash = hash_conntrack(net, tuple); |
56d52d489 netfilter: conntr... |
784 |
ct_hash = nf_conntrack_hash; |
5e3c61f98 netfilter: conntr... |
785 786 787 |
} while (read_seqcount_retry(&nf_conntrack_generation, sequence)); hlist_nulls_for_each_entry_rcu(h, n, &ct_hash[hash], hnnode) { |
5d0aa2ccd netfilter: nf_con... |
788 789 |
ct = nf_ct_tuplehash_to_ctrack(h); if (ct != ignored_conntrack && |
e0c7d4722 netfilter: conntr... |
790 |
nf_ct_key_equal(h, tuple, zone, net)) { |
2cf123480 netfilter: conntr... |
791 792 |
NF_CT_STAT_INC_ATOMIC(net, found); rcu_read_unlock(); |
ba419aff2 [NETFILTER]: nf_c... |
793 794 |
return 1; } |
2cf123480 netfilter: conntr... |
795 |
NF_CT_STAT_INC_ATOMIC(net, searched); |
ba419aff2 [NETFILTER]: nf_c... |
796 |
} |
2cf123480 netfilter: conntr... |
797 |
rcu_read_unlock(); |
9fb9cbb10 [NETFILTER]: Add ... |
798 |
|
ba419aff2 [NETFILTER]: nf_c... |
799 |
return 0; |
9fb9cbb10 [NETFILTER]: Add ... |
800 |
} |
13b183391 [NETFILTER]: nf_c... |
801 |
EXPORT_SYMBOL_GPL(nf_conntrack_tuple_taken); |
9fb9cbb10 [NETFILTER]: Add ... |
802 |
|
7ae7730fd [NETFILTER]: nf_c... |
803 |
#define NF_CT_EVICTION_RANGE 8 |
9fb9cbb10 [NETFILTER]: Add ... |
804 805 |
/* There's a small race here where we may free a just-assured connection. Too bad: we're in trouble anyway. */ |
93bb0ceb7 netfilter: conntr... |
806 |
static noinline int early_drop(struct net *net, unsigned int _hash) |
9fb9cbb10 [NETFILTER]: Add ... |
807 |
{ |
f205c5e0c [NETFILTER]: nf_c... |
808 |
/* Use oldest entry, which is roughly LRU */ |
9fb9cbb10 [NETFILTER]: Add ... |
809 |
struct nf_conntrack_tuple_hash *h; |
3e86638e9 netfilter: conntr... |
810 |
struct nf_conn *tmp; |
ea781f197 netfilter: nf_con... |
811 |
struct hlist_nulls_node *n; |
3e86638e9 netfilter: conntr... |
812 813 |
unsigned int i, hash, sequence; struct nf_conn *ct = NULL; |
93bb0ceb7 netfilter: conntr... |
814 |
spinlock_t *lockp; |
3e86638e9 netfilter: conntr... |
815 816 817 |
bool ret = false; i = 0; |
9fb9cbb10 [NETFILTER]: Add ... |
818 |
|
93bb0ceb7 netfilter: conntr... |
819 820 |
local_bh_disable(); restart: |
a3efd8120 netfilter: conntr... |
821 |
sequence = read_seqcount_begin(&nf_conntrack_generation); |
3e86638e9 netfilter: conntr... |
822 823 |
for (; i < NF_CT_EVICTION_RANGE; i++) { hash = scale_hash(_hash++); |
93bb0ceb7 netfilter: conntr... |
824 |
lockp = &nf_conntrack_locks[hash % CONNTRACK_LOCKS]; |
b16c29191 netfilter: nf_con... |
825 |
nf_conntrack_lock(lockp); |
a3efd8120 netfilter: conntr... |
826 |
if (read_seqcount_retry(&nf_conntrack_generation, sequence)) { |
93bb0ceb7 netfilter: conntr... |
827 828 829 |
spin_unlock(lockp); goto restart; } |
56d52d489 netfilter: conntr... |
830 831 |
hlist_nulls_for_each_entry_rcu(h, n, &nf_conntrack_hash[hash], hnnode) { |
7ae7730fd [NETFILTER]: nf_c... |
832 |
tmp = nf_ct_tuplehash_to_ctrack(h); |
3e86638e9 netfilter: conntr... |
833 834 835 836 837 838 839 |
if (test_bit(IPS_ASSURED_BIT, &tmp->status) || !net_eq(nf_ct_net(tmp), net) || nf_ct_is_dying(tmp)) continue; if (atomic_inc_not_zero(&tmp->ct_general.use)) { |
7ae7730fd [NETFILTER]: nf_c... |
840 |
ct = tmp; |
93bb0ceb7 netfilter: conntr... |
841 842 |
break; } |
7ae7730fd [NETFILTER]: nf_c... |
843 |
} |
76507f69c [NETFILTER]: nf_c... |
844 |
|
93bb0ceb7 netfilter: conntr... |
845 |
spin_unlock(lockp); |
3e86638e9 netfilter: conntr... |
846 |
if (ct) |
7ae7730fd [NETFILTER]: nf_c... |
847 |
break; |
9fb9cbb10 [NETFILTER]: Add ... |
848 |
} |
3e86638e9 netfilter: conntr... |
849 |
|
93bb0ceb7 netfilter: conntr... |
850 |
local_bh_enable(); |
9fb9cbb10 [NETFILTER]: Add ... |
851 852 |
if (!ct) |
3e86638e9 netfilter: conntr... |
853 |
return false; |
9fb9cbb10 [NETFILTER]: Add ... |
854 |
|
3e86638e9 netfilter: conntr... |
855 856 857 858 |
/* kill only if in same netns -- might have moved due to * SLAB_DESTROY_BY_RCU rules */ if (net_eq(nf_ct_net(ct), net) && del_timer(&ct->timeout)) { |
02982c27b netfilter: nf_con... |
859 |
if (nf_ct_delete(ct, 0, 0)) { |
741385119 netfilter: nf_con... |
860 |
NF_CT_STAT_INC_ATOMIC(net, early_drop); |
3e86638e9 netfilter: conntr... |
861 |
ret = true; |
741385119 netfilter: nf_con... |
862 |
} |
9fb9cbb10 [NETFILTER]: Add ... |
863 |
} |
3e86638e9 netfilter: conntr... |
864 |
|
9fb9cbb10 [NETFILTER]: Add ... |
865 |
nf_ct_put(ct); |
3e86638e9 netfilter: conntr... |
866 |
return ret; |
9fb9cbb10 [NETFILTER]: Add ... |
867 |
} |
99f07e91b netfilter: save t... |
868 |
static struct nf_conn * |
308ac9143 netfilter: nf_con... |
869 870 |
__nf_conntrack_alloc(struct net *net, const struct nf_conntrack_zone *zone, |
99f07e91b netfilter: save t... |
871 872 873 |
const struct nf_conntrack_tuple *orig, const struct nf_conntrack_tuple *repl, gfp_t gfp, u32 hash) |
9fb9cbb10 [NETFILTER]: Add ... |
874 |
{ |
cd7fcbf1c netfilter 07/09: ... |
875 |
struct nf_conn *ct; |
9fb9cbb10 [NETFILTER]: Add ... |
876 |
|
5251e2d21 [NETFILTER]: conn... |
877 |
/* We don't want any race condition at early drop stage */ |
49ac8713b netfilter: netns ... |
878 |
atomic_inc(&net->ct.count); |
5251e2d21 [NETFILTER]: conn... |
879 |
|
76eb94604 [NETFILTER]: nf_c... |
880 |
if (nf_conntrack_max && |
49ac8713b netfilter: netns ... |
881 |
unlikely(atomic_read(&net->ct.count) > nf_conntrack_max)) { |
93bb0ceb7 netfilter: conntr... |
882 |
if (!early_drop(net, hash)) { |
49ac8713b netfilter: netns ... |
883 |
atomic_dec(&net->ct.count); |
e87cc4728 net: Convert net_... |
884 885 |
net_warn_ratelimited("nf_conntrack: table full, dropping packet "); |
9fb9cbb10 [NETFILTER]: Add ... |
886 887 888 |
return ERR_PTR(-ENOMEM); } } |
941297f44 netfilter: nf_con... |
889 890 891 892 |
/* * Do not use kmem_cache_zalloc(), as this cache uses * SLAB_DESTROY_BY_RCU. */ |
0c5366b3a netfilter: conntr... |
893 |
ct = kmem_cache_alloc(nf_conntrack_cachep, gfp); |
5e8018fc6 netfilter: nf_con... |
894 895 |
if (ct == NULL) goto out; |
440f0d588 netfilter: nf_con... |
896 |
spin_lock_init(&ct->lock); |
c88130bcd [NETFILTER]: nf_c... |
897 |
ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig; |
941297f44 netfilter: nf_con... |
898 |
ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode.pprev = NULL; |
c88130bcd [NETFILTER]: nf_c... |
899 |
ct->tuplehash[IP_CT_DIR_REPLY].tuple = *repl; |
99f07e91b netfilter: save t... |
900 901 |
/* save hash for reusing when confirming */ *(unsigned long *)(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev) = hash; |
c41884ce0 netfilter: conntr... |
902 |
ct->status = 0; |
9fb9cbb10 [NETFILTER]: Add ... |
903 |
/* Don't set timer yet: wait for confirmation */ |
c88130bcd [NETFILTER]: nf_c... |
904 |
setup_timer(&ct->timeout, death_by_timeout, (unsigned long)ct); |
c2d9ba9bc net: CONFIG_NET_N... |
905 |
write_pnet(&ct->ct_net, net); |
c41884ce0 netfilter: conntr... |
906 907 908 |
memset(&ct->__nfct_init_offset[0], 0, offsetof(struct nf_conn, proto) - offsetof(struct nf_conn, __nfct_init_offset[0])); |
5e8018fc6 netfilter: nf_con... |
909 |
|
6c8dee984 netfilter: move z... |
910 |
nf_ct_zone_add(ct, zone); |
5e8018fc6 netfilter: nf_con... |
911 |
|
e53376bef netfilter: nf_con... |
912 913 |
/* Because we use RCU lookups, we set ct_general.use to zero before * this is inserted in any list. |
941297f44 netfilter: nf_con... |
914 |
*/ |
e53376bef netfilter: nf_con... |
915 |
atomic_set(&ct->ct_general.use, 0); |
c88130bcd [NETFILTER]: nf_c... |
916 |
return ct; |
5e8018fc6 netfilter: nf_con... |
917 918 |
out: atomic_dec(&net->ct.count); |
5d0aa2ccd netfilter: nf_con... |
919 |
return ERR_PTR(-ENOMEM); |
9fb9cbb10 [NETFILTER]: Add ... |
920 |
} |
99f07e91b netfilter: save t... |
921 |
|
308ac9143 netfilter: nf_con... |
922 923 |
struct nf_conn *nf_conntrack_alloc(struct net *net, const struct nf_conntrack_zone *zone, |
99f07e91b netfilter: save t... |
924 925 926 927 928 929 |
const struct nf_conntrack_tuple *orig, const struct nf_conntrack_tuple *repl, gfp_t gfp) { return __nf_conntrack_alloc(net, zone, orig, repl, gfp, 0); } |
13b183391 [NETFILTER]: nf_c... |
930 |
EXPORT_SYMBOL_GPL(nf_conntrack_alloc); |
9fb9cbb10 [NETFILTER]: Add ... |
931 |
|
c88130bcd [NETFILTER]: nf_c... |
932 |
void nf_conntrack_free(struct nf_conn *ct) |
76507f69c [NETFILTER]: nf_c... |
933 |
{ |
1d45209d8 netfilter: nf_con... |
934 |
struct net *net = nf_ct_net(ct); |
e53376bef netfilter: nf_con... |
935 936 937 938 |
/* A freed object has refcnt == 0, that's * the golden rule for SLAB_DESTROY_BY_RCU */ NF_CT_ASSERT(atomic_read(&ct->ct_general.use) == 0); |
ceeff7541 netfilter: nf_con... |
939 |
nf_ct_ext_destroy(ct); |
ea781f197 netfilter: nf_con... |
940 |
nf_ct_ext_free(ct); |
0c5366b3a netfilter: conntr... |
941 |
kmem_cache_free(nf_conntrack_cachep, ct); |
4e857c58e arch: Mass conver... |
942 |
smp_mb__before_atomic(); |
0c3c6c00c netfilter: nf_con... |
943 |
atomic_dec(&net->ct.count); |
76507f69c [NETFILTER]: nf_c... |
944 |
} |
13b183391 [NETFILTER]: nf_c... |
945 |
EXPORT_SYMBOL_GPL(nf_conntrack_free); |
9fb9cbb10 [NETFILTER]: Add ... |
946 |
|
c539f0171 netfilter: add co... |
947 |
|
9fb9cbb10 [NETFILTER]: Add ... |
948 949 950 |
/* Allocate a new conntrack: we return -ENOMEM if classification failed due to stress. Otherwise it really is unclassifiable. */ static struct nf_conntrack_tuple_hash * |
b2a15a604 netfilter: nf_con... |
951 |
init_conntrack(struct net *net, struct nf_conn *tmpl, |
5a1fb391d netfilter: netns ... |
952 |
const struct nf_conntrack_tuple *tuple, |
9fb9cbb10 [NETFILTER]: Add ... |
953 |
struct nf_conntrack_l3proto *l3proto, |
605dcad6c [NETFILTER]: nf_c... |
954 |
struct nf_conntrack_l4proto *l4proto, |
9fb9cbb10 [NETFILTER]: Add ... |
955 |
struct sk_buff *skb, |
60b5f8f74 netfilter: nf_con... |
956 |
unsigned int dataoff, u32 hash) |
9fb9cbb10 [NETFILTER]: Add ... |
957 |
{ |
c88130bcd [NETFILTER]: nf_c... |
958 |
struct nf_conn *ct; |
3c158f7f5 [NETFILTER]: nf_c... |
959 |
struct nf_conn_help *help; |
9fb9cbb10 [NETFILTER]: Add ... |
960 |
struct nf_conntrack_tuple repl_tuple; |
b2a15a604 netfilter: nf_con... |
961 |
struct nf_conntrack_ecache *ecache; |
ca7433df3 netfilter: conntr... |
962 |
struct nf_conntrack_expect *exp = NULL; |
308ac9143 netfilter: nf_con... |
963 |
const struct nf_conntrack_zone *zone; |
60b5f8f74 netfilter: nf_con... |
964 |
struct nf_conn_timeout *timeout_ext; |
5e8018fc6 netfilter: nf_con... |
965 |
struct nf_conntrack_zone tmp; |
60b5f8f74 netfilter: nf_con... |
966 |
unsigned int *timeouts; |
9fb9cbb10 [NETFILTER]: Add ... |
967 |
|
605dcad6c [NETFILTER]: nf_c... |
968 |
if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) { |
0d53778e8 [NETFILTER]: Conv... |
969 970 |
pr_debug("Can't invert tuple. "); |
9fb9cbb10 [NETFILTER]: Add ... |
971 972 |
return NULL; } |
5e8018fc6 netfilter: nf_con... |
973 |
zone = nf_ct_zone_tmpl(tmpl, skb, &tmp); |
99f07e91b netfilter: save t... |
974 975 |
ct = __nf_conntrack_alloc(net, zone, tuple, &repl_tuple, GFP_ATOMIC, hash); |
0a9ee8134 netfilter: Remove... |
976 |
if (IS_ERR(ct)) |
c88130bcd [NETFILTER]: nf_c... |
977 |
return (struct nf_conntrack_tuple_hash *)ct; |
9fb9cbb10 [NETFILTER]: Add ... |
978 |
|
48b1de4c1 netfilter: add SY... |
979 980 981 982 |
if (tmpl && nfct_synproxy(tmpl)) { nfct_seqadj_ext_add(ct); nfct_synproxy_ext_add(ct); } |
60b5f8f74 netfilter: nf_con... |
983 |
timeout_ext = tmpl ? nf_ct_timeout_find(tmpl) : NULL; |
ae2d708ed netfilter: conntr... |
984 985 986 987 988 |
if (timeout_ext) { timeouts = nf_ct_timeout_data(timeout_ext); if (unlikely(!timeouts)) timeouts = l4proto->get_timeouts(net); } else { |
60b5f8f74 netfilter: nf_con... |
989 |
timeouts = l4proto->get_timeouts(net); |
ae2d708ed netfilter: conntr... |
990 |
} |
60b5f8f74 netfilter: nf_con... |
991 |
|
2c8503f55 netfilter: nf_con... |
992 |
if (!l4proto->new(ct, skb, dataoff, timeouts)) { |
c88130bcd [NETFILTER]: nf_c... |
993 |
nf_conntrack_free(ct); |
ccd63c20f netfilter: nf_con... |
994 995 |
pr_debug("can't track with proto module "); |
9fb9cbb10 [NETFILTER]: Add ... |
996 997 |
return NULL; } |
60b5f8f74 netfilter: nf_con... |
998 |
if (timeout_ext) |
ae2d708ed netfilter: conntr... |
999 1000 |
nf_ct_timeout_ext_add(ct, rcu_dereference(timeout_ext->timeout), GFP_ATOMIC); |
60b5f8f74 netfilter: nf_con... |
1001 |
|
584015727 netfilter: accoun... |
1002 |
nf_ct_acct_ext_add(ct, GFP_ATOMIC); |
a992ca2a0 netfilter: nf_con... |
1003 |
nf_ct_tstamp_ext_add(ct, GFP_ATOMIC); |
c539f0171 netfilter: add co... |
1004 |
nf_ct_labels_ext_add(ct); |
b2a15a604 netfilter: nf_con... |
1005 1006 1007 1008 1009 |
ecache = tmpl ? nf_ct_ecache_find(tmpl) : NULL; nf_ct_ecache_ext_add(ct, ecache ? ecache->ctmask : 0, ecache ? ecache->expmask : 0, GFP_ATOMIC); |
584015727 netfilter: accoun... |
1010 |
|
ca7433df3 netfilter: conntr... |
1011 1012 1013 1014 1015 |
local_bh_disable(); if (net->ct.expect_count) { spin_lock(&nf_conntrack_expect_lock); exp = nf_ct_find_expectation(net, zone, tuple); if (exp) { |
ccd63c20f netfilter: nf_con... |
1016 1017 |
pr_debug("expectation arrives ct=%p exp=%p ", |
ca7433df3 netfilter: conntr... |
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 |
ct, exp); /* Welcome, Mr. Bond. We've been expecting you... */ __set_bit(IPS_EXPECTED_BIT, &ct->status); /* exp->master safe, refcnt bumped in nf_ct_find_expectation */ ct->master = exp->master; if (exp->helper) { help = nf_ct_helper_ext_add(ct, exp->helper, GFP_ATOMIC); if (help) rcu_assign_pointer(help->helper, exp->helper); } |
ceceae1b1 [NETFILTER]: nf_c... |
1029 |
|
9fb9cbb10 [NETFILTER]: Add ... |
1030 |
#ifdef CONFIG_NF_CONNTRACK_MARK |
ca7433df3 netfilter: conntr... |
1031 |
ct->mark = exp->master->mark; |
9fb9cbb10 [NETFILTER]: Add ... |
1032 |
#endif |
7c9728c39 [SECMARK]: Add se... |
1033 |
#ifdef CONFIG_NF_CONNTRACK_SECMARK |
ca7433df3 netfilter: conntr... |
1034 |
ct->secmark = exp->master->secmark; |
7c9728c39 [SECMARK]: Add se... |
1035 |
#endif |
ca7433df3 netfilter: conntr... |
1036 1037 1038 1039 1040 |
NF_CT_STAT_INC(net, expect_new); } spin_unlock(&nf_conntrack_expect_lock); } if (!exp) { |
b2a15a604 netfilter: nf_con... |
1041 |
__nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC); |
0d55af879 netfilter: netns ... |
1042 |
NF_CT_STAT_INC(net, new); |
22e7410b7 [NETFILTER]: nf_c... |
1043 |
} |
9fb9cbb10 [NETFILTER]: Add ... |
1044 |
|
e53376bef netfilter: nf_con... |
1045 1046 |
/* Now it is inserted into the unconfirmed list, bump refcount */ nf_conntrack_get(&ct->ct_general); |
b7779d06f netfilter: conntr... |
1047 |
nf_ct_add_to_unconfirmed_list(ct); |
9fb9cbb10 [NETFILTER]: Add ... |
1048 |
|
ca7433df3 netfilter: conntr... |
1049 |
local_bh_enable(); |
9fb9cbb10 [NETFILTER]: Add ... |
1050 1051 1052 |
if (exp) { if (exp->expectfn) |
c88130bcd [NETFILTER]: nf_c... |
1053 |
exp->expectfn(ct, exp); |
6823645d6 [NETFILTER]: nf_c... |
1054 |
nf_ct_expect_put(exp); |
9fb9cbb10 [NETFILTER]: Add ... |
1055 |
} |
c88130bcd [NETFILTER]: nf_c... |
1056 |
return &ct->tuplehash[IP_CT_DIR_ORIGINAL]; |
9fb9cbb10 [NETFILTER]: Add ... |
1057 1058 1059 1060 |
} /* On success, returns conntrack ptr, sets skb->nfct and ctinfo */ static inline struct nf_conn * |
b2a15a604 netfilter: nf_con... |
1061 |
resolve_normal_ct(struct net *net, struct nf_conn *tmpl, |
a702a65fc netfilter: netns ... |
1062 |
struct sk_buff *skb, |
9fb9cbb10 [NETFILTER]: Add ... |
1063 1064 1065 1066 |
unsigned int dataoff, u_int16_t l3num, u_int8_t protonum, struct nf_conntrack_l3proto *l3proto, |
605dcad6c [NETFILTER]: nf_c... |
1067 |
struct nf_conntrack_l4proto *l4proto, |
9fb9cbb10 [NETFILTER]: Add ... |
1068 |
int *set_reply, |
60b5f8f74 netfilter: nf_con... |
1069 |
enum ip_conntrack_info *ctinfo) |
9fb9cbb10 [NETFILTER]: Add ... |
1070 |
{ |
308ac9143 netfilter: nf_con... |
1071 |
const struct nf_conntrack_zone *zone; |
9fb9cbb10 [NETFILTER]: Add ... |
1072 1073 |
struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple_hash *h; |
5e8018fc6 netfilter: nf_con... |
1074 |
struct nf_conntrack_zone tmp; |
9fb9cbb10 [NETFILTER]: Add ... |
1075 |
struct nf_conn *ct; |
99f07e91b netfilter: save t... |
1076 |
u32 hash; |
9fb9cbb10 [NETFILTER]: Add ... |
1077 |
|
bbe735e42 [SK_BUFF]: Introd... |
1078 |
if (!nf_ct_get_tuple(skb, skb_network_offset(skb), |
a31f1adc0 netfilter: nf_con... |
1079 |
dataoff, l3num, protonum, net, &tuple, l3proto, |
605dcad6c [NETFILTER]: nf_c... |
1080 |
l4proto)) { |
ccd63c20f netfilter: nf_con... |
1081 1082 |
pr_debug("Can't get tuple "); |
9fb9cbb10 [NETFILTER]: Add ... |
1083 1084 1085 1086 |
return NULL; } /* look for tuple match */ |
5e8018fc6 netfilter: nf_con... |
1087 |
zone = nf_ct_zone_tmpl(tmpl, skb, &tmp); |
1b8c8a9f6 netfilter: conntr... |
1088 |
hash = hash_conntrack_raw(&tuple, net); |
99f07e91b netfilter: save t... |
1089 |
h = __nf_conntrack_find_get(net, zone, &tuple, hash); |
9fb9cbb10 [NETFILTER]: Add ... |
1090 |
if (!h) { |
b2a15a604 netfilter: nf_con... |
1091 |
h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto, |
60b5f8f74 netfilter: nf_con... |
1092 |
skb, dataoff, hash); |
9fb9cbb10 [NETFILTER]: Add ... |
1093 1094 1095 1096 1097 1098 1099 1100 1101 |
if (!h) return NULL; if (IS_ERR(h)) return (void *)h; } ct = nf_ct_tuplehash_to_ctrack(h); /* It exists; we have (non-exclusive) reference. */ if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) { |
fb0488337 netfilter: add mo... |
1102 |
*ctinfo = IP_CT_ESTABLISHED_REPLY; |
9fb9cbb10 [NETFILTER]: Add ... |
1103 1104 1105 1106 1107 |
/* Please set reply bit if this packet OK */ *set_reply = 1; } else { /* Once we've had two way comms, always ESTABLISHED. */ if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { |
ccd63c20f netfilter: nf_con... |
1108 1109 |
pr_debug("normal packet for %p ", ct); |
9fb9cbb10 [NETFILTER]: Add ... |
1110 1111 |
*ctinfo = IP_CT_ESTABLISHED; } else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) { |
ccd63c20f netfilter: nf_con... |
1112 1113 |
pr_debug("related packet for %p ", ct); |
9fb9cbb10 [NETFILTER]: Add ... |
1114 1115 |
*ctinfo = IP_CT_RELATED; } else { |
ccd63c20f netfilter: nf_con... |
1116 1117 |
pr_debug("new packet for %p ", ct); |
9fb9cbb10 [NETFILTER]: Add ... |
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 |
*ctinfo = IP_CT_NEW; } *set_reply = 0; } skb->nfct = &ct->ct_general; skb->nfctinfo = *ctinfo; return ct; } unsigned int |
a702a65fc netfilter: netns ... |
1128 1129 |
nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, struct sk_buff *skb) |
9fb9cbb10 [NETFILTER]: Add ... |
1130 |
{ |
b2a15a604 netfilter: nf_con... |
1131 |
struct nf_conn *ct, *tmpl = NULL; |
9fb9cbb10 [NETFILTER]: Add ... |
1132 1133 |
enum ip_conntrack_info ctinfo; struct nf_conntrack_l3proto *l3proto; |
605dcad6c [NETFILTER]: nf_c... |
1134 |
struct nf_conntrack_l4proto *l4proto; |
2c8503f55 netfilter: nf_con... |
1135 |
unsigned int *timeouts; |
9fb9cbb10 [NETFILTER]: Add ... |
1136 1137 1138 1139 |
unsigned int dataoff; u_int8_t protonum; int set_reply = 0; int ret; |
3db05fea5 [NETFILTER]: Repl... |
1140 |
if (skb->nfct) { |
b2a15a604 netfilter: nf_con... |
1141 1142 1143 1144 1145 1146 1147 |
/* Previously seen (loopback or untracked)? Ignore. */ tmpl = (struct nf_conn *)skb->nfct; if (!nf_ct_is_template(tmpl)) { NF_CT_STAT_INC_ATOMIC(net, ignore); return NF_ACCEPT; } skb->nfct = NULL; |
9fb9cbb10 [NETFILTER]: Add ... |
1148 |
} |
923f4902f [NETFILTER]: nf_c... |
1149 |
/* rcu_read_lock()ed by nf_hook_slow */ |
76108cea0 netfilter: Use un... |
1150 |
l3proto = __nf_ct_l3proto_find(pf); |
3db05fea5 [NETFILTER]: Repl... |
1151 |
ret = l3proto->get_l4proto(skb, skb_network_offset(skb), |
ffc306904 [NETFILTER]: nf_c... |
1152 1153 |
&dataoff, &protonum); if (ret <= 0) { |
25985edce Fix common misspe... |
1154 1155 |
pr_debug("not prepared to track yet or error occurred "); |
0d55af879 netfilter: netns ... |
1156 1157 |
NF_CT_STAT_INC_ATOMIC(net, error); NF_CT_STAT_INC_ATOMIC(net, invalid); |
b2a15a604 netfilter: nf_con... |
1158 1159 |
ret = -ret; goto out; |
9fb9cbb10 [NETFILTER]: Add ... |
1160 |
} |
76108cea0 netfilter: Use un... |
1161 |
l4proto = __nf_ct_l4proto_find(pf, protonum); |
9fb9cbb10 [NETFILTER]: Add ... |
1162 1163 1164 1165 |
/* It may be an special packet, error, unclean... * inverse of the return code tells to the netfilter * core what to do with the packet. */ |
74c51a149 netfilter: netns ... |
1166 |
if (l4proto->error != NULL) { |
8fea97ec1 netfilter: nf_con... |
1167 1168 |
ret = l4proto->error(net, tmpl, skb, dataoff, &ctinfo, pf, hooknum); |
74c51a149 netfilter: netns ... |
1169 |
if (ret <= 0) { |
0d55af879 netfilter: netns ... |
1170 1171 |
NF_CT_STAT_INC_ATOMIC(net, error); NF_CT_STAT_INC_ATOMIC(net, invalid); |
b2a15a604 netfilter: nf_con... |
1172 1173 |
ret = -ret; goto out; |
74c51a149 netfilter: netns ... |
1174 |
} |
88ed01d17 netfilter: nf_con... |
1175 1176 1177 |
/* ICMP[v6] protocol trackers may assign one conntrack. */ if (skb->nfct) goto out; |
9fb9cbb10 [NETFILTER]: Add ... |
1178 |
} |
b2a15a604 netfilter: nf_con... |
1179 |
ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum, |
60b5f8f74 netfilter: nf_con... |
1180 |
l3proto, l4proto, &set_reply, &ctinfo); |
9fb9cbb10 [NETFILTER]: Add ... |
1181 1182 |
if (!ct) { /* Not valid part of a connection */ |
0d55af879 netfilter: netns ... |
1183 |
NF_CT_STAT_INC_ATOMIC(net, invalid); |
b2a15a604 netfilter: nf_con... |
1184 1185 |
ret = NF_ACCEPT; goto out; |
9fb9cbb10 [NETFILTER]: Add ... |
1186 1187 1188 1189 |
} if (IS_ERR(ct)) { /* Too stressed to deal. */ |
0d55af879 netfilter: netns ... |
1190 |
NF_CT_STAT_INC_ATOMIC(net, drop); |
b2a15a604 netfilter: nf_con... |
1191 1192 |
ret = NF_DROP; goto out; |
9fb9cbb10 [NETFILTER]: Add ... |
1193 |
} |
3db05fea5 [NETFILTER]: Repl... |
1194 |
NF_CT_ASSERT(skb->nfct); |
9fb9cbb10 [NETFILTER]: Add ... |
1195 |
|
60b5f8f74 netfilter: nf_con... |
1196 |
/* Decide what timeout policy we want to apply to this flow. */ |
84b5ee939 netfilter: nf_con... |
1197 |
timeouts = nf_ct_timeout_lookup(net, ct, l4proto); |
60b5f8f74 netfilter: nf_con... |
1198 |
|
2c8503f55 netfilter: nf_con... |
1199 |
ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum, timeouts); |
ec8d54096 netfilter: conntr... |
1200 |
if (ret <= 0) { |
9fb9cbb10 [NETFILTER]: Add ... |
1201 1202 |
/* Invalid: inverse of the return code tells * the netfilter core what to do */ |
0d53778e8 [NETFILTER]: Conv... |
1203 1204 |
pr_debug("nf_conntrack_in: Can't track with proto module "); |
3db05fea5 [NETFILTER]: Repl... |
1205 1206 |
nf_conntrack_put(skb->nfct); skb->nfct = NULL; |
0d55af879 netfilter: netns ... |
1207 |
NF_CT_STAT_INC_ATOMIC(net, invalid); |
7d1e04598 netfilter: nf_con... |
1208 1209 |
if (ret == -NF_DROP) NF_CT_STAT_INC_ATOMIC(net, drop); |
b2a15a604 netfilter: nf_con... |
1210 1211 |
ret = -ret; goto out; |
9fb9cbb10 [NETFILTER]: Add ... |
1212 1213 1214 |
} if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status)) |
858b31330 netfilter: nf_con... |
1215 |
nf_conntrack_event_cache(IPCT_REPLY, ct); |
b2a15a604 netfilter: nf_con... |
1216 |
out: |
c31742864 netfilter: nf_con... |
1217 1218 1219 1220 1221 1222 1223 1224 1225 |
if (tmpl) { /* Special case: we have to repeat this hook, assign the * template again to this packet. We assume that this packet * has no conntrack assigned. This is used by nf_ct_tcp. */ if (ret == NF_REPEAT) skb->nfct = (struct nf_conntrack *)tmpl; else nf_ct_put(tmpl); } |
9fb9cbb10 [NETFILTER]: Add ... |
1226 1227 1228 |
return ret; } |
13b183391 [NETFILTER]: nf_c... |
1229 |
EXPORT_SYMBOL_GPL(nf_conntrack_in); |
9fb9cbb10 [NETFILTER]: Add ... |
1230 |
|
5f2b4c900 [NETFILTER]: nf_c... |
1231 1232 |
bool nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, const struct nf_conntrack_tuple *orig) |
9fb9cbb10 [NETFILTER]: Add ... |
1233 |
{ |
5f2b4c900 [NETFILTER]: nf_c... |
1234 |
bool ret; |
923f4902f [NETFILTER]: nf_c... |
1235 1236 1237 1238 1239 1240 1241 1242 |
rcu_read_lock(); ret = nf_ct_invert_tuple(inverse, orig, __nf_ct_l3proto_find(orig->src.l3num), __nf_ct_l4proto_find(orig->src.l3num, orig->dst.protonum)); rcu_read_unlock(); return ret; |
9fb9cbb10 [NETFILTER]: Add ... |
1243 |
} |
13b183391 [NETFILTER]: nf_c... |
1244 |
EXPORT_SYMBOL_GPL(nf_ct_invert_tuplepr); |
9fb9cbb10 [NETFILTER]: Add ... |
1245 |
|
5b1158e90 [NETFILTER]: Add ... |
1246 1247 1248 1249 1250 1251 |
/* Alter reply tuple (maybe alter helper). This is for NAT, and is implicitly racy: see __nf_conntrack_confirm */ void nf_conntrack_alter_reply(struct nf_conn *ct, const struct nf_conntrack_tuple *newreply) { struct nf_conn_help *help = nfct_help(ct); |
5b1158e90 [NETFILTER]: Add ... |
1252 1253 |
/* Should be unconfirmed, so not in hash table yet */ NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); |
0d53778e8 [NETFILTER]: Conv... |
1254 |
pr_debug("Altering reply tuple of %p to ", ct); |
3c9fba656 [NETFILTER]: nf_c... |
1255 |
nf_ct_dump_tuple(newreply); |
5b1158e90 [NETFILTER]: Add ... |
1256 1257 |
ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; |
ef1a5a50b [NETFILTER]: nf_c... |
1258 |
if (ct->master || (help && !hlist_empty(&help->expectations))) |
c52fbb410 [NETFILTER]: nf_c... |
1259 |
return; |
ceceae1b1 [NETFILTER]: nf_c... |
1260 |
|
c52fbb410 [NETFILTER]: nf_c... |
1261 |
rcu_read_lock(); |
b2a15a604 netfilter: nf_con... |
1262 |
__nf_ct_try_assign_helper(ct, NULL, GFP_ATOMIC); |
c52fbb410 [NETFILTER]: nf_c... |
1263 |
rcu_read_unlock(); |
5b1158e90 [NETFILTER]: Add ... |
1264 |
} |
13b183391 [NETFILTER]: nf_c... |
1265 |
EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply); |
5b1158e90 [NETFILTER]: Add ... |
1266 |
|
9fb9cbb10 [NETFILTER]: Add ... |
1267 1268 1269 1270 1271 1272 1273 |
/* Refresh conntrack for this many jiffies and do accounting if do_acct is 1 */ void __nf_ct_refresh_acct(struct nf_conn *ct, enum ip_conntrack_info ctinfo, const struct sk_buff *skb, unsigned long extra_jiffies, int do_acct) { |
9fb9cbb10 [NETFILTER]: Add ... |
1274 1275 |
NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct); NF_CT_ASSERT(skb); |
997ae831a [NETFILTER]: conn... |
1276 |
/* Only update if this is not a fixed timeout */ |
47d950454 [NETFILTER]: nf_c... |
1277 1278 |
if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) goto acct; |
997ae831a [NETFILTER]: conn... |
1279 |
|
9fb9cbb10 [NETFILTER]: Add ... |
1280 1281 1282 |
/* If not in hash table, timer will not be active yet */ if (!nf_ct_is_confirmed(ct)) { ct->timeout.expires = extra_jiffies; |
9fb9cbb10 [NETFILTER]: Add ... |
1283 |
} else { |
be00c8e48 [NETFILTER]: nf_c... |
1284 1285 1286 1287 1288 |
unsigned long newtime = jiffies + extra_jiffies; /* Only update the timeout if the new timeout is at least HZ jiffies from the old timeout. Need del_timer for race avoidance (may already be dying). */ |
65cb9fda3 netfilter: nf_con... |
1289 1290 |
if (newtime - ct->timeout.expires >= HZ) mod_timer_pending(&ct->timeout, newtime); |
9fb9cbb10 [NETFILTER]: Add ... |
1291 |
} |
47d950454 [NETFILTER]: nf_c... |
1292 |
acct: |
ba76738c0 netfilter: conntr... |
1293 1294 |
if (do_acct) nf_ct_acct_update(ct, ctinfo, skb->len); |
9fb9cbb10 [NETFILTER]: Add ... |
1295 |
} |
13b183391 [NETFILTER]: nf_c... |
1296 |
EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct); |
9fb9cbb10 [NETFILTER]: Add ... |
1297 |
|
4c8894980 netfilter: Let nf... |
1298 1299 1300 1301 |
bool __nf_ct_kill_acct(struct nf_conn *ct, enum ip_conntrack_info ctinfo, const struct sk_buff *skb, int do_acct) |
51091764f netfilter: nf_con... |
1302 |
{ |
ba76738c0 netfilter: conntr... |
1303 1304 |
if (do_acct) nf_ct_acct_update(ct, ctinfo, skb->len); |
584015727 netfilter: accoun... |
1305 |
|
4c8894980 netfilter: Let nf... |
1306 |
if (del_timer(&ct->timeout)) { |
51091764f netfilter: nf_con... |
1307 |
ct->timeout.function((unsigned long)ct); |
4c8894980 netfilter: Let nf... |
1308 1309 1310 |
return true; } return false; |
51091764f netfilter: nf_con... |
1311 |
} |
718d4ad98 netfilter: nf_con... |
1312 |
EXPORT_SYMBOL_GPL(__nf_ct_kill_acct); |
51091764f netfilter: nf_con... |
1313 |
|
c0cd11566 net:netfilter: us... |
1314 |
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
c1d10adb4 [NETFILTER]: Add ... |
1315 1316 1317 |
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink_conntrack.h> |
57b47a53e [NET]: sem2mutex ... |
1318 |
#include <linux/mutex.h> |
c1d10adb4 [NETFILTER]: Add ... |
1319 1320 1321 |
/* Generic function for tcp/udp/sctp/dccp and alike. This needs to be * in ip_conntrack_core, since we don't want the protocols to autoload * or depend on ctnetlink */ |
fdf708322 [NETFILTER]: nfne... |
1322 |
int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb, |
c1d10adb4 [NETFILTER]: Add ... |
1323 1324 |
const struct nf_conntrack_tuple *tuple) { |
bae65be89 nf_conntrack_core... |
1325 1326 1327 |
if (nla_put_be16(skb, CTA_PROTO_SRC_PORT, tuple->src.u.tcp.port) || nla_put_be16(skb, CTA_PROTO_DST_PORT, tuple->dst.u.tcp.port)) goto nla_put_failure; |
c1d10adb4 [NETFILTER]: Add ... |
1328 |
return 0; |
df6fb868d [NETFILTER]: nfne... |
1329 |
nla_put_failure: |
c1d10adb4 [NETFILTER]: Add ... |
1330 1331 |
return -1; } |
fdf708322 [NETFILTER]: nfne... |
1332 |
EXPORT_SYMBOL_GPL(nf_ct_port_tuple_to_nlattr); |
c1d10adb4 [NETFILTER]: Add ... |
1333 |
|
f73e924cd [NETFILTER]: ctne... |
1334 1335 1336 |
const struct nla_policy nf_ct_port_nla_policy[CTA_PROTO_MAX+1] = { [CTA_PROTO_SRC_PORT] = { .type = NLA_U16 }, [CTA_PROTO_DST_PORT] = { .type = NLA_U16 }, |
c1d10adb4 [NETFILTER]: Add ... |
1337 |
}; |
f73e924cd [NETFILTER]: ctne... |
1338 |
EXPORT_SYMBOL_GPL(nf_ct_port_nla_policy); |
c1d10adb4 [NETFILTER]: Add ... |
1339 |
|
fdf708322 [NETFILTER]: nfne... |
1340 |
int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], |
c1d10adb4 [NETFILTER]: Add ... |
1341 1342 |
struct nf_conntrack_tuple *t) { |
df6fb868d [NETFILTER]: nfne... |
1343 |
if (!tb[CTA_PROTO_SRC_PORT] || !tb[CTA_PROTO_DST_PORT]) |
c1d10adb4 [NETFILTER]: Add ... |
1344 |
return -EINVAL; |
77236b6e3 [NETFILTER]: ctne... |
1345 1346 |
t->src.u.tcp.port = nla_get_be16(tb[CTA_PROTO_SRC_PORT]); t->dst.u.tcp.port = nla_get_be16(tb[CTA_PROTO_DST_PORT]); |
c1d10adb4 [NETFILTER]: Add ... |
1347 1348 1349 |
return 0; } |
fdf708322 [NETFILTER]: nfne... |
1350 |
EXPORT_SYMBOL_GPL(nf_ct_port_nlattr_to_tuple); |
5c0de29d0 netfilter: nf_con... |
1351 1352 1353 1354 1355 1356 |
int nf_ct_port_nlattr_tuple_size(void) { return nla_policy_len(nf_ct_port_nla_policy, CTA_PROTO_MAX + 1); } EXPORT_SYMBOL_GPL(nf_ct_port_nlattr_tuple_size); |
c1d10adb4 [NETFILTER]: Add ... |
1357 |
#endif |
9fb9cbb10 [NETFILTER]: Add ... |
1358 |
/* Used by ipt_REJECT and ip6t_REJECT. */ |
312a0c16c netfilter: nf_con... |
1359 |
static void nf_conntrack_attach(struct sk_buff *nskb, const struct sk_buff *skb) |
9fb9cbb10 [NETFILTER]: Add ... |
1360 1361 1362 1363 1364 1365 1366 |
{ struct nf_conn *ct; enum ip_conntrack_info ctinfo; /* This ICMP is in reverse direction to the packet which caused it */ ct = nf_ct_get(skb, &ctinfo); if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) |
fb0488337 netfilter: add mo... |
1367 |
ctinfo = IP_CT_RELATED_REPLY; |
9fb9cbb10 [NETFILTER]: Add ... |
1368 1369 1370 1371 1372 1373 1374 1375 |
else ctinfo = IP_CT_RELATED; /* Attach to new skbuff, and increment count */ nskb->nfct = &ct->ct_general; nskb->nfctinfo = ctinfo; nf_conntrack_get(nskb->nfct); } |
9fb9cbb10 [NETFILTER]: Add ... |
1376 |
/* Bring out ya dead! */ |
df0933dcb [NETFILTER]: kill... |
1377 |
static struct nf_conn * |
400dad39d netfilter: netns ... |
1378 |
get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data), |
9fb9cbb10 [NETFILTER]: Add ... |
1379 1380 |
void *data, unsigned int *bucket) { |
df0933dcb [NETFILTER]: kill... |
1381 1382 |
struct nf_conntrack_tuple_hash *h; struct nf_conn *ct; |
ea781f197 netfilter: nf_con... |
1383 |
struct hlist_nulls_node *n; |
b7779d06f netfilter: conntr... |
1384 |
int cpu; |
93bb0ceb7 netfilter: conntr... |
1385 |
spinlock_t *lockp; |
9fb9cbb10 [NETFILTER]: Add ... |
1386 |
|
56d52d489 netfilter: conntr... |
1387 |
for (; *bucket < nf_conntrack_htable_size; (*bucket)++) { |
93bb0ceb7 netfilter: conntr... |
1388 1389 |
lockp = &nf_conntrack_locks[*bucket % CONNTRACK_LOCKS]; local_bh_disable(); |
b16c29191 netfilter: nf_con... |
1390 |
nf_conntrack_lock(lockp); |
56d52d489 netfilter: conntr... |
1391 1392 |
if (*bucket < nf_conntrack_htable_size) { hlist_nulls_for_each_entry(h, n, &nf_conntrack_hash[*bucket], hnnode) { |
93bb0ceb7 netfilter: conntr... |
1393 1394 1395 |
if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) continue; ct = nf_ct_tuplehash_to_ctrack(h); |
e0c7d4722 netfilter: conntr... |
1396 1397 |
if (net_eq(nf_ct_net(ct), net) && iter(ct, data)) |
93bb0ceb7 netfilter: conntr... |
1398 1399 |
goto found; } |
df0933dcb [NETFILTER]: kill... |
1400 |
} |
93bb0ceb7 netfilter: conntr... |
1401 1402 |
spin_unlock(lockp); local_bh_enable(); |
d93c6258e netfilter: conntr... |
1403 |
cond_resched(); |
601e68e10 [NETFILTER]: Fix ... |
1404 |
} |
b7779d06f netfilter: conntr... |
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 |
for_each_possible_cpu(cpu) { struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); spin_lock_bh(&pcpu->lock); hlist_nulls_for_each_entry(h, n, &pcpu->unconfirmed, hnnode) { ct = nf_ct_tuplehash_to_ctrack(h); if (iter(ct, data)) set_bit(IPS_DYING_BIT, &ct->status); } spin_unlock_bh(&pcpu->lock); |
d93c6258e netfilter: conntr... |
1416 |
cond_resched(); |
b7779d06f netfilter: conntr... |
1417 |
} |
df0933dcb [NETFILTER]: kill... |
1418 1419 |
return NULL; found: |
c073e3fa8 [NETFILTER]: nf_c... |
1420 |
atomic_inc(&ct->ct_general.use); |
93bb0ceb7 netfilter: conntr... |
1421 1422 |
spin_unlock(lockp); local_bh_enable(); |
df0933dcb [NETFILTER]: kill... |
1423 |
return ct; |
9fb9cbb10 [NETFILTER]: Add ... |
1424 |
} |
400dad39d netfilter: netns ... |
1425 1426 |
void nf_ct_iterate_cleanup(struct net *net, int (*iter)(struct nf_conn *i, void *data), |
c655bc689 netfilter: nf_con... |
1427 |
void *data, u32 portid, int report) |
9fb9cbb10 [NETFILTER]: Add ... |
1428 |
{ |
df0933dcb [NETFILTER]: kill... |
1429 |
struct nf_conn *ct; |
9fb9cbb10 [NETFILTER]: Add ... |
1430 |
unsigned int bucket = 0; |
d93c6258e netfilter: conntr... |
1431 |
might_sleep(); |
88b68bc52 netfilter: conntr... |
1432 1433 |
if (atomic_read(&net->ct.count) == 0) return; |
400dad39d netfilter: netns ... |
1434 |
while ((ct = get_next_corpse(net, iter, data, &bucket)) != NULL) { |
9fb9cbb10 [NETFILTER]: Add ... |
1435 1436 |
/* Time to push up daises... */ if (del_timer(&ct->timeout)) |
c655bc689 netfilter: nf_con... |
1437 |
nf_ct_delete(ct, portid, report); |
02982c27b netfilter: nf_con... |
1438 |
|
9fb9cbb10 [NETFILTER]: Add ... |
1439 1440 1441 |
/* ... else the timer will get him soon. */ nf_ct_put(ct); |
d93c6258e netfilter: conntr... |
1442 |
cond_resched(); |
9fb9cbb10 [NETFILTER]: Add ... |
1443 1444 |
} } |
13b183391 [NETFILTER]: nf_c... |
1445 |
EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup); |
9fb9cbb10 [NETFILTER]: Add ... |
1446 |
|
274d383b9 netfilter: conntr... |
1447 1448 1449 1450 |
static int kill_all(struct nf_conn *i, void *data) { return 1; } |
d862a6622 netfilter: nf_con... |
1451 |
void nf_ct_free_hashtable(void *hash, unsigned int size) |
9fb9cbb10 [NETFILTER]: Add ... |
1452 |
{ |
d862a6622 netfilter: nf_con... |
1453 |
if (is_vmalloc_addr(hash)) |
9fb9cbb10 [NETFILTER]: Add ... |
1454 1455 |
vfree(hash); else |
601e68e10 [NETFILTER]: Fix ... |
1456 |
free_pages((unsigned long)hash, |
f205c5e0c [NETFILTER]: nf_c... |
1457 |
get_order(sizeof(struct hlist_head) * size)); |
9fb9cbb10 [NETFILTER]: Add ... |
1458 |
} |
ac565e5fc [NETFILTER]: nf_c... |
1459 |
EXPORT_SYMBOL_GPL(nf_ct_free_hashtable); |
9fb9cbb10 [NETFILTER]: Add ... |
1460 |
|
b3c5163fe netfilter: nf_con... |
1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 |
static int untrack_refs(void) { int cnt = 0, cpu; for_each_possible_cpu(cpu) { struct nf_conn *ct = &per_cpu(nf_conntrack_untracked, cpu); cnt += atomic_read(&ct->ct_general.use) - 1; } return cnt; } |
f94161c1b netfilter: nf_con... |
1472 |
void nf_conntrack_cleanup_start(void) |
9fb9cbb10 [NETFILTER]: Add ... |
1473 |
{ |
f94161c1b netfilter: nf_con... |
1474 1475 1476 1477 1478 1479 |
RCU_INIT_POINTER(ip_ct_attach, NULL); } void nf_conntrack_cleanup_end(void) { RCU_INIT_POINTER(nf_ct_destroy, NULL); |
b3c5163fe netfilter: nf_con... |
1480 |
while (untrack_refs() > 0) |
9edd7ca0a netfilter: nf_con... |
1481 |
schedule(); |
56d52d489 netfilter: conntr... |
1482 |
nf_ct_free_hashtable(nf_conntrack_hash, nf_conntrack_htable_size); |
04d870017 netfilter: nf_ct_... |
1483 |
nf_conntrack_proto_fini(); |
41d73ec05 netfilter: nf_con... |
1484 |
nf_conntrack_seqadj_fini(); |
5f69b8f52 netfilter: nf_ct_... |
1485 |
nf_conntrack_labels_fini(); |
5e615b220 netfilter: nf_ct_... |
1486 |
nf_conntrack_helper_fini(); |
8684094cf netfilter: nf_ct_... |
1487 |
nf_conntrack_timeout_fini(); |
3fe0f943d netfilter: nf_ct_... |
1488 |
nf_conntrack_ecache_fini(); |
73f4001a5 netfilter: nf_ct_... |
1489 |
nf_conntrack_tstamp_fini(); |
b7ff3a1fa netfilter: nf_ct_... |
1490 |
nf_conntrack_acct_fini(); |
83b4dbe19 netfilter: nf_ct_... |
1491 |
nf_conntrack_expect_fini(); |
775711497 netfilter: conntr... |
1492 1493 |
kmem_cache_destroy(nf_conntrack_cachep); |
08f6547d2 netfilter: netns ... |
1494 |
} |
9fb9cbb10 [NETFILTER]: Add ... |
1495 |
|
f94161c1b netfilter: nf_con... |
1496 1497 1498 1499 1500 |
/* * Mishearing the voices in his head, our hero wonders how he's * supposed to kill the mall. */ void nf_conntrack_cleanup_net(struct net *net) |
08f6547d2 netfilter: netns ... |
1501 |
{ |
dece40e84 netfilter: nf_con... |
1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 |
LIST_HEAD(single); list_add(&net->exit_list, &single); nf_conntrack_cleanup_net_list(&single); } void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list) { int busy; struct net *net; |
f94161c1b netfilter: nf_con... |
1512 1513 1514 1515 1516 1517 |
/* * This makes sure all current packets have passed through * netfilter framework. Roll on, two-stage module * delete... */ synchronize_net(); |
dece40e84 netfilter: nf_con... |
1518 1519 1520 |
i_see_dead_people: busy = 0; list_for_each_entry(net, net_exit_list, exit_list) { |
c655bc689 netfilter: nf_con... |
1521 |
nf_ct_iterate_cleanup(net, kill_all, NULL, 0, 0); |
dece40e84 netfilter: nf_con... |
1522 1523 1524 1525 |
if (atomic_read(&net->ct.count) != 0) busy = 1; } if (busy) { |
9fb9cbb10 [NETFILTER]: Add ... |
1526 1527 1528 |
schedule(); goto i_see_dead_people; } |
dece40e84 netfilter: nf_con... |
1529 |
list_for_each_entry(net, net_exit_list, exit_list) { |
dece40e84 netfilter: nf_con... |
1530 1531 1532 1533 1534 1535 |
nf_conntrack_proto_pernet_fini(net); nf_conntrack_helper_pernet_fini(net); nf_conntrack_ecache_pernet_fini(net); nf_conntrack_tstamp_pernet_fini(net); nf_conntrack_acct_pernet_fini(net); nf_conntrack_expect_pernet_fini(net); |
dece40e84 netfilter: nf_con... |
1536 |
free_percpu(net->ct.stat); |
b7779d06f netfilter: conntr... |
1537 |
free_percpu(net->ct.pcpu_lists); |
dece40e84 netfilter: nf_con... |
1538 |
} |
08f6547d2 netfilter: netns ... |
1539 |
} |
d862a6622 netfilter: nf_con... |
1540 |
void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls) |
9fb9cbb10 [NETFILTER]: Add ... |
1541 |
{ |
ea781f197 netfilter: nf_con... |
1542 1543 1544 |
struct hlist_nulls_head *hash; unsigned int nr_slots, i; size_t sz; |
9fb9cbb10 [NETFILTER]: Add ... |
1545 |
|
ea781f197 netfilter: nf_con... |
1546 1547 1548 1549 1550 |
BUILD_BUG_ON(sizeof(struct hlist_nulls_head) != sizeof(struct hlist_head)); nr_slots = *sizep = roundup(*sizep, PAGE_SIZE / sizeof(struct hlist_nulls_head)); sz = nr_slots * sizeof(struct hlist_nulls_head); hash = (void *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, get_order(sz)); |
f0ad46218 netfilter: nf_con... |
1551 |
if (!hash) |
966567b76 net: two vzalloc(... |
1552 |
hash = vzalloc(sz); |
9fb9cbb10 [NETFILTER]: Add ... |
1553 |
|
ea781f197 netfilter: nf_con... |
1554 1555 1556 |
if (hash && nulls) for (i = 0; i < nr_slots; i++) INIT_HLIST_NULLS_HEAD(&hash[i], i); |
9fb9cbb10 [NETFILTER]: Add ... |
1557 1558 1559 |
return hash; } |
ac565e5fc [NETFILTER]: nf_c... |
1560 |
EXPORT_SYMBOL_GPL(nf_ct_alloc_hashtable); |
9fb9cbb10 [NETFILTER]: Add ... |
1561 |
|
3183ab899 netfilter: conntr... |
1562 |
int nf_conntrack_hash_resize(unsigned int hashsize) |
9fb9cbb10 [NETFILTER]: Add ... |
1563 |
{ |
3183ab899 netfilter: conntr... |
1564 1565 |
int i, bucket; unsigned int old_size; |
ea781f197 netfilter: nf_con... |
1566 |
struct hlist_nulls_head *hash, *old_hash; |
9fb9cbb10 [NETFILTER]: Add ... |
1567 |
struct nf_conntrack_tuple_hash *h; |
5d0aa2ccd netfilter: nf_con... |
1568 |
struct nf_conn *ct; |
9fb9cbb10 [NETFILTER]: Add ... |
1569 |
|
9fb9cbb10 [NETFILTER]: Add ... |
1570 1571 |
if (!hashsize) return -EINVAL; |
d862a6622 netfilter: nf_con... |
1572 |
hash = nf_ct_alloc_hashtable(&hashsize, 1); |
9fb9cbb10 [NETFILTER]: Add ... |
1573 1574 |
if (!hash) return -ENOMEM; |
3183ab899 netfilter: conntr... |
1575 1576 1577 1578 1579 |
old_size = nf_conntrack_htable_size; if (old_size == hashsize) { nf_ct_free_hashtable(hash, hashsize); return 0; } |
93bb0ceb7 netfilter: conntr... |
1580 1581 |
local_bh_disable(); nf_conntrack_all_lock(); |
a3efd8120 netfilter: conntr... |
1582 |
write_seqcount_begin(&nf_conntrack_generation); |
93bb0ceb7 netfilter: conntr... |
1583 |
|
76507f69c [NETFILTER]: nf_c... |
1584 1585 1586 |
/* Lookups in the old hash might happen in parallel, which means we * might get false negatives during connection lookup. New connections * created because of a false negative won't make it into the hash |
93bb0ceb7 netfilter: conntr... |
1587 |
* though since that required taking the locks. |
76507f69c [NETFILTER]: nf_c... |
1588 |
*/ |
93bb0ceb7 netfilter: conntr... |
1589 |
|
56d52d489 netfilter: conntr... |
1590 1591 1592 1593 |
for (i = 0; i < nf_conntrack_htable_size; i++) { while (!hlist_nulls_empty(&nf_conntrack_hash[i])) { h = hlist_nulls_entry(nf_conntrack_hash[i].first, struct nf_conntrack_tuple_hash, hnnode); |
5d0aa2ccd netfilter: nf_con... |
1594 |
ct = nf_ct_tuplehash_to_ctrack(h); |
ea781f197 netfilter: nf_con... |
1595 |
hlist_nulls_del_rcu(&h->hnnode); |
1b8c8a9f6 netfilter: conntr... |
1596 1597 |
bucket = __hash_conntrack(nf_ct_net(ct), &h->tuple, hashsize); |
ea781f197 netfilter: nf_con... |
1598 |
hlist_nulls_add_head_rcu(&h->hnnode, &hash[bucket]); |
9fb9cbb10 [NETFILTER]: Add ... |
1599 1600 |
} } |
56d52d489 netfilter: conntr... |
1601 1602 |
old_size = nf_conntrack_htable_size; old_hash = nf_conntrack_hash; |
9fb9cbb10 [NETFILTER]: Add ... |
1603 |
|
56d52d489 netfilter: conntr... |
1604 1605 |
nf_conntrack_hash = hash; nf_conntrack_htable_size = hashsize; |
93bb0ceb7 netfilter: conntr... |
1606 |
|
a3efd8120 netfilter: conntr... |
1607 |
write_seqcount_end(&nf_conntrack_generation); |
93bb0ceb7 netfilter: conntr... |
1608 1609 |
nf_conntrack_all_unlock(); local_bh_enable(); |
9fb9cbb10 [NETFILTER]: Add ... |
1610 |
|
5e3c61f98 netfilter: conntr... |
1611 |
synchronize_net(); |
d862a6622 netfilter: nf_con... |
1612 |
nf_ct_free_hashtable(old_hash, old_size); |
9fb9cbb10 [NETFILTER]: Add ... |
1613 1614 |
return 0; } |
3183ab899 netfilter: conntr... |
1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 |
int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) { unsigned int hashsize; int rc; if (current->nsproxy->net_ns != &init_net) return -EOPNOTSUPP; /* On boot, we can set this without any fancy locking. */ if (!nf_conntrack_htable_size) return param_set_uint(val, kp); rc = kstrtouint(val, 0, &hashsize); if (rc) return rc; return nf_conntrack_hash_resize(hashsize); } |
fae718dda [NETFILTER]: nf_c... |
1634 |
EXPORT_SYMBOL_GPL(nf_conntrack_set_hashsize); |
9fb9cbb10 [NETFILTER]: Add ... |
1635 |
|
fae718dda [NETFILTER]: nf_c... |
1636 |
module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, |
9fb9cbb10 [NETFILTER]: Add ... |
1637 |
&nf_conntrack_htable_size, 0600); |
5bfddbd46 netfilter: nf_con... |
1638 1639 |
void nf_ct_untracked_status_or(unsigned long bits) { |
b3c5163fe netfilter: nf_con... |
1640 1641 1642 1643 |
int cpu; for_each_possible_cpu(cpu) per_cpu(nf_conntrack_untracked, cpu).status |= bits; |
5bfddbd46 netfilter: nf_con... |
1644 1645 |
} EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or); |
f94161c1b netfilter: nf_con... |
1646 |
int nf_conntrack_init_start(void) |
9fb9cbb10 [NETFILTER]: Add ... |
1647 |
{ |
f205c5e0c [NETFILTER]: nf_c... |
1648 |
int max_factor = 8; |
0c5366b3a netfilter: conntr... |
1649 1650 |
int ret = -ENOMEM; int i, cpu; |
93bb0ceb7 netfilter: conntr... |
1651 |
|
a3efd8120 netfilter: conntr... |
1652 |
seqcount_init(&nf_conntrack_generation); |
d5d20912d netfilter: conntr... |
1653 |
for (i = 0; i < CONNTRACK_LOCKS; i++) |
93bb0ceb7 netfilter: conntr... |
1654 |
spin_lock_init(&nf_conntrack_locks[i]); |
9fb9cbb10 [NETFILTER]: Add ... |
1655 |
|
9fb9cbb10 [NETFILTER]: Add ... |
1656 |
if (!nf_conntrack_htable_size) { |
88eab472e netfilter: conntr... |
1657 1658 1659 1660 1661 |
/* Idea from tcp.c: use 1/16384 of memory. * On i386: 32MB machine has 512 buckets. * >= 1GB machines have 16384 buckets. * >= 4GB machines have 65536 buckets. */ |
9fb9cbb10 [NETFILTER]: Add ... |
1662 |
nf_conntrack_htable_size |
4481374ce mm: replace vario... |
1663 |
= (((totalram_pages << PAGE_SHIFT) / 16384) |
f205c5e0c [NETFILTER]: nf_c... |
1664 |
/ sizeof(struct hlist_head)); |
88eab472e netfilter: conntr... |
1665 1666 1667 |
if (totalram_pages > (4 * (1024 * 1024 * 1024 / PAGE_SIZE))) nf_conntrack_htable_size = 65536; else if (totalram_pages > (1024 * 1024 * 1024 / PAGE_SIZE)) |
f205c5e0c [NETFILTER]: nf_c... |
1668 1669 1670 1671 1672 1673 1674 1675 1676 |
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; |
9fb9cbb10 [NETFILTER]: Add ... |
1677 |
} |
56d52d489 netfilter: conntr... |
1678 1679 1680 1681 |
nf_conntrack_hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, 1); if (!nf_conntrack_hash) return -ENOMEM; |
f205c5e0c [NETFILTER]: nf_c... |
1682 |
nf_conntrack_max = max_factor * nf_conntrack_htable_size; |
8e5105a0c [NETFILTER]: nf_c... |
1683 |
|
0c5366b3a netfilter: conntr... |
1684 1685 |
nf_conntrack_cachep = kmem_cache_create("nf_conntrack", sizeof(struct nf_conn), 0, |
5a75cdeba netfilter: conntr... |
1686 |
SLAB_DESTROY_BY_RCU | SLAB_HWCACHE_ALIGN, NULL); |
0c5366b3a netfilter: conntr... |
1687 1688 |
if (!nf_conntrack_cachep) goto err_cachep; |
654d0fbdc netfilter: cleanu... |
1689 1690 |
printk(KERN_INFO "nf_conntrack version %s (%u buckets, %d max) ", |
8e5105a0c [NETFILTER]: nf_c... |
1691 1692 |
NF_CONNTRACK_VERSION, nf_conntrack_htable_size, nf_conntrack_max); |
83b4dbe19 netfilter: nf_ct_... |
1693 1694 1695 1696 |
ret = nf_conntrack_expect_init(); if (ret < 0) goto err_expect; |
b7ff3a1fa netfilter: nf_ct_... |
1697 1698 1699 |
ret = nf_conntrack_acct_init(); if (ret < 0) goto err_acct; |
73f4001a5 netfilter: nf_ct_... |
1700 1701 1702 |
ret = nf_conntrack_tstamp_init(); if (ret < 0) goto err_tstamp; |
3fe0f943d netfilter: nf_ct_... |
1703 1704 1705 |
ret = nf_conntrack_ecache_init(); if (ret < 0) goto err_ecache; |
8684094cf netfilter: nf_ct_... |
1706 1707 1708 |
ret = nf_conntrack_timeout_init(); if (ret < 0) goto err_timeout; |
5e615b220 netfilter: nf_ct_... |
1709 1710 1711 |
ret = nf_conntrack_helper_init(); if (ret < 0) goto err_helper; |
5f69b8f52 netfilter: nf_ct_... |
1712 1713 1714 |
ret = nf_conntrack_labels_init(); if (ret < 0) goto err_labels; |
41d73ec05 netfilter: nf_con... |
1715 1716 1717 |
ret = nf_conntrack_seqadj_init(); if (ret < 0) goto err_seqadj; |
04d870017 netfilter: nf_ct_... |
1718 1719 1720 |
ret = nf_conntrack_proto_init(); if (ret < 0) goto err_proto; |
9edd7ca0a netfilter: nf_con... |
1721 |
/* Set up fake conntrack: to never be deleted, not in any hashes */ |
b3c5163fe netfilter: nf_con... |
1722 1723 |
for_each_possible_cpu(cpu) { struct nf_conn *ct = &per_cpu(nf_conntrack_untracked, cpu); |
b3c5163fe netfilter: nf_con... |
1724 1725 1726 |
write_pnet(&ct->ct_net, &init_net); atomic_set(&ct->ct_general.use, 1); } |
9edd7ca0a netfilter: nf_con... |
1727 |
/* - and look it like as a confirmed connection */ |
5bfddbd46 netfilter: nf_con... |
1728 |
nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED); |
08f6547d2 netfilter: netns ... |
1729 |
return 0; |
04d870017 netfilter: nf_ct_... |
1730 |
err_proto: |
41d73ec05 netfilter: nf_con... |
1731 1732 |
nf_conntrack_seqadj_fini(); err_seqadj: |
04d870017 netfilter: nf_ct_... |
1733 |
nf_conntrack_labels_fini(); |
5f69b8f52 netfilter: nf_ct_... |
1734 1735 |
err_labels: nf_conntrack_helper_fini(); |
5e615b220 netfilter: nf_ct_... |
1736 1737 |
err_helper: nf_conntrack_timeout_fini(); |
8684094cf netfilter: nf_ct_... |
1738 1739 |
err_timeout: nf_conntrack_ecache_fini(); |
3fe0f943d netfilter: nf_ct_... |
1740 1741 |
err_ecache: nf_conntrack_tstamp_fini(); |
73f4001a5 netfilter: nf_ct_... |
1742 1743 |
err_tstamp: nf_conntrack_acct_fini(); |
b7ff3a1fa netfilter: nf_ct_... |
1744 1745 |
err_acct: nf_conntrack_expect_fini(); |
83b4dbe19 netfilter: nf_ct_... |
1746 |
err_expect: |
0c5366b3a netfilter: conntr... |
1747 1748 |
kmem_cache_destroy(nf_conntrack_cachep); err_cachep: |
56d52d489 netfilter: conntr... |
1749 |
nf_ct_free_hashtable(nf_conntrack_hash, nf_conntrack_htable_size); |
08f6547d2 netfilter: netns ... |
1750 1751 |
return ret; } |
f94161c1b netfilter: nf_con... |
1752 1753 1754 1755 1756 |
void nf_conntrack_init_end(void) { /* For use by REJECT target */ RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach); RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack); |
f94161c1b netfilter: nf_con... |
1757 |
} |
8cc20198c netfilter: nf_con... |
1758 1759 1760 1761 1762 |
/* * We need to use special "null" values, not used in hash table */ #define UNCONFIRMED_NULLS_VAL ((1<<30)+0) #define DYING_NULLS_VAL ((1<<30)+1) |
252b3e8c1 netfilter: xt_CT:... |
1763 |
#define TEMPLATE_NULLS_VAL ((1<<30)+2) |
8cc20198c netfilter: nf_con... |
1764 |
|
f94161c1b netfilter: nf_con... |
1765 |
int nf_conntrack_init_net(struct net *net) |
08f6547d2 netfilter: netns ... |
1766 |
{ |
b7779d06f netfilter: conntr... |
1767 1768 |
int ret = -ENOMEM; int cpu; |
ceceae1b1 [NETFILTER]: nf_c... |
1769 |
|
08f6547d2 netfilter: netns ... |
1770 |
atomic_set(&net->ct.count, 0); |
b7779d06f netfilter: conntr... |
1771 1772 1773 |
net->ct.pcpu_lists = alloc_percpu(struct ct_pcpu); if (!net->ct.pcpu_lists) |
08f6547d2 netfilter: netns ... |
1774 |
goto err_stat; |
b7779d06f netfilter: conntr... |
1775 1776 1777 1778 1779 1780 1781 |
for_each_possible_cpu(cpu) { struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); spin_lock_init(&pcpu->lock); INIT_HLIST_NULLS_HEAD(&pcpu->unconfirmed, UNCONFIRMED_NULLS_VAL); INIT_HLIST_NULLS_HEAD(&pcpu->dying, DYING_NULLS_VAL); |
08f6547d2 netfilter: netns ... |
1782 |
} |
5b3501faa netfilter: nf_con... |
1783 |
|
b7779d06f netfilter: conntr... |
1784 1785 1786 |
net->ct.stat = alloc_percpu(struct ip_conntrack_stat); if (!net->ct.stat) goto err_pcpu_lists; |
83b4dbe19 netfilter: nf_ct_... |
1787 |
ret = nf_conntrack_expect_pernet_init(net); |
08f6547d2 netfilter: netns ... |
1788 1789 |
if (ret < 0) goto err_expect; |
b7ff3a1fa netfilter: nf_ct_... |
1790 |
ret = nf_conntrack_acct_pernet_init(net); |
584015727 netfilter: accoun... |
1791 |
if (ret < 0) |
08f6547d2 netfilter: netns ... |
1792 |
goto err_acct; |
73f4001a5 netfilter: nf_ct_... |
1793 |
ret = nf_conntrack_tstamp_pernet_init(net); |
a992ca2a0 netfilter: nf_con... |
1794 1795 |
if (ret < 0) goto err_tstamp; |
3fe0f943d netfilter: nf_ct_... |
1796 |
ret = nf_conntrack_ecache_pernet_init(net); |
a0891aa6a netfilter: conntr... |
1797 1798 |
if (ret < 0) goto err_ecache; |
5e615b220 netfilter: nf_ct_... |
1799 |
ret = nf_conntrack_helper_pernet_init(net); |
a90068926 netfilter: nf_ct_... |
1800 1801 |
if (ret < 0) goto err_helper; |
04d870017 netfilter: nf_ct_... |
1802 |
ret = nf_conntrack_proto_pernet_init(net); |
f94161c1b netfilter: nf_con... |
1803 1804 |
if (ret < 0) goto err_proto; |
08f6547d2 netfilter: netns ... |
1805 |
return 0; |
c539f0171 netfilter: add co... |
1806 |
|
f94161c1b netfilter: nf_con... |
1807 |
err_proto: |
5e615b220 netfilter: nf_ct_... |
1808 |
nf_conntrack_helper_pernet_fini(net); |
a90068926 netfilter: nf_ct_... |
1809 |
err_helper: |
3fe0f943d netfilter: nf_ct_... |
1810 |
nf_conntrack_ecache_pernet_fini(net); |
a0891aa6a netfilter: conntr... |
1811 |
err_ecache: |
73f4001a5 netfilter: nf_ct_... |
1812 |
nf_conntrack_tstamp_pernet_fini(net); |
a992ca2a0 netfilter: nf_con... |
1813 |
err_tstamp: |
b7ff3a1fa netfilter: nf_ct_... |
1814 |
nf_conntrack_acct_pernet_fini(net); |
08f6547d2 netfilter: netns ... |
1815 |
err_acct: |
83b4dbe19 netfilter: nf_ct_... |
1816 |
nf_conntrack_expect_pernet_fini(net); |
08f6547d2 netfilter: netns ... |
1817 |
err_expect: |
0d55af879 netfilter: netns ... |
1818 |
free_percpu(net->ct.stat); |
b7779d06f netfilter: conntr... |
1819 1820 |
err_pcpu_lists: free_percpu(net->ct.pcpu_lists); |
0d55af879 netfilter: netns ... |
1821 |
err_stat: |
08f6547d2 netfilter: netns ... |
1822 1823 |
return ret; } |