Blame view

net/netfilter/nf_conntrack_helper.c 15.1 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
2
3
4
5
6
  /* Helper handling for netfilter. */
  
  /* (C) 1999-2001 Paul `Rusty' Russell
   * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
   * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
f229f6ce4   Patrick McHardy   netfilter: add my...
7
   * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
8
9
10
11
12
13
14
15
   */
  
  #include <linux/types.h>
  #include <linux/netfilter.h>
  #include <linux/module.h>
  #include <linux/skbuff.h>
  #include <linux/vmalloc.h>
  #include <linux/stddef.h>
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
16
17
18
19
  #include <linux/random.h>
  #include <linux/err.h>
  #include <linux/kernel.h>
  #include <linux/netdevice.h>
2ba4cc319   Ingo Molnar   rcu: fix nf_connt...
20
  #include <linux/rculist.h>
efb9a8c28   Alexey Dobriyan   netfilter: netns ...
21
  #include <linux/rtnetlink.h>
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
22

7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
23
  #include <net/netfilter/nf_conntrack.h>
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
24
  #include <net/netfilter/nf_conntrack_core.h>
40d102cde   Jeremy Sowden   netfilter: update...
25
  #include <net/netfilter/nf_conntrack_ecache.h>
ceceae1b1   Yasuyuki Kozakai   [NETFILTER]: nf_c...
26
  #include <net/netfilter/nf_conntrack_extend.h>
40d102cde   Jeremy Sowden   netfilter: update...
27
28
  #include <net/netfilter/nf_conntrack_helper.h>
  #include <net/netfilter/nf_conntrack_l4proto.h>
b20ab9cc6   Pablo Neira Ayuso   netfilter: nf_ct_...
29
  #include <net/netfilter/nf_log.h>
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
30

58a3c9bb0   Patrick McHardy   [NETFILTER]: nf_c...
31
  static DEFINE_MUTEX(nf_ct_helper_mutex);
12f7a5053   Pablo Neira Ayuso   netfilter: add us...
32
33
34
35
  struct hlist_head *nf_ct_helper_hash __read_mostly;
  EXPORT_SYMBOL_GPL(nf_ct_helper_hash);
  unsigned int nf_ct_helper_hsize __read_mostly;
  EXPORT_SYMBOL_GPL(nf_ct_helper_hsize);
b8a7fe6c1   Patrick McHardy   [NETFILTER]: nf_c...
36
  static unsigned int nf_ct_helper_count __read_mostly;
b8a7fe6c1   Patrick McHardy   [NETFILTER]: nf_c...
37

3bb398d92   Pablo Neira Ayuso   netfilter: nf_ct_...
38
  static bool nf_ct_auto_assign_helper __read_mostly = false;
a90068926   Eric Leblond   netfilter: nf_ct_...
39
40
  module_param_named(nf_conntrack_helper, nf_ct_auto_assign_helper, bool, 0644);
  MODULE_PARM_DESC(nf_conntrack_helper,
3bb398d92   Pablo Neira Ayuso   netfilter: nf_ct_...
41
  		 "Enable automatic conntrack helper assignment (default 0)");
a90068926   Eric Leblond   netfilter: nf_ct_...
42

08010a216   Flavio Leitner   netfilter: add AP...
43
44
  static DEFINE_MUTEX(nf_ct_nat_helpers_mutex);
  static struct list_head nf_ct_nat_helpers __read_mostly;
b8a7fe6c1   Patrick McHardy   [NETFILTER]: nf_c...
45
46
47
48
49
  /* Stupid hash, but collision free for the default registrations of the
   * helpers currently in the kernel. */
  static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple)
  {
  	return (((tuple->src.l3num << 8) | tuple->dst.protonum) ^
a34c45896   Al Viro   netfilter endian ...
50
  		(__force __u16)tuple->src.u.all) % nf_ct_helper_hsize;
b8a7fe6c1   Patrick McHardy   [NETFILTER]: nf_c...
51
  }
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
52

