blob: caa4efe5930b940f36dfc26d1390146c65a59373 [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 Ayuso392025f2012-06-26 20:27:09 +02007 * (C) 2005-2012 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>
Patrick McHardy41d73ec2013-08-27 08:50:12 +020040#include <net/netfilter/nf_conntrack_seqadj.h>
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080041#include <net/netfilter/nf_conntrack_l3proto.h>
Martin Josefsson605dcad2006-11-29 02:35:06 +010042#include <net/netfilter/nf_conntrack_l4proto.h>
Jozsef Kadlecsik5b1158e2006-12-02 22:07:13 -080043#include <net/netfilter/nf_conntrack_tuple.h>
Krzysztof Piotr Oledzki58401572008-07-21 10:01:34 -070044#include <net/netfilter/nf_conntrack_acct.h>
Patrick McHardyef00f892010-02-15 18:14:57 +010045#include <net/netfilter/nf_conntrack_zones.h>
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +010046#include <net/netfilter/nf_conntrack_timestamp.h>
Florian Westphalc539f012013-01-11 06:30:44 +000047#include <net/netfilter/nf_conntrack_labels.h>
Jozsef Kadlecsik5b1158e2006-12-02 22:07:13 -080048#ifdef CONFIG_NF_NAT_NEEDED
49#include <net/netfilter/nf_nat_core.h>
Patrick McHardyc7232c92012-08-26 19:14:06 +020050#include <net/netfilter/nf_nat_l4proto.h>
Pablo Neira Ayuso8c88f872012-06-07 13:31:25 +020051#include <net/netfilter/nf_nat_helper.h>
Jozsef Kadlecsik5b1158e2006-12-02 22:07:13 -080052#endif
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080053
54#include <linux/netfilter/nfnetlink.h>
55#include <linux/netfilter/nfnetlink_conntrack.h>
56
57MODULE_LICENSE("GPL");
58
Harald Weltedc808fe2006-03-20 17:56:32 -080059static char __initdata version[] = "0.93";
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080060
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +020061static int ctnetlink_dump_tuples_proto(struct sk_buff *skb,
62 const struct nf_conntrack_tuple *tuple,
63 struct nf_conntrack_l4proto *l4proto)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080064{
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080065 int ret = 0;
Patrick McHardydf6fb862007-09-28 14:37:03 -070066 struct nlattr *nest_parms;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080067
Patrick McHardydf6fb862007-09-28 14:37:03 -070068 nest_parms = nla_nest_start(skb, CTA_TUPLE_PROTO | NLA_F_NESTED);
69 if (!nest_parms)
70 goto nla_put_failure;
David S. Millercc1eb432012-04-01 18:57:48 -040071 if (nla_put_u8(skb, CTA_PROTO_NUM, tuple->dst.protonum))
72 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080073
Patrick McHardyfdf70832007-09-28 14:37:41 -070074 if (likely(l4proto->tuple_to_nlattr))
75 ret = l4proto->tuple_to_nlattr(skb, tuple);
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -080076
Patrick McHardydf6fb862007-09-28 14:37:03 -070077 nla_nest_end(skb, nest_parms);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080078
79 return ret;
80
Patrick McHardydf6fb862007-09-28 14:37:03 -070081nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080082 return -1;
83}
84
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +020085static int ctnetlink_dump_tuples_ip(struct sk_buff *skb,
86 const struct nf_conntrack_tuple *tuple,
87 struct nf_conntrack_l3proto *l3proto)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080088{
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080089 int ret = 0;
Patrick McHardydf6fb862007-09-28 14:37:03 -070090 struct nlattr *nest_parms;
91
92 nest_parms = nla_nest_start(skb, CTA_TUPLE_IP | NLA_F_NESTED);
93 if (!nest_parms)
94 goto nla_put_failure;
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -080095
Patrick McHardyfdf70832007-09-28 14:37:41 -070096 if (likely(l3proto->tuple_to_nlattr))
97 ret = l3proto->tuple_to_nlattr(skb, tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -080098
Patrick McHardydf6fb862007-09-28 14:37:03 -070099 nla_nest_end(skb, nest_parms);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800100
101 return ret;
102
Patrick McHardydf6fb862007-09-28 14:37:03 -0700103nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800104 return -1;
105}
106
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200107static int ctnetlink_dump_tuples(struct sk_buff *skb,
108 const struct nf_conntrack_tuple *tuple)
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -0800109{
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
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200127static int ctnetlink_dump_zone_id(struct sk_buff *skb, int attrtype,
128 const struct nf_conntrack_zone *zone, int dir)
Daniel Borkmanndeedb592015-08-14 16:03:39 +0200129{
130 if (zone->id == NF_CT_DEFAULT_ZONE_ID || zone->dir != dir)
131 return 0;
132 if (nla_put_be16(skb, attrtype, htons(zone->id)))
133 goto nla_put_failure;
134 return 0;
135
136nla_put_failure:
137 return -1;
138}
139
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200140static int ctnetlink_dump_status(struct sk_buff *skb, const struct nf_conn *ct)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800141{
David S. Millercc1eb432012-04-01 18:57:48 -0400142 if (nla_put_be32(skb, CTA_STATUS, htonl(ct->status)))
143 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800144 return 0;
145
Patrick McHardydf6fb862007-09-28 14:37:03 -0700146nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800147 return -1;
148}
149
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200150static int ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800151{
Xi Wangc1216382011-12-30 10:40:17 -0500152 long timeout = ((long)ct->timeout.expires - (long)jiffies) / HZ;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800153
Patrick McHardy77236b62007-12-17 22:29:45 -0800154 if (timeout < 0)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800155 timeout = 0;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800156
David S. Millercc1eb432012-04-01 18:57:48 -0400157 if (nla_put_be32(skb, CTA_TIMEOUT, htonl(timeout)))
158 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800159 return 0;
160
Patrick McHardydf6fb862007-09-28 14:37:03 -0700161nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800162 return -1;
163}
164
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200165static int ctnetlink_dump_protoinfo(struct sk_buff *skb, struct nf_conn *ct)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800166{
Patrick McHardy5e8fbe22008-04-14 11:15:52 +0200167 struct nf_conntrack_l4proto *l4proto;
Patrick McHardydf6fb862007-09-28 14:37:03 -0700168 struct nlattr *nest_proto;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800169 int ret;
170
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +0100171 l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
172 if (!l4proto->to_nlattr)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800173 return 0;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800174
Patrick McHardydf6fb862007-09-28 14:37:03 -0700175 nest_proto = nla_nest_start(skb, CTA_PROTOINFO | NLA_F_NESTED);
176 if (!nest_proto)
177 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800178
Patrick McHardyfdf70832007-09-28 14:37:41 -0700179 ret = l4proto->to_nlattr(skb, nest_proto, ct);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800180
Patrick McHardydf6fb862007-09-28 14:37:03 -0700181 nla_nest_end(skb, nest_proto);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800182
183 return ret;
184
Patrick McHardydf6fb862007-09-28 14:37:03 -0700185nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800186 return -1;
187}
188
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200189static int ctnetlink_dump_helpinfo(struct sk_buff *skb,
190 const struct nf_conn *ct)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800191{
Patrick McHardydf6fb862007-09-28 14:37:03 -0700192 struct nlattr *nest_helper;
Harald Weltedc808fe2006-03-20 17:56:32 -0800193 const struct nf_conn_help *help = nfct_help(ct);
Patrick McHarrdy3c158f72007-06-05 12:55:27 -0700194 struct nf_conntrack_helper *helper;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800195
Patrick McHarrdy3c158f72007-06-05 12:55:27 -0700196 if (!help)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800197 return 0;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800198
Patrick McHarrdy3c158f72007-06-05 12:55:27 -0700199 helper = rcu_dereference(help->helper);
200 if (!helper)
201 goto out;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800202
Patrick McHardydf6fb862007-09-28 14:37:03 -0700203 nest_helper = nla_nest_start(skb, CTA_HELP | NLA_F_NESTED);
204 if (!nest_helper)
205 goto nla_put_failure;
David S. Millercc1eb432012-04-01 18:57:48 -0400206 if (nla_put_string(skb, CTA_HELP_NAME, helper->name))
207 goto nla_put_failure;
Patrick McHarrdy3c158f72007-06-05 12:55:27 -0700208
Patrick McHardyfdf70832007-09-28 14:37:41 -0700209 if (helper->to_nlattr)
210 helper->to_nlattr(skb, ct);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800211
Patrick McHardydf6fb862007-09-28 14:37:03 -0700212 nla_nest_end(skb, nest_helper);
Patrick McHarrdy3c158f72007-06-05 12:55:27 -0700213out:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800214 return 0;
215
Patrick McHardydf6fb862007-09-28 14:37:03 -0700216nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800217 return -1;
218}
219
Ilpo Järvinenbb5cf802008-01-05 23:11:31 -0800220static int
Holger Eitzenberger4542fa42013-09-26 17:31:52 +0200221dump_counters(struct sk_buff *skb, struct nf_conn_acct *acct,
222 enum ip_conntrack_dir dir, int type)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800223{
Holger Eitzenberger4542fa42013-09-26 17:31:52 +0200224 enum ctattr_type attr = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
225 struct nf_conn_counter *counter = acct->counter;
Patrick McHardydf6fb862007-09-28 14:37:03 -0700226 struct nlattr *nest_count;
Holger Eitzenberger4542fa42013-09-26 17:31:52 +0200227 u64 pkts, bytes;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800228
Holger Eitzenberger4542fa42013-09-26 17:31:52 +0200229 if (type == IPCTNL_MSG_CT_GET_CTRZERO) {
230 pkts = atomic64_xchg(&counter[dir].packets, 0);
231 bytes = atomic64_xchg(&counter[dir].bytes, 0);
232 } else {
233 pkts = atomic64_read(&counter[dir].packets);
234 bytes = atomic64_read(&counter[dir].bytes);
235 }
236
237 nest_count = nla_nest_start(skb, attr | NLA_F_NESTED);
Patrick McHardydf6fb862007-09-28 14:37:03 -0700238 if (!nest_count)
239 goto nla_put_failure;
240
David S. Millercc1eb432012-04-01 18:57:48 -0400241 if (nla_put_be64(skb, CTA_COUNTERS_PACKETS, cpu_to_be64(pkts)) ||
242 nla_put_be64(skb, CTA_COUNTERS_BYTES, cpu_to_be64(bytes)))
243 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800244
Patrick McHardydf6fb862007-09-28 14:37:03 -0700245 nla_nest_end(skb, nest_count);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800246
247 return 0;
248
Patrick McHardydf6fb862007-09-28 14:37:03 -0700249nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800250 return -1;
251}
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800252
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +0100253static int
Holger Eitzenberger4542fa42013-09-26 17:31:52 +0200254ctnetlink_dump_acct(struct sk_buff *skb, const struct nf_conn *ct, int type)
Pablo Neira Ayuso80e60e62011-12-24 14:11:39 +0100255{
Holger Eitzenberger4542fa42013-09-26 17:31:52 +0200256 struct nf_conn_acct *acct = nf_conn_acct_find(ct);
Pablo Neira Ayuso80e60e62011-12-24 14:11:39 +0100257
Pablo Neira Ayuso80e60e62011-12-24 14:11:39 +0100258 if (!acct)
259 return 0;
260
Holger Eitzenberger4542fa42013-09-26 17:31:52 +0200261 if (dump_counters(skb, acct, IP_CT_DIR_ORIGINAL, type) < 0)
262 return -1;
263 if (dump_counters(skb, acct, IP_CT_DIR_REPLY, type) < 0)
264 return -1;
265
266 return 0;
Pablo Neira Ayuso80e60e62011-12-24 14:11:39 +0100267}
268
269static int
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +0100270ctnetlink_dump_timestamp(struct sk_buff *skb, const struct nf_conn *ct)
271{
272 struct nlattr *nest_count;
273 const struct nf_conn_tstamp *tstamp;
274
275 tstamp = nf_conn_tstamp_find(ct);
276 if (!tstamp)
277 return 0;
278
279 nest_count = nla_nest_start(skb, CTA_TIMESTAMP | NLA_F_NESTED);
280 if (!nest_count)
281 goto nla_put_failure;
282
David S. Millercc1eb432012-04-01 18:57:48 -0400283 if (nla_put_be64(skb, CTA_TIMESTAMP_START, cpu_to_be64(tstamp->start)) ||
284 (tstamp->stop != 0 && nla_put_be64(skb, CTA_TIMESTAMP_STOP,
285 cpu_to_be64(tstamp->stop))))
286 goto nla_put_failure;
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +0100287 nla_nest_end(skb, nest_count);
288
289 return 0;
290
291nla_put_failure:
292 return -1;
293}
294
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800295#ifdef CONFIG_NF_CONNTRACK_MARK
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200296static int ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800297{
David S. Millercc1eb432012-04-01 18:57:48 -0400298 if (nla_put_be32(skb, CTA_MARK, htonl(ct->mark)))
299 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800300 return 0;
301
Patrick McHardydf6fb862007-09-28 14:37:03 -0700302nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800303 return -1;
304}
305#else
306#define ctnetlink_dump_mark(a, b) (0)
307#endif
308
Pablo Neira Ayuso37fccd82007-12-17 22:28:41 -0800309#ifdef CONFIG_NF_CONNTRACK_SECMARK
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200310static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
Pablo Neira Ayuso37fccd82007-12-17 22:28:41 -0800311{
Eric Paris1cc63242010-10-13 16:24:54 -0400312 struct nlattr *nest_secctx;
313 int len, ret;
314 char *secctx;
Pablo Neira Ayuso37fccd82007-12-17 22:28:41 -0800315
Eric Paris1cc63242010-10-13 16:24:54 -0400316 ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
317 if (ret)
Pablo Neira Ayusocba85b52011-01-06 11:25:00 -0800318 return 0;
Eric Paris1cc63242010-10-13 16:24:54 -0400319
320 ret = -1;
321 nest_secctx = nla_nest_start(skb, CTA_SECCTX | NLA_F_NESTED);
322 if (!nest_secctx)
323 goto nla_put_failure;
324
David S. Millercc1eb432012-04-01 18:57:48 -0400325 if (nla_put_string(skb, CTA_SECCTX_NAME, secctx))
326 goto nla_put_failure;
Eric Paris1cc63242010-10-13 16:24:54 -0400327 nla_nest_end(skb, nest_secctx);
328
329 ret = 0;
Pablo Neira Ayuso37fccd82007-12-17 22:28:41 -0800330nla_put_failure:
Eric Paris1cc63242010-10-13 16:24:54 -0400331 security_release_secctx(secctx, len);
332 return ret;
Pablo Neira Ayuso37fccd82007-12-17 22:28:41 -0800333}
334#else
Eric Paris1cc63242010-10-13 16:24:54 -0400335#define ctnetlink_dump_secctx(a, b) (0)
Pablo Neira Ayuso37fccd82007-12-17 22:28:41 -0800336#endif
337
Florian Westphal0ceabd82013-01-11 06:30:45 +0000338#ifdef CONFIG_NF_CONNTRACK_LABELS
339static int ctnetlink_label_size(const struct nf_conn *ct)
340{
341 struct nf_conn_labels *labels = nf_ct_labels_find(ct);
342
343 if (!labels)
344 return 0;
345 return nla_total_size(labels->words * sizeof(long));
346}
347
348static int
349ctnetlink_dump_labels(struct sk_buff *skb, const struct nf_conn *ct)
350{
351 struct nf_conn_labels *labels = nf_ct_labels_find(ct);
352 unsigned int len, i;
353
354 if (!labels)
355 return 0;
356
357 len = labels->words * sizeof(long);
358 i = 0;
359 do {
360 if (labels->bits[i] != 0)
361 return nla_put(skb, CTA_LABELS, len, labels->bits);
362 i++;
363 } while (i < labels->words);
364
365 return 0;
366}
367#else
368#define ctnetlink_dump_labels(a, b) (0)
369#define ctnetlink_label_size(a) (0)
370#endif
371
Pablo Neira Ayuso0f417ce2007-12-17 22:28:19 -0800372#define master_tuple(ct) &(ct->master->tuplehash[IP_CT_DIR_ORIGINAL].tuple)
373
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200374static int ctnetlink_dump_master(struct sk_buff *skb, const struct nf_conn *ct)
Pablo Neira Ayuso0f417ce2007-12-17 22:28:19 -0800375{
376 struct nlattr *nest_parms;
377
378 if (!(ct->status & IPS_EXPECTED))
379 return 0;
380
381 nest_parms = nla_nest_start(skb, CTA_TUPLE_MASTER | NLA_F_NESTED);
382 if (!nest_parms)
383 goto nla_put_failure;
384 if (ctnetlink_dump_tuples(skb, master_tuple(ct)) < 0)
385 goto nla_put_failure;
386 nla_nest_end(skb, nest_parms);
387
388 return 0;
389
390nla_put_failure:
391 return -1;
392}
393
Ilpo Järvinenbb5cf802008-01-05 23:11:31 -0800394static int
Patrick McHardy41d73ec2013-08-27 08:50:12 +0200395dump_ct_seq_adj(struct sk_buff *skb, const struct nf_ct_seqadj *seq, int type)
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800396{
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800397 struct nlattr *nest_parms;
398
399 nest_parms = nla_nest_start(skb, type | NLA_F_NESTED);
400 if (!nest_parms)
401 goto nla_put_failure;
402
Patrick McHardy41d73ec2013-08-27 08:50:12 +0200403 if (nla_put_be32(skb, CTA_SEQADJ_CORRECTION_POS,
404 htonl(seq->correction_pos)) ||
405 nla_put_be32(skb, CTA_SEQADJ_OFFSET_BEFORE,
406 htonl(seq->offset_before)) ||
407 nla_put_be32(skb, CTA_SEQADJ_OFFSET_AFTER,
408 htonl(seq->offset_after)))
David S. Millercc1eb432012-04-01 18:57:48 -0400409 goto nla_put_failure;
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800410
411 nla_nest_end(skb, nest_parms);
412
413 return 0;
414
415nla_put_failure:
416 return -1;
417}
418
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200419static int ctnetlink_dump_ct_seq_adj(struct sk_buff *skb,
420 const struct nf_conn *ct)
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800421{
Patrick McHardy41d73ec2013-08-27 08:50:12 +0200422 struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
423 struct nf_ct_seqadj *seq;
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800424
Patrick McHardy41d73ec2013-08-27 08:50:12 +0200425 if (!(ct->status & IPS_SEQ_ADJUST) || !seqadj)
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800426 return 0;
427
Patrick McHardy41d73ec2013-08-27 08:50:12 +0200428 seq = &seqadj->seq[IP_CT_DIR_ORIGINAL];
429 if (dump_ct_seq_adj(skb, seq, CTA_SEQ_ADJ_ORIG) == -1)
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800430 return -1;
431
Patrick McHardy41d73ec2013-08-27 08:50:12 +0200432 seq = &seqadj->seq[IP_CT_DIR_REPLY];
433 if (dump_ct_seq_adj(skb, seq, CTA_SEQ_ADJ_REPLY) == -1)
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800434 return -1;
435
436 return 0;
437}
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800438
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200439static int ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800440{
David S. Millercc1eb432012-04-01 18:57:48 -0400441 if (nla_put_be32(skb, CTA_ID, htonl((unsigned long)ct)))
442 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800443 return 0;
444
Patrick McHardydf6fb862007-09-28 14:37:03 -0700445nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800446 return -1;
447}
448
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200449static int ctnetlink_dump_use(struct sk_buff *skb, const struct nf_conn *ct)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800450{
David S. Millercc1eb432012-04-01 18:57:48 -0400451 if (nla_put_be32(skb, CTA_USE, htonl(atomic_read(&ct->ct_general.use))))
452 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800453 return 0;
454
Patrick McHardydf6fb862007-09-28 14:37:03 -0700455nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800456 return -1;
457}
458
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800459static int
Eric W. Biederman15e47302012-09-07 20:12:54 +0000460ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
Pablo Neira Ayuso80e60e62011-12-24 14:11:39 +0100461 struct nf_conn *ct)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800462{
Daniel Borkmann308ac912015-08-08 21:40:01 +0200463 const struct nf_conntrack_zone *zone;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800464 struct nlmsghdr *nlh;
465 struct nfgenmsg *nfmsg;
Patrick McHardydf6fb862007-09-28 14:37:03 -0700466 struct nlattr *nest_parms;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000467 unsigned int flags = portid ? NLM_F_MULTI : 0, event;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800468
Pablo Neira Ayuso80e60e62011-12-24 14:11:39 +0100469 event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_CT_NEW);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000470 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200471 if (nlh == NULL)
472 goto nlmsg_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800473
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200474 nfmsg = nlmsg_data(nlh);
Patrick McHardy5e8fbe22008-04-14 11:15:52 +0200475 nfmsg->nfgen_family = nf_ct_l3num(ct);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800476 nfmsg->version = NFNETLINK_V0;
477 nfmsg->res_id = 0;
478
Daniel Borkmanndeedb592015-08-14 16:03:39 +0200479 zone = nf_ct_zone(ct);
480
Patrick McHardydf6fb862007-09-28 14:37:03 -0700481 nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED);
482 if (!nest_parms)
483 goto nla_put_failure;
Pablo Neira Ayusof2f3e382009-06-02 20:03:35 +0200484 if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700485 goto nla_put_failure;
Daniel Borkmanndeedb592015-08-14 16:03:39 +0200486 if (ctnetlink_dump_zone_id(skb, CTA_TUPLE_ZONE, zone,
487 NF_CT_ZONE_DIR_ORIG) < 0)
488 goto nla_put_failure;
Patrick McHardydf6fb862007-09-28 14:37:03 -0700489 nla_nest_end(skb, nest_parms);
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800490
Patrick McHardydf6fb862007-09-28 14:37:03 -0700491 nest_parms = nla_nest_start(skb, CTA_TUPLE_REPLY | NLA_F_NESTED);
492 if (!nest_parms)
493 goto nla_put_failure;
Pablo Neira Ayusof2f3e382009-06-02 20:03:35 +0200494 if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_REPLY)) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700495 goto nla_put_failure;
Daniel Borkmanndeedb592015-08-14 16:03:39 +0200496 if (ctnetlink_dump_zone_id(skb, CTA_TUPLE_ZONE, zone,
497 NF_CT_ZONE_DIR_REPL) < 0)
498 goto nla_put_failure;
Patrick McHardydf6fb862007-09-28 14:37:03 -0700499 nla_nest_end(skb, nest_parms);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800500
Daniel Borkmanndeedb592015-08-14 16:03:39 +0200501 if (ctnetlink_dump_zone_id(skb, CTA_ZONE, zone,
502 NF_CT_DEFAULT_ZONE_DIR) < 0)
David S. Millercc1eb432012-04-01 18:57:48 -0400503 goto nla_put_failure;
Patrick McHardyef00f892010-02-15 18:14:57 +0100504
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800505 if (ctnetlink_dump_status(skb, ct) < 0 ||
506 ctnetlink_dump_timeout(skb, ct) < 0 ||
Holger Eitzenberger4542fa42013-09-26 17:31:52 +0200507 ctnetlink_dump_acct(skb, ct, type) < 0 ||
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +0100508 ctnetlink_dump_timestamp(skb, ct) < 0 ||
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800509 ctnetlink_dump_protoinfo(skb, ct) < 0 ||
510 ctnetlink_dump_helpinfo(skb, ct) < 0 ||
511 ctnetlink_dump_mark(skb, ct) < 0 ||
Eric Paris1cc63242010-10-13 16:24:54 -0400512 ctnetlink_dump_secctx(skb, ct) < 0 ||
Florian Westphal0ceabd82013-01-11 06:30:45 +0000513 ctnetlink_dump_labels(skb, ct) < 0 ||
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800514 ctnetlink_dump_id(skb, ct) < 0 ||
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800515 ctnetlink_dump_use(skb, ct) < 0 ||
Pablo Neira Ayuso0f417ce2007-12-17 22:28:19 -0800516 ctnetlink_dump_master(skb, ct) < 0 ||
Patrick McHardy41d73ec2013-08-27 08:50:12 +0200517 ctnetlink_dump_ct_seq_adj(skb, ct) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700518 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800519
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200520 nlmsg_end(skb, nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800521 return skb->len;
522
523nlmsg_failure:
Patrick McHardydf6fb862007-09-28 14:37:03 -0700524nla_put_failure:
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200525 nlmsg_cancel(skb, nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800526 return -1;
527}
528
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200529static size_t ctnetlink_proto_size(const struct nf_conn *ct)
Holger Eitzenberger2732c4e2009-03-25 21:50:59 +0100530{
531 struct nf_conntrack_l3proto *l3proto;
532 struct nf_conntrack_l4proto *l4proto;
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200533 size_t len = 0;
Holger Eitzenberger2732c4e2009-03-25 21:50:59 +0100534
535 rcu_read_lock();
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200536 l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct));
Holger Eitzenberger2732c4e2009-03-25 21:50:59 +0100537 len += l3proto->nla_size;
538
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200539 l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
Holger Eitzenberger2732c4e2009-03-25 21:50:59 +0100540 len += l4proto->nla_size;
541 rcu_read_unlock();
542
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200543 return len;
544}
545
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200546static size_t ctnetlink_acct_size(const struct nf_conn *ct)
Jiri Pirkod26e6a02010-04-01 12:39:19 +0200547{
548 if (!nf_ct_ext_exist(ct, NF_CT_EXT_ACCT))
549 return 0;
550 return 2 * nla_total_size(0) /* CTA_COUNTERS_ORIG|REPL */
551 + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_PACKETS */
552 + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_BYTES */
553 ;
554}
555
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200556static int ctnetlink_secctx_size(const struct nf_conn *ct)
Eric Paris1cc63242010-10-13 16:24:54 -0400557{
Pablo Neira Ayusocba85b52011-01-06 11:25:00 -0800558#ifdef CONFIG_NF_CONNTRACK_SECMARK
559 int len, ret;
Eric Paris1cc63242010-10-13 16:24:54 -0400560
Pablo Neira Ayusocba85b52011-01-06 11:25:00 -0800561 ret = security_secid_to_secctx(ct->secmark, NULL, &len);
562 if (ret)
563 return 0;
Eric Paris1cc63242010-10-13 16:24:54 -0400564
Pablo Neira Ayusocba85b52011-01-06 11:25:00 -0800565 return nla_total_size(0) /* CTA_SECCTX */
566 + nla_total_size(sizeof(char) * len); /* CTA_SECCTX_NAME */
567#else
568 return 0;
Eric Paris1cc63242010-10-13 16:24:54 -0400569#endif
Pablo Neira Ayusocba85b52011-01-06 11:25:00 -0800570}
Eric Paris1cc63242010-10-13 16:24:54 -0400571
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200572static size_t ctnetlink_timestamp_size(const struct nf_conn *ct)
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +0100573{
574#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
575 if (!nf_ct_ext_exist(ct, NF_CT_EXT_TSTAMP))
576 return 0;
577 return nla_total_size(0) + 2 * nla_total_size(sizeof(uint64_t));
578#else
579 return 0;
580#endif
581}
582
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200583#ifdef CONFIG_NF_CONNTRACK_EVENTS
584static size_t ctnetlink_nlmsg_size(const struct nf_conn *ct)
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200585{
586 return NLMSG_ALIGN(sizeof(struct nfgenmsg))
587 + 3 * nla_total_size(0) /* CTA_TUPLE_ORIG|REPL|MASTER */
588 + 3 * nla_total_size(0) /* CTA_TUPLE_IP */
589 + 3 * nla_total_size(0) /* CTA_TUPLE_PROTO */
590 + 3 * nla_total_size(sizeof(u_int8_t)) /* CTA_PROTO_NUM */
591 + nla_total_size(sizeof(u_int32_t)) /* CTA_ID */
592 + nla_total_size(sizeof(u_int32_t)) /* CTA_STATUS */
Holger Eitzenbergerf7b13e42013-09-26 17:31:51 +0200593 + ctnetlink_acct_size(ct)
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +0100594 + ctnetlink_timestamp_size(ct)
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200595 + nla_total_size(sizeof(u_int32_t)) /* CTA_TIMEOUT */
596 + nla_total_size(0) /* CTA_PROTOINFO */
597 + nla_total_size(0) /* CTA_HELP */
598 + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */
Pablo Neira Ayusocba85b52011-01-06 11:25:00 -0800599 + ctnetlink_secctx_size(ct)
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200600#ifdef CONFIG_NF_NAT_NEEDED
601 + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */
602 + 6 * nla_total_size(sizeof(u_int32_t)) /* CTA_NAT_SEQ_OFFSET */
603#endif
604#ifdef CONFIG_NF_CONNTRACK_MARK
605 + nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */
606#endif
Ken-ichirou MATSUZAWA4a001062014-06-16 13:52:34 +0200607#ifdef CONFIG_NF_CONNTRACK_ZONES
Daniel Borkmanndeedb592015-08-14 16:03:39 +0200608 + nla_total_size(sizeof(u_int16_t)) /* CTA_ZONE|CTA_TUPLE_ZONE */
Ken-ichirou MATSUZAWA4a001062014-06-16 13:52:34 +0200609#endif
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200610 + ctnetlink_proto_size(ct)
Florian Westphal0ceabd82013-01-11 06:30:45 +0000611 + ctnetlink_label_size(ct)
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200612 ;
Holger Eitzenberger2732c4e2009-03-25 21:50:59 +0100613}
614
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200615static int
616ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800617{
Daniel Borkmann308ac912015-08-08 21:40:01 +0200618 const struct nf_conntrack_zone *zone;
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +0100619 struct net *net;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800620 struct nlmsghdr *nlh;
621 struct nfgenmsg *nfmsg;
Patrick McHardydf6fb862007-09-28 14:37:03 -0700622 struct nlattr *nest_parms;
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100623 struct nf_conn *ct = item->ct;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800624 struct sk_buff *skb;
625 unsigned int type;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800626 unsigned int flags = 0, group;
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200627 int err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800628
629 /* ignore our fake conntrack entry */
Eric Dumazet5bfddbd2010-06-08 16:09:52 +0200630 if (nf_ct_is_untracked(ct))
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200631 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800632
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200633 if (events & (1 << IPCT_DESTROY)) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800634 type = IPCTNL_MSG_CT_DELETE;
635 group = NFNLGRP_CONNTRACK_DESTROY;
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200636 } else if (events & ((1 << IPCT_NEW) | (1 << IPCT_RELATED))) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800637 type = IPCTNL_MSG_CT_NEW;
638 flags = NLM_F_CREATE|NLM_F_EXCL;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800639 group = NFNLGRP_CONNTRACK_NEW;
Pablo Neira Ayuso17e6e4e2009-06-02 20:08:46 +0200640 } else if (events) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800641 type = IPCTNL_MSG_CT_NEW;
642 group = NFNLGRP_CONNTRACK_UPDATE;
643 } else
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200644 return 0;
Patrick McHardya2427692006-03-20 18:03:59 -0800645
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +0100646 net = nf_ct_net(ct);
647 if (!item->report && !nfnetlink_has_listeners(net, group))
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200648 return 0;
Patrick McHardya2427692006-03-20 18:03:59 -0800649
Pablo Neira Ayuso03b64f52009-06-02 20:08:27 +0200650 skb = nlmsg_new(ctnetlink_nlmsg_size(ct), GFP_ATOMIC);
651 if (skb == NULL)
Pablo Neira Ayuso150ace02009-04-17 17:47:31 +0200652 goto errout;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800653
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800654 type |= NFNL_SUBSYS_CTNETLINK << 8;
Eric W. Biederman15e47302012-09-07 20:12:54 +0000655 nlh = nlmsg_put(skb, item->portid, 0, type, sizeof(*nfmsg), flags);
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200656 if (nlh == NULL)
657 goto nlmsg_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800658
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200659 nfmsg = nlmsg_data(nlh);
Patrick McHardy5e8fbe22008-04-14 11:15:52 +0200660 nfmsg->nfgen_family = nf_ct_l3num(ct);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800661 nfmsg->version = NFNETLINK_V0;
662 nfmsg->res_id = 0;
663
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +0100664 rcu_read_lock();
Daniel Borkmanndeedb592015-08-14 16:03:39 +0200665 zone = nf_ct_zone(ct);
666
Patrick McHardydf6fb862007-09-28 14:37:03 -0700667 nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED);
668 if (!nest_parms)
669 goto nla_put_failure;
Pablo Neira Ayusof2f3e382009-06-02 20:03:35 +0200670 if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700671 goto nla_put_failure;
Daniel Borkmanndeedb592015-08-14 16:03:39 +0200672 if (ctnetlink_dump_zone_id(skb, CTA_TUPLE_ZONE, zone,
673 NF_CT_ZONE_DIR_ORIG) < 0)
674 goto nla_put_failure;
Patrick McHardydf6fb862007-09-28 14:37:03 -0700675 nla_nest_end(skb, nest_parms);
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800676
Patrick McHardydf6fb862007-09-28 14:37:03 -0700677 nest_parms = nla_nest_start(skb, CTA_TUPLE_REPLY | NLA_F_NESTED);
678 if (!nest_parms)
679 goto nla_put_failure;
Pablo Neira Ayusof2f3e382009-06-02 20:03:35 +0200680 if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_REPLY)) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700681 goto nla_put_failure;
Daniel Borkmanndeedb592015-08-14 16:03:39 +0200682 if (ctnetlink_dump_zone_id(skb, CTA_TUPLE_ZONE, zone,
683 NF_CT_ZONE_DIR_REPL) < 0)
684 goto nla_put_failure;
Patrick McHardydf6fb862007-09-28 14:37:03 -0700685 nla_nest_end(skb, nest_parms);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800686
Daniel Borkmanndeedb592015-08-14 16:03:39 +0200687 if (ctnetlink_dump_zone_id(skb, CTA_ZONE, zone,
688 NF_CT_DEFAULT_ZONE_DIR) < 0)
David S. Millercc1eb432012-04-01 18:57:48 -0400689 goto nla_put_failure;
Patrick McHardyef00f892010-02-15 18:14:57 +0100690
Eric Leblond1eedf692008-05-13 23:27:11 -0700691 if (ctnetlink_dump_id(skb, ct) < 0)
692 goto nla_put_failure;
693
Fabian Hugelshofere57dce62008-06-09 15:59:58 -0700694 if (ctnetlink_dump_status(skb, ct) < 0)
695 goto nla_put_failure;
696
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200697 if (events & (1 << IPCT_DESTROY)) {
Holger Eitzenberger4542fa42013-09-26 17:31:52 +0200698 if (ctnetlink_dump_acct(skb, ct, type) < 0 ||
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +0100699 ctnetlink_dump_timestamp(skb, ct) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700700 goto nla_put_failure;
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100701 } else {
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100702 if (ctnetlink_dump_timeout(skb, ct) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700703 goto nla_put_failure;
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100704
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200705 if (events & (1 << IPCT_PROTOINFO)
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100706 && ctnetlink_dump_protoinfo(skb, ct) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700707 goto nla_put_failure;
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100708
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200709 if ((events & (1 << IPCT_HELPER) || nfct_help(ct))
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100710 && ctnetlink_dump_helpinfo(skb, ct) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -0700711 goto nla_put_failure;
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100712
Eric Parisff660c82010-10-19 18:17:32 -0400713#ifdef CONFIG_NF_CONNTRACK_SECMARK
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200714 if ((events & (1 << IPCT_SECMARK) || ct->secmark)
Eric Paris1cc63242010-10-13 16:24:54 -0400715 && ctnetlink_dump_secctx(skb, ct) < 0)
Pablo Neira Ayuso37fccd82007-12-17 22:28:41 -0800716 goto nla_put_failure;
Eric Parisff660c82010-10-19 18:17:32 -0400717#endif
Florian Westphal0ceabd82013-01-11 06:30:45 +0000718 if (events & (1 << IPCT_LABEL) &&
719 ctnetlink_dump_labels(skb, ct) < 0)
720 goto nla_put_failure;
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100721
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200722 if (events & (1 << IPCT_RELATED) &&
Pablo Neira Ayuso0f417ce2007-12-17 22:28:19 -0800723 ctnetlink_dump_master(skb, ct) < 0)
724 goto nla_put_failure;
725
Patrick McHardy41d73ec2013-08-27 08:50:12 +0200726 if (events & (1 << IPCT_SEQADJ) &&
727 ctnetlink_dump_ct_seq_adj(skb, ct) < 0)
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -0800728 goto nla_put_failure;
Pablo Neira Ayuso7b621c12006-11-29 02:35:32 +0100729 }
Pablo Neira Ayusob9a37e02006-08-22 00:31:49 -0700730
Eric Leblonda83099a2008-01-31 04:44:27 -0800731#ifdef CONFIG_NF_CONNTRACK_MARK
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +0200732 if ((events & (1 << IPCT_MARK) || ct->mark)
Eric Leblonda83099a2008-01-31 04:44:27 -0800733 && ctnetlink_dump_mark(skb, ct) < 0)
734 goto nla_put_failure;
735#endif
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +0100736 rcu_read_unlock();
Eric Leblonda83099a2008-01-31 04:44:27 -0800737
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200738 nlmsg_end(skb, nlh);
Eric W. Biederman15e47302012-09-07 20:12:54 +0000739 err = nfnetlink_send(skb, net, item->portid, group, item->report,
Alexey Dobriyancd8c20b2010-01-13 16:02:14 +0100740 GFP_ATOMIC);
Pablo Neira Ayusodd7669a2009-06-13 12:30:52 +0200741 if (err == -ENOBUFS || err == -EAGAIN)
742 return -ENOBUFS;
743
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200744 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800745
Patrick McHardydf6fb862007-09-28 14:37:03 -0700746nla_put_failure:
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +0100747 rcu_read_unlock();
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200748 nlmsg_cancel(skb, nlh);
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +0100749nlmsg_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800750 kfree_skb(skb);
Pablo Neira Ayuso150ace02009-04-17 17:47:31 +0200751errout:
Pablo Neira Ayuso37b7ef72010-03-16 13:30:21 +0000752 if (nfnetlink_set_err(net, 0, group, -ENOBUFS) > 0)
753 return -ENOBUFS;
754
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +0200755 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800756}
757#endif /* CONFIG_NF_CONNTRACK_EVENTS */
758
759static int ctnetlink_done(struct netlink_callback *cb)
760{
Patrick McHardy89f2e212006-05-29 18:24:58 -0700761 if (cb->args[1])
762 nf_ct_put((struct nf_conn *)cb->args[1]);
Fabian Frederick397304b2014-06-20 22:38:58 +0200763 kfree(cb->data);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800764 return 0;
765}
766
Kristian Evensen866476f2014-12-24 09:57:10 +0100767struct ctnetlink_filter {
Pablo Neira Ayuso0f298a22012-02-24 14:41:50 +0000768 struct {
769 u_int32_t val;
770 u_int32_t mask;
771 } mark;
772};
773
Kristian Evensen866476f2014-12-24 09:57:10 +0100774static struct ctnetlink_filter *
775ctnetlink_alloc_filter(const struct nlattr * const cda[])
776{
777#ifdef CONFIG_NF_CONNTRACK_MARK
778 struct ctnetlink_filter *filter;
779
780 filter = kzalloc(sizeof(*filter), GFP_KERNEL);
781 if (filter == NULL)
782 return ERR_PTR(-ENOMEM);
783
784 filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK]));
785 filter->mark.mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
786
787 return filter;
788#else
789 return ERR_PTR(-EOPNOTSUPP);
790#endif
791}
792
793static int ctnetlink_filter_match(struct nf_conn *ct, void *data)
794{
795 struct ctnetlink_filter *filter = data;
796
797 if (filter == NULL)
798 return 1;
799
800#ifdef CONFIG_NF_CONNTRACK_MARK
801 if ((ct->mark & filter->mark.mask) == filter->mark.val)
802 return 1;
803#endif
804
805 return 0;
806}
807
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800808static int
809ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
810{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +0100811 struct net *net = sock_net(skb->sk);
Patrick McHardy89f2e212006-05-29 18:24:58 -0700812 struct nf_conn *ct, *last;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800813 struct nf_conntrack_tuple_hash *h;
Eric Dumazetea781f12009-03-25 21:05:46 +0100814 struct hlist_nulls_node *n;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +0200815 struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
Pablo Neira Ayuso87711cb2006-01-05 12:19:23 -0800816 u_int8_t l3proto = nfmsg->nfgen_family;
Hans Schillstrom3b988ec2012-03-05 02:24:29 +0000817 int res;
Jesper Dangaard Brouer93bb0ce2014-03-03 14:46:13 +0100818 spinlock_t *lockp;
819
Patrick McHardyd205dc42006-08-17 18:12:38 -0700820 last = (struct nf_conn *)cb->args[1];
Jesper Dangaard Brouer93bb0ce2014-03-03 14:46:13 +0100821
822 local_bh_disable();
Patrick McHardy9ab99d52010-02-10 14:17:10 +0100823 for (; cb->args[0] < net->ct.htable_size; cb->args[0]++) {
Patrick McHardy89f2e212006-05-29 18:24:58 -0700824restart:
Jesper Dangaard Brouer93bb0ce2014-03-03 14:46:13 +0100825 lockp = &nf_conntrack_locks[cb->args[0] % CONNTRACK_LOCKS];
Sasha Levinb16c2912016-01-18 19:23:51 -0500826 nf_conntrack_lock(lockp);
Jesper Dangaard Brouer93bb0ce2014-03-03 14:46:13 +0100827 if (cb->args[0] >= net->ct.htable_size) {
828 spin_unlock(lockp);
829 goto out;
830 }
Stephen Hemminger13ee6ac2011-01-11 23:54:42 +0100831 hlist_nulls_for_each_entry(h, n, &net->ct.hash[cb->args[0]],
Eric Dumazetea781f12009-03-25 21:05:46 +0100832 hnnode) {
Jozsef Kadlecsik5b1158e2006-12-02 22:07:13 -0800833 if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800834 continue;
835 ct = nf_ct_tuplehash_to_ctrack(h);
Pablo Neira Ayuso87711cb2006-01-05 12:19:23 -0800836 /* Dump entries of a given L3 protocol number.
837 * If it is not specified, ie. l3proto == 0,
838 * then dump everything. */
Patrick McHardy5e8fbe22008-04-14 11:15:52 +0200839 if (l3proto && nf_ct_l3num(ct) != l3proto)
Stephen Hemminger13ee6ac2011-01-11 23:54:42 +0100840 continue;
Patrick McHardyd205dc42006-08-17 18:12:38 -0700841 if (cb->args[1]) {
842 if (ct != last)
Stephen Hemminger13ee6ac2011-01-11 23:54:42 +0100843 continue;
Patrick McHardyd205dc42006-08-17 18:12:38 -0700844 cb->args[1] = 0;
Patrick McHardy89f2e212006-05-29 18:24:58 -0700845 }
Kristian Evensen866476f2014-12-24 09:57:10 +0100846 if (!ctnetlink_filter_match(ct, cb->data))
Pablo Neira Ayuso0f298a22012-02-24 14:41:50 +0000847 continue;
Kristian Evensen866476f2014-12-24 09:57:10 +0100848
Hans Schillstrom3b988ec2012-03-05 02:24:29 +0000849 rcu_read_lock();
850 res =
Eric W. Biederman15e47302012-09-07 20:12:54 +0000851 ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).portid,
Hans Schillstrom3b988ec2012-03-05 02:24:29 +0000852 cb->nlh->nlmsg_seq,
853 NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
854 ct);
855 rcu_read_unlock();
856 if (res < 0) {
Pablo Neira Ayusoc71caf42011-01-24 19:01:07 +0100857 nf_conntrack_get(&ct->ct_general);
Patrick McHardy89f2e212006-05-29 18:24:58 -0700858 cb->args[1] = (unsigned long)ct;
Jesper Dangaard Brouer93bb0ce2014-03-03 14:46:13 +0100859 spin_unlock(lockp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800860 goto out;
Patrick McHardy89f2e212006-05-29 18:24:58 -0700861 }
862 }
Jesper Dangaard Brouer93bb0ce2014-03-03 14:46:13 +0100863 spin_unlock(lockp);
Patrick McHardyd205dc42006-08-17 18:12:38 -0700864 if (cb->args[1]) {
Patrick McHardy89f2e212006-05-29 18:24:58 -0700865 cb->args[1] = 0;
866 goto restart;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800867 }
868 }
Patrick McHardy89f2e212006-05-29 18:24:58 -0700869out:
Jesper Dangaard Brouer93bb0ce2014-03-03 14:46:13 +0100870 local_bh_enable();
Patrick McHardyd205dc42006-08-17 18:12:38 -0700871 if (last)
872 nf_ct_put(last);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800873
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800874 return skb->len;
875}
876
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200877static int ctnetlink_parse_tuple_ip(struct nlattr *attr,
878 struct nf_conntrack_tuple *tuple)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800879{
Patrick McHardydf6fb862007-09-28 14:37:03 -0700880 struct nlattr *tb[CTA_IP_MAX+1];
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800881 struct nf_conntrack_l3proto *l3proto;
882 int ret = 0;
883
Daniel Borkmann130ffbc2013-06-12 17:54:51 +0200884 ret = nla_parse_nested(tb, CTA_IP_MAX, attr, NULL);
885 if (ret < 0)
886 return ret;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800887
Florian Westphalcd915662009-03-18 17:28:37 +0100888 rcu_read_lock();
889 l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800890
Patrick McHardyf73e9242007-09-28 14:39:55 -0700891 if (likely(l3proto->nlattr_to_tuple)) {
892 ret = nla_validate_nested(attr, CTA_IP_MAX,
893 l3proto->nla_policy);
894 if (ret == 0)
895 ret = l3proto->nlattr_to_tuple(tb, tuple);
896 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800897
Florian Westphalcd915662009-03-18 17:28:37 +0100898 rcu_read_unlock();
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800899
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800900 return ret;
901}
902
Patrick McHardyf73e9242007-09-28 14:39:55 -0700903static const struct nla_policy proto_nla_policy[CTA_PROTO_MAX+1] = {
904 [CTA_PROTO_NUM] = { .type = NLA_U8 },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800905};
906
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +0200907static int ctnetlink_parse_tuple_proto(struct nlattr *attr,
908 struct nf_conntrack_tuple *tuple)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800909{
Patrick McHardydf6fb862007-09-28 14:37:03 -0700910 struct nlattr *tb[CTA_PROTO_MAX+1];
Martin Josefsson605dcad2006-11-29 02:35:06 +0100911 struct nf_conntrack_l4proto *l4proto;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800912 int ret = 0;
913
Patrick McHardyf73e9242007-09-28 14:39:55 -0700914 ret = nla_parse_nested(tb, CTA_PROTO_MAX, attr, proto_nla_policy);
915 if (ret < 0)
916 return ret;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800917
Patrick McHardydf6fb862007-09-28 14:37:03 -0700918 if (!tb[CTA_PROTO_NUM])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800919 return -EINVAL;
Patrick McHardy77236b62007-12-17 22:29:45 -0800920 tuple->dst.protonum = nla_get_u8(tb[CTA_PROTO_NUM]);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800921
Florian Westphalcd915662009-03-18 17:28:37 +0100922 rcu_read_lock();
923 l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800924
Patrick McHardyf73e9242007-09-28 14:39:55 -0700925 if (likely(l4proto->nlattr_to_tuple)) {
926 ret = nla_validate_nested(attr, CTA_PROTO_MAX,
927 l4proto->nla_policy);
928 if (ret == 0)
929 ret = l4proto->nlattr_to_tuple(tb, tuple);
930 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800931
Florian Westphalcd915662009-03-18 17:28:37 +0100932 rcu_read_unlock();
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800933
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800934 return ret;
935}
936
Daniel Borkmanndeedb592015-08-14 16:03:39 +0200937static int
938ctnetlink_parse_zone(const struct nlattr *attr,
939 struct nf_conntrack_zone *zone)
940{
Daniel Borkmann5e8018f2015-08-14 16:03:40 +0200941 nf_ct_zone_init(zone, NF_CT_DEFAULT_ZONE_ID,
942 NF_CT_DEFAULT_ZONE_DIR, 0);
Daniel Borkmanndeedb592015-08-14 16:03:39 +0200943#ifdef CONFIG_NF_CONNTRACK_ZONES
944 if (attr)
945 zone->id = ntohs(nla_get_be16(attr));
946#else
947 if (attr)
948 return -EOPNOTSUPP;
949#endif
950 return 0;
951}
952
953static int
954ctnetlink_parse_tuple_zone(struct nlattr *attr, enum ctattr_type type,
955 struct nf_conntrack_zone *zone)
956{
957 int ret;
958
959 if (zone->id != NF_CT_DEFAULT_ZONE_ID)
960 return -EINVAL;
961
962 ret = ctnetlink_parse_zone(attr, zone);
963 if (ret < 0)
964 return ret;
965
966 if (type == CTA_TUPLE_REPLY)
967 zone->dir = NF_CT_ZONE_DIR_REPL;
968 else
969 zone->dir = NF_CT_ZONE_DIR_ORIG;
970
971 return 0;
972}
973
Patrick McHardyd0b02682010-02-10 15:38:33 +0100974static const struct nla_policy tuple_nla_policy[CTA_TUPLE_MAX+1] = {
975 [CTA_TUPLE_IP] = { .type = NLA_NESTED },
976 [CTA_TUPLE_PROTO] = { .type = NLA_NESTED },
Daniel Borkmanndeedb592015-08-14 16:03:39 +0200977 [CTA_TUPLE_ZONE] = { .type = NLA_U16 },
Patrick McHardyd0b02682010-02-10 15:38:33 +0100978};
979
Ilpo Järvinenbb5cf802008-01-05 23:11:31 -0800980static int
Patrick McHardy39938322009-08-25 16:07:58 +0200981ctnetlink_parse_tuple(const struct nlattr * const cda[],
982 struct nf_conntrack_tuple *tuple,
Daniel Borkmanndeedb592015-08-14 16:03:39 +0200983 enum ctattr_type type, u_int8_t l3num,
984 struct nf_conntrack_zone *zone)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800985{
Patrick McHardydf6fb862007-09-28 14:37:03 -0700986 struct nlattr *tb[CTA_TUPLE_MAX+1];
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800987 int err;
988
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800989 memset(tuple, 0, sizeof(*tuple));
990
Daniel Borkmann130ffbc2013-06-12 17:54:51 +0200991 err = nla_parse_nested(tb, CTA_TUPLE_MAX, cda[type], tuple_nla_policy);
992 if (err < 0)
993 return err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800994
Patrick McHardydf6fb862007-09-28 14:37:03 -0700995 if (!tb[CTA_TUPLE_IP])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -0800996 return -EINVAL;
997
998 tuple->src.l3num = l3num;
999
Patrick McHardydf6fb862007-09-28 14:37:03 -07001000 err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP], tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001001 if (err < 0)
1002 return err;
1003
Patrick McHardydf6fb862007-09-28 14:37:03 -07001004 if (!tb[CTA_TUPLE_PROTO])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001005 return -EINVAL;
1006
Patrick McHardydf6fb862007-09-28 14:37:03 -07001007 err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO], tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001008 if (err < 0)
1009 return err;
1010
Daniel Borkmanndeedb592015-08-14 16:03:39 +02001011 if (tb[CTA_TUPLE_ZONE]) {
1012 if (!zone)
1013 return -EINVAL;
1014
1015 err = ctnetlink_parse_tuple_zone(tb[CTA_TUPLE_ZONE],
1016 type, zone);
1017 if (err < 0)
1018 return err;
1019 }
1020
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001021 /* orig and expect tuples get DIR_ORIGINAL */
1022 if (type == CTA_TUPLE_REPLY)
1023 tuple->dst.dir = IP_CT_DIR_REPLY;
1024 else
1025 tuple->dst.dir = IP_CT_DIR_ORIGINAL;
1026
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001027 return 0;
1028}
1029
Patrick McHardyd0b02682010-02-10 15:38:33 +01001030static const struct nla_policy help_nla_policy[CTA_HELP_MAX+1] = {
Florian Westphal6d1fafc2012-11-22 01:32:46 +00001031 [CTA_HELP_NAME] = { .type = NLA_NUL_STRING,
1032 .len = NF_CT_HELPER_NAME_LEN - 1 },
Patrick McHardyd0b02682010-02-10 15:38:33 +01001033};
1034
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +02001035static int ctnetlink_parse_help(const struct nlattr *attr, char **helper_name,
1036 struct nlattr **helpinfo)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001037{
Daniel Borkmann130ffbc2013-06-12 17:54:51 +02001038 int err;
Patrick McHardydf6fb862007-09-28 14:37:03 -07001039 struct nlattr *tb[CTA_HELP_MAX+1];
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001040
Daniel Borkmann130ffbc2013-06-12 17:54:51 +02001041 err = nla_parse_nested(tb, CTA_HELP_MAX, attr, help_nla_policy);
1042 if (err < 0)
1043 return err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001044
Patrick McHardydf6fb862007-09-28 14:37:03 -07001045 if (!tb[CTA_HELP_NAME])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001046 return -EINVAL;
1047
Patrick McHardydf6fb862007-09-28 14:37:03 -07001048 *helper_name = nla_data(tb[CTA_HELP_NAME]);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001049
Pablo Neira Ayusoae243be2012-06-07 14:19:42 +02001050 if (tb[CTA_HELP_INFO])
1051 *helpinfo = tb[CTA_HELP_INFO];
1052
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001053 return 0;
1054}
1055
Patrick McHardyf73e9242007-09-28 14:39:55 -07001056static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
Patrick McHardyd0b02682010-02-10 15:38:33 +01001057 [CTA_TUPLE_ORIG] = { .type = NLA_NESTED },
1058 [CTA_TUPLE_REPLY] = { .type = NLA_NESTED },
Patrick McHardyf73e9242007-09-28 14:39:55 -07001059 [CTA_STATUS] = { .type = NLA_U32 },
Patrick McHardyd0b02682010-02-10 15:38:33 +01001060 [CTA_PROTOINFO] = { .type = NLA_NESTED },
1061 [CTA_HELP] = { .type = NLA_NESTED },
1062 [CTA_NAT_SRC] = { .type = NLA_NESTED },
Patrick McHardyf73e9242007-09-28 14:39:55 -07001063 [CTA_TIMEOUT] = { .type = NLA_U32 },
1064 [CTA_MARK] = { .type = NLA_U32 },
Patrick McHardyf73e9242007-09-28 14:39:55 -07001065 [CTA_ID] = { .type = NLA_U32 },
Patrick McHardyd0b02682010-02-10 15:38:33 +01001066 [CTA_NAT_DST] = { .type = NLA_NESTED },
1067 [CTA_TUPLE_MASTER] = { .type = NLA_NESTED },
Florian Westphal6d1fafc2012-11-22 01:32:46 +00001068 [CTA_NAT_SEQ_ADJ_ORIG] = { .type = NLA_NESTED },
1069 [CTA_NAT_SEQ_ADJ_REPLY] = { .type = NLA_NESTED },
Patrick McHardyef00f892010-02-15 18:14:57 +01001070 [CTA_ZONE] = { .type = NLA_U16 },
Pablo Neira Ayuso0f298a22012-02-24 14:41:50 +00001071 [CTA_MARK_MASK] = { .type = NLA_U32 },
Florian Westphal9b21f6a2013-01-11 06:30:46 +00001072 [CTA_LABELS] = { .type = NLA_BINARY,
Florian Westphald2bf2f32014-02-18 15:25:32 +01001073 .len = NF_CT_LABELS_MAX_SIZE },
Florian Westphal9b21f6a2013-01-11 06:30:46 +00001074 [CTA_LABELS_MASK] = { .type = NLA_BINARY,
Florian Westphald2bf2f32014-02-18 15:25:32 +01001075 .len = NF_CT_LABELS_MAX_SIZE },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001076};
1077
Kristian Evensen866476f2014-12-24 09:57:10 +01001078static int ctnetlink_flush_conntrack(struct net *net,
1079 const struct nlattr * const cda[],
1080 u32 portid, int report)
1081{
1082 struct ctnetlink_filter *filter = NULL;
1083
1084 if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) {
1085 filter = ctnetlink_alloc_filter(cda);
1086 if (IS_ERR(filter))
1087 return PTR_ERR(filter);
1088 }
1089
1090 nf_ct_iterate_cleanup(net, ctnetlink_filter_match, filter,
1091 portid, report);
1092 kfree(filter);
1093
1094 return 0;
1095}
1096
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01001097static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
1098 struct sk_buff *skb,
1099 const struct nlmsghdr *nlh,
1100 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001101{
1102 struct nf_conntrack_tuple_hash *h;
1103 struct nf_conntrack_tuple tuple;
1104 struct nf_conn *ct;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001105 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001106 u_int8_t u3 = nfmsg->nfgen_family;
Daniel Borkmann308ac912015-08-08 21:40:01 +02001107 struct nf_conntrack_zone zone;
Patrick McHardyef00f892010-02-15 18:14:57 +01001108 int err;
1109
1110 err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
1111 if (err < 0)
1112 return err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001113
Patrick McHardydf6fb862007-09-28 14:37:03 -07001114 if (cda[CTA_TUPLE_ORIG])
Daniel Borkmanndeedb592015-08-14 16:03:39 +02001115 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG,
1116 u3, &zone);
Patrick McHardydf6fb862007-09-28 14:37:03 -07001117 else if (cda[CTA_TUPLE_REPLY])
Daniel Borkmanndeedb592015-08-14 16:03:39 +02001118 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY,
1119 u3, &zone);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001120 else {
Kristian Evensen866476f2014-12-24 09:57:10 +01001121 return ctnetlink_flush_conntrack(net, cda,
1122 NETLINK_CB(skb).portid,
1123 nlmsg_report(nlh));
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001124 }
1125
1126 if (err < 0)
1127 return err;
1128
Daniel Borkmann308ac912015-08-08 21:40:01 +02001129 h = nf_conntrack_find_get(net, &zone, &tuple);
Pablo Neira Ayuso9ea8cfd2006-10-12 14:09:16 -07001130 if (!h)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001131 return -ENOENT;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001132
1133 ct = nf_ct_tuplehash_to_ctrack(h);
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001134
Patrick McHardydf6fb862007-09-28 14:37:03 -07001135 if (cda[CTA_ID]) {
Patrick McHardy77236b62007-12-17 22:29:45 -08001136 u_int32_t id = ntohl(nla_get_be32(cda[CTA_ID]));
Patrick McHardy7f85f912007-09-28 14:41:27 -07001137 if (id != (u32)(unsigned long)ct) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001138 nf_ct_put(ct);
1139 return -ENOENT;
1140 }
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001141 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001142
Florian Westphal02982c22013-07-29 15:41:54 +02001143 if (del_timer(&ct->timeout))
1144 nf_ct_delete(ct, NETLINK_CB(skb).portid, nlmsg_report(nlh));
1145
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001146 nf_ct_put(ct);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001147
1148 return 0;
1149}
1150
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01001151static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
1152 struct sk_buff *skb,
1153 const struct nlmsghdr *nlh,
1154 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001155{
1156 struct nf_conntrack_tuple_hash *h;
1157 struct nf_conntrack_tuple tuple;
1158 struct nf_conn *ct;
1159 struct sk_buff *skb2 = NULL;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001160 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001161 u_int8_t u3 = nfmsg->nfgen_family;
Daniel Borkmann308ac912015-08-08 21:40:01 +02001162 struct nf_conntrack_zone zone;
Patrick McHardyef00f892010-02-15 18:14:57 +01001163 int err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001164
Pablo Neira Ayuso80d326f2012-02-24 14:30:15 +00001165 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1166 struct netlink_dump_control c = {
1167 .dump = ctnetlink_dump_table,
1168 .done = ctnetlink_done,
1169 };
Kristian Evensen866476f2014-12-24 09:57:10 +01001170
Pablo Neira Ayuso0f298a22012-02-24 14:41:50 +00001171 if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) {
Kristian Evensen866476f2014-12-24 09:57:10 +01001172 struct ctnetlink_filter *filter;
Pablo Neira Ayuso0f298a22012-02-24 14:41:50 +00001173
Kristian Evensen866476f2014-12-24 09:57:10 +01001174 filter = ctnetlink_alloc_filter(cda);
1175 if (IS_ERR(filter))
1176 return PTR_ERR(filter);
Pablo Neira Ayuso0f298a22012-02-24 14:41:50 +00001177
Pablo Neira Ayuso0f298a22012-02-24 14:41:50 +00001178 c.data = filter;
1179 }
Pablo Neira Ayuso80d326f2012-02-24 14:30:15 +00001180 return netlink_dump_start(ctnl, skb, nlh, &c);
1181 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001182
Patrick McHardyef00f892010-02-15 18:14:57 +01001183 err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
1184 if (err < 0)
1185 return err;
1186
Patrick McHardydf6fb862007-09-28 14:37:03 -07001187 if (cda[CTA_TUPLE_ORIG])
Daniel Borkmanndeedb592015-08-14 16:03:39 +02001188 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG,
1189 u3, &zone);
Patrick McHardydf6fb862007-09-28 14:37:03 -07001190 else if (cda[CTA_TUPLE_REPLY])
Daniel Borkmanndeedb592015-08-14 16:03:39 +02001191 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY,
1192 u3, &zone);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001193 else
1194 return -EINVAL;
1195
1196 if (err < 0)
1197 return err;
1198
Daniel Borkmann308ac912015-08-08 21:40:01 +02001199 h = nf_conntrack_find_get(net, &zone, &tuple);
Pablo Neira Ayuso9ea8cfd2006-10-12 14:09:16 -07001200 if (!h)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001201 return -ENOENT;
Pablo Neira Ayuso9ea8cfd2006-10-12 14:09:16 -07001202
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001203 ct = nf_ct_tuplehash_to_ctrack(h);
1204
1205 err = -ENOMEM;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001206 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1207 if (skb2 == NULL) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001208 nf_ct_put(ct);
1209 return -ENOMEM;
1210 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001211
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001212 rcu_read_lock();
Eric W. Biederman15e47302012-09-07 20:12:54 +00001213 err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
Pablo Neira Ayuso80e60e62011-12-24 14:11:39 +01001214 NFNL_MSG_TYPE(nlh->nlmsg_type), ct);
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01001215 rcu_read_unlock();
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001216 nf_ct_put(ct);
1217 if (err <= 0)
1218 goto free;
1219
Eric W. Biederman15e47302012-09-07 20:12:54 +00001220 err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001221 if (err < 0)
1222 goto out;
1223
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001224 return 0;
1225
1226free:
1227 kfree_skb(skb2);
1228out:
Pablo Neira Ayusof31e8d492011-01-13 14:19:55 +01001229 /* this avoids a loop in nfnetlink. */
1230 return err == -EAGAIN ? -ENOBUFS : err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001231}
1232
Pablo Neira Ayusod871bef2012-11-27 14:49:42 +01001233static int ctnetlink_done_list(struct netlink_callback *cb)
1234{
1235 if (cb->args[1])
1236 nf_ct_put((struct nf_conn *)cb->args[1]);
1237 return 0;
1238}
1239
1240static int
Jesper Dangaard Brouerb7779d02014-03-03 14:45:20 +01001241ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying)
Pablo Neira Ayusod871bef2012-11-27 14:49:42 +01001242{
Florian Westphalcd5f3362014-06-08 11:41:23 +02001243 struct nf_conn *ct, *last;
Pablo Neira Ayusod871bef2012-11-27 14:49:42 +01001244 struct nf_conntrack_tuple_hash *h;
1245 struct hlist_nulls_node *n;
1246 struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
1247 u_int8_t l3proto = nfmsg->nfgen_family;
1248 int res;
Jesper Dangaard Brouerb7779d02014-03-03 14:45:20 +01001249 int cpu;
1250 struct hlist_nulls_head *list;
1251 struct net *net = sock_net(skb->sk);
Pablo Neira Ayusod871bef2012-11-27 14:49:42 +01001252
1253 if (cb->args[2])
1254 return 0;
1255
Florian Westphalcd5f3362014-06-08 11:41:23 +02001256 last = (struct nf_conn *)cb->args[1];
1257
Jesper Dangaard Brouerb7779d02014-03-03 14:45:20 +01001258 for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) {
1259 struct ct_pcpu *pcpu;
1260
1261 if (!cpu_possible(cpu))
Pablo Neira Ayusod871bef2012-11-27 14:49:42 +01001262 continue;
Jesper Dangaard Brouerb7779d02014-03-03 14:45:20 +01001263
1264 pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
1265 spin_lock_bh(&pcpu->lock);
Jesper Dangaard Brouerb7779d02014-03-03 14:45:20 +01001266 list = dying ? &pcpu->dying : &pcpu->unconfirmed;
1267restart:
1268 hlist_nulls_for_each_entry(h, n, list, hnnode) {
1269 ct = nf_ct_tuplehash_to_ctrack(h);
1270 if (l3proto && nf_ct_l3num(ct) != l3proto)
Pablo Neira Ayusod871bef2012-11-27 14:49:42 +01001271 continue;
Jesper Dangaard Brouerb7779d02014-03-03 14:45:20 +01001272 if (cb->args[1]) {
1273 if (ct != last)
1274 continue;
1275 cb->args[1] = 0;
1276 }
1277 rcu_read_lock();
1278 res = ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).portid,
1279 cb->nlh->nlmsg_seq,
1280 NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
1281 ct);
1282 rcu_read_unlock();
1283 if (res < 0) {
Florian Westphalcd5f3362014-06-08 11:41:23 +02001284 if (!atomic_inc_not_zero(&ct->ct_general.use))
1285 continue;
Pablo Neira Ayuso266155b2014-06-05 14:28:44 +02001286 cb->args[0] = cpu;
Jesper Dangaard Brouerb7779d02014-03-03 14:45:20 +01001287 cb->args[1] = (unsigned long)ct;
1288 spin_unlock_bh(&pcpu->lock);
1289 goto out;
1290 }
1291 }
1292 if (cb->args[1]) {
Pablo Neira Ayusod871bef2012-11-27 14:49:42 +01001293 cb->args[1] = 0;
Jesper Dangaard Brouerb7779d02014-03-03 14:45:20 +01001294 goto restart;
Pablo Neira Ayuso266155b2014-06-05 14:28:44 +02001295 }
Jesper Dangaard Brouerb7779d02014-03-03 14:45:20 +01001296 spin_unlock_bh(&pcpu->lock);
Pablo Neira Ayusod871bef2012-11-27 14:49:42 +01001297 }
Pablo Neira Ayuso266155b2014-06-05 14:28:44 +02001298 cb->args[2] = 1;
Pablo Neira Ayusod871bef2012-11-27 14:49:42 +01001299out:
Pablo Neira Ayusod871bef2012-11-27 14:49:42 +01001300 if (last)
1301 nf_ct_put(last);
1302
1303 return skb->len;
1304}
1305
1306static int
1307ctnetlink_dump_dying(struct sk_buff *skb, struct netlink_callback *cb)
1308{
Jesper Dangaard Brouerb7779d02014-03-03 14:45:20 +01001309 return ctnetlink_dump_list(skb, cb, true);
Pablo Neira Ayusod871bef2012-11-27 14:49:42 +01001310}
1311
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01001312static int ctnetlink_get_ct_dying(struct net *net, struct sock *ctnl,
1313 struct sk_buff *skb,
1314 const struct nlmsghdr *nlh,
1315 const struct nlattr * const cda[])
Pablo Neira Ayusod871bef2012-11-27 14:49:42 +01001316{
1317 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1318 struct netlink_dump_control c = {
1319 .dump = ctnetlink_dump_dying,
1320 .done = ctnetlink_done_list,
1321 };
1322 return netlink_dump_start(ctnl, skb, nlh, &c);
1323 }
1324
1325 return -EOPNOTSUPP;
1326}
1327
1328static int
1329ctnetlink_dump_unconfirmed(struct sk_buff *skb, struct netlink_callback *cb)
1330{
Jesper Dangaard Brouerb7779d02014-03-03 14:45:20 +01001331 return ctnetlink_dump_list(skb, cb, false);
Pablo Neira Ayusod871bef2012-11-27 14:49:42 +01001332}
1333
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01001334static int ctnetlink_get_ct_unconfirmed(struct net *net, struct sock *ctnl,
1335 struct sk_buff *skb,
1336 const struct nlmsghdr *nlh,
1337 const struct nlattr * const cda[])
Pablo Neira Ayusod871bef2012-11-27 14:49:42 +01001338{
1339 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1340 struct netlink_dump_control c = {
1341 .dump = ctnetlink_dump_unconfirmed,
1342 .done = ctnetlink_done_list,
1343 };
1344 return netlink_dump_start(ctnl, skb, nlh, &c);
1345 }
1346
1347 return -EOPNOTSUPP;
1348}
1349
Pablo Neira Ayuso67671842008-10-20 03:34:27 -07001350#ifdef CONFIG_NF_NAT_NEEDED
Ilpo Järvinenbb5cf802008-01-05 23:11:31 -08001351static int
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001352ctnetlink_parse_nat_setup(struct nf_conn *ct,
1353 enum nf_nat_manip_type manip,
Patrick McHardy39938322009-08-25 16:07:58 +02001354 const struct nlattr *attr)
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001355{
1356 typeof(nfnetlink_parse_nat_setup_hook) parse_nat_setup;
Patrick McHardyc7232c92012-08-26 19:14:06 +02001357 int err;
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001358
1359 parse_nat_setup = rcu_dereference(nfnetlink_parse_nat_setup_hook);
1360 if (!parse_nat_setup) {
Johannes Berg95a5afc2008-10-16 15:24:51 -07001361#ifdef CONFIG_MODULES
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001362 rcu_read_unlock();
Pablo Neira Ayusoc14b78e2013-02-05 01:50:26 +01001363 nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
Patrick McHardyc7232c92012-08-26 19:14:06 +02001364 if (request_module("nf-nat") < 0) {
Pablo Neira Ayusoc14b78e2013-02-05 01:50:26 +01001365 nfnl_lock(NFNL_SUBSYS_CTNETLINK);
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001366 rcu_read_lock();
1367 return -EOPNOTSUPP;
1368 }
Pablo Neira Ayusoc14b78e2013-02-05 01:50:26 +01001369 nfnl_lock(NFNL_SUBSYS_CTNETLINK);
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001370 rcu_read_lock();
1371 if (nfnetlink_parse_nat_setup_hook)
1372 return -EAGAIN;
1373#endif
1374 return -EOPNOTSUPP;
1375 }
1376
Patrick McHardyc7232c92012-08-26 19:14:06 +02001377 err = parse_nat_setup(ct, manip, attr);
1378 if (err == -EAGAIN) {
1379#ifdef CONFIG_MODULES
1380 rcu_read_unlock();
Pablo Neira Ayusoc14b78e2013-02-05 01:50:26 +01001381 nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
Patrick McHardyc7232c92012-08-26 19:14:06 +02001382 if (request_module("nf-nat-%u", nf_ct_l3num(ct)) < 0) {
Pablo Neira Ayusoc14b78e2013-02-05 01:50:26 +01001383 nfnl_lock(NFNL_SUBSYS_CTNETLINK);
Patrick McHardyc7232c92012-08-26 19:14:06 +02001384 rcu_read_lock();
1385 return -EOPNOTSUPP;
1386 }
Pablo Neira Ayusoc14b78e2013-02-05 01:50:26 +01001387 nfnl_lock(NFNL_SUBSYS_CTNETLINK);
Patrick McHardyc7232c92012-08-26 19:14:06 +02001388 rcu_read_lock();
1389#else
1390 err = -EOPNOTSUPP;
1391#endif
1392 }
1393 return err;
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001394}
Pablo Neira Ayuso67671842008-10-20 03:34:27 -07001395#endif
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001396
1397static int
Patrick McHardy39938322009-08-25 16:07:58 +02001398ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001399{
1400 unsigned long d;
Patrick McHardy77236b62007-12-17 22:29:45 -08001401 unsigned int status = ntohl(nla_get_be32(cda[CTA_STATUS]));
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001402 d = ct->status ^ status;
1403
1404 if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
1405 /* unchangeable */
Pablo Neira Ayuso0adf9d62008-06-09 15:56:20 -07001406 return -EBUSY;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001407
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001408 if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
1409 /* SEEN_REPLY bit can only be set */
Pablo Neira Ayuso0adf9d62008-06-09 15:56:20 -07001410 return -EBUSY;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001411
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001412 if (d & IPS_ASSURED && !(status & IPS_ASSURED))
1413 /* ASSURED bit can only be set */
Pablo Neira Ayuso0adf9d62008-06-09 15:56:20 -07001414 return -EBUSY;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001415
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001416 /* Be careful here, modifying NAT bits can screw up things,
1417 * so don't let users modify them directly if they don't pass
Jozsef Kadlecsik5b1158e2006-12-02 22:07:13 -08001418 * nf_nat_range. */
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001419 ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);
1420 return 0;
1421}
1422
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001423static int
Pablo Neira Ayuso0eba8012014-02-16 12:15:43 +01001424ctnetlink_setup_nat(struct nf_conn *ct, const struct nlattr * const cda[])
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001425{
1426#ifdef CONFIG_NF_NAT_NEEDED
1427 int ret;
1428
Florian Westphalfe337ac2014-04-28 21:07:31 +02001429 if (!cda[CTA_NAT_DST] && !cda[CTA_NAT_SRC])
1430 return 0;
1431
Pablo Neira Ayuso0eba8012014-02-16 12:15:43 +01001432 ret = ctnetlink_parse_nat_setup(ct, NF_NAT_MANIP_DST,
1433 cda[CTA_NAT_DST]);
1434 if (ret < 0)
1435 return ret;
1436
1437 ret = ctnetlink_parse_nat_setup(ct, NF_NAT_MANIP_SRC,
1438 cda[CTA_NAT_SRC]);
1439 return ret;
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001440#else
Pablo Neira Ayuso0eba8012014-02-16 12:15:43 +01001441 if (!cda[CTA_NAT_DST] && !cda[CTA_NAT_SRC])
1442 return 0;
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001443 return -EOPNOTSUPP;
1444#endif
1445}
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001446
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +02001447static int ctnetlink_change_helper(struct nf_conn *ct,
1448 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001449{
1450 struct nf_conntrack_helper *helper;
Harald Weltedc808fe2006-03-20 17:56:32 -08001451 struct nf_conn_help *help = nfct_help(ct);
Pablo Neira Ayuso29fe1b42009-04-22 02:26:37 -07001452 char *helpname = NULL;
Pablo Neira Ayusoae243be2012-06-07 14:19:42 +02001453 struct nlattr *helpinfo = NULL;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001454 int err;
1455
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001456 /* don't change helper of sibling connections */
1457 if (ct->master)
Pablo Neira Ayuso0adf9d62008-06-09 15:56:20 -07001458 return -EBUSY;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001459
Pablo Neira Ayusoae243be2012-06-07 14:19:42 +02001460 err = ctnetlink_parse_help(cda[CTA_HELP], &helpname, &helpinfo);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001461 if (err < 0)
1462 return err;
1463
Yasuyuki Kozakaidf293bb2007-05-10 14:15:58 -07001464 if (!strcmp(helpname, "")) {
1465 if (help && help->helper) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001466 /* we had a helper before ... */
1467 nf_ct_remove_expectations(ct);
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001468 RCU_INIT_POINTER(help->helper, NULL);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001469 }
Yasuyuki Kozakaidf293bb2007-05-10 14:15:58 -07001470
1471 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001472 }
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001473
Patrick McHardy794e6872010-02-03 13:41:29 +01001474 helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
1475 nf_ct_protonum(ct));
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001476 if (helper == NULL) {
1477#ifdef CONFIG_MODULES
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01001478 spin_unlock_bh(&nf_conntrack_expect_lock);
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001479
1480 if (request_module("nfct-helper-%s", helpname) < 0) {
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01001481 spin_lock_bh(&nf_conntrack_expect_lock);
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001482 return -EOPNOTSUPP;
1483 }
1484
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01001485 spin_lock_bh(&nf_conntrack_expect_lock);
Patrick McHardy794e6872010-02-03 13:41:29 +01001486 helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
1487 nf_ct_protonum(ct));
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001488 if (helper)
1489 return -EAGAIN;
1490#endif
Pablo Neira Ayuso0adf9d62008-06-09 15:56:20 -07001491 return -EOPNOTSUPP;
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001492 }
Yasuyuki Kozakaidf293bb2007-05-10 14:15:58 -07001493
Yasuyuki Kozakaiceceae12007-07-07 22:23:42 -07001494 if (help) {
Pablo Neira Ayusoae243be2012-06-07 14:19:42 +02001495 if (help->helper == helper) {
1496 /* update private helper data if allowed. */
Pablo Neira Ayuso7be54ca2012-09-21 16:52:08 +02001497 if (helper->from_nlattr)
Pablo Neira Ayusoae243be2012-06-07 14:19:42 +02001498 helper->from_nlattr(helpinfo, ct);
Yasuyuki Kozakaiceceae12007-07-07 22:23:42 -07001499 return 0;
Pablo Neira Ayusofd7462d2012-06-18 17:29:53 +02001500 } else
Yasuyuki Kozakaiceceae12007-07-07 22:23:42 -07001501 return -EBUSY;
Yasuyuki Kozakaiceceae12007-07-07 22:23:42 -07001502 }
Yasuyuki Kozakaidf293bb2007-05-10 14:15:58 -07001503
Pablo Neira Ayusofd7462d2012-06-18 17:29:53 +02001504 /* we cannot set a helper for an existing conntrack */
1505 return -EOPNOTSUPP;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001506}
1507
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +02001508static int ctnetlink_change_timeout(struct nf_conn *ct,
1509 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001510{
Patrick McHardy77236b62007-12-17 22:29:45 -08001511 u_int32_t timeout = ntohl(nla_get_be32(cda[CTA_TIMEOUT]));
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08001512
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001513 if (!del_timer(&ct->timeout))
1514 return -ETIME;
1515
1516 ct->timeout.expires = jiffies + timeout * HZ;
1517 add_timer(&ct->timeout);
1518
1519 return 0;
1520}
1521
Patrick McHardyd0b02682010-02-10 15:38:33 +01001522static const struct nla_policy protoinfo_policy[CTA_PROTOINFO_MAX+1] = {
1523 [CTA_PROTOINFO_TCP] = { .type = NLA_NESTED },
1524 [CTA_PROTOINFO_DCCP] = { .type = NLA_NESTED },
1525 [CTA_PROTOINFO_SCTP] = { .type = NLA_NESTED },
1526};
1527
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +02001528static int ctnetlink_change_protoinfo(struct nf_conn *ct,
1529 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001530{
Patrick McHardy39938322009-08-25 16:07:58 +02001531 const struct nlattr *attr = cda[CTA_PROTOINFO];
1532 struct nlattr *tb[CTA_PROTOINFO_MAX+1];
Martin Josefsson605dcad2006-11-29 02:35:06 +01001533 struct nf_conntrack_l4proto *l4proto;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001534 int err = 0;
1535
Daniel Borkmann130ffbc2013-06-12 17:54:51 +02001536 err = nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, protoinfo_policy);
1537 if (err < 0)
1538 return err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001539
Florian Westphalcd915662009-03-18 17:28:37 +01001540 rcu_read_lock();
1541 l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
Patrick McHardyfdf70832007-09-28 14:37:41 -07001542 if (l4proto->from_nlattr)
1543 err = l4proto->from_nlattr(tb, ct);
Florian Westphalcd915662009-03-18 17:28:37 +01001544 rcu_read_unlock();
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001545
1546 return err;
1547}
1548
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001549static const struct nla_policy seqadj_policy[CTA_SEQADJ_MAX+1] = {
1550 [CTA_SEQADJ_CORRECTION_POS] = { .type = NLA_U32 },
1551 [CTA_SEQADJ_OFFSET_BEFORE] = { .type = NLA_U32 },
1552 [CTA_SEQADJ_OFFSET_AFTER] = { .type = NLA_U32 },
Patrick McHardyd0b02682010-02-10 15:38:33 +01001553};
1554
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +02001555static int change_seq_adj(struct nf_ct_seqadj *seq,
1556 const struct nlattr * const attr)
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001557{
Daniel Borkmann130ffbc2013-06-12 17:54:51 +02001558 int err;
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001559 struct nlattr *cda[CTA_SEQADJ_MAX+1];
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001560
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001561 err = nla_parse_nested(cda, CTA_SEQADJ_MAX, attr, seqadj_policy);
Daniel Borkmann130ffbc2013-06-12 17:54:51 +02001562 if (err < 0)
1563 return err;
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001564
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001565 if (!cda[CTA_SEQADJ_CORRECTION_POS])
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001566 return -EINVAL;
1567
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001568 seq->correction_pos =
1569 ntohl(nla_get_be32(cda[CTA_SEQADJ_CORRECTION_POS]));
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001570
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001571 if (!cda[CTA_SEQADJ_OFFSET_BEFORE])
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001572 return -EINVAL;
1573
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001574 seq->offset_before =
1575 ntohl(nla_get_be32(cda[CTA_SEQADJ_OFFSET_BEFORE]));
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001576
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001577 if (!cda[CTA_SEQADJ_OFFSET_AFTER])
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001578 return -EINVAL;
1579
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001580 seq->offset_after =
1581 ntohl(nla_get_be32(cda[CTA_SEQADJ_OFFSET_AFTER]));
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001582
1583 return 0;
1584}
1585
1586static int
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001587ctnetlink_change_seq_adj(struct nf_conn *ct,
1588 const struct nlattr * const cda[])
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001589{
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001590 struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001591 int ret = 0;
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001592
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001593 if (!seqadj)
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001594 return 0;
1595
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001596 if (cda[CTA_SEQ_ADJ_ORIG]) {
1597 ret = change_seq_adj(&seqadj->seq[IP_CT_DIR_ORIGINAL],
1598 cda[CTA_SEQ_ADJ_ORIG]);
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001599 if (ret < 0)
1600 return ret;
1601
1602 ct->status |= IPS_SEQ_ADJUST;
1603 }
1604
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001605 if (cda[CTA_SEQ_ADJ_REPLY]) {
1606 ret = change_seq_adj(&seqadj->seq[IP_CT_DIR_REPLY],
1607 cda[CTA_SEQ_ADJ_REPLY]);
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001608 if (ret < 0)
1609 return ret;
1610
1611 ct->status |= IPS_SEQ_ADJUST;
1612 }
1613
1614 return 0;
1615}
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001616
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001617static int
Florian Westphal9b21f6a2013-01-11 06:30:46 +00001618ctnetlink_attach_labels(struct nf_conn *ct, const struct nlattr * const cda[])
1619{
1620#ifdef CONFIG_NF_CONNTRACK_LABELS
1621 size_t len = nla_len(cda[CTA_LABELS]);
1622 const void *mask = cda[CTA_LABELS_MASK];
1623
1624 if (len & (sizeof(u32)-1)) /* must be multiple of u32 */
1625 return -EINVAL;
1626
1627 if (mask) {
1628 if (nla_len(cda[CTA_LABELS_MASK]) == 0 ||
1629 nla_len(cda[CTA_LABELS_MASK]) != len)
1630 return -EINVAL;
1631 mask = nla_data(cda[CTA_LABELS_MASK]);
1632 }
1633
1634 len /= sizeof(u32);
1635
1636 return nf_connlabels_replace(ct, nla_data(cda[CTA_LABELS]), mask, len);
1637#else
1638 return -EOPNOTSUPP;
1639#endif
1640}
1641
1642static int
Patrick McHardy39938322009-08-25 16:07:58 +02001643ctnetlink_change_conntrack(struct nf_conn *ct,
1644 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001645{
1646 int err;
1647
Pablo Neira Ayusoe0983602009-03-16 15:27:22 +01001648 /* only allow NAT changes and master assignation for new conntracks */
1649 if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST] || cda[CTA_TUPLE_MASTER])
1650 return -EOPNOTSUPP;
1651
Patrick McHardydf6fb862007-09-28 14:37:03 -07001652 if (cda[CTA_HELP]) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001653 err = ctnetlink_change_helper(ct, cda);
1654 if (err < 0)
1655 return err;
1656 }
1657
Patrick McHardydf6fb862007-09-28 14:37:03 -07001658 if (cda[CTA_TIMEOUT]) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001659 err = ctnetlink_change_timeout(ct, cda);
1660 if (err < 0)
1661 return err;
1662 }
1663
Patrick McHardydf6fb862007-09-28 14:37:03 -07001664 if (cda[CTA_STATUS]) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001665 err = ctnetlink_change_status(ct, cda);
1666 if (err < 0)
1667 return err;
1668 }
1669
Patrick McHardydf6fb862007-09-28 14:37:03 -07001670 if (cda[CTA_PROTOINFO]) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001671 err = ctnetlink_change_protoinfo(ct, cda);
1672 if (err < 0)
1673 return err;
1674 }
1675
Martin Josefssonbcd1e832006-04-01 02:23:21 -08001676#if defined(CONFIG_NF_CONNTRACK_MARK)
Patrick McHardydf6fb862007-09-28 14:37:03 -07001677 if (cda[CTA_MARK])
Patrick McHardy77236b62007-12-17 22:29:45 -08001678 ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001679#endif
1680
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001681 if (cda[CTA_SEQ_ADJ_ORIG] || cda[CTA_SEQ_ADJ_REPLY]) {
1682 err = ctnetlink_change_seq_adj(ct, cda);
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001683 if (err < 0)
1684 return err;
1685 }
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001686
Florian Westphal9b21f6a2013-01-11 06:30:46 +00001687 if (cda[CTA_LABELS]) {
1688 err = ctnetlink_attach_labels(ct, cda);
1689 if (err < 0)
1690 return err;
1691 }
Pablo Neira Ayuso13eae152007-12-17 22:28:00 -08001692
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001693 return 0;
1694}
1695
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001696static struct nf_conn *
Daniel Borkmann308ac912015-08-08 21:40:01 +02001697ctnetlink_create_conntrack(struct net *net,
1698 const struct nf_conntrack_zone *zone,
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01001699 const struct nlattr * const cda[],
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001700 struct nf_conntrack_tuple *otuple,
Pablo Neira Ayuso5faa1f42007-09-28 14:43:53 -07001701 struct nf_conntrack_tuple *rtuple,
Pablo Neira Ayuso7ec47492009-03-16 15:25:46 +01001702 u8 u3)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001703{
1704 struct nf_conn *ct;
1705 int err = -EINVAL;
Yasuyuki Kozakaiceceae12007-07-07 22:23:42 -07001706 struct nf_conntrack_helper *helper;
Pablo Neira Ayuso315c34d2011-04-21 10:55:07 +02001707 struct nf_conn_tstamp *tstamp;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001708
Patrick McHardyef00f892010-02-15 18:14:57 +01001709 ct = nf_conntrack_alloc(net, zone, otuple, rtuple, GFP_ATOMIC);
Julia Lawallcd7fcbf2009-01-12 00:06:08 +00001710 if (IS_ERR(ct))
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001711 return ERR_PTR(-ENOMEM);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001712
Patrick McHardydf6fb862007-09-28 14:37:03 -07001713 if (!cda[CTA_TIMEOUT])
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001714 goto err1;
Patrick McHardy77236b62007-12-17 22:29:45 -08001715 ct->timeout.expires = ntohl(nla_get_be32(cda[CTA_TIMEOUT]));
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001716
1717 ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001718
Patrick McHardy58a3c9b2008-01-31 04:36:54 -08001719 rcu_read_lock();
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001720 if (cda[CTA_HELP]) {
Pablo Neira Ayuso29fe1b42009-04-22 02:26:37 -07001721 char *helpname = NULL;
Pablo Neira Ayusoae243be2012-06-07 14:19:42 +02001722 struct nlattr *helpinfo = NULL;
1723
1724 err = ctnetlink_parse_help(cda[CTA_HELP], &helpname, &helpinfo);
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001725 if (err < 0)
1726 goto err2;
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001727
Patrick McHardy794e6872010-02-03 13:41:29 +01001728 helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
1729 nf_ct_protonum(ct));
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001730 if (helper == NULL) {
1731 rcu_read_unlock();
1732#ifdef CONFIG_MODULES
1733 if (request_module("nfct-helper-%s", helpname) < 0) {
1734 err = -EOPNOTSUPP;
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001735 goto err1;
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001736 }
1737
1738 rcu_read_lock();
Patrick McHardy794e6872010-02-03 13:41:29 +01001739 helper = __nf_conntrack_helper_find(helpname,
1740 nf_ct_l3num(ct),
1741 nf_ct_protonum(ct));
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001742 if (helper) {
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001743 err = -EAGAIN;
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001744 goto err2;
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001745 }
1746 rcu_read_unlock();
1747#endif
1748 err = -EOPNOTSUPP;
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001749 goto err1;
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001750 } else {
1751 struct nf_conn_help *help;
1752
Pablo Neira Ayuso1afc5672012-06-07 12:11:50 +02001753 help = nf_ct_helper_ext_add(ct, helper, GFP_ATOMIC);
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001754 if (help == NULL) {
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001755 err = -ENOMEM;
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001756 goto err2;
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001757 }
Pablo Neira Ayusoae243be2012-06-07 14:19:42 +02001758 /* set private helper data if allowed. */
Pablo Neira Ayuso7be54ca2012-09-21 16:52:08 +02001759 if (helper->from_nlattr)
Pablo Neira Ayusoae243be2012-06-07 14:19:42 +02001760 helper->from_nlattr(helpinfo, ct);
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001761
1762 /* not in hash table yet so not strictly necessary */
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +00001763 RCU_INIT_POINTER(help->helper, helper);
Pablo Neira Ayuso226c0c02008-11-18 11:54:05 +01001764 }
1765 } else {
1766 /* try an implicit helper assignation */
Patrick McHardyb2a15a62010-02-03 14:13:03 +01001767 err = __nf_ct_try_assign_helper(ct, NULL, GFP_ATOMIC);
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001768 if (err < 0)
1769 goto err2;
Patrick McHarrdy3c158f72007-06-05 12:55:27 -07001770 }
Yasuyuki Kozakaidafc7412006-11-27 10:25:32 -08001771
Pablo Neira Ayuso0eba8012014-02-16 12:15:43 +01001772 err = ctnetlink_setup_nat(ct, cda);
1773 if (err < 0)
1774 goto err2;
Pablo Neira Ayuso1575e7e2008-08-18 21:30:55 -07001775
Pablo Neira Ayusoa88e22a2010-02-19 14:24:39 +01001776 nf_ct_acct_ext_add(ct, GFP_ATOMIC);
Pablo Neira Ayusoa992ca22011-01-19 16:00:07 +01001777 nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
Pablo Neira Ayusoa88e22a2010-02-19 14:24:39 +01001778 nf_ct_ecache_ext_add(ct, 0, 0, GFP_ATOMIC);
Florian Westphalc539f012013-01-11 06:30:44 +00001779 nf_ct_labels_ext_add(ct);
1780
Pablo Neira Ayusoa88e22a2010-02-19 14:24:39 +01001781 /* we must add conntrack extensions before confirmation. */
1782 ct->status |= IPS_CONFIRMED;
1783
1784 if (cda[CTA_STATUS]) {
1785 err = ctnetlink_change_status(ct, cda);
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001786 if (err < 0)
1787 goto err2;
Pablo Neira Ayusoe6a7d3c2008-10-14 11:58:31 -07001788 }
1789
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001790 if (cda[CTA_SEQ_ADJ_ORIG] || cda[CTA_SEQ_ADJ_REPLY]) {
1791 err = ctnetlink_change_seq_adj(ct, cda);
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001792 if (err < 0)
1793 goto err2;
Pablo Neira Ayusoc969aa72009-02-09 14:33:57 -08001794 }
Pablo Neira Ayusoc969aa72009-02-09 14:33:57 -08001795
Changli Gaoe5fc9e72010-11-12 17:33:17 +01001796 memset(&ct->proto, 0, sizeof(ct->proto));
Pablo Neira Ayuso1575e7e2008-08-18 21:30:55 -07001797 if (cda[CTA_PROTOINFO]) {
1798 err = ctnetlink_change_protoinfo(ct, cda);
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001799 if (err < 0)
1800 goto err2;
Pablo Neira Ayuso1575e7e2008-08-18 21:30:55 -07001801 }
1802
Pablo Neira Ayuso1575e7e2008-08-18 21:30:55 -07001803#if defined(CONFIG_NF_CONNTRACK_MARK)
1804 if (cda[CTA_MARK])
1805 ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
1806#endif
1807
Pablo Neira Ayuso5faa1f42007-09-28 14:43:53 -07001808 /* setup master conntrack: this is a confirmed expectation */
Pablo Neira Ayuso7ec47492009-03-16 15:25:46 +01001809 if (cda[CTA_TUPLE_MASTER]) {
1810 struct nf_conntrack_tuple master;
1811 struct nf_conntrack_tuple_hash *master_h;
1812 struct nf_conn *master_ct;
1813
Daniel Borkmanndeedb592015-08-14 16:03:39 +02001814 err = ctnetlink_parse_tuple(cda, &master, CTA_TUPLE_MASTER,
1815 u3, NULL);
Pablo Neira Ayuso7ec47492009-03-16 15:25:46 +01001816 if (err < 0)
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001817 goto err2;
Pablo Neira Ayuso7ec47492009-03-16 15:25:46 +01001818
Patrick McHardyef00f892010-02-15 18:14:57 +01001819 master_h = nf_conntrack_find_get(net, zone, &master);
Pablo Neira Ayuso7ec47492009-03-16 15:25:46 +01001820 if (master_h == NULL) {
1821 err = -ENOENT;
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001822 goto err2;
Pablo Neira Ayuso7ec47492009-03-16 15:25:46 +01001823 }
1824 master_ct = nf_ct_tuplehash_to_ctrack(master_h);
Pablo Neira Ayusof2a89002007-12-12 10:34:29 -08001825 __set_bit(IPS_EXPECTED_BIT, &ct->status);
Pablo Neira Ayuso5faa1f42007-09-28 14:43:53 -07001826 ct->master = master_ct;
Pablo Neira Ayusof2a89002007-12-12 10:34:29 -08001827 }
Pablo Neira Ayuso315c34d2011-04-21 10:55:07 +02001828 tstamp = nf_conn_tstamp_find(ct);
1829 if (tstamp)
Eric Dumazetd2de8752014-08-22 18:32:09 -07001830 tstamp->start = ktime_get_real_ns();
Pablo Neira Ayuso5faa1f42007-09-28 14:43:53 -07001831
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001832 err = nf_conntrack_hash_check_insert(ct);
1833 if (err < 0)
1834 goto err2;
1835
Patrick McHardy58a3c9b2008-01-31 04:36:54 -08001836 rcu_read_unlock();
Yasuyuki Kozakaidafc7412006-11-27 10:25:32 -08001837
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001838 return ct;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001839
Patrick McHardy0f5b3e82009-03-18 17:36:40 +01001840err2:
1841 rcu_read_unlock();
1842err1:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001843 nf_conntrack_free(ct);
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001844 return ERR_PTR(err);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001845}
1846
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01001847static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
1848 struct sk_buff *skb,
1849 const struct nlmsghdr *nlh,
1850 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001851{
1852 struct nf_conntrack_tuple otuple, rtuple;
1853 struct nf_conntrack_tuple_hash *h = NULL;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02001854 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001855 struct nf_conn *ct;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001856 u_int8_t u3 = nfmsg->nfgen_family;
Daniel Borkmann308ac912015-08-08 21:40:01 +02001857 struct nf_conntrack_zone zone;
Patrick McHardyef00f892010-02-15 18:14:57 +01001858 int err;
1859
1860 err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
1861 if (err < 0)
1862 return err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001863
Patrick McHardydf6fb862007-09-28 14:37:03 -07001864 if (cda[CTA_TUPLE_ORIG]) {
Daniel Borkmanndeedb592015-08-14 16:03:39 +02001865 err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG,
1866 u3, &zone);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001867 if (err < 0)
1868 return err;
1869 }
1870
Patrick McHardydf6fb862007-09-28 14:37:03 -07001871 if (cda[CTA_TUPLE_REPLY]) {
Daniel Borkmanndeedb592015-08-14 16:03:39 +02001872 err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY,
1873 u3, &zone);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001874 if (err < 0)
1875 return err;
1876 }
1877
Patrick McHardydf6fb862007-09-28 14:37:03 -07001878 if (cda[CTA_TUPLE_ORIG])
Daniel Borkmann308ac912015-08-08 21:40:01 +02001879 h = nf_conntrack_find_get(net, &zone, &otuple);
Patrick McHardydf6fb862007-09-28 14:37:03 -07001880 else if (cda[CTA_TUPLE_REPLY])
Daniel Borkmann308ac912015-08-08 21:40:01 +02001881 h = nf_conntrack_find_get(net, &zone, &rtuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001882
1883 if (h == NULL) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001884 err = -ENOENT;
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001885 if (nlh->nlmsg_flags & NLM_F_CREATE) {
Pablo Neira Ayusofecc1132009-05-05 17:48:26 +02001886 enum ip_conntrack_events events;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001887
Florian Westphal442fad92013-02-11 23:22:38 +00001888 if (!cda[CTA_TUPLE_ORIG] || !cda[CTA_TUPLE_REPLY])
1889 return -EINVAL;
1890
Daniel Borkmann308ac912015-08-08 21:40:01 +02001891 ct = ctnetlink_create_conntrack(net, &zone, cda, &otuple,
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001892 &rtuple, u3);
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001893 if (IS_ERR(ct))
1894 return PTR_ERR(ct);
1895
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001896 err = 0;
Pablo Neira Ayusofecc1132009-05-05 17:48:26 +02001897 if (test_bit(IPS_EXPECTED_BIT, &ct->status))
1898 events = IPCT_RELATED;
1899 else
1900 events = IPCT_NEW;
1901
Florian Westphal9b21f6a2013-01-11 06:30:46 +00001902 if (cda[CTA_LABELS] &&
1903 ctnetlink_attach_labels(ct, cda) == 0)
1904 events |= (1 << IPCT_LABEL);
1905
Patrick McHardy858b31332010-02-03 13:48:53 +01001906 nf_conntrack_eventmask_report((1 << IPCT_REPLY) |
1907 (1 << IPCT_ASSURED) |
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +02001908 (1 << IPCT_HELPER) |
1909 (1 << IPCT_PROTOINFO) |
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001910 (1 << IPCT_SEQADJ) |
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +02001911 (1 << IPCT_MARK) | events,
Eric W. Biederman15e47302012-09-07 20:12:54 +00001912 ct, NETLINK_CB(skb).portid,
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +02001913 nlmsg_report(nlh));
Pablo Neira Ayusof0a3c082009-03-16 15:28:09 +01001914 nf_ct_put(ct);
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001915 }
Pablo Neira Ayuso5faa1f42007-09-28 14:43:53 -07001916
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001917 return err;
1918 }
1919 /* implicit 'else' */
1920
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001921 err = -EEXIST;
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001922 ct = nf_ct_tuplehash_to_ctrack(h);
Pablo Neira Ayusoff4ca822007-08-07 18:11:26 -07001923 if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01001924 spin_lock_bh(&nf_conntrack_expect_lock);
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +01001925 err = ctnetlink_change_conntrack(ct, cda);
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01001926 spin_unlock_bh(&nf_conntrack_expect_lock);
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +01001927 if (err == 0) {
Patrick McHardy858b31332010-02-03 13:48:53 +01001928 nf_conntrack_eventmask_report((1 << IPCT_REPLY) |
1929 (1 << IPCT_ASSURED) |
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +02001930 (1 << IPCT_HELPER) |
Florian Westphal797a7d62013-06-21 16:51:30 +02001931 (1 << IPCT_LABEL) |
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +02001932 (1 << IPCT_PROTOINFO) |
Patrick McHardy41d73ec2013-08-27 08:50:12 +02001933 (1 << IPCT_SEQADJ) |
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +02001934 (1 << IPCT_MARK),
Eric W. Biederman15e47302012-09-07 20:12:54 +00001935 ct, NETLINK_CB(skb).portid,
Pablo Neira Ayusoa0891aa2009-06-13 12:26:29 +02001936 nlmsg_report(nlh));
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001937 }
Pablo Neira Ayusoff4ca822007-08-07 18:11:26 -07001938 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001939
Jozsef Kadlecsik7d367e02012-02-24 11:45:49 +01001940 nf_ct_put(ct);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08001941 return err;
1942}
1943
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02001944static int
Eric W. Biederman15e47302012-09-07 20:12:54 +00001945ctnetlink_ct_stat_cpu_fill_info(struct sk_buff *skb, u32 portid, u32 seq,
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02001946 __u16 cpu, const struct ip_conntrack_stat *st)
1947{
1948 struct nlmsghdr *nlh;
1949 struct nfgenmsg *nfmsg;
Eric W. Biederman15e47302012-09-07 20:12:54 +00001950 unsigned int flags = portid ? NLM_F_MULTI : 0, event;
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02001951
1952 event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_CT_GET_STATS_CPU);
Eric W. Biederman15e47302012-09-07 20:12:54 +00001953 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02001954 if (nlh == NULL)
1955 goto nlmsg_failure;
1956
1957 nfmsg = nlmsg_data(nlh);
1958 nfmsg->nfgen_family = AF_UNSPEC;
1959 nfmsg->version = NFNETLINK_V0;
1960 nfmsg->res_id = htons(cpu);
1961
1962 if (nla_put_be32(skb, CTA_STATS_SEARCHED, htonl(st->searched)) ||
1963 nla_put_be32(skb, CTA_STATS_FOUND, htonl(st->found)) ||
1964 nla_put_be32(skb, CTA_STATS_NEW, htonl(st->new)) ||
1965 nla_put_be32(skb, CTA_STATS_INVALID, htonl(st->invalid)) ||
1966 nla_put_be32(skb, CTA_STATS_IGNORE, htonl(st->ignore)) ||
1967 nla_put_be32(skb, CTA_STATS_DELETE, htonl(st->delete)) ||
1968 nla_put_be32(skb, CTA_STATS_DELETE_LIST, htonl(st->delete_list)) ||
1969 nla_put_be32(skb, CTA_STATS_INSERT, htonl(st->insert)) ||
1970 nla_put_be32(skb, CTA_STATS_INSERT_FAILED,
1971 htonl(st->insert_failed)) ||
1972 nla_put_be32(skb, CTA_STATS_DROP, htonl(st->drop)) ||
1973 nla_put_be32(skb, CTA_STATS_EARLY_DROP, htonl(st->early_drop)) ||
1974 nla_put_be32(skb, CTA_STATS_ERROR, htonl(st->error)) ||
1975 nla_put_be32(skb, CTA_STATS_SEARCH_RESTART,
1976 htonl(st->search_restart)))
1977 goto nla_put_failure;
1978
1979 nlmsg_end(skb, nlh);
1980 return skb->len;
1981
1982nla_put_failure:
1983nlmsg_failure:
1984 nlmsg_cancel(skb, nlh);
1985 return -1;
1986}
1987
1988static int
1989ctnetlink_ct_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
1990{
1991 int cpu;
1992 struct net *net = sock_net(skb->sk);
1993
1994 if (cb->args[0] == nr_cpu_ids)
1995 return 0;
1996
1997 for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) {
1998 const struct ip_conntrack_stat *st;
1999
2000 if (!cpu_possible(cpu))
2001 continue;
2002
2003 st = per_cpu_ptr(net->ct.stat, cpu);
2004 if (ctnetlink_ct_stat_cpu_fill_info(skb,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002005 NETLINK_CB(cb->skb).portid,
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02002006 cb->nlh->nlmsg_seq,
2007 cpu, st) < 0)
2008 break;
2009 }
2010 cb->args[0] = cpu;
2011
2012 return skb->len;
2013}
2014
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01002015static int ctnetlink_stat_ct_cpu(struct net *net, struct sock *ctnl,
2016 struct sk_buff *skb,
2017 const struct nlmsghdr *nlh,
2018 const struct nlattr * const cda[])
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02002019{
2020 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2021 struct netlink_dump_control c = {
2022 .dump = ctnetlink_ct_stat_cpu_dump,
2023 };
2024 return netlink_dump_start(ctnl, skb, nlh, &c);
2025 }
2026
2027 return 0;
2028}
2029
2030static int
Eric W. Biederman15e47302012-09-07 20:12:54 +00002031ctnetlink_stat_ct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02002032 struct net *net)
2033{
2034 struct nlmsghdr *nlh;
2035 struct nfgenmsg *nfmsg;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002036 unsigned int flags = portid ? NLM_F_MULTI : 0, event;
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02002037 unsigned int nr_conntracks = atomic_read(&net->ct.count);
2038
2039 event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_CT_GET_STATS);
Eric W. Biederman15e47302012-09-07 20:12:54 +00002040 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02002041 if (nlh == NULL)
2042 goto nlmsg_failure;
2043
2044 nfmsg = nlmsg_data(nlh);
2045 nfmsg->nfgen_family = AF_UNSPEC;
2046 nfmsg->version = NFNETLINK_V0;
2047 nfmsg->res_id = 0;
2048
2049 if (nla_put_be32(skb, CTA_STATS_GLOBAL_ENTRIES, htonl(nr_conntracks)))
2050 goto nla_put_failure;
2051
2052 nlmsg_end(skb, nlh);
2053 return skb->len;
2054
2055nla_put_failure:
2056nlmsg_failure:
2057 nlmsg_cancel(skb, nlh);
2058 return -1;
2059}
2060
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01002061static int ctnetlink_stat_ct(struct net *net, struct sock *ctnl,
2062 struct sk_buff *skb, const struct nlmsghdr *nlh,
2063 const struct nlattr * const cda[])
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02002064{
2065 struct sk_buff *skb2;
2066 int err;
2067
2068 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2069 if (skb2 == NULL)
2070 return -ENOMEM;
2071
Eric W. Biederman15e47302012-09-07 20:12:54 +00002072 err = ctnetlink_stat_ct_fill_info(skb2, NETLINK_CB(skb).portid,
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02002073 nlh->nlmsg_seq,
2074 NFNL_MSG_TYPE(nlh->nlmsg_type),
2075 sock_net(skb->sk));
2076 if (err <= 0)
2077 goto free;
2078
Eric W. Biederman15e47302012-09-07 20:12:54 +00002079 err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02002080 if (err < 0)
2081 goto out;
2082
2083 return 0;
2084
2085free:
2086 kfree_skb(skb2);
2087out:
2088 /* this avoids a loop in nfnetlink. */
2089 return err == -EAGAIN ? -ENOBUFS : err;
2090}
2091
Pablo Neira Ayusobd077932013-08-07 18:13:20 +02002092static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
2093 [CTA_EXPECT_MASTER] = { .type = NLA_NESTED },
2094 [CTA_EXPECT_TUPLE] = { .type = NLA_NESTED },
2095 [CTA_EXPECT_MASK] = { .type = NLA_NESTED },
2096 [CTA_EXPECT_TIMEOUT] = { .type = NLA_U32 },
2097 [CTA_EXPECT_ID] = { .type = NLA_U32 },
2098 [CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING,
2099 .len = NF_CT_HELPER_NAME_LEN - 1 },
2100 [CTA_EXPECT_ZONE] = { .type = NLA_U16 },
2101 [CTA_EXPECT_FLAGS] = { .type = NLA_U32 },
2102 [CTA_EXPECT_CLASS] = { .type = NLA_U32 },
2103 [CTA_EXPECT_NAT] = { .type = NLA_NESTED },
2104 [CTA_EXPECT_FN] = { .type = NLA_NUL_STRING },
2105};
2106
2107static struct nf_conntrack_expect *
2108ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct,
2109 struct nf_conntrack_helper *helper,
2110 struct nf_conntrack_tuple *tuple,
2111 struct nf_conntrack_tuple *mask);
2112
Ken-ichirou MATSUZAWA83f3e942015-10-05 11:48:47 +09002113#ifdef CONFIG_NETFILTER_NETLINK_GLUE_CT
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002114static size_t
Ken-ichirou MATSUZAWAa4b47662015-10-05 11:47:13 +09002115ctnetlink_glue_build_size(const struct nf_conn *ct)
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002116{
2117 return 3 * nla_total_size(0) /* CTA_TUPLE_ORIG|REPL|MASTER */
2118 + 3 * nla_total_size(0) /* CTA_TUPLE_IP */
2119 + 3 * nla_total_size(0) /* CTA_TUPLE_PROTO */
2120 + 3 * nla_total_size(sizeof(u_int8_t)) /* CTA_PROTO_NUM */
2121 + nla_total_size(sizeof(u_int32_t)) /* CTA_ID */
2122 + nla_total_size(sizeof(u_int32_t)) /* CTA_STATUS */
2123 + nla_total_size(sizeof(u_int32_t)) /* CTA_TIMEOUT */
2124 + nla_total_size(0) /* CTA_PROTOINFO */
2125 + nla_total_size(0) /* CTA_HELP */
2126 + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */
2127 + ctnetlink_secctx_size(ct)
2128#ifdef CONFIG_NF_NAT_NEEDED
2129 + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */
2130 + 6 * nla_total_size(sizeof(u_int32_t)) /* CTA_NAT_SEQ_OFFSET */
2131#endif
2132#ifdef CONFIG_NF_CONNTRACK_MARK
2133 + nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */
2134#endif
Ken-ichirou MATSUZAWA4a001062014-06-16 13:52:34 +02002135#ifdef CONFIG_NF_CONNTRACK_ZONES
Daniel Borkmanndeedb592015-08-14 16:03:39 +02002136 + nla_total_size(sizeof(u_int16_t)) /* CTA_ZONE|CTA_TUPLE_ZONE */
Ken-ichirou MATSUZAWA4a001062014-06-16 13:52:34 +02002137#endif
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002138 + ctnetlink_proto_size(ct)
2139 ;
2140}
2141
Ken-ichirou MATSUZAWA224a0592015-10-05 11:49:56 +09002142static struct nf_conn *ctnetlink_glue_get_ct(const struct sk_buff *skb,
Ken-ichirou MATSUZAWAa4b47662015-10-05 11:47:13 +09002143 enum ip_conntrack_info *ctinfo)
Pablo Neira Ayusob7bd1802015-09-30 22:53:44 +01002144{
2145 struct nf_conn *ct;
2146
2147 ct = nf_ct_get(skb, ctinfo);
2148 if (ct && nf_ct_is_untracked(ct))
2149 ct = NULL;
2150
2151 return ct;
2152}
2153
Ken-ichirou MATSUZAWAa4b47662015-10-05 11:47:13 +09002154static int __ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct)
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002155{
Daniel Borkmann308ac912015-08-08 21:40:01 +02002156 const struct nf_conntrack_zone *zone;
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002157 struct nlattr *nest_parms;
2158
2159 rcu_read_lock();
Daniel Borkmanndeedb592015-08-14 16:03:39 +02002160 zone = nf_ct_zone(ct);
2161
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002162 nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED);
2163 if (!nest_parms)
2164 goto nla_put_failure;
2165 if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)
2166 goto nla_put_failure;
Daniel Borkmanndeedb592015-08-14 16:03:39 +02002167 if (ctnetlink_dump_zone_id(skb, CTA_TUPLE_ZONE, zone,
2168 NF_CT_ZONE_DIR_ORIG) < 0)
2169 goto nla_put_failure;
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002170 nla_nest_end(skb, nest_parms);
2171
2172 nest_parms = nla_nest_start(skb, CTA_TUPLE_REPLY | NLA_F_NESTED);
2173 if (!nest_parms)
2174 goto nla_put_failure;
2175 if (ctnetlink_dump_tuples(skb, nf_ct_tuple(ct, IP_CT_DIR_REPLY)) < 0)
2176 goto nla_put_failure;
Daniel Borkmanndeedb592015-08-14 16:03:39 +02002177 if (ctnetlink_dump_zone_id(skb, CTA_TUPLE_ZONE, zone,
2178 NF_CT_ZONE_DIR_REPL) < 0)
2179 goto nla_put_failure;
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002180 nla_nest_end(skb, nest_parms);
2181
Daniel Borkmanndeedb592015-08-14 16:03:39 +02002182 if (ctnetlink_dump_zone_id(skb, CTA_ZONE, zone,
2183 NF_CT_DEFAULT_ZONE_DIR) < 0)
Daniel Borkmann308ac912015-08-08 21:40:01 +02002184 goto nla_put_failure;
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002185
2186 if (ctnetlink_dump_id(skb, ct) < 0)
2187 goto nla_put_failure;
2188
2189 if (ctnetlink_dump_status(skb, ct) < 0)
2190 goto nla_put_failure;
2191
2192 if (ctnetlink_dump_timeout(skb, ct) < 0)
2193 goto nla_put_failure;
2194
2195 if (ctnetlink_dump_protoinfo(skb, ct) < 0)
2196 goto nla_put_failure;
2197
2198 if (ctnetlink_dump_helpinfo(skb, ct) < 0)
2199 goto nla_put_failure;
2200
2201#ifdef CONFIG_NF_CONNTRACK_SECMARK
2202 if (ct->secmark && ctnetlink_dump_secctx(skb, ct) < 0)
2203 goto nla_put_failure;
2204#endif
2205 if (ct->master && ctnetlink_dump_master(skb, ct) < 0)
2206 goto nla_put_failure;
2207
2208 if ((ct->status & IPS_SEQ_ADJUST) &&
Patrick McHardy41d73ec2013-08-27 08:50:12 +02002209 ctnetlink_dump_ct_seq_adj(skb, ct) < 0)
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002210 goto nla_put_failure;
2211
2212#ifdef CONFIG_NF_CONNTRACK_MARK
2213 if (ct->mark && ctnetlink_dump_mark(skb, ct) < 0)
2214 goto nla_put_failure;
2215#endif
Florian Westphal0ceabd82013-01-11 06:30:45 +00002216 if (ctnetlink_dump_labels(skb, ct) < 0)
2217 goto nla_put_failure;
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002218 rcu_read_unlock();
2219 return 0;
2220
2221nla_put_failure:
2222 rcu_read_unlock();
2223 return -ENOSPC;
2224}
2225
2226static int
Ken-ichirou MATSUZAWAa4b47662015-10-05 11:47:13 +09002227ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct,
2228 enum ip_conntrack_info ctinfo,
2229 u_int16_t ct_attr, u_int16_t ct_info_attr)
Pablo Neira Ayusob7bd1802015-09-30 22:53:44 +01002230{
2231 struct nlattr *nest_parms;
2232
2233 nest_parms = nla_nest_start(skb, ct_attr | NLA_F_NESTED);
2234 if (!nest_parms)
2235 goto nla_put_failure;
2236
Ken-ichirou MATSUZAWAa4b47662015-10-05 11:47:13 +09002237 if (__ctnetlink_glue_build(skb, ct) < 0)
Pablo Neira Ayusob7bd1802015-09-30 22:53:44 +01002238 goto nla_put_failure;
2239
2240 nla_nest_end(skb, nest_parms);
2241
2242 if (nla_put_be32(skb, ct_info_attr, htonl(ctinfo)))
2243 goto nla_put_failure;
2244
2245 return 0;
2246
2247nla_put_failure:
2248 return -ENOSPC;
2249}
2250
2251static int
Ken-ichirou MATSUZAWAa4b47662015-10-05 11:47:13 +09002252ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002253{
2254 int err;
2255
2256 if (cda[CTA_TIMEOUT]) {
2257 err = ctnetlink_change_timeout(ct, cda);
2258 if (err < 0)
2259 return err;
2260 }
2261 if (cda[CTA_STATUS]) {
2262 err = ctnetlink_change_status(ct, cda);
2263 if (err < 0)
2264 return err;
2265 }
2266 if (cda[CTA_HELP]) {
2267 err = ctnetlink_change_helper(ct, cda);
2268 if (err < 0)
2269 return err;
2270 }
Florian Westphal9b21f6a2013-01-11 06:30:46 +00002271 if (cda[CTA_LABELS]) {
2272 err = ctnetlink_attach_labels(ct, cda);
2273 if (err < 0)
2274 return err;
2275 }
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002276#if defined(CONFIG_NF_CONNTRACK_MARK)
Florian Westphal534473c2013-12-19 18:25:15 +01002277 if (cda[CTA_MARK]) {
2278 u32 mask = 0, mark, newmark;
2279 if (cda[CTA_MARK_MASK])
2280 mask = ~ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
2281
2282 mark = ntohl(nla_get_be32(cda[CTA_MARK]));
2283 newmark = (ct->mark & mask) ^ mark;
2284 if (newmark != ct->mark)
2285 ct->mark = newmark;
2286 }
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002287#endif
2288 return 0;
2289}
2290
2291static int
Ken-ichirou MATSUZAWAa4b47662015-10-05 11:47:13 +09002292ctnetlink_glue_parse(const struct nlattr *attr, struct nf_conn *ct)
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002293{
2294 struct nlattr *cda[CTA_MAX+1];
Pablo Neira Ayuso68e035c2012-08-14 12:47:37 +02002295 int ret;
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002296
Daniel Borkmann130ffbc2013-06-12 17:54:51 +02002297 ret = nla_parse_nested(cda, CTA_MAX, attr, ct_nla_policy);
2298 if (ret < 0)
2299 return ret;
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002300
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01002301 spin_lock_bh(&nf_conntrack_expect_lock);
Ken-ichirou MATSUZAWAa4b47662015-10-05 11:47:13 +09002302 ret = ctnetlink_glue_parse_ct((const struct nlattr **)cda, ct);
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01002303 spin_unlock_bh(&nf_conntrack_expect_lock);
Pablo Neira Ayuso68e035c2012-08-14 12:47:37 +02002304
2305 return ret;
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002306}
2307
Ken-ichirou MATSUZAWAa4b47662015-10-05 11:47:13 +09002308static int ctnetlink_glue_exp_parse(const struct nlattr * const *cda,
2309 const struct nf_conn *ct,
2310 struct nf_conntrack_tuple *tuple,
2311 struct nf_conntrack_tuple *mask)
Pablo Neira Ayusobd077932013-08-07 18:13:20 +02002312{
2313 int err;
2314
2315 err = ctnetlink_parse_tuple(cda, tuple, CTA_EXPECT_TUPLE,
Daniel Borkmanndeedb592015-08-14 16:03:39 +02002316 nf_ct_l3num(ct), NULL);
Pablo Neira Ayusobd077932013-08-07 18:13:20 +02002317 if (err < 0)
2318 return err;
2319
2320 return ctnetlink_parse_tuple(cda, mask, CTA_EXPECT_MASK,
Daniel Borkmanndeedb592015-08-14 16:03:39 +02002321 nf_ct_l3num(ct), NULL);
Pablo Neira Ayusobd077932013-08-07 18:13:20 +02002322}
2323
2324static int
Ken-ichirou MATSUZAWAa4b47662015-10-05 11:47:13 +09002325ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct,
2326 u32 portid, u32 report)
Pablo Neira Ayusobd077932013-08-07 18:13:20 +02002327{
2328 struct nlattr *cda[CTA_EXPECT_MAX+1];
2329 struct nf_conntrack_tuple tuple, mask;
Florian Westphalb7e092c2013-08-27 11:47:26 +02002330 struct nf_conntrack_helper *helper = NULL;
Pablo Neira Ayusobd077932013-08-07 18:13:20 +02002331 struct nf_conntrack_expect *exp;
2332 int err;
2333
2334 err = nla_parse_nested(cda, CTA_EXPECT_MAX, attr, exp_nla_policy);
2335 if (err < 0)
2336 return err;
2337
Ken-ichirou MATSUZAWAa4b47662015-10-05 11:47:13 +09002338 err = ctnetlink_glue_exp_parse((const struct nlattr * const *)cda,
2339 ct, &tuple, &mask);
Pablo Neira Ayusobd077932013-08-07 18:13:20 +02002340 if (err < 0)
2341 return err;
2342
2343 if (cda[CTA_EXPECT_HELP_NAME]) {
2344 const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
2345
2346 helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
2347 nf_ct_protonum(ct));
2348 if (helper == NULL)
2349 return -EOPNOTSUPP;
2350 }
2351
2352 exp = ctnetlink_alloc_expect((const struct nlattr * const *)cda, ct,
2353 helper, &tuple, &mask);
2354 if (IS_ERR(exp))
2355 return PTR_ERR(exp);
2356
2357 err = nf_ct_expect_related_report(exp, portid, report);
2358 if (err < 0) {
2359 nf_ct_expect_put(exp);
2360 return err;
2361 }
2362
2363 return 0;
2364}
2365
Ken-ichirou MATSUZAWAa4b47662015-10-05 11:47:13 +09002366static void ctnetlink_glue_seqadj(struct sk_buff *skb, struct nf_conn *ct,
2367 enum ip_conntrack_info ctinfo, int diff)
Pablo Neira Ayusob7bd1802015-09-30 22:53:44 +01002368{
2369 if (!(ct->status & IPS_NAT_MASK))
2370 return;
2371
2372 nf_ct_tcp_seqadj_set(skb, ct, ctinfo, diff);
2373}
2374
Ken-ichirou MATSUZAWAa4b47662015-10-05 11:47:13 +09002375static struct nfnl_ct_hook ctnetlink_glue_hook = {
2376 .get_ct = ctnetlink_glue_get_ct,
2377 .build_size = ctnetlink_glue_build_size,
2378 .build = ctnetlink_glue_build,
2379 .parse = ctnetlink_glue_parse,
2380 .attach_expect = ctnetlink_glue_attach_expect,
2381 .seq_adjust = ctnetlink_glue_seqadj,
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002382};
Ken-ichirou MATSUZAWA83f3e942015-10-05 11:48:47 +09002383#endif /* CONFIG_NETFILTER_NETLINK_GLUE_CT */
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02002384
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002385/***********************************************************************
2386 * EXPECT
2387 ***********************************************************************/
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002388
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +02002389static int ctnetlink_exp_dump_tuple(struct sk_buff *skb,
2390 const struct nf_conntrack_tuple *tuple,
2391 enum ctattr_expect type)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002392{
Patrick McHardydf6fb862007-09-28 14:37:03 -07002393 struct nlattr *nest_parms;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002394
Patrick McHardydf6fb862007-09-28 14:37:03 -07002395 nest_parms = nla_nest_start(skb, type | NLA_F_NESTED);
2396 if (!nest_parms)
2397 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002398 if (ctnetlink_dump_tuples(skb, tuple) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07002399 goto nla_put_failure;
2400 nla_nest_end(skb, nest_parms);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002401
2402 return 0;
2403
Patrick McHardydf6fb862007-09-28 14:37:03 -07002404nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002405 return -1;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002406}
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002407
Pablo Neira Ayuso4054ff42016-04-12 23:32:34 +02002408static int ctnetlink_exp_dump_mask(struct sk_buff *skb,
2409 const struct nf_conntrack_tuple *tuple,
2410 const struct nf_conntrack_tuple_mask *mask)
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08002411{
2412 int ret;
2413 struct nf_conntrack_l3proto *l3proto;
Martin Josefsson605dcad2006-11-29 02:35:06 +01002414 struct nf_conntrack_l4proto *l4proto;
Patrick McHardyd4156e82007-07-07 22:31:32 -07002415 struct nf_conntrack_tuple m;
Patrick McHardydf6fb862007-09-28 14:37:03 -07002416 struct nlattr *nest_parms;
Patrick McHardyd4156e82007-07-07 22:31:32 -07002417
2418 memset(&m, 0xFF, sizeof(m));
Patrick McHardyd4156e82007-07-07 22:31:32 -07002419 memcpy(&m.src.u3, &mask->src.u3, sizeof(m.src.u3));
Patrick McHardye5787562010-01-26 17:04:02 +01002420 m.src.u.all = mask->src.u.all;
2421 m.dst.protonum = tuple->dst.protonum;
Patrick McHardyd4156e82007-07-07 22:31:32 -07002422
Patrick McHardydf6fb862007-09-28 14:37:03 -07002423 nest_parms = nla_nest_start(skb, CTA_EXPECT_MASK | NLA_F_NESTED);
2424 if (!nest_parms)
2425 goto nla_put_failure;
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08002426
Hans Schillstrom3b988ec2012-03-05 02:24:29 +00002427 rcu_read_lock();
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01002428 l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
Patrick McHardyd4156e82007-07-07 22:31:32 -07002429 ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto);
Hans Schillstrom3b988ec2012-03-05 02:24:29 +00002430 if (ret >= 0) {
2431 l4proto = __nf_ct_l4proto_find(tuple->src.l3num,
2432 tuple->dst.protonum);
Patrick McHardyd4156e82007-07-07 22:31:32 -07002433 ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto);
Hans Schillstrom3b988ec2012-03-05 02:24:29 +00002434 }
2435 rcu_read_unlock();
2436
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08002437 if (unlikely(ret < 0))
Patrick McHardydf6fb862007-09-28 14:37:03 -07002438 goto nla_put_failure;
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08002439
Patrick McHardydf6fb862007-09-28 14:37:03 -07002440 nla_nest_end(skb, nest_parms);
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08002441
2442 return 0;
2443
Patrick McHardydf6fb862007-09-28 14:37:03 -07002444nla_put_failure:
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08002445 return -1;
2446}
2447
Patrick McHardyc7232c92012-08-26 19:14:06 +02002448static const union nf_inet_addr any_addr;
2449
Ilpo Järvinenbb5cf802008-01-05 23:11:31 -08002450static int
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002451ctnetlink_exp_dump_expect(struct sk_buff *skb,
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002452 const struct nf_conntrack_expect *exp)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002453{
2454 struct nf_conn *master = exp->master;
Xi Wangc1216382011-12-30 10:40:17 -05002455 long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ;
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02002456 struct nf_conn_help *help;
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002457#ifdef CONFIG_NF_NAT_NEEDED
2458 struct nlattr *nest_parms;
2459 struct nf_conntrack_tuple nat_tuple = {};
2460#endif
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +01002461 struct nf_ct_helper_expectfn *expfn;
2462
Patrick McHardyd978e5d2007-12-17 22:37:03 -08002463 if (timeout < 0)
2464 timeout = 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002465
2466 if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07002467 goto nla_put_failure;
Pablo Neira Ayuso1cde6432006-03-22 13:54:15 -08002468 if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07002469 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002470 if (ctnetlink_exp_dump_tuple(skb,
2471 &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
2472 CTA_EXPECT_MASTER) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07002473 goto nla_put_failure;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002474
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002475#ifdef CONFIG_NF_NAT_NEEDED
Patrick McHardyc7232c92012-08-26 19:14:06 +02002476 if (!nf_inet_addr_cmp(&exp->saved_addr, &any_addr) ||
2477 exp->saved_proto.all) {
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002478 nest_parms = nla_nest_start(skb, CTA_EXPECT_NAT | NLA_F_NESTED);
2479 if (!nest_parms)
2480 goto nla_put_failure;
2481
David S. Millercc1eb432012-04-01 18:57:48 -04002482 if (nla_put_be32(skb, CTA_EXPECT_NAT_DIR, htonl(exp->dir)))
2483 goto nla_put_failure;
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002484
2485 nat_tuple.src.l3num = nf_ct_l3num(master);
Patrick McHardyc7232c92012-08-26 19:14:06 +02002486 nat_tuple.src.u3 = exp->saved_addr;
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002487 nat_tuple.dst.protonum = nf_ct_protonum(master);
2488 nat_tuple.src.u = exp->saved_proto;
2489
2490 if (ctnetlink_exp_dump_tuple(skb, &nat_tuple,
2491 CTA_EXPECT_NAT_TUPLE) < 0)
2492 goto nla_put_failure;
2493 nla_nest_end(skb, nest_parms);
2494 }
2495#endif
David S. Millercc1eb432012-04-01 18:57:48 -04002496 if (nla_put_be32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)) ||
2497 nla_put_be32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)) ||
2498 nla_put_be32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)) ||
2499 nla_put_be32(skb, CTA_EXPECT_CLASS, htonl(exp->class)))
2500 goto nla_put_failure;
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02002501 help = nfct_help(master);
2502 if (help) {
2503 struct nf_conntrack_helper *helper;
2504
2505 helper = rcu_dereference(help->helper);
David S. Millercc1eb432012-04-01 18:57:48 -04002506 if (helper &&
2507 nla_put_string(skb, CTA_EXPECT_HELP_NAME, helper->name))
2508 goto nla_put_failure;
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02002509 }
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +01002510 expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn);
David S. Millercc1eb432012-04-01 18:57:48 -04002511 if (expfn != NULL &&
2512 nla_put_string(skb, CTA_EXPECT_FN, expfn->name))
2513 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002514
2515 return 0;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002516
Patrick McHardydf6fb862007-09-28 14:37:03 -07002517nla_put_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002518 return -1;
2519}
2520
2521static int
Eric W. Biederman15e47302012-09-07 20:12:54 +00002522ctnetlink_exp_fill_info(struct sk_buff *skb, u32 portid, u32 seq,
Pablo Neira Ayuso8b0a2312009-06-02 20:03:34 +02002523 int event, const struct nf_conntrack_expect *exp)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002524{
2525 struct nlmsghdr *nlh;
2526 struct nfgenmsg *nfmsg;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002527 unsigned int flags = portid ? NLM_F_MULTI : 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002528
2529 event |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002530 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002531 if (nlh == NULL)
2532 goto nlmsg_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002533
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002534 nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002535 nfmsg->nfgen_family = exp->tuple.src.l3num;
2536 nfmsg->version = NFNETLINK_V0;
2537 nfmsg->res_id = 0;
2538
2539 if (ctnetlink_exp_dump_expect(skb, exp) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07002540 goto nla_put_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002541
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002542 nlmsg_end(skb, nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002543 return skb->len;
2544
2545nlmsg_failure:
Patrick McHardydf6fb862007-09-28 14:37:03 -07002546nla_put_failure:
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002547 nlmsg_cancel(skb, nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002548 return -1;
2549}
2550
2551#ifdef CONFIG_NF_CONNTRACK_EVENTS
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02002552static int
2553ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002554{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01002555 struct nf_conntrack_expect *exp = item->exp;
2556 struct net *net = nf_ct_exp_net(exp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002557 struct nlmsghdr *nlh;
2558 struct nfgenmsg *nfmsg;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002559 struct sk_buff *skb;
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002560 unsigned int type, group;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002561 int flags = 0;
2562
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002563 if (events & (1 << IPEXP_DESTROY)) {
2564 type = IPCTNL_MSG_EXP_DELETE;
2565 group = NFNLGRP_CONNTRACK_EXP_DESTROY;
2566 } else if (events & (1 << IPEXP_NEW)) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002567 type = IPCTNL_MSG_EXP_NEW;
2568 flags = NLM_F_CREATE|NLM_F_EXCL;
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002569 group = NFNLGRP_CONNTRACK_EXP_NEW;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002570 } else
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02002571 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002572
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002573 if (!item->report && !nfnetlink_has_listeners(net, group))
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02002574 return 0;
Pablo Neira Ayusob3a27bf2006-08-22 00:32:05 -07002575
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002576 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
2577 if (skb == NULL)
Pablo Neira Ayuso150ace02009-04-17 17:47:31 +02002578 goto errout;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002579
Marcus Sundbergb633ad52006-02-04 02:11:09 -08002580 type |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002581 nlh = nlmsg_put(skb, item->portid, 0, type, sizeof(*nfmsg), flags);
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002582 if (nlh == NULL)
2583 goto nlmsg_failure;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002584
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002585 nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002586 nfmsg->nfgen_family = exp->tuple.src.l3num;
2587 nfmsg->version = NFNETLINK_V0;
2588 nfmsg->res_id = 0;
2589
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01002590 rcu_read_lock();
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002591 if (ctnetlink_exp_dump_expect(skb, exp) < 0)
Patrick McHardydf6fb862007-09-28 14:37:03 -07002592 goto nla_put_failure;
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01002593 rcu_read_unlock();
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002594
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002595 nlmsg_end(skb, nlh);
Eric W. Biederman15e47302012-09-07 20:12:54 +00002596 nfnetlink_send(skb, net, item->portid, group, item->report, GFP_ATOMIC);
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02002597 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002598
Patrick McHardydf6fb862007-09-28 14:37:03 -07002599nla_put_failure:
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01002600 rcu_read_unlock();
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002601 nlmsg_cancel(skb, nlh);
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01002602nlmsg_failure:
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002603 kfree_skb(skb);
Pablo Neira Ayuso150ace02009-04-17 17:47:31 +02002604errout:
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01002605 nfnetlink_set_err(net, 0, 0, -ENOBUFS);
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02002606 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002607}
2608#endif
Patrick McHardycf6994c2007-07-07 22:32:34 -07002609static int ctnetlink_exp_done(struct netlink_callback *cb)
2610{
Patrick McHardy31f15872007-07-07 22:35:21 -07002611 if (cb->args[1])
2612 nf_ct_expect_put((struct nf_conntrack_expect *)cb->args[1]);
Patrick McHardycf6994c2007-07-07 22:32:34 -07002613 return 0;
2614}
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002615
2616static int
2617ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
2618{
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01002619 struct net *net = sock_net(skb->sk);
Patrick McHardycf6994c2007-07-07 22:32:34 -07002620 struct nf_conntrack_expect *exp, *last;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002621 struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
Pablo Neira Ayuso87711cb2006-01-05 12:19:23 -08002622 u_int8_t l3proto = nfmsg->nfgen_family;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002623
Patrick McHardy7d0742d2008-01-31 04:38:19 -08002624 rcu_read_lock();
Patrick McHardy31f15872007-07-07 22:35:21 -07002625 last = (struct nf_conntrack_expect *)cb->args[1];
2626 for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
Patrick McHardycf6994c2007-07-07 22:32:34 -07002627restart:
Sasha Levinb67bfe02013-02-27 17:06:00 -08002628 hlist_for_each_entry(exp, &net->ct.expect_hash[cb->args[0]],
Patrick McHardy31f15872007-07-07 22:35:21 -07002629 hnode) {
2630 if (l3proto && exp->tuple.src.l3num != l3proto)
Patrick McHardycf6994c2007-07-07 22:32:34 -07002631 continue;
Patrick McHardy31f15872007-07-07 22:35:21 -07002632 if (cb->args[1]) {
2633 if (exp != last)
2634 continue;
2635 cb->args[1] = 0;
2636 }
Pablo Neira Ayuso8b0a2312009-06-02 20:03:34 +02002637 if (ctnetlink_exp_fill_info(skb,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002638 NETLINK_CB(cb->skb).portid,
Patrick McHardy31f15872007-07-07 22:35:21 -07002639 cb->nlh->nlmsg_seq,
2640 IPCTNL_MSG_EXP_NEW,
Pablo Neira Ayuso8b0a2312009-06-02 20:03:34 +02002641 exp) < 0) {
Patrick McHardy7d0742d2008-01-31 04:38:19 -08002642 if (!atomic_inc_not_zero(&exp->use))
2643 continue;
Patrick McHardy31f15872007-07-07 22:35:21 -07002644 cb->args[1] = (unsigned long)exp;
2645 goto out;
2646 }
Patrick McHardycf6994c2007-07-07 22:32:34 -07002647 }
Patrick McHardy31f15872007-07-07 22:35:21 -07002648 if (cb->args[1]) {
2649 cb->args[1] = 0;
2650 goto restart;
Patrick McHardycf6994c2007-07-07 22:32:34 -07002651 }
2652 }
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002653out:
Patrick McHardy7d0742d2008-01-31 04:38:19 -08002654 rcu_read_unlock();
Patrick McHardycf6994c2007-07-07 22:32:34 -07002655 if (last)
2656 nf_ct_expect_put(last);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002657
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002658 return skb->len;
2659}
2660
Pablo Neira Ayusoe844a922013-03-17 23:21:36 +00002661static int
2662ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
2663{
2664 struct nf_conntrack_expect *exp, *last;
2665 struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
2666 struct nf_conn *ct = cb->data;
2667 struct nf_conn_help *help = nfct_help(ct);
2668 u_int8_t l3proto = nfmsg->nfgen_family;
2669
2670 if (cb->args[0])
2671 return 0;
2672
2673 rcu_read_lock();
2674 last = (struct nf_conntrack_expect *)cb->args[1];
2675restart:
2676 hlist_for_each_entry(exp, &help->expectations, lnode) {
2677 if (l3proto && exp->tuple.src.l3num != l3proto)
2678 continue;
2679 if (cb->args[1]) {
2680 if (exp != last)
2681 continue;
2682 cb->args[1] = 0;
2683 }
2684 if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).portid,
2685 cb->nlh->nlmsg_seq,
2686 IPCTNL_MSG_EXP_NEW,
2687 exp) < 0) {
2688 if (!atomic_inc_not_zero(&exp->use))
2689 continue;
2690 cb->args[1] = (unsigned long)exp;
2691 goto out;
2692 }
2693 }
2694 if (cb->args[1]) {
2695 cb->args[1] = 0;
2696 goto restart;
2697 }
2698 cb->args[0] = 1;
2699out:
2700 rcu_read_unlock();
2701 if (last)
2702 nf_ct_expect_put(last);
2703
2704 return skb->len;
2705}
2706
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01002707static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
2708 struct sk_buff *skb,
Pablo Neira Ayusoe844a922013-03-17 23:21:36 +00002709 const struct nlmsghdr *nlh,
2710 const struct nlattr * const cda[])
2711{
2712 int err;
Pablo Neira Ayusoe844a922013-03-17 23:21:36 +00002713 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
2714 u_int8_t u3 = nfmsg->nfgen_family;
2715 struct nf_conntrack_tuple tuple;
2716 struct nf_conntrack_tuple_hash *h;
2717 struct nf_conn *ct;
Daniel Borkmann308ac912015-08-08 21:40:01 +02002718 struct nf_conntrack_zone zone;
Pablo Neira Ayusoe844a922013-03-17 23:21:36 +00002719 struct netlink_dump_control c = {
2720 .dump = ctnetlink_exp_ct_dump_table,
2721 .done = ctnetlink_exp_done,
2722 };
2723
Daniel Borkmanndeedb592015-08-14 16:03:39 +02002724 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER,
2725 u3, NULL);
Pablo Neira Ayusoe844a922013-03-17 23:21:36 +00002726 if (err < 0)
2727 return err;
2728
Daniel Borkmann308ac912015-08-08 21:40:01 +02002729 err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
2730 if (err < 0)
2731 return err;
Pablo Neira Ayusoe844a922013-03-17 23:21:36 +00002732
Daniel Borkmann308ac912015-08-08 21:40:01 +02002733 h = nf_conntrack_find_get(net, &zone, &tuple);
Pablo Neira Ayusoe844a922013-03-17 23:21:36 +00002734 if (!h)
2735 return -ENOENT;
2736
2737 ct = nf_ct_tuplehash_to_ctrack(h);
2738 c.data = ct;
2739
2740 err = netlink_dump_start(ctnl, skb, nlh, &c);
2741 nf_ct_put(ct);
2742
2743 return err;
2744}
2745
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01002746static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
2747 struct sk_buff *skb, const struct nlmsghdr *nlh,
2748 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002749{
2750 struct nf_conntrack_tuple tuple;
2751 struct nf_conntrack_expect *exp;
2752 struct sk_buff *skb2;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002753 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002754 u_int8_t u3 = nfmsg->nfgen_family;
Daniel Borkmann308ac912015-08-08 21:40:01 +02002755 struct nf_conntrack_zone zone;
Patrick McHardyef00f892010-02-15 18:14:57 +01002756 int err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002757
David S. Millerb8f3ab42011-01-18 12:40:38 -08002758 if (nlh->nlmsg_flags & NLM_F_DUMP) {
Pablo Neira Ayusoe844a922013-03-17 23:21:36 +00002759 if (cda[CTA_EXPECT_MASTER])
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01002760 return ctnetlink_dump_exp_ct(net, ctnl, skb, nlh, cda);
Pablo Neira Ayusoe844a922013-03-17 23:21:36 +00002761 else {
2762 struct netlink_dump_control c = {
2763 .dump = ctnetlink_exp_dump_table,
2764 .done = ctnetlink_exp_done,
2765 };
2766 return netlink_dump_start(ctnl, skb, nlh, &c);
2767 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002768 }
2769
Patrick McHardyef00f892010-02-15 18:14:57 +01002770 err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
2771 if (err < 0)
2772 return err;
2773
Pablo Neira Ayuso35dba1d2011-12-14 12:45:22 +01002774 if (cda[CTA_EXPECT_TUPLE])
Daniel Borkmanndeedb592015-08-14 16:03:39 +02002775 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE,
2776 u3, NULL);
Pablo Neira Ayuso35dba1d2011-12-14 12:45:22 +01002777 else if (cda[CTA_EXPECT_MASTER])
Daniel Borkmanndeedb592015-08-14 16:03:39 +02002778 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER,
2779 u3, NULL);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002780 else
2781 return -EINVAL;
2782
2783 if (err < 0)
2784 return err;
2785
Daniel Borkmann308ac912015-08-08 21:40:01 +02002786 exp = nf_ct_expect_find_get(net, &zone, &tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002787 if (!exp)
2788 return -ENOENT;
2789
Patrick McHardydf6fb862007-09-28 14:37:03 -07002790 if (cda[CTA_EXPECT_ID]) {
Patrick McHardy77236b62007-12-17 22:29:45 -08002791 __be32 id = nla_get_be32(cda[CTA_EXPECT_ID]);
Patrick McHardy35832402007-09-28 14:41:50 -07002792 if (ntohl(id) != (u32)(unsigned long)exp) {
Patrick McHardy68236452007-07-07 22:30:49 -07002793 nf_ct_expect_put(exp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002794 return -ENOENT;
2795 }
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002796 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002797
2798 err = -ENOMEM;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002799 skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01002800 if (skb2 == NULL) {
2801 nf_ct_expect_put(exp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002802 goto out;
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01002803 }
Thomas Graf4e9b8262006-11-27 09:25:58 -08002804
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01002805 rcu_read_lock();
Eric W. Biederman15e47302012-09-07 20:12:54 +00002806 err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).portid,
Pablo Neira Ayuso8b0a2312009-06-02 20:03:34 +02002807 nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, exp);
Pablo Neira Ayuso528a3a62008-11-17 16:00:40 +01002808 rcu_read_unlock();
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01002809 nf_ct_expect_put(exp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002810 if (err <= 0)
2811 goto free;
2812
Eric W. Biederman15e47302012-09-07 20:12:54 +00002813 err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01002814 if (err < 0)
2815 goto out;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002816
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01002817 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002818
2819free:
2820 kfree_skb(skb2);
2821out:
Pablo Neira Ayuso81378f72011-12-24 19:03:46 +01002822 /* this avoids a loop in nfnetlink. */
2823 return err == -EAGAIN ? -ENOBUFS : err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002824}
2825
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01002826static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
2827 struct sk_buff *skb, const struct nlmsghdr *nlh,
2828 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002829{
Patrick McHardy31f15872007-07-07 22:35:21 -07002830 struct nf_conntrack_expect *exp;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002831 struct nf_conntrack_tuple tuple;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02002832 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Sasha Levinb67bfe02013-02-27 17:06:00 -08002833 struct hlist_node *next;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002834 u_int8_t u3 = nfmsg->nfgen_family;
Daniel Borkmann308ac912015-08-08 21:40:01 +02002835 struct nf_conntrack_zone zone;
Patrick McHardy31f15872007-07-07 22:35:21 -07002836 unsigned int i;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002837 int err;
2838
Patrick McHardydf6fb862007-09-28 14:37:03 -07002839 if (cda[CTA_EXPECT_TUPLE]) {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002840 /* delete a single expect by tuple */
Patrick McHardyef00f892010-02-15 18:14:57 +01002841 err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
2842 if (err < 0)
2843 return err;
2844
Daniel Borkmanndeedb592015-08-14 16:03:39 +02002845 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE,
2846 u3, NULL);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002847 if (err < 0)
2848 return err;
2849
2850 /* bump usage count to 2 */
Daniel Borkmann308ac912015-08-08 21:40:01 +02002851 exp = nf_ct_expect_find_get(net, &zone, &tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002852 if (!exp)
2853 return -ENOENT;
2854
Patrick McHardydf6fb862007-09-28 14:37:03 -07002855 if (cda[CTA_EXPECT_ID]) {
Patrick McHardy77236b62007-12-17 22:29:45 -08002856 __be32 id = nla_get_be32(cda[CTA_EXPECT_ID]);
Patrick McHardy35832402007-09-28 14:41:50 -07002857 if (ntohl(id) != (u32)(unsigned long)exp) {
Patrick McHardy68236452007-07-07 22:30:49 -07002858 nf_ct_expect_put(exp);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002859 return -ENOENT;
2860 }
2861 }
2862
2863 /* after list removal, usage count == 1 */
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01002864 spin_lock_bh(&nf_conntrack_expect_lock);
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002865 if (del_timer(&exp->timeout)) {
Eric W. Biederman15e47302012-09-07 20:12:54 +00002866 nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid,
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002867 nlmsg_report(nlh));
2868 nf_ct_expect_put(exp);
2869 }
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01002870 spin_unlock_bh(&nf_conntrack_expect_lock);
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002871 /* have to put what we 'get' above.
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002872 * after this line usage count == 0 */
Patrick McHardy68236452007-07-07 22:30:49 -07002873 nf_ct_expect_put(exp);
Patrick McHardydf6fb862007-09-28 14:37:03 -07002874 } else if (cda[CTA_EXPECT_HELP_NAME]) {
2875 char *name = nla_data(cda[CTA_EXPECT_HELP_NAME]);
Patrick McHardy31f15872007-07-07 22:35:21 -07002876 struct nf_conn_help *m_help;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002877
2878 /* delete all expectations for this helper */
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01002879 spin_lock_bh(&nf_conntrack_expect_lock);
Patrick McHardy31f15872007-07-07 22:35:21 -07002880 for (i = 0; i < nf_ct_expect_hsize; i++) {
Sasha Levinb67bfe02013-02-27 17:06:00 -08002881 hlist_for_each_entry_safe(exp, next,
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01002882 &net->ct.expect_hash[i],
Patrick McHardy31f15872007-07-07 22:35:21 -07002883 hnode) {
2884 m_help = nfct_help(exp->master);
Patrick McHardy794e6872010-02-03 13:41:29 +01002885 if (!strcmp(m_help->helper->name, name) &&
2886 del_timer(&exp->timeout)) {
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002887 nf_ct_unlink_expect_report(exp,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002888 NETLINK_CB(skb).portid,
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002889 nlmsg_report(nlh));
Patrick McHardy31f15872007-07-07 22:35:21 -07002890 nf_ct_expect_put(exp);
2891 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002892 }
2893 }
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01002894 spin_unlock_bh(&nf_conntrack_expect_lock);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002895 } else {
2896 /* This basically means we have to flush everything*/
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01002897 spin_lock_bh(&nf_conntrack_expect_lock);
Patrick McHardy31f15872007-07-07 22:35:21 -07002898 for (i = 0; i < nf_ct_expect_hsize; i++) {
Sasha Levinb67bfe02013-02-27 17:06:00 -08002899 hlist_for_each_entry_safe(exp, next,
Alexey Dobriyan9592a5c2010-01-13 16:04:18 +01002900 &net->ct.expect_hash[i],
Patrick McHardy31f15872007-07-07 22:35:21 -07002901 hnode) {
2902 if (del_timer(&exp->timeout)) {
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002903 nf_ct_unlink_expect_report(exp,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002904 NETLINK_CB(skb).portid,
Pablo Neira Ayusoebbf41d2010-10-19 10:19:06 +02002905 nlmsg_report(nlh));
Patrick McHardy31f15872007-07-07 22:35:21 -07002906 nf_ct_expect_put(exp);
2907 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002908 }
2909 }
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01002910 spin_unlock_bh(&nf_conntrack_expect_lock);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002911 }
2912
2913 return 0;
2914}
2915static int
Patrick McHardy39938322009-08-25 16:07:58 +02002916ctnetlink_change_expect(struct nf_conntrack_expect *x,
2917 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002918{
Kelvie Wong9768e1a2012-05-02 14:39:24 +00002919 if (cda[CTA_EXPECT_TIMEOUT]) {
2920 if (!del_timer(&x->timeout))
2921 return -ETIME;
2922
2923 x->timeout.expires = jiffies +
2924 ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ;
2925 add_timer(&x->timeout);
2926 }
2927 return 0;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002928}
2929
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002930static const struct nla_policy exp_nat_nla_policy[CTA_EXPECT_NAT_MAX+1] = {
2931 [CTA_EXPECT_NAT_DIR] = { .type = NLA_U32 },
2932 [CTA_EXPECT_NAT_TUPLE] = { .type = NLA_NESTED },
2933};
2934
2935static int
2936ctnetlink_parse_expect_nat(const struct nlattr *attr,
2937 struct nf_conntrack_expect *exp,
2938 u_int8_t u3)
2939{
2940#ifdef CONFIG_NF_NAT_NEEDED
2941 struct nlattr *tb[CTA_EXPECT_NAT_MAX+1];
2942 struct nf_conntrack_tuple nat_tuple = {};
2943 int err;
2944
Daniel Borkmann130ffbc2013-06-12 17:54:51 +02002945 err = nla_parse_nested(tb, CTA_EXPECT_NAT_MAX, attr, exp_nat_nla_policy);
2946 if (err < 0)
2947 return err;
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002948
2949 if (!tb[CTA_EXPECT_NAT_DIR] || !tb[CTA_EXPECT_NAT_TUPLE])
2950 return -EINVAL;
2951
2952 err = ctnetlink_parse_tuple((const struct nlattr * const *)tb,
Daniel Borkmanndeedb592015-08-14 16:03:39 +02002953 &nat_tuple, CTA_EXPECT_NAT_TUPLE,
2954 u3, NULL);
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002955 if (err < 0)
2956 return err;
2957
Patrick McHardyc7232c92012-08-26 19:14:06 +02002958 exp->saved_addr = nat_tuple.src.u3;
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01002959 exp->saved_proto = nat_tuple.src.u;
2960 exp->dir = ntohl(nla_get_be32(tb[CTA_EXPECT_NAT_DIR]));
2961
2962 return 0;
2963#else
2964 return -EOPNOTSUPP;
2965#endif
2966}
2967
Pablo Neira Ayuso0ef71ee2013-08-07 19:12:34 +02002968static struct nf_conntrack_expect *
2969ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
2970 struct nf_conntrack_helper *helper,
2971 struct nf_conntrack_tuple *tuple,
2972 struct nf_conntrack_tuple *mask)
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08002973{
Pablo Neira Ayusob8c5e522012-02-05 03:21:12 +01002974 u_int32_t class = 0;
Pablo Neira Ayuso0ef71ee2013-08-07 19:12:34 +02002975 struct nf_conntrack_expect *exp;
2976 struct nf_conn_help *help;
2977 int err;
Pablo Neira Ayuso660fdb22012-02-05 02:34:16 +01002978
Pablo Neira Ayusob8c5e522012-02-05 03:21:12 +01002979 if (cda[CTA_EXPECT_CLASS] && helper) {
2980 class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS]));
Pablo Neira Ayuso0ef71ee2013-08-07 19:12:34 +02002981 if (class > helper->expect_class_max)
2982 return ERR_PTR(-EINVAL);
Pablo Neira Ayusob8c5e522012-02-05 03:21:12 +01002983 }
Patrick McHardy68236452007-07-07 22:30:49 -07002984 exp = nf_ct_expect_alloc(ct);
Pablo Neira Ayuso0ef71ee2013-08-07 19:12:34 +02002985 if (!exp)
2986 return ERR_PTR(-ENOMEM);
2987
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02002988 help = nfct_help(ct);
2989 if (!help) {
2990 if (!cda[CTA_EXPECT_TIMEOUT]) {
2991 err = -EINVAL;
Jesper Juhl1310b9552012-12-26 11:49:40 +00002992 goto err_out;
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02002993 }
2994 exp->timeout.expires =
2995 jiffies + ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ;
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -08002996
Pablo Neira Ayusobc01befd2010-09-28 21:06:34 +02002997 exp->flags = NF_CT_EXPECT_USERSPACE;
2998 if (cda[CTA_EXPECT_FLAGS]) {
2999 exp->flags |=
3000 ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS]));
3001 }
3002 } else {
3003 if (cda[CTA_EXPECT_FLAGS]) {
3004 exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS]));
3005 exp->flags &= ~NF_CT_EXPECT_USERSPACE;
3006 } else
3007 exp->flags = 0;
3008 }
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +01003009 if (cda[CTA_EXPECT_FN]) {
3010 const char *name = nla_data(cda[CTA_EXPECT_FN]);
3011 struct nf_ct_helper_expectfn *expfn;
3012
3013 expfn = nf_ct_helper_expectfn_find_by_name(name);
3014 if (expfn == NULL) {
3015 err = -EINVAL;
3016 goto err_out;
3017 }
3018 exp->expectfn = expfn->expectfn;
3019 } else
3020 exp->expectfn = NULL;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003021
Pablo Neira Ayusob8c5e522012-02-05 03:21:12 +01003022 exp->class = class;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003023 exp->master = ct;
Pablo Neira Ayuso660fdb22012-02-05 02:34:16 +01003024 exp->helper = helper;
Pablo Neira Ayuso0ef71ee2013-08-07 19:12:34 +02003025 exp->tuple = *tuple;
3026 exp->mask.src.u3 = mask->src.u3;
3027 exp->mask.src.u.all = mask->src.u.all;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003028
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01003029 if (cda[CTA_EXPECT_NAT]) {
3030 err = ctnetlink_parse_expect_nat(cda[CTA_EXPECT_NAT],
Pablo Neira Ayuso0ef71ee2013-08-07 19:12:34 +02003031 exp, nf_ct_l3num(ct));
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01003032 if (err < 0)
3033 goto err_out;
3034 }
Pablo Neira Ayuso0ef71ee2013-08-07 19:12:34 +02003035 return exp;
Pablo Neira Ayuso076a0ca2012-02-05 03:41:52 +01003036err_out:
Patrick McHardy68236452007-07-07 22:30:49 -07003037 nf_ct_expect_put(exp);
Pablo Neira Ayuso0ef71ee2013-08-07 19:12:34 +02003038 return ERR_PTR(err);
3039}
3040
3041static int
Daniel Borkmann308ac912015-08-08 21:40:01 +02003042ctnetlink_create_expect(struct net *net,
3043 const struct nf_conntrack_zone *zone,
Pablo Neira Ayuso0ef71ee2013-08-07 19:12:34 +02003044 const struct nlattr * const cda[],
3045 u_int8_t u3, u32 portid, int report)
3046{
3047 struct nf_conntrack_tuple tuple, mask, master_tuple;
3048 struct nf_conntrack_tuple_hash *h = NULL;
3049 struct nf_conntrack_helper *helper = NULL;
3050 struct nf_conntrack_expect *exp;
3051 struct nf_conn *ct;
3052 int err;
3053
3054 /* caller guarantees that those three CTA_EXPECT_* exist */
Daniel Borkmanndeedb592015-08-14 16:03:39 +02003055 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE,
3056 u3, NULL);
Pablo Neira Ayuso0ef71ee2013-08-07 19:12:34 +02003057 if (err < 0)
3058 return err;
Daniel Borkmanndeedb592015-08-14 16:03:39 +02003059 err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK,
3060 u3, NULL);
Pablo Neira Ayuso0ef71ee2013-08-07 19:12:34 +02003061 if (err < 0)
3062 return err;
Daniel Borkmanndeedb592015-08-14 16:03:39 +02003063 err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER,
3064 u3, NULL);
Pablo Neira Ayuso0ef71ee2013-08-07 19:12:34 +02003065 if (err < 0)
3066 return err;
3067
3068 /* Look for master conntrack of this expectation */
3069 h = nf_conntrack_find_get(net, zone, &master_tuple);
3070 if (!h)
3071 return -ENOENT;
3072 ct = nf_ct_tuplehash_to_ctrack(h);
3073
3074 if (cda[CTA_EXPECT_HELP_NAME]) {
3075 const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
3076
3077 helper = __nf_conntrack_helper_find(helpname, u3,
3078 nf_ct_protonum(ct));
3079 if (helper == NULL) {
3080#ifdef CONFIG_MODULES
3081 if (request_module("nfct-helper-%s", helpname) < 0) {
3082 err = -EOPNOTSUPP;
3083 goto err_ct;
3084 }
3085 helper = __nf_conntrack_helper_find(helpname, u3,
3086 nf_ct_protonum(ct));
3087 if (helper) {
3088 err = -EAGAIN;
3089 goto err_ct;
3090 }
3091#endif
3092 err = -EOPNOTSUPP;
3093 goto err_ct;
3094 }
3095 }
3096
3097 exp = ctnetlink_alloc_expect(cda, ct, helper, &tuple, &mask);
3098 if (IS_ERR(exp)) {
3099 err = PTR_ERR(exp);
3100 goto err_ct;
3101 }
3102
3103 err = nf_ct_expect_related_report(exp, portid, report);
Pablo Neira Ayuso0ef71ee2013-08-07 19:12:34 +02003104 nf_ct_expect_put(exp);
3105err_ct:
3106 nf_ct_put(ct);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003107 return err;
3108}
3109
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01003110static int ctnetlink_new_expect(struct net *net, struct sock *ctnl,
3111 struct sk_buff *skb, const struct nlmsghdr *nlh,
3112 const struct nlattr * const cda[])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003113{
3114 struct nf_conntrack_tuple tuple;
3115 struct nf_conntrack_expect *exp;
Pablo Neira Ayuso96bcf932009-06-02 20:07:39 +02003116 struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003117 u_int8_t u3 = nfmsg->nfgen_family;
Daniel Borkmann308ac912015-08-08 21:40:01 +02003118 struct nf_conntrack_zone zone;
Patrick McHardyef00f892010-02-15 18:14:57 +01003119 int err;
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003120
Patrick McHardydf6fb862007-09-28 14:37:03 -07003121 if (!cda[CTA_EXPECT_TUPLE]
3122 || !cda[CTA_EXPECT_MASK]
3123 || !cda[CTA_EXPECT_MASTER])
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003124 return -EINVAL;
3125
Patrick McHardyef00f892010-02-15 18:14:57 +01003126 err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
3127 if (err < 0)
3128 return err;
3129
Daniel Borkmanndeedb592015-08-14 16:03:39 +02003130 err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE,
3131 u3, NULL);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003132 if (err < 0)
3133 return err;
3134
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01003135 spin_lock_bh(&nf_conntrack_expect_lock);
Daniel Borkmann308ac912015-08-08 21:40:01 +02003136 exp = __nf_ct_expect_find(net, &zone, &tuple);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003137 if (!exp) {
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01003138 spin_unlock_bh(&nf_conntrack_expect_lock);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003139 err = -ENOENT;
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +01003140 if (nlh->nlmsg_flags & NLM_F_CREATE) {
Daniel Borkmann308ac912015-08-08 21:40:01 +02003141 err = ctnetlink_create_expect(net, &zone, cda, u3,
Eric W. Biederman15e47302012-09-07 20:12:54 +00003142 NETLINK_CB(skb).portid,
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +01003143 nlmsg_report(nlh));
3144 }
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003145 return err;
3146 }
3147
3148 err = -EEXIST;
3149 if (!(nlh->nlmsg_flags & NLM_F_EXCL))
3150 err = ctnetlink_change_expect(exp, cda);
Jesper Dangaard Brouerca7433d2014-03-03 14:46:01 +01003151 spin_unlock_bh(&nf_conntrack_expect_lock);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003152
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003153 return err;
3154}
3155
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02003156static int
Eric W. Biederman15e47302012-09-07 20:12:54 +00003157ctnetlink_exp_stat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, int cpu,
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02003158 const struct ip_conntrack_stat *st)
3159{
3160 struct nlmsghdr *nlh;
3161 struct nfgenmsg *nfmsg;
Eric W. Biederman15e47302012-09-07 20:12:54 +00003162 unsigned int flags = portid ? NLM_F_MULTI : 0, event;
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02003163
3164 event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_EXP_GET_STATS_CPU);
Eric W. Biederman15e47302012-09-07 20:12:54 +00003165 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02003166 if (nlh == NULL)
3167 goto nlmsg_failure;
3168
3169 nfmsg = nlmsg_data(nlh);
3170 nfmsg->nfgen_family = AF_UNSPEC;
3171 nfmsg->version = NFNETLINK_V0;
3172 nfmsg->res_id = htons(cpu);
3173
3174 if (nla_put_be32(skb, CTA_STATS_EXP_NEW, htonl(st->expect_new)) ||
3175 nla_put_be32(skb, CTA_STATS_EXP_CREATE, htonl(st->expect_create)) ||
3176 nla_put_be32(skb, CTA_STATS_EXP_DELETE, htonl(st->expect_delete)))
3177 goto nla_put_failure;
3178
3179 nlmsg_end(skb, nlh);
3180 return skb->len;
3181
3182nla_put_failure:
3183nlmsg_failure:
3184 nlmsg_cancel(skb, nlh);
3185 return -1;
3186}
3187
3188static int
3189ctnetlink_exp_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
3190{
3191 int cpu;
3192 struct net *net = sock_net(skb->sk);
3193
3194 if (cb->args[0] == nr_cpu_ids)
3195 return 0;
3196
3197 for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) {
3198 const struct ip_conntrack_stat *st;
3199
3200 if (!cpu_possible(cpu))
3201 continue;
3202
3203 st = per_cpu_ptr(net->ct.stat, cpu);
Eric W. Biederman15e47302012-09-07 20:12:54 +00003204 if (ctnetlink_exp_stat_fill_info(skb, NETLINK_CB(cb->skb).portid,
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02003205 cb->nlh->nlmsg_seq,
3206 cpu, st) < 0)
3207 break;
3208 }
3209 cb->args[0] = cpu;
3210
3211 return skb->len;
3212}
3213
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01003214static int ctnetlink_stat_exp_cpu(struct net *net, struct sock *ctnl,
3215 struct sk_buff *skb,
3216 const struct nlmsghdr *nlh,
3217 const struct nlattr * const cda[])
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02003218{
3219 if (nlh->nlmsg_flags & NLM_F_DUMP) {
3220 struct netlink_dump_control c = {
3221 .dump = ctnetlink_exp_stat_cpu_dump,
3222 };
3223 return netlink_dump_start(ctnl, skb, nlh, &c);
3224 }
3225
3226 return 0;
3227}
3228
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003229#ifdef CONFIG_NF_CONNTRACK_EVENTS
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02003230static struct nf_ct_event_notifier ctnl_notifier = {
3231 .fcn = ctnetlink_conntrack_event,
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003232};
3233
Pablo Neira Ayusoe34d5c12009-06-03 10:32:06 +02003234static struct nf_exp_event_notifier ctnl_notifier_exp = {
3235 .fcn = ctnetlink_expect_event,
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003236};
3237#endif
3238
Patrick McHardy7c8d4cb2007-09-28 14:15:45 -07003239static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003240 [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack,
Patrick McHardyf73e9242007-09-28 14:39:55 -07003241 .attr_count = CTA_MAX,
3242 .policy = ct_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003243 [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack,
Patrick McHardyf73e9242007-09-28 14:39:55 -07003244 .attr_count = CTA_MAX,
3245 .policy = ct_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003246 [IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack,
Patrick McHardyf73e9242007-09-28 14:39:55 -07003247 .attr_count = CTA_MAX,
3248 .policy = ct_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003249 [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack,
Patrick McHardyf73e9242007-09-28 14:39:55 -07003250 .attr_count = CTA_MAX,
3251 .policy = ct_nla_policy },
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02003252 [IPCTNL_MSG_CT_GET_STATS_CPU] = { .call = ctnetlink_stat_ct_cpu },
3253 [IPCTNL_MSG_CT_GET_STATS] = { .call = ctnetlink_stat_ct },
Pablo Neira Ayusod871bef2012-11-27 14:49:42 +01003254 [IPCTNL_MSG_CT_GET_DYING] = { .call = ctnetlink_get_ct_dying },
3255 [IPCTNL_MSG_CT_GET_UNCONFIRMED] = { .call = ctnetlink_get_ct_unconfirmed },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003256};
3257
Patrick McHardy7c8d4cb2007-09-28 14:15:45 -07003258static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003259 [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect,
Patrick McHardyf73e9242007-09-28 14:39:55 -07003260 .attr_count = CTA_EXPECT_MAX,
3261 .policy = exp_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003262 [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect,
Patrick McHardyf73e9242007-09-28 14:39:55 -07003263 .attr_count = CTA_EXPECT_MAX,
3264 .policy = exp_nla_policy },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003265 [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect,
Patrick McHardyf73e9242007-09-28 14:39:55 -07003266 .attr_count = CTA_EXPECT_MAX,
3267 .policy = exp_nla_policy },
Pablo Neira Ayuso392025f2012-06-26 20:27:09 +02003268 [IPCTNL_MSG_EXP_GET_STATS_CPU] = { .call = ctnetlink_stat_exp_cpu },
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003269};
3270
Patrick McHardy7c8d4cb2007-09-28 14:15:45 -07003271static const struct nfnetlink_subsystem ctnl_subsys = {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003272 .name = "conntrack",
3273 .subsys_id = NFNL_SUBSYS_CTNETLINK,
3274 .cb_count = IPCTNL_MSG_MAX,
3275 .cb = ctnl_cb,
3276};
3277
Patrick McHardy7c8d4cb2007-09-28 14:15:45 -07003278static const struct nfnetlink_subsystem ctnl_exp_subsys = {
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003279 .name = "conntrack_expect",
3280 .subsys_id = NFNL_SUBSYS_CTNETLINK_EXP,
3281 .cb_count = IPCTNL_MSG_EXP_MAX,
3282 .cb = ctnl_exp_cb,
3283};
3284
Patrick McHardyd2483dd2006-12-02 22:06:05 -08003285MODULE_ALIAS("ip_conntrack_netlink");
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003286MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);
Pablo Neira Ayuso34f9a2e2006-02-04 02:11:41 -08003287MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003288
Pablo Neira Ayuso70e99422011-11-22 00:16:51 +01003289static int __net_init ctnetlink_net_init(struct net *net)
3290{
3291#ifdef CONFIG_NF_CONNTRACK_EVENTS
3292 int ret;
3293
3294 ret = nf_conntrack_register_notifier(net, &ctnl_notifier);
3295 if (ret < 0) {
3296 pr_err("ctnetlink_init: cannot register notifier.\n");
3297 goto err_out;
3298 }
3299
3300 ret = nf_ct_expect_register_notifier(net, &ctnl_notifier_exp);
3301 if (ret < 0) {
3302 pr_err("ctnetlink_init: cannot expect register notifier.\n");
3303 goto err_unreg_notifier;
3304 }
3305#endif
3306 return 0;
3307
3308#ifdef CONFIG_NF_CONNTRACK_EVENTS
3309err_unreg_notifier:
3310 nf_conntrack_unregister_notifier(net, &ctnl_notifier);
3311err_out:
3312 return ret;
3313#endif
3314}
3315
3316static void ctnetlink_net_exit(struct net *net)
3317{
3318#ifdef CONFIG_NF_CONNTRACK_EVENTS
3319 nf_ct_expect_unregister_notifier(net, &ctnl_notifier_exp);
3320 nf_conntrack_unregister_notifier(net, &ctnl_notifier);
3321#endif
3322}
3323
3324static void __net_exit ctnetlink_net_exit_batch(struct list_head *net_exit_list)
3325{
3326 struct net *net;
3327
3328 list_for_each_entry(net, net_exit_list, exit_list)
3329 ctnetlink_net_exit(net);
3330}
3331
3332static struct pernet_operations ctnetlink_net_ops = {
3333 .init = ctnetlink_net_init,
3334 .exit_batch = ctnetlink_net_exit_batch,
3335};
3336
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003337static int __init ctnetlink_init(void)
3338{
3339 int ret;
3340
Stephen Hemminger654d0fb2010-05-13 15:02:08 +02003341 pr_info("ctnetlink v%s: registering with nfnetlink.\n", version);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003342 ret = nfnetlink_subsys_register(&ctnl_subsys);
3343 if (ret < 0) {
Stephen Hemminger654d0fb2010-05-13 15:02:08 +02003344 pr_err("ctnetlink_init: cannot register with nfnetlink.\n");
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003345 goto err_out;
3346 }
3347
3348 ret = nfnetlink_subsys_register(&ctnl_exp_subsys);
3349 if (ret < 0) {
Stephen Hemminger654d0fb2010-05-13 15:02:08 +02003350 pr_err("ctnetlink_init: cannot register exp with nfnetlink.\n");
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003351 goto err_unreg_subsys;
3352 }
3353
Julia Lawallef6acf62012-08-29 06:49:16 +00003354 ret = register_pernet_subsys(&ctnetlink_net_ops);
3355 if (ret < 0) {
Pablo Neira Ayuso70e99422011-11-22 00:16:51 +01003356 pr_err("ctnetlink_init: cannot register pernet operations\n");
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003357 goto err_unreg_exp_subsys;
3358 }
Ken-ichirou MATSUZAWA83f3e942015-10-05 11:48:47 +09003359#ifdef CONFIG_NETFILTER_NETLINK_GLUE_CT
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02003360 /* setup interaction between nf_queue and nf_conntrack_netlink. */
Ken-ichirou MATSUZAWAa4b47662015-10-05 11:47:13 +09003361 RCU_INIT_POINTER(nfnl_ct_hook, &ctnetlink_glue_hook);
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02003362#endif
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003363 return 0;
3364
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003365err_unreg_exp_subsys:
3366 nfnetlink_subsys_unregister(&ctnl_exp_subsys);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003367err_unreg_subsys:
3368 nfnetlink_subsys_unregister(&ctnl_subsys);
3369err_out:
3370 return ret;
3371}
3372
3373static void __exit ctnetlink_exit(void)
3374{
Stephen Hemminger654d0fb2010-05-13 15:02:08 +02003375 pr_info("ctnetlink: unregistering from nfnetlink.\n");
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003376
Pablo Neira Ayuso70e99422011-11-22 00:16:51 +01003377 unregister_pernet_subsys(&ctnetlink_net_ops);
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003378 nfnetlink_subsys_unregister(&ctnl_exp_subsys);
3379 nfnetlink_subsys_unregister(&ctnl_subsys);
Ken-ichirou MATSUZAWA83f3e942015-10-05 11:48:47 +09003380#ifdef CONFIG_NETFILTER_NETLINK_GLUE_CT
Ken-ichirou MATSUZAWAa4b47662015-10-05 11:47:13 +09003381 RCU_INIT_POINTER(nfnl_ct_hook, NULL);
Pablo Neira Ayuso9cb01762012-06-07 12:13:39 +02003382#endif
Pablo Neira Ayusoc1d10ad2006-01-05 12:19:05 -08003383}
3384
3385module_init(ctnetlink_init);
3386module_exit(ctnetlink_exit);