Blame view

net/netfilter/nfnetlink_cttimeout.c 15.3 KB
e97150df8   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
509784623   Pablo Neira Ayuso   netfilter: add ct...
2
3
4
  /*
   * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
   * (C) 2012 by Vyatta Inc. <http://www.vyatta.com>
509784623   Pablo Neira Ayuso   netfilter: add ct...
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
   */
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/rculist.h>
  #include <linux/rculist_nulls.h>
  #include <linux/types.h>
  #include <linux/timer.h>
  #include <linux/security.h>
  #include <linux/skbuff.h>
  #include <linux/errno.h>
  #include <linux/netlink.h>
  #include <linux/spinlock.h>
  #include <linux/interrupt.h>
  #include <linux/slab.h>
  
  #include <linux/netfilter.h>
  #include <net/netlink.h>
  #include <net/sock.h>
  #include <net/netfilter/nf_conntrack.h>
  #include <net/netfilter/nf_conntrack_core.h>
509784623   Pablo Neira Ayuso   netfilter: add ct...
26
27
  #include <net/netfilter/nf_conntrack_l4proto.h>
  #include <net/netfilter/nf_conntrack_tuple.h>
24de58f46   Pablo Neira Ayuso   netfilter: xt_CT:...
28
  #include <net/netfilter/nf_conntrack_timeout.h>
509784623   Pablo Neira Ayuso   netfilter: add ct...
29
30
31
32
33
34
35
  
  #include <linux/netfilter/nfnetlink.h>
  #include <linux/netfilter/nfnetlink_cttimeout.h>
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
  MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tuning");
509784623   Pablo Neira Ayuso   netfilter: add ct...
36
  static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = {
e93b5f9f3   Florian Westphal   netfilter: cttime...
37
38
  	[CTA_TIMEOUT_NAME]	= { .type = NLA_NUL_STRING,
  				    .len  = CTNL_TIMEOUT_NAME_MAX - 1},
509784623   Pablo Neira Ayuso   netfilter: add ct...
39
40
41
42
43
44
  	[CTA_TIMEOUT_L3PROTO]	= { .type = NLA_U16 },
  	[CTA_TIMEOUT_L4PROTO]	= { .type = NLA_U8 },
  	[CTA_TIMEOUT_DATA]	= { .type = NLA_NESTED },
  };
  
  static int
c779e8496   Florian Westphal   netfilter: conntr...
45
  ctnl_timeout_parse_policy(void *timeout,
2a04aabf5   Julia Lawall   netfilter: consti...
46
  			  const struct nf_conntrack_l4proto *l4proto,
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
47
  			  struct net *net, const struct nlattr *attr)
509784623   Pablo Neira Ayuso   netfilter: add ct...
48
  {
8039ab43e   Gustavo A. R. Silva   netfilter: cttime...
49
  	struct nlattr **tb;
509784623   Pablo Neira Ayuso   netfilter: add ct...
50
  	int ret = 0;
8039ab43e   Gustavo A. R. Silva   netfilter: cttime...
51
52
  	tb = kcalloc(l4proto->ctnl_timeout.nlattr_max + 1, sizeof(*tb),
  		     GFP_KERNEL);
509784623   Pablo Neira Ayuso   netfilter: add ct...
53

8039ab43e   Gustavo A. R. Silva   netfilter: cttime...
54
55
  	if (!tb)
  		return -ENOMEM;
8cb081746   Johannes Berg   netlink: make val...
56
57
58
59
60
  	ret = nla_parse_nested_deprecated(tb,
  					  l4proto->ctnl_timeout.nlattr_max,
  					  attr,
  					  l4proto->ctnl_timeout.nla_policy,
  					  NULL);
8039ab43e   Gustavo A. R. Silva   netfilter: cttime...
61
62
  	if (ret < 0)
  		goto err;
c779e8496   Florian Westphal   netfilter: conntr...
63
  	ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, timeout);
8039ab43e   Gustavo A. R. Silva   netfilter: cttime...
64
65
66
  
  err:
  	kfree(tb);
509784623   Pablo Neira Ayuso   netfilter: add ct...
67
68
  	return ret;
  }
7b8002a15   Pablo Neira Ayuso   netfilter: nfnetl...
69
70
71
  static int cttimeout_new_timeout(struct net *net, struct sock *ctnl,
  				 struct sk_buff *skb,
  				 const struct nlmsghdr *nlh,
04ba724b6   Pablo Neira Ayuso   netfilter: nfnetl...
72
73
  				 const struct nlattr * const cda[],
  				 struct netlink_ext_ack *extack)