226c0c0ef   Pablo Neira Ayuso   netfilter: ctnetl...
53
  static struct nf_conntrack_helper *
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
54
55
  __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
  {
b8a7fe6c1   Patrick McHardy   [NETFILTER]: nf_c...
56
  	struct nf_conntrack_helper *helper;
d4156e8cd   Patrick McHardy   [NETFILTER]: nf_c...
57
  	struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
b8a7fe6c1   Patrick McHardy   [NETFILTER]: nf_c...
58
  	unsigned int h;
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
59

b8a7fe6c1   Patrick McHardy   [NETFILTER]: nf_c...
60
61
62
63
  	if (!nf_ct_helper_count)
  		return NULL;
  
  	h = helper_hash(tuple);
b67bfe0d4   Sasha Levin   hlist: drop the n...
64
  	hlist_for_each_entry_rcu(helper, &nf_ct_helper_hash[h], hnode) {
b8a7fe6c1   Patrick McHardy   [NETFILTER]: nf_c...
65
66
  		if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask))
  			return helper;
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
67
68
69
  	}
  	return NULL;
  }
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
70
71
  
  struct nf_conntrack_helper *
794e68716   Patrick McHardy   netfilter: ctnetl...
72
  __nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum)
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
73
74
  {
  	struct nf_conntrack_helper *h;
b8a7fe6c1   Patrick McHardy   [NETFILTER]: nf_c...
75
  	unsigned int i;
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
76

b8a7fe6c1   Patrick McHardy   [NETFILTER]: nf_c...
77
  	for (i = 0; i < nf_ct_helper_hsize; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
78
  		hlist_for_each_entry_rcu(h, &nf_ct_helper_hash[i], hnode) {
6114cc516   Florian Westphal   netfilter: conntr...
79
80
81
82
83
84
85
86
  			if (strcmp(h->name, name))
  				continue;
  
  			if (h->tuple.src.l3num != NFPROTO_UNSPEC &&
  			    h->tuple.src.l3num != l3num)
  				continue;
  
  			if (h->tuple.dst.protonum == protonum)
b8a7fe6c1   Patrick McHardy   [NETFILTER]: nf_c...
87
88
  				return h;
  		}
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
89
  	}
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
90
91
  	return NULL;
  }
794e68716   Patrick McHardy   netfilter: ctnetl...
92
  EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find);
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
93

84f3bb9ae   Patrick McHardy   netfilter: xtable...
94
95
96
97
  struct nf_conntrack_helper *
  nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
  {
  	struct nf_conntrack_helper *h;
8b5995d06   Gao Feng   netfilter: helper...
98
  	rcu_read_lock();
84f3bb9ae   Patrick McHardy   netfilter: xtable...
99
100
101
  	h = __nf_conntrack_helper_find(name, l3num, protonum);
  #ifdef CONFIG_MODULES
  	if (h == NULL) {
8b5995d06   Gao Feng   netfilter: helper...
102
103
104
  		rcu_read_unlock();
  		if (request_module("nfct-helper-%s", name) == 0) {
  			rcu_read_lock();
84f3bb9ae   Patrick McHardy   netfilter: xtable...
105
  			h = __nf_conntrack_helper_find(name, l3num, protonum);
8b5995d06   Gao Feng   netfilter: helper...
106
107
108
  		} else {
  			return h;
  		}
84f3bb9ae   Patrick McHardy   netfilter: xtable...
109
110
111
112
  	}
  #endif
  	if (h != NULL && !try_module_get(h->me))
  		h = NULL;
9338d7b44   Liping Zhang   netfilter: nfnl_c...
113
114
115
116
  	if (h != NULL && !refcount_inc_not_zero(&h->refcnt)) {
  		module_put(h->me);
  		h = NULL;
  	}
84f3bb9ae   Patrick McHardy   netfilter: xtable...
117

8b5995d06   Gao Feng   netfilter: helper...
118
  	rcu_read_unlock();
84f3bb9ae   Patrick McHardy   netfilter: xtable...
119
120
121
  	return h;
  }
  EXPORT_SYMBOL_GPL(nf_conntrack_helper_try_module_get);
d91fc59cd   Liping Zhang   netfilter: introd...
122
123
  void nf_conntrack_helper_put(struct nf_conntrack_helper *helper)
  {
9338d7b44   Liping Zhang   netfilter: nfnl_c...
124
  	refcount_dec(&helper->refcnt);
d91fc59cd   Liping Zhang   netfilter: introd...
125
126
127
  	module_put(helper->me);
  }
  EXPORT_SYMBOL_GPL(nf_conntrack_helper_put);
