blob: d304d5917950701f8ee6992f00f13e2a9cb0223a [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 */
Pablo Neira Ayuso1afc5672012-06-07 12:11:50 +02001221 memset(help->data, 0, help->helper->data_len);
Yasuyuki Kozakaiceceae12007-07-07 22:23:42 -07001222 } 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
Pablo Neira Ayuso1afc5672012-06-07 12:11:50 +02001443 help = nf_ct_helper_ext_add(ct, helper, GFP_ATOMIC);
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001444 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
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02001623#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || \
1624 defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE)
1625static size_t
1626ctnetlink_nfqueue_build_size(const struct nf_conn *ct)
1627{
1628 return 3 * nla_total_size(0) /* CTA_TUPLE_ORIG|REPL|MASTER */
1629 + 3 * nla_total_size(0) /* CTA_TUPLE_IP */
1630 + 3 * nla_total_size(0) /* CTA_TUPLE_PROTO */
1631 + 3 * nla_total_size(sizeof(u_int8_t)) /* CTA_PROTO_NUM */
1632 + nla_total_size(sizeof(u_int32_t)) /* CTA_ID */
1633 + nla_total_size(sizeof(u_int32_t)) /* CTA_STATUS */
1634 + nla_total_size(sizeof(u_int32_t)) /* CTA_TIMEOUT */
1635 + nla_total_size(0) /* CTA_PROTOINFO */
1636 + nla_total_size(0) /* CTA_HELP */
1637 + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */
1638 + ctnetlink_secctx_size(ct)
1639#ifdef CONFIG_NF_NAT_NEEDED
1640 + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */
1641 + 6 * nla_total_size(sizeof(u_int32_t)) /* CTA_NAT_SEQ_OFFSET */
1642#endif
1643#ifdef CONFIG_NF_CONNTRACK_MARK
1644 + nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */
1645#endif
1646 + ctnetlink_proto_size(ct)
1647 ;
1648}
1649
1650static int
1651ctnetlink_nfqueue_build(struct sk_buff *skb, struct nf_conn *ct)
1652{
1653 struct nlattr *nest_parms;
1654
1655 rcu_read_lock();
1656 nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED);
1657 if (!nest_parms)
1658 goto nla_put_failure;
1659 if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
1660 goto nla_put_failure;
1661 nla_nest_end(skb, nest_parms);
1662
1663 nest_parms = nla_nest_start(skb, CTA_TUPLE_REPLY | NLA_F_NESTED);
1664 if (!nest_parms)
1665 goto nla_put_failure;
1666 if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_REPLY)) < 0)
1667 goto nla_put_failure;
1668 nla_nest_end(skb, nest_parms);
1669
1670 if (nf_ct_zone(ct)) {
1671 if (nla_put_be16(skb, CTA_ZONE, htons(nf_ct_zone(ct))))
1672 goto nla_put_failure;
1673 }
1674
1675 if (ctnetlink_dump_id(skb, ct) < 0)
1676 goto nla_put_failure;
1677
1678 if (ctnetlink_dump_status(skb, ct) < 0)
1679 goto nla_put_failure;
1680
1681 if (ctnetlink_dump_timeout(skb, ct) < 0)
1682 goto nla_put_failure;
1683
1684 if (ctnetlink_dump_protoinfo(skb, ct) < 0)
1685 goto nla_put_failure;
1686
1687 if (ctnetlink_dump_helpinfo(skb, ct) < 0)
1688 goto nla_put_failure;
1689
1690#ifdef CONFIG_NF_CONNTRACK_SECMARK
1691 if (ct->secmark && ctnetlink_dump_secctx(skb, ct) < 0)
1692 goto nla_put_failure;
1693#endif
1694 if (ct->master && ctnetlink_dump_master(skb, ct) < 0)
1695 goto nla_put_failure;
1696
1697 if ((ct->status & IPS_SEQ_ADJUST) &&
1698 ctnetlink_dump_nat_seq_adj(skb, ct) < 0)
1699 goto nla_put_failure;
1700
1701#ifdef CONFIG_NF_CONNTRACK_MARK
1702 if (ct->mark && ctnetlink_dump_mark(skb, ct) < 0)
1703 goto nla_put_failure;
1704#endif
1705 rcu_read_unlock();
1706 return 0;
1707
1708nla_put_failure:
1709 rcu_read_unlock();
1710 return -ENOSPC;
1711}
1712
1713static int
1714ctnetlink_nfqueue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
1715{
1716 int err;
1717
1718 if (cda[CTA_TIMEOUT]) {
1719 err = ctnetlink_change_timeout(ct, cda);
1720 if (err < 0)
1721 return err;
1722 }
1723 if (cda[CTA_STATUS]) {
1724 err = ctnetlink_change_status(ct, cda);
1725 if (err < 0)
1726 return err;
1727 }
1728 if (cda[CTA_HELP]) {
1729 err = ctnetlink_change_helper(ct, cda);
1730 if (err < 0)
1731 return err;
1732 }
1733#if defined(CONFIG_NF_CONNTRACK_MARK)
1734 if (cda[CTA_MARK])
1735 ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
1736#endif
1737 return 0;
1738}
1739
1740static int
1741ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct)
1742{
1743 struct nlattr *cda[CTA_MAX+1];
1744
1745 nla_parse_nested(cda, CTA_MAX, attr, ct_nla_policy);
1746
1747 return ctnetlink_nfqueue_parse_ct((const struct nlattr **)cda, ct);
1748}
1749
1750static struct nfq_ct_hook ctnetlink_nfqueue_hook = {
1751 .build_size = ctnetlink_nfqueue_build_size,
1752 .build = ctnetlink_nfqueue_build,
1753 .parse = ctnetlink_nfqueue_parse,
1754};
1755#endif /* CONFIG_NETFILTER_NETLINK_QUEUE */
1756
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001757/***********************************************************************
1758 * EXPECT
1759 ***********************************************************************/
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001760
1761static inline int
1762ctnetlink_exp_dump_tuple(struct sk_buff *skb,
1763 const struct nf_conntrack_tuple *tuple,
1764 enum ctattr_expect type)
1765{
Patrick McHardydf6fb862007-09-28 14:37:03 -07001766 struct nlattr *nest_parms;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001767
Patrick McHardydf6fb862007-09-28 14:37:03 -07001768 nest_parms = nla_nest_start(skb, type | NLA_F_NESTED);
1769 if (!nest_parms)
1770 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001771 if (ctnetlink_dump_tuples(skb, tuple) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07001772 goto nla_put_failure;
1773 nla_nest_end(skb, nest_parms);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001774
1775 return 0;
1776
Patrick McHardydf6fb862007-09-28 14:37:03 -07001777nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001778 return -1;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001779}
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001780
1781static inline int
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001782ctnetlink_exp_dump_mask(struct sk_buff *skb,
1783 const struct nf_conntrack_tuple *tuple,
Patrick McHardyd4156e82007-07-07 22:31:32 -07001784 const struct nf_conntrack_tuple_mask *mask)
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001785{
1786 int ret;
1787 struct nf_conntrack_l3proto *l3proto;
Martin Josefsson605dcad2006-11-29 02:35:06 +01001788 struct nf_conntrack_l4proto *l4proto;
Patrick McHardyd4156e82007-07-07 22:31:32 -07001789 struct nf_conntrack_tuple m;
Patrick McHardydf6fb862007-09-28 14:37:03 -07001790 struct nlattr *nest_parms;
Patrick McHardyd4156e82007-07-07 22:31:32 -07001791
1792 memset(&m, 0xFF, sizeof(m));
Patrick McHardyd4156e82007-07-07 22:31:32 -07001793 memcpy(&m.src.u3, &mask->src.u3, sizeof(m.src.u3));
Patrick McHardye5787562010-01-26 17:04:02 +01001794 m.src.u.all = mask->src.u.all;
1795 m.dst.protonum = tuple->dst.protonum;
Patrick McHardyd4156e82007-07-07 22:31:32 -07001796
Patrick McHardydf6fb862007-09-28 14:37:03 -07001797 nest_parms = nla_nest_start(skb, CTA_EXPECT_MASK | NLA_F_NESTED);
1798 if (!nest_parms)
1799 goto nla_put_failure;
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001800
Hans Schillstrom3b988ec2012-03-05 02:24:29 +00001801 rcu_read_lock();
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001802 l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
Patrick McHardyd4156e82007-07-07 22:31:32 -07001803 ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto);
Hans Schillstrom3b988ec2012-03-05 02:24:29 +00001804 if (ret >= 0) {
1805 l4proto = __nf_ct_l4proto_find(tuple->src.l3num,
1806 tuple->dst.protonum);
Patrick McHardyd4156e82007-07-07 22:31:32 -07001807 ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto);
Hans Schillstrom3b988ec2012-03-05 02:24:29 +00001808 }
1809 rcu_read_unlock();
1810
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001811 if (unlikely(ret < 0))
Patrick McHardydf6fb862007-09-28 14:37:03 -07001812 goto nla_put_failure;
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001813
Patrick McHardydf6fb862007-09-28 14:37:03 -07001814 nla_nest_end(skb, nest_parms);
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001815
1816 return 0;
1817
Patrick McHardydf6fb862007-09-28 14:37:03 -07001818nla_put_failure:
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001819 return -1;
1820}
1821
Ilpo Järvinenbb5cf802008-01-05 23:11:31 -08001822static int
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001823ctnetlink_exp_dump_expect(struct sk_buff *skb,
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001824 const struct nf_conntrack_expect *exp)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001825{
1826 struct nf_conn *master = exp->master;
Xi Wangc1216382011-12-30 10:40:17 -05001827 long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ;
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02001828 struct nf_conn_help *help;
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01001829#ifdef CONFIG_NF_NAT_NEEDED
1830 struct nlattr *nest_parms;
1831 struct nf_conntrack_tuple nat_tuple = {};
1832#endif
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +01001833 struct nf_ct_helper_expectfn *expfn;
1834
Patrick McHardyd978e5d2007-12-17 22:37:03 -08001835 if (timeout < 0)
1836 timeout = 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001837
1838 if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07001839 goto nla_put_failure;
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08001840 if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07001841 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001842 if (ctnetlink_exp_dump_tuple(skb,
1843 &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
1844 CTA_EXPECT_MASTER) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07001845 goto nla_put_failure;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001846
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01001847#ifdef CONFIG_NF_NAT_NEEDED
1848 if (exp->saved_ip || exp->saved_proto.all) {
1849 nest_parms = nla_nest_start(skb, CTA_EXPECT_NAT | NLA_F_NESTED);
1850 if (!nest_parms)
1851 goto nla_put_failure;
1852
David S. Millercc1eb432012-04-01 18:57:48 -04001853 if (nla_put_be32(skb, CTA_EXPECT_NAT_DIR, htonl(exp->dir)))
1854 goto nla_put_failure;
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01001855
1856 nat_tuple.src.l3num = nf_ct_l3num(master);
1857 nat_tuple.src.u3.ip = exp->saved_ip;
1858 nat_tuple.dst.protonum = nf_ct_protonum(master);
1859 nat_tuple.src.u = exp->saved_proto;
1860
1861 if (ctnetlink_exp_dump_tuple(skb, &nat_tuple,
1862 CTA_EXPECT_NAT_TUPLE) < 0)
1863 goto nla_put_failure;
1864 nla_nest_end(skb, nest_parms);
1865 }
1866#endif
David S. Millercc1eb432012-04-01 18:57:48 -04001867 if (nla_put_be32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)) ||
1868 nla_put_be32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)) ||
1869 nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) ||
1870 nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class)))
1871 goto nla_put_failure;
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02001872 help = nfct_help(master);
1873 if (help) {
1874 struct nf_conntrack_helper *helper;
1875
1876 helper = rcu_dereference(help->helper);
David S. Millercc1eb432012-04-01 18:57:48 -04001877 if (helper &&
1878 nla_put_string(skb, CTA_EXPECT_HELP_NAME, helper->name))
1879 goto nla_put_failure;
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02001880 }
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +01001881 expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn);
David S. Millercc1eb432012-04-01 18:57:48 -04001882 if (expfn != NULL &&
1883 nla_put_string(skb, CTA_EXPECT_FN, expfn->name))
1884 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001885
1886 return 0;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001887
Patrick McHardydf6fb862007-09-28 14:37:03 -07001888nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001889 return -1;
1890}
1891
1892static int
1893ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
Pablo Neira Ayuso8b0a2312009-06-02 20:03:34 +02001894 int event, const struct nf_conntrack_expect *exp)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001895{
1896 struct nlmsghdr *nlh;
1897 struct nfgenmsg *nfmsg;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001898 unsigned int flags = pid ? NLM_F_MULTI : 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001899
1900 event |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001901 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags);
1902 if (nlh == NULL)
1903 goto nlmsg_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001904
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001905 nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001906 nfmsg->nfgen_family = exp->tuple.src.l3num;
1907 nfmsg->version = NFNETLINK_V0;
1908 nfmsg->res_id = 0;
1909
1910 if (ctnetlink_exp_dump_expect(skb, exp) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07001911 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001912
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001913 nlmsg_end(skb, nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001914 return skb->len;
1915
1916nlmsg_failure:
Patrick McHardydf6fb862007-09-28 14:37:03 -07001917nla_put_failure:
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001918 nlmsg_cancel(skb, nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001919 return -1;
1920}
1921
1922#ifdef CONFIG_NF_CONNTRACK_EVENTS
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02001923static int
1924ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001925{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01001926 struct nf_conntrack_expect *exp = item->exp;
1927 struct net *net = nf_ct_exp_net(exp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001928 struct nlmsghdr *nlh;
1929 struct nfgenmsg *nfmsg;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001930 struct sk_buff *skb;
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02001931 unsigned int type, group;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001932 int flags = 0;
1933
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02001934 if (events & (1 << IPEXP_DESTROY)) {
1935 type = IPCTNL_MSG_EXP_DELETE;
1936 group = NFNLGRP_CONNTRACK_EXP_DESTROY;
1937 } else if (events & (1 << IPEXP_NEW)) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001938 type = IPCTNL_MSG_EXP_NEW;
1939 flags = NLM_F_CREATE|NLM_F_EXCL;
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02001940 group = NFNLGRP_CONNTRACK_EXP_NEW;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001941 } else
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02001942 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001943
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02001944 if (!item->report && !nfnetlink_has_listeners(net, group))
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02001945 return 0;
Pablo Neira Ayusob3a27bf2006-08-22 00:32:05 -07001946
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001947 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
1948 if (skb == NULL)
Pablo Neira Ayuso150ace02009-04-17 17:47:31 +02001949 goto errout;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001950
Marcus Sundbergb633ad52006-02-04 02:11:09 -08001951 type |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001952 nlh = nlmsg_put(skb, item->pid, 0, type, sizeof(*nfmsg), flags);
1953 if (nlh == NULL)
1954 goto nlmsg_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001955
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001956 nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001957 nfmsg->nfgen_family = exp->tuple.src.l3num;
1958 nfmsg->version = NFNETLINK_V0;
1959 nfmsg->res_id = 0;
1960
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001961 rcu_read_lock();
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001962 if (ctnetlink_exp_dump_expect(skb, exp) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07001963 goto nla_put_failure;
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001964 rcu_read_unlock();
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001965
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001966 nlmsg_end(skb, nlh);
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02001967 nfnetlink_send(skb, net, item->pid, group, item->report, GFP_ATOMIC);
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02001968 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001969
Patrick McHardydf6fb862007-09-28 14:37:03 -07001970nla_put_failure:
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001971 rcu_read_unlock();
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001972 nlmsg_cancel(skb, nlh);
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001973nlmsg_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001974 kfree_skb(skb);
Pablo Neira Ayuso150ace02009-04-17 17:47:31 +02001975errout:
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01001976 nfnetlink_set_err(net, 0, 0, -ENOBUFS);
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02001977 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001978}
1979#endif
Patrick McHardycf6994c2007-07-07 22:32:34 -07001980static int ctnetlink_exp_done(struct netlink_callback *cb)
1981{
Patrick McHardy31f15872007-07-07 22:35:21 -07001982 if (cb->args[1])
1983 nf_ct_expect_put((struct nf_conntrack_expect *)cb->args[1]);
Patrick McHardycf6994c2007-07-07 22:32:34 -07001984 return 0;
1985}
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001986
1987static int
1988ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
1989{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01001990 struct net *net = sock_net(skb->sk);
Patrick McHardycf6994c2007-07-07 22:32:34 -07001991 struct nf_conntrack_expect *exp, *last;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001992 struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
Patrick McHardy31f15872007-07-07 22:35:21 -07001993 struct hlist_node *n;
Pablo Neira Ayuso87711cb2006-01-05 12:19:23 -08001994 u_int8_t l3proto = nfmsg->nfgen_family;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001995
Patrick McHardy7d0742d2008-01-31 04:38:19 -08001996 rcu_read_lock();
Patrick McHardy31f15872007-07-07 22:35:21 -07001997 last = (struct nf_conntrack_expect *)cb->args[1];
1998 for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
Patrick McHardycf6994c2007-07-07 22:32:34 -07001999restart:
Alexey Dobriyan9b03f382008-10-08 11:35:03 +02002000 hlist_for_each_entry(exp, n, &net->ct.expect_hash[cb->args[0]],
Patrick McHardy31f15872007-07-07 22:35:21 -07002001 hnode) {
2002 if (l3proto && exp->tuple.src.l3num != l3proto)
Patrick McHardycf6994c2007-07-07 22:32:34 -07002003 continue;
Patrick McHardy31f15872007-07-07 22:35:21 -07002004 if (cb->args[1]) {
2005 if (exp != last)
2006 continue;
2007 cb->args[1] = 0;
2008 }
Pablo Neira Ayuso8b0a2312009-06-02 20:03:34 +02002009 if (ctnetlink_exp_fill_info(skb,
2010 NETLINK_CB(cb->skb).pid,
Patrick McHardy31f15872007-07-07 22:35:21 -07002011 cb->nlh->nlmsg_seq,
2012 IPCTNL_MSG_EXP_NEW,
Pablo Neira Ayuso8b0a2312009-06-02 20:03:34 +02002013 exp) < 0) {
Patrick McHardy7d0742d2008-01-31 04:38:19 -08002014 if (!atomic_inc_not_zero(&exp->use))
2015 continue;
Patrick McHardy31f15872007-07-07 22:35:21 -07002016 cb->args[1] = (unsigned long)exp;
2017 goto out;
2018 }
Patrick McHardycf6994c2007-07-07 22:32:34 -07002019 }
Patrick McHardy31f15872007-07-07 22:35:21 -07002020 if (cb->args[1]) {
2021 cb->args[1] = 0;
2022 goto restart;
Patrick McHardycf6994c2007-07-07 22:32:34 -07002023 }
2024 }
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002025out:
Patrick McHardy7d0742d2008-01-31 04:38:19 -08002026 rcu_read_unlock();
Patrick McHardycf6994c2007-07-07 22:32:34 -07002027 if (last)
2028 nf_ct_expect_put(last);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002029
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002030 return skb->len;
2031}
2032
Patrick McHardyf73e9242007-09-28 14:39:55 -07002033static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
Patrick McHardyd0b02682010-02-10 15:38:33 +01002034 [CTA_EXPECT_MASTER] = { .type = NLA_NESTED },
2035 [CTA_EXPECT_TUPLE] = { .type = NLA_NESTED },
2036 [CTA_EXPECT_MASK] = { .type = NLA_NESTED },
Patrick McHardyf73e9242007-09-28 14:39:55 -07002037 [CTA_EXPECT_TIMEOUT] = { .type = NLA_U32 },
2038 [CTA_EXPECT_ID] = { .type = NLA_U32 },
Patrick McHardyd0b02682010-02-10 15:38:33 +01002039 [CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING },
Pablo Neira Ayusobcac0df2010-09-22 08:35:36 +02002040 [CTA_EXPECT_ZONE] = { .type = NLA_U16 },
Pablo Neira Ayuso8b008fa2010-09-22 08:36:59 +02002041 [CTA_EXPECT_FLAGS] = { .type = NLA_U32 },
Pablo Neira Ayusob8c5e522012-02-05 03:21:12 +01002042 [CTA_EXPECT_CLASS] = { .type = NLA_U32 },
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002043 [CTA_EXPECT_NAT] = { .type = NLA_NESTED },
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +01002044 [CTA_EXPECT_FN] = { .type = NLA_NUL_STRING },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002045};
2046
2047static int
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002048ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
Patrick McHardy39938322009-08-25 16:07:58 +02002049 const struct nlmsghdr *nlh,
2050 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002051{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01002052 struct net *net = sock_net(ctnl);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002053 struct nf_conntrack_tuple tuple;
2054 struct nf_conntrack_expect *exp;
2055 struct sk_buff *skb2;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002056 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002057 u_int8_t u3 = nfmsg->nfgen_family;
Patrick McHardyef00f892010-02-15 18:14:57 +01002058 u16 zone;
2059 int err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002060
David S. Millerb8f3ab42011-01-18 12:40:38 -08002061 if (nlh->nlmsg_flags & NLM_F_DUMP) {
Pablo Neira Ayuso80d326f2012-02-24 14:30:15 +00002062 struct netlink_dump_control c = {
2063 .dump = ctnetlink_exp_dump_table,
2064 .done = ctnetlink_exp_done,
2065 };
2066 return netlink_dump_start(ctnl, skb, nlh, &c);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002067 }
2068
Patrick McHardyef00f892010-02-15 18:14:57 +01002069 err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
2070 if (err < 0)
2071 return err;
2072
Pablo Neira Ayuso35dba1d2011-12-14 12:45:22 +01002073 if (cda[CTA_EXPECT_TUPLE])
2074 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
2075 else if (cda[CTA_EXPECT_MASTER])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002076 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER, u3);
2077 else
2078 return -EINVAL;
2079
2080 if (err < 0)
2081 return err;
2082
Patrick McHardyef00f892010-02-15 18:14:57 +01002083 exp = nf_ct_expect_find_get(net, zone, &tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002084 if (!exp)
2085 return -ENOENT;
2086
Patrick McHardydf6fb862007-09-28 14:37:03 -07002087 if (cda[CTA_EXPECT_ID]) {
Patrick McHardy77236b62007-12-17 22:29:45 -08002088 __be32 id = nla_get_be32(cda[CTA_EXPECT_ID]);
Patrick McHardy35832402007-09-28 14:41:50 -07002089 if (ntohl(id) != (u32)(unsigned long)exp) {
Patrick McHardy68236452007-07-07 22:30:49 -07002090 nf_ct_expect_put(exp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002091 return -ENOENT;
2092 }
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002093 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002094
2095 err = -ENOMEM;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002096 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01002097 if (skb2 == NULL) {
2098 nf_ct_expect_put(exp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002099 goto out;
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01002100 }
Thomas Graf4e9b8262006-11-27 09:25:58 -08002101
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01002102 rcu_read_lock();
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002103 err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid,
Pablo Neira Ayuso8b0a2312009-06-02 20:03:34 +02002104 nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, exp);
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01002105 rcu_read_unlock();
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01002106 nf_ct_expect_put(exp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002107 if (err <= 0)
2108 goto free;
2109
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01002110 err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
2111 if (err < 0)
2112 goto out;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002113
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01002114 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002115
2116free:
2117 kfree_skb(skb2);
2118out:
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01002119 /* this avoids a loop in nfnetlink. */
2120 return err == -EAGAIN ? -ENOBUFS : err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002121}
2122
2123static int
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002124ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
Patrick McHardy39938322009-08-25 16:07:58 +02002125 const struct nlmsghdr *nlh,
2126 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002127{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01002128 struct net *net = sock_net(ctnl);
Patrick McHardy31f15872007-07-07 22:35:21 -07002129 struct nf_conntrack_expect *exp;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002130 struct nf_conntrack_tuple tuple;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002131 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Patrick McHardy31f15872007-07-07 22:35:21 -07002132 struct hlist_node *n, *next;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002133 u_int8_t u3 = nfmsg->nfgen_family;
Patrick McHardy31f15872007-07-07 22:35:21 -07002134 unsigned int i;
Patrick McHardyef00f892010-02-15 18:14:57 +01002135 u16 zone;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002136 int err;
2137
Patrick McHardydf6fb862007-09-28 14:37:03 -07002138 if (cda[CTA_EXPECT_TUPLE]) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002139 /* delete a single expect by tuple */
Patrick McHardyef00f892010-02-15 18:14:57 +01002140 err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
2141 if (err < 0)
2142 return err;
2143
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002144 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
2145 if (err < 0)
2146 return err;
2147
2148 /* bump usage count to 2 */
Patrick McHardyef00f892010-02-15 18:14:57 +01002149 exp = nf_ct_expect_find_get(net, zone, &tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002150 if (!exp)
2151 return -ENOENT;
2152
Patrick McHardydf6fb862007-09-28 14:37:03 -07002153 if (cda[CTA_EXPECT_ID]) {
Patrick McHardy77236b62007-12-17 22:29:45 -08002154 __be32 id = nla_get_be32(cda[CTA_EXPECT_ID]);
Patrick McHardy35832402007-09-28 14:41:50 -07002155 if (ntohl(id) != (u32)(unsigned long)exp) {
Patrick McHardy68236452007-07-07 22:30:49 -07002156 nf_ct_expect_put(exp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002157 return -ENOENT;
2158 }
2159 }
2160
2161 /* after list removal, usage count == 1 */
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002162 spin_lock_bh(&nf_conntrack_lock);
2163 if (del_timer(&exp->timeout)) {
2164 nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).pid,
2165 nlmsg_report(nlh));
2166 nf_ct_expect_put(exp);
2167 }
2168 spin_unlock_bh(&nf_conntrack_lock);
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002169 /* have to put what we 'get' above.
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002170 * after this line usage count == 0 */
Patrick McHardy68236452007-07-07 22:30:49 -07002171 nf_ct_expect_put(exp);
Patrick McHardydf6fb862007-09-28 14:37:03 -07002172 } else if (cda[CTA_EXPECT_HELP_NAME]) {
2173 char *name = nla_data(cda[CTA_EXPECT_HELP_NAME]);
Patrick McHardy31f15872007-07-07 22:35:21 -07002174 struct nf_conn_help *m_help;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002175
2176 /* delete all expectations for this helper */
Patrick McHardyf8ba1af2008-01-31 04:38:58 -08002177 spin_lock_bh(&nf_conntrack_lock);
Patrick McHardy31f15872007-07-07 22:35:21 -07002178 for (i = 0; i < nf_ct_expect_hsize; i++) {
2179 hlist_for_each_entry_safe(exp, n, next,
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01002180 &net->ct.expect_hash[i],
Patrick McHardy31f15872007-07-07 22:35:21 -07002181 hnode) {
2182 m_help = nfct_help(exp->master);
Patrick McHardy794e6872010-02-03 13:41:29 +01002183 if (!strcmp(m_help->helper->name, name) &&
2184 del_timer(&exp->timeout)) {
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002185 nf_ct_unlink_expect_report(exp,
2186 NETLINK_CB(skb).pid,
2187 nlmsg_report(nlh));
Patrick McHardy31f15872007-07-07 22:35:21 -07002188 nf_ct_expect_put(exp);
2189 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002190 }
2191 }
Patrick McHardyf8ba1af2008-01-31 04:38:58 -08002192 spin_unlock_bh(&nf_conntrack_lock);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002193 } else {
2194 /* This basically means we have to flush everything*/
Patrick McHardyf8ba1af2008-01-31 04:38:58 -08002195 spin_lock_bh(&nf_conntrack_lock);
Patrick McHardy31f15872007-07-07 22:35:21 -07002196 for (i = 0; i < nf_ct_expect_hsize; i++) {
2197 hlist_for_each_entry_safe(exp, n, next,
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01002198 &net->ct.expect_hash[i],
Patrick McHardy31f15872007-07-07 22:35:21 -07002199 hnode) {
2200 if (del_timer(&exp->timeout)) {
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002201 nf_ct_unlink_expect_report(exp,
2202 NETLINK_CB(skb).pid,
2203 nlmsg_report(nlh));
Patrick McHardy31f15872007-07-07 22:35:21 -07002204 nf_ct_expect_put(exp);
2205 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002206 }
2207 }
Patrick McHardyf8ba1af2008-01-31 04:38:58 -08002208 spin_unlock_bh(&nf_conntrack_lock);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002209 }
2210
2211 return 0;
2212}
2213static int
Patrick McHardy39938322009-08-25 16:07:58 +02002214ctnetlink_change_expect(struct nf_conntrack_expect *x,
2215 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002216{
Kelvie Wong9768e1a2012-05-02 14:39:24 +00002217 if (cda[CTA_EXPECT_TIMEOUT]) {
2218 if (!del_timer(&x->timeout))
2219 return -ETIME;
2220
2221 x->timeout.expires = jiffies +
2222 ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ;
2223 add_timer(&x->timeout);
2224 }
2225 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002226}
2227
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002228static const struct nla_policy exp_nat_nla_policy[CTA_EXPECT_NAT_MAX+1] = {
2229 [CTA_EXPECT_NAT_DIR] = { .type = NLA_U32 },
2230 [CTA_EXPECT_NAT_TUPLE] = { .type = NLA_NESTED },
2231};
2232
2233static int
2234ctnetlink_parse_expect_nat(const struct nlattr *attr,
2235 struct nf_conntrack_expect *exp,
2236 u_int8_t u3)
2237{
2238#ifdef CONFIG_NF_NAT_NEEDED
2239 struct nlattr *tb[CTA_EXPECT_NAT_MAX+1];
2240 struct nf_conntrack_tuple nat_tuple = {};
2241 int err;
2242
2243 nla_parse_nested(tb, CTA_EXPECT_NAT_MAX, attr, exp_nat_nla_policy);
2244
2245 if (!tb[CTA_EXPECT_NAT_DIR] || !tb[CTA_EXPECT_NAT_TUPLE])
2246 return -EINVAL;
2247
2248 err = ctnetlink_parse_tuple((const struct nlattr * const *)tb,
2249 &nat_tuple, CTA_EXPECT_NAT_TUPLE, u3);
2250 if (err < 0)
2251 return err;
2252
2253 exp->saved_ip = nat_tuple.src.u3.ip;
2254 exp->saved_proto = nat_tuple.src.u;
2255 exp->dir = ntohl(nla_get_be32(tb[CTA_EXPECT_NAT_DIR]));
2256
2257 return 0;
2258#else
2259 return -EOPNOTSUPP;
2260#endif
2261}
2262
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002263static int
Patrick McHardyef00f892010-02-15 18:14:57 +01002264ctnetlink_create_expect(struct net *net, u16 zone,
2265 const struct nlattr * const cda[],
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01002266 u_int8_t u3,
Patrick McHardy39938322009-08-25 16:07:58 +02002267 u32 pid, int report)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002268{
2269 struct nf_conntrack_tuple tuple, mask, master_tuple;
2270 struct nf_conntrack_tuple_hash *h = NULL;
2271 struct nf_conntrack_expect *exp;
2272 struct nf_conn *ct;
Harald Weltedc808fe2006-03-20 17:56:32 -08002273 struct nf_conn_help *help;
Pablo Neira Ayuso660fdb22012-02-05 02:34:16 +01002274 struct nf_conntrack_helper *helper = NULL;
Pablo Neira Ayusob8c5e522012-02-05 03:21:12 +01002275 u_int32_t class = 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002276 int err = 0;
2277
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002278 /* caller guarantees that those three CTA_EXPECT_* exist */
2279 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
2280 if (err < 0)
2281 return err;
2282 err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK, u3);
2283 if (err < 0)
2284 return err;
2285 err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER, u3);
2286 if (err < 0)
2287 return err;
2288
2289 /* Look for master conntrack of this expectation */
Patrick McHardyef00f892010-02-15 18:14:57 +01002290 h = nf_conntrack_find_get(net, zone, &master_tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002291 if (!h)
2292 return -ENOENT;
2293 ct = nf_ct_tuplehash_to_ctrack(h);
Pablo Neira Ayuso660fdb22012-02-05 02:34:16 +01002294
2295 /* Look for helper of this expectation */
2296 if (cda[CTA_EXPECT_HELP_NAME]) {
2297 const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
2298
2299 helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
2300 nf_ct_protonum(ct));
2301 if (helper == NULL) {
2302#ifdef CONFIG_MODULES
2303 if (request_module("nfct-helper-%s", helpname) < 0) {
2304 err = -EOPNOTSUPP;
2305 goto out;
2306 }
2307
2308 helper = __nf_conntrack_helper_find(helpname,
2309 nf_ct_l3num(ct),
2310 nf_ct_protonum(ct));
2311 if (helper) {
2312 err = -EAGAIN;
2313 goto out;
2314 }
2315#endif
2316 err = -EOPNOTSUPP;
2317 goto out;
2318 }
2319 }
2320
Pablo Neira Ayusob8c5e522012-02-05 03:21:12 +01002321 if (cda[CTA_EXPECT_CLASS] && helper) {
2322 class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS]));
2323 if (class > helper->expect_class_max) {
2324 err = -EINVAL;
2325 goto out;
2326 }
2327 }
Patrick McHardy68236452007-07-07 22:30:49 -07002328 exp = nf_ct_expect_alloc(ct);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002329 if (!exp) {
2330 err = -ENOMEM;
2331 goto out;
2332 }
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02002333 help = nfct_help(ct);
2334 if (!help) {
2335 if (!cda[CTA_EXPECT_TIMEOUT]) {
2336 err = -EINVAL;
2337 goto out;
2338 }
2339 exp->timeout.expires =
2340 jiffies + ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002341
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02002342 exp->flags = NF_CT_EXPECT_USERSPACE;
2343 if (cda[CTA_EXPECT_FLAGS]) {
2344 exp->flags |=
2345 ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS]));
2346 }
2347 } else {
2348 if (cda[CTA_EXPECT_FLAGS]) {
2349 exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS]));
2350 exp->flags &= ~NF_CT_EXPECT_USERSPACE;
2351 } else
2352 exp->flags = 0;
2353 }
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +01002354 if (cda[CTA_EXPECT_FN]) {
2355 const char *name = nla_data(cda[CTA_EXPECT_FN]);
2356 struct nf_ct_helper_expectfn *expfn;
2357
2358 expfn = nf_ct_helper_expectfn_find_by_name(name);
2359 if (expfn == NULL) {
2360 err = -EINVAL;
2361 goto err_out;
2362 }
2363 exp->expectfn = expfn->expectfn;
2364 } else
2365 exp->expectfn = NULL;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002366
Pablo Neira Ayusob8c5e522012-02-05 03:21:12 +01002367 exp->class = class;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002368 exp->master = ct;
Pablo Neira Ayuso660fdb22012-02-05 02:34:16 +01002369 exp->helper = helper;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002370 memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple));
Patrick McHardyd4156e82007-07-07 22:31:32 -07002371 memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3));
2372 exp->mask.src.u.all = mask.src.u.all;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002373
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002374 if (cda[CTA_EXPECT_NAT]) {
2375 err = ctnetlink_parse_expect_nat(cda[CTA_EXPECT_NAT],
2376 exp, u3);
2377 if (err < 0)
2378 goto err_out;
2379 }
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +01002380 err = nf_ct_expect_related_report(exp, pid, report);
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002381err_out:
Patrick McHardy68236452007-07-07 22:30:49 -07002382 nf_ct_expect_put(exp);
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002383out:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002384 nf_ct_put(nf_ct_tuplehash_to_ctrack(h));
2385 return err;
2386}
2387
2388static int
2389ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
Patrick McHardy39938322009-08-25 16:07:58 +02002390 const struct nlmsghdr *nlh,
2391 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002392{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01002393 struct net *net = sock_net(ctnl);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002394 struct nf_conntrack_tuple tuple;
2395 struct nf_conntrack_expect *exp;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002396 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002397 u_int8_t u3 = nfmsg->nfgen_family;
Patrick McHardyef00f892010-02-15 18:14:57 +01002398 u16 zone;
2399 int err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002400
Patrick McHardydf6fb862007-09-28 14:37:03 -07002401 if (!cda[CTA_EXPECT_TUPLE]
2402 || !cda[CTA_EXPECT_MASK]
2403 || !cda[CTA_EXPECT_MASTER])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002404 return -EINVAL;
2405
Patrick McHardyef00f892010-02-15 18:14:57 +01002406 err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
2407 if (err < 0)
2408 return err;
2409
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002410 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
2411 if (err < 0)
2412 return err;
2413
Patrick McHardyf8ba1af2008-01-31 04:38:58 -08002414 spin_lock_bh(&nf_conntrack_lock);
Patrick McHardyef00f892010-02-15 18:14:57 +01002415 exp = __nf_ct_expect_find(net, zone, &tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002416
2417 if (!exp) {
Patrick McHardyf8ba1af2008-01-31 04:38:58 -08002418 spin_unlock_bh(&nf_conntrack_lock);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002419 err = -ENOENT;
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +01002420 if (nlh->nlmsg_flags & NLM_F_CREATE) {
Patrick McHardyef00f892010-02-15 18:14:57 +01002421 err = ctnetlink_create_expect(net, zone, cda,
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +01002422 u3,
2423 NETLINK_CB(skb).pid,
2424 nlmsg_report(nlh));
2425 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002426 return err;
2427 }
2428
2429 err = -EEXIST;
2430 if (!(nlh->nlmsg_flags & NLM_F_EXCL))
2431 err = ctnetlink_change_expect(exp, cda);
Patrick McHardyf8ba1af2008-01-31 04:38:58 -08002432 spin_unlock_bh(&nf_conntrack_lock);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002433
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002434 return err;
2435}
2436
2437#ifdef CONFIG_NF_CONNTRACK_EVENTS
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02002438static struct nf_ct_event_notifier ctnl_notifier = {
2439 .fcn = ctnetlink_conntrack_event,
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002440};
2441
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02002442static struct nf_exp_event_notifier ctnl_notifier_exp = {
2443 .fcn = ctnetlink_expect_event,
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002444};
2445#endif
2446
Patrick McHardy7c8d4cb2007-09-28 14:15:45 -07002447static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002448 [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack,
Patrick McHardyf73e9242007-09-28 14:39:55 -07002449 .attr_count = CTA_MAX,
2450 .policy = ct_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002451 [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack,
Patrick McHardyf73e9242007-09-28 14:39:55 -07002452 .attr_count = CTA_MAX,
2453 .policy = ct_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002454 [IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack,
Patrick McHardyf73e9242007-09-28 14:39:55 -07002455 .attr_count = CTA_MAX,
2456 .policy = ct_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002457 [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack,
Patrick McHardyf73e9242007-09-28 14:39:55 -07002458 .attr_count = CTA_MAX,
2459 .policy = ct_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002460};
2461
Patrick McHardy7c8d4cb2007-09-28 14:15:45 -07002462static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002463 [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect,
Patrick McHardyf73e9242007-09-28 14:39:55 -07002464 .attr_count = CTA_EXPECT_MAX,
2465 .policy = exp_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002466 [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect,
Patrick McHardyf73e9242007-09-28 14:39:55 -07002467 .attr_count = CTA_EXPECT_MAX,
2468 .policy = exp_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002469 [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect,
Patrick McHardyf73e9242007-09-28 14:39:55 -07002470 .attr_count = CTA_EXPECT_MAX,
2471 .policy = exp_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002472};
2473
Patrick McHardy7c8d4cb2007-09-28 14:15:45 -07002474static const struct nfnetlink_subsystem ctnl_subsys = {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002475 .name = "conntrack",
2476 .subsys_id = NFNL_SUBSYS_CTNETLINK,
2477 .cb_count = IPCTNL_MSG_MAX,
2478 .cb = ctnl_cb,
2479};
2480
Patrick McHardy7c8d4cb2007-09-28 14:15:45 -07002481static const struct nfnetlink_subsystem ctnl_exp_subsys = {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002482 .name = "conntrack_expect",
2483 .subsys_id = NFNL_SUBSYS_CTNETLINK_EXP,
2484 .cb_count = IPCTNL_MSG_EXP_MAX,
2485 .cb = ctnl_exp_cb,
2486};
2487
Patrick McHardyd2483dd2006-12-02 22:06:05 -08002488MODULE_ALIAS("ip_conntrack_netlink");
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002489MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);
Pablo Neira Ayuso34f9a2e2006-02-04 02:11:41 -08002490MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002491
Pablo Neira Ayuso70e99422011-11-22 00:16:51 +01002492static int __net_init ctnetlink_net_init(struct net *net)
2493{
2494#ifdef CONFIG_NF_CONNTRACK_EVENTS
2495 int ret;
2496
2497 ret = nf_conntrack_register_notifier(net, &ctnl_notifier);
2498 if (ret < 0) {
2499 pr_err("ctnetlink_init: cannot register notifier.\n");
2500 goto err_out;
2501 }
2502
2503 ret = nf_ct_expect_register_notifier(net, &ctnl_notifier_exp);
2504 if (ret < 0) {
2505 pr_err("ctnetlink_init: cannot expect register notifier.\n");
2506 goto err_unreg_notifier;
2507 }
2508#endif
2509 return 0;
2510
2511#ifdef CONFIG_NF_CONNTRACK_EVENTS
2512err_unreg_notifier:
2513 nf_conntrack_unregister_notifier(net, &ctnl_notifier);
2514err_out:
2515 return ret;
2516#endif
2517}
2518
2519static void ctnetlink_net_exit(struct net *net)
2520{
2521#ifdef CONFIG_NF_CONNTRACK_EVENTS
2522 nf_ct_expect_unregister_notifier(net, &ctnl_notifier_exp);
2523 nf_conntrack_unregister_notifier(net, &ctnl_notifier);
2524#endif
2525}
2526
2527static void __net_exit ctnetlink_net_exit_batch(struct list_head *net_exit_list)
2528{
2529 struct net *net;
2530
2531 list_for_each_entry(net, net_exit_list, exit_list)
2532 ctnetlink_net_exit(net);
2533}
2534
2535static struct pernet_operations ctnetlink_net_ops = {
2536 .init = ctnetlink_net_init,
2537 .exit_batch = ctnetlink_net_exit_batch,
2538};
2539
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002540static int __init ctnetlink_init(void)
2541{
2542 int ret;
2543
Stephen Hemminger654d0fb2010-05-13 15:02:08 +02002544 pr_info("ctnetlink v%s: registering with nfnetlink.\n", version);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002545 ret = nfnetlink_subsys_register(&ctnl_subsys);
2546 if (ret < 0) {
Stephen Hemminger654d0fb2010-05-13 15:02:08 +02002547 pr_err("ctnetlink_init: cannot register with nfnetlink.\n");
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002548 goto err_out;
2549 }
2550
2551 ret = nfnetlink_subsys_register(&ctnl_exp_subsys);
2552 if (ret < 0) {
Stephen Hemminger654d0fb2010-05-13 15:02:08 +02002553 pr_err("ctnetlink_init: cannot register exp with nfnetlink.\n");
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002554 goto err_unreg_subsys;
2555 }
2556
Pablo Neira Ayuso70e99422011-11-22 00:16:51 +01002557 if (register_pernet_subsys(&ctnetlink_net_ops)) {
2558 pr_err("ctnetlink_init: cannot register pernet operations\n");
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002559 goto err_unreg_exp_subsys;
2560 }
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002561#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || \
2562 defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE)
2563 /* setup interaction between nf_queue and nf_conntrack_netlink. */
2564 RCU_INIT_POINTER(nfq_ct_hook, &ctnetlink_nfqueue_hook);
2565#endif
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002566 return 0;
2567
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002568err_unreg_exp_subsys:
2569 nfnetlink_subsys_unregister(&ctnl_exp_subsys);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002570err_unreg_subsys:
2571 nfnetlink_subsys_unregister(&ctnl_subsys);
2572err_out:
2573 return ret;
2574}
2575
2576static void __exit ctnetlink_exit(void)
2577{
Stephen Hemminger654d0fb2010-05-13 15:02:08 +02002578 pr_info("ctnetlink: unregistering from nfnetlink.\n");
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002579
Pablo Neira Ayuso70e99422011-11-22 00:16:51 +01002580 unregister_pernet_subsys(&ctnetlink_net_ops);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002581 nfnetlink_subsys_unregister(&ctnl_exp_subsys);
2582 nfnetlink_subsys_unregister(&ctnl_subsys);
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002583#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || \
2584 defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE)
2585 RCU_INIT_POINTER(nfq_ct_hook, NULL);
2586#endif
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002587}
2588
2589module_init(ctnetlink_init);
2590module_exit(ctnetlink_exit);