blob: 6f4b00a8fc737a60f9f2ff5fa3f41d92ff9553a2 [file] [log] [blame]
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001/* Connection tracking via netlink socket. Allows for user space
2 * protocol helpers and general trouble making from userspace.
3 *
4 * (C) 2001 by Jay Schulist <jschlst@samba.org>
Harald Weltedc808fe2006-03-20 17:56:32 -08005 * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org>
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08006 * (C) 2003 by Patrick Mchardy <kaber@trash.net>
Pablo Neira Ayuso70e99422011-11-22 00:16:51 +01007 * (C) 2005-2011 by Pablo Neira Ayuso <pablo@netfilter.org>
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08008 *
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08009 * Initial connection tracking via netlink development funded and
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080010 * generally made possible by Network Robots, Inc. (www.networkrobots.com)
11 *
12 * Further development of this code funded by Astaro AG (http://www.astaro.com)
13 *
14 * This software may be used and distributed according to the terms
15 * of the GNU General Public License, incorporated herein by reference.
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080016 */
17
18#include <linux/init.h>
19#include <linux/module.h>
20#include <linux/kernel.h>
Ingo Molnar711bbdd2008-05-17 08:26:25 +020021#include <linux/rculist.h>
Eric Dumazetea781f12009-03-25 21:05:46 +010022#include <linux/rculist_nulls.h>
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080023#include <linux/types.h>
24#include <linux/timer.h>
Eric Paris1cc63242010-10-13 16:24:54 -040025#include <linux/security.h>
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080026#include <linux/skbuff.h>
27#include <linux/errno.h>
28#include <linux/netlink.h>
29#include <linux/spinlock.h>
Yasuyuki Kozakai40a839f2006-06-27 03:00:35 -070030#include <linux/interrupt.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090031#include <linux/slab.h>
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080032
33#include <linux/netfilter.h>
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -070034#include <net/netlink.h>
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +010035#include <net/sock.h>
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080036#include <net/netfilter/nf_conntrack.h>
37#include <net/netfilter/nf_conntrack_core.h>
Martin Josefsson77ab9cf2006-11-29 02:34:58 +010038#include <net/netfilter/nf_conntrack_expect.h>
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080039#include <net/netfilter/nf_conntrack_helper.h>
40#include <net/netfilter/nf_conntrack_l3proto.h>
Martin Josefsson605dcad2006-11-29 02:35:06 +010041#include <net/netfilter/nf_conntrack_l4proto.h>
Jozsef Kadlecsik5b1158e2006-12-02 22:07:13 -080042#include <net/netfilter/nf_conntrack_tuple.h>
Krzysztof Piotr Oledzki58401572008-07-21 10:01:34 -070043#include <net/netfilter/nf_conntrack_acct.h>
Patrick McHardyef00f892010-02-15 18:14:57 +010044#include <net/netfilter/nf_conntrack_zones.h>
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +010045#include <net/netfilter/nf_conntrack_timestamp.h>
Jozsef Kadlecsik5b1158e2006-12-02 22:07:13 -080046#ifdef CONFIG_NF_NAT_NEEDED
47#include <net/netfilter/nf_nat_core.h>
48#include <net/netfilter/nf_nat_protocol.h>
49#endif
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080050
51#include <linux/netfilter/nfnetlink.h>
52#include <linux/netfilter/nfnetlink_conntrack.h>
53
54MODULE_LICENSE("GPL");
55
Harald Weltedc808fe2006-03-20 17:56:32 -080056static char __initdata version[] = "0.93";
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080057
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080058static inline int
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -080059ctnetlink_dump_tuples_proto(struct sk_buff *skb,
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -080060 const struct nf_conntrack_tuple *tuple,
Martin Josefsson605dcad2006-11-29 02:35:06 +010061 struct nf_conntrack_l4proto *l4proto)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080062{
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080063 int ret = 0;
Patrick McHardydf6fb862007-09-28 14:37:03 -070064 struct nlattr *nest_parms;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080065
Patrick McHardydf6fb862007-09-28 14:37:03 -070066 nest_parms = nla_nest_start(skb, CTA_TUPLE_PROTO | NLA_F_NESTED);
67 if (!nest_parms)
68 goto nla_put_failure;
David S. Millercc1eb432012-04-01 18:57:48 -040069 if (nla_put_u8(skb, CTA_PROTO_NUM, tuple->dst.protonum))
70 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080071
Patrick McHardyfdf70832007-09-28 14:37:41 -070072 if (likely(l4proto->tuple_to_nlattr))
73 ret = l4proto->tuple_to_nlattr(skb, tuple);
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -080074
Patrick McHardydf6fb862007-09-28 14:37:03 -070075 nla_nest_end(skb, nest_parms);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080076
77 return ret;
78
Patrick McHardydf6fb862007-09-28 14:37:03 -070079nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080080 return -1;
81}
82
83static inline int
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -080084ctnetlink_dump_tuples_ip(struct sk_buff *skb,
85 const struct nf_conntrack_tuple *tuple,
86 struct nf_conntrack_l3proto *l3proto)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080087{
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080088 int ret = 0;
Patrick McHardydf6fb862007-09-28 14:37:03 -070089 struct nlattr *nest_parms;
90
91 nest_parms = nla_nest_start(skb, CTA_TUPLE_IP | NLA_F_NESTED);
92 if (!nest_parms)
93 goto nla_put_failure;
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -080094
Patrick McHardyfdf70832007-09-28 14:37:41 -070095 if (likely(l3proto->tuple_to_nlattr))
96 ret = l3proto->tuple_to_nlattr(skb, tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080097
Patrick McHardydf6fb862007-09-28 14:37:03 -070098 nla_nest_end(skb, nest_parms);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080099
100 return ret;
101
Patrick McHardydf6fb862007-09-28 14:37:03 -0700102nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800103 return -1;
104}
105
Ilpo Järvinenbb5cf802008-01-05 23:11:31 -0800106static int
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -0800107ctnetlink_dump_tuples(struct sk_buff *skb,
108 const struct nf_conntrack_tuple *tuple)
109{
110 int ret;
111 struct nf_conntrack_l3proto *l3proto;
Martin Josefsson605dcad2006-11-29 02:35:06 +0100112 struct nf_conntrack_l4proto *l4proto;
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -0800113
Hans Schillstrom3b988ec2012-03-05 02:24:29 +0000114 rcu_read_lock();
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +0100115 l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -0800116 ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto);
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -0800117
Hans Schillstrom3b988ec2012-03-05 02:24:29 +0000118 if (ret >= 0) {
119 l4proto = __nf_ct_l4proto_find(tuple->src.l3num,
120 tuple->dst.protonum);
121 ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto);
122 }
123 rcu_read_unlock();
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -0800124 return ret;
125}
126
127static inline int
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800128ctnetlink_dump_status(struct sk_buff *skb, const struct nf_conn *ct)
129{
David S. Millercc1eb432012-04-01 18:57:48 -0400130 if (nla_put_be32(skb, CTA_STATUS, htonl(ct->status)))
131 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800132 return 0;
133
Patrick McHardydf6fb862007-09-28 14:37:03 -0700134nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800135 return -1;
136}
137
138static inline int
139ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct)
140{
Xi Wangc1216382011-12-30 10:40:17 -0500141 long timeout = ((long)ct->timeout.expires - (long)jiffies) / HZ;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800142
Patrick McHardy77236b62007-12-17 22:29:45 -0800143 if (timeout < 0)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800144 timeout = 0;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800145
David S. Millercc1eb432012-04-01 18:57:48 -0400146 if (nla_put_be32(skb, CTA_TIMEOUT, htonl(timeout)))
147 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800148 return 0;
149
Patrick McHardydf6fb862007-09-28 14:37:03 -0700150nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800151 return -1;
152}
153
154static inline int
Patrick McHardy440f0d52009-06-10 14:32:47 +0200155ctnetlink_dump_protoinfo(struct sk_buff *skb, struct nf_conn *ct)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800156{
Patrick McHardy5e8fbe22008-04-14 11:15:52 +0200157 struct nf_conntrack_l4proto *l4proto;
Patrick McHardydf6fb862007-09-28 14:37:03 -0700158 struct nlattr *nest_proto;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800159 int ret;
160
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +0100161 l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
162 if (!l4proto->to_nlattr)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800163 return 0;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800164
Patrick McHardydf6fb862007-09-28 14:37:03 -0700165 nest_proto = nla_nest_start(skb, CTA_PROTOINFO | NLA_F_NESTED);
166 if (!nest_proto)
167 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800168
Patrick McHardyfdf70832007-09-28 14:37:41 -0700169 ret = l4proto->to_nlattr(skb, nest_proto, ct);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800170
Patrick McHardydf6fb862007-09-28 14:37:03 -0700171 nla_nest_end(skb, nest_proto);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800172
173 return ret;
174
Patrick McHardydf6fb862007-09-28 14:37:03 -0700175nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800176 return -1;
177}
178
179static inline int
180ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct)
181{
Patrick McHardydf6fb862007-09-28 14:37:03 -0700182 struct nlattr *nest_helper;
Harald Weltedc808fe2006-03-20 17:56:32 -0800183 const struct nf_conn_help *help = nfct_help(ct);
Patrick McHarrdy3c158f72007-06-05 12:55:27 -0700184 struct nf_conntrack_helper *helper;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800185
Patrick McHarrdy3c158f72007-06-05 12:55:27 -0700186 if (!help)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800187 return 0;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800188
Patrick McHarrdy3c158f72007-06-05 12:55:27 -0700189 helper = rcu_dereference(help->helper);
190 if (!helper)
191 goto out;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800192
Patrick McHardydf6fb862007-09-28 14:37:03 -0700193 nest_helper = nla_nest_start(skb, CTA_HELP | NLA_F_NESTED);
194 if (!nest_helper)
195 goto nla_put_failure;
David S. Millercc1eb432012-04-01 18:57:48 -0400196 if (nla_put_string(skb, CTA_HELP_NAME, helper->name))
197 goto nla_put_failure;
Patrick McHarrdy3c158f72007-06-05 12:55:27 -0700198
Patrick McHardyfdf70832007-09-28 14:37:41 -0700199 if (helper->to_nlattr)
200 helper->to_nlattr(skb, ct);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800201
Patrick McHardydf6fb862007-09-28 14:37:03 -0700202 nla_nest_end(skb, nest_helper);
Patrick McHarrdy3c158f72007-06-05 12:55:27 -0700203out:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800204 return 0;
205
Patrick McHardydf6fb862007-09-28 14:37:03 -0700206nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800207 return -1;
208}
209
Ilpo Järvinenbb5cf802008-01-05 23:11:31 -0800210static int
Pablo Neira Ayuso80e60e62011-12-24 14:11:39 +0100211dump_counters(struct sk_buff *skb, u64 pkts, u64 bytes,
212 enum ip_conntrack_dir dir)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800213{
214 enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
Patrick McHardydf6fb862007-09-28 14:37:03 -0700215 struct nlattr *nest_count;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800216
Patrick McHardydf6fb862007-09-28 14:37:03 -0700217 nest_count = nla_nest_start(skb, type | NLA_F_NESTED);
218 if (!nest_count)
219 goto nla_put_failure;
220
David S. Millercc1eb432012-04-01 18:57:48 -0400221 if (nla_put_be64(skb, CTA_COUNTERS_PACKETS, cpu_to_be64(pkts)) ||
222 nla_put_be64(skb, CTA_COUNTERS_BYTES, cpu_to_be64(bytes)))
223 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800224
Patrick McHardydf6fb862007-09-28 14:37:03 -0700225 nla_nest_end(skb, nest_count);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800226
227 return 0;
228
Patrick McHardydf6fb862007-09-28 14:37:03 -0700229nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800230 return -1;
231}
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800232
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +0100233static int
Pablo Neira Ayuso80e60e62011-12-24 14:11:39 +0100234ctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct,
235 enum ip_conntrack_dir dir, int type)
236{
237 struct nf_conn_counter *acct;
238 u64 pkts, bytes;
239
240 acct = nf_conn_acct_find(ct);
241 if (!acct)
242 return 0;
243
244 if (type == IPCTNL_MSG_CT_GET_CTRZERO) {
245 pkts = atomic64_xchg(&acct[dir].packets, 0);
246 bytes = atomic64_xchg(&acct[dir].bytes, 0);
247 } else {
248 pkts = atomic64_read(&acct[dir].packets);
249 bytes = atomic64_read(&acct[dir].bytes);
250 }
251 return dump_counters(skb, pkts, bytes, dir);
252}
253
254static int
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +0100255ctnetlink_dump_timestamp(struct sk_buff *skb, const struct nf_conn *ct)
256{
257 struct nlattr *nest_count;
258 const struct nf_conn_tstamp *tstamp;
259
260 tstamp = nf_conn_tstamp_find(ct);
261 if (!tstamp)
262 return 0;
263
264 nest_count = nla_nest_start(skb, CTA_TIMESTAMP | NLA_F_NESTED);
265 if (!nest_count)
266 goto nla_put_failure;
267
David S. Millercc1eb432012-04-01 18:57:48 -0400268 if (nla_put_be64(skb, CTA_TIMESTAMP_START, cpu_to_be64(tstamp->start)) ||
269 (tstamp->stop != 0 && nla_put_be64(skb, CTA_TIMESTAMP_STOP,
270 cpu_to_be64(tstamp->stop))))
271 goto nla_put_failure;
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +0100272 nla_nest_end(skb, nest_count);
273
274 return 0;
275
276nla_put_failure:
277 return -1;
278}
279
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800280#ifdef CONFIG_NF_CONNTRACK_MARK
281static inline int
282ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct)
283{
David S. Millercc1eb432012-04-01 18:57:48 -0400284 if (nla_put_be32(skb, CTA_MARK, htonl(ct->mark)))
285 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800286 return 0;
287
Patrick McHardydf6fb862007-09-28 14:37:03 -0700288nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800289 return -1;
290}
291#else
292#define ctnetlink_dump_mark(a, b) (0)
293#endif
294
Pablo Neira Ayuso37fccd82007-12-17 22:28:41 -0800295#ifdef CONFIG_NF_CONNTRACK_SECMARK
296static inline int
Eric Paris1cc63242010-10-13 16:24:54 -0400297ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
Pablo Neira Ayuso37fccd82007-12-17 22:28:41 -0800298{
Eric Paris1cc63242010-10-13 16:24:54 -0400299 struct nlattr *nest_secctx;
300 int len, ret;
301 char *secctx;
Pablo Neira Ayuso37fccd82007-12-17 22:28:41 -0800302
Eric Paris1cc63242010-10-13 16:24:54 -0400303 ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
304 if (ret)
Pablo Neira Ayusocba85b52011-01-06 11:25:00 -0800305 return 0;
Eric Paris1cc63242010-10-13 16:24:54 -0400306
307 ret = -1;
308 nest_secctx = nla_nest_start(skb, CTA_SECCTX | NLA_F_NESTED);
309 if (!nest_secctx)
310 goto nla_put_failure;
311
David S. Millercc1eb432012-04-01 18:57:48 -0400312 if (nla_put_string(skb, CTA_SECCTX_NAME, secctx))
313 goto nla_put_failure;
Eric Paris1cc63242010-10-13 16:24:54 -0400314 nla_nest_end(skb, nest_secctx);
315
316 ret = 0;
Pablo Neira Ayuso37fccd82007-12-17 22:28:41 -0800317nla_put_failure:
Eric Paris1cc63242010-10-13 16:24:54 -0400318 security_release_secctx(secctx, len);
319 return ret;
Pablo Neira Ayuso37fccd82007-12-17 22:28:41 -0800320}
321#else
Eric Paris1cc63242010-10-13 16:24:54 -0400322#define ctnetlink_dump_secctx(a, b) (0)
Pablo Neira Ayuso37fccd82007-12-17 22:28:41 -0800323#endif
324
Pablo Neira Ayuso0f417ce2007-12-17 22:28:19 -0800325#define master_tuple(ct) &(ct->master->tuplehash[IP_CT_DIR_ORIGINAL].tuple)
326
327static inline int
328ctnetlink_dump_master(struct sk_buff *skb, const struct nf_conn *ct)
329{
330 struct nlattr *nest_parms;
331
332 if (!(ct->status & IPS_EXPECTED))
333 return 0;
334
335 nest_parms = nla_nest_start(skb, CTA_TUPLE_MASTER | NLA_F_NESTED);
336 if (!nest_parms)
337 goto nla_put_failure;
338 if (ctnetlink_dump_tuples(skb, master_tuple(ct)) < 0)
339 goto nla_put_failure;
340 nla_nest_end(skb, nest_parms);
341
342 return 0;
343
344nla_put_failure:
345 return -1;
346}
347
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800348#ifdef CONFIG_NF_NAT_NEEDED
Ilpo Järvinenbb5cf802008-01-05 23:11:31 -0800349static int
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800350dump_nat_seq_adj(struct sk_buff *skb, const struct nf_nat_seq *natseq, int type)
351{
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800352 struct nlattr *nest_parms;
353
354 nest_parms = nla_nest_start(skb, type | NLA_F_NESTED);
355 if (!nest_parms)
356 goto nla_put_failure;
357
David S. Millercc1eb432012-04-01 18:57:48 -0400358 if (nla_put_be32(skb, CTA_NAT_SEQ_CORRECTION_POS,
359 htonl(natseq->correction_pos)) ||
360 nla_put_be32(skb, CTA_NAT_SEQ_OFFSET_BEFORE,
361 htonl(natseq->offset_before)) ||
362 nla_put_be32(skb, CTA_NAT_SEQ_OFFSET_AFTER,
363 htonl(natseq->offset_after)))
364 goto nla_put_failure;
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800365
366 nla_nest_end(skb, nest_parms);
367
368 return 0;
369
370nla_put_failure:
371 return -1;
372}
373
374static inline int
375ctnetlink_dump_nat_seq_adj(struct sk_buff *skb, const struct nf_conn *ct)
376{
377 struct nf_nat_seq *natseq;
378 struct nf_conn_nat *nat = nfct_nat(ct);
379
380 if (!(ct->status & IPS_SEQ_ADJUST) || !nat)
381 return 0;
382
383 natseq = &nat->seq[IP_CT_DIR_ORIGINAL];
384 if (dump_nat_seq_adj(skb, natseq, CTA_NAT_SEQ_ADJ_ORIG) == -1)
385 return -1;
386
387 natseq = &nat->seq[IP_CT_DIR_REPLY];
388 if (dump_nat_seq_adj(skb, natseq, CTA_NAT_SEQ_ADJ_REPLY) == -1)
389 return -1;
390
391 return 0;
392}
393#else
394#define ctnetlink_dump_nat_seq_adj(a, b) (0)
395#endif
396
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800397static inline int
398ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct)
399{
David S. Millercc1eb432012-04-01 18:57:48 -0400400 if (nla_put_be32(skb, CTA_ID, htonl((unsigned long)ct)))
401 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800402 return 0;
403
Patrick McHardydf6fb862007-09-28 14:37:03 -0700404nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800405 return -1;
406}
407
408static inline int
409ctnetlink_dump_use(struct sk_buff *skb, const struct nf_conn *ct)
410{
David S. Millercc1eb432012-04-01 18:57:48 -0400411 if (nla_put_be32(skb, CTA_USE, htonl(atomic_read(&ct->ct_general.use))))
412 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800413 return 0;
414
Patrick McHardydf6fb862007-09-28 14:37:03 -0700415nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800416 return -1;
417}
418
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800419static int
Pablo Neira Ayuso80e60e62011-12-24 14:11:39 +0100420ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type,
421 struct nf_conn *ct)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800422{
423 struct nlmsghdr *nlh;
424 struct nfgenmsg *nfmsg;
Patrick McHardydf6fb862007-09-28 14:37:03 -0700425 struct nlattr *nest_parms;
Pablo Neira Ayuso80e60e62011-12-24 14:11:39 +0100426 unsigned int flags = pid ? NLM_F_MULTI : 0, event;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800427
Pablo Neira Ayuso80e60e62011-12-24 14:11:39 +0100428 event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_CT_NEW);
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200429 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags);
430 if (nlh == NULL)
431 goto nlmsg_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800432
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200433 nfmsg = nlmsg_data(nlh);
Patrick McHardy5e8fbe22008-04-14 11:15:52 +0200434 nfmsg->nfgen_family = nf_ct_l3num(ct);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800435 nfmsg->version = NFNETLINK_V0;
436 nfmsg->res_id = 0;
437
Patrick McHardydf6fb862007-09-28 14:37:03 -0700438 nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED);
439 if (!nest_parms)
440 goto nla_put_failure;
Pablo Neira Ayusof2f3e382009-06-02 20:03:35 +0200441 if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700442 goto nla_put_failure;
443 nla_nest_end(skb, nest_parms);
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800444
Patrick McHardydf6fb862007-09-28 14:37:03 -0700445 nest_parms = nla_nest_start(skb, CTA_TUPLE_REPLY | NLA_F_NESTED);
446 if (!nest_parms)
447 goto nla_put_failure;
Pablo Neira Ayusof2f3e382009-06-02 20:03:35 +0200448 if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_REPLY)) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700449 goto nla_put_failure;
450 nla_nest_end(skb, nest_parms);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800451
David S. Millercc1eb432012-04-01 18:57:48 -0400452 if (nf_ct_zone(ct) &&
453 nla_put_be16(skb, CTA_ZONE, htons(nf_ct_zone(ct))))
454 goto nla_put_failure;
Patrick McHardyef00f892010-02-15 18:14:57 +0100455
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800456 if (ctnetlink_dump_status(skb, ct) < 0 ||
457 ctnetlink_dump_timeout(skb, ct) < 0 ||
Pablo Neira Ayuso80e60e62011-12-24 14:11:39 +0100458 ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL, type) < 0 ||
459 ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY, type) < 0 ||
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +0100460 ctnetlink_dump_timestamp(skb, ct) < 0 ||
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800461 ctnetlink_dump_protoinfo(skb, ct) < 0 ||
462 ctnetlink_dump_helpinfo(skb, ct) < 0 ||
463 ctnetlink_dump_mark(skb, ct) < 0 ||
Eric Paris1cc63242010-10-13 16:24:54 -0400464 ctnetlink_dump_secctx(skb, ct) < 0 ||
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800465 ctnetlink_dump_id(skb, ct) < 0 ||
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800466 ctnetlink_dump_use(skb, ct) < 0 ||
Pablo Neira Ayuso0f417ce2007-12-17 22:28:19 -0800467 ctnetlink_dump_master(skb, ct) < 0 ||
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800468 ctnetlink_dump_nat_seq_adj(skb, ct) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700469 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800470
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200471 nlmsg_end(skb, nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800472 return skb->len;
473
474nlmsg_failure:
Patrick McHardydf6fb862007-09-28 14:37:03 -0700475nla_put_failure:
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200476 nlmsg_cancel(skb, nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800477 return -1;
478}
479
480#ifdef CONFIG_NF_CONNTRACK_EVENTS
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200481static inline size_t
482ctnetlink_proto_size(const struct nf_conn *ct)
Holger Eitzenberger2732c4e2009-03-25 21:50:59 +0100483{
484 struct nf_conntrack_l3proto *l3proto;
485 struct nf_conntrack_l4proto *l4proto;
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200486 size_t len = 0;
Holger Eitzenberger2732c4e2009-03-25 21:50:59 +0100487
488 rcu_read_lock();
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200489 l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct));
Holger Eitzenberger2732c4e2009-03-25 21:50:59 +0100490 len += l3proto->nla_size;
491
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200492 l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
Holger Eitzenberger2732c4e2009-03-25 21:50:59 +0100493 len += l4proto->nla_size;
494 rcu_read_unlock();
495
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200496 return len;
497}
498
499static inline size_t
Jiri Pirkod26e6a02010-04-01 12:39:19 +0200500ctnetlink_counters_size(const struct nf_conn *ct)
501{
502 if (!nf_ct_ext_exist(ct, NF_CT_EXT_ACCT))
503 return 0;
504 return 2 * nla_total_size(0) /* CTA_COUNTERS_ORIG|REPL */
505 + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_PACKETS */
506 + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_BYTES */
507 ;
508}
509
Pablo Neira Ayusocba85b52011-01-06 11:25:00 -0800510static inline int
511ctnetlink_secctx_size(const struct nf_conn *ct)
Eric Paris1cc63242010-10-13 16:24:54 -0400512{
Pablo Neira Ayusocba85b52011-01-06 11:25:00 -0800513#ifdef CONFIG_NF_CONNTRACK_SECMARK
514 int len, ret;
Eric Paris1cc63242010-10-13 16:24:54 -0400515
Pablo Neira Ayusocba85b52011-01-06 11:25:00 -0800516 ret = security_secid_to_secctx(ct->secmark, NULL, &len);
517 if (ret)
518 return 0;
Eric Paris1cc63242010-10-13 16:24:54 -0400519
Pablo Neira Ayusocba85b52011-01-06 11:25:00 -0800520 return nla_total_size(0) /* CTA_SECCTX */
521 + nla_total_size(sizeof(char) * len); /* CTA_SECCTX_NAME */
522#else
523 return 0;
Eric Paris1cc63242010-10-13 16:24:54 -0400524#endif
Pablo Neira Ayusocba85b52011-01-06 11:25:00 -0800525}
Eric Paris1cc63242010-10-13 16:24:54 -0400526
Jiri Pirkod26e6a02010-04-01 12:39:19 +0200527static inline size_t
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +0100528ctnetlink_timestamp_size(const struct nf_conn *ct)
529{
530#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
531 if (!nf_ct_ext_exist(ct, NF_CT_EXT_TSTAMP))
532 return 0;
533 return nla_total_size(0) + 2 * nla_total_size(sizeof(uint64_t));
534#else
535 return 0;
536#endif
537}
538
539static inline size_t
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200540ctnetlink_nlmsg_size(const struct nf_conn *ct)
541{
542 return NLMSG_ALIGN(sizeof(struct nfgenmsg))
543 + 3 * nla_total_size(0) /* CTA_TUPLE_ORIG|REPL|MASTER */
544 + 3 * nla_total_size(0) /* CTA_TUPLE_IP */
545 + 3 * nla_total_size(0) /* CTA_TUPLE_PROTO */
546 + 3 * nla_total_size(sizeof(u_int8_t)) /* CTA_PROTO_NUM */
547 + nla_total_size(sizeof(u_int32_t)) /* CTA_ID */
548 + nla_total_size(sizeof(u_int32_t)) /* CTA_STATUS */
Jiri Pirkod26e6a02010-04-01 12:39:19 +0200549 + ctnetlink_counters_size(ct)
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +0100550 + ctnetlink_timestamp_size(ct)
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200551 + nla_total_size(sizeof(u_int32_t)) /* CTA_TIMEOUT */
552 + nla_total_size(0) /* CTA_PROTOINFO */
553 + nla_total_size(0) /* CTA_HELP */
554 + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */
Pablo Neira Ayusocba85b52011-01-06 11:25:00 -0800555 + ctnetlink_secctx_size(ct)
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200556#ifdef CONFIG_NF_NAT_NEEDED
557 + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */
558 + 6 * nla_total_size(sizeof(u_int32_t)) /* CTA_NAT_SEQ_OFFSET */
559#endif
560#ifdef CONFIG_NF_CONNTRACK_MARK
561 + nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */
562#endif
563 + ctnetlink_proto_size(ct)
564 ;
Holger Eitzenberger2732c4e2009-03-25 21:50:59 +0100565}
566
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200567static int
568ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800569{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +0100570 struct net *net;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800571 struct nlmsghdr *nlh;
572 struct nfgenmsg *nfmsg;
Patrick McHardydf6fb862007-09-28 14:37:03 -0700573 struct nlattr *nest_parms;
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100574 struct nf_conn *ct = item->ct;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800575 struct sk_buff *skb;
576 unsigned int type;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800577 unsigned int flags = 0, group;
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200578 int err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800579
580 /* ignore our fake conntrack entry */
Eric Dumazet5bfddbd2010-06-08 16:09:52 +0200581 if (nf_ct_is_untracked(ct))
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200582 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800583
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200584 if (events & (1 << IPCT_DESTROY)) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800585 type = IPCTNL_MSG_CT_DELETE;
586 group = NFNLGRP_CONNTRACK_DESTROY;
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200587 } else if (events & ((1 << IPCT_NEW) | (1 << IPCT_RELATED))) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800588 type = IPCTNL_MSG_CT_NEW;
589 flags = NLM_F_CREATE|NLM_F_EXCL;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800590 group = NFNLGRP_CONNTRACK_NEW;
Pablo Neira Ayuso17e6e4e2009-06-02 20:08:46 +0200591 } else if (events) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800592 type = IPCTNL_MSG_CT_NEW;
593 group = NFNLGRP_CONNTRACK_UPDATE;
594 } else
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200595 return 0;
Patrick McHardya2427692006-03-20 18:03:59 -0800596
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +0100597 net = nf_ct_net(ct);
598 if (!item->report && !nfnetlink_has_listeners(net, group))
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200599 return 0;
Patrick McHardya2427692006-03-20 18:03:59 -0800600
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200601 skb = nlmsg_new(ctnetlink_nlmsg_size(ct), GFP_ATOMIC);
602 if (skb == NULL)
Pablo Neira Ayuso150ace02009-04-17 17:47:31 +0200603 goto errout;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800604
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800605 type |= NFNL_SUBSYS_CTNETLINK << 8;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200606 nlh = nlmsg_put(skb, item->pid, 0, type, sizeof(*nfmsg), flags);
607 if (nlh == NULL)
608 goto nlmsg_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800609
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200610 nfmsg = nlmsg_data(nlh);
Patrick McHardy5e8fbe22008-04-14 11:15:52 +0200611 nfmsg->nfgen_family = nf_ct_l3num(ct);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800612 nfmsg->version = NFNETLINK_V0;
613 nfmsg->res_id = 0;
614
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +0100615 rcu_read_lock();
Patrick McHardydf6fb862007-09-28 14:37:03 -0700616 nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED);
617 if (!nest_parms)
618 goto nla_put_failure;
Pablo Neira Ayusof2f3e382009-06-02 20:03:35 +0200619 if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700620 goto nla_put_failure;
621 nla_nest_end(skb, nest_parms);
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800622
Patrick McHardydf6fb862007-09-28 14:37:03 -0700623 nest_parms = nla_nest_start(skb, CTA_TUPLE_REPLY | NLA_F_NESTED);
624 if (!nest_parms)
625 goto nla_put_failure;
Pablo Neira Ayusof2f3e382009-06-02 20:03:35 +0200626 if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_REPLY)) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700627 goto nla_put_failure;
628 nla_nest_end(skb, nest_parms);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800629
David S. Millercc1eb432012-04-01 18:57:48 -0400630 if (nf_ct_zone(ct) &&
631 nla_put_be16(skb, CTA_ZONE, htons(nf_ct_zone(ct))))
632 goto nla_put_failure;
Patrick McHardyef00f892010-02-15 18:14:57 +0100633
Eric Leblond1eedf692008-05-13 23:27:11 -0700634 if (ctnetlink_dump_id(skb, ct) < 0)
635 goto nla_put_failure;
636
Fabian Hugelshofere57dce62008-06-09 15:59:58 -0700637 if (ctnetlink_dump_status(skb, ct) < 0)
638 goto nla_put_failure;
639
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200640 if (events & (1 << IPCT_DESTROY)) {
Pablo Neira Ayuso80e60e62011-12-24 14:11:39 +0100641 if (ctnetlink_dump_counters(skb, ct,
642 IP_CT_DIR_ORIGINAL, type) < 0 ||
643 ctnetlink_dump_counters(skb, ct,
644 IP_CT_DIR_REPLY, type) < 0 ||
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +0100645 ctnetlink_dump_timestamp(skb, ct) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700646 goto nla_put_failure;
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100647 } else {
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100648 if (ctnetlink_dump_timeout(skb, ct) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700649 goto nla_put_failure;
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100650
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200651 if (events & (1 << IPCT_PROTOINFO)
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100652 && ctnetlink_dump_protoinfo(skb, ct) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700653 goto nla_put_failure;
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100654
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200655 if ((events & (1 << IPCT_HELPER) || nfct_help(ct))
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100656 && ctnetlink_dump_helpinfo(skb, ct) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700657 goto nla_put_failure;
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100658
Eric Parisff660c82010-10-19 18:17:32 -0400659#ifdef CONFIG_NF_CONNTRACK_SECMARK
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200660 if ((events & (1 << IPCT_SECMARK) || ct->secmark)
Eric Paris1cc63242010-10-13 16:24:54 -0400661 && ctnetlink_dump_secctx(skb, ct) < 0)
Pablo Neira Ayuso37fccd82007-12-17 22:28:41 -0800662 goto nla_put_failure;
Eric Parisff660c82010-10-19 18:17:32 -0400663#endif
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100664
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200665 if (events & (1 << IPCT_RELATED) &&
Pablo Neira Ayuso0f417ce2007-12-17 22:28:19 -0800666 ctnetlink_dump_master(skb, ct) < 0)
667 goto nla_put_failure;
668
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200669 if (events & (1 << IPCT_NATSEQADJ) &&
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800670 ctnetlink_dump_nat_seq_adj(skb, ct) < 0)
671 goto nla_put_failure;
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100672 }
Pablo Neira Ayusob9a37e02006-08-22 00:31:49 -0700673
Eric Leblonda83099a2008-01-31 04:44:27 -0800674#ifdef CONFIG_NF_CONNTRACK_MARK
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200675 if ((events & (1 << IPCT_MARK) || ct->mark)
Eric Leblonda83099a2008-01-31 04:44:27 -0800676 && ctnetlink_dump_mark(skb, ct) < 0)
677 goto nla_put_failure;
678#endif
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +0100679 rcu_read_unlock();
Eric Leblonda83099a2008-01-31 04:44:27 -0800680
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200681 nlmsg_end(skb, nlh);
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +0100682 err = nfnetlink_send(skb, net, item->pid, group, item->report,
Alexey Dobriyancd8c20b2010-01-13 16:02:14 +0100683 GFP_ATOMIC);
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200684 if (err == -ENOBUFS || err == -EAGAIN)
685 return -ENOBUFS;
686
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200687 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800688
Patrick McHardydf6fb862007-09-28 14:37:03 -0700689nla_put_failure:
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +0100690 rcu_read_unlock();
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200691 nlmsg_cancel(skb, nlh);
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +0100692nlmsg_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800693 kfree_skb(skb);
Pablo Neira Ayuso150ace02009-04-17 17:47:31 +0200694errout:
Pablo Neira Ayuso37b7ef72010-03-16 13:30:21 +0000695 if (nfnetlink_set_err(net, 0, group, -ENOBUFS) > 0)
696 return -ENOBUFS;
697
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200698 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800699}
700#endif /* CONFIG_NF_CONNTRACK_EVENTS */
701
702static int ctnetlink_done(struct netlink_callback *cb)
703{
Patrick McHardy89f2e212006-05-29 18:24:58 -0700704 if (cb->args[1])
705 nf_ct_put((struct nf_conn *)cb->args[1]);
Pablo Neira Ayuso0f298a22012-02-24 14:41:50 +0000706 if (cb->data)
707 kfree(cb->data);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800708 return 0;
709}
710
Pablo Neira Ayuso0f298a22012-02-24 14:41:50 +0000711struct ctnetlink_dump_filter {
712 struct {
713 u_int32_t val;
714 u_int32_t mask;
715 } mark;
716};
717
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800718static int
719ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
720{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +0100721 struct net *net = sock_net(skb->sk);
Patrick McHardy89f2e212006-05-29 18:24:58 -0700722 struct nf_conn *ct, *last;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800723 struct nf_conntrack_tuple_hash *h;
Eric Dumazetea781f12009-03-25 21:05:46 +0100724 struct hlist_nulls_node *n;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200725 struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
Pablo Neira Ayuso87711cb2006-01-05 12:19:23 -0800726 u_int8_t l3proto = nfmsg->nfgen_family;
Hans Schillstrom3b988ec2012-03-05 02:24:29 +0000727 int res;
Pablo Neira Ayuso0f298a22012-02-24 14:41:50 +0000728#ifdef CONFIG_NF_CONNTRACK_MARK
729 const struct ctnetlink_dump_filter *filter = cb->data;
730#endif
Hans Schillstrom3b988ec2012-03-05 02:24:29 +0000731
Stephen Hemminger13ee6ac2011-01-11 23:54:42 +0100732 spin_lock_bh(&nf_conntrack_lock);
Patrick McHardyd205dc42006-08-17 18:12:38 -0700733 last = (struct nf_conn *)cb->args[1];
Patrick McHardy9ab99d52010-02-10 14:17:10 +0100734 for (; cb->args[0] < net->ct.htable_size; cb->args[0]++) {
Patrick McHardy89f2e212006-05-29 18:24:58 -0700735restart:
Stephen Hemminger13ee6ac2011-01-11 23:54:42 +0100736 hlist_nulls_for_each_entry(h, n, &net->ct.hash[cb->args[0]],
Eric Dumazetea781f12009-03-25 21:05:46 +0100737 hnnode) {
Jozsef Kadlecsik5b1158e2006-12-02 22:07:13 -0800738 if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800739 continue;
740 ct = nf_ct_tuplehash_to_ctrack(h);
Pablo Neira Ayuso87711cb2006-01-05 12:19:23 -0800741 /* Dump entries of a given L3 protocol number.
742 * If it is not specified, ie. l3proto == 0,
743 * then dump everything. */
Patrick McHardy5e8fbe22008-04-14 11:15:52 +0200744 if (l3proto && nf_ct_l3num(ct) != l3proto)
Stephen Hemminger13ee6ac2011-01-11 23:54:42 +0100745 continue;
Patrick McHardyd205dc42006-08-17 18:12:38 -0700746 if (cb->args[1]) {
747 if (ct != last)
Stephen Hemminger13ee6ac2011-01-11 23:54:42 +0100748 continue;
Patrick McHardyd205dc42006-08-17 18:12:38 -0700749 cb->args[1] = 0;
Patrick McHardy89f2e212006-05-29 18:24:58 -0700750 }
Pablo Neira Ayuso0f298a22012-02-24 14:41:50 +0000751#ifdef CONFIG_NF_CONNTRACK_MARK
752 if (filter && !((ct->mark & filter->mark.mask) ==
753 filter->mark.val)) {
754 continue;
755 }
756#endif
Hans Schillstrom3b988ec2012-03-05 02:24:29 +0000757 rcu_read_lock();
758 res =
759 ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
760 cb->nlh->nlmsg_seq,
761 NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
762 ct);
763 rcu_read_unlock();
764 if (res < 0) {
Pablo Neira Ayusoc71caf42011-01-24 19:01:07 +0100765 nf_conntrack_get(&ct->ct_general);
Patrick McHardy89f2e212006-05-29 18:24:58 -0700766 cb->args[1] = (unsigned long)ct;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800767 goto out;
Patrick McHardy89f2e212006-05-29 18:24:58 -0700768 }
769 }
Patrick McHardyd205dc42006-08-17 18:12:38 -0700770 if (cb->args[1]) {
Patrick McHardy89f2e212006-05-29 18:24:58 -0700771 cb->args[1] = 0;
772 goto restart;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800773 }
774 }
Patrick McHardy89f2e212006-05-29 18:24:58 -0700775out:
Stephen Hemminger13ee6ac2011-01-11 23:54:42 +0100776 spin_unlock_bh(&nf_conntrack_lock);
Patrick McHardyd205dc42006-08-17 18:12:38 -0700777 if (last)
778 nf_ct_put(last);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800779
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800780 return skb->len;
781}
782
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800783static inline int
Patrick McHardydf6fb862007-09-28 14:37:03 -0700784ctnetlink_parse_tuple_ip(struct nlattr *attr, struct nf_conntrack_tuple *tuple)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800785{
Patrick McHardydf6fb862007-09-28 14:37:03 -0700786 struct nlattr *tb[CTA_IP_MAX+1];
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800787 struct nf_conntrack_l3proto *l3proto;
788 int ret = 0;
789
Patrick McHardydf6fb862007-09-28 14:37:03 -0700790 nla_parse_nested(tb, CTA_IP_MAX, attr, NULL);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800791
Florian Westphalcd915662009-03-18 17:28:37 +0100792 rcu_read_lock();
793 l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800794
Patrick McHardyf73e9242007-09-28 14:39:55 -0700795 if (likely(l3proto->nlattr_to_tuple)) {
796 ret = nla_validate_nested(attr, CTA_IP_MAX,
797 l3proto->nla_policy);
798 if (ret == 0)
799 ret = l3proto->nlattr_to_tuple(tb, tuple);
800 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800801
Florian Westphalcd915662009-03-18 17:28:37 +0100802 rcu_read_unlock();
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800803
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800804 return ret;
805}
806
Patrick McHardyf73e9242007-09-28 14:39:55 -0700807static const struct nla_policy proto_nla_policy[CTA_PROTO_MAX+1] = {
808 [CTA_PROTO_NUM] = { .type = NLA_U8 },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800809};
810
811static inline int
Patrick McHardydf6fb862007-09-28 14:37:03 -0700812ctnetlink_parse_tuple_proto(struct nlattr *attr,
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800813 struct nf_conntrack_tuple *tuple)
814{
Patrick McHardydf6fb862007-09-28 14:37:03 -0700815 struct nlattr *tb[CTA_PROTO_MAX+1];
Martin Josefsson605dcad2006-11-29 02:35:06 +0100816 struct nf_conntrack_l4proto *l4proto;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800817 int ret = 0;
818
Patrick McHardyf73e9242007-09-28 14:39:55 -0700819 ret = nla_parse_nested(tb, CTA_PROTO_MAX, attr, proto_nla_policy);
820 if (ret < 0)
821 return ret;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800822
Patrick McHardydf6fb862007-09-28 14:37:03 -0700823 if (!tb[CTA_PROTO_NUM])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800824 return -EINVAL;
Patrick McHardy77236b62007-12-17 22:29:45 -0800825 tuple->dst.protonum = nla_get_u8(tb[CTA_PROTO_NUM]);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800826
Florian Westphalcd915662009-03-18 17:28:37 +0100827 rcu_read_lock();
828 l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800829
Patrick McHardyf73e9242007-09-28 14:39:55 -0700830 if (likely(l4proto->nlattr_to_tuple)) {
831 ret = nla_validate_nested(attr, CTA_PROTO_MAX,
832 l4proto->nla_policy);
833 if (ret == 0)
834 ret = l4proto->nlattr_to_tuple(tb, tuple);
835 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800836
Florian Westphalcd915662009-03-18 17:28:37 +0100837 rcu_read_unlock();
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800838
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800839 return ret;
840}
841
Patrick McHardyd0b02682010-02-10 15:38:33 +0100842static const struct nla_policy tuple_nla_policy[CTA_TUPLE_MAX+1] = {
843 [CTA_TUPLE_IP] = { .type = NLA_NESTED },
844 [CTA_TUPLE_PROTO] = { .type = NLA_NESTED },
845};
846
Ilpo Järvinenbb5cf802008-01-05 23:11:31 -0800847static int
Patrick McHardy39938322009-08-25 16:07:58 +0200848ctnetlink_parse_tuple(const struct nlattr * const cda[],
849 struct nf_conntrack_tuple *tuple,
Patrick McHardya00f1f32011-02-01 17:26:37 +0100850 enum ctattr_type type, u_int8_t l3num)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800851{
Patrick McHardydf6fb862007-09-28 14:37:03 -0700852 struct nlattr *tb[CTA_TUPLE_MAX+1];
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800853 int err;
854
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800855 memset(tuple, 0, sizeof(*tuple));
856
Patrick McHardyd0b02682010-02-10 15:38:33 +0100857 nla_parse_nested(tb, CTA_TUPLE_MAX, cda[type], tuple_nla_policy);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800858
Patrick McHardydf6fb862007-09-28 14:37:03 -0700859 if (!tb[CTA_TUPLE_IP])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800860 return -EINVAL;
861
862 tuple->src.l3num = l3num;
863
Patrick McHardydf6fb862007-09-28 14:37:03 -0700864 err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP], tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800865 if (err < 0)
866 return err;
867
Patrick McHardydf6fb862007-09-28 14:37:03 -0700868 if (!tb[CTA_TUPLE_PROTO])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800869 return -EINVAL;
870
Patrick McHardydf6fb862007-09-28 14:37:03 -0700871 err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO], tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800872 if (err < 0)
873 return err;
874
875 /* orig and expect tuples get DIR_ORIGINAL */
876 if (type == CTA_TUPLE_REPLY)
877 tuple->dst.dir = IP_CT_DIR_REPLY;
878 else
879 tuple->dst.dir = IP_CT_DIR_ORIGINAL;
880
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800881 return 0;
882}
883
Patrick McHardyef00f892010-02-15 18:14:57 +0100884static int
885ctnetlink_parse_zone(const struct nlattr *attr, u16 *zone)
886{
887 if (attr)
888#ifdef CONFIG_NF_CONNTRACK_ZONES
889 *zone = ntohs(nla_get_be16(attr));
890#else
891 return -EOPNOTSUPP;
892#endif
893 else
894 *zone = 0;
895
896 return 0;
897}
898
Patrick McHardyd0b02682010-02-10 15:38:33 +0100899static const struct nla_policy help_nla_policy[CTA_HELP_MAX+1] = {
900 [CTA_HELP_NAME] = { .type = NLA_NUL_STRING },
901};
902
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800903static inline int
Patrick McHardy39938322009-08-25 16:07:58 +0200904ctnetlink_parse_help(const struct nlattr *attr, char **helper_name)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800905{
Patrick McHardydf6fb862007-09-28 14:37:03 -0700906 struct nlattr *tb[CTA_HELP_MAX+1];
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800907
Patrick McHardyd0b02682010-02-10 15:38:33 +0100908 nla_parse_nested(tb, CTA_HELP_MAX, attr, help_nla_policy);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800909
Patrick McHardydf6fb862007-09-28 14:37:03 -0700910 if (!tb[CTA_HELP_NAME])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800911 return -EINVAL;
912
Patrick McHardydf6fb862007-09-28 14:37:03 -0700913 *helper_name = nla_data(tb[CTA_HELP_NAME]);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800914
915 return 0;
916}
917
Patrick McHardyf73e9242007-09-28 14:39:55 -0700918static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
Patrick McHardyd0b02682010-02-10 15:38:33 +0100919 [CTA_TUPLE_ORIG] = { .type = NLA_NESTED },
920 [CTA_TUPLE_REPLY] = { .type = NLA_NESTED },
Patrick McHardyf73e9242007-09-28 14:39:55 -0700921 [CTA_STATUS] = { .type = NLA_U32 },
Patrick McHardyd0b02682010-02-10 15:38:33 +0100922 [CTA_PROTOINFO] = { .type = NLA_NESTED },
923 [CTA_HELP] = { .type = NLA_NESTED },
924 [CTA_NAT_SRC] = { .type = NLA_NESTED },
Patrick McHardyf73e9242007-09-28 14:39:55 -0700925 [CTA_TIMEOUT] = { .type = NLA_U32 },
926 [CTA_MARK] = { .type = NLA_U32 },
Patrick McHardyf73e9242007-09-28 14:39:55 -0700927 [CTA_ID] = { .type = NLA_U32 },
Patrick McHardyd0b02682010-02-10 15:38:33 +0100928 [CTA_NAT_DST] = { .type = NLA_NESTED },
929 [CTA_TUPLE_MASTER] = { .type = NLA_NESTED },
Patrick McHardyef00f892010-02-15 18:14:57 +0100930 [CTA_ZONE] = { .type = NLA_U16 },
Pablo Neira Ayuso0f298a22012-02-24 14:41:50 +0000931 [CTA_MARK_MASK] = { .type = NLA_U32 },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800932};
933
934static int
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800935ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
Patrick McHardy39938322009-08-25 16:07:58 +0200936 const struct nlmsghdr *nlh,
937 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800938{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +0100939 struct net *net = sock_net(ctnl);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800940 struct nf_conntrack_tuple_hash *h;
941 struct nf_conntrack_tuple tuple;
942 struct nf_conn *ct;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200943 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800944 u_int8_t u3 = nfmsg->nfgen_family;
Patrick McHardyef00f892010-02-15 18:14:57 +0100945 u16 zone;
946 int err;
947
948 err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
949 if (err < 0)
950 return err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800951
Patrick McHardydf6fb862007-09-28 14:37:03 -0700952 if (cda[CTA_TUPLE_ORIG])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800953 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3);
Patrick McHardydf6fb862007-09-28 14:37:03 -0700954 else if (cda[CTA_TUPLE_REPLY])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800955 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3);
956 else {
957 /* Flush the whole table */
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +0100958 nf_conntrack_flush_report(net,
Pablo Neira Ayuso274d3832009-06-02 20:08:38 +0200959 NETLINK_CB(skb).pid,
960 nlmsg_report(nlh));
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800961 return 0;
962 }
963
964 if (err < 0)
965 return err;
966
Patrick McHardyef00f892010-02-15 18:14:57 +0100967 h = nf_conntrack_find_get(net, zone, &tuple);
Pablo Neira Ayuso9ea8cfd2006-10-12 14:09:16 -0700968 if (!h)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800969 return -ENOENT;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800970
971 ct = nf_ct_tuplehash_to_ctrack(h);
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800972
Patrick McHardydf6fb862007-09-28 14:37:03 -0700973 if (cda[CTA_ID]) {
Patrick McHardy77236b62007-12-17 22:29:45 -0800974 u_int32_t id = ntohl(nla_get_be32(cda[CTA_ID]));
Patrick McHardy7f85f912007-09-28 14:41:27 -0700975 if (id != (u32)(unsigned long)ct) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800976 nf_ct_put(ct);
977 return -ENOENT;
978 }
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800979 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800980
Pablo Neira Ayusoa16a1642012-03-16 02:00:34 +0000981 if (del_timer(&ct->timeout)) {
982 if (nf_conntrack_event_report(IPCT_DESTROY, ct,
983 NETLINK_CB(skb).pid,
984 nlmsg_report(nlh)) < 0) {
985 nf_ct_delete_from_lists(ct);
986 /* we failed to report the event, try later */
987 nf_ct_insert_dying_list(ct);
988 nf_ct_put(ct);
989 return 0;
990 }
991 /* death_by_timeout would report the event again */
992 set_bit(IPS_DYING_BIT, &ct->status);
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200993 nf_ct_delete_from_lists(ct);
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200994 nf_ct_put(ct);
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200995 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800996 nf_ct_put(ct);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800997
998 return 0;
999}
1000
1001static int
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001002ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
Patrick McHardy39938322009-08-25 16:07:58 +02001003 const struct nlmsghdr *nlh,
1004 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001005{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01001006 struct net *net = sock_net(ctnl);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001007 struct nf_conntrack_tuple_hash *h;
1008 struct nf_conntrack_tuple tuple;
1009 struct nf_conn *ct;
1010 struct sk_buff *skb2 = NULL;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001011 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001012 u_int8_t u3 = nfmsg->nfgen_family;
Patrick McHardyef00f892010-02-15 18:14:57 +01001013 u16 zone;
1014 int err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001015
Pablo Neira Ayuso80d326f2012-02-24 14:30:15 +00001016 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1017 struct netlink_dump_control c = {
1018 .dump = ctnetlink_dump_table,
1019 .done = ctnetlink_done,
1020 };
Pablo Neira Ayuso0f298a22012-02-24 14:41:50 +00001021#ifdef CONFIG_NF_CONNTRACK_MARK
1022 if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) {
1023 struct ctnetlink_dump_filter *filter;
1024
1025 filter = kzalloc(sizeof(struct ctnetlink_dump_filter),
1026 GFP_ATOMIC);
1027 if (filter == NULL)
1028 return -ENOMEM;
1029
1030 filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK]));
1031 filter->mark.mask =
1032 ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
1033 c.data = filter;
1034 }
1035#endif
Pablo Neira Ayuso80d326f2012-02-24 14:30:15 +00001036 return netlink_dump_start(ctnl, skb, nlh, &c);
1037 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001038
Patrick McHardyef00f892010-02-15 18:14:57 +01001039 err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
1040 if (err < 0)
1041 return err;
1042
Patrick McHardydf6fb862007-09-28 14:37:03 -07001043 if (cda[CTA_TUPLE_ORIG])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001044 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3);
Patrick McHardydf6fb862007-09-28 14:37:03 -07001045 else if (cda[CTA_TUPLE_REPLY])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001046 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3);
1047 else
1048 return -EINVAL;
1049
1050 if (err < 0)
1051 return err;
1052
Patrick McHardyef00f892010-02-15 18:14:57 +01001053 h = nf_conntrack_find_get(net, zone, &tuple);
Pablo Neira Ayuso9ea8cfd2006-10-12 14:09:16 -07001054 if (!h)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001055 return -ENOENT;
Pablo Neira Ayuso9ea8cfd2006-10-12 14:09:16 -07001056
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001057 ct = nf_ct_tuplehash_to_ctrack(h);
1058
1059 err = -ENOMEM;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001060 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1061 if (skb2 == NULL) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001062 nf_ct_put(ct);
1063 return -ENOMEM;
1064 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001065
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001066 rcu_read_lock();
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001067 err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq,
Pablo Neira Ayuso80e60e62011-12-24 14:11:39 +01001068 NFNL_MSG_TYPE(nlh->nlmsg_type), ct);
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001069 rcu_read_unlock();
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001070 nf_ct_put(ct);
1071 if (err <= 0)
1072 goto free;
1073
1074 err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
1075 if (err < 0)
1076 goto out;
1077
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001078 return 0;
1079
1080free:
1081 kfree_skb(skb2);
1082out:
Pablo Neira Ayusof31e8d492011-01-13 14:19:55 +01001083 /* this avoids a loop in nfnetlink. */
1084 return err == -EAGAIN ? -ENOBUFS : err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001085}
1086
Pablo Neira Ayuso67671842008-10-20 03:34:27 -07001087#ifdef CONFIG_NF_NAT_NEEDED
Ilpo Järvinenbb5cf802008-01-05 23:11:31 -08001088static int
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001089ctnetlink_parse_nat_setup(struct nf_conn *ct,
1090 enum nf_nat_manip_type manip,
Patrick McHardy39938322009-08-25 16:07:58 +02001091 const struct nlattr *attr)
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001092{
1093 typeof(nfnetlink_parse_nat_setup_hook) parse_nat_setup;
1094
1095 parse_nat_setup = rcu_dereference(nfnetlink_parse_nat_setup_hook);
1096 if (!parse_nat_setup) {
Johannes Berg95a5afc2008-10-16 15:24:51 -07001097#ifdef CONFIG_MODULES
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001098 rcu_read_unlock();
1099 nfnl_unlock();
1100 if (request_module("nf-nat-ipv4") < 0) {
1101 nfnl_lock();
1102 rcu_read_lock();
1103 return -EOPNOTSUPP;
1104 }
1105 nfnl_lock();
1106 rcu_read_lock();
1107 if (nfnetlink_parse_nat_setup_hook)
1108 return -EAGAIN;
1109#endif
1110 return -EOPNOTSUPP;
1111 }
1112
1113 return parse_nat_setup(ct, manip, attr);
1114}
Pablo Neira Ayuso67671842008-10-20 03:34:27 -07001115#endif
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001116
1117static int
Patrick McHardy39938322009-08-25 16:07:58 +02001118ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001119{
1120 unsigned long d;
Patrick McHardy77236b62007-12-17 22:29:45 -08001121 unsigned int status = ntohl(nla_get_be32(cda[CTA_STATUS]));
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001122 d = ct->status ^ status;
1123
1124 if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
1125 /* unchangeable */
Pablo Neira Ayuso0adf9d62008-06-09 15:56:20 -07001126 return -EBUSY;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001127
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001128 if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
1129 /* SEEN_REPLY bit can only be set */
Pablo Neira Ayuso0adf9d62008-06-09 15:56:20 -07001130 return -EBUSY;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001131
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001132 if (d & IPS_ASSURED && !(status & IPS_ASSURED))
1133 /* ASSURED bit can only be set */
Pablo Neira Ayuso0adf9d62008-06-09 15:56:20 -07001134 return -EBUSY;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001135
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001136 /* Be careful here, modifying NAT bits can screw up things,
1137 * so don't let users modify them directly if they don't pass
Jozsef Kadlecsik5b1158e2006-12-02 22:07:13 -08001138 * nf_nat_range. */
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001139 ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);
1140 return 0;
1141}
1142
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001143static int
Patrick McHardy39938322009-08-25 16:07:58 +02001144ctnetlink_change_nat(struct nf_conn *ct, const struct nlattr * const cda[])
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001145{
1146#ifdef CONFIG_NF_NAT_NEEDED
1147 int ret;
1148
1149 if (cda[CTA_NAT_DST]) {
1150 ret = ctnetlink_parse_nat_setup(ct,
Patrick McHardycbc9f2f2011-12-23 13:59:49 +01001151 NF_NAT_MANIP_DST,
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001152 cda[CTA_NAT_DST]);
1153 if (ret < 0)
1154 return ret;
1155 }
1156 if (cda[CTA_NAT_SRC]) {
1157 ret = ctnetlink_parse_nat_setup(ct,
Patrick McHardycbc9f2f2011-12-23 13:59:49 +01001158 NF_NAT_MANIP_SRC,
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001159 cda[CTA_NAT_SRC]);
1160 if (ret < 0)
1161 return ret;
1162 }
1163 return 0;
1164#else
1165 return -EOPNOTSUPP;
1166#endif
1167}
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001168
1169static inline int
Patrick McHardy39938322009-08-25 16:07:58 +02001170ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001171{
1172 struct nf_conntrack_helper *helper;
Harald Weltedc808fe2006-03-20 17:56:32 -08001173 struct nf_conn_help *help = nfct_help(ct);
Pablo Neira Ayuso29fe1b42009-04-22 02:26:37 -07001174 char *helpname = NULL;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001175 int err;
1176
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001177 /* don't change helper of sibling connections */
1178 if (ct->master)
Pablo Neira Ayuso0adf9d62008-06-09 15:56:20 -07001179 return -EBUSY;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001180
Patrick McHardydf6fb862007-09-28 14:37:03 -07001181 err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001182 if (err < 0)
1183 return err;
1184
Yasuyuki Kozakaidf293bb2007-05-10 14:15:58 -07001185 if (!strcmp(helpname, "")) {
1186 if (help && help->helper) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001187 /* we had a helper before ... */
1188 nf_ct_remove_expectations(ct);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001189 RCU_INIT_POINTER(help->helper, NULL);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001190 }
Yasuyuki Kozakaidf293bb2007-05-10 14:15:58 -07001191
1192 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001193 }
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001194
Patrick McHardy794e6872010-02-03 13:41:29 +01001195 helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
1196 nf_ct_protonum(ct));
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001197 if (helper == NULL) {
1198#ifdef CONFIG_MODULES
1199 spin_unlock_bh(&nf_conntrack_lock);
1200
1201 if (request_module("nfct-helper-%s", helpname) < 0) {
1202 spin_lock_bh(&nf_conntrack_lock);
1203 return -EOPNOTSUPP;
1204 }
1205
1206 spin_lock_bh(&nf_conntrack_lock);
Patrick McHardy794e6872010-02-03 13:41:29 +01001207 helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
1208 nf_ct_protonum(ct));
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001209 if (helper)
1210 return -EAGAIN;
1211#endif
Pablo Neira Ayuso0adf9d62008-06-09 15:56:20 -07001212 return -EOPNOTSUPP;
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001213 }
Yasuyuki Kozakaidf293bb2007-05-10 14:15:58 -07001214
Yasuyuki Kozakaiceceae12007-07-07 22:23:42 -07001215 if (help) {
1216 if (help->helper == helper)
1217 return 0;
1218 if (help->helper)
1219 return -EBUSY;
1220 /* need to zero data of old helper */
1221 memset(&help->help, 0, sizeof(help->help));
1222 } else {
Pablo Neira Ayusoa88e22a2010-02-19 14:24:39 +01001223 /* we cannot set a helper for an existing conntrack */
1224 return -EOPNOTSUPP;
Yasuyuki Kozakaiceceae12007-07-07 22:23:42 -07001225 }
Yasuyuki Kozakaidf293bb2007-05-10 14:15:58 -07001226
Eric Dumazetcf778b02012-01-12 04:41:32 +00001227 rcu_assign_pointer(help->helper, helper);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001228
1229 return 0;
1230}
1231
1232static inline int
Patrick McHardy39938322009-08-25 16:07:58 +02001233ctnetlink_change_timeout(struct nf_conn *ct, const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001234{
Patrick McHardy77236b62007-12-17 22:29:45 -08001235 u_int32_t timeout = ntohl(nla_get_be32(cda[CTA_TIMEOUT]));
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001236
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001237 if (!del_timer(&ct->timeout))
1238 return -ETIME;
1239
1240 ct->timeout.expires = jiffies + timeout * HZ;
1241 add_timer(&ct->timeout);
1242
1243 return 0;
1244}
1245
Patrick McHardyd0b02682010-02-10 15:38:33 +01001246static const struct nla_policy protoinfo_policy[CTA_PROTOINFO_MAX+1] = {
1247 [CTA_PROTOINFO_TCP] = { .type = NLA_NESTED },
1248 [CTA_PROTOINFO_DCCP] = { .type = NLA_NESTED },
1249 [CTA_PROTOINFO_SCTP] = { .type = NLA_NESTED },
1250};
1251
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001252static inline int
Patrick McHardy39938322009-08-25 16:07:58 +02001253ctnetlink_change_protoinfo(struct nf_conn *ct, const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001254{
Patrick McHardy39938322009-08-25 16:07:58 +02001255 const struct nlattr *attr = cda[CTA_PROTOINFO];
1256 struct nlattr *tb[CTA_PROTOINFO_MAX+1];
Martin Josefsson605dcad2006-11-29 02:35:06 +01001257 struct nf_conntrack_l4proto *l4proto;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001258 int err = 0;
1259
Patrick McHardyd0b02682010-02-10 15:38:33 +01001260 nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, protoinfo_policy);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001261
Florian Westphalcd915662009-03-18 17:28:37 +01001262 rcu_read_lock();
1263 l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
Patrick McHardyfdf70832007-09-28 14:37:41 -07001264 if (l4proto->from_nlattr)
1265 err = l4proto->from_nlattr(tb, ct);
Florian Westphalcd915662009-03-18 17:28:37 +01001266 rcu_read_unlock();
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001267
1268 return err;
1269}
1270
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001271#ifdef CONFIG_NF_NAT_NEEDED
Patrick McHardyd0b02682010-02-10 15:38:33 +01001272static const struct nla_policy nat_seq_policy[CTA_NAT_SEQ_MAX+1] = {
1273 [CTA_NAT_SEQ_CORRECTION_POS] = { .type = NLA_U32 },
1274 [CTA_NAT_SEQ_OFFSET_BEFORE] = { .type = NLA_U32 },
1275 [CTA_NAT_SEQ_OFFSET_AFTER] = { .type = NLA_U32 },
1276};
1277
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001278static inline int
Patrick McHardy39938322009-08-25 16:07:58 +02001279change_nat_seq_adj(struct nf_nat_seq *natseq, const struct nlattr * const attr)
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001280{
1281 struct nlattr *cda[CTA_NAT_SEQ_MAX+1];
1282
Patrick McHardyd0b02682010-02-10 15:38:33 +01001283 nla_parse_nested(cda, CTA_NAT_SEQ_MAX, attr, nat_seq_policy);
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001284
1285 if (!cda[CTA_NAT_SEQ_CORRECTION_POS])
1286 return -EINVAL;
1287
1288 natseq->correction_pos =
Patrick McHardy77236b62007-12-17 22:29:45 -08001289 ntohl(nla_get_be32(cda[CTA_NAT_SEQ_CORRECTION_POS]));
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001290
1291 if (!cda[CTA_NAT_SEQ_OFFSET_BEFORE])
1292 return -EINVAL;
1293
1294 natseq->offset_before =
Patrick McHardy77236b62007-12-17 22:29:45 -08001295 ntohl(nla_get_be32(cda[CTA_NAT_SEQ_OFFSET_BEFORE]));
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001296
1297 if (!cda[CTA_NAT_SEQ_OFFSET_AFTER])
1298 return -EINVAL;
1299
1300 natseq->offset_after =
Patrick McHardy77236b62007-12-17 22:29:45 -08001301 ntohl(nla_get_be32(cda[CTA_NAT_SEQ_OFFSET_AFTER]));
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001302
1303 return 0;
1304}
1305
1306static int
Patrick McHardy39938322009-08-25 16:07:58 +02001307ctnetlink_change_nat_seq_adj(struct nf_conn *ct,
1308 const struct nlattr * const cda[])
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001309{
1310 int ret = 0;
1311 struct nf_conn_nat *nat = nfct_nat(ct);
1312
1313 if (!nat)
1314 return 0;
1315
1316 if (cda[CTA_NAT_SEQ_ADJ_ORIG]) {
1317 ret = change_nat_seq_adj(&nat->seq[IP_CT_DIR_ORIGINAL],
1318 cda[CTA_NAT_SEQ_ADJ_ORIG]);
1319 if (ret < 0)
1320 return ret;
1321
1322 ct->status |= IPS_SEQ_ADJUST;
1323 }
1324
1325 if (cda[CTA_NAT_SEQ_ADJ_REPLY]) {
1326 ret = change_nat_seq_adj(&nat->seq[IP_CT_DIR_REPLY],
1327 cda[CTA_NAT_SEQ_ADJ_REPLY]);
1328 if (ret < 0)
1329 return ret;
1330
1331 ct->status |= IPS_SEQ_ADJUST;
1332 }
1333
1334 return 0;
1335}
1336#endif
1337
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001338static int
Patrick McHardy39938322009-08-25 16:07:58 +02001339ctnetlink_change_conntrack(struct nf_conn *ct,
1340 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001341{
1342 int err;
1343
Pablo Neira Ayusoe0983602009-03-16 15:27:22 +01001344 /* only allow NAT changes and master assignation for new conntracks */
1345 if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST] || cda[CTA_TUPLE_MASTER])
1346 return -EOPNOTSUPP;
1347
Patrick McHardydf6fb862007-09-28 14:37:03 -07001348 if (cda[CTA_HELP]) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001349 err = ctnetlink_change_helper(ct, cda);
1350 if (err < 0)
1351 return err;
1352 }
1353
Patrick McHardydf6fb862007-09-28 14:37:03 -07001354 if (cda[CTA_TIMEOUT]) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001355 err = ctnetlink_change_timeout(ct, cda);
1356 if (err < 0)
1357 return err;
1358 }
1359
Patrick McHardydf6fb862007-09-28 14:37:03 -07001360 if (cda[CTA_STATUS]) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001361 err = ctnetlink_change_status(ct, cda);
1362 if (err < 0)
1363 return err;
1364 }
1365
Patrick McHardydf6fb862007-09-28 14:37:03 -07001366 if (cda[CTA_PROTOINFO]) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001367 err = ctnetlink_change_protoinfo(ct, cda);
1368 if (err < 0)
1369 return err;
1370 }
1371
Martin Josefssonbcd1e832006-04-01 02:23:21 -08001372#if defined(CONFIG_NF_CONNTRACK_MARK)
Patrick McHardydf6fb862007-09-28 14:37:03 -07001373 if (cda[CTA_MARK])
Patrick McHardy77236b62007-12-17 22:29:45 -08001374 ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001375#endif
1376
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001377#ifdef CONFIG_NF_NAT_NEEDED
1378 if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) {
1379 err = ctnetlink_change_nat_seq_adj(ct, cda);
1380 if (err < 0)
1381 return err;
1382 }
1383#endif
1384
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001385 return 0;
1386}
1387
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001388static struct nf_conn *
Patrick McHardyef00f892010-02-15 18:14:57 +01001389ctnetlink_create_conntrack(struct net *net, u16 zone,
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01001390 const struct nlattr * const cda[],
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001391 struct nf_conntrack_tuple *otuple,
Pablo Neira Ayuso5faa1f42007-09-28 14:43:53 -07001392 struct nf_conntrack_tuple *rtuple,
Pablo Neira Ayuso7ec47492009-03-16 15:25:46 +01001393 u8 u3)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001394{
1395 struct nf_conn *ct;
1396 int err = -EINVAL;
Yasuyuki Kozakaiceceae12007-07-07 22:23:42 -07001397 struct nf_conntrack_helper *helper;
Pablo Neira Ayuso315c34d2011-04-21 10:55:07 +02001398 struct nf_conn_tstamp *tstamp;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001399
Patrick McHardyef00f892010-02-15 18:14:57 +01001400 ct = nf_conntrack_alloc(net, zone, otuple, rtuple, GFP_ATOMIC);
Julia Lawallcd7fcbf2009-01-12 00:06:08 +00001401 if (IS_ERR(ct))
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001402 return ERR_PTR(-ENOMEM);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001403
Patrick McHardydf6fb862007-09-28 14:37:03 -07001404 if (!cda[CTA_TIMEOUT])
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001405 goto err1;
Patrick McHardy77236b62007-12-17 22:29:45 -08001406 ct->timeout.expires = ntohl(nla_get_be32(cda[CTA_TIMEOUT]));
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001407
1408 ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001409
Patrick McHardy58a3c9b2008-01-31 04:36:54 -08001410 rcu_read_lock();
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001411 if (cda[CTA_HELP]) {
Pablo Neira Ayuso29fe1b42009-04-22 02:26:37 -07001412 char *helpname = NULL;
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001413
1414 err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001415 if (err < 0)
1416 goto err2;
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001417
Patrick McHardy794e6872010-02-03 13:41:29 +01001418 helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
1419 nf_ct_protonum(ct));
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001420 if (helper == NULL) {
1421 rcu_read_unlock();
1422#ifdef CONFIG_MODULES
1423 if (request_module("nfct-helper-%s", helpname) < 0) {
1424 err = -EOPNOTSUPP;
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001425 goto err1;
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001426 }
1427
1428 rcu_read_lock();
Patrick McHardy794e6872010-02-03 13:41:29 +01001429 helper = __nf_conntrack_helper_find(helpname,
1430 nf_ct_l3num(ct),
1431 nf_ct_protonum(ct));
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001432 if (helper) {
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001433 err = -EAGAIN;
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001434 goto err2;
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001435 }
1436 rcu_read_unlock();
1437#endif
1438 err = -EOPNOTSUPP;
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001439 goto err1;
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001440 } else {
1441 struct nf_conn_help *help;
1442
1443 help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
1444 if (help == NULL) {
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001445 err = -ENOMEM;
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001446 goto err2;
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001447 }
1448
1449 /* not in hash table yet so not strictly necessary */
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001450 RCU_INIT_POINTER(help->helper, helper);
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001451 }
1452 } else {
1453 /* try an implicit helper assignation */
Patrick McHardyb2a15a62010-02-03 14:13:03 +01001454 err = __nf_ct_try_assign_helper(ct, NULL, GFP_ATOMIC);
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001455 if (err < 0)
1456 goto err2;
Patrick McHarrdy3c158f72007-06-05 12:55:27 -07001457 }
Yasuyuki Kozakaidafc7412006-11-27 10:25:32 -08001458
Pablo Neira Ayusoa88e22a2010-02-19 14:24:39 +01001459 if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
1460 err = ctnetlink_change_nat(ct, cda);
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001461 if (err < 0)
1462 goto err2;
Pablo Neira Ayuso1575e7e2008-08-18 21:30:55 -07001463 }
1464
Pablo Neira Ayusoa88e22a2010-02-19 14:24:39 +01001465 nf_ct_acct_ext_add(ct, GFP_ATOMIC);
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +01001466 nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
Pablo Neira Ayusoa88e22a2010-02-19 14:24:39 +01001467 nf_ct_ecache_ext_add(ct, 0, 0, GFP_ATOMIC);
1468 /* we must add conntrack extensions before confirmation. */
1469 ct->status |= IPS_CONFIRMED;
1470
1471 if (cda[CTA_STATUS]) {
1472 err = ctnetlink_change_status(ct, cda);
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001473 if (err < 0)
1474 goto err2;
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001475 }
1476
Pablo Neira Ayusoc969aa72009-02-09 14:33:57 -08001477#ifdef CONFIG_NF_NAT_NEEDED
1478 if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) {
1479 err = ctnetlink_change_nat_seq_adj(ct, cda);
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001480 if (err < 0)
1481 goto err2;
Pablo Neira Ayusoc969aa72009-02-09 14:33:57 -08001482 }
1483#endif
1484
Changli Gaoe5fc9e72010-11-12 17:33:17 +01001485 memset(&ct->proto, 0, sizeof(ct->proto));
Pablo Neira Ayuso1575e7e2008-08-18 21:30:55 -07001486 if (cda[CTA_PROTOINFO]) {
1487 err = ctnetlink_change_protoinfo(ct, cda);
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001488 if (err < 0)
1489 goto err2;
Pablo Neira Ayuso1575e7e2008-08-18 21:30:55 -07001490 }
1491
Pablo Neira Ayuso1575e7e2008-08-18 21:30:55 -07001492#if defined(CONFIG_NF_CONNTRACK_MARK)
1493 if (cda[CTA_MARK])
1494 ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
1495#endif
1496
Pablo Neira Ayuso5faa1f42007-09-28 14:43:53 -07001497 /* setup master conntrack: this is a confirmed expectation */
Pablo Neira Ayuso7ec47492009-03-16 15:25:46 +01001498 if (cda[CTA_TUPLE_MASTER]) {
1499 struct nf_conntrack_tuple master;
1500 struct nf_conntrack_tuple_hash *master_h;
1501 struct nf_conn *master_ct;
1502
1503 err = ctnetlink_parse_tuple(cda, &master, CTA_TUPLE_MASTER, u3);
1504 if (err < 0)
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001505 goto err2;
Pablo Neira Ayuso7ec47492009-03-16 15:25:46 +01001506
Patrick McHardyef00f892010-02-15 18:14:57 +01001507 master_h = nf_conntrack_find_get(net, zone, &master);
Pablo Neira Ayuso7ec47492009-03-16 15:25:46 +01001508 if (master_h == NULL) {
1509 err = -ENOENT;
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001510 goto err2;
Pablo Neira Ayuso7ec47492009-03-16 15:25:46 +01001511 }
1512 master_ct = nf_ct_tuplehash_to_ctrack(master_h);
Pablo Neira Ayusof2a89002007-12-12 10:34:29 -08001513 __set_bit(IPS_EXPECTED_BIT, &ct->status);
Pablo Neira Ayuso5faa1f42007-09-28 14:43:53 -07001514 ct->master = master_ct;
Pablo Neira Ayusof2a89002007-12-12 10:34:29 -08001515 }
Pablo Neira Ayuso315c34d2011-04-21 10:55:07 +02001516 tstamp = nf_conn_tstamp_find(ct);
1517 if (tstamp)
1518 tstamp->start = ktime_to_ns(ktime_get_real());
Pablo Neira Ayuso5faa1f42007-09-28 14:43:53 -07001519
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001520 err = nf_conntrack_hash_check_insert(ct);
1521 if (err < 0)
1522 goto err2;
1523
Patrick McHardy58a3c9b2008-01-31 04:36:54 -08001524 rcu_read_unlock();
Yasuyuki Kozakaidafc7412006-11-27 10:25:32 -08001525
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001526 return ct;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001527
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001528err2:
1529 rcu_read_unlock();
1530err1:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001531 nf_conntrack_free(ct);
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001532 return ERR_PTR(err);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001533}
1534
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001535static int
1536ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
Patrick McHardy39938322009-08-25 16:07:58 +02001537 const struct nlmsghdr *nlh,
1538 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001539{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01001540 struct net *net = sock_net(ctnl);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001541 struct nf_conntrack_tuple otuple, rtuple;
1542 struct nf_conntrack_tuple_hash *h = NULL;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001543 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001544 struct nf_conn *ct;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001545 u_int8_t u3 = nfmsg->nfgen_family;
Patrick McHardyef00f892010-02-15 18:14:57 +01001546 u16 zone;
1547 int err;
1548
1549 err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
1550 if (err < 0)
1551 return err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001552
Patrick McHardydf6fb862007-09-28 14:37:03 -07001553 if (cda[CTA_TUPLE_ORIG]) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001554 err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG, u3);
1555 if (err < 0)
1556 return err;
1557 }
1558
Patrick McHardydf6fb862007-09-28 14:37:03 -07001559 if (cda[CTA_TUPLE_REPLY]) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001560 err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY, u3);
1561 if (err < 0)
1562 return err;
1563 }
1564
Patrick McHardydf6fb862007-09-28 14:37:03 -07001565 if (cda[CTA_TUPLE_ORIG])
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001566 h = nf_conntrack_find_get(net, zone, &otuple);
Patrick McHardydf6fb862007-09-28 14:37:03 -07001567 else if (cda[CTA_TUPLE_REPLY])
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001568 h = nf_conntrack_find_get(net, zone, &rtuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001569
1570 if (h == NULL) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001571 err = -ENOENT;
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001572 if (nlh->nlmsg_flags & NLM_F_CREATE) {
Pablo Neira Ayusofecc1132009-05-05 17:48:26 +02001573 enum ip_conntrack_events events;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001574
Patrick McHardyef00f892010-02-15 18:14:57 +01001575 ct = ctnetlink_create_conntrack(net, zone, cda, &otuple,
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001576 &rtuple, u3);
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001577 if (IS_ERR(ct))
1578 return PTR_ERR(ct);
1579
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001580 err = 0;
Pablo Neira Ayusofecc1132009-05-05 17:48:26 +02001581 if (test_bit(IPS_EXPECTED_BIT, &ct->status))
1582 events = IPCT_RELATED;
1583 else
1584 events = IPCT_NEW;
1585
Patrick McHardy858b31332010-02-03 13:48:53 +01001586 nf_conntrack_eventmask_report((1 << IPCT_REPLY) |
1587 (1 << IPCT_ASSURED) |
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +02001588 (1 << IPCT_HELPER) |
1589 (1 << IPCT_PROTOINFO) |
1590 (1 << IPCT_NATSEQADJ) |
1591 (1 << IPCT_MARK) | events,
1592 ct, NETLINK_CB(skb).pid,
1593 nlmsg_report(nlh));
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001594 nf_ct_put(ct);
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001595 }
Pablo Neira Ayuso5faa1f42007-09-28 14:43:53 -07001596
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001597 return err;
1598 }
1599 /* implicit 'else' */
1600
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001601 err = -EEXIST;
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001602 ct = nf_ct_tuplehash_to_ctrack(h);
Pablo Neira Ayusoff4ca822007-08-07 18:11:26 -07001603 if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001604 spin_lock_bh(&nf_conntrack_lock);
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +01001605 err = ctnetlink_change_conntrack(ct, cda);
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001606 spin_unlock_bh(&nf_conntrack_lock);
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +01001607 if (err == 0) {
Patrick McHardy858b31332010-02-03 13:48:53 +01001608 nf_conntrack_eventmask_report((1 << IPCT_REPLY) |
1609 (1 << IPCT_ASSURED) |
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +02001610 (1 << IPCT_HELPER) |
1611 (1 << IPCT_PROTOINFO) |
1612 (1 << IPCT_NATSEQADJ) |
1613 (1 << IPCT_MARK),
1614 ct, NETLINK_CB(skb).pid,
1615 nlmsg_report(nlh));
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001616 }
Pablo Neira Ayusoff4ca822007-08-07 18:11:26 -07001617 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001618
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001619 nf_ct_put(ct);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001620 return err;
1621}
1622
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001623/***********************************************************************
1624 * EXPECT
1625 ***********************************************************************/
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001626
1627static inline int
1628ctnetlink_exp_dump_tuple(struct sk_buff *skb,
1629 const struct nf_conntrack_tuple *tuple,
1630 enum ctattr_expect type)
1631{
Patrick McHardydf6fb862007-09-28 14:37:03 -07001632 struct nlattr *nest_parms;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001633
Patrick McHardydf6fb862007-09-28 14:37:03 -07001634 nest_parms = nla_nest_start(skb, type | NLA_F_NESTED);
1635 if (!nest_parms)
1636 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001637 if (ctnetlink_dump_tuples(skb, tuple) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07001638 goto nla_put_failure;
1639 nla_nest_end(skb, nest_parms);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001640
1641 return 0;
1642
Patrick McHardydf6fb862007-09-28 14:37:03 -07001643nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001644 return -1;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001645}
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001646
1647static inline int
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001648ctnetlink_exp_dump_mask(struct sk_buff *skb,
1649 const struct nf_conntrack_tuple *tuple,
Patrick McHardyd4156e82007-07-07 22:31:32 -07001650 const struct nf_conntrack_tuple_mask *mask)
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001651{
1652 int ret;
1653 struct nf_conntrack_l3proto *l3proto;
Martin Josefsson605dcad2006-11-29 02:35:06 +01001654 struct nf_conntrack_l4proto *l4proto;
Patrick McHardyd4156e82007-07-07 22:31:32 -07001655 struct nf_conntrack_tuple m;
Patrick McHardydf6fb862007-09-28 14:37:03 -07001656 struct nlattr *nest_parms;
Patrick McHardyd4156e82007-07-07 22:31:32 -07001657
1658 memset(&m, 0xFF, sizeof(m));
Patrick McHardyd4156e82007-07-07 22:31:32 -07001659 memcpy(&m.src.u3, &mask->src.u3, sizeof(m.src.u3));
Patrick McHardye5787562010-01-26 17:04:02 +01001660 m.src.u.all = mask->src.u.all;
1661 m.dst.protonum = tuple->dst.protonum;
Patrick McHardyd4156e82007-07-07 22:31:32 -07001662
Patrick McHardydf6fb862007-09-28 14:37:03 -07001663 nest_parms = nla_nest_start(skb, CTA_EXPECT_MASK | NLA_F_NESTED);
1664 if (!nest_parms)
1665 goto nla_put_failure;
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001666
Hans Schillstrom3b988ec2012-03-05 02:24:29 +00001667 rcu_read_lock();
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001668 l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
Patrick McHardyd4156e82007-07-07 22:31:32 -07001669 ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto);
Hans Schillstrom3b988ec2012-03-05 02:24:29 +00001670 if (ret >= 0) {
1671 l4proto = __nf_ct_l4proto_find(tuple->src.l3num,
1672 tuple->dst.protonum);
Patrick McHardyd4156e82007-07-07 22:31:32 -07001673 ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto);
Hans Schillstrom3b988ec2012-03-05 02:24:29 +00001674 }
1675 rcu_read_unlock();
1676
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001677 if (unlikely(ret < 0))
Patrick McHardydf6fb862007-09-28 14:37:03 -07001678 goto nla_put_failure;
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001679
Patrick McHardydf6fb862007-09-28 14:37:03 -07001680 nla_nest_end(skb, nest_parms);
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001681
1682 return 0;
1683
Patrick McHardydf6fb862007-09-28 14:37:03 -07001684nla_put_failure:
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001685 return -1;
1686}
1687
Ilpo Järvinenbb5cf802008-01-05 23:11:31 -08001688static int
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001689ctnetlink_exp_dump_expect(struct sk_buff *skb,
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001690 const struct nf_conntrack_expect *exp)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001691{
1692 struct nf_conn *master = exp->master;
Xi Wangc1216382011-12-30 10:40:17 -05001693 long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ;
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02001694 struct nf_conn_help *help;
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01001695#ifdef CONFIG_NF_NAT_NEEDED
1696 struct nlattr *nest_parms;
1697 struct nf_conntrack_tuple nat_tuple = {};
1698#endif
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +01001699 struct nf_ct_helper_expectfn *expfn;
1700
Patrick McHardyd978e5d2007-12-17 22:37:03 -08001701 if (timeout < 0)
1702 timeout = 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001703
1704 if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07001705 goto nla_put_failure;
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001706 if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07001707 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001708 if (ctnetlink_exp_dump_tuple(skb,
1709 &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
1710 CTA_EXPECT_MASTER) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07001711 goto nla_put_failure;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001712
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01001713#ifdef CONFIG_NF_NAT_NEEDED
1714 if (exp->saved_ip || exp->saved_proto.all) {
1715 nest_parms = nla_nest_start(skb, CTA_EXPECT_NAT | NLA_F_NESTED);
1716 if (!nest_parms)
1717 goto nla_put_failure;
1718
David S. Millercc1eb432012-04-01 18:57:48 -04001719 if (nla_put_be32(skb, CTA_EXPECT_NAT_DIR, htonl(exp->dir)))
1720 goto nla_put_failure;
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01001721
1722 nat_tuple.src.l3num = nf_ct_l3num(master);
1723 nat_tuple.src.u3.ip = exp->saved_ip;
1724 nat_tuple.dst.protonum = nf_ct_protonum(master);
1725 nat_tuple.src.u = exp->saved_proto;
1726
1727 if (ctnetlink_exp_dump_tuple(skb, &nat_tuple,
1728 CTA_EXPECT_NAT_TUPLE) < 0)
1729 goto nla_put_failure;
1730 nla_nest_end(skb, nest_parms);
1731 }
1732#endif
David S. Millercc1eb432012-04-01 18:57:48 -04001733 if (nla_put_be32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)) ||
1734 nla_put_be32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)) ||
1735 nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) ||
1736 nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class)))
1737 goto nla_put_failure;
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02001738 help = nfct_help(master);
1739 if (help) {
1740 struct nf_conntrack_helper *helper;
1741
1742 helper = rcu_dereference(help->helper);
David S. Millercc1eb432012-04-01 18:57:48 -04001743 if (helper &&
1744 nla_put_string(skb, CTA_EXPECT_HELP_NAME, helper->name))
1745 goto nla_put_failure;
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02001746 }
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +01001747 expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn);
David S. Millercc1eb432012-04-01 18:57:48 -04001748 if (expfn != NULL &&
1749 nla_put_string(skb, CTA_EXPECT_FN, expfn->name))
1750 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001751
1752 return 0;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001753
Patrick McHardydf6fb862007-09-28 14:37:03 -07001754nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001755 return -1;
1756}
1757
1758static int
1759ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
Pablo Neira Ayuso8b0a2312009-06-02 20:03:34 +02001760 int event, const struct nf_conntrack_expect *exp)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001761{
1762 struct nlmsghdr *nlh;
1763 struct nfgenmsg *nfmsg;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001764 unsigned int flags = pid ? NLM_F_MULTI : 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001765
1766 event |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001767 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags);
1768 if (nlh == NULL)
1769 goto nlmsg_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001770
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001771 nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001772 nfmsg->nfgen_family = exp->tuple.src.l3num;
1773 nfmsg->version = NFNETLINK_V0;
1774 nfmsg->res_id = 0;
1775
1776 if (ctnetlink_exp_dump_expect(skb, exp) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07001777 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001778
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001779 nlmsg_end(skb, nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001780 return skb->len;
1781
1782nlmsg_failure:
Patrick McHardydf6fb862007-09-28 14:37:03 -07001783nla_put_failure:
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001784 nlmsg_cancel(skb, nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001785 return -1;
1786}
1787
1788#ifdef CONFIG_NF_CONNTRACK_EVENTS
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02001789static int
1790ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001791{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01001792 struct nf_conntrack_expect *exp = item->exp;
1793 struct net *net = nf_ct_exp_net(exp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001794 struct nlmsghdr *nlh;
1795 struct nfgenmsg *nfmsg;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001796 struct sk_buff *skb;
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02001797 unsigned int type, group;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001798 int flags = 0;
1799
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02001800 if (events & (1 << IPEXP_DESTROY)) {
1801 type = IPCTNL_MSG_EXP_DELETE;
1802 group = NFNLGRP_CONNTRACK_EXP_DESTROY;
1803 } else if (events & (1 << IPEXP_NEW)) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001804 type = IPCTNL_MSG_EXP_NEW;
1805 flags = NLM_F_CREATE|NLM_F_EXCL;
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02001806 group = NFNLGRP_CONNTRACK_EXP_NEW;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001807 } else
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02001808 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001809
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02001810 if (!item->report && !nfnetlink_has_listeners(net, group))
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02001811 return 0;
Pablo Neira Ayusob3a27bf2006-08-22 00:32:05 -07001812
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001813 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
1814 if (skb == NULL)
Pablo Neira Ayuso150ace02009-04-17 17:47:31 +02001815 goto errout;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001816
Marcus Sundbergb633ad52006-02-04 02:11:09 -08001817 type |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001818 nlh = nlmsg_put(skb, item->pid, 0, type, sizeof(*nfmsg), flags);
1819 if (nlh == NULL)
1820 goto nlmsg_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001821
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001822 nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001823 nfmsg->nfgen_family = exp->tuple.src.l3num;
1824 nfmsg->version = NFNETLINK_V0;
1825 nfmsg->res_id = 0;
1826
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001827 rcu_read_lock();
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001828 if (ctnetlink_exp_dump_expect(skb, exp) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07001829 goto nla_put_failure;
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001830 rcu_read_unlock();
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001831
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001832 nlmsg_end(skb, nlh);
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02001833 nfnetlink_send(skb, net, item->pid, group, item->report, GFP_ATOMIC);
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02001834 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001835
Patrick McHardydf6fb862007-09-28 14:37:03 -07001836nla_put_failure:
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001837 rcu_read_unlock();
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001838 nlmsg_cancel(skb, nlh);
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001839nlmsg_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001840 kfree_skb(skb);
Pablo Neira Ayuso150ace02009-04-17 17:47:31 +02001841errout:
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01001842 nfnetlink_set_err(net, 0, 0, -ENOBUFS);
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02001843 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001844}
1845#endif
Patrick McHardycf6994c2007-07-07 22:32:34 -07001846static int ctnetlink_exp_done(struct netlink_callback *cb)
1847{
Patrick McHardy31f15872007-07-07 22:35:21 -07001848 if (cb->args[1])
1849 nf_ct_expect_put((struct nf_conntrack_expect *)cb->args[1]);
Patrick McHardycf6994c2007-07-07 22:32:34 -07001850 return 0;
1851}
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001852
1853static int
1854ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
1855{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01001856 struct net *net = sock_net(skb->sk);
Patrick McHardycf6994c2007-07-07 22:32:34 -07001857 struct nf_conntrack_expect *exp, *last;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001858 struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
Patrick McHardy31f15872007-07-07 22:35:21 -07001859 struct hlist_node *n;
Pablo Neira Ayuso87711cb2006-01-05 12:19:23 -08001860 u_int8_t l3proto = nfmsg->nfgen_family;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001861
Patrick McHardy7d0742d2008-01-31 04:38:19 -08001862 rcu_read_lock();
Patrick McHardy31f15872007-07-07 22:35:21 -07001863 last = (struct nf_conntrack_expect *)cb->args[1];
1864 for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
Patrick McHardycf6994c2007-07-07 22:32:34 -07001865restart:
Alexey Dobriyan9b03f382008-10-08 11:35:03 +02001866 hlist_for_each_entry(exp, n, &net->ct.expect_hash[cb->args[0]],
Patrick McHardy31f15872007-07-07 22:35:21 -07001867 hnode) {
1868 if (l3proto && exp->tuple.src.l3num != l3proto)
Patrick McHardycf6994c2007-07-07 22:32:34 -07001869 continue;
Patrick McHardy31f15872007-07-07 22:35:21 -07001870 if (cb->args[1]) {
1871 if (exp != last)
1872 continue;
1873 cb->args[1] = 0;
1874 }
Pablo Neira Ayuso8b0a2312009-06-02 20:03:34 +02001875 if (ctnetlink_exp_fill_info(skb,
1876 NETLINK_CB(cb->skb).pid,
Patrick McHardy31f15872007-07-07 22:35:21 -07001877 cb->nlh->nlmsg_seq,
1878 IPCTNL_MSG_EXP_NEW,
Pablo Neira Ayuso8b0a2312009-06-02 20:03:34 +02001879 exp) < 0) {
Patrick McHardy7d0742d2008-01-31 04:38:19 -08001880 if (!atomic_inc_not_zero(&exp->use))
1881 continue;
Patrick McHardy31f15872007-07-07 22:35:21 -07001882 cb->args[1] = (unsigned long)exp;
1883 goto out;
1884 }
Patrick McHardycf6994c2007-07-07 22:32:34 -07001885 }
Patrick McHardy31f15872007-07-07 22:35:21 -07001886 if (cb->args[1]) {
1887 cb->args[1] = 0;
1888 goto restart;
Patrick McHardycf6994c2007-07-07 22:32:34 -07001889 }
1890 }
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001891out:
Patrick McHardy7d0742d2008-01-31 04:38:19 -08001892 rcu_read_unlock();
Patrick McHardycf6994c2007-07-07 22:32:34 -07001893 if (last)
1894 nf_ct_expect_put(last);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001895
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001896 return skb->len;
1897}
1898
Patrick McHardyf73e9242007-09-28 14:39:55 -07001899static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
Patrick McHardyd0b02682010-02-10 15:38:33 +01001900 [CTA_EXPECT_MASTER] = { .type = NLA_NESTED },
1901 [CTA_EXPECT_TUPLE] = { .type = NLA_NESTED },
1902 [CTA_EXPECT_MASK] = { .type = NLA_NESTED },
Patrick McHardyf73e9242007-09-28 14:39:55 -07001903 [CTA_EXPECT_TIMEOUT] = { .type = NLA_U32 },
1904 [CTA_EXPECT_ID] = { .type = NLA_U32 },
Patrick McHardyd0b02682010-02-10 15:38:33 +01001905 [CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING },
Pablo Neira Ayusobcac0df2010-09-22 08:35:36 +02001906 [CTA_EXPECT_ZONE] = { .type = NLA_U16 },
Pablo Neira Ayuso8b008fa2010-09-22 08:36:59 +02001907 [CTA_EXPECT_FLAGS] = { .type = NLA_U32 },
Pablo Neira Ayusob8c5e522012-02-05 03:21:12 +01001908 [CTA_EXPECT_CLASS] = { .type = NLA_U32 },
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01001909 [CTA_EXPECT_NAT] = { .type = NLA_NESTED },
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +01001910 [CTA_EXPECT_FN] = { .type = NLA_NUL_STRING },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001911};
1912
1913static int
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001914ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
Patrick McHardy39938322009-08-25 16:07:58 +02001915 const struct nlmsghdr *nlh,
1916 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001917{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01001918 struct net *net = sock_net(ctnl);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001919 struct nf_conntrack_tuple tuple;
1920 struct nf_conntrack_expect *exp;
1921 struct sk_buff *skb2;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001922 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001923 u_int8_t u3 = nfmsg->nfgen_family;
Patrick McHardyef00f892010-02-15 18:14:57 +01001924 u16 zone;
1925 int err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001926
David S. Millerb8f3ab42011-01-18 12:40:38 -08001927 if (nlh->nlmsg_flags & NLM_F_DUMP) {
Pablo Neira Ayuso80d326f2012-02-24 14:30:15 +00001928 struct netlink_dump_control c = {
1929 .dump = ctnetlink_exp_dump_table,
1930 .done = ctnetlink_exp_done,
1931 };
1932 return netlink_dump_start(ctnl, skb, nlh, &c);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001933 }
1934
Patrick McHardyef00f892010-02-15 18:14:57 +01001935 err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
1936 if (err < 0)
1937 return err;
1938
Pablo Neira Ayuso35dba1d2011-12-14 12:45:22 +01001939 if (cda[CTA_EXPECT_TUPLE])
1940 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
1941 else if (cda[CTA_EXPECT_MASTER])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001942 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER, u3);
1943 else
1944 return -EINVAL;
1945
1946 if (err < 0)
1947 return err;
1948
Patrick McHardyef00f892010-02-15 18:14:57 +01001949 exp = nf_ct_expect_find_get(net, zone, &tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001950 if (!exp)
1951 return -ENOENT;
1952
Patrick McHardydf6fb862007-09-28 14:37:03 -07001953 if (cda[CTA_EXPECT_ID]) {
Patrick McHardy77236b62007-12-17 22:29:45 -08001954 __be32 id = nla_get_be32(cda[CTA_EXPECT_ID]);
Patrick McHardy35832402007-09-28 14:41:50 -07001955 if (ntohl(id) != (u32)(unsigned long)exp) {
Patrick McHardy68236452007-07-07 22:30:49 -07001956 nf_ct_expect_put(exp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001957 return -ENOENT;
1958 }
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001959 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001960
1961 err = -ENOMEM;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001962 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01001963 if (skb2 == NULL) {
1964 nf_ct_expect_put(exp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001965 goto out;
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01001966 }
Thomas Graf4e9b8262006-11-27 09:25:58 -08001967
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001968 rcu_read_lock();
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001969 err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid,
Pablo Neira Ayuso8b0a2312009-06-02 20:03:34 +02001970 nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, exp);
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001971 rcu_read_unlock();
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01001972 nf_ct_expect_put(exp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001973 if (err <= 0)
1974 goto free;
1975
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01001976 err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
1977 if (err < 0)
1978 goto out;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001979
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01001980 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001981
1982free:
1983 kfree_skb(skb2);
1984out:
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01001985 /* this avoids a loop in nfnetlink. */
1986 return err == -EAGAIN ? -ENOBUFS : err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001987}
1988
1989static int
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001990ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
Patrick McHardy39938322009-08-25 16:07:58 +02001991 const struct nlmsghdr *nlh,
1992 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001993{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01001994 struct net *net = sock_net(ctnl);
Patrick McHardy31f15872007-07-07 22:35:21 -07001995 struct nf_conntrack_expect *exp;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001996 struct nf_conntrack_tuple tuple;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001997 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Patrick McHardy31f15872007-07-07 22:35:21 -07001998 struct hlist_node *n, *next;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001999 u_int8_t u3 = nfmsg->nfgen_family;
Patrick McHardy31f15872007-07-07 22:35:21 -07002000 unsigned int i;
Patrick McHardyef00f892010-02-15 18:14:57 +01002001 u16 zone;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002002 int err;
2003
Patrick McHardydf6fb862007-09-28 14:37:03 -07002004 if (cda[CTA_EXPECT_TUPLE]) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002005 /* delete a single expect by tuple */
Patrick McHardyef00f892010-02-15 18:14:57 +01002006 err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
2007 if (err < 0)
2008 return err;
2009
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002010 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
2011 if (err < 0)
2012 return err;
2013
2014 /* bump usage count to 2 */
Patrick McHardyef00f892010-02-15 18:14:57 +01002015 exp = nf_ct_expect_find_get(net, zone, &tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002016 if (!exp)
2017 return -ENOENT;
2018
Patrick McHardydf6fb862007-09-28 14:37:03 -07002019 if (cda[CTA_EXPECT_ID]) {
Patrick McHardy77236b62007-12-17 22:29:45 -08002020 __be32 id = nla_get_be32(cda[CTA_EXPECT_ID]);
Patrick McHardy35832402007-09-28 14:41:50 -07002021 if (ntohl(id) != (u32)(unsigned long)exp) {
Patrick McHardy68236452007-07-07 22:30:49 -07002022 nf_ct_expect_put(exp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002023 return -ENOENT;
2024 }
2025 }
2026
2027 /* after list removal, usage count == 1 */
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002028 spin_lock_bh(&nf_conntrack_lock);
2029 if (del_timer(&exp->timeout)) {
2030 nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).pid,
2031 nlmsg_report(nlh));
2032 nf_ct_expect_put(exp);
2033 }
2034 spin_unlock_bh(&nf_conntrack_lock);
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002035 /* have to put what we 'get' above.
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002036 * after this line usage count == 0 */
Patrick McHardy68236452007-07-07 22:30:49 -07002037 nf_ct_expect_put(exp);
Patrick McHardydf6fb862007-09-28 14:37:03 -07002038 } else if (cda[CTA_EXPECT_HELP_NAME]) {
2039 char *name = nla_data(cda[CTA_EXPECT_HELP_NAME]);
Patrick McHardy31f15872007-07-07 22:35:21 -07002040 struct nf_conn_help *m_help;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002041
2042 /* delete all expectations for this helper */
Patrick McHardyf8ba1af2008-01-31 04:38:58 -08002043 spin_lock_bh(&nf_conntrack_lock);
Patrick McHardy31f15872007-07-07 22:35:21 -07002044 for (i = 0; i < nf_ct_expect_hsize; i++) {
2045 hlist_for_each_entry_safe(exp, n, next,
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01002046 &net->ct.expect_hash[i],
Patrick McHardy31f15872007-07-07 22:35:21 -07002047 hnode) {
2048 m_help = nfct_help(exp->master);
Patrick McHardy794e6872010-02-03 13:41:29 +01002049 if (!strcmp(m_help->helper->name, name) &&
2050 del_timer(&exp->timeout)) {
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002051 nf_ct_unlink_expect_report(exp,
2052 NETLINK_CB(skb).pid,
2053 nlmsg_report(nlh));
Patrick McHardy31f15872007-07-07 22:35:21 -07002054 nf_ct_expect_put(exp);
2055 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002056 }
2057 }
Patrick McHardyf8ba1af2008-01-31 04:38:58 -08002058 spin_unlock_bh(&nf_conntrack_lock);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002059 } else {
2060 /* This basically means we have to flush everything*/
Patrick McHardyf8ba1af2008-01-31 04:38:58 -08002061 spin_lock_bh(&nf_conntrack_lock);
Patrick McHardy31f15872007-07-07 22:35:21 -07002062 for (i = 0; i < nf_ct_expect_hsize; i++) {
2063 hlist_for_each_entry_safe(exp, n, next,
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01002064 &net->ct.expect_hash[i],
Patrick McHardy31f15872007-07-07 22:35:21 -07002065 hnode) {
2066 if (del_timer(&exp->timeout)) {
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002067 nf_ct_unlink_expect_report(exp,
2068 NETLINK_CB(skb).pid,
2069 nlmsg_report(nlh));
Patrick McHardy31f15872007-07-07 22:35:21 -07002070 nf_ct_expect_put(exp);
2071 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002072 }
2073 }
Patrick McHardyf8ba1af2008-01-31 04:38:58 -08002074 spin_unlock_bh(&nf_conntrack_lock);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002075 }
2076
2077 return 0;
2078}
2079static int
Patrick McHardy39938322009-08-25 16:07:58 +02002080ctnetlink_change_expect(struct nf_conntrack_expect *x,
2081 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002082{
Kelvie Wong9768e1a2012-05-02 14:39:24 +00002083 if (cda[CTA_EXPECT_TIMEOUT]) {
2084 if (!del_timer(&x->timeout))
2085 return -ETIME;
2086
2087 x->timeout.expires = jiffies +
2088 ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ;
2089 add_timer(&x->timeout);
2090 }
2091 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002092}
2093
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002094static const struct nla_policy exp_nat_nla_policy[CTA_EXPECT_NAT_MAX+1] = {
2095 [CTA_EXPECT_NAT_DIR] = { .type = NLA_U32 },
2096 [CTA_EXPECT_NAT_TUPLE] = { .type = NLA_NESTED },
2097};
2098
2099static int
2100ctnetlink_parse_expect_nat(const struct nlattr *attr,
2101 struct nf_conntrack_expect *exp,
2102 u_int8_t u3)
2103{
2104#ifdef CONFIG_NF_NAT_NEEDED
2105 struct nlattr *tb[CTA_EXPECT_NAT_MAX+1];
2106 struct nf_conntrack_tuple nat_tuple = {};
2107 int err;
2108
2109 nla_parse_nested(tb, CTA_EXPECT_NAT_MAX, attr, exp_nat_nla_policy);
2110
2111 if (!tb[CTA_EXPECT_NAT_DIR] || !tb[CTA_EXPECT_NAT_TUPLE])
2112 return -EINVAL;
2113
2114 err = ctnetlink_parse_tuple((const struct nlattr * const *)tb,
2115 &nat_tuple, CTA_EXPECT_NAT_TUPLE, u3);
2116 if (err < 0)
2117 return err;
2118
2119 exp->saved_ip = nat_tuple.src.u3.ip;
2120 exp->saved_proto = nat_tuple.src.u;
2121 exp->dir = ntohl(nla_get_be32(tb[CTA_EXPECT_NAT_DIR]));
2122
2123 return 0;
2124#else
2125 return -EOPNOTSUPP;
2126#endif
2127}
2128
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002129static int
Patrick McHardyef00f892010-02-15 18:14:57 +01002130ctnetlink_create_expect(struct net *net, u16 zone,
2131 const struct nlattr * const cda[],
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01002132 u_int8_t u3,
Patrick McHardy39938322009-08-25 16:07:58 +02002133 u32 pid, int report)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002134{
2135 struct nf_conntrack_tuple tuple, mask, master_tuple;
2136 struct nf_conntrack_tuple_hash *h = NULL;
2137 struct nf_conntrack_expect *exp;
2138 struct nf_conn *ct;
Harald Weltedc808fe2006-03-20 17:56:32 -08002139 struct nf_conn_help *help;
Pablo Neira Ayuso660fdb22012-02-05 02:34:16 +01002140 struct nf_conntrack_helper *helper = NULL;
Pablo Neira Ayusob8c5e522012-02-05 03:21:12 +01002141 u_int32_t class = 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002142 int err = 0;
2143
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002144 /* caller guarantees that those three CTA_EXPECT_* exist */
2145 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
2146 if (err < 0)
2147 return err;
2148 err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK, u3);
2149 if (err < 0)
2150 return err;
2151 err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER, u3);
2152 if (err < 0)
2153 return err;
2154
2155 /* Look for master conntrack of this expectation */
Patrick McHardyef00f892010-02-15 18:14:57 +01002156 h = nf_conntrack_find_get(net, zone, &master_tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002157 if (!h)
2158 return -ENOENT;
2159 ct = nf_ct_tuplehash_to_ctrack(h);
Pablo Neira Ayuso660fdb22012-02-05 02:34:16 +01002160
2161 /* Look for helper of this expectation */
2162 if (cda[CTA_EXPECT_HELP_NAME]) {
2163 const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
2164
2165 helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
2166 nf_ct_protonum(ct));
2167 if (helper == NULL) {
2168#ifdef CONFIG_MODULES
2169 if (request_module("nfct-helper-%s", helpname) < 0) {
2170 err = -EOPNOTSUPP;
2171 goto out;
2172 }
2173
2174 helper = __nf_conntrack_helper_find(helpname,
2175 nf_ct_l3num(ct),
2176 nf_ct_protonum(ct));
2177 if (helper) {
2178 err = -EAGAIN;
2179 goto out;
2180 }
2181#endif
2182 err = -EOPNOTSUPP;
2183 goto out;
2184 }
2185 }
2186
Pablo Neira Ayusob8c5e522012-02-05 03:21:12 +01002187 if (cda[CTA_EXPECT_CLASS] && helper) {
2188 class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS]));
2189 if (class > helper->expect_class_max) {
2190 err = -EINVAL;
2191 goto out;
2192 }
2193 }
Patrick McHardy68236452007-07-07 22:30:49 -07002194 exp = nf_ct_expect_alloc(ct);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002195 if (!exp) {
2196 err = -ENOMEM;
2197 goto out;
2198 }
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02002199 help = nfct_help(ct);
2200 if (!help) {
2201 if (!cda[CTA_EXPECT_TIMEOUT]) {
2202 err = -EINVAL;
2203 goto out;
2204 }
2205 exp->timeout.expires =
2206 jiffies + ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002207
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02002208 exp->flags = NF_CT_EXPECT_USERSPACE;
2209 if (cda[CTA_EXPECT_FLAGS]) {
2210 exp->flags |=
2211 ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS]));
2212 }
2213 } else {
2214 if (cda[CTA_EXPECT_FLAGS]) {
2215 exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS]));
2216 exp->flags &= ~NF_CT_EXPECT_USERSPACE;
2217 } else
2218 exp->flags = 0;
2219 }
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +01002220 if (cda[CTA_EXPECT_FN]) {
2221 const char *name = nla_data(cda[CTA_EXPECT_FN]);
2222 struct nf_ct_helper_expectfn *expfn;
2223
2224 expfn = nf_ct_helper_expectfn_find_by_name(name);
2225 if (expfn == NULL) {
2226 err = -EINVAL;
2227 goto err_out;
2228 }
2229 exp->expectfn = expfn->expectfn;
2230 } else
2231 exp->expectfn = NULL;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002232
Pablo Neira Ayusob8c5e522012-02-05 03:21:12 +01002233 exp->class = class;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002234 exp->master = ct;
Pablo Neira Ayuso660fdb22012-02-05 02:34:16 +01002235 exp->helper = helper;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002236 memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple));
Patrick McHardyd4156e82007-07-07 22:31:32 -07002237 memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3));
2238 exp->mask.src.u.all = mask.src.u.all;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002239
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002240 if (cda[CTA_EXPECT_NAT]) {
2241 err = ctnetlink_parse_expect_nat(cda[CTA_EXPECT_NAT],
2242 exp, u3);
2243 if (err < 0)
2244 goto err_out;
2245 }
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +01002246 err = nf_ct_expect_related_report(exp, pid, report);
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002247err_out:
Patrick McHardy68236452007-07-07 22:30:49 -07002248 nf_ct_expect_put(exp);
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002249out:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002250 nf_ct_put(nf_ct_tuplehash_to_ctrack(h));
2251 return err;
2252}
2253
2254static int
2255ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
Patrick McHardy39938322009-08-25 16:07:58 +02002256 const struct nlmsghdr *nlh,
2257 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002258{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01002259 struct net *net = sock_net(ctnl);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002260 struct nf_conntrack_tuple tuple;
2261 struct nf_conntrack_expect *exp;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002262 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002263 u_int8_t u3 = nfmsg->nfgen_family;
Patrick McHardyef00f892010-02-15 18:14:57 +01002264 u16 zone;
2265 int err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002266
Patrick McHardydf6fb862007-09-28 14:37:03 -07002267 if (!cda[CTA_EXPECT_TUPLE]
2268 || !cda[CTA_EXPECT_MASK]
2269 || !cda[CTA_EXPECT_MASTER])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002270 return -EINVAL;
2271
Patrick McHardyef00f892010-02-15 18:14:57 +01002272 err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
2273 if (err < 0)
2274 return err;
2275
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002276 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
2277 if (err < 0)
2278 return err;
2279
Patrick McHardyf8ba1af2008-01-31 04:38:58 -08002280 spin_lock_bh(&nf_conntrack_lock);
Patrick McHardyef00f892010-02-15 18:14:57 +01002281 exp = __nf_ct_expect_find(net, zone, &tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002282
2283 if (!exp) {
Patrick McHardyf8ba1af2008-01-31 04:38:58 -08002284 spin_unlock_bh(&nf_conntrack_lock);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002285 err = -ENOENT;
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +01002286 if (nlh->nlmsg_flags & NLM_F_CREATE) {
Patrick McHardyef00f892010-02-15 18:14:57 +01002287 err = ctnetlink_create_expect(net, zone, cda,
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +01002288 u3,
2289 NETLINK_CB(skb).pid,
2290 nlmsg_report(nlh));
2291 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002292 return err;
2293 }
2294
2295 err = -EEXIST;
2296 if (!(nlh->nlmsg_flags & NLM_F_EXCL))
2297 err = ctnetlink_change_expect(exp, cda);
Patrick McHardyf8ba1af2008-01-31 04:38:58 -08002298 spin_unlock_bh(&nf_conntrack_lock);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002299
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002300 return err;
2301}
2302
2303#ifdef CONFIG_NF_CONNTRACK_EVENTS
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02002304static struct nf_ct_event_notifier ctnl_notifier = {
2305 .fcn = ctnetlink_conntrack_event,
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002306};
2307
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02002308static struct nf_exp_event_notifier ctnl_notifier_exp = {
2309 .fcn = ctnetlink_expect_event,
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002310};
2311#endif
2312
Patrick McHardy7c8d4cb2007-09-28 14:15:45 -07002313static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002314 [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack,
Patrick McHardyf73e9242007-09-28 14:39:55 -07002315 .attr_count = CTA_MAX,
2316 .policy = ct_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002317 [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack,
Patrick McHardyf73e9242007-09-28 14:39:55 -07002318 .attr_count = CTA_MAX,
2319 .policy = ct_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002320 [IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack,
Patrick McHardyf73e9242007-09-28 14:39:55 -07002321 .attr_count = CTA_MAX,
2322 .policy = ct_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002323 [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack,
Patrick McHardyf73e9242007-09-28 14:39:55 -07002324 .attr_count = CTA_MAX,
2325 .policy = ct_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002326};
2327
Patrick McHardy7c8d4cb2007-09-28 14:15:45 -07002328static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002329 [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect,
Patrick McHardyf73e9242007-09-28 14:39:55 -07002330 .attr_count = CTA_EXPECT_MAX,
2331 .policy = exp_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002332 [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect,
Patrick McHardyf73e9242007-09-28 14:39:55 -07002333 .attr_count = CTA_EXPECT_MAX,
2334 .policy = exp_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002335 [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect,
Patrick McHardyf73e9242007-09-28 14:39:55 -07002336 .attr_count = CTA_EXPECT_MAX,
2337 .policy = exp_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002338};
2339
Patrick McHardy7c8d4cb2007-09-28 14:15:45 -07002340static const struct nfnetlink_subsystem ctnl_subsys = {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002341 .name = "conntrack",
2342 .subsys_id = NFNL_SUBSYS_CTNETLINK,
2343 .cb_count = IPCTNL_MSG_MAX,
2344 .cb = ctnl_cb,
2345};
2346
Patrick McHardy7c8d4cb2007-09-28 14:15:45 -07002347static const struct nfnetlink_subsystem ctnl_exp_subsys = {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002348 .name = "conntrack_expect",
2349 .subsys_id = NFNL_SUBSYS_CTNETLINK_EXP,
2350 .cb_count = IPCTNL_MSG_EXP_MAX,
2351 .cb = ctnl_exp_cb,
2352};
2353
Patrick McHardyd2483dd2006-12-02 22:06:05 -08002354MODULE_ALIAS("ip_conntrack_netlink");
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002355MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);
Pablo Neira Ayuso34f9a2e2006-02-04 02:11:41 -08002356MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002357
Pablo Neira Ayuso70e99422011-11-22 00:16:51 +01002358static int __net_init ctnetlink_net_init(struct net *net)
2359{
2360#ifdef CONFIG_NF_CONNTRACK_EVENTS
2361 int ret;
2362
2363 ret = nf_conntrack_register_notifier(net, &ctnl_notifier);
2364 if (ret < 0) {
2365 pr_err("ctnetlink_init: cannot register notifier.\n");
2366 goto err_out;
2367 }
2368
2369 ret = nf_ct_expect_register_notifier(net, &ctnl_notifier_exp);
2370 if (ret < 0) {
2371 pr_err("ctnetlink_init: cannot expect register notifier.\n");
2372 goto err_unreg_notifier;
2373 }
2374#endif
2375 return 0;
2376
2377#ifdef CONFIG_NF_CONNTRACK_EVENTS
2378err_unreg_notifier:
2379 nf_conntrack_unregister_notifier(net, &ctnl_notifier);
2380err_out:
2381 return ret;
2382#endif
2383}
2384
2385static void ctnetlink_net_exit(struct net *net)
2386{
2387#ifdef CONFIG_NF_CONNTRACK_EVENTS
2388 nf_ct_expect_unregister_notifier(net, &ctnl_notifier_exp);
2389 nf_conntrack_unregister_notifier(net, &ctnl_notifier);
2390#endif
2391}
2392
2393static void __net_exit ctnetlink_net_exit_batch(struct list_head *net_exit_list)
2394{
2395 struct net *net;
2396
2397 list_for_each_entry(net, net_exit_list, exit_list)
2398 ctnetlink_net_exit(net);
2399}
2400
2401static struct pernet_operations ctnetlink_net_ops = {
2402 .init = ctnetlink_net_init,
2403 .exit_batch = ctnetlink_net_exit_batch,
2404};
2405
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002406static int __init ctnetlink_init(void)
2407{
2408 int ret;
2409
Stephen Hemminger654d0fb2010-05-13 15:02:08 +02002410 pr_info("ctnetlink v%s: registering with nfnetlink.\n", version);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002411 ret = nfnetlink_subsys_register(&ctnl_subsys);
2412 if (ret < 0) {
Stephen Hemminger654d0fb2010-05-13 15:02:08 +02002413 pr_err("ctnetlink_init: cannot register with nfnetlink.\n");
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002414 goto err_out;
2415 }
2416
2417 ret = nfnetlink_subsys_register(&ctnl_exp_subsys);
2418 if (ret < 0) {
Stephen Hemminger654d0fb2010-05-13 15:02:08 +02002419 pr_err("ctnetlink_init: cannot register exp with nfnetlink.\n");
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002420 goto err_unreg_subsys;
2421 }
2422
Pablo Neira Ayuso70e99422011-11-22 00:16:51 +01002423 if (register_pernet_subsys(&ctnetlink_net_ops)) {
2424 pr_err("ctnetlink_init: cannot register pernet operations\n");
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002425 goto err_unreg_exp_subsys;
2426 }
2427
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002428 return 0;
2429
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002430err_unreg_exp_subsys:
2431 nfnetlink_subsys_unregister(&ctnl_exp_subsys);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002432err_unreg_subsys:
2433 nfnetlink_subsys_unregister(&ctnl_subsys);
2434err_out:
2435 return ret;
2436}
2437
2438static void __exit ctnetlink_exit(void)
2439{
Stephen Hemminger654d0fb2010-05-13 15:02:08 +02002440 pr_info("ctnetlink: unregistering from nfnetlink.\n");
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002441
Pablo Neira Ayuso70e99422011-11-22 00:16:51 +01002442 unregister_pernet_subsys(&ctnetlink_net_ops);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002443 nfnetlink_subsys_unregister(&ctnl_exp_subsys);
2444 nfnetlink_subsys_unregister(&ctnl_subsys);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002445}
2446
2447module_init(ctnetlink_init);
2448module_exit(ctnetlink_exit);