08010a216   Flavio Leitner   netfilter: add AP...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  static struct nf_conntrack_nat_helper *
  nf_conntrack_nat_helper_find(const char *mod_name)
  {
  	struct nf_conntrack_nat_helper *cur;
  	bool found = false;
  
  	list_for_each_entry_rcu(cur, &nf_ct_nat_helpers, list) {
  		if (!strcmp(cur->mod_name, mod_name)) {
  			found = true;
  			break;
  		}
  	}
  	return found ? cur : NULL;
  }
  
  int
  nf_nat_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
  {
  	struct nf_conntrack_helper *h;
  	struct nf_conntrack_nat_helper *nat;
  	char mod_name[NF_CT_HELPER_NAME_LEN];
  	int ret = 0;
  
  	rcu_read_lock();
  	h = __nf_conntrack_helper_find(name, l3num, protonum);
  	if (!h) {
  		rcu_read_unlock();
  		return -ENOENT;
  	}
  
  	nat = nf_conntrack_nat_helper_find(h->nat_mod_name);
  	if (!nat) {
  		snprintf(mod_name, sizeof(mod_name), "%s", h->nat_mod_name);
  		rcu_read_unlock();
  		request_module(mod_name);
  
  		rcu_read_lock();
  		nat = nf_conntrack_nat_helper_find(mod_name);
  		if (!nat) {
  			rcu_read_unlock();
  			return -ENOENT;
  		}
  	}
  
  	if (!try_module_get(nat->module))
  		ret = -ENOENT;
  
  	rcu_read_unlock();
  	return ret;
  }
  EXPORT_SYMBOL_GPL(nf_nat_helper_try_module_get);
  
  void nf_nat_helper_put(struct nf_conntrack_helper *helper)
  {
  	struct nf_conntrack_nat_helper *nat;
  
  	nat = nf_conntrack_nat_helper_find(helper->nat_mod_name);
  	if (WARN_ON_ONCE(!nat))
  		return;
  
  	module_put(nat->module);
  }
  EXPORT_SYMBOL_GPL(nf_nat_helper_put);
1afc56794   Pablo Neira Ayuso   netfilter: nf_ct_...
191
  struct nf_conn_help *
440534d3c   Gao Feng   netfilter: Remove...
192
  nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)
b560580a1   Patrick McHardy   [NETFILTER]: nf_c...
193
194
  {
  	struct nf_conn_help *help;
9f0f3ebed   Florian Westphal   netfilter: helper...
195
  	help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, gfp);
b560580a1   Patrick McHardy   [NETFILTER]: nf_c...
196
197
198
199
200
201
202
  	if (help)
  		INIT_HLIST_HEAD(&help->expectations);
  	else
  		pr_debug("failed to add helper extension area");
  	return help;
  }
  EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add);
dfe75ff8c   Jiri Kosina   netfilter: nf_ct_...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  static struct nf_conntrack_helper *
  nf_ct_lookup_helper(struct nf_conn *ct, struct net *net)
  {
  	if (!net->ct.sysctl_auto_assign_helper) {
  		if (net->ct.auto_assign_helper_warned)
  			return NULL;
  		if (!__nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple))
  			return NULL;
  		pr_info("nf_conntrack: default automatic helper assignment "
  			"has been turned off for security reasons and CT-based "
  			" firewall rule not found. Use the iptables CT target "
  			"to attach helpers instead.
  ");
  		net->ct.auto_assign_helper_warned = 1;
  		return NULL;
  	}
  
  	return __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
  }
b2a15a604   Patrick McHardy   netfilter: nf_con...
222
223
  int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
  			      gfp_t flags)