509784623   Pablo Neira Ayuso   netfilter: add ct...
74
75
76
  {
  	__u16 l3num;
  	__u8 l4num;
b3480fe05   Florian Westphal   netfilter: conntr...
77
  	const struct nf_conntrack_l4proto *l4proto;
509784623   Pablo Neira Ayuso   netfilter: add ct...
78
79
80
81
82
83
84
85
86
87
88
89
90
  	struct ctnl_timeout *timeout, *matching = NULL;
  	char *name;
  	int ret;
  
  	if (!cda[CTA_TIMEOUT_NAME] ||
  	    !cda[CTA_TIMEOUT_L3PROTO] ||
  	    !cda[CTA_TIMEOUT_L4PROTO] ||
  	    !cda[CTA_TIMEOUT_DATA])
  		return -EINVAL;
  
  	name = nla_data(cda[CTA_TIMEOUT_NAME]);
  	l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
  	l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
19576c947   Pablo Neira   netfilter: cttime...
91
  	list_for_each_entry(timeout, &net->nfct_timeout_list, head) {
509784623   Pablo Neira Ayuso   netfilter: add ct...
92
93
94
95
96
97
98
99
100
  		if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
  			continue;
  
  		if (nlh->nlmsg_flags & NLM_F_EXCL)
  			return -EEXIST;
  
  		matching = timeout;
  		break;
  	}
509784623   Pablo Neira Ayuso   netfilter: add ct...
101
102
103
104
105
  	if (matching) {
  		if (nlh->nlmsg_flags & NLM_F_REPLACE) {
  			/* You cannot replace one timeout policy by another of
  			 * different kind, sorry.
  			 */
6c1fd7dc4   Pablo Neira Ayuso   netfilter: cttime...
106
107
  			if (matching->timeout.l3num != l3num ||
  			    matching->timeout.l4proto->l4proto != l4num)
23aaba5ad   Liping Zhang   netfilter: cttime...
108
  				return -EINVAL;
6c1fd7dc4   Pablo Neira Ayuso   netfilter: cttime...
109
110
111
  			return ctnl_timeout_parse_policy(&matching->timeout.data,
  							 matching->timeout.l4proto,
  							 net, cda[CTA_TIMEOUT_DATA]);
509784623   Pablo Neira Ayuso   netfilter: add ct...
112
  		}
23aaba5ad   Liping Zhang   netfilter: cttime...
113
114
115
  
  		return -EBUSY;
  	}
4a60dc748   Florian Westphal   netfilter: conntr...
116
  	l4proto = nf_ct_l4proto_find(l4num);
23aaba5ad   Liping Zhang   netfilter: cttime...
117
118
119
120
  
  	/* This protocol is not supportted, skip. */
  	if (l4proto->l4proto != l4num) {
  		ret = -EOPNOTSUPP;
c1ebd7dff   Pablo Neira Ayuso   netfilter: cttime...
121
  		goto err_proto_put;
509784623   Pablo Neira Ayuso   netfilter: add ct...
122
123
124
125
  	}
  
  	timeout = kzalloc(sizeof(struct ctnl_timeout) +
  			  l4proto->ctnl_timeout.obj_size, GFP_KERNEL);
c1ebd7dff   Pablo Neira Ayuso   netfilter: cttime...
126
127
128
129
  	if (timeout == NULL) {
  		ret = -ENOMEM;
  		goto err_proto_put;
  	}
509784623   Pablo Neira Ayuso   netfilter: add ct...
130

6c1fd7dc4   Pablo Neira Ayuso   netfilter: cttime...
131
  	ret = ctnl_timeout_parse_policy(&timeout->timeout.data, l4proto, net,
509784623   Pablo Neira Ayuso   netfilter: add ct...
132
133
134
135
136
  					cda[CTA_TIMEOUT_DATA]);
  	if (ret < 0)
  		goto err;
  
  	strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME]));
6c1fd7dc4   Pablo Neira Ayuso   netfilter: cttime...
137
138
  	timeout->timeout.l3num = l3num;
  	timeout->timeout.l4proto = l4proto;
b54ab92b8   Reshetova, Elena   netfilter: refcou...
139
  	refcount_set(&timeout->refcnt, 1);
19576c947   Pablo Neira   netfilter: cttime...
140
  	list_add_tail_rcu(&timeout->head, &net->nfct_timeout_list);
509784623   Pablo Neira Ayuso   netfilter: add ct...
141
142
143
144
  
  	return 0;
  err:
  	kfree(timeout);
c1ebd7dff   Pablo Neira Ayuso   netfilter: cttime...
145
  err_proto_put:
509784623   Pablo Neira Ayuso   netfilter: add ct...
146
147
148
149
  	return ret;
  }
  
  static int
