blob: ea737fd789e871d025faf27e6324feb89c930b83 [file] [log] [blame]
Patrick McHardy96518512013-10-14 11:00:02 +02001/*
Patrick McHardyef1f7df2013-10-10 11:41:20 +02002 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
Pablo Neira Ayuso25443262016-10-20 18:07:14 +02003 * Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.org>
Patrick McHardy96518512013-10-14 11:00:02 +02004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Development of this code funded by Astaro AG (http://www.astaro.com/)
10 */
11
12#include <linux/kernel.h>
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/netlink.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter/nf_tables.h>
18#include <net/netfilter/nf_tables.h>
19#include <net/netfilter/nf_conntrack.h>
Florian Westphal48f66c92016-01-07 21:34:24 +010020#include <net/netfilter/nf_conntrack_acct.h>
Patrick McHardy96518512013-10-14 11:00:02 +020021#include <net/netfilter/nf_conntrack_tuple.h>
22#include <net/netfilter/nf_conntrack_helper.h>
Kristian Evensenc4ede3d2014-01-07 16:43:54 +010023#include <net/netfilter/nf_conntrack_ecache.h>
Florian Westphald2bf2f32014-02-18 15:25:32 +010024#include <net/netfilter/nf_conntrack_labels.h>
Patrick McHardy96518512013-10-14 11:00:02 +020025
26struct nft_ct {
27 enum nft_ct_keys key:8;
28 enum ip_conntrack_dir dir:8;
Patrick McHardyd46f2cd2014-03-07 19:08:32 +010029 union {
Kristian Evensenc4ede3d2014-01-07 16:43:54 +010030 enum nft_registers dreg:8;
31 enum nft_registers sreg:8;
32 };
Patrick McHardy96518512013-10-14 11:00:02 +020033};
34
Florian Westphal1a64edf52017-03-08 16:48:44 +010035struct nft_ct_helper_obj {
36 struct nf_conntrack_helper *helper4;
37 struct nf_conntrack_helper *helper6;
38 u8 l4proto;
39};
40
Florian Westphaledee4f12017-02-03 13:35:50 +010041#ifdef CONFIG_NF_CONNTRACK_ZONES
42static DEFINE_PER_CPU(struct nf_conn *, nft_ct_pcpu_template);
43static unsigned int nft_ct_pcpu_template_refcnt __read_mostly;
44#endif
45
Florian Westphal48f66c92016-01-07 21:34:24 +010046static u64 nft_ct_get_eval_counter(const struct nf_conn_counter *c,
47 enum nft_ct_keys k,
48 enum ip_conntrack_dir d)
49{
50 if (d < IP_CT_DIR_MAX)
51 return k == NFT_CT_BYTES ? atomic64_read(&c[d].bytes) :
52 atomic64_read(&c[d].packets);
53
54 return nft_ct_get_eval_counter(c, k, IP_CT_DIR_ORIGINAL) +
55 nft_ct_get_eval_counter(c, k, IP_CT_DIR_REPLY);
56}
57
Kristian Evensenc4ede3d2014-01-07 16:43:54 +010058static void nft_ct_get_eval(const struct nft_expr *expr,
Patrick McHardya55e22e2015-04-11 02:27:31 +010059 struct nft_regs *regs,
Kristian Evensenc4ede3d2014-01-07 16:43:54 +010060 const struct nft_pktinfo *pkt)
Patrick McHardy96518512013-10-14 11:00:02 +020061{
62 const struct nft_ct *priv = nft_expr_priv(expr);
Patrick McHardy49499c32015-04-11 02:27:37 +010063 u32 *dest = &regs->data[priv->dreg];
Patrick McHardy96518512013-10-14 11:00:02 +020064 enum ip_conntrack_info ctinfo;
65 const struct nf_conn *ct;
66 const struct nf_conn_help *help;
67 const struct nf_conntrack_tuple *tuple;
68 const struct nf_conntrack_helper *helper;
Patrick McHardy96518512013-10-14 11:00:02 +020069 unsigned int state;
70
71 ct = nf_ct_get(pkt->skb, &ctinfo);
72
73 switch (priv->key) {
74 case NFT_CT_STATE:
Florian Westphalcc41c842017-04-14 20:31:08 +020075 if (ct)
76 state = NF_CT_STATE_BIT(ctinfo);
77 else if (ctinfo == IP_CT_UNTRACKED)
Patrick McHardy96518512013-10-14 11:00:02 +020078 state = NF_CT_STATE_UNTRACKED_BIT;
79 else
Florian Westphalcc41c842017-04-14 20:31:08 +020080 state = NF_CT_STATE_INVALID_BIT;
Patrick McHardyfad136e2015-04-11 02:27:33 +010081 *dest = state;
Patrick McHardy96518512013-10-14 11:00:02 +020082 return;
David Millerc1f86672015-04-07 23:05:42 -040083 default:
84 break;
Patrick McHardy96518512013-10-14 11:00:02 +020085 }
86
87 if (ct == NULL)
88 goto err;
89
90 switch (priv->key) {
91 case NFT_CT_DIRECTION:
Liping Zhang10596602017-03-08 22:54:18 +080092 nft_reg_store8(dest, CTINFO2DIR(ctinfo));
Patrick McHardy96518512013-10-14 11:00:02 +020093 return;
94 case NFT_CT_STATUS:
Patrick McHardyfad136e2015-04-11 02:27:33 +010095 *dest = ct->status;
Patrick McHardy96518512013-10-14 11:00:02 +020096 return;
97#ifdef CONFIG_NF_CONNTRACK_MARK
98 case NFT_CT_MARK:
Patrick McHardyfad136e2015-04-11 02:27:33 +010099 *dest = ct->mark;
Patrick McHardy96518512013-10-14 11:00:02 +0200100 return;
101#endif
102#ifdef CONFIG_NF_CONNTRACK_SECMARK
103 case NFT_CT_SECMARK:
Patrick McHardyfad136e2015-04-11 02:27:33 +0100104 *dest = ct->secmark;
Patrick McHardy96518512013-10-14 11:00:02 +0200105 return;
106#endif
107 case NFT_CT_EXPIRATION:
Florian Westphalc8607e02016-07-06 14:53:06 +0200108 *dest = jiffies_to_msecs(nf_ct_expires(ct));
Patrick McHardy96518512013-10-14 11:00:02 +0200109 return;
110 case NFT_CT_HELPER:
111 if (ct->master == NULL)
112 goto err;
113 help = nfct_help(ct->master);
114 if (help == NULL)
115 goto err;
116 helper = rcu_dereference(help->helper);
117 if (helper == NULL)
118 goto err;
Patrick McHardyfad136e2015-04-11 02:27:33 +0100119 strncpy((char *)dest, helper->name, NF_CT_HELPER_NAME_LEN);
Patrick McHardy96518512013-10-14 11:00:02 +0200120 return;
Florian Westphald2bf2f32014-02-18 15:25:32 +0100121#ifdef CONFIG_NF_CONNTRACK_LABELS
122 case NFT_CT_LABELS: {
123 struct nf_conn_labels *labels = nf_ct_labels_find(ct);
Florian Westphald2bf2f32014-02-18 15:25:32 +0100124
Florian Westphal23014012016-07-21 12:51:16 +0200125 if (labels)
126 memcpy(dest, labels->bits, NF_CT_LABELS_MAX_SIZE);
127 else
Patrick McHardyfad136e2015-04-11 02:27:33 +0100128 memset(dest, 0, NF_CT_LABELS_MAX_SIZE);
Florian Westphald2bf2f32014-02-18 15:25:32 +0100129 return;
130 }
Pablo Neira Ayusoefaea942016-01-13 17:34:38 +0100131#endif
Florian Westphal48f66c92016-01-07 21:34:24 +0100132 case NFT_CT_BYTES: /* fallthrough */
133 case NFT_CT_PKTS: {
134 const struct nf_conn_acct *acct = nf_conn_acct_find(ct);
135 u64 count = 0;
136
137 if (acct)
138 count = nft_ct_get_eval_counter(acct->counter,
139 priv->key, priv->dir);
140 memcpy(dest, &count, sizeof(count));
141 return;
142 }
Liping Zhang949a3582016-12-25 19:58:59 +0800143 case NFT_CT_AVGPKT: {
144 const struct nf_conn_acct *acct = nf_conn_acct_find(ct);
145 u64 avgcnt = 0, bcnt = 0, pcnt = 0;
146
147 if (acct) {
148 pcnt = nft_ct_get_eval_counter(acct->counter,
149 NFT_CT_PKTS, priv->dir);
150 bcnt = nft_ct_get_eval_counter(acct->counter,
151 NFT_CT_BYTES, priv->dir);
152 if (pcnt != 0)
153 avgcnt = div64_u64(bcnt, pcnt);
154 }
155
156 memcpy(dest, &avgcnt, sizeof(avgcnt));
157 return;
158 }
Liping Zhangd767ff22016-09-22 22:28:51 +0800159 case NFT_CT_L3PROTOCOL:
Liping Zhang10596602017-03-08 22:54:18 +0800160 nft_reg_store8(dest, nf_ct_l3num(ct));
Liping Zhangd767ff22016-09-22 22:28:51 +0800161 return;
162 case NFT_CT_PROTOCOL:
Liping Zhang10596602017-03-08 22:54:18 +0800163 nft_reg_store8(dest, nf_ct_protonum(ct));
Liping Zhangd767ff22016-09-22 22:28:51 +0800164 return;
Florian Westphalab238212017-02-03 13:35:48 +0100165#ifdef CONFIG_NF_CONNTRACK_ZONES
166 case NFT_CT_ZONE: {
167 const struct nf_conntrack_zone *zone = nf_ct_zone(ct);
Liping Zhang10596602017-03-08 22:54:18 +0800168 u16 zoneid;
Florian Westphalab238212017-02-03 13:35:48 +0100169
170 if (priv->dir < IP_CT_DIR_MAX)
Liping Zhang10596602017-03-08 22:54:18 +0800171 zoneid = nf_ct_zone_id(zone, priv->dir);
Florian Westphalab238212017-02-03 13:35:48 +0100172 else
Liping Zhang10596602017-03-08 22:54:18 +0800173 zoneid = zone->id;
Florian Westphalab238212017-02-03 13:35:48 +0100174
Liping Zhang10596602017-03-08 22:54:18 +0800175 nft_reg_store16(dest, zoneid);
Florian Westphalab238212017-02-03 13:35:48 +0100176 return;
177 }
178#endif
David Millerc1f86672015-04-07 23:05:42 -0400179 default:
180 break;
Patrick McHardy96518512013-10-14 11:00:02 +0200181 }
182
183 tuple = &ct->tuplehash[priv->dir].tuple;
184 switch (priv->key) {
Patrick McHardy96518512013-10-14 11:00:02 +0200185 case NFT_CT_SRC:
Patrick McHardyfad136e2015-04-11 02:27:33 +0100186 memcpy(dest, tuple->src.u3.all,
Patrick McHardy96518512013-10-14 11:00:02 +0200187 nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
188 return;
189 case NFT_CT_DST:
Patrick McHardyfad136e2015-04-11 02:27:33 +0100190 memcpy(dest, tuple->dst.u3.all,
Patrick McHardy96518512013-10-14 11:00:02 +0200191 nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
192 return;
Patrick McHardy96518512013-10-14 11:00:02 +0200193 case NFT_CT_PROTO_SRC:
Liping Zhang10596602017-03-08 22:54:18 +0800194 nft_reg_store16(dest, (__force u16)tuple->src.u.all);
Patrick McHardy96518512013-10-14 11:00:02 +0200195 return;
196 case NFT_CT_PROTO_DST:
Liping Zhang10596602017-03-08 22:54:18 +0800197 nft_reg_store16(dest, (__force u16)tuple->dst.u.all);
Patrick McHardy96518512013-10-14 11:00:02 +0200198 return;
Pablo Neira Ayusod719e3f2018-03-09 11:57:20 +0100199 case NFT_CT_SRC_IP:
200 if (nf_ct_l3num(ct) != NFPROTO_IPV4)
201 goto err;
202 *dest = tuple->src.u3.ip;
203 return;
204 case NFT_CT_DST_IP:
205 if (nf_ct_l3num(ct) != NFPROTO_IPV4)
206 goto err;
207 *dest = tuple->dst.u3.ip;
208 return;
209 case NFT_CT_SRC_IP6:
210 if (nf_ct_l3num(ct) != NFPROTO_IPV6)
211 goto err;
212 memcpy(dest, tuple->src.u3.ip6, sizeof(struct in6_addr));
213 return;
214 case NFT_CT_DST_IP6:
215 if (nf_ct_l3num(ct) != NFPROTO_IPV6)
216 goto err;
217 memcpy(dest, tuple->dst.u3.ip6, sizeof(struct in6_addr));
218 return;
David Millerc1f86672015-04-07 23:05:42 -0400219 default:
220 break;
Patrick McHardy96518512013-10-14 11:00:02 +0200221 }
222 return;
223err:
Patrick McHardya55e22e2015-04-11 02:27:31 +0100224 regs->verdict.code = NFT_BREAK;
Patrick McHardy96518512013-10-14 11:00:02 +0200225}
226
Florian Westphaledee4f12017-02-03 13:35:50 +0100227#ifdef CONFIG_NF_CONNTRACK_ZONES
228static void nft_ct_set_zone_eval(const struct nft_expr *expr,
229 struct nft_regs *regs,
230 const struct nft_pktinfo *pkt)
231{
232 struct nf_conntrack_zone zone = { .dir = NF_CT_DEFAULT_ZONE_DIR };
233 const struct nft_ct *priv = nft_expr_priv(expr);
234 struct sk_buff *skb = pkt->skb;
235 enum ip_conntrack_info ctinfo;
Liping Zhang10596602017-03-08 22:54:18 +0800236 u16 value = nft_reg_load16(&regs->data[priv->sreg]);
Florian Westphaledee4f12017-02-03 13:35:50 +0100237 struct nf_conn *ct;
238
239 ct = nf_ct_get(skb, &ctinfo);
240 if (ct) /* already tracked */
241 return;
242
243 zone.id = value;
244
245 switch (priv->dir) {
246 case IP_CT_DIR_ORIGINAL:
247 zone.dir = NF_CT_ZONE_DIR_ORIG;
248 break;
249 case IP_CT_DIR_REPLY:
250 zone.dir = NF_CT_ZONE_DIR_REPL;
251 break;
252 default:
253 break;
254 }
255
256 ct = this_cpu_read(nft_ct_pcpu_template);
257
258 if (likely(atomic_read(&ct->ct_general.use) == 1)) {
259 nf_ct_zone_add(ct, &zone);
260 } else {
261 /* previous skb got queued to userspace */
262 ct = nf_ct_tmpl_alloc(nft_net(pkt), &zone, GFP_ATOMIC);
263 if (!ct) {
264 regs->verdict.code = NF_DROP;
265 return;
266 }
267 }
268
269 atomic_inc(&ct->ct_general.use);
270 nf_ct_set(skb, ct, IP_CT_NEW);
271}
272#endif
273
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100274static void nft_ct_set_eval(const struct nft_expr *expr,
Patrick McHardya55e22e2015-04-11 02:27:31 +0100275 struct nft_regs *regs,
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100276 const struct nft_pktinfo *pkt)
277{
278 const struct nft_ct *priv = nft_expr_priv(expr);
279 struct sk_buff *skb = pkt->skb;
Kristian Evensen847c8e22014-01-10 21:43:20 +0100280#ifdef CONFIG_NF_CONNTRACK_MARK
Patrick McHardy49499c32015-04-11 02:27:37 +0100281 u32 value = regs->data[priv->sreg];
Kristian Evensen847c8e22014-01-10 21:43:20 +0100282#endif
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100283 enum ip_conntrack_info ctinfo;
284 struct nf_conn *ct;
285
286 ct = nf_ct_get(skb, &ctinfo);
Florian Westphal694a0052017-04-15 19:26:10 +0200287 if (ct == NULL || nf_ct_is_template(ct))
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100288 return;
289
290 switch (priv->key) {
291#ifdef CONFIG_NF_CONNTRACK_MARK
292 case NFT_CT_MARK:
293 if (ct->mark != value) {
294 ct->mark = value;
295 nf_conntrack_event_cache(IPCT_MARK, ct);
296 }
297 break;
298#endif
Florian Westphal1ad8f482016-04-26 11:59:53 +0200299#ifdef CONFIG_NF_CONNTRACK_LABELS
300 case NFT_CT_LABELS:
301 nf_connlabels_replace(ct,
302 &regs->data[priv->sreg],
303 &regs->data[priv->sreg],
304 NF_CT_LABELS_MAX_SIZE / sizeof(u32));
305 break;
306#endif
Florian Westphal694a0052017-04-15 19:26:10 +0200307#ifdef CONFIG_NF_CONNTRACK_EVENTS
308 case NFT_CT_EVENTMASK: {
309 struct nf_conntrack_ecache *e = nf_ct_ecache_find(ct);
310 u32 ctmask = regs->data[priv->sreg];
311
312 if (e) {
313 if (e->ctmask != ctmask)
314 e->ctmask = ctmask;
315 break;
316 }
317
318 if (ctmask && !nf_ct_is_confirmed(ct))
319 nf_ct_ecache_ext_add(ct, ctmask, 0, GFP_ATOMIC);
320 break;
321 }
322#endif
David Millerc1f86672015-04-07 23:05:42 -0400323 default:
324 break;
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100325 }
326}
327
Patrick McHardy96518512013-10-14 11:00:02 +0200328static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = {
329 [NFTA_CT_DREG] = { .type = NLA_U32 },
330 [NFTA_CT_KEY] = { .type = NLA_U32 },
331 [NFTA_CT_DIRECTION] = { .type = NLA_U8 },
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100332 [NFTA_CT_SREG] = { .type = NLA_U32 },
Patrick McHardy96518512013-10-14 11:00:02 +0200333};
334
Florian Westphaledee4f12017-02-03 13:35:50 +0100335#ifdef CONFIG_NF_CONNTRACK_ZONES
336static void nft_ct_tmpl_put_pcpu(void)
337{
338 struct nf_conn *ct;
339 int cpu;
340
341 for_each_possible_cpu(cpu) {
342 ct = per_cpu(nft_ct_pcpu_template, cpu);
343 if (!ct)
344 break;
345 nf_ct_put(ct);
346 per_cpu(nft_ct_pcpu_template, cpu) = NULL;
347 }
348}
349
350static bool nft_ct_tmpl_alloc_pcpu(void)
351{
352 struct nf_conntrack_zone zone = { .id = 0 };
353 struct nf_conn *tmp;
354 int cpu;
355
356 if (nft_ct_pcpu_template_refcnt)
357 return true;
358
359 for_each_possible_cpu(cpu) {
360 tmp = nf_ct_tmpl_alloc(&init_net, &zone, GFP_KERNEL);
361 if (!tmp) {
362 nft_ct_tmpl_put_pcpu();
363 return false;
364 }
365
366 atomic_set(&tmp->ct_general.use, 1);
367 per_cpu(nft_ct_pcpu_template, cpu) = tmp;
368 }
369
370 return true;
371}
372#endif
373
Patrick McHardyfe92ca42014-03-29 10:43:03 +0000374static int nft_ct_get_init(const struct nft_ctx *ctx,
375 const struct nft_expr *expr,
376 const struct nlattr * const tb[])
Patrick McHardy96518512013-10-14 11:00:02 +0200377{
378 struct nft_ct *priv = nft_expr_priv(expr);
Patrick McHardy45d9bcd2015-04-11 02:27:26 +0100379 unsigned int len;
Patrick McHardyfe92ca42014-03-29 10:43:03 +0000380 int err;
Patrick McHardy96518512013-10-14 11:00:02 +0200381
Patrick McHardyfe92ca42014-03-29 10:43:03 +0000382 priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
Florian Westphalab238212017-02-03 13:35:48 +0100383 priv->dir = IP_CT_DIR_MAX;
Patrick McHardy96518512013-10-14 11:00:02 +0200384 switch (priv->key) {
Patrick McHardy96518512013-10-14 11:00:02 +0200385 case NFT_CT_DIRECTION:
Patrick McHardy45d9bcd2015-04-11 02:27:26 +0100386 if (tb[NFTA_CT_DIRECTION] != NULL)
387 return -EINVAL;
388 len = sizeof(u8);
389 break;
390 case NFT_CT_STATE:
Patrick McHardy96518512013-10-14 11:00:02 +0200391 case NFT_CT_STATUS:
392#ifdef CONFIG_NF_CONNTRACK_MARK
393 case NFT_CT_MARK:
394#endif
395#ifdef CONFIG_NF_CONNTRACK_SECMARK
396 case NFT_CT_SECMARK:
397#endif
Patrick McHardy45d9bcd2015-04-11 02:27:26 +0100398 case NFT_CT_EXPIRATION:
399 if (tb[NFTA_CT_DIRECTION] != NULL)
400 return -EINVAL;
401 len = sizeof(u32);
402 break;
Florian Westphald2bf2f32014-02-18 15:25:32 +0100403#ifdef CONFIG_NF_CONNTRACK_LABELS
404 case NFT_CT_LABELS:
Patrick McHardy45d9bcd2015-04-11 02:27:26 +0100405 if (tb[NFTA_CT_DIRECTION] != NULL)
406 return -EINVAL;
407 len = NF_CT_LABELS_MAX_SIZE;
408 break;
Florian Westphald2bf2f32014-02-18 15:25:32 +0100409#endif
Patrick McHardy96518512013-10-14 11:00:02 +0200410 case NFT_CT_HELPER:
411 if (tb[NFTA_CT_DIRECTION] != NULL)
412 return -EINVAL;
Patrick McHardy45d9bcd2015-04-11 02:27:26 +0100413 len = NF_CT_HELPER_NAME_LEN;
Patrick McHardy96518512013-10-14 11:00:02 +0200414 break;
Patrick McHardy45d9bcd2015-04-11 02:27:26 +0100415
Patrick McHardy51292c02014-02-05 15:03:36 +0000416 case NFT_CT_L3PROTOCOL:
Patrick McHardy96518512013-10-14 11:00:02 +0200417 case NFT_CT_PROTOCOL:
Liping Zhangd767ff22016-09-22 22:28:51 +0800418 /* For compatibility, do not report error if NFTA_CT_DIRECTION
419 * attribute is specified.
420 */
Patrick McHardy45d9bcd2015-04-11 02:27:26 +0100421 len = sizeof(u8);
422 break;
Patrick McHardy96518512013-10-14 11:00:02 +0200423 case NFT_CT_SRC:
424 case NFT_CT_DST:
Patrick McHardy45d9bcd2015-04-11 02:27:26 +0100425 if (tb[NFTA_CT_DIRECTION] == NULL)
426 return -EINVAL;
427
Pablo Neira Ayuso36596da2018-01-09 02:38:03 +0100428 switch (ctx->family) {
Patrick McHardy45d9bcd2015-04-11 02:27:26 +0100429 case NFPROTO_IPV4:
430 len = FIELD_SIZEOF(struct nf_conntrack_tuple,
431 src.u3.ip);
432 break;
433 case NFPROTO_IPV6:
434 case NFPROTO_INET:
435 len = FIELD_SIZEOF(struct nf_conntrack_tuple,
436 src.u3.ip6);
437 break;
438 default:
439 return -EAFNOSUPPORT;
440 }
441 break;
Pablo Neira Ayusod719e3f2018-03-09 11:57:20 +0100442 case NFT_CT_SRC_IP:
443 case NFT_CT_DST_IP:
444 if (tb[NFTA_CT_DIRECTION] == NULL)
445 return -EINVAL;
446
447 len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u3.ip);
448 break;
449 case NFT_CT_SRC_IP6:
450 case NFT_CT_DST_IP6:
451 if (tb[NFTA_CT_DIRECTION] == NULL)
452 return -EINVAL;
453
454 len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u3.ip6);
455 break;
Patrick McHardy96518512013-10-14 11:00:02 +0200456 case NFT_CT_PROTO_SRC:
457 case NFT_CT_PROTO_DST:
458 if (tb[NFTA_CT_DIRECTION] == NULL)
459 return -EINVAL;
Patrick McHardy45d9bcd2015-04-11 02:27:26 +0100460 len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all);
Patrick McHardy96518512013-10-14 11:00:02 +0200461 break;
Florian Westphal48f66c92016-01-07 21:34:24 +0100462 case NFT_CT_BYTES:
463 case NFT_CT_PKTS:
Liping Zhang949a3582016-12-25 19:58:59 +0800464 case NFT_CT_AVGPKT:
Florian Westphal48f66c92016-01-07 21:34:24 +0100465 len = sizeof(u64);
466 break;
Florian Westphalab238212017-02-03 13:35:48 +0100467#ifdef CONFIG_NF_CONNTRACK_ZONES
468 case NFT_CT_ZONE:
469 len = sizeof(u16);
470 break;
471#endif
Patrick McHardy96518512013-10-14 11:00:02 +0200472 default:
473 return -EOPNOTSUPP;
474 }
475
Patrick McHardyfe92ca42014-03-29 10:43:03 +0000476 if (tb[NFTA_CT_DIRECTION] != NULL) {
477 priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
478 switch (priv->dir) {
479 case IP_CT_DIR_ORIGINAL:
480 case IP_CT_DIR_REPLY:
481 break;
482 default:
483 return -EINVAL;
484 }
485 }
486
Patrick McHardyb1c96ed2015-04-11 02:27:36 +0100487 priv->dreg = nft_parse_register(tb[NFTA_CT_DREG]);
Patrick McHardy1ec10212015-04-11 02:27:27 +0100488 err = nft_validate_register_store(ctx, priv->dreg, NULL,
489 NFT_DATA_VALUE, len);
Patrick McHardyfe92ca42014-03-29 10:43:03 +0000490 if (err < 0)
491 return err;
492
Pablo Neira Ayuso36596da2018-01-09 02:38:03 +0100493 err = nf_ct_netns_get(ctx->net, ctx->family);
Patrick McHardyfe92ca42014-03-29 10:43:03 +0000494 if (err < 0)
495 return err;
496
Liping Zhang949a3582016-12-25 19:58:59 +0800497 if (priv->key == NFT_CT_BYTES ||
498 priv->key == NFT_CT_PKTS ||
499 priv->key == NFT_CT_AVGPKT)
Liping Zhang3f8b61b2016-07-05 23:23:00 +0800500 nf_ct_set_acct(ctx->net, true);
501
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100502 return 0;
503}
504
Florian Westphal5c178d82017-02-03 13:35:49 +0100505static void __nft_ct_set_destroy(const struct nft_ctx *ctx, struct nft_ct *priv)
506{
507 switch (priv->key) {
508#ifdef CONFIG_NF_CONNTRACK_LABELS
509 case NFT_CT_LABELS:
510 nf_connlabels_put(ctx->net);
511 break;
512#endif
Florian Westphaledee4f12017-02-03 13:35:50 +0100513#ifdef CONFIG_NF_CONNTRACK_ZONES
514 case NFT_CT_ZONE:
515 if (--nft_ct_pcpu_template_refcnt == 0)
516 nft_ct_tmpl_put_pcpu();
517#endif
Florian Westphal5c178d82017-02-03 13:35:49 +0100518 default:
519 break;
520 }
521}
522
Patrick McHardyfe92ca42014-03-29 10:43:03 +0000523static int nft_ct_set_init(const struct nft_ctx *ctx,
524 const struct nft_expr *expr,
525 const struct nlattr * const tb[])
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100526{
Patrick McHardyfe92ca42014-03-29 10:43:03 +0000527 struct nft_ct *priv = nft_expr_priv(expr);
Patrick McHardyd07db982015-04-11 02:27:30 +0100528 unsigned int len;
Patrick McHardyfe92ca42014-03-29 10:43:03 +0000529 int err;
530
Florian Westphaledee4f12017-02-03 13:35:50 +0100531 priv->dir = IP_CT_DIR_MAX;
Patrick McHardyfe92ca42014-03-29 10:43:03 +0000532 priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
533 switch (priv->key) {
Patrick McHardye88e5142014-03-29 10:43:01 +0000534#ifdef CONFIG_NF_CONNTRACK_MARK
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100535 case NFT_CT_MARK:
Liping Zhang7bfdde72016-09-22 22:28:52 +0800536 if (tb[NFTA_CT_DIRECTION])
537 return -EINVAL;
Patrick McHardyd07db982015-04-11 02:27:30 +0100538 len = FIELD_SIZEOF(struct nf_conn, mark);
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100539 break;
Patrick McHardye88e5142014-03-29 10:43:01 +0000540#endif
Florian Westphal1ad8f482016-04-26 11:59:53 +0200541#ifdef CONFIG_NF_CONNTRACK_LABELS
542 case NFT_CT_LABELS:
543 if (tb[NFTA_CT_DIRECTION])
544 return -EINVAL;
545 len = NF_CT_LABELS_MAX_SIZE;
546 err = nf_connlabels_get(ctx->net, (len * BITS_PER_BYTE) - 1);
547 if (err)
548 return err;
549 break;
550#endif
Florian Westphaledee4f12017-02-03 13:35:50 +0100551#ifdef CONFIG_NF_CONNTRACK_ZONES
552 case NFT_CT_ZONE:
553 if (!nft_ct_tmpl_alloc_pcpu())
554 return -ENOMEM;
555 nft_ct_pcpu_template_refcnt++;
Florian Westphal427345d2017-02-13 22:26:49 +0100556 len = sizeof(u16);
Florian Westphaledee4f12017-02-03 13:35:50 +0100557 break;
558#endif
Florian Westphal694a0052017-04-15 19:26:10 +0200559#ifdef CONFIG_NF_CONNTRACK_EVENTS
560 case NFT_CT_EVENTMASK:
561 if (tb[NFTA_CT_DIRECTION])
562 return -EINVAL;
563 len = sizeof(u32);
564 break;
565#endif
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100566 default:
567 return -EOPNOTSUPP;
568 }
569
Florian Westphaledee4f12017-02-03 13:35:50 +0100570 if (tb[NFTA_CT_DIRECTION]) {
571 priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
572 switch (priv->dir) {
573 case IP_CT_DIR_ORIGINAL:
574 case IP_CT_DIR_REPLY:
575 break;
576 default:
Liping Zhang4494dbc2017-03-15 22:22:08 +0800577 err = -EINVAL;
578 goto err1;
Florian Westphaledee4f12017-02-03 13:35:50 +0100579 }
580 }
581
Patrick McHardyb1c96ed2015-04-11 02:27:36 +0100582 priv->sreg = nft_parse_register(tb[NFTA_CT_SREG]);
Patrick McHardyd07db982015-04-11 02:27:30 +0100583 err = nft_validate_register_load(priv->sreg, len);
Patrick McHardyfe92ca42014-03-29 10:43:03 +0000584 if (err < 0)
Liping Zhang590025a2016-07-16 14:27:21 +0800585 goto err1;
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100586
Pablo Neira Ayuso36596da2018-01-09 02:38:03 +0100587 err = nf_ct_netns_get(ctx->net, ctx->family);
Patrick McHardy96518512013-10-14 11:00:02 +0200588 if (err < 0)
Liping Zhang590025a2016-07-16 14:27:21 +0800589 goto err1;
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100590
Patrick McHardy96518512013-10-14 11:00:02 +0200591 return 0;
Liping Zhang590025a2016-07-16 14:27:21 +0800592
593err1:
Florian Westphal5c178d82017-02-03 13:35:49 +0100594 __nft_ct_set_destroy(ctx, priv);
Liping Zhang590025a2016-07-16 14:27:21 +0800595 return err;
Patrick McHardy96518512013-10-14 11:00:02 +0200596}
597
Liping Zhang590025a2016-07-16 14:27:21 +0800598static void nft_ct_get_destroy(const struct nft_ctx *ctx,
599 const struct nft_expr *expr)
600{
Pablo Neira Ayuso36596da2018-01-09 02:38:03 +0100601 nf_ct_netns_put(ctx->net, ctx->family);
Liping Zhang590025a2016-07-16 14:27:21 +0800602}
603
604static void nft_ct_set_destroy(const struct nft_ctx *ctx,
605 const struct nft_expr *expr)
Patrick McHardy96518512013-10-14 11:00:02 +0200606{
Florian Westphal1ad8f482016-04-26 11:59:53 +0200607 struct nft_ct *priv = nft_expr_priv(expr);
608
Florian Westphal5c178d82017-02-03 13:35:49 +0100609 __nft_ct_set_destroy(ctx, priv);
Pablo Neira Ayuso36596da2018-01-09 02:38:03 +0100610 nf_ct_netns_put(ctx->net, ctx->family);
Patrick McHardy96518512013-10-14 11:00:02 +0200611}
612
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100613static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
Patrick McHardy96518512013-10-14 11:00:02 +0200614{
615 const struct nft_ct *priv = nft_expr_priv(expr);
616
Patrick McHardyb1c96ed2015-04-11 02:27:36 +0100617 if (nft_dump_register(skb, NFTA_CT_DREG, priv->dreg))
Patrick McHardy96518512013-10-14 11:00:02 +0200618 goto nla_put_failure;
619 if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
620 goto nla_put_failure;
Arturo Borrero2a53bfb2014-01-17 02:28:45 +0100621
622 switch (priv->key) {
Arturo Borrero2a53bfb2014-01-17 02:28:45 +0100623 case NFT_CT_SRC:
624 case NFT_CT_DST:
Pablo Neira Ayusod719e3f2018-03-09 11:57:20 +0100625 case NFT_CT_SRC_IP:
626 case NFT_CT_DST_IP:
627 case NFT_CT_SRC_IP6:
628 case NFT_CT_DST_IP6:
Arturo Borrero2a53bfb2014-01-17 02:28:45 +0100629 case NFT_CT_PROTO_SRC:
630 case NFT_CT_PROTO_DST:
631 if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
632 goto nla_put_failure;
Florian Westphal48f66c92016-01-07 21:34:24 +0100633 break;
634 case NFT_CT_BYTES:
635 case NFT_CT_PKTS:
Liping Zhang949a3582016-12-25 19:58:59 +0800636 case NFT_CT_AVGPKT:
Florian Westphalab238212017-02-03 13:35:48 +0100637 case NFT_CT_ZONE:
Florian Westphal48f66c92016-01-07 21:34:24 +0100638 if (priv->dir < IP_CT_DIR_MAX &&
639 nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
640 goto nla_put_failure;
641 break;
Arturo Borrero2a53bfb2014-01-17 02:28:45 +0100642 default:
643 break;
644 }
645
Patrick McHardy96518512013-10-14 11:00:02 +0200646 return 0;
647
648nla_put_failure:
649 return -1;
650}
651
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100652static int nft_ct_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
653{
654 const struct nft_ct *priv = nft_expr_priv(expr);
655
Patrick McHardyb1c96ed2015-04-11 02:27:36 +0100656 if (nft_dump_register(skb, NFTA_CT_SREG, priv->sreg))
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100657 goto nla_put_failure;
658 if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
659 goto nla_put_failure;
Florian Westphaledee4f12017-02-03 13:35:50 +0100660
661 switch (priv->key) {
662 case NFT_CT_ZONE:
663 if (priv->dir < IP_CT_DIR_MAX &&
664 nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
665 goto nla_put_failure;
666 break;
667 default:
668 break;
669 }
670
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100671 return 0;
672
673nla_put_failure:
674 return -1;
675}
676
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200677static struct nft_expr_type nft_ct_type;
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100678static const struct nft_expr_ops nft_ct_get_ops = {
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200679 .type = &nft_ct_type,
Patrick McHardy96518512013-10-14 11:00:02 +0200680 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100681 .eval = nft_ct_get_eval,
Patrick McHardyfe92ca42014-03-29 10:43:03 +0000682 .init = nft_ct_get_init,
Liping Zhang590025a2016-07-16 14:27:21 +0800683 .destroy = nft_ct_get_destroy,
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100684 .dump = nft_ct_get_dump,
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200685};
686
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100687static const struct nft_expr_ops nft_ct_set_ops = {
688 .type = &nft_ct_type,
689 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
690 .eval = nft_ct_set_eval,
Patrick McHardyfe92ca42014-03-29 10:43:03 +0000691 .init = nft_ct_set_init,
Liping Zhang590025a2016-07-16 14:27:21 +0800692 .destroy = nft_ct_set_destroy,
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100693 .dump = nft_ct_set_dump,
694};
695
Florian Westphaledee4f12017-02-03 13:35:50 +0100696#ifdef CONFIG_NF_CONNTRACK_ZONES
697static const struct nft_expr_ops nft_ct_set_zone_ops = {
698 .type = &nft_ct_type,
699 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
700 .eval = nft_ct_set_zone_eval,
701 .init = nft_ct_set_init,
702 .destroy = nft_ct_set_destroy,
703 .dump = nft_ct_set_dump,
704};
705#endif
706
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100707static const struct nft_expr_ops *
708nft_ct_select_ops(const struct nft_ctx *ctx,
709 const struct nlattr * const tb[])
710{
711 if (tb[NFTA_CT_KEY] == NULL)
712 return ERR_PTR(-EINVAL);
713
714 if (tb[NFTA_CT_DREG] && tb[NFTA_CT_SREG])
715 return ERR_PTR(-EINVAL);
716
717 if (tb[NFTA_CT_DREG])
718 return &nft_ct_get_ops;
719
Florian Westphaledee4f12017-02-03 13:35:50 +0100720 if (tb[NFTA_CT_SREG]) {
721#ifdef CONFIG_NF_CONNTRACK_ZONES
722 if (nla_get_be32(tb[NFTA_CT_KEY]) == htonl(NFT_CT_ZONE))
723 return &nft_ct_set_zone_ops;
724#endif
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100725 return &nft_ct_set_ops;
Florian Westphaledee4f12017-02-03 13:35:50 +0100726 }
Kristian Evensenc4ede3d2014-01-07 16:43:54 +0100727
728 return ERR_PTR(-EINVAL);
729}
730
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200731static struct nft_expr_type nft_ct_type __read_mostly = {
732 .name = "ct",
Arushi Singhald4ef3832017-04-02 14:52:12 +0530733 .select_ops = nft_ct_select_ops,
Patrick McHardy96518512013-10-14 11:00:02 +0200734 .policy = nft_ct_policy,
735 .maxattr = NFTA_CT_MAX,
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200736 .owner = THIS_MODULE,
Patrick McHardy96518512013-10-14 11:00:02 +0200737};
738
Pablo Neira Ayuso25443262016-10-20 18:07:14 +0200739static void nft_notrack_eval(const struct nft_expr *expr,
740 struct nft_regs *regs,
741 const struct nft_pktinfo *pkt)
742{
743 struct sk_buff *skb = pkt->skb;
744 enum ip_conntrack_info ctinfo;
745 struct nf_conn *ct;
746
747 ct = nf_ct_get(pkt->skb, &ctinfo);
748 /* Previously seen (loopback or untracked)? Ignore. */
Florian Westphalcc41c842017-04-14 20:31:08 +0200749 if (ct || ctinfo == IP_CT_UNTRACKED)
Pablo Neira Ayuso25443262016-10-20 18:07:14 +0200750 return;
751
Florian Westphalcc41c842017-04-14 20:31:08 +0200752 nf_ct_set(skb, ct, IP_CT_UNTRACKED);
Pablo Neira Ayuso25443262016-10-20 18:07:14 +0200753}
754
755static struct nft_expr_type nft_notrack_type;
756static const struct nft_expr_ops nft_notrack_ops = {
757 .type = &nft_notrack_type,
758 .size = NFT_EXPR_SIZE(0),
759 .eval = nft_notrack_eval,
760};
761
762static struct nft_expr_type nft_notrack_type __read_mostly = {
763 .name = "notrack",
764 .ops = &nft_notrack_ops,
765 .owner = THIS_MODULE,
766};
767
Florian Westphal1a64edf52017-03-08 16:48:44 +0100768static int nft_ct_helper_obj_init(const struct nft_ctx *ctx,
769 const struct nlattr * const tb[],
770 struct nft_object *obj)
771{
772 struct nft_ct_helper_obj *priv = nft_obj_data(obj);
773 struct nf_conntrack_helper *help4, *help6;
774 char name[NF_CT_HELPER_NAME_LEN];
Pablo Neira Ayuso36596da2018-01-09 02:38:03 +0100775 int family = ctx->family;
Florian Westphal1a64edf52017-03-08 16:48:44 +0100776
777 if (!tb[NFTA_CT_HELPER_NAME] || !tb[NFTA_CT_HELPER_L4PROTO])
778 return -EINVAL;
779
780 priv->l4proto = nla_get_u8(tb[NFTA_CT_HELPER_L4PROTO]);
781 if (!priv->l4proto)
782 return -ENOENT;
783
784 nla_strlcpy(name, tb[NFTA_CT_HELPER_NAME], sizeof(name));
785
786 if (tb[NFTA_CT_HELPER_L3PROTO])
787 family = ntohs(nla_get_be16(tb[NFTA_CT_HELPER_L3PROTO]));
788
789 help4 = NULL;
790 help6 = NULL;
791
792 switch (family) {
793 case NFPROTO_IPV4:
Pablo Neira Ayuso36596da2018-01-09 02:38:03 +0100794 if (ctx->family == NFPROTO_IPV6)
Florian Westphal1a64edf52017-03-08 16:48:44 +0100795 return -EINVAL;
796
797 help4 = nf_conntrack_helper_try_module_get(name, family,
798 priv->l4proto);
799 break;
800 case NFPROTO_IPV6:
Pablo Neira Ayuso36596da2018-01-09 02:38:03 +0100801 if (ctx->family == NFPROTO_IPV4)
Florian Westphal1a64edf52017-03-08 16:48:44 +0100802 return -EINVAL;
803
804 help6 = nf_conntrack_helper_try_module_get(name, family,
805 priv->l4proto);
806 break;
807 case NFPROTO_NETDEV: /* fallthrough */
808 case NFPROTO_BRIDGE: /* same */
809 case NFPROTO_INET:
810 help4 = nf_conntrack_helper_try_module_get(name, NFPROTO_IPV4,
811 priv->l4proto);
812 help6 = nf_conntrack_helper_try_module_get(name, NFPROTO_IPV6,
813 priv->l4proto);
814 break;
815 default:
816 return -EAFNOSUPPORT;
817 }
818
819 /* && is intentional; only error if INET found neither ipv4 or ipv6 */
820 if (!help4 && !help6)
821 return -ENOENT;
822
823 priv->helper4 = help4;
824 priv->helper6 = help6;
825
826 return 0;
827}
828
829static void nft_ct_helper_obj_destroy(struct nft_object *obj)
830{
831 struct nft_ct_helper_obj *priv = nft_obj_data(obj);
832
833 if (priv->helper4)
Liping Zhangd91fc592017-05-07 22:01:55 +0800834 nf_conntrack_helper_put(priv->helper4);
Florian Westphal1a64edf52017-03-08 16:48:44 +0100835 if (priv->helper6)
Liping Zhangd91fc592017-05-07 22:01:55 +0800836 nf_conntrack_helper_put(priv->helper6);
Florian Westphal1a64edf52017-03-08 16:48:44 +0100837}
838
839static void nft_ct_helper_obj_eval(struct nft_object *obj,
840 struct nft_regs *regs,
841 const struct nft_pktinfo *pkt)
842{
843 const struct nft_ct_helper_obj *priv = nft_obj_data(obj);
844 struct nf_conn *ct = (struct nf_conn *)skb_nfct(pkt->skb);
845 struct nf_conntrack_helper *to_assign = NULL;
846 struct nf_conn_help *help;
847
848 if (!ct ||
849 nf_ct_is_confirmed(ct) ||
850 nf_ct_is_template(ct) ||
851 priv->l4proto != nf_ct_protonum(ct))
852 return;
853
854 switch (nf_ct_l3num(ct)) {
855 case NFPROTO_IPV4:
856 to_assign = priv->helper4;
857 break;
858 case NFPROTO_IPV6:
859 to_assign = priv->helper6;
860 break;
861 default:
862 WARN_ON_ONCE(1);
863 return;
864 }
865
866 if (!to_assign)
867 return;
868
869 if (test_bit(IPS_HELPER_BIT, &ct->status))
870 return;
871
872 help = nf_ct_helper_ext_add(ct, to_assign, GFP_ATOMIC);
873 if (help) {
874 rcu_assign_pointer(help->helper, to_assign);
875 set_bit(IPS_HELPER_BIT, &ct->status);
876 }
877}
878
879static int nft_ct_helper_obj_dump(struct sk_buff *skb,
880 struct nft_object *obj, bool reset)
881{
882 const struct nft_ct_helper_obj *priv = nft_obj_data(obj);
883 const struct nf_conntrack_helper *helper = priv->helper4;
884 u16 family;
885
886 if (nla_put_string(skb, NFTA_CT_HELPER_NAME, helper->name))
887 return -1;
888
889 if (nla_put_u8(skb, NFTA_CT_HELPER_L4PROTO, priv->l4proto))
890 return -1;
891
892 if (priv->helper4 && priv->helper6)
893 family = NFPROTO_INET;
894 else if (priv->helper6)
895 family = NFPROTO_IPV6;
896 else
897 family = NFPROTO_IPV4;
898
899 if (nla_put_be16(skb, NFTA_CT_HELPER_L3PROTO, htons(family)))
900 return -1;
901
902 return 0;
903}
904
905static const struct nla_policy nft_ct_helper_policy[NFTA_CT_HELPER_MAX + 1] = {
906 [NFTA_CT_HELPER_NAME] = { .type = NLA_STRING,
907 .len = NF_CT_HELPER_NAME_LEN - 1 },
908 [NFTA_CT_HELPER_L3PROTO] = { .type = NLA_U16 },
909 [NFTA_CT_HELPER_L4PROTO] = { .type = NLA_U8 },
910};
911
Pablo M. Bermudo Garaydfc46032017-08-23 22:41:23 +0200912static struct nft_object_type nft_ct_helper_obj_type;
913static const struct nft_object_ops nft_ct_helper_obj_ops = {
914 .type = &nft_ct_helper_obj_type,
Florian Westphal1a64edf52017-03-08 16:48:44 +0100915 .size = sizeof(struct nft_ct_helper_obj),
Florian Westphal1a64edf52017-03-08 16:48:44 +0100916 .eval = nft_ct_helper_obj_eval,
917 .init = nft_ct_helper_obj_init,
918 .destroy = nft_ct_helper_obj_destroy,
919 .dump = nft_ct_helper_obj_dump,
Pablo M. Bermudo Garaydfc46032017-08-23 22:41:23 +0200920};
921
922static struct nft_object_type nft_ct_helper_obj_type __read_mostly = {
923 .type = NFT_OBJECT_CT_HELPER,
924 .ops = &nft_ct_helper_obj_ops,
925 .maxattr = NFTA_CT_HELPER_MAX,
926 .policy = nft_ct_helper_policy,
Florian Westphal1a64edf52017-03-08 16:48:44 +0100927 .owner = THIS_MODULE,
928};
929
Patrick McHardy96518512013-10-14 11:00:02 +0200930static int __init nft_ct_module_init(void)
931{
Pablo Neira Ayuso25443262016-10-20 18:07:14 +0200932 int err;
933
Florian Westphaladff6c62016-04-12 18:14:25 +0200934 BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE > NFT_REG_SIZE);
935
Pablo Neira Ayuso25443262016-10-20 18:07:14 +0200936 err = nft_register_expr(&nft_ct_type);
937 if (err < 0)
938 return err;
939
940 err = nft_register_expr(&nft_notrack_type);
941 if (err < 0)
942 goto err1;
943
Pablo M. Bermudo Garaydfc46032017-08-23 22:41:23 +0200944 err = nft_register_obj(&nft_ct_helper_obj_type);
Florian Westphal1a64edf52017-03-08 16:48:44 +0100945 if (err < 0)
946 goto err2;
947
Pablo Neira Ayuso25443262016-10-20 18:07:14 +0200948 return 0;
Florian Westphal1a64edf52017-03-08 16:48:44 +0100949
950err2:
951 nft_unregister_expr(&nft_notrack_type);
Pablo Neira Ayuso25443262016-10-20 18:07:14 +0200952err1:
953 nft_unregister_expr(&nft_ct_type);
954 return err;
Patrick McHardy96518512013-10-14 11:00:02 +0200955}
956
957static void __exit nft_ct_module_exit(void)
958{
Pablo M. Bermudo Garaydfc46032017-08-23 22:41:23 +0200959 nft_unregister_obj(&nft_ct_helper_obj_type);
Pablo Neira Ayuso25443262016-10-20 18:07:14 +0200960 nft_unregister_expr(&nft_notrack_type);
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200961 nft_unregister_expr(&nft_ct_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200962}
963
964module_init(nft_ct_module_init);
965module_exit(nft_ct_module_exit);
966
967MODULE_LICENSE("GPL");
968MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
969MODULE_ALIAS_NFT_EXPR("ct");
Pablo Neira Ayuso25443262016-10-20 18:07:14 +0200970MODULE_ALIAS_NFT_EXPR("notrack");
Florian Westphal1a64edf52017-03-08 16:48:44 +0100971MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_HELPER);