226c0c0ef   Pablo Neira Ayuso   netfilter: ctnetl...
224
  {
b2a15a604   Patrick McHardy   netfilter: nf_con...
225
226
  	struct nf_conntrack_helper *helper = NULL;
  	struct nf_conn_help *help;
a90068926   Eric Leblond   netfilter: nf_ct_...
227
  	struct net *net = nf_ct_net(ct);
226c0c0ef   Pablo Neira Ayuso   netfilter: ctnetl...
228

6714cf546   Pablo Neira Ayuso   netfilter: nf_con...
229
230
231
232
233
234
235
236
  	/* We already got a helper explicitly attached. The function
  	 * nf_conntrack_alter_reply - in case NAT is in use - asks for looking
  	 * the helper up again. Since now the user is in full control of
  	 * making consistent helper configurations, skip this automatic
  	 * re-lookup, otherwise we'll lose the helper.
  	 */
  	if (test_bit(IPS_HELPER_BIT, &ct->status))
  		return 0;
b2a15a604   Patrick McHardy   netfilter: nf_con...
237
238
  	if (tmpl != NULL) {
  		help = nfct_help(tmpl);
6714cf546   Pablo Neira Ayuso   netfilter: nf_con...
239
  		if (help != NULL) {
b2a15a604   Patrick McHardy   netfilter: nf_con...
240
  			helper = help->helper;
6714cf546   Pablo Neira Ayuso   netfilter: nf_con...
241
242
  			set_bit(IPS_HELPER_BIT, &ct->status);
  		}
b2a15a604   Patrick McHardy   netfilter: nf_con...
243
244
245
  	}
  
  	help = nfct_help(ct);
a90068926   Eric Leblond   netfilter: nf_ct_...
246

226c0c0ef   Pablo Neira Ayuso   netfilter: ctnetl...
247
  	if (helper == NULL) {
dfe75ff8c   Jiri Kosina   netfilter: nf_ct_...
248
249
250
251
252
253
  		helper = nf_ct_lookup_helper(ct, net);
  		if (helper == NULL) {
  			if (help)
  				RCU_INIT_POINTER(help->helper, NULL);
  			return 0;
  		}
226c0c0ef   Pablo Neira Ayuso   netfilter: ctnetl...
254
255
256
  	}
  
  	if (help == NULL) {
440534d3c   Gao Feng   netfilter: Remove...
257
  		help = nf_ct_helper_ext_add(ct, flags);
cf71c03ed   Pablo Neira   netfilter: nf_con...
258
259
  		if (help == NULL)
  			return -ENOMEM;
226c0c0ef   Pablo Neira Ayuso   netfilter: ctnetl...
260
  	} else {
32f537600   Pablo Neira Ayuso   netfilter: nf_ct_...
261
262
263
  		/* We only allow helper re-assignment of the same sort since
  		 * we cannot reallocate the helper extension area.
  		 */
6e2f0aa8c   Florian Westphal   netfilter: nf_ct_...
264
265
266
  		struct nf_conntrack_helper *tmp = rcu_dereference(help->helper);
  
  		if (tmp && tmp->help != helper->help) {
32f537600   Pablo Neira Ayuso   netfilter: nf_ct_...
267
  			RCU_INIT_POINTER(help->helper, NULL);
cf71c03ed   Pablo Neira   netfilter: nf_con...
268
  			return 0;
32f537600   Pablo Neira Ayuso   netfilter: nf_ct_...
269
  		}
226c0c0ef   Pablo Neira Ayuso   netfilter: ctnetl...
270
  	}
cf778b00e   Eric Dumazet   net: reintroduce ...
271
  	rcu_assign_pointer(help->helper, helper);
cf71c03ed   Pablo Neira   netfilter: nf_con...
272
273
  
  	return 0;
226c0c0ef   Pablo Neira Ayuso   netfilter: ctnetl...
274
275
  }
  EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper);
01cfa0a4e   stephen hemminger   netfilter: fix sp...
276
  /* appropriate ct lock protecting must be taken by caller */
ff1acc496   Liping Zhang   netfilter: nf_ct_...
277
  static int unhelp(struct nf_conn *ct, void *me)
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
278
  {
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
279
  	struct nf_conn_help *help = nfct_help(ct);
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
280
  	if (help && rcu_dereference_raw(help->helper) == me) {
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
281
  		nf_conntrack_event(IPCT_HELPER, ct);
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
282
  		RCU_INIT_POINTER(help->helper, NULL);
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
283
  	}
ff1acc496   Liping Zhang   netfilter: nf_ct_...
284
285
  
  	/* We are not intended to delete this conntrack. */
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
286
287
  	return 0;
  }