15e473046   Eric W. Biederman   netlink: Rename p...
150
  ctnl_timeout_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
509784623   Pablo Neira Ayuso   netfilter: add ct...
151
152
153
154
  		       int event, struct ctnl_timeout *timeout)
  {
  	struct nlmsghdr *nlh;
  	struct nfgenmsg *nfmsg;
15e473046   Eric W. Biederman   netlink: Rename p...
155
  	unsigned int flags = portid ? NLM_F_MULTI : 0;
6c1fd7dc4   Pablo Neira Ayuso   netfilter: cttime...
156
  	const struct nf_conntrack_l4proto *l4proto = timeout->timeout.l4proto;
4430b897a   Pablo Neira Ayuso   netfilter: cttime...
157
158
  	struct nlattr *nest_parms;
  	int ret;
509784623   Pablo Neira Ayuso   netfilter: add ct...
159

dedb67c4b   Pablo Neira Ayuso   netfilter: Add nf...
160
  	event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event);
15e473046   Eric W. Biederman   netlink: Rename p...
161
  	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
509784623   Pablo Neira Ayuso   netfilter: add ct...
162
163
164
165
166
167
168
  	if (nlh == NULL)
  		goto nlmsg_failure;
  
  	nfmsg = nlmsg_data(nlh);
  	nfmsg->nfgen_family = AF_UNSPEC;
  	nfmsg->version = NFNETLINK_V0;
  	nfmsg->res_id = 0;
48f03bdad   David S. Miller   nfnetlink_cttimeo...
169
  	if (nla_put_string(skb, CTA_TIMEOUT_NAME, timeout->name) ||
6c1fd7dc4   Pablo Neira Ayuso   netfilter: cttime...
170
171
172
  	    nla_put_be16(skb, CTA_TIMEOUT_L3PROTO,
  			 htons(timeout->timeout.l3num)) ||
  	    nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, l4proto->l4proto) ||
48f03bdad   David S. Miller   nfnetlink_cttimeo...
173
  	    nla_put_be32(skb, CTA_TIMEOUT_USE,
b54ab92b8   Reshetova, Elena   netfilter: refcou...
174
  			 htonl(refcount_read(&timeout->refcnt))))
48f03bdad   David S. Miller   nfnetlink_cttimeo...
175
  		goto nla_put_failure;
509784623   Pablo Neira Ayuso   netfilter: add ct...
176

ae0be8de9   Michal Kubecek   netlink: make nla...
177
  	nest_parms = nla_nest_start(skb, CTA_TIMEOUT_DATA);
4430b897a   Pablo Neira Ayuso   netfilter: cttime...
178
179
  	if (!nest_parms)
  		goto nla_put_failure;
509784623   Pablo Neira Ayuso   netfilter: add ct...
180

4430b897a   Pablo Neira Ayuso   netfilter: cttime...
181
182
183
  	ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, &timeout->timeout.data);
  	if (ret < 0)
  		goto nla_put_failure;
509784623   Pablo Neira Ayuso   netfilter: add ct...
184

4430b897a   Pablo Neira Ayuso   netfilter: cttime...
185
  	nla_nest_end(skb, nest_parms);
c1ebd7dff   Pablo Neira Ayuso   netfilter: cttime...
186

509784623   Pablo Neira Ayuso   netfilter: add ct...
187
188
189
190
191
192
193
194
195
196
197
198
  	nlmsg_end(skb, nlh);
  	return skb->len;
  
  nlmsg_failure:
  nla_put_failure:
  	nlmsg_cancel(skb, nlh);
  	return -1;
  }
  
  static int
  ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb)
  {
19576c947   Pablo Neira   netfilter: cttime...
199
  	struct net *net = sock_net(skb->sk);
509784623   Pablo Neira Ayuso   netfilter: add ct...
200
201
202
203
204
205
206
207
208
209
  	struct ctnl_timeout *cur, *last;
  
  	if (cb->args[2])
  		return 0;
  
  	last = (struct ctnl_timeout *)cb->args[1];
  	if (cb->args[1])
  		cb->args[1] = 0;
  
  	rcu_read_lock();
19576c947   Pablo Neira   netfilter: cttime...
210
  	list_for_each_entry_rcu(cur, &net->nfct_timeout_list, head) {
37bc4f8df   Pablo Neira Ayuso   netfilter: nfnetl...
211
212
213
  		if (last) {
  			if (cur != last)
  				continue;
509784623   Pablo Neira Ayuso   netfilter: add ct...
214

37bc4f8df   Pablo Neira Ayuso   netfilter: nfnetl...
215
216
  			last = NULL;
  		}
15e473046   Eric W. Biederman   netlink: Rename p...
217
  		if (ctnl_timeout_fill_info(skb, NETLINK_CB(cb->skb).portid,
509784623   Pablo Neira Ayuso   netfilter: add ct...
218
219
220
221
222
223
224
225
226
227
228
229
  					   cb->nlh->nlmsg_seq,
  					   NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
  					   IPCTNL_MSG_TIMEOUT_NEW, cur) < 0) {
  			cb->args[1] = (unsigned long)cur;
  			break;
  		}
  	}
  	if (!cb->args[1])
  		cb->args[2] = 1;
  	rcu_read_unlock();
  	return skb->len;
  }