9858a3ae1   Pablo Neira Ayuso   netfilter: conntr...
288
289
290
291
292
293
294
295
296
297
298
299
300
  void nf_ct_helper_destroy(struct nf_conn *ct)
  {
  	struct nf_conn_help *help = nfct_help(ct);
  	struct nf_conntrack_helper *helper;
  
  	if (help) {
  		rcu_read_lock();
  		helper = rcu_dereference(help->helper);
  		if (helper && helper->destroy)
  			helper->destroy(ct);
  		rcu_read_unlock();
  	}
  }
544d5c7d9   Pablo Neira Ayuso   netfilter: ctnetl...
301
302
303
304
  static LIST_HEAD(nf_ct_helper_expectfn_list);
  
  void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n)
  {
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
305
  	spin_lock_bh(&nf_conntrack_expect_lock);
544d5c7d9   Pablo Neira Ayuso   netfilter: ctnetl...
306
  	list_add_rcu(&n->head, &nf_ct_helper_expectfn_list);
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
307
  	spin_unlock_bh(&nf_conntrack_expect_lock);
544d5c7d9   Pablo Neira Ayuso   netfilter: ctnetl...
308
309
310
311
312
  }
  EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_register);
  
  void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n)
  {
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
313
  	spin_lock_bh(&nf_conntrack_expect_lock);
544d5c7d9   Pablo Neira Ayuso   netfilter: ctnetl...
314
  	list_del_rcu(&n->head);
ca7433df3   Jesper Dangaard Brouer   netfilter: conntr...
315
  	spin_unlock_bh(&nf_conntrack_expect_lock);
544d5c7d9   Pablo Neira Ayuso   netfilter: ctnetl...
316
317
  }
  EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister);
8b5995d06   Gao Feng   netfilter: helper...
318
  /* Caller should hold the rcu lock */
544d5c7d9   Pablo Neira Ayuso   netfilter: ctnetl...
319
320
321
322
323
  struct nf_ct_helper_expectfn *
  nf_ct_helper_expectfn_find_by_name(const char *name)
  {
  	struct nf_ct_helper_expectfn *cur;
  	bool found = false;
544d5c7d9   Pablo Neira Ayuso   netfilter: ctnetl...
324
325
326
327
328
329
  	list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
  		if (!strcmp(cur->name, name)) {
  			found = true;
  			break;
  		}
  	}
544d5c7d9   Pablo Neira Ayuso   netfilter: ctnetl...
330
331
332
  	return found ? cur : NULL;
  }
  EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_name);
8b5995d06   Gao Feng   netfilter: helper...
333
  /* Caller should hold the rcu lock */
544d5c7d9   Pablo Neira Ayuso   netfilter: ctnetl...
334
335
336
337
338
  struct nf_ct_helper_expectfn *
  nf_ct_helper_expectfn_find_by_symbol(const void *symbol)
  {
  	struct nf_ct_helper_expectfn *cur;
  	bool found = false;
544d5c7d9   Pablo Neira Ayuso   netfilter: ctnetl...
339
340
341
342
343
344
  	list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
  		if (cur->expectfn == symbol) {
  			found = true;
  			break;
  		}
  	}
544d5c7d9   Pablo Neira Ayuso   netfilter: ctnetl...
345
346
347
  	return found ? cur : NULL;
  }
  EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol);