7b8002a15   Pablo Neira Ayuso   netfilter: nfnetl...
230
231
232
  static int cttimeout_get_timeout(struct net *net, struct sock *ctnl,
  				 struct sk_buff *skb,
  				 const struct nlmsghdr *nlh,
04ba724b6   Pablo Neira Ayuso   netfilter: nfnetl...
233
234
  				 const struct nlattr * const cda[],
  				 struct netlink_ext_ack *extack)
509784623   Pablo Neira Ayuso   netfilter: add ct...
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
  {
  	int ret = -ENOENT;
  	char *name;
  	struct ctnl_timeout *cur;
  
  	if (nlh->nlmsg_flags & NLM_F_DUMP) {
  		struct netlink_dump_control c = {
  			.dump = ctnl_timeout_dump,
  		};
  		return netlink_dump_start(ctnl, skb, nlh, &c);
  	}
  
  	if (!cda[CTA_TIMEOUT_NAME])
  		return -EINVAL;
  	name = nla_data(cda[CTA_TIMEOUT_NAME]);
19576c947   Pablo Neira   netfilter: cttime...
250
  	list_for_each_entry(cur, &net->nfct_timeout_list, head) {
509784623   Pablo Neira Ayuso   netfilter: add ct...
251
252
253
254
255
256
257
258
259
260
  		struct sk_buff *skb2;
  
  		if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
  			continue;
  
  		skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  		if (skb2 == NULL) {
  			ret = -ENOMEM;
  			break;
  		}
15e473046   Eric W. Biederman   netlink: Rename p...
261
  		ret = ctnl_timeout_fill_info(skb2, NETLINK_CB(skb).portid,
509784623   Pablo Neira Ayuso   netfilter: add ct...
262
263
264
265
266
267
268
  					     nlh->nlmsg_seq,
  					     NFNL_MSG_TYPE(nlh->nlmsg_type),
  					     IPCTNL_MSG_TIMEOUT_NEW, cur);
  		if (ret <= 0) {
  			kfree_skb(skb2);
  			break;
  		}
15e473046   Eric W. Biederman   netlink: Rename p...
269
  		ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid,
509784623   Pablo Neira Ayuso   netfilter: add ct...
270
271
272
273
274
275
276
277
278
279
280
  					MSG_DONTWAIT);
  		if (ret > 0)
  			ret = 0;
  
  		/* this avoids a loop in nfnetlink. */
  		return ret == -EAGAIN ? -ENOBUFS : ret;
  	}
  	return ret;
  }
  
  /* try to delete object, fail if it is still in use. */
19576c947   Pablo Neira   netfilter: cttime...
281
  static int ctnl_timeout_try_del(struct net *net, struct ctnl_timeout *timeout)
509784623   Pablo Neira Ayuso   netfilter: add ct...
282
283
  {
  	int ret = 0;
b75911b66   Liping Zhang   netfilter: cttime...
284
285
286
  	/* We want to avoid races with ctnl_timeout_put. So only when the
  	 * current refcnt is 1, we decrease it to 0.
  	 */
b54ab92b8   Reshetova, Elena   netfilter: refcou...
287
  	if (refcount_dec_if_one(&timeout->refcnt)) {
509784623   Pablo Neira Ayuso   netfilter: add ct...
288
289
  		/* We are protected by nfnl mutex. */
  		list_del_rcu(&timeout->head);
6c1fd7dc4   Pablo Neira Ayuso   netfilter: cttime...
290
  		nf_ct_untimeout(net, &timeout->timeout);
509784623   Pablo Neira Ayuso   netfilter: add ct...
291
292
  		kfree_rcu(timeout, rcu_head);
  	} else {
509784623   Pablo Neira Ayuso   netfilter: add ct...
293
294
295
296
  		ret = -EBUSY;
  	}
  	return ret;
  }
7b8002a15   Pablo Neira Ayuso   netfilter: nfnetl...
297
298
299
  static int cttimeout_del_timeout(struct net *net, struct sock *ctnl,
  				 struct sk_buff *skb,
  				 const struct nlmsghdr *nlh,
04ba724b6   Pablo Neira Ayuso   netfilter: nfnetl...
300
301
  				 const struct nlattr * const cda[],
  				 struct netlink_ext_ack *extack)
509784623   Pablo Neira Ayuso   netfilter: add ct...
302
  {
93fac10b9   Liping Zhang   netfilter: nfnetl...
303
  	struct ctnl_timeout *cur, *tmp;
509784623   Pablo Neira Ayuso   netfilter: add ct...
304
  	int ret = -ENOENT;
7b8002a15   Pablo Neira Ayuso   netfilter: nfnetl...
305
  	char *name;
509784623   Pablo Neira Ayuso   netfilter: add ct...
306
307
  
  	if (!cda[CTA_TIMEOUT_NAME]) {
93fac10b9   Liping Zhang   netfilter: nfnetl...
308
309
  		list_for_each_entry_safe(cur, tmp, &net->nfct_timeout_list,
  					 head)
19576c947   Pablo Neira   netfilter: cttime...
310
  			ctnl_timeout_try_del(net, cur);
509784623   Pablo Neira Ayuso   netfilter: add ct...
311
312
313
314
  
  		return 0;
  	}
  	name = nla_data(cda[CTA_TIMEOUT_NAME]);
19576c947   Pablo Neira   netfilter: cttime...
315
  	list_for_each_entry(cur, &net->nfct_timeout_list, head) {
509784623   Pablo Neira Ayuso   netfilter: add ct...
316
317
  		if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
  			continue;
19576c947   Pablo Neira   netfilter: cttime...
318
  		ret = ctnl_timeout_try_del(net, cur);
509784623   Pablo Neira Ayuso   netfilter: add ct...
319
320
321
322
323
324
325
  		if (ret < 0)
  			return ret;
  
  		break;
  	}
  	return ret;
  }
7b8002a15   Pablo Neira Ayuso   netfilter: nfnetl...
326
327
328
  static int cttimeout_default_set(struct net *net, struct sock *ctnl,
  				 struct sk_buff *skb,
  				 const struct nlmsghdr *nlh,
04ba724b6   Pablo Neira Ayuso   netfilter: nfnetl...
329
330
  				 const struct nlattr * const cda[],
  				 struct netlink_ext_ack *extack)
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
331
  {
b3480fe05   Florian Westphal   netfilter: conntr...
332
  	const struct nf_conntrack_l4proto *l4proto;
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
333
  	__u8 l4num;
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
334
335
336
337
338
339
  	int ret;
  
  	if (!cda[CTA_TIMEOUT_L3PROTO] ||
  	    !cda[CTA_TIMEOUT_L4PROTO] ||
  	    !cda[CTA_TIMEOUT_DATA])
  		return -EINVAL;
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
340
  	l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
4a60dc748   Florian Westphal   netfilter: conntr...
341
  	l4proto = nf_ct_l4proto_find(l4num);
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
342
343
344
345
346
347
  
  	/* This protocol is not supported, skip. */
  	if (l4proto->l4proto != l4num) {
  		ret = -EOPNOTSUPP;
  		goto err;
  	}
c779e8496   Florian Westphal   netfilter: conntr...
348
  	ret = ctnl_timeout_parse_policy(NULL, l4proto, net,
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
349
350
351
  					cda[CTA_TIMEOUT_DATA]);
  	if (ret < 0)
  		goto err;
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
352
353
  	return 0;
  err:
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
354
355
356
357
358
  	return ret;
  }
  
  static int
  cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid,
dd2934a95   Florian Westphal   netfilter: conntr...
359
  			    u32 seq, u32 type, int event, u16 l3num,
8866df926   Pablo Neira Ayuso   netfilter: nfnetl...
360
361
  			    const struct nf_conntrack_l4proto *l4proto,
  			    const unsigned int *timeouts)
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
362
363
364
365
  {
  	struct nlmsghdr *nlh;
  	struct nfgenmsg *nfmsg;
  	unsigned int flags = portid ? NLM_F_MULTI : 0;
4430b897a   Pablo Neira Ayuso   netfilter: cttime...
366
367
  	struct nlattr *nest_parms;
  	int ret;
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
368

dedb67c4b   Pablo Neira Ayuso   netfilter: Add nf...
369
  	event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event);
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
370
371
372
373
374
375
376
377
  	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
  	if (nlh == NULL)
  		goto nlmsg_failure;
  
  	nfmsg = nlmsg_data(nlh);
  	nfmsg->nfgen_family = AF_UNSPEC;
  	nfmsg->version = NFNETLINK_V0;
  	nfmsg->res_id = 0;