b20ab9cc6   Pablo Neira Ayuso   netfilter: nf_ct_...
348
349
350
351
352
353
  __printf(3, 4)
  void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct,
  		      const char *fmt, ...)
  {
  	const struct nf_conn_help *help;
  	const struct nf_conntrack_helper *helper;
f9caed59f   Joe Perches   netfilter: nf_ct_...
354
355
356
357
358
359
360
  	struct va_format vaf;
  	va_list args;
  
  	va_start(args, fmt);
  
  	vaf.fmt = fmt;
  	vaf.va = &args;
b20ab9cc6   Pablo Neira Ayuso   netfilter: nf_ct_...
361
362
363
  
  	/* Called from the helper function, this call never fails */
  	help = nfct_help(ct);
e2361cb90   Aaron Conole   netfilter: Remove...
364
  	/* rcu_read_lock()ed by nf_hook_thresh */
b20ab9cc6   Pablo Neira Ayuso   netfilter: nf_ct_...
365
  	helper = rcu_dereference(help->helper);
30e0c6a6b   Gao feng   netfilter: nf_log...
366
  	nf_log_packet(nf_ct_net(ct), nf_ct_l3num(ct), 0, skb, NULL, NULL, NULL,
f9caed59f   Joe Perches   netfilter: nf_ct_...
367
368
369
  		      "nf_ct_%s: dropping packet: %pV ", helper->name, &vaf);
  
  	va_end(args);
b20ab9cc6   Pablo Neira Ayuso   netfilter: nf_ct_...
370
371
  }
  EXPORT_SYMBOL_GPL(nf_ct_helper_log);
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
372
373
  int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
  {
893e093c7   Pablo Neira Ayuso   netfilter: nf_ct_...
374
  	struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
b8a7fe6c1   Patrick McHardy   [NETFILTER]: nf_c...
375
  	unsigned int h = helper_hash(&me->tuple);
893e093c7   Pablo Neira Ayuso   netfilter: nf_ct_...
376
  	struct nf_conntrack_helper *cur;
66e5a6b18   Liping Zhang   netfilter: nf_ct_...
377
  	int ret = 0, i;
b8a7fe6c1   Patrick McHardy   [NETFILTER]: nf_c...
378

6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
379
380
  	BUG_ON(me->expect_policy == NULL);
  	BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES);
af9d32ad6   Holger Eitzenberger   netfilter: limit ...
381
  	BUG_ON(strlen(me->name) > NF_CT_HELPER_NAME_LEN - 1);
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
382

92f73221f   Gao Feng   netfilter: expect...
383
384
  	if (me->expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
  		return -EINVAL;
58a3c9bb0   Patrick McHardy   [NETFILTER]: nf_c...
385
  	mutex_lock(&nf_ct_helper_mutex);
66e5a6b18   Liping Zhang   netfilter: nf_ct_...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
  	for (i = 0; i < nf_ct_helper_hsize; i++) {
  		hlist_for_each_entry(cur, &nf_ct_helper_hash[i], hnode) {
  			if (!strcmp(cur->name, me->name) &&
  			    (cur->tuple.src.l3num == NFPROTO_UNSPEC ||
  			     cur->tuple.src.l3num == me->tuple.src.l3num) &&
  			    cur->tuple.dst.protonum == me->tuple.dst.protonum) {
  				ret = -EEXIST;
  				goto out;
  			}
  		}
  	}
  
  	/* avoid unpredictable behaviour for auto_assign_helper */
  	if (!(me->flags & NF_CT_HELPER_F_USERSPACE)) {
  		hlist_for_each_entry(cur, &nf_ct_helper_hash[h], hnode) {
  			if (nf_ct_tuple_src_mask_cmp(&cur->tuple, &me->tuple,
  						     &mask)) {
  				ret = -EEXIST;
  				goto out;
  			}
12f7a5053   Pablo Neira Ayuso   netfilter: add us...
406
407
  		}
  	}
9338d7b44   Liping Zhang   netfilter: nfnl_c...
408
  	refcount_set(&me->refcnt, 1);
58a3c9bb0   Patrick McHardy   [NETFILTER]: nf_c...
409
  	hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);
b8a7fe6c1   Patrick McHardy   [NETFILTER]: nf_c...
410
  	nf_ct_helper_count++;
12f7a5053   Pablo Neira Ayuso   netfilter: add us...
411
  out:
58a3c9bb0   Patrick McHardy   [NETFILTER]: nf_c...
412
  	mutex_unlock(&nf_ct_helper_mutex);
12f7a5053   Pablo Neira Ayuso   netfilter: add us...
413
  	return ret;
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
414
  }
13b183391   Patrick McHardy   [NETFILTER]: nf_c...
415
  EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
416

ac7b84839   Florian Westphal   netfilter: expect...
417
  static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