dd2934a95   Florian Westphal   netfilter: conntr...
378
  	if (nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(l3num)) ||
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
379
380
  	    nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, l4proto->l4proto))
  		goto nla_put_failure;
ae0be8de9   Michal Kubecek   netlink: make nla...
381
  	nest_parms = nla_nest_start(skb, CTA_TIMEOUT_DATA);
4430b897a   Pablo Neira Ayuso   netfilter: cttime...
382
383
  	if (!nest_parms)
  		goto nla_put_failure;
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
384

8866df926   Pablo Neira Ayuso   netfilter: nfnetl...
385
  	ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, timeouts);
4430b897a   Pablo Neira Ayuso   netfilter: cttime...
386
387
  	if (ret < 0)
  		goto nla_put_failure;
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
388

4430b897a   Pablo Neira Ayuso   netfilter: cttime...
389
  	nla_nest_end(skb, nest_parms);
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
390
391
392
393
394
395
396
397
398
  
  	nlmsg_end(skb, nlh);
  	return skb->len;
  
  nlmsg_failure:
  nla_put_failure:
  	nlmsg_cancel(skb, nlh);
  	return -1;
  }
7b8002a15   Pablo Neira Ayuso   netfilter: nfnetl...
399
400
  static int cttimeout_default_get(struct net *net, struct sock *ctnl,
  				 struct sk_buff *skb,
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
401
  				 const struct nlmsghdr *nlh,
04ba724b6   Pablo Neira Ayuso   netfilter: nfnetl...
402
403
  				 const struct nlattr * const cda[],
  				 struct netlink_ext_ack *extack)
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
404
  {
b3480fe05   Florian Westphal   netfilter: conntr...
405
  	const struct nf_conntrack_l4proto *l4proto;
8866df926   Pablo Neira Ayuso   netfilter: nfnetl...
406
  	unsigned int *timeouts = NULL;
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
407
408
  	struct sk_buff *skb2;
  	int ret, err;
b3480fe05   Florian Westphal   netfilter: conntr...
409
410
  	__u16 l3num;
  	__u8 l4num;
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
411
412
413
414
415
416
  
  	if (!cda[CTA_TIMEOUT_L3PROTO] || !cda[CTA_TIMEOUT_L4PROTO])
  		return -EINVAL;
  
  	l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
  	l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
4a60dc748   Florian Westphal   netfilter: conntr...
417
  	l4proto = nf_ct_l4proto_find(l4num);
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
418

8866df926   Pablo Neira Ayuso   netfilter: nfnetl...
419
420
  	err = -EOPNOTSUPP;
  	if (l4proto->l4proto != l4num)
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
421
  		goto err;
8866df926   Pablo Neira Ayuso   netfilter: nfnetl...
422
423
424
425
426
427
428
429
  
  	switch (l4proto->l4proto) {
  	case IPPROTO_ICMP:
  		timeouts = &nf_icmp_pernet(net)->timeout;
  		break;
  	case IPPROTO_TCP:
  		timeouts = nf_tcp_pernet(net)->timeouts;
  		break;
89259088c   Florian Westphal   netfilter: nfnetl...
430
431
  	case IPPROTO_UDP: /* fallthrough */
  	case IPPROTO_UDPLITE:
8866df926   Pablo Neira Ayuso   netfilter: nfnetl...
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
  		timeouts = nf_udp_pernet(net)->timeouts;
  		break;
  	case IPPROTO_DCCP:
  #ifdef CONFIG_NF_CT_PROTO_DCCP
  		timeouts = nf_dccp_pernet(net)->dccp_timeout;
  #endif
  		break;
  	case IPPROTO_ICMPV6:
  		timeouts = &nf_icmpv6_pernet(net)->timeout;
  		break;
  	case IPPROTO_SCTP:
  #ifdef CONFIG_NF_CT_PROTO_SCTP
  		timeouts = nf_sctp_pernet(net)->timeouts;
  #endif
  		break;
89259088c   Florian Westphal   netfilter: nfnetl...
447
448
  	case IPPROTO_GRE:
  #ifdef CONFIG_NF_CT_PROTO_GRE
22fc4c4c9   Florian Westphal   netfilter: conntr...
449
  		timeouts = nf_gre_pernet(net)->timeouts;
89259088c   Florian Westphal   netfilter: nfnetl...
450
451
  #endif
  		break;
8866df926   Pablo Neira Ayuso   netfilter: nfnetl...
452
453
454
455
  	case 255:
  		timeouts = &nf_generic_pernet(net)->timeout;
  		break;
  	default:
89259088c   Florian Westphal   netfilter: nfnetl...
456
  		WARN_ONCE(1, "Missing timeouts for proto %d", l4proto->l4proto);
8866df926   Pablo Neira Ayuso   netfilter: nfnetl...
457
  		break;
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
458
  	}
8866df926   Pablo Neira Ayuso   netfilter: nfnetl...
459
460
  	if (!timeouts)
  		goto err;
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
461
462
463
464
465
466
467
468
469
470
  	skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  	if (skb2 == NULL) {
  		err = -ENOMEM;
  		goto err;
  	}
  
  	ret = cttimeout_default_fill_info(net, skb2, NETLINK_CB(skb).portid,
  					  nlh->nlmsg_seq,
  					  NFNL_MSG_TYPE(nlh->nlmsg_type),
  					  IPCTNL_MSG_TIMEOUT_DEFAULT_SET,
8866df926   Pablo Neira Ayuso   netfilter: nfnetl...
471
  					  l3num, l4proto, timeouts);
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
472
473
474
475
476
477
478
479
480
481
482
483
  	if (ret <= 0) {
  		kfree_skb(skb2);
  		err = -ENOMEM;
  		goto err;
  	}
  	ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
  	if (ret > 0)
  		ret = 0;
  
  	/* this avoids a loop in nfnetlink. */
  	return ret == -EAGAIN ? -ENOBUFS : ret;
  err:
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
484
485
  	return err;
  }