436a850dd   Florian Westphal   netfilter: helper...
418
  {
ac7b84839   Florian Westphal   netfilter: expect...
419
420
421
422
423
424
  	struct nf_conn_help *help = nfct_help(exp->master);
  	const struct nf_conntrack_helper *me = data;
  	const struct nf_conntrack_helper *this;
  
  	if (exp->helper == me)
  		return true;
436a850dd   Florian Westphal   netfilter: helper...
425

ac7b84839   Florian Westphal   netfilter: expect...
426
427
428
429
430
431
432
  	this = rcu_dereference_protected(help->helper,
  					 lockdep_is_held(&nf_conntrack_expect_lock));
  	return this == me;
  }
  
  void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
  {
436a850dd   Florian Westphal   netfilter: helper...
433
434
435
436
437
438
439
440
441
  	mutex_lock(&nf_ct_helper_mutex);
  	hlist_del_rcu(&me->hnode);
  	nf_ct_helper_count--;
  	mutex_unlock(&nf_ct_helper_mutex);
  
  	/* Make sure every nothing is still using the helper unless its a
  	 * connection in the hash.
  	 */
  	synchronize_rcu();
7e5d03bb9   Martin Josefsson   [NETFILTER]: nf_c...
442

ac7b84839   Florian Westphal   netfilter: expect...
443
  	nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
ff1acc496   Liping Zhang   netfilter: nf_ct_...
444
  	nf_ct_iterate_destroy(unhelp, me);
ad9852af9   Gao Feng   netfilter: nf_ct_...
445
446
447
448
449
  
  	/* Maybe someone has gotten the helper already when unhelp above.
  	 * So need to wait it.
  	 */
  	synchronize_rcu();
680479376   Alexey Dobriyan   netfilter: netns ...
450
  }
13b183391   Patrick McHardy   [NETFILTER]: nf_c...
451
  EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
ceceae1b1   Yasuyuki Kozakai   [NETFILTER]: nf_c...
452

82de0be68   Gao Feng   netfilter: Add he...
453
454
455
456
  void nf_ct_helper_init(struct nf_conntrack_helper *helper,
  		       u16 l3num, u16 protonum, const char *name,
  		       u16 default_port, u16 spec_port, u32 id,
  		       const struct nf_conntrack_expect_policy *exp_pol,
9f0f3ebed   Florian Westphal   netfilter: helper...
457
  		       u32 expect_class_max,
82de0be68   Gao Feng   netfilter: Add he...
458
459
460
461
462
463
464
465
466
467
468
469
  		       int (*help)(struct sk_buff *skb, unsigned int protoff,
  				   struct nf_conn *ct,
  				   enum ip_conntrack_info ctinfo),
  		       int (*from_nlattr)(struct nlattr *attr,
  					  struct nf_conn *ct),
  		       struct module *module)
  {
  	helper->tuple.src.l3num = l3num;
  	helper->tuple.dst.protonum = protonum;
  	helper->tuple.src.u.all = htons(spec_port);
  	helper->expect_policy = exp_pol;
  	helper->expect_class_max = expect_class_max;
82de0be68   Gao Feng   netfilter: Add he...
470
471
472
  	helper->help = help;
  	helper->from_nlattr = from_nlattr;
  	helper->me = module;
08010a216   Flavio Leitner   netfilter: add AP...
473
474
  	snprintf(helper->nat_mod_name, sizeof(helper->nat_mod_name),
  		 NF_NAT_HELPER_PREFIX "%s", name);
82de0be68   Gao Feng   netfilter: Add he...
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
  
  	if (spec_port == default_port)
  		snprintf(helper->name, sizeof(helper->name), "%s", name);
  	else
  		snprintf(helper->name, sizeof(helper->name), "%s-%u", name, id);
  }
  EXPORT_SYMBOL_GPL(nf_ct_helper_init);
  
  int nf_conntrack_helpers_register(struct nf_conntrack_helper *helper,
  				  unsigned int n)
  {
  	unsigned int i;
  	int err = 0;
  
  	for (i = 0; i < n; i++) {
  		err = nf_conntrack_helper_register(&helper[i]);
  		if (err < 0)
  			goto err;
  	}
  
  	return err;
  err:
  	if (i > 0)
  		nf_conntrack_helpers_unregister(helper, i);
  	return err;
  }
  EXPORT_SYMBOL_GPL(nf_conntrack_helpers_register);
  
  void nf_conntrack_helpers_unregister(struct nf_conntrack_helper *helper,
  				unsigned int n)
  {
  	while (n-- > 0)
  		nf_conntrack_helper_unregister(&helper[n]);
  }
  EXPORT_SYMBOL_GPL(nf_conntrack_helpers_unregister);