99e25d071   Pablo Neira Ayuso   netfilter: cttime...
486
487
  static struct nf_ct_timeout *ctnl_timeout_find_get(struct net *net,
  						   const char *name)
24de58f46   Pablo Neira Ayuso   netfilter: xt_CT:...
488
489
  {
  	struct ctnl_timeout *timeout, *matching = NULL;
19576c947   Pablo Neira   netfilter: cttime...
490
  	list_for_each_entry_rcu(timeout, &net->nfct_timeout_list, head) {
24de58f46   Pablo Neira Ayuso   netfilter: xt_CT:...
491
492
493
494
495
  		if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0)
  			continue;
  
  		if (!try_module_get(THIS_MODULE))
  			goto err;
b54ab92b8   Reshetova, Elena   netfilter: refcou...
496
  		if (!refcount_inc_not_zero(&timeout->refcnt)) {
24de58f46   Pablo Neira Ayuso   netfilter: xt_CT:...
497
498
499
500
501
502
503
  			module_put(THIS_MODULE);
  			goto err;
  		}
  		matching = timeout;
  		break;
  	}
  err:
99e25d071   Pablo Neira Ayuso   netfilter: cttime...
504
  	return matching ? &matching->timeout : NULL;
24de58f46   Pablo Neira Ayuso   netfilter: xt_CT:...
505
  }
6c1fd7dc4   Pablo Neira Ayuso   netfilter: cttime...
506
  static void ctnl_timeout_put(struct nf_ct_timeout *t)
24de58f46   Pablo Neira Ayuso   netfilter: xt_CT:...
507
  {
6c1fd7dc4   Pablo Neira Ayuso   netfilter: cttime...
508
509
  	struct ctnl_timeout *timeout =
  		container_of(t, struct ctnl_timeout, timeout);
b54ab92b8   Reshetova, Elena   netfilter: refcou...
510
  	if (refcount_dec_and_test(&timeout->refcnt))
b75911b66   Liping Zhang   netfilter: cttime...
511
  		kfree_rcu(timeout, rcu_head);
24de58f46   Pablo Neira Ayuso   netfilter: xt_CT:...
512
513
  	module_put(THIS_MODULE);
  }
24de58f46   Pablo Neira Ayuso   netfilter: xt_CT:...
514