08010a216   Flavio Leitner   netfilter: add AP...
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
  void nf_nat_helper_register(struct nf_conntrack_nat_helper *nat)
  {
  	mutex_lock(&nf_ct_nat_helpers_mutex);
  	list_add_rcu(&nat->list, &nf_ct_nat_helpers);
  	mutex_unlock(&nf_ct_nat_helpers_mutex);
  }
  EXPORT_SYMBOL_GPL(nf_nat_helper_register);
  
  void nf_nat_helper_unregister(struct nf_conntrack_nat_helper *nat)
  {
  	mutex_lock(&nf_ct_nat_helpers_mutex);
  	list_del_rcu(&nat->list);
  	mutex_unlock(&nf_ct_nat_helpers_mutex);
  }
  EXPORT_SYMBOL_GPL(nf_nat_helper_unregister);
23f671a1b   Florian Westphal   netfilter: conntr...
525
  static const struct nf_ct_ext_type helper_extend = {
ceceae1b1   Yasuyuki Kozakai   [NETFILTER]: nf_c...
526
527
528
529
  	.len	= sizeof(struct nf_conn_help),
  	.align	= __alignof__(struct nf_conn_help),
  	.id	= NF_CT_EXT_HELPER,
  };
fc3893fd5   Florian Westphal   netfilter: conntr...
530
  void nf_conntrack_helper_pernet_init(struct net *net)
ceceae1b1   Yasuyuki Kozakai   [NETFILTER]: nf_c...
531
  {
a90068926   Eric Leblond   netfilter: nf_ct_...
532
533
  	net->ct.auto_assign_helper_warned = false;
  	net->ct.sysctl_auto_assign_helper = nf_ct_auto_assign_helper;
5e615b220   Gao feng   netfilter: nf_ct_...
534
  }
a90068926   Eric Leblond   netfilter: nf_ct_...
535

5e615b220   Gao feng   netfilter: nf_ct_...
536
537
538
539
540
541
542
543
544
545
546
547
548
549
  int nf_conntrack_helper_init(void)
  {
  	int ret;
  	nf_ct_helper_hsize = 1; /* gets rounded up to use one page */
  	nf_ct_helper_hash =
  		nf_ct_alloc_hashtable(&nf_ct_helper_hsize, 0);
  	if (!nf_ct_helper_hash)
  		return -ENOMEM;
  
  	ret = nf_ct_extend_register(&helper_extend);
  	if (ret < 0) {
  		pr_err("nf_ct_helper: Unable to register helper extension.
  ");
  		goto out_extend;
a90068926   Eric Leblond   netfilter: nf_ct_...
550
  	}
08010a216   Flavio Leitner   netfilter: add AP...
551
  	INIT_LIST_HEAD(&nf_ct_nat_helpers);
b8a7fe6c1   Patrick McHardy   [NETFILTER]: nf_c...
552
  	return 0;
5e615b220   Gao feng   netfilter: nf_ct_...
553
  out_extend:
285189c78   Li RongQing   netfilter: use kv...
554
  	kvfree(nf_ct_helper_hash);
5e615b220   Gao feng   netfilter: nf_ct_...
555
  	return ret;
ceceae1b1   Yasuyuki Kozakai   [NETFILTER]: nf_c...
556
  }
5e615b220   Gao feng   netfilter: nf_ct_...
557
  void nf_conntrack_helper_fini(void)
ceceae1b1   Yasuyuki Kozakai   [NETFILTER]: nf_c...
558
  {
5e615b220   Gao feng   netfilter: nf_ct_...
559
  	nf_ct_extend_unregister(&helper_extend);
285189c78   Li RongQing   netfilter: use kv...
560
  	kvfree(nf_ct_helper_hash);
ceceae1b1   Yasuyuki Kozakai   [NETFILTER]: nf_c...
561
  }