509784623   Pablo Neira Ayuso   netfilter: add ct...
515
516
517
518
519
520
521
522
523
524
  static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = {
  	[IPCTNL_MSG_TIMEOUT_NEW]	= { .call = cttimeout_new_timeout,
  					    .attr_count = CTA_TIMEOUT_MAX,
  					    .policy = cttimeout_nla_policy },
  	[IPCTNL_MSG_TIMEOUT_GET]	= { .call = cttimeout_get_timeout,
  					    .attr_count = CTA_TIMEOUT_MAX,
  					    .policy = cttimeout_nla_policy },
  	[IPCTNL_MSG_TIMEOUT_DELETE]	= { .call = cttimeout_del_timeout,
  					    .attr_count = CTA_TIMEOUT_MAX,
  					    .policy = cttimeout_nla_policy },
91cb498e6   Pablo Neira Ayuso   netfilter: cttime...
525
526
527
528
529
530
  	[IPCTNL_MSG_TIMEOUT_DEFAULT_SET]= { .call = cttimeout_default_set,
  					    .attr_count = CTA_TIMEOUT_MAX,
  					    .policy = cttimeout_nla_policy },
  	[IPCTNL_MSG_TIMEOUT_DEFAULT_GET]= { .call = cttimeout_default_get,
  					    .attr_count = CTA_TIMEOUT_MAX,
  					    .policy = cttimeout_nla_policy },
509784623   Pablo Neira Ayuso   netfilter: add ct...
531
532
533
534
535
536
537
538
539
540
  };
  
  static const struct nfnetlink_subsystem cttimeout_subsys = {
  	.name				= "conntrack_timeout",
  	.subsys_id			= NFNL_SUBSYS_CTNETLINK_TIMEOUT,
  	.cb_count			= IPCTNL_MSG_TIMEOUT_MAX,
  	.cb				= cttimeout_cb,
  };
  
  MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_TIMEOUT);
19576c947   Pablo Neira   netfilter: cttime...
541
542
543
544
545
546
547
548
549
550
  static int __net_init cttimeout_net_init(struct net *net)
  {
  	INIT_LIST_HEAD(&net->nfct_timeout_list);
  
  	return 0;
  }
  
  static void __net_exit cttimeout_net_exit(struct net *net)
  {
  	struct ctnl_timeout *cur, *tmp;
84657984c   Florian Westphal   netfilter: add an...
551
  	nf_ct_unconfirmed_destroy(net);
4e665afbd   Harsha Sharma   netfilter: cttime...
552
  	nf_ct_untimeout(net, NULL);
19576c947   Pablo Neira   netfilter: cttime...
553
554
555
  
  	list_for_each_entry_safe(cur, tmp, &net->nfct_timeout_list, head) {
  		list_del_rcu(&cur->head);
b75911b66   Liping Zhang   netfilter: cttime...
556

b54ab92b8   Reshetova, Elena   netfilter: refcou...
557
  		if (refcount_dec_and_test(&cur->refcnt))
b75911b66   Liping Zhang   netfilter: cttime...
558
  			kfree_rcu(cur, rcu_head);
19576c947   Pablo Neira   netfilter: cttime...
559
560
561
562
563
564
565
  	}
  }
  
  static struct pernet_operations cttimeout_ops = {
  	.init	= cttimeout_net_init,
  	.exit	= cttimeout_net_exit,
  };
509784623   Pablo Neira Ayuso   netfilter: add ct...
566
567
568
  static int __init cttimeout_init(void)
  {
  	int ret;
19576c947   Pablo Neira   netfilter: cttime...
569
570
571
  	ret = register_pernet_subsys(&cttimeout_ops);
  	if (ret < 0)
  		return ret;
509784623   Pablo Neira Ayuso   netfilter: add ct...
572
573
574
575
576
577
578
  	ret = nfnetlink_subsys_register(&cttimeout_subsys);
  	if (ret < 0) {
  		pr_err("cttimeout_init: cannot register cttimeout with "
  			"nfnetlink.
  ");
  		goto err_out;
  	}
24de58f46   Pablo Neira Ayuso   netfilter: xt_CT:...
579
580
  	RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, ctnl_timeout_find_get);
  	RCU_INIT_POINTER(nf_ct_timeout_put_hook, ctnl_timeout_put);
509784623   Pablo Neira Ayuso   netfilter: add ct...
581
582
583
  	return 0;
  
  err_out:
19576c947   Pablo Neira   netfilter: cttime...
584
  	unregister_pernet_subsys(&cttimeout_ops);
509784623   Pablo Neira Ayuso   netfilter: add ct...
585
586
587
588
589
  	return ret;
  }
  
  static void __exit cttimeout_exit(void)
  {
509784623   Pablo Neira Ayuso   netfilter: add ct...
590
  	nfnetlink_subsys_unregister(&cttimeout_subsys);
ae2d708ed   Pablo Neira Ayuso   netfilter: conntr...
591

19576c947   Pablo Neira   netfilter: cttime...
592
  	unregister_pernet_subsys(&cttimeout_ops);
24de58f46   Pablo Neira Ayuso   netfilter: xt_CT:...
593
594
  	RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL);
  	RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL);
3b7dabf02   Liping Zhang   netfilter: invoke...
595
  	synchronize_rcu();
509784623   Pablo Neira Ayuso   netfilter: add ct...
596
597
598
599
  }
  
  module_init(cttimeout_init);
  module_exit(cttimeout_exit);