blob: 0fd69988f00b0759aadb5a20a84b1da4f0fcb8d2 [file] [log] [blame]
Patrick McHardy96518512013-10-14 11:00:02 +02001/*
Patrick McHardy20a69342013-10-11 12:06:22 +02002 * Copyright (c) 2007-2009 Patrick McHardy <kaber@trash.net>
Patrick McHardy96518512013-10-14 11:00:02 +02003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/module.h>
12#include <linux/init.h>
13#include <linux/list.h>
14#include <linux/skbuff.h>
15#include <linux/netlink.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter/nfnetlink.h>
18#include <linux/netfilter/nf_tables.h>
19#include <net/netfilter/nf_tables_core.h>
20#include <net/netfilter/nf_tables.h>
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020021#include <net/net_namespace.h>
Patrick McHardy96518512013-10-14 11:00:02 +020022#include <net/sock.h>
23
Patrick McHardy96518512013-10-14 11:00:02 +020024static LIST_HEAD(nf_tables_expressions);
25
26/**
27 * nft_register_afinfo - register nf_tables address family info
28 *
29 * @afi: address family info to register
30 *
31 * Register the address family for use with nf_tables. Returns zero on
32 * success or a negative errno code otherwise.
33 */
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020034int nft_register_afinfo(struct net *net, struct nft_af_info *afi)
Patrick McHardy96518512013-10-14 11:00:02 +020035{
36 INIT_LIST_HEAD(&afi->tables);
37 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +020038 list_add_tail_rcu(&afi->list, &net->nft.af_info);
Patrick McHardy96518512013-10-14 11:00:02 +020039 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
40 return 0;
41}
42EXPORT_SYMBOL_GPL(nft_register_afinfo);
43
Pablo Neira Ayusodf05ef82015-12-15 19:39:32 +010044static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi);
45
Patrick McHardy96518512013-10-14 11:00:02 +020046/**
47 * nft_unregister_afinfo - unregister nf_tables address family info
48 *
49 * @afi: address family info to unregister
50 *
51 * Unregister the address family for use with nf_tables.
52 */
Pablo Neira Ayusodf05ef82015-12-15 19:39:32 +010053void nft_unregister_afinfo(struct net *net, struct nft_af_info *afi)
Patrick McHardy96518512013-10-14 11:00:02 +020054{
55 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayusodf05ef82015-12-15 19:39:32 +010056 __nft_release_afinfo(net, afi);
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +020057 list_del_rcu(&afi->list);
Patrick McHardy96518512013-10-14 11:00:02 +020058 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
59}
60EXPORT_SYMBOL_GPL(nft_unregister_afinfo);
61
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020062static struct nft_af_info *nft_afinfo_lookup(struct net *net, int family)
Patrick McHardy96518512013-10-14 11:00:02 +020063{
64 struct nft_af_info *afi;
65
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020066 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +020067 if (afi->family == family)
68 return afi;
69 }
70 return NULL;
71}
72
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020073static struct nft_af_info *
74nf_tables_afinfo_lookup(struct net *net, int family, bool autoload)
Patrick McHardy96518512013-10-14 11:00:02 +020075{
76 struct nft_af_info *afi;
77
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020078 afi = nft_afinfo_lookup(net, family);
Patrick McHardy96518512013-10-14 11:00:02 +020079 if (afi != NULL)
80 return afi;
81#ifdef CONFIG_MODULES
82 if (autoload) {
83 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
84 request_module("nft-afinfo-%u", family);
85 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020086 afi = nft_afinfo_lookup(net, family);
Patrick McHardy96518512013-10-14 11:00:02 +020087 if (afi != NULL)
88 return ERR_PTR(-EAGAIN);
89 }
90#endif
91 return ERR_PTR(-EAFNOSUPPORT);
92}
93
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +020094static void nft_ctx_init(struct nft_ctx *ctx,
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +010095 struct net *net,
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +020096 const struct sk_buff *skb,
97 const struct nlmsghdr *nlh,
98 struct nft_af_info *afi,
99 struct nft_table *table,
100 struct nft_chain *chain,
101 const struct nlattr * const *nla)
102{
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +0100103 ctx->net = net;
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +0200104 ctx->afi = afi;
105 ctx->table = table;
106 ctx->chain = chain;
107 ctx->nla = nla;
108 ctx->portid = NETLINK_CB(skb).portid;
109 ctx->report = nlmsg_report(nlh);
110 ctx->seq = nlh->nlmsg_seq;
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +0200111}
112
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +0200113static struct nft_trans *nft_trans_alloc(struct nft_ctx *ctx, int msg_type,
114 u32 size)
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +0200115{
116 struct nft_trans *trans;
117
118 trans = kzalloc(sizeof(struct nft_trans) + size, GFP_KERNEL);
119 if (trans == NULL)
120 return NULL;
121
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +0200122 trans->msg_type = msg_type;
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +0200123 trans->ctx = *ctx;
124
125 return trans;
126}
127
128static void nft_trans_destroy(struct nft_trans *trans)
129{
130 list_del(&trans->list);
131 kfree(trans);
132}
133
Pablo Neira Ayuso5ebe0b02015-12-15 19:40:49 +0100134static int nft_register_basechain(struct nft_base_chain *basechain,
135 unsigned int hook_nops)
Pablo Neira Ayusod8ee8f72015-06-15 02:42:31 +0200136{
Eric W. Biedermanfd2ecda2015-07-10 18:15:44 -0500137 struct net *net = read_pnet(&basechain->pnet);
138
Pablo Neira Ayuso835b8032015-06-15 12:12:01 +0200139 if (basechain->flags & NFT_BASECHAIN_DISABLED)
140 return 0;
141
Eric W. Biedermanfd2ecda2015-07-10 18:15:44 -0500142 return nf_register_net_hooks(net, basechain->ops, hook_nops);
Pablo Neira Ayusod8ee8f72015-06-15 02:42:31 +0200143}
144
Pablo Neira Ayuso5ebe0b02015-12-15 19:40:49 +0100145static void nft_unregister_basechain(struct nft_base_chain *basechain,
146 unsigned int hook_nops)
Pablo Neira Ayusod8ee8f72015-06-15 02:42:31 +0200147{
Eric W. Biedermanfd2ecda2015-07-10 18:15:44 -0500148 struct net *net = read_pnet(&basechain->pnet);
149
Pablo Neira Ayuso835b8032015-06-15 12:12:01 +0200150 if (basechain->flags & NFT_BASECHAIN_DISABLED)
151 return;
152
Eric W. Biedermanfd2ecda2015-07-10 18:15:44 -0500153 nf_unregister_net_hooks(net, basechain->ops, hook_nops);
Pablo Neira Ayusod8ee8f72015-06-15 02:42:31 +0200154}
155
156static int nf_tables_register_hooks(const struct nft_table *table,
157 struct nft_chain *chain,
158 unsigned int hook_nops)
159{
160 if (table->flags & NFT_TABLE_F_DORMANT ||
161 !(chain->flags & NFT_BASE_CHAIN))
162 return 0;
163
164 return nft_register_basechain(nft_base_chain(chain), hook_nops);
165}
166
Arturo Borreroc5598792014-09-02 16:42:23 +0200167static void nf_tables_unregister_hooks(const struct nft_table *table,
Pablo Neira Ayusod8ee8f72015-06-15 02:42:31 +0200168 struct nft_chain *chain,
Arturo Borreroc5598792014-09-02 16:42:23 +0200169 unsigned int hook_nops)
170{
Pablo Neira Ayusod8ee8f72015-06-15 02:42:31 +0200171 if (table->flags & NFT_TABLE_F_DORMANT ||
172 !(chain->flags & NFT_BASE_CHAIN))
173 return;
174
175 nft_unregister_basechain(nft_base_chain(chain), hook_nops);
Arturo Borreroc5598792014-09-02 16:42:23 +0200176}
177
Arturo Borreroee01d542014-09-02 16:42:25 +0200178/* Internal table flags */
179#define NFT_TABLE_INACTIVE (1 << 15)
180
181static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type)
182{
183 struct nft_trans *trans;
184
185 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_table));
186 if (trans == NULL)
187 return -ENOMEM;
188
189 if (msg_type == NFT_MSG_NEWTABLE)
190 ctx->table->flags |= NFT_TABLE_INACTIVE;
191
192 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
193 return 0;
194}
195
196static int nft_deltable(struct nft_ctx *ctx)
197{
198 int err;
199
200 err = nft_trans_table_add(ctx, NFT_MSG_DELTABLE);
201 if (err < 0)
202 return err;
203
204 list_del_rcu(&ctx->table->list);
205 return err;
206}
207
208static int nft_trans_chain_add(struct nft_ctx *ctx, int msg_type)
209{
210 struct nft_trans *trans;
211
212 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_chain));
213 if (trans == NULL)
214 return -ENOMEM;
215
216 if (msg_type == NFT_MSG_NEWCHAIN)
217 ctx->chain->flags |= NFT_CHAIN_INACTIVE;
218
219 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
220 return 0;
221}
222
223static int nft_delchain(struct nft_ctx *ctx)
224{
225 int err;
226
227 err = nft_trans_chain_add(ctx, NFT_MSG_DELCHAIN);
228 if (err < 0)
229 return err;
230
231 ctx->table->use--;
232 list_del_rcu(&ctx->chain->list);
233
234 return err;
235}
236
237static inline bool
238nft_rule_is_active(struct net *net, const struct nft_rule *rule)
239{
Patrick McHardyea4bd992015-03-25 14:08:49 +0000240 return (rule->genmask & nft_genmask_cur(net)) == 0;
Arturo Borreroee01d542014-09-02 16:42:25 +0200241}
242
243static inline int
244nft_rule_is_active_next(struct net *net, const struct nft_rule *rule)
245{
Patrick McHardyea4bd992015-03-25 14:08:49 +0000246 return (rule->genmask & nft_genmask_next(net)) == 0;
Arturo Borreroee01d542014-09-02 16:42:25 +0200247}
248
249static inline void
250nft_rule_activate_next(struct net *net, struct nft_rule *rule)
251{
252 /* Now inactive, will be active in the future */
Patrick McHardyea4bd992015-03-25 14:08:49 +0000253 rule->genmask = nft_genmask_cur(net);
Arturo Borreroee01d542014-09-02 16:42:25 +0200254}
255
256static inline void
257nft_rule_deactivate_next(struct net *net, struct nft_rule *rule)
258{
Patrick McHardyea4bd992015-03-25 14:08:49 +0000259 rule->genmask = nft_genmask_next(net);
Arturo Borreroee01d542014-09-02 16:42:25 +0200260}
261
262static inline void nft_rule_clear(struct net *net, struct nft_rule *rule)
263{
Patrick McHardyea4bd992015-03-25 14:08:49 +0000264 rule->genmask &= ~nft_genmask_next(net);
Arturo Borreroee01d542014-09-02 16:42:25 +0200265}
266
267static int
268nf_tables_delrule_deactivate(struct nft_ctx *ctx, struct nft_rule *rule)
269{
270 /* You cannot delete the same rule twice */
271 if (nft_rule_is_active_next(ctx->net, rule)) {
272 nft_rule_deactivate_next(ctx->net, rule);
273 ctx->chain->use--;
274 return 0;
275 }
276 return -ENOENT;
277}
278
279static struct nft_trans *nft_trans_rule_add(struct nft_ctx *ctx, int msg_type,
280 struct nft_rule *rule)
281{
282 struct nft_trans *trans;
283
284 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_rule));
285 if (trans == NULL)
286 return NULL;
287
288 nft_trans_rule(trans) = rule;
289 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
290
291 return trans;
292}
293
294static int nft_delrule(struct nft_ctx *ctx, struct nft_rule *rule)
295{
296 struct nft_trans *trans;
297 int err;
298
299 trans = nft_trans_rule_add(ctx, NFT_MSG_DELRULE, rule);
300 if (trans == NULL)
301 return -ENOMEM;
302
303 err = nf_tables_delrule_deactivate(ctx, rule);
304 if (err < 0) {
305 nft_trans_destroy(trans);
306 return err;
307 }
308
309 return 0;
310}
311
312static int nft_delrule_by_chain(struct nft_ctx *ctx)
313{
314 struct nft_rule *rule;
315 int err;
316
317 list_for_each_entry(rule, &ctx->chain->rules, list) {
318 err = nft_delrule(ctx, rule);
319 if (err < 0)
320 return err;
321 }
322 return 0;
323}
324
325/* Internal set flag */
326#define NFT_SET_INACTIVE (1 << 15)
327
328static int nft_trans_set_add(struct nft_ctx *ctx, int msg_type,
329 struct nft_set *set)
330{
331 struct nft_trans *trans;
332
333 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_set));
334 if (trans == NULL)
335 return -ENOMEM;
336
337 if (msg_type == NFT_MSG_NEWSET && ctx->nla[NFTA_SET_ID] != NULL) {
338 nft_trans_set_id(trans) =
339 ntohl(nla_get_be32(ctx->nla[NFTA_SET_ID]));
340 set->flags |= NFT_SET_INACTIVE;
341 }
342 nft_trans_set(trans) = set;
343 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
344
345 return 0;
346}
347
348static int nft_delset(struct nft_ctx *ctx, struct nft_set *set)
349{
350 int err;
351
352 err = nft_trans_set_add(ctx, NFT_MSG_DELSET, set);
353 if (err < 0)
354 return err;
355
356 list_del_rcu(&set->list);
357 ctx->table->use--;
358
359 return err;
360}
361
Patrick McHardy96518512013-10-14 11:00:02 +0200362/*
363 * Tables
364 */
365
366static struct nft_table *nft_table_lookup(const struct nft_af_info *afi,
367 const struct nlattr *nla)
368{
369 struct nft_table *table;
370
371 list_for_each_entry(table, &afi->tables, list) {
372 if (!nla_strcmp(nla, table->name))
373 return table;
374 }
375 return NULL;
376}
377
378static struct nft_table *nf_tables_table_lookup(const struct nft_af_info *afi,
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200379 const struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +0200380{
381 struct nft_table *table;
382
383 if (nla == NULL)
384 return ERR_PTR(-EINVAL);
385
386 table = nft_table_lookup(afi, nla);
387 if (table != NULL)
388 return table;
389
Patrick McHardy96518512013-10-14 11:00:02 +0200390 return ERR_PTR(-ENOENT);
391}
392
393static inline u64 nf_tables_alloc_handle(struct nft_table *table)
394{
395 return ++table->hgenerator;
396}
397
Patrick McHardy2a37d752014-01-09 18:42:37 +0000398static const struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200399
Patrick McHardy2a37d752014-01-09 18:42:37 +0000400static const struct nf_chain_type *
Patrick McHardybaae3e62014-01-09 18:42:34 +0000401__nf_tables_chain_type_lookup(int family, const struct nlattr *nla)
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200402{
403 int i;
404
Patrick McHardybaae3e62014-01-09 18:42:34 +0000405 for (i = 0; i < NFT_CHAIN_T_MAX; i++) {
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200406 if (chain_type[family][i] != NULL &&
407 !nla_strcmp(nla, chain_type[family][i]->name))
Patrick McHardybaae3e62014-01-09 18:42:34 +0000408 return chain_type[family][i];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200409 }
Patrick McHardybaae3e62014-01-09 18:42:34 +0000410 return NULL;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200411}
412
Patrick McHardy2a37d752014-01-09 18:42:37 +0000413static const struct nf_chain_type *
Patrick McHardybaae3e62014-01-09 18:42:34 +0000414nf_tables_chain_type_lookup(const struct nft_af_info *afi,
415 const struct nlattr *nla,
416 bool autoload)
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200417{
Patrick McHardy2a37d752014-01-09 18:42:37 +0000418 const struct nf_chain_type *type;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200419
420 type = __nf_tables_chain_type_lookup(afi->family, nla);
Patrick McHardy93b08062014-01-09 18:42:36 +0000421 if (type != NULL)
422 return type;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200423#ifdef CONFIG_MODULES
Patrick McHardy93b08062014-01-09 18:42:36 +0000424 if (autoload) {
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200425 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso2fec6bb2014-03-31 12:26:39 +0200426 request_module("nft-chain-%u-%.*s", afi->family,
427 nla_len(nla), (const char *)nla_data(nla));
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200428 nfnl_lock(NFNL_SUBSYS_NFTABLES);
429 type = __nf_tables_chain_type_lookup(afi->family, nla);
Patrick McHardy93b08062014-01-09 18:42:36 +0000430 if (type != NULL)
431 return ERR_PTR(-EAGAIN);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200432 }
433#endif
Patrick McHardy93b08062014-01-09 18:42:36 +0000434 return ERR_PTR(-ENOENT);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200435}
436
Patrick McHardy96518512013-10-14 11:00:02 +0200437static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
Pablo Neira Ayuso1cae5652015-03-05 15:05:36 +0100438 [NFTA_TABLE_NAME] = { .type = NLA_STRING,
439 .len = NFT_TABLE_MAXNAMELEN - 1 },
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200440 [NFTA_TABLE_FLAGS] = { .type = NLA_U32 },
Patrick McHardy96518512013-10-14 11:00:02 +0200441};
442
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +0200443static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
444 u32 portid, u32 seq, int event, u32 flags,
445 int family, const struct nft_table *table)
Patrick McHardy96518512013-10-14 11:00:02 +0200446{
447 struct nlmsghdr *nlh;
448 struct nfgenmsg *nfmsg;
449
450 event |= NFNL_SUBSYS_NFTABLES << 8;
451 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
452 if (nlh == NULL)
453 goto nla_put_failure;
454
455 nfmsg = nlmsg_data(nlh);
456 nfmsg->nfgen_family = family;
457 nfmsg->version = NFNETLINK_V0;
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +0200458 nfmsg->res_id = htons(net->nft.base_seq & 0xffff);
Patrick McHardy96518512013-10-14 11:00:02 +0200459
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200460 if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
Tomasz Bursztykad8bcc7682013-12-12 15:00:42 +0200461 nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
462 nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)))
Patrick McHardy96518512013-10-14 11:00:02 +0200463 goto nla_put_failure;
464
Johannes Berg053c0952015-01-16 22:09:00 +0100465 nlmsg_end(skb, nlh);
466 return 0;
Patrick McHardy96518512013-10-14 11:00:02 +0200467
468nla_put_failure:
469 nlmsg_trim(skb, nlh);
470 return -1;
471}
472
Pablo Neira Ayuso35151d82014-05-05 17:12:40 +0200473static int nf_tables_table_notify(const struct nft_ctx *ctx, int event)
Patrick McHardy96518512013-10-14 11:00:02 +0200474{
475 struct sk_buff *skb;
Patrick McHardy96518512013-10-14 11:00:02 +0200476 int err;
477
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +0200478 if (!ctx->report &&
479 !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
Patrick McHardy96518512013-10-14 11:00:02 +0200480 return 0;
481
482 err = -ENOBUFS;
483 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
484 if (skb == NULL)
485 goto err;
486
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +0200487 err = nf_tables_fill_table_info(skb, ctx->net, ctx->portid, ctx->seq,
488 event, 0, ctx->afi->family, ctx->table);
Patrick McHardy96518512013-10-14 11:00:02 +0200489 if (err < 0) {
490 kfree_skb(skb);
491 goto err;
492 }
493
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +0200494 err = nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
495 ctx->report, GFP_KERNEL);
Patrick McHardy96518512013-10-14 11:00:02 +0200496err:
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +0200497 if (err < 0) {
498 nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES,
499 err);
500 }
Patrick McHardy96518512013-10-14 11:00:02 +0200501 return err;
502}
503
504static int nf_tables_dump_tables(struct sk_buff *skb,
505 struct netlink_callback *cb)
506{
507 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
508 const struct nft_af_info *afi;
509 const struct nft_table *table;
510 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200511 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200512 int family = nfmsg->nfgen_family;
513
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +0200514 rcu_read_lock();
Pablo Neira Ayuso38e029f2014-07-01 12:23:12 +0200515 cb->seq = net->nft.base_seq;
516
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +0200517 list_for_each_entry_rcu(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +0200518 if (family != NFPROTO_UNSPEC && family != afi->family)
519 continue;
520
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +0200521 list_for_each_entry_rcu(table, &afi->tables, list) {
Patrick McHardy96518512013-10-14 11:00:02 +0200522 if (idx < s_idx)
523 goto cont;
524 if (idx > s_idx)
525 memset(&cb->args[1], 0,
526 sizeof(cb->args) - sizeof(cb->args[0]));
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +0200527 if (nf_tables_fill_table_info(skb, net,
Patrick McHardy96518512013-10-14 11:00:02 +0200528 NETLINK_CB(cb->skb).portid,
529 cb->nlh->nlmsg_seq,
530 NFT_MSG_NEWTABLE,
531 NLM_F_MULTI,
532 afi->family, table) < 0)
533 goto done;
Pablo Neira Ayuso38e029f2014-07-01 12:23:12 +0200534
535 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Patrick McHardy96518512013-10-14 11:00:02 +0200536cont:
537 idx++;
538 }
539 }
540done:
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +0200541 rcu_read_unlock();
Patrick McHardy96518512013-10-14 11:00:02 +0200542 cb->args[0] = idx;
543 return skb->len;
544}
545
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +0100546static int nf_tables_gettable(struct net *net, struct sock *nlsk,
547 struct sk_buff *skb, const struct nlmsghdr *nlh,
Patrick McHardy96518512013-10-14 11:00:02 +0200548 const struct nlattr * const nla[])
549{
550 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
551 const struct nft_af_info *afi;
552 const struct nft_table *table;
553 struct sk_buff *skb2;
554 int family = nfmsg->nfgen_family;
555 int err;
556
557 if (nlh->nlmsg_flags & NLM_F_DUMP) {
558 struct netlink_dump_control c = {
559 .dump = nf_tables_dump_tables,
560 };
561 return netlink_dump_start(nlsk, skb, nlh, &c);
562 }
563
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200564 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200565 if (IS_ERR(afi))
566 return PTR_ERR(afi);
567
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200568 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
Patrick McHardy96518512013-10-14 11:00:02 +0200569 if (IS_ERR(table))
570 return PTR_ERR(table);
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200571 if (table->flags & NFT_TABLE_INACTIVE)
572 return -ENOENT;
Patrick McHardy96518512013-10-14 11:00:02 +0200573
574 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
575 if (!skb2)
576 return -ENOMEM;
577
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +0200578 err = nf_tables_fill_table_info(skb2, net, NETLINK_CB(skb).portid,
Patrick McHardy96518512013-10-14 11:00:02 +0200579 nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0,
580 family, table);
581 if (err < 0)
582 goto err;
583
584 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
585
586err:
587 kfree_skb(skb2);
588 return err;
589}
590
Patrick McHardy115a60b2014-01-03 12:16:15 +0000591static int nf_tables_table_enable(const struct nft_af_info *afi,
592 struct nft_table *table)
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200593{
594 struct nft_chain *chain;
595 int err, i = 0;
596
597 list_for_each_entry(chain, &table->chains, list) {
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100598 if (!(chain->flags & NFT_BASE_CHAIN))
599 continue;
600
Pablo Neira Ayusod8ee8f72015-06-15 02:42:31 +0200601 err = nft_register_basechain(nft_base_chain(chain), afi->nops);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200602 if (err < 0)
603 goto err;
604
605 i++;
606 }
607 return 0;
608err:
609 list_for_each_entry(chain, &table->chains, list) {
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100610 if (!(chain->flags & NFT_BASE_CHAIN))
611 continue;
612
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200613 if (i-- <= 0)
614 break;
615
Pablo Neira Ayusod8ee8f72015-06-15 02:42:31 +0200616 nft_unregister_basechain(nft_base_chain(chain), afi->nops);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200617 }
618 return err;
619}
620
Pablo Neira Ayusof75edf52014-03-30 14:04:52 +0200621static void nf_tables_table_disable(const struct nft_af_info *afi,
Pablo Neira Ayusod8ee8f72015-06-15 02:42:31 +0200622 struct nft_table *table)
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200623{
624 struct nft_chain *chain;
625
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100626 list_for_each_entry(chain, &table->chains, list) {
627 if (chain->flags & NFT_BASE_CHAIN)
Pablo Neira Ayusod8ee8f72015-06-15 02:42:31 +0200628 nft_unregister_basechain(nft_base_chain(chain),
629 afi->nops);
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100630 }
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200631}
632
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200633static int nf_tables_updtable(struct nft_ctx *ctx)
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200634{
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200635 struct nft_trans *trans;
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200636 u32 flags;
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200637 int ret = 0;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200638
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200639 if (!ctx->nla[NFTA_TABLE_FLAGS])
640 return 0;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200641
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200642 flags = ntohl(nla_get_be32(ctx->nla[NFTA_TABLE_FLAGS]));
643 if (flags & ~NFT_TABLE_F_DORMANT)
644 return -EINVAL;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200645
Pablo Neira Ayuso63283dd2014-06-27 18:51:39 +0200646 if (flags == ctx->table->flags)
647 return 0;
648
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200649 trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE,
650 sizeof(struct nft_trans_table));
651 if (trans == NULL)
652 return -ENOMEM;
653
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200654 if ((flags & NFT_TABLE_F_DORMANT) &&
655 !(ctx->table->flags & NFT_TABLE_F_DORMANT)) {
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200656 nft_trans_table_enable(trans) = false;
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200657 } else if (!(flags & NFT_TABLE_F_DORMANT) &&
658 ctx->table->flags & NFT_TABLE_F_DORMANT) {
659 ret = nf_tables_table_enable(ctx->afi, ctx->table);
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200660 if (ret >= 0) {
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200661 ctx->table->flags &= ~NFT_TABLE_F_DORMANT;
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200662 nft_trans_table_enable(trans) = true;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200663 }
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200664 }
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200665 if (ret < 0)
666 goto err;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200667
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200668 nft_trans_table_update(trans) = true;
669 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
670 return 0;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200671err:
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200672 nft_trans_destroy(trans);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200673 return ret;
674}
675
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +0100676static int nf_tables_newtable(struct net *net, struct sock *nlsk,
677 struct sk_buff *skb, const struct nlmsghdr *nlh,
Patrick McHardy96518512013-10-14 11:00:02 +0200678 const struct nlattr * const nla[])
679{
680 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
681 const struct nlattr *name;
682 struct nft_af_info *afi;
683 struct nft_table *table;
684 int family = nfmsg->nfgen_family;
Patrick McHardyc5c1f972014-01-09 18:42:39 +0000685 u32 flags = 0;
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200686 struct nft_ctx ctx;
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200687 int err;
Patrick McHardy96518512013-10-14 11:00:02 +0200688
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200689 afi = nf_tables_afinfo_lookup(net, family, true);
Patrick McHardy96518512013-10-14 11:00:02 +0200690 if (IS_ERR(afi))
691 return PTR_ERR(afi);
692
693 name = nla[NFTA_TABLE_NAME];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200694 table = nf_tables_table_lookup(afi, name);
Patrick McHardy96518512013-10-14 11:00:02 +0200695 if (IS_ERR(table)) {
696 if (PTR_ERR(table) != -ENOENT)
697 return PTR_ERR(table);
698 table = NULL;
699 }
700
701 if (table != NULL) {
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200702 if (table->flags & NFT_TABLE_INACTIVE)
703 return -ENOENT;
Patrick McHardy96518512013-10-14 11:00:02 +0200704 if (nlh->nlmsg_flags & NLM_F_EXCL)
705 return -EEXIST;
706 if (nlh->nlmsg_flags & NLM_F_REPLACE)
707 return -EOPNOTSUPP;
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200708
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +0100709 nft_ctx_init(&ctx, net, skb, nlh, afi, table, NULL, nla);
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200710 return nf_tables_updtable(&ctx);
Patrick McHardy96518512013-10-14 11:00:02 +0200711 }
712
Patrick McHardyc5c1f972014-01-09 18:42:39 +0000713 if (nla[NFTA_TABLE_FLAGS]) {
714 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
715 if (flags & ~NFT_TABLE_F_DORMANT)
716 return -EINVAL;
717 }
718
Pablo Neira Ayusoebddf1a2015-05-26 18:41:20 +0200719 err = -EAFNOSUPPORT;
Patrick McHardy7047f9d2014-01-09 18:42:40 +0000720 if (!try_module_get(afi->owner))
Pablo Neira Ayusoebddf1a2015-05-26 18:41:20 +0200721 goto err1;
Patrick McHardy7047f9d2014-01-09 18:42:40 +0000722
Pablo Neira Ayusoffdb2102015-03-17 19:53:23 +0100723 err = -ENOMEM;
Pablo Neira Ayuso1cae5652015-03-05 15:05:36 +0100724 table = kzalloc(sizeof(*table), GFP_KERNEL);
Pablo Neira Ayusoffdb2102015-03-17 19:53:23 +0100725 if (table == NULL)
Pablo Neira Ayusoebddf1a2015-05-26 18:41:20 +0200726 goto err2;
Patrick McHardy96518512013-10-14 11:00:02 +0200727
Pablo Neira Ayuso1cae5652015-03-05 15:05:36 +0100728 nla_strlcpy(table->name, name, NFT_TABLE_MAXNAMELEN);
Patrick McHardy96518512013-10-14 11:00:02 +0200729 INIT_LIST_HEAD(&table->chains);
Patrick McHardy20a69342013-10-11 12:06:22 +0200730 INIT_LIST_HEAD(&table->sets);
Patrick McHardyc5c1f972014-01-09 18:42:39 +0000731 table->flags = flags;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200732
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +0100733 nft_ctx_init(&ctx, net, skb, nlh, afi, table, NULL, nla);
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200734 err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE);
Pablo Neira Ayusoffdb2102015-03-17 19:53:23 +0100735 if (err < 0)
Pablo Neira Ayusoebddf1a2015-05-26 18:41:20 +0200736 goto err3;
Pablo Neira Ayusoffdb2102015-03-17 19:53:23 +0100737
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +0200738 list_add_tail_rcu(&table->list, &afi->tables);
Patrick McHardy96518512013-10-14 11:00:02 +0200739 return 0;
Pablo Neira Ayusoebddf1a2015-05-26 18:41:20 +0200740err3:
Pablo Neira Ayusoffdb2102015-03-17 19:53:23 +0100741 kfree(table);
Pablo Neira Ayusoebddf1a2015-05-26 18:41:20 +0200742err2:
Pablo Neira Ayusoffdb2102015-03-17 19:53:23 +0100743 module_put(afi->owner);
Pablo Neira Ayusoebddf1a2015-05-26 18:41:20 +0200744err1:
Pablo Neira Ayusoffdb2102015-03-17 19:53:23 +0100745 return err;
Patrick McHardy96518512013-10-14 11:00:02 +0200746}
747
Arturo Borrerob9ac12e2014-09-02 16:42:26 +0200748static int nft_flush_table(struct nft_ctx *ctx)
749{
750 int err;
751 struct nft_chain *chain, *nc;
752 struct nft_set *set, *ns;
753
Pablo Neira Ayusoa2f18db2015-01-04 15:14:22 +0100754 list_for_each_entry(chain, &ctx->table->chains, list) {
Arturo Borrerob9ac12e2014-09-02 16:42:26 +0200755 ctx->chain = chain;
756
757 err = nft_delrule_by_chain(ctx);
758 if (err < 0)
759 goto out;
Arturo Borrerob9ac12e2014-09-02 16:42:26 +0200760 }
761
762 list_for_each_entry_safe(set, ns, &ctx->table->sets, list) {
763 if (set->flags & NFT_SET_ANONYMOUS &&
764 !list_empty(&set->bindings))
765 continue;
766
767 err = nft_delset(ctx, set);
768 if (err < 0)
769 goto out;
770 }
771
Pablo Neira Ayusoa2f18db2015-01-04 15:14:22 +0100772 list_for_each_entry_safe(chain, nc, &ctx->table->chains, list) {
773 ctx->chain = chain;
774
775 err = nft_delchain(ctx);
776 if (err < 0)
777 goto out;
778 }
779
Arturo Borrerob9ac12e2014-09-02 16:42:26 +0200780 err = nft_deltable(ctx);
781out:
782 return err;
783}
784
785static int nft_flush(struct nft_ctx *ctx, int family)
786{
787 struct nft_af_info *afi;
788 struct nft_table *table, *nt;
789 const struct nlattr * const *nla = ctx->nla;
790 int err = 0;
791
792 list_for_each_entry(afi, &ctx->net->nft.af_info, list) {
793 if (family != AF_UNSPEC && afi->family != family)
794 continue;
795
796 ctx->afi = afi;
797 list_for_each_entry_safe(table, nt, &afi->tables, list) {
798 if (nla[NFTA_TABLE_NAME] &&
799 nla_strcmp(nla[NFTA_TABLE_NAME], table->name) != 0)
800 continue;
801
802 ctx->table = table;
803
804 err = nft_flush_table(ctx);
805 if (err < 0)
806 goto out;
807 }
808 }
809out:
810 return err;
811}
812
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +0100813static int nf_tables_deltable(struct net *net, struct sock *nlsk,
814 struct sk_buff *skb, const struct nlmsghdr *nlh,
Patrick McHardy96518512013-10-14 11:00:02 +0200815 const struct nlattr * const nla[])
816{
817 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
818 struct nft_af_info *afi;
819 struct nft_table *table;
Arturo Borreroee01d542014-09-02 16:42:25 +0200820 int family = nfmsg->nfgen_family;
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200821 struct nft_ctx ctx;
Patrick McHardy96518512013-10-14 11:00:02 +0200822
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +0100823 nft_ctx_init(&ctx, net, skb, nlh, NULL, NULL, NULL, nla);
Arturo Borrerob9ac12e2014-09-02 16:42:26 +0200824 if (family == AF_UNSPEC || nla[NFTA_TABLE_NAME] == NULL)
825 return nft_flush(&ctx, family);
826
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200827 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200828 if (IS_ERR(afi))
829 return PTR_ERR(afi);
830
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200831 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
Patrick McHardy96518512013-10-14 11:00:02 +0200832 if (IS_ERR(table))
833 return PTR_ERR(table);
Patrick McHardy96518512013-10-14 11:00:02 +0200834
Arturo Borrerob9ac12e2014-09-02 16:42:26 +0200835 ctx.afi = afi;
836 ctx.table = table;
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200837
Arturo Borrerob9ac12e2014-09-02 16:42:26 +0200838 return nft_flush_table(&ctx);
Patrick McHardy96518512013-10-14 11:00:02 +0200839}
840
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200841static void nf_tables_table_destroy(struct nft_ctx *ctx)
842{
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +0200843 BUG_ON(ctx->table->use > 0);
844
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +0200845 kfree(ctx->table);
846 module_put(ctx->afi->owner);
847}
848
Patrick McHardy2a37d752014-01-09 18:42:37 +0000849int nft_register_chain_type(const struct nf_chain_type *ctype)
Patrick McHardy96518512013-10-14 11:00:02 +0200850{
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200851 int err = 0;
Patrick McHardy96518512013-10-14 11:00:02 +0200852
853 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200854 if (chain_type[ctype->family][ctype->type] != NULL) {
855 err = -EBUSY;
856 goto out;
Patrick McHardy96518512013-10-14 11:00:02 +0200857 }
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200858 chain_type[ctype->family][ctype->type] = ctype;
859out:
Patrick McHardy96518512013-10-14 11:00:02 +0200860 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
861 return err;
862}
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200863EXPORT_SYMBOL_GPL(nft_register_chain_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200864
Patrick McHardy2a37d752014-01-09 18:42:37 +0000865void nft_unregister_chain_type(const struct nf_chain_type *ctype)
Patrick McHardy96518512013-10-14 11:00:02 +0200866{
Patrick McHardy96518512013-10-14 11:00:02 +0200867 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200868 chain_type[ctype->family][ctype->type] = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +0200869 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
870}
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200871EXPORT_SYMBOL_GPL(nft_unregister_chain_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200872
873/*
874 * Chains
875 */
876
877static struct nft_chain *
878nf_tables_chain_lookup_byhandle(const struct nft_table *table, u64 handle)
879{
880 struct nft_chain *chain;
881
882 list_for_each_entry(chain, &table->chains, list) {
883 if (chain->handle == handle)
884 return chain;
885 }
886
887 return ERR_PTR(-ENOENT);
888}
889
890static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table,
891 const struct nlattr *nla)
892{
893 struct nft_chain *chain;
894
895 if (nla == NULL)
896 return ERR_PTR(-EINVAL);
897
898 list_for_each_entry(chain, &table->chains, list) {
899 if (!nla_strcmp(nla, chain->name))
900 return chain;
901 }
902
903 return ERR_PTR(-ENOENT);
904}
905
906static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
907 [NFTA_CHAIN_TABLE] = { .type = NLA_STRING },
908 [NFTA_CHAIN_HANDLE] = { .type = NLA_U64 },
909 [NFTA_CHAIN_NAME] = { .type = NLA_STRING,
910 .len = NFT_CHAIN_MAXNAMELEN - 1 },
911 [NFTA_CHAIN_HOOK] = { .type = NLA_NESTED },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200912 [NFTA_CHAIN_POLICY] = { .type = NLA_U32 },
Pablo Neira4c1f7812014-03-31 17:43:47 +0200913 [NFTA_CHAIN_TYPE] = { .type = NLA_STRING },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200914 [NFTA_CHAIN_COUNTERS] = { .type = NLA_NESTED },
Patrick McHardy96518512013-10-14 11:00:02 +0200915};
916
917static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = {
918 [NFTA_HOOK_HOOKNUM] = { .type = NLA_U32 },
919 [NFTA_HOOK_PRIORITY] = { .type = NLA_U32 },
Pablo Neira Ayuso2cbce132015-06-12 13:55:41 +0200920 [NFTA_HOOK_DEV] = { .type = NLA_STRING,
921 .len = IFNAMSIZ - 1 },
Patrick McHardy96518512013-10-14 11:00:02 +0200922};
923
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200924static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats)
925{
926 struct nft_stats *cpu_stats, total;
927 struct nlattr *nest;
Eric Dumazetce355e22014-07-09 15:14:06 +0200928 unsigned int seq;
929 u64 pkts, bytes;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200930 int cpu;
931
932 memset(&total, 0, sizeof(total));
933 for_each_possible_cpu(cpu) {
934 cpu_stats = per_cpu_ptr(stats, cpu);
Eric Dumazetce355e22014-07-09 15:14:06 +0200935 do {
936 seq = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
937 pkts = cpu_stats->pkts;
938 bytes = cpu_stats->bytes;
939 } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, seq));
940 total.pkts += pkts;
941 total.bytes += bytes;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200942 }
943 nest = nla_nest_start(skb, NFTA_CHAIN_COUNTERS);
944 if (nest == NULL)
945 goto nla_put_failure;
946
Nicolas Dichtelb46f6de2016-04-22 17:31:18 +0200947 if (nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(total.pkts),
948 NFTA_COUNTER_PAD) ||
949 nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes),
950 NFTA_COUNTER_PAD))
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200951 goto nla_put_failure;
952
953 nla_nest_end(skb, nest);
954 return 0;
955
956nla_put_failure:
957 return -ENOSPC;
958}
959
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +0200960static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
961 u32 portid, u32 seq, int event, u32 flags,
962 int family, const struct nft_table *table,
Patrick McHardy96518512013-10-14 11:00:02 +0200963 const struct nft_chain *chain)
964{
965 struct nlmsghdr *nlh;
966 struct nfgenmsg *nfmsg;
967
968 event |= NFNL_SUBSYS_NFTABLES << 8;
969 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
970 if (nlh == NULL)
971 goto nla_put_failure;
972
973 nfmsg = nlmsg_data(nlh);
974 nfmsg->nfgen_family = family;
975 nfmsg->version = NFNETLINK_V0;
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +0200976 nfmsg->res_id = htons(net->nft.base_seq & 0xffff);
Patrick McHardy96518512013-10-14 11:00:02 +0200977
978 if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name))
979 goto nla_put_failure;
Nicolas Dichtelb46f6de2016-04-22 17:31:18 +0200980 if (nla_put_be64(skb, NFTA_CHAIN_HANDLE, cpu_to_be64(chain->handle),
981 NFTA_CHAIN_PAD))
Patrick McHardy96518512013-10-14 11:00:02 +0200982 goto nla_put_failure;
983 if (nla_put_string(skb, NFTA_CHAIN_NAME, chain->name))
984 goto nla_put_failure;
985
986 if (chain->flags & NFT_BASE_CHAIN) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200987 const struct nft_base_chain *basechain = nft_base_chain(chain);
Patrick McHardy115a60b2014-01-03 12:16:15 +0000988 const struct nf_hook_ops *ops = &basechain->ops[0];
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200989 struct nlattr *nest;
990
991 nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
Patrick McHardy96518512013-10-14 11:00:02 +0200992 if (nest == NULL)
993 goto nla_put_failure;
994 if (nla_put_be32(skb, NFTA_HOOK_HOOKNUM, htonl(ops->hooknum)))
995 goto nla_put_failure;
996 if (nla_put_be32(skb, NFTA_HOOK_PRIORITY, htonl(ops->priority)))
997 goto nla_put_failure;
Pablo Neira Ayuso2cbce132015-06-12 13:55:41 +0200998 if (basechain->dev_name[0] &&
999 nla_put_string(skb, NFTA_HOOK_DEV, basechain->dev_name))
1000 goto nla_put_failure;
Patrick McHardy96518512013-10-14 11:00:02 +02001001 nla_nest_end(skb, nest);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001002
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001003 if (nla_put_be32(skb, NFTA_CHAIN_POLICY,
1004 htonl(basechain->policy)))
1005 goto nla_put_failure;
1006
Patrick McHardybaae3e62014-01-09 18:42:34 +00001007 if (nla_put_string(skb, NFTA_CHAIN_TYPE, basechain->type->name))
1008 goto nla_put_failure;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001009
1010 if (nft_dump_stats(skb, nft_base_chain(chain)->stats))
1011 goto nla_put_failure;
Patrick McHardy96518512013-10-14 11:00:02 +02001012 }
1013
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001014 if (nla_put_be32(skb, NFTA_CHAIN_USE, htonl(chain->use)))
1015 goto nla_put_failure;
1016
Johannes Berg053c0952015-01-16 22:09:00 +01001017 nlmsg_end(skb, nlh);
1018 return 0;
Patrick McHardy96518512013-10-14 11:00:02 +02001019
1020nla_put_failure:
1021 nlmsg_trim(skb, nlh);
1022 return -1;
1023}
1024
Pablo Neira Ayuso35151d82014-05-05 17:12:40 +02001025static int nf_tables_chain_notify(const struct nft_ctx *ctx, int event)
Patrick McHardy96518512013-10-14 11:00:02 +02001026{
1027 struct sk_buff *skb;
Patrick McHardy96518512013-10-14 11:00:02 +02001028 int err;
1029
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +02001030 if (!ctx->report &&
1031 !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
Patrick McHardy96518512013-10-14 11:00:02 +02001032 return 0;
1033
1034 err = -ENOBUFS;
1035 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1036 if (skb == NULL)
1037 goto err;
1038
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02001039 err = nf_tables_fill_chain_info(skb, ctx->net, ctx->portid, ctx->seq,
1040 event, 0, ctx->afi->family, ctx->table,
Pablo Neira Ayuso35151d82014-05-05 17:12:40 +02001041 ctx->chain);
Patrick McHardy96518512013-10-14 11:00:02 +02001042 if (err < 0) {
1043 kfree_skb(skb);
1044 goto err;
1045 }
1046
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +02001047 err = nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
1048 ctx->report, GFP_KERNEL);
Patrick McHardy96518512013-10-14 11:00:02 +02001049err:
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +02001050 if (err < 0) {
1051 nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES,
1052 err);
1053 }
Patrick McHardy96518512013-10-14 11:00:02 +02001054 return err;
1055}
1056
1057static int nf_tables_dump_chains(struct sk_buff *skb,
1058 struct netlink_callback *cb)
1059{
1060 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
1061 const struct nft_af_info *afi;
1062 const struct nft_table *table;
1063 const struct nft_chain *chain;
1064 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001065 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001066 int family = nfmsg->nfgen_family;
1067
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02001068 rcu_read_lock();
Pablo Neira Ayuso38e029f2014-07-01 12:23:12 +02001069 cb->seq = net->nft.base_seq;
1070
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02001071 list_for_each_entry_rcu(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +02001072 if (family != NFPROTO_UNSPEC && family != afi->family)
1073 continue;
1074
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02001075 list_for_each_entry_rcu(table, &afi->tables, list) {
1076 list_for_each_entry_rcu(chain, &table->chains, list) {
Patrick McHardy96518512013-10-14 11:00:02 +02001077 if (idx < s_idx)
1078 goto cont;
1079 if (idx > s_idx)
1080 memset(&cb->args[1], 0,
1081 sizeof(cb->args) - sizeof(cb->args[0]));
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02001082 if (nf_tables_fill_chain_info(skb, net,
1083 NETLINK_CB(cb->skb).portid,
Patrick McHardy96518512013-10-14 11:00:02 +02001084 cb->nlh->nlmsg_seq,
1085 NFT_MSG_NEWCHAIN,
1086 NLM_F_MULTI,
1087 afi->family, table, chain) < 0)
1088 goto done;
Pablo Neira Ayuso38e029f2014-07-01 12:23:12 +02001089
1090 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Patrick McHardy96518512013-10-14 11:00:02 +02001091cont:
1092 idx++;
1093 }
1094 }
1095 }
1096done:
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02001097 rcu_read_unlock();
Patrick McHardy96518512013-10-14 11:00:02 +02001098 cb->args[0] = idx;
1099 return skb->len;
1100}
1101
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01001102static int nf_tables_getchain(struct net *net, struct sock *nlsk,
1103 struct sk_buff *skb, const struct nlmsghdr *nlh,
Patrick McHardy96518512013-10-14 11:00:02 +02001104 const struct nlattr * const nla[])
1105{
1106 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1107 const struct nft_af_info *afi;
1108 const struct nft_table *table;
1109 const struct nft_chain *chain;
1110 struct sk_buff *skb2;
1111 int family = nfmsg->nfgen_family;
1112 int err;
1113
1114 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1115 struct netlink_dump_control c = {
1116 .dump = nf_tables_dump_chains,
1117 };
1118 return netlink_dump_start(nlsk, skb, nlh, &c);
1119 }
1120
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001121 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001122 if (IS_ERR(afi))
1123 return PTR_ERR(afi);
1124
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001125 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001126 if (IS_ERR(table))
1127 return PTR_ERR(table);
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +02001128 if (table->flags & NFT_TABLE_INACTIVE)
1129 return -ENOENT;
Patrick McHardy96518512013-10-14 11:00:02 +02001130
1131 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
1132 if (IS_ERR(chain))
1133 return PTR_ERR(chain);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001134 if (chain->flags & NFT_CHAIN_INACTIVE)
1135 return -ENOENT;
Patrick McHardy96518512013-10-14 11:00:02 +02001136
1137 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1138 if (!skb2)
1139 return -ENOMEM;
1140
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02001141 err = nf_tables_fill_chain_info(skb2, net, NETLINK_CB(skb).portid,
Patrick McHardy96518512013-10-14 11:00:02 +02001142 nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0,
1143 family, table, chain);
1144 if (err < 0)
1145 goto err;
1146
1147 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
1148
1149err:
1150 kfree_skb(skb2);
1151 return err;
1152}
1153
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001154static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = {
1155 [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 },
1156 [NFTA_COUNTER_BYTES] = { .type = NLA_U64 },
1157};
1158
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001159static struct nft_stats __percpu *nft_stats_alloc(const struct nlattr *attr)
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001160{
1161 struct nlattr *tb[NFTA_COUNTER_MAX+1];
1162 struct nft_stats __percpu *newstats;
1163 struct nft_stats *stats;
1164 int err;
1165
1166 err = nla_parse_nested(tb, NFTA_COUNTER_MAX, attr, nft_counter_policy);
1167 if (err < 0)
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001168 return ERR_PTR(err);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001169
1170 if (!tb[NFTA_COUNTER_BYTES] || !tb[NFTA_COUNTER_PACKETS])
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001171 return ERR_PTR(-EINVAL);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001172
Eric Dumazetce355e22014-07-09 15:14:06 +02001173 newstats = netdev_alloc_pcpu_stats(struct nft_stats);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001174 if (newstats == NULL)
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001175 return ERR_PTR(-ENOMEM);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001176
1177 /* Restore old counters on this cpu, no problem. Per-cpu statistics
1178 * are not exposed to userspace.
1179 */
Pablo Neira Ayusoe8781f72015-01-21 18:04:18 +01001180 preempt_disable();
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001181 stats = this_cpu_ptr(newstats);
1182 stats->bytes = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES]));
1183 stats->pkts = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS]));
Pablo Neira Ayusoe8781f72015-01-21 18:04:18 +01001184 preempt_enable();
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001185
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001186 return newstats;
1187}
1188
1189static void nft_chain_stats_replace(struct nft_base_chain *chain,
1190 struct nft_stats __percpu *newstats)
1191{
Pablo Neira Ayusob88825d2014-08-05 17:25:59 +02001192 if (newstats == NULL)
1193 return;
1194
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001195 if (chain->stats) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001196 struct nft_stats __percpu *oldstats =
Patrick McHardy67a8fc22014-02-18 18:06:49 +00001197 nft_dereference(chain->stats);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001198
1199 rcu_assign_pointer(chain->stats, newstats);
1200 synchronize_rcu();
1201 free_percpu(oldstats);
1202 } else
1203 rcu_assign_pointer(chain->stats, newstats);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001204}
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001205
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001206static void nf_tables_chain_destroy(struct nft_chain *chain)
1207{
1208 BUG_ON(chain->use > 0);
1209
1210 if (chain->flags & NFT_BASE_CHAIN) {
Pablo Neira Ayuso2cbce132015-06-12 13:55:41 +02001211 struct nft_base_chain *basechain = nft_base_chain(chain);
1212
1213 module_put(basechain->type->owner);
1214 free_percpu(basechain->stats);
1215 if (basechain->ops[0].dev != NULL)
1216 dev_put(basechain->ops[0].dev);
1217 kfree(basechain);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001218 } else {
1219 kfree(chain);
1220 }
1221}
1222
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01001223static int nf_tables_newchain(struct net *net, struct sock *nlsk,
1224 struct sk_buff *skb, const struct nlmsghdr *nlh,
Patrick McHardy96518512013-10-14 11:00:02 +02001225 const struct nlattr * const nla[])
1226{
1227 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1228 const struct nlattr * uninitialized_var(name);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02001229 struct nft_af_info *afi;
Patrick McHardy96518512013-10-14 11:00:02 +02001230 struct nft_table *table;
1231 struct nft_chain *chain;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001232 struct nft_base_chain *basechain = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +02001233 struct nlattr *ha[NFTA_HOOK_MAX + 1];
1234 int family = nfmsg->nfgen_family;
Pablo Neira Ayuso2cbce132015-06-12 13:55:41 +02001235 struct net_device *dev = NULL;
Patrick McHardy57de2a02014-01-09 18:42:31 +00001236 u8 policy = NF_ACCEPT;
Patrick McHardy96518512013-10-14 11:00:02 +02001237 u64 handle = 0;
Patrick McHardy115a60b2014-01-03 12:16:15 +00001238 unsigned int i;
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001239 struct nft_stats __percpu *stats;
Patrick McHardy96518512013-10-14 11:00:02 +02001240 int err;
1241 bool create;
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001242 struct nft_ctx ctx;
Patrick McHardy96518512013-10-14 11:00:02 +02001243
1244 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
1245
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001246 afi = nf_tables_afinfo_lookup(net, family, true);
Patrick McHardy96518512013-10-14 11:00:02 +02001247 if (IS_ERR(afi))
1248 return PTR_ERR(afi);
1249
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001250 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001251 if (IS_ERR(table))
1252 return PTR_ERR(table);
1253
Patrick McHardy96518512013-10-14 11:00:02 +02001254 chain = NULL;
1255 name = nla[NFTA_CHAIN_NAME];
1256
1257 if (nla[NFTA_CHAIN_HANDLE]) {
1258 handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
1259 chain = nf_tables_chain_lookup_byhandle(table, handle);
1260 if (IS_ERR(chain))
1261 return PTR_ERR(chain);
1262 } else {
1263 chain = nf_tables_chain_lookup(table, name);
1264 if (IS_ERR(chain)) {
1265 if (PTR_ERR(chain) != -ENOENT)
1266 return PTR_ERR(chain);
1267 chain = NULL;
1268 }
1269 }
1270
Patrick McHardy57de2a02014-01-09 18:42:31 +00001271 if (nla[NFTA_CHAIN_POLICY]) {
1272 if ((chain != NULL &&
Pablo Neira Ayusod6b6cb12015-03-17 13:21:42 +01001273 !(chain->flags & NFT_BASE_CHAIN)))
1274 return -EOPNOTSUPP;
1275
1276 if (chain == NULL &&
Patrick McHardy57de2a02014-01-09 18:42:31 +00001277 nla[NFTA_CHAIN_HOOK] == NULL)
1278 return -EOPNOTSUPP;
1279
Pablo Neira Ayuso8f46df12014-01-10 15:11:25 +01001280 policy = ntohl(nla_get_be32(nla[NFTA_CHAIN_POLICY]));
Patrick McHardy57de2a02014-01-09 18:42:31 +00001281 switch (policy) {
1282 case NF_DROP:
1283 case NF_ACCEPT:
1284 break;
1285 default:
1286 return -EINVAL;
1287 }
1288 }
1289
Patrick McHardy96518512013-10-14 11:00:02 +02001290 if (chain != NULL) {
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001291 struct nft_stats *stats = NULL;
1292 struct nft_trans *trans;
1293
1294 if (chain->flags & NFT_CHAIN_INACTIVE)
1295 return -ENOENT;
Patrick McHardy96518512013-10-14 11:00:02 +02001296 if (nlh->nlmsg_flags & NLM_F_EXCL)
1297 return -EEXIST;
1298 if (nlh->nlmsg_flags & NLM_F_REPLACE)
1299 return -EOPNOTSUPP;
1300
1301 if (nla[NFTA_CHAIN_HANDLE] && name &&
1302 !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME])))
1303 return -EEXIST;
1304
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001305 if (nla[NFTA_CHAIN_COUNTERS]) {
1306 if (!(chain->flags & NFT_BASE_CHAIN))
1307 return -EOPNOTSUPP;
1308
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001309 stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]);
1310 if (IS_ERR(stats))
1311 return PTR_ERR(stats);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001312 }
1313
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01001314 nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001315 trans = nft_trans_alloc(&ctx, NFT_MSG_NEWCHAIN,
1316 sizeof(struct nft_trans_chain));
Pablo Neira Ayusof5553c12015-01-29 19:08:09 +01001317 if (trans == NULL) {
1318 free_percpu(stats);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001319 return -ENOMEM;
Pablo Neira Ayusof5553c12015-01-29 19:08:09 +01001320 }
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001321
1322 nft_trans_chain_stats(trans) = stats;
1323 nft_trans_chain_update(trans) = true;
1324
Patrick McHardy4401a862014-01-09 18:42:32 +00001325 if (nla[NFTA_CHAIN_POLICY])
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001326 nft_trans_chain_policy(trans) = policy;
1327 else
1328 nft_trans_chain_policy(trans) = -1;
Patrick McHardy4401a862014-01-09 18:42:32 +00001329
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001330 if (nla[NFTA_CHAIN_HANDLE] && name) {
1331 nla_strlcpy(nft_trans_chain_name(trans), name,
1332 NFT_CHAIN_MAXNAMELEN);
1333 }
1334 list_add_tail(&trans->list, &net->nft.commit_list);
1335 return 0;
Patrick McHardy96518512013-10-14 11:00:02 +02001336 }
1337
Patrick McHardy75820672014-01-09 18:42:33 +00001338 if (table->use == UINT_MAX)
1339 return -EOVERFLOW;
1340
Patrick McHardy96518512013-10-14 11:00:02 +02001341 if (nla[NFTA_CHAIN_HOOK]) {
Patrick McHardy2a37d752014-01-09 18:42:37 +00001342 const struct nf_chain_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001343 struct nf_hook_ops *ops;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001344 nf_hookfn *hookfn;
Patrick McHardy115a60b2014-01-03 12:16:15 +00001345 u32 hooknum, priority;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001346
Patrick McHardybaae3e62014-01-09 18:42:34 +00001347 type = chain_type[family][NFT_CHAIN_T_DEFAULT];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001348 if (nla[NFTA_CHAIN_TYPE]) {
1349 type = nf_tables_chain_type_lookup(afi,
1350 nla[NFTA_CHAIN_TYPE],
1351 create);
Patrick McHardy93b08062014-01-09 18:42:36 +00001352 if (IS_ERR(type))
1353 return PTR_ERR(type);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001354 }
Patrick McHardy96518512013-10-14 11:00:02 +02001355
1356 err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK],
1357 nft_hook_policy);
1358 if (err < 0)
1359 return err;
1360 if (ha[NFTA_HOOK_HOOKNUM] == NULL ||
1361 ha[NFTA_HOOK_PRIORITY] == NULL)
1362 return -EINVAL;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001363
1364 hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
1365 if (hooknum >= afi->nhooks)
Patrick McHardy96518512013-10-14 11:00:02 +02001366 return -EINVAL;
Patrick McHardy115a60b2014-01-03 12:16:15 +00001367 priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
Patrick McHardy96518512013-10-14 11:00:02 +02001368
Patrick McHardybaae3e62014-01-09 18:42:34 +00001369 if (!(type->hook_mask & (1 << hooknum)))
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001370 return -EOPNOTSUPP;
Patrick McHardyfa2c1de2014-01-09 18:42:38 +00001371 if (!try_module_get(type->owner))
Patrick McHardybaae3e62014-01-09 18:42:34 +00001372 return -ENOENT;
Patrick McHardyfa2c1de2014-01-09 18:42:38 +00001373 hookfn = type->hooks[hooknum];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001374
Pablo Neira Ayuso2cbce132015-06-12 13:55:41 +02001375 if (afi->flags & NFT_AF_NEEDS_DEV) {
1376 char ifname[IFNAMSIZ];
1377
1378 if (!ha[NFTA_HOOK_DEV]) {
1379 module_put(type->owner);
1380 return -EOPNOTSUPP;
1381 }
1382
1383 nla_strlcpy(ifname, ha[NFTA_HOOK_DEV], IFNAMSIZ);
1384 dev = dev_get_by_name(net, ifname);
1385 if (!dev) {
1386 module_put(type->owner);
1387 return -ENOENT;
1388 }
1389 } else if (ha[NFTA_HOOK_DEV]) {
1390 module_put(type->owner);
1391 return -EOPNOTSUPP;
1392 }
1393
Patrick McHardy96518512013-10-14 11:00:02 +02001394 basechain = kzalloc(sizeof(*basechain), GFP_KERNEL);
Pablo Neira Ayusof5553c12015-01-29 19:08:09 +01001395 if (basechain == NULL) {
1396 module_put(type->owner);
Pablo Neira Ayuso2cbce132015-06-12 13:55:41 +02001397 if (dev != NULL)
1398 dev_put(dev);
Patrick McHardy96518512013-10-14 11:00:02 +02001399 return -ENOMEM;
Pablo Neira Ayusof5553c12015-01-29 19:08:09 +01001400 }
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001401
Pablo Neira Ayuso2cbce132015-06-12 13:55:41 +02001402 if (dev != NULL)
1403 strncpy(basechain->dev_name, dev->name, IFNAMSIZ);
1404
Patrick McHardy4401a862014-01-09 18:42:32 +00001405 if (nla[NFTA_CHAIN_COUNTERS]) {
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001406 stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]);
1407 if (IS_ERR(stats)) {
Patrick McHardyfa2c1de2014-01-09 18:42:38 +00001408 module_put(type->owner);
Patrick McHardy4401a862014-01-09 18:42:32 +00001409 kfree(basechain);
Pablo Neira Ayuso2cbce132015-06-12 13:55:41 +02001410 if (dev != NULL)
1411 dev_put(dev);
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001412 return PTR_ERR(stats);
Patrick McHardy4401a862014-01-09 18:42:32 +00001413 }
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001414 basechain->stats = stats;
Patrick McHardy4401a862014-01-09 18:42:32 +00001415 } else {
Eric Dumazetce355e22014-07-09 15:14:06 +02001416 stats = netdev_alloc_pcpu_stats(struct nft_stats);
Sabrina Dubrocac123bb72014-10-21 11:08:21 +02001417 if (stats == NULL) {
Patrick McHardyfa2c1de2014-01-09 18:42:38 +00001418 module_put(type->owner);
Patrick McHardy4401a862014-01-09 18:42:32 +00001419 kfree(basechain);
Pablo Neira Ayuso2cbce132015-06-12 13:55:41 +02001420 if (dev != NULL)
1421 dev_put(dev);
Sabrina Dubrocac123bb72014-10-21 11:08:21 +02001422 return -ENOMEM;
Patrick McHardy4401a862014-01-09 18:42:32 +00001423 }
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001424 rcu_assign_pointer(basechain->stats, stats);
Patrick McHardy4401a862014-01-09 18:42:32 +00001425 }
1426
Patrick McHardy5ebb3352015-03-21 15:19:15 +00001427 write_pnet(&basechain->pnet, net);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001428 basechain->type = type;
Patrick McHardy96518512013-10-14 11:00:02 +02001429 chain = &basechain->chain;
1430
Patrick McHardy115a60b2014-01-03 12:16:15 +00001431 for (i = 0; i < afi->nops; i++) {
1432 ops = &basechain->ops[i];
1433 ops->pf = family;
Patrick McHardy115a60b2014-01-03 12:16:15 +00001434 ops->hooknum = hooknum;
1435 ops->priority = priority;
1436 ops->priv = chain;
1437 ops->hook = afi->hooks[ops->hooknum];
Pablo Neira Ayuso2cbce132015-06-12 13:55:41 +02001438 ops->dev = dev;
Patrick McHardy115a60b2014-01-03 12:16:15 +00001439 if (hookfn)
1440 ops->hook = hookfn;
1441 if (afi->hook_ops_init)
1442 afi->hook_ops_init(ops, i);
1443 }
Patrick McHardy96518512013-10-14 11:00:02 +02001444
1445 chain->flags |= NFT_BASE_CHAIN;
Patrick McHardy57de2a02014-01-09 18:42:31 +00001446 basechain->policy = policy;
Patrick McHardy96518512013-10-14 11:00:02 +02001447 } else {
1448 chain = kzalloc(sizeof(*chain), GFP_KERNEL);
1449 if (chain == NULL)
1450 return -ENOMEM;
1451 }
1452
1453 INIT_LIST_HEAD(&chain->rules);
1454 chain->handle = nf_tables_alloc_handle(table);
Pablo Neira Ayusob5bc89b2013-10-10 16:49:19 +02001455 chain->table = table;
Patrick McHardy96518512013-10-14 11:00:02 +02001456 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
1457
Pablo Neira Ayusod8ee8f72015-06-15 02:42:31 +02001458 err = nf_tables_register_hooks(table, chain, afi->nops);
1459 if (err < 0)
1460 goto err1;
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001461
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01001462 nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001463 err = nft_trans_chain_add(&ctx, NFT_MSG_NEWCHAIN);
1464 if (err < 0)
1465 goto err2;
1466
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +02001467 table->use++;
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02001468 list_add_tail_rcu(&chain->list, &table->chains);
Patrick McHardy96518512013-10-14 11:00:02 +02001469 return 0;
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001470err2:
Arturo Borreroc5598792014-09-02 16:42:23 +02001471 nf_tables_unregister_hooks(table, chain, afi->nops);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001472err1:
1473 nf_tables_chain_destroy(chain);
1474 return err;
Patrick McHardy96518512013-10-14 11:00:02 +02001475}
1476
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01001477static int nf_tables_delchain(struct net *net, struct sock *nlsk,
1478 struct sk_buff *skb, const struct nlmsghdr *nlh,
Patrick McHardy96518512013-10-14 11:00:02 +02001479 const struct nlattr * const nla[])
1480{
1481 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02001482 struct nft_af_info *afi;
Patrick McHardy96518512013-10-14 11:00:02 +02001483 struct nft_table *table;
1484 struct nft_chain *chain;
1485 int family = nfmsg->nfgen_family;
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001486 struct nft_ctx ctx;
Patrick McHardy96518512013-10-14 11:00:02 +02001487
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001488 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001489 if (IS_ERR(afi))
1490 return PTR_ERR(afi);
1491
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001492 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001493 if (IS_ERR(table))
1494 return PTR_ERR(table);
1495
1496 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
1497 if (IS_ERR(chain))
1498 return PTR_ERR(chain);
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +02001499 if (chain->use > 0)
Patrick McHardy96518512013-10-14 11:00:02 +02001500 return -EBUSY;
1501
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01001502 nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001503
Arturo Borreroee01d542014-09-02 16:42:25 +02001504 return nft_delchain(&ctx);
Patrick McHardy96518512013-10-14 11:00:02 +02001505}
1506
Patrick McHardy96518512013-10-14 11:00:02 +02001507/*
1508 * Expressions
1509 */
1510
1511/**
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001512 * nft_register_expr - register nf_tables expr type
1513 * @ops: expr type
Patrick McHardy96518512013-10-14 11:00:02 +02001514 *
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001515 * Registers the expr type for use with nf_tables. Returns zero on
Patrick McHardy96518512013-10-14 11:00:02 +02001516 * success or a negative errno code otherwise.
1517 */
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001518int nft_register_expr(struct nft_expr_type *type)
Patrick McHardy96518512013-10-14 11:00:02 +02001519{
1520 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Tomasz Bursztyka758dbce2014-04-14 15:41:26 +03001521 if (type->family == NFPROTO_UNSPEC)
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02001522 list_add_tail_rcu(&type->list, &nf_tables_expressions);
Tomasz Bursztyka758dbce2014-04-14 15:41:26 +03001523 else
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02001524 list_add_rcu(&type->list, &nf_tables_expressions);
Patrick McHardy96518512013-10-14 11:00:02 +02001525 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1526 return 0;
1527}
1528EXPORT_SYMBOL_GPL(nft_register_expr);
1529
1530/**
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001531 * nft_unregister_expr - unregister nf_tables expr type
1532 * @ops: expr type
Patrick McHardy96518512013-10-14 11:00:02 +02001533 *
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001534 * Unregisters the expr typefor use with nf_tables.
Patrick McHardy96518512013-10-14 11:00:02 +02001535 */
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001536void nft_unregister_expr(struct nft_expr_type *type)
Patrick McHardy96518512013-10-14 11:00:02 +02001537{
1538 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02001539 list_del_rcu(&type->list);
Patrick McHardy96518512013-10-14 11:00:02 +02001540 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1541}
1542EXPORT_SYMBOL_GPL(nft_unregister_expr);
1543
Patrick McHardy64d46802014-02-05 15:03:37 +00001544static const struct nft_expr_type *__nft_expr_type_get(u8 family,
1545 struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001546{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001547 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001548
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001549 list_for_each_entry(type, &nf_tables_expressions, list) {
Patrick McHardy64d46802014-02-05 15:03:37 +00001550 if (!nla_strcmp(nla, type->name) &&
1551 (!type->family || type->family == family))
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001552 return type;
Patrick McHardy96518512013-10-14 11:00:02 +02001553 }
1554 return NULL;
1555}
1556
Patrick McHardy64d46802014-02-05 15:03:37 +00001557static const struct nft_expr_type *nft_expr_type_get(u8 family,
1558 struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001559{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001560 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001561
1562 if (nla == NULL)
1563 return ERR_PTR(-EINVAL);
1564
Patrick McHardy64d46802014-02-05 15:03:37 +00001565 type = __nft_expr_type_get(family, nla);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001566 if (type != NULL && try_module_get(type->owner))
1567 return type;
Patrick McHardy96518512013-10-14 11:00:02 +02001568
1569#ifdef CONFIG_MODULES
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001570 if (type == NULL) {
Patrick McHardy96518512013-10-14 11:00:02 +02001571 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
Patrick McHardy64d46802014-02-05 15:03:37 +00001572 request_module("nft-expr-%u-%.*s", family,
1573 nla_len(nla), (char *)nla_data(nla));
1574 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1575 if (__nft_expr_type_get(family, nla))
1576 return ERR_PTR(-EAGAIN);
1577
1578 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
Patrick McHardy96518512013-10-14 11:00:02 +02001579 request_module("nft-expr-%.*s",
1580 nla_len(nla), (char *)nla_data(nla));
1581 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardy64d46802014-02-05 15:03:37 +00001582 if (__nft_expr_type_get(family, nla))
Patrick McHardy96518512013-10-14 11:00:02 +02001583 return ERR_PTR(-EAGAIN);
1584 }
1585#endif
1586 return ERR_PTR(-ENOENT);
1587}
1588
1589static const struct nla_policy nft_expr_policy[NFTA_EXPR_MAX + 1] = {
1590 [NFTA_EXPR_NAME] = { .type = NLA_STRING },
1591 [NFTA_EXPR_DATA] = { .type = NLA_NESTED },
1592};
1593
1594static int nf_tables_fill_expr_info(struct sk_buff *skb,
1595 const struct nft_expr *expr)
1596{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001597 if (nla_put_string(skb, NFTA_EXPR_NAME, expr->ops->type->name))
Patrick McHardy96518512013-10-14 11:00:02 +02001598 goto nla_put_failure;
1599
1600 if (expr->ops->dump) {
1601 struct nlattr *data = nla_nest_start(skb, NFTA_EXPR_DATA);
1602 if (data == NULL)
1603 goto nla_put_failure;
1604 if (expr->ops->dump(skb, expr) < 0)
1605 goto nla_put_failure;
1606 nla_nest_end(skb, data);
1607 }
1608
1609 return skb->len;
1610
1611nla_put_failure:
1612 return -1;
1613};
1614
Patrick McHardy0b2d8a72015-04-11 10:46:38 +01001615int nft_expr_dump(struct sk_buff *skb, unsigned int attr,
1616 const struct nft_expr *expr)
1617{
1618 struct nlattr *nest;
1619
1620 nest = nla_nest_start(skb, attr);
1621 if (!nest)
1622 goto nla_put_failure;
1623 if (nf_tables_fill_expr_info(skb, expr) < 0)
1624 goto nla_put_failure;
1625 nla_nest_end(skb, nest);
1626 return 0;
1627
1628nla_put_failure:
1629 return -1;
1630}
1631
Patrick McHardy96518512013-10-14 11:00:02 +02001632struct nft_expr_info {
1633 const struct nft_expr_ops *ops;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001634 struct nlattr *tb[NFT_EXPR_MAXATTR + 1];
Patrick McHardy96518512013-10-14 11:00:02 +02001635};
1636
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001637static int nf_tables_expr_parse(const struct nft_ctx *ctx,
1638 const struct nlattr *nla,
Patrick McHardy96518512013-10-14 11:00:02 +02001639 struct nft_expr_info *info)
1640{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001641 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001642 const struct nft_expr_ops *ops;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001643 struct nlattr *tb[NFTA_EXPR_MAX + 1];
Patrick McHardy96518512013-10-14 11:00:02 +02001644 int err;
1645
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001646 err = nla_parse_nested(tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
Patrick McHardy96518512013-10-14 11:00:02 +02001647 if (err < 0)
1648 return err;
1649
Patrick McHardy64d46802014-02-05 15:03:37 +00001650 type = nft_expr_type_get(ctx->afi->family, tb[NFTA_EXPR_NAME]);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001651 if (IS_ERR(type))
1652 return PTR_ERR(type);
1653
1654 if (tb[NFTA_EXPR_DATA]) {
1655 err = nla_parse_nested(info->tb, type->maxattr,
1656 tb[NFTA_EXPR_DATA], type->policy);
1657 if (err < 0)
1658 goto err1;
1659 } else
1660 memset(info->tb, 0, sizeof(info->tb[0]) * (type->maxattr + 1));
1661
1662 if (type->select_ops != NULL) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001663 ops = type->select_ops(ctx,
1664 (const struct nlattr * const *)info->tb);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001665 if (IS_ERR(ops)) {
1666 err = PTR_ERR(ops);
1667 goto err1;
1668 }
1669 } else
1670 ops = type->ops;
1671
Patrick McHardy96518512013-10-14 11:00:02 +02001672 info->ops = ops;
1673 return 0;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001674
1675err1:
1676 module_put(type->owner);
1677 return err;
Patrick McHardy96518512013-10-14 11:00:02 +02001678}
1679
1680static int nf_tables_newexpr(const struct nft_ctx *ctx,
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001681 const struct nft_expr_info *info,
Patrick McHardy96518512013-10-14 11:00:02 +02001682 struct nft_expr *expr)
1683{
1684 const struct nft_expr_ops *ops = info->ops;
1685 int err;
1686
1687 expr->ops = ops;
1688 if (ops->init) {
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001689 err = ops->init(ctx, expr, (const struct nlattr **)info->tb);
Patrick McHardy96518512013-10-14 11:00:02 +02001690 if (err < 0)
1691 goto err1;
1692 }
1693
Patrick McHardy96518512013-10-14 11:00:02 +02001694 return 0;
1695
1696err1:
1697 expr->ops = NULL;
1698 return err;
1699}
1700
Patrick McHardy62472bc2014-03-07 19:08:30 +01001701static void nf_tables_expr_destroy(const struct nft_ctx *ctx,
1702 struct nft_expr *expr)
Patrick McHardy96518512013-10-14 11:00:02 +02001703{
1704 if (expr->ops->destroy)
Patrick McHardy62472bc2014-03-07 19:08:30 +01001705 expr->ops->destroy(ctx, expr);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001706 module_put(expr->ops->type->owner);
Patrick McHardy96518512013-10-14 11:00:02 +02001707}
1708
Patrick McHardy0b2d8a72015-04-11 10:46:38 +01001709struct nft_expr *nft_expr_init(const struct nft_ctx *ctx,
1710 const struct nlattr *nla)
1711{
1712 struct nft_expr_info info;
1713 struct nft_expr *expr;
1714 int err;
1715
1716 err = nf_tables_expr_parse(ctx, nla, &info);
1717 if (err < 0)
1718 goto err1;
1719
1720 err = -ENOMEM;
1721 expr = kzalloc(info.ops->size, GFP_KERNEL);
1722 if (expr == NULL)
1723 goto err2;
1724
1725 err = nf_tables_newexpr(ctx, &info, expr);
1726 if (err < 0)
1727 goto err2;
1728
1729 return expr;
1730err2:
1731 module_put(info.ops->type->owner);
1732err1:
1733 return ERR_PTR(err);
1734}
1735
1736void nft_expr_destroy(const struct nft_ctx *ctx, struct nft_expr *expr)
1737{
1738 nf_tables_expr_destroy(ctx, expr);
1739 kfree(expr);
1740}
1741
Patrick McHardy96518512013-10-14 11:00:02 +02001742/*
1743 * Rules
1744 */
1745
1746static struct nft_rule *__nf_tables_rule_lookup(const struct nft_chain *chain,
1747 u64 handle)
1748{
1749 struct nft_rule *rule;
1750
1751 // FIXME: this sucks
1752 list_for_each_entry(rule, &chain->rules, list) {
1753 if (handle == rule->handle)
1754 return rule;
1755 }
1756
1757 return ERR_PTR(-ENOENT);
1758}
1759
1760static struct nft_rule *nf_tables_rule_lookup(const struct nft_chain *chain,
1761 const struct nlattr *nla)
1762{
1763 if (nla == NULL)
1764 return ERR_PTR(-EINVAL);
1765
1766 return __nf_tables_rule_lookup(chain, be64_to_cpu(nla_get_be64(nla)));
1767}
1768
1769static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
1770 [NFTA_RULE_TABLE] = { .type = NLA_STRING },
1771 [NFTA_RULE_CHAIN] = { .type = NLA_STRING,
1772 .len = NFT_CHAIN_MAXNAMELEN - 1 },
1773 [NFTA_RULE_HANDLE] = { .type = NLA_U64 },
1774 [NFTA_RULE_EXPRESSIONS] = { .type = NLA_NESTED },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001775 [NFTA_RULE_COMPAT] = { .type = NLA_NESTED },
Eric Leblond5e948462013-10-10 13:41:44 +02001776 [NFTA_RULE_POSITION] = { .type = NLA_U64 },
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01001777 [NFTA_RULE_USERDATA] = { .type = NLA_BINARY,
1778 .len = NFT_USERDATA_MAXLEN },
Patrick McHardy96518512013-10-14 11:00:02 +02001779};
1780
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02001781static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
1782 u32 portid, u32 seq, int event,
1783 u32 flags, int family,
Patrick McHardy96518512013-10-14 11:00:02 +02001784 const struct nft_table *table,
1785 const struct nft_chain *chain,
1786 const struct nft_rule *rule)
1787{
1788 struct nlmsghdr *nlh;
1789 struct nfgenmsg *nfmsg;
1790 const struct nft_expr *expr, *next;
1791 struct nlattr *list;
Eric Leblond5e948462013-10-10 13:41:44 +02001792 const struct nft_rule *prule;
1793 int type = event | NFNL_SUBSYS_NFTABLES << 8;
Patrick McHardy96518512013-10-14 11:00:02 +02001794
Eric Leblond5e948462013-10-10 13:41:44 +02001795 nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg),
Patrick McHardy96518512013-10-14 11:00:02 +02001796 flags);
1797 if (nlh == NULL)
1798 goto nla_put_failure;
1799
1800 nfmsg = nlmsg_data(nlh);
1801 nfmsg->nfgen_family = family;
1802 nfmsg->version = NFNETLINK_V0;
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02001803 nfmsg->res_id = htons(net->nft.base_seq & 0xffff);
Patrick McHardy96518512013-10-14 11:00:02 +02001804
1805 if (nla_put_string(skb, NFTA_RULE_TABLE, table->name))
1806 goto nla_put_failure;
1807 if (nla_put_string(skb, NFTA_RULE_CHAIN, chain->name))
1808 goto nla_put_failure;
Nicolas Dichtelb46f6de2016-04-22 17:31:18 +02001809 if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle),
1810 NFTA_RULE_PAD))
Patrick McHardy96518512013-10-14 11:00:02 +02001811 goto nla_put_failure;
1812
Eric Leblond5e948462013-10-10 13:41:44 +02001813 if ((event != NFT_MSG_DELRULE) && (rule->list.prev != &chain->rules)) {
1814 prule = list_entry(rule->list.prev, struct nft_rule, list);
1815 if (nla_put_be64(skb, NFTA_RULE_POSITION,
Nicolas Dichtelb46f6de2016-04-22 17:31:18 +02001816 cpu_to_be64(prule->handle),
1817 NFTA_RULE_PAD))
Eric Leblond5e948462013-10-10 13:41:44 +02001818 goto nla_put_failure;
1819 }
1820
Patrick McHardy96518512013-10-14 11:00:02 +02001821 list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
1822 if (list == NULL)
1823 goto nla_put_failure;
1824 nft_rule_for_each_expr(expr, next, rule) {
Patrick McHardy0b2d8a72015-04-11 10:46:38 +01001825 if (nft_expr_dump(skb, NFTA_LIST_ELEM, expr) < 0)
Patrick McHardy96518512013-10-14 11:00:02 +02001826 goto nla_put_failure;
Patrick McHardy96518512013-10-14 11:00:02 +02001827 }
1828 nla_nest_end(skb, list);
1829
Patrick McHardy86f1ec32015-03-03 20:04:20 +00001830 if (rule->udata) {
1831 struct nft_userdata *udata = nft_userdata(rule);
1832 if (nla_put(skb, NFTA_RULE_USERDATA, udata->len + 1,
1833 udata->data) < 0)
1834 goto nla_put_failure;
1835 }
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01001836
Johannes Berg053c0952015-01-16 22:09:00 +01001837 nlmsg_end(skb, nlh);
1838 return 0;
Patrick McHardy96518512013-10-14 11:00:02 +02001839
1840nla_put_failure:
1841 nlmsg_trim(skb, nlh);
1842 return -1;
1843}
1844
Pablo Neira Ayuso35151d82014-05-05 17:12:40 +02001845static int nf_tables_rule_notify(const struct nft_ctx *ctx,
Patrick McHardy96518512013-10-14 11:00:02 +02001846 const struct nft_rule *rule,
Pablo Neira Ayuso35151d82014-05-05 17:12:40 +02001847 int event)
Patrick McHardy96518512013-10-14 11:00:02 +02001848{
1849 struct sk_buff *skb;
Patrick McHardy96518512013-10-14 11:00:02 +02001850 int err;
1851
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +02001852 if (!ctx->report &&
1853 !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
Patrick McHardy96518512013-10-14 11:00:02 +02001854 return 0;
1855
1856 err = -ENOBUFS;
1857 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1858 if (skb == NULL)
1859 goto err;
1860
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02001861 err = nf_tables_fill_rule_info(skb, ctx->net, ctx->portid, ctx->seq,
1862 event, 0, ctx->afi->family, ctx->table,
Pablo Neira Ayuso35151d82014-05-05 17:12:40 +02001863 ctx->chain, rule);
Patrick McHardy96518512013-10-14 11:00:02 +02001864 if (err < 0) {
1865 kfree_skb(skb);
1866 goto err;
1867 }
1868
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +02001869 err = nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
1870 ctx->report, GFP_KERNEL);
Patrick McHardy96518512013-10-14 11:00:02 +02001871err:
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +02001872 if (err < 0) {
1873 nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES,
1874 err);
1875 }
Patrick McHardy96518512013-10-14 11:00:02 +02001876 return err;
1877}
1878
1879static int nf_tables_dump_rules(struct sk_buff *skb,
1880 struct netlink_callback *cb)
1881{
1882 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
1883 const struct nft_af_info *afi;
1884 const struct nft_table *table;
1885 const struct nft_chain *chain;
1886 const struct nft_rule *rule;
1887 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001888 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001889 int family = nfmsg->nfgen_family;
1890
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02001891 rcu_read_lock();
Pablo Neira Ayuso38e029f2014-07-01 12:23:12 +02001892 cb->seq = net->nft.base_seq;
1893
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02001894 list_for_each_entry_rcu(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +02001895 if (family != NFPROTO_UNSPEC && family != afi->family)
1896 continue;
1897
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02001898 list_for_each_entry_rcu(table, &afi->tables, list) {
1899 list_for_each_entry_rcu(chain, &table->chains, list) {
1900 list_for_each_entry_rcu(rule, &chain->rules, list) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001901 if (!nft_rule_is_active(net, rule))
1902 goto cont;
Patrick McHardy96518512013-10-14 11:00:02 +02001903 if (idx < s_idx)
1904 goto cont;
1905 if (idx > s_idx)
1906 memset(&cb->args[1], 0,
1907 sizeof(cb->args) - sizeof(cb->args[0]));
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02001908 if (nf_tables_fill_rule_info(skb, net, NETLINK_CB(cb->skb).portid,
Patrick McHardy96518512013-10-14 11:00:02 +02001909 cb->nlh->nlmsg_seq,
1910 NFT_MSG_NEWRULE,
1911 NLM_F_MULTI | NLM_F_APPEND,
1912 afi->family, table, chain, rule) < 0)
1913 goto done;
Pablo Neira Ayuso38e029f2014-07-01 12:23:12 +02001914
1915 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Patrick McHardy96518512013-10-14 11:00:02 +02001916cont:
1917 idx++;
1918 }
1919 }
1920 }
1921 }
1922done:
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02001923 rcu_read_unlock();
1924
Patrick McHardy96518512013-10-14 11:00:02 +02001925 cb->args[0] = idx;
1926 return skb->len;
1927}
1928
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01001929static int nf_tables_getrule(struct net *net, struct sock *nlsk,
1930 struct sk_buff *skb, const struct nlmsghdr *nlh,
Patrick McHardy96518512013-10-14 11:00:02 +02001931 const struct nlattr * const nla[])
1932{
1933 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1934 const struct nft_af_info *afi;
1935 const struct nft_table *table;
1936 const struct nft_chain *chain;
1937 const struct nft_rule *rule;
1938 struct sk_buff *skb2;
1939 int family = nfmsg->nfgen_family;
1940 int err;
1941
1942 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1943 struct netlink_dump_control c = {
1944 .dump = nf_tables_dump_rules,
1945 };
1946 return netlink_dump_start(nlsk, skb, nlh, &c);
1947 }
1948
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001949 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001950 if (IS_ERR(afi))
1951 return PTR_ERR(afi);
1952
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001953 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001954 if (IS_ERR(table))
1955 return PTR_ERR(table);
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +02001956 if (table->flags & NFT_TABLE_INACTIVE)
1957 return -ENOENT;
Patrick McHardy96518512013-10-14 11:00:02 +02001958
1959 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1960 if (IS_ERR(chain))
1961 return PTR_ERR(chain);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001962 if (chain->flags & NFT_CHAIN_INACTIVE)
1963 return -ENOENT;
Patrick McHardy96518512013-10-14 11:00:02 +02001964
1965 rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
1966 if (IS_ERR(rule))
1967 return PTR_ERR(rule);
1968
1969 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1970 if (!skb2)
1971 return -ENOMEM;
1972
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02001973 err = nf_tables_fill_rule_info(skb2, net, NETLINK_CB(skb).portid,
Patrick McHardy96518512013-10-14 11:00:02 +02001974 nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
1975 family, table, chain, rule);
1976 if (err < 0)
1977 goto err;
1978
1979 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
1980
1981err:
1982 kfree_skb(skb2);
1983 return err;
1984}
1985
Patrick McHardy62472bc2014-03-07 19:08:30 +01001986static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
1987 struct nft_rule *rule)
Patrick McHardy96518512013-10-14 11:00:02 +02001988{
Patrick McHardy96518512013-10-14 11:00:02 +02001989 struct nft_expr *expr;
1990
1991 /*
1992 * Careful: some expressions might not be initialized in case this
1993 * is called on error from nf_tables_newrule().
1994 */
1995 expr = nft_expr_first(rule);
1996 while (expr->ops && expr != nft_expr_last(rule)) {
Patrick McHardy62472bc2014-03-07 19:08:30 +01001997 nf_tables_expr_destroy(ctx, expr);
Patrick McHardy96518512013-10-14 11:00:02 +02001998 expr = nft_expr_next(expr);
1999 }
2000 kfree(rule);
2001}
2002
Patrick McHardy96518512013-10-14 11:00:02 +02002003#define NFT_RULE_MAXEXPRS 128
2004
2005static struct nft_expr_info *info;
2006
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01002007static int nf_tables_newrule(struct net *net, struct sock *nlsk,
2008 struct sk_buff *skb, const struct nlmsghdr *nlh,
Patrick McHardy96518512013-10-14 11:00:02 +02002009 const struct nlattr * const nla[])
2010{
2011 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02002012 struct nft_af_info *afi;
Patrick McHardy96518512013-10-14 11:00:02 +02002013 struct nft_table *table;
2014 struct nft_chain *chain;
2015 struct nft_rule *rule, *old_rule = NULL;
Patrick McHardy86f1ec32015-03-03 20:04:20 +00002016 struct nft_userdata *udata;
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02002017 struct nft_trans *trans = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +02002018 struct nft_expr *expr;
2019 struct nft_ctx ctx;
2020 struct nlattr *tmp;
Patrick McHardy86f1ec32015-03-03 20:04:20 +00002021 unsigned int size, i, n, ulen = 0, usize = 0;
Patrick McHardy96518512013-10-14 11:00:02 +02002022 int err, rem;
2023 bool create;
Eric Leblond5e948462013-10-10 13:41:44 +02002024 u64 handle, pos_handle;
Patrick McHardy96518512013-10-14 11:00:02 +02002025
2026 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
2027
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002028 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
Patrick McHardy96518512013-10-14 11:00:02 +02002029 if (IS_ERR(afi))
2030 return PTR_ERR(afi);
2031
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002032 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02002033 if (IS_ERR(table))
2034 return PTR_ERR(table);
2035
2036 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
2037 if (IS_ERR(chain))
2038 return PTR_ERR(chain);
2039
2040 if (nla[NFTA_RULE_HANDLE]) {
2041 handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
2042 rule = __nf_tables_rule_lookup(chain, handle);
2043 if (IS_ERR(rule))
2044 return PTR_ERR(rule);
2045
2046 if (nlh->nlmsg_flags & NLM_F_EXCL)
2047 return -EEXIST;
2048 if (nlh->nlmsg_flags & NLM_F_REPLACE)
2049 old_rule = rule;
2050 else
2051 return -EOPNOTSUPP;
2052 } else {
2053 if (!create || nlh->nlmsg_flags & NLM_F_REPLACE)
2054 return -EINVAL;
2055 handle = nf_tables_alloc_handle(table);
Pablo Neira Ayusoa0a73792014-06-10 10:53:01 +02002056
2057 if (chain->use == UINT_MAX)
2058 return -EOVERFLOW;
Patrick McHardy96518512013-10-14 11:00:02 +02002059 }
2060
Eric Leblond5e948462013-10-10 13:41:44 +02002061 if (nla[NFTA_RULE_POSITION]) {
2062 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
2063 return -EOPNOTSUPP;
2064
2065 pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
2066 old_rule = __nf_tables_rule_lookup(chain, pos_handle);
2067 if (IS_ERR(old_rule))
2068 return PTR_ERR(old_rule);
2069 }
2070
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01002071 nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002072
Patrick McHardy96518512013-10-14 11:00:02 +02002073 n = 0;
2074 size = 0;
2075 if (nla[NFTA_RULE_EXPRESSIONS]) {
2076 nla_for_each_nested(tmp, nla[NFTA_RULE_EXPRESSIONS], rem) {
2077 err = -EINVAL;
2078 if (nla_type(tmp) != NFTA_LIST_ELEM)
2079 goto err1;
2080 if (n == NFT_RULE_MAXEXPRS)
2081 goto err1;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002082 err = nf_tables_expr_parse(&ctx, tmp, &info[n]);
Patrick McHardy96518512013-10-14 11:00:02 +02002083 if (err < 0)
2084 goto err1;
2085 size += info[n].ops->size;
2086 n++;
2087 }
2088 }
Patrick McHardy98898402015-03-03 20:04:19 +00002089 /* Check for overflow of dlen field */
2090 err = -EFBIG;
2091 if (size >= 1 << 12)
2092 goto err1;
Patrick McHardy96518512013-10-14 11:00:02 +02002093
Patrick McHardy86f1ec32015-03-03 20:04:20 +00002094 if (nla[NFTA_RULE_USERDATA]) {
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01002095 ulen = nla_len(nla[NFTA_RULE_USERDATA]);
Patrick McHardy86f1ec32015-03-03 20:04:20 +00002096 if (ulen > 0)
2097 usize = sizeof(struct nft_userdata) + ulen;
2098 }
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01002099
Patrick McHardy96518512013-10-14 11:00:02 +02002100 err = -ENOMEM;
Patrick McHardy86f1ec32015-03-03 20:04:20 +00002101 rule = kzalloc(sizeof(*rule) + size + usize, GFP_KERNEL);
Patrick McHardy96518512013-10-14 11:00:02 +02002102 if (rule == NULL)
2103 goto err1;
2104
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002105 nft_rule_activate_next(net, rule);
2106
Patrick McHardy96518512013-10-14 11:00:02 +02002107 rule->handle = handle;
2108 rule->dlen = size;
Patrick McHardy86f1ec32015-03-03 20:04:20 +00002109 rule->udata = ulen ? 1 : 0;
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01002110
Patrick McHardy86f1ec32015-03-03 20:04:20 +00002111 if (ulen) {
2112 udata = nft_userdata(rule);
2113 udata->len = ulen - 1;
2114 nla_memcpy(udata->data, nla[NFTA_RULE_USERDATA], ulen);
2115 }
Patrick McHardy96518512013-10-14 11:00:02 +02002116
Patrick McHardy96518512013-10-14 11:00:02 +02002117 expr = nft_expr_first(rule);
2118 for (i = 0; i < n; i++) {
2119 err = nf_tables_newexpr(&ctx, &info[i], expr);
2120 if (err < 0)
2121 goto err2;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02002122 info[i].ops = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +02002123 expr = nft_expr_next(expr);
2124 }
2125
Patrick McHardy96518512013-10-14 11:00:02 +02002126 if (nlh->nlmsg_flags & NLM_F_REPLACE) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002127 if (nft_rule_is_active_next(net, old_rule)) {
Pablo Neira Ayusoac904ac2014-06-10 10:53:03 +02002128 trans = nft_trans_rule_add(&ctx, NFT_MSG_DELRULE,
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02002129 old_rule);
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02002130 if (trans == NULL) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002131 err = -ENOMEM;
2132 goto err2;
2133 }
Arturo Borreroee01d542014-09-02 16:42:25 +02002134 nft_rule_deactivate_next(net, old_rule);
Pablo Neira Ayusoac34b862014-06-10 10:53:02 +02002135 chain->use--;
Pablo Neira Ayuso5bc5c302014-06-10 10:53:00 +02002136 list_add_tail_rcu(&rule->list, &old_rule->list);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002137 } else {
2138 err = -ENOENT;
2139 goto err2;
2140 }
Patrick McHardy96518512013-10-14 11:00:02 +02002141 } else if (nlh->nlmsg_flags & NLM_F_APPEND)
Eric Leblond5e948462013-10-10 13:41:44 +02002142 if (old_rule)
2143 list_add_rcu(&rule->list, &old_rule->list);
2144 else
2145 list_add_tail_rcu(&rule->list, &chain->rules);
2146 else {
2147 if (old_rule)
2148 list_add_tail_rcu(&rule->list, &old_rule->list);
2149 else
2150 list_add_rcu(&rule->list, &chain->rules);
2151 }
Patrick McHardy96518512013-10-14 11:00:02 +02002152
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02002153 if (nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule) == NULL) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002154 err = -ENOMEM;
2155 goto err3;
2156 }
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +02002157 chain->use++;
Patrick McHardy96518512013-10-14 11:00:02 +02002158 return 0;
2159
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002160err3:
2161 list_del_rcu(&rule->list);
Patrick McHardy96518512013-10-14 11:00:02 +02002162err2:
Patrick McHardy62472bc2014-03-07 19:08:30 +01002163 nf_tables_rule_destroy(&ctx, rule);
Patrick McHardy96518512013-10-14 11:00:02 +02002164err1:
2165 for (i = 0; i < n; i++) {
2166 if (info[i].ops != NULL)
Patrick McHardyef1f7df2013-10-10 11:41:20 +02002167 module_put(info[i].ops->type->owner);
Patrick McHardy96518512013-10-14 11:00:02 +02002168 }
2169 return err;
2170}
2171
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01002172static int nf_tables_delrule(struct net *net, struct sock *nlsk,
2173 struct sk_buff *skb, const struct nlmsghdr *nlh,
Patrick McHardy96518512013-10-14 11:00:02 +02002174 const struct nlattr * const nla[])
2175{
2176 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02002177 struct nft_af_info *afi;
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02002178 struct nft_table *table;
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01002179 struct nft_chain *chain = NULL;
2180 struct nft_rule *rule;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002181 int family = nfmsg->nfgen_family, err = 0;
2182 struct nft_ctx ctx;
Patrick McHardy96518512013-10-14 11:00:02 +02002183
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002184 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02002185 if (IS_ERR(afi))
2186 return PTR_ERR(afi);
2187
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002188 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02002189 if (IS_ERR(table))
2190 return PTR_ERR(table);
2191
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01002192 if (nla[NFTA_RULE_CHAIN]) {
2193 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
2194 if (IS_ERR(chain))
2195 return PTR_ERR(chain);
2196 }
Patrick McHardy96518512013-10-14 11:00:02 +02002197
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01002198 nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002199
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01002200 if (chain) {
2201 if (nla[NFTA_RULE_HANDLE]) {
2202 rule = nf_tables_rule_lookup(chain,
2203 nla[NFTA_RULE_HANDLE]);
2204 if (IS_ERR(rule))
2205 return PTR_ERR(rule);
Patrick McHardy96518512013-10-14 11:00:02 +02002206
Arturo Borrero5e266fe2014-09-02 16:42:21 +02002207 err = nft_delrule(&ctx, rule);
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01002208 } else {
Arturo Borreroce24b722014-09-02 16:42:24 +02002209 err = nft_delrule_by_chain(&ctx);
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01002210 }
2211 } else {
2212 list_for_each_entry(chain, &table->chains, list) {
2213 ctx.chain = chain;
Arturo Borreroce24b722014-09-02 16:42:24 +02002214 err = nft_delrule_by_chain(&ctx);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002215 if (err < 0)
2216 break;
Patrick McHardy96518512013-10-14 11:00:02 +02002217 }
2218 }
2219
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002220 return err;
2221}
2222
Patrick McHardy20a69342013-10-11 12:06:22 +02002223/*
2224 * Sets
2225 */
2226
2227static LIST_HEAD(nf_tables_set_ops);
2228
2229int nft_register_set(struct nft_set_ops *ops)
2230{
2231 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02002232 list_add_tail_rcu(&ops->list, &nf_tables_set_ops);
Patrick McHardy20a69342013-10-11 12:06:22 +02002233 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
2234 return 0;
2235}
2236EXPORT_SYMBOL_GPL(nft_register_set);
2237
2238void nft_unregister_set(struct nft_set_ops *ops)
2239{
2240 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02002241 list_del_rcu(&ops->list);
Patrick McHardy20a69342013-10-11 12:06:22 +02002242 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
2243}
2244EXPORT_SYMBOL_GPL(nft_unregister_set);
2245
Patrick McHardyc50b9602014-03-28 10:19:47 +00002246/*
2247 * Select a set implementation based on the data characteristics and the
2248 * given policy. The total memory use might not be known if no size is
2249 * given, in that case the amount of memory per element is used.
2250 */
2251static const struct nft_set_ops *
2252nft_select_set_ops(const struct nlattr * const nla[],
2253 const struct nft_set_desc *desc,
2254 enum nft_set_policies policy)
Patrick McHardy20a69342013-10-11 12:06:22 +02002255{
Patrick McHardyc50b9602014-03-28 10:19:47 +00002256 const struct nft_set_ops *ops, *bops;
2257 struct nft_set_estimate est, best;
Patrick McHardy20a69342013-10-11 12:06:22 +02002258 u32 features;
2259
2260#ifdef CONFIG_MODULES
2261 if (list_empty(&nf_tables_set_ops)) {
2262 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
2263 request_module("nft-set");
2264 nfnl_lock(NFNL_SUBSYS_NFTABLES);
2265 if (!list_empty(&nf_tables_set_ops))
2266 return ERR_PTR(-EAGAIN);
2267 }
2268#endif
2269 features = 0;
2270 if (nla[NFTA_SET_FLAGS] != NULL) {
2271 features = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
Patrick McHardy4a8678e2015-04-05 14:41:05 +02002272 features &= NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_TIMEOUT;
Patrick McHardy20a69342013-10-11 12:06:22 +02002273 }
2274
Patrick McHardyc50b9602014-03-28 10:19:47 +00002275 bops = NULL;
2276 best.size = ~0;
2277 best.class = ~0;
2278
Patrick McHardy20a69342013-10-11 12:06:22 +02002279 list_for_each_entry(ops, &nf_tables_set_ops, list) {
2280 if ((ops->features & features) != features)
2281 continue;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002282 if (!ops->estimate(desc, features, &est))
2283 continue;
2284
2285 switch (policy) {
2286 case NFT_SET_POL_PERFORMANCE:
2287 if (est.class < best.class)
2288 break;
2289 if (est.class == best.class && est.size < best.size)
2290 break;
2291 continue;
2292 case NFT_SET_POL_MEMORY:
2293 if (est.size < best.size)
2294 break;
2295 if (est.size == best.size && est.class < best.class)
2296 break;
2297 continue;
2298 default:
2299 break;
2300 }
2301
Patrick McHardy20a69342013-10-11 12:06:22 +02002302 if (!try_module_get(ops->owner))
2303 continue;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002304 if (bops != NULL)
2305 module_put(bops->owner);
2306
2307 bops = ops;
2308 best = est;
Patrick McHardy20a69342013-10-11 12:06:22 +02002309 }
2310
Patrick McHardyc50b9602014-03-28 10:19:47 +00002311 if (bops != NULL)
2312 return bops;
2313
Patrick McHardy20a69342013-10-11 12:06:22 +02002314 return ERR_PTR(-EOPNOTSUPP);
2315}
2316
2317static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
2318 [NFTA_SET_TABLE] = { .type = NLA_STRING },
Pablo Neira Ayusoa9bdd832014-03-24 15:10:37 +01002319 [NFTA_SET_NAME] = { .type = NLA_STRING,
Pablo Neira Ayusocb39ad82016-05-04 17:49:53 +02002320 .len = NFT_SET_MAXNAMELEN - 1 },
Patrick McHardy20a69342013-10-11 12:06:22 +02002321 [NFTA_SET_FLAGS] = { .type = NLA_U32 },
2322 [NFTA_SET_KEY_TYPE] = { .type = NLA_U32 },
2323 [NFTA_SET_KEY_LEN] = { .type = NLA_U32 },
2324 [NFTA_SET_DATA_TYPE] = { .type = NLA_U32 },
2325 [NFTA_SET_DATA_LEN] = { .type = NLA_U32 },
Patrick McHardyc50b9602014-03-28 10:19:47 +00002326 [NFTA_SET_POLICY] = { .type = NLA_U32 },
2327 [NFTA_SET_DESC] = { .type = NLA_NESTED },
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002328 [NFTA_SET_ID] = { .type = NLA_U32 },
Patrick McHardy761da292015-03-26 12:39:36 +00002329 [NFTA_SET_TIMEOUT] = { .type = NLA_U64 },
2330 [NFTA_SET_GC_INTERVAL] = { .type = NLA_U32 },
Carlos Falgueras Garcíae6d8eca2016-01-05 14:03:32 +01002331 [NFTA_SET_USERDATA] = { .type = NLA_BINARY,
2332 .len = NFT_USERDATA_MAXLEN },
Patrick McHardyc50b9602014-03-28 10:19:47 +00002333};
2334
2335static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
2336 [NFTA_SET_DESC_SIZE] = { .type = NLA_U32 },
Patrick McHardy20a69342013-10-11 12:06:22 +02002337};
2338
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01002339static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
Patrick McHardy20a69342013-10-11 12:06:22 +02002340 const struct sk_buff *skb,
2341 const struct nlmsghdr *nlh,
2342 const struct nlattr * const nla[])
2343{
2344 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02002345 struct nft_af_info *afi = NULL;
2346 struct nft_table *table = NULL;
Patrick McHardy20a69342013-10-11 12:06:22 +02002347
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002348 if (nfmsg->nfgen_family != NFPROTO_UNSPEC) {
2349 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
2350 if (IS_ERR(afi))
2351 return PTR_ERR(afi);
2352 }
Patrick McHardy20a69342013-10-11 12:06:22 +02002353
2354 if (nla[NFTA_SET_TABLE] != NULL) {
Patrick McHardyec2c9932014-02-05 15:03:35 +00002355 if (afi == NULL)
2356 return -EAFNOSUPPORT;
2357
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002358 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02002359 if (IS_ERR(table))
2360 return PTR_ERR(table);
2361 }
2362
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01002363 nft_ctx_init(ctx, net, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002364 return 0;
2365}
2366
2367struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
2368 const struct nlattr *nla)
2369{
2370 struct nft_set *set;
2371
2372 if (nla == NULL)
2373 return ERR_PTR(-EINVAL);
2374
2375 list_for_each_entry(set, &table->sets, list) {
2376 if (!nla_strcmp(nla, set->name))
2377 return set;
2378 }
2379 return ERR_PTR(-ENOENT);
2380}
2381
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002382struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
2383 const struct nlattr *nla)
2384{
2385 struct nft_trans *trans;
2386 u32 id = ntohl(nla_get_be32(nla));
2387
2388 list_for_each_entry(trans, &net->nft.commit_list, list) {
2389 if (trans->msg_type == NFT_MSG_NEWSET &&
2390 id == nft_trans_set_id(trans))
2391 return nft_trans_set(trans);
2392 }
2393 return ERR_PTR(-ENOENT);
2394}
2395
Patrick McHardy20a69342013-10-11 12:06:22 +02002396static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
2397 const char *name)
2398{
2399 const struct nft_set *i;
2400 const char *p;
2401 unsigned long *inuse;
Patrick McHardy60eb1892014-03-07 12:34:05 +01002402 unsigned int n = 0, min = 0;
Patrick McHardy20a69342013-10-11 12:06:22 +02002403
Pablo Neira Ayusocb39ad82016-05-04 17:49:53 +02002404 p = strnchr(name, NFT_SET_MAXNAMELEN, '%');
Patrick McHardy20a69342013-10-11 12:06:22 +02002405 if (p != NULL) {
2406 if (p[1] != 'd' || strchr(p + 2, '%'))
2407 return -EINVAL;
2408
2409 inuse = (unsigned long *)get_zeroed_page(GFP_KERNEL);
2410 if (inuse == NULL)
2411 return -ENOMEM;
Patrick McHardy60eb1892014-03-07 12:34:05 +01002412cont:
Patrick McHardy20a69342013-10-11 12:06:22 +02002413 list_for_each_entry(i, &ctx->table->sets, list) {
Daniel Borkmann14662912013-12-31 12:40:05 +01002414 int tmp;
2415
2416 if (!sscanf(i->name, name, &tmp))
Patrick McHardy20a69342013-10-11 12:06:22 +02002417 continue;
Patrick McHardy60eb1892014-03-07 12:34:05 +01002418 if (tmp < min || tmp >= min + BITS_PER_BYTE * PAGE_SIZE)
Patrick McHardy20a69342013-10-11 12:06:22 +02002419 continue;
Daniel Borkmann14662912013-12-31 12:40:05 +01002420
Patrick McHardy60eb1892014-03-07 12:34:05 +01002421 set_bit(tmp - min, inuse);
Patrick McHardy20a69342013-10-11 12:06:22 +02002422 }
2423
Patrick McHardy53b70282014-02-05 12:26:22 +01002424 n = find_first_zero_bit(inuse, BITS_PER_BYTE * PAGE_SIZE);
Patrick McHardy60eb1892014-03-07 12:34:05 +01002425 if (n >= BITS_PER_BYTE * PAGE_SIZE) {
2426 min += BITS_PER_BYTE * PAGE_SIZE;
2427 memset(inuse, 0, PAGE_SIZE);
2428 goto cont;
2429 }
Patrick McHardy20a69342013-10-11 12:06:22 +02002430 free_page((unsigned long)inuse);
2431 }
2432
Patrick McHardy60eb1892014-03-07 12:34:05 +01002433 snprintf(set->name, sizeof(set->name), name, min + n);
Patrick McHardy20a69342013-10-11 12:06:22 +02002434 list_for_each_entry(i, &ctx->table->sets, list) {
2435 if (!strcmp(set->name, i->name))
2436 return -ENFILE;
2437 }
2438 return 0;
2439}
2440
2441static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
2442 const struct nft_set *set, u16 event, u16 flags)
2443{
2444 struct nfgenmsg *nfmsg;
2445 struct nlmsghdr *nlh;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002446 struct nlattr *desc;
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +02002447 u32 portid = ctx->portid;
2448 u32 seq = ctx->seq;
Patrick McHardy20a69342013-10-11 12:06:22 +02002449
2450 event |= NFNL_SUBSYS_NFTABLES << 8;
2451 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
2452 flags);
2453 if (nlh == NULL)
2454 goto nla_put_failure;
2455
2456 nfmsg = nlmsg_data(nlh);
2457 nfmsg->nfgen_family = ctx->afi->family;
2458 nfmsg->version = NFNETLINK_V0;
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02002459 nfmsg->res_id = htons(ctx->net->nft.base_seq & 0xffff);
Patrick McHardy20a69342013-10-11 12:06:22 +02002460
2461 if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
2462 goto nla_put_failure;
2463 if (nla_put_string(skb, NFTA_SET_NAME, set->name))
2464 goto nla_put_failure;
2465 if (set->flags != 0)
2466 if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
2467 goto nla_put_failure;
2468
2469 if (nla_put_be32(skb, NFTA_SET_KEY_TYPE, htonl(set->ktype)))
2470 goto nla_put_failure;
2471 if (nla_put_be32(skb, NFTA_SET_KEY_LEN, htonl(set->klen)))
2472 goto nla_put_failure;
2473 if (set->flags & NFT_SET_MAP) {
2474 if (nla_put_be32(skb, NFTA_SET_DATA_TYPE, htonl(set->dtype)))
2475 goto nla_put_failure;
2476 if (nla_put_be32(skb, NFTA_SET_DATA_LEN, htonl(set->dlen)))
2477 goto nla_put_failure;
2478 }
2479
Patrick McHardy761da292015-03-26 12:39:36 +00002480 if (set->timeout &&
Nicolas Dichtelb46f6de2016-04-22 17:31:18 +02002481 nla_put_be64(skb, NFTA_SET_TIMEOUT, cpu_to_be64(set->timeout),
2482 NFTA_SET_PAD))
Patrick McHardy761da292015-03-26 12:39:36 +00002483 goto nla_put_failure;
2484 if (set->gc_int &&
2485 nla_put_be32(skb, NFTA_SET_GC_INTERVAL, htonl(set->gc_int)))
2486 goto nla_put_failure;
2487
Arturo Borrero9363dc42014-09-23 13:30:41 +02002488 if (set->policy != NFT_SET_POL_PERFORMANCE) {
2489 if (nla_put_be32(skb, NFTA_SET_POLICY, htonl(set->policy)))
2490 goto nla_put_failure;
2491 }
2492
Carlos Falgueras Garcíae6d8eca2016-01-05 14:03:32 +01002493 if (nla_put(skb, NFTA_SET_USERDATA, set->udlen, set->udata))
2494 goto nla_put_failure;
2495
Patrick McHardyc50b9602014-03-28 10:19:47 +00002496 desc = nla_nest_start(skb, NFTA_SET_DESC);
2497 if (desc == NULL)
2498 goto nla_put_failure;
2499 if (set->size &&
2500 nla_put_be32(skb, NFTA_SET_DESC_SIZE, htonl(set->size)))
2501 goto nla_put_failure;
2502 nla_nest_end(skb, desc);
2503
Johannes Berg053c0952015-01-16 22:09:00 +01002504 nlmsg_end(skb, nlh);
2505 return 0;
Patrick McHardy20a69342013-10-11 12:06:22 +02002506
2507nla_put_failure:
2508 nlmsg_trim(skb, nlh);
2509 return -1;
2510}
2511
2512static int nf_tables_set_notify(const struct nft_ctx *ctx,
2513 const struct nft_set *set,
Pablo Neira Ayuso31f84412014-05-29 10:29:58 +02002514 int event, gfp_t gfp_flags)
Patrick McHardy20a69342013-10-11 12:06:22 +02002515{
2516 struct sk_buff *skb;
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +02002517 u32 portid = ctx->portid;
Patrick McHardy20a69342013-10-11 12:06:22 +02002518 int err;
2519
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +02002520 if (!ctx->report &&
2521 !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
Patrick McHardy20a69342013-10-11 12:06:22 +02002522 return 0;
2523
2524 err = -ENOBUFS;
Pablo Neira Ayuso31f84412014-05-29 10:29:58 +02002525 skb = nlmsg_new(NLMSG_GOODSIZE, gfp_flags);
Patrick McHardy20a69342013-10-11 12:06:22 +02002526 if (skb == NULL)
2527 goto err;
2528
2529 err = nf_tables_fill_set(skb, ctx, set, event, 0);
2530 if (err < 0) {
2531 kfree_skb(skb);
2532 goto err;
2533 }
2534
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +02002535 err = nfnetlink_send(skb, ctx->net, portid, NFNLGRP_NFTABLES,
Pablo Neira Ayuso31f84412014-05-29 10:29:58 +02002536 ctx->report, gfp_flags);
Patrick McHardy20a69342013-10-11 12:06:22 +02002537err:
2538 if (err < 0)
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002539 nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, err);
Patrick McHardy20a69342013-10-11 12:06:22 +02002540 return err;
2541}
2542
Pablo Neira Ayuso5b96af72014-07-16 17:35:18 +02002543static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002544{
2545 const struct nft_set *set;
2546 unsigned int idx, s_idx = cb->args[0];
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02002547 struct nft_af_info *afi;
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002548 struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
2549 struct net *net = sock_net(skb->sk);
2550 int cur_family = cb->args[3];
Pablo Neira Ayuso5b96af72014-07-16 17:35:18 +02002551 struct nft_ctx *ctx = cb->data, ctx_set;
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002552
2553 if (cb->args[1])
2554 return skb->len;
2555
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02002556 rcu_read_lock();
Pablo Neira Ayuso38e029f2014-07-01 12:23:12 +02002557 cb->seq = net->nft.base_seq;
2558
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02002559 list_for_each_entry_rcu(afi, &net->nft.af_info, list) {
Pablo Neira Ayuso5b96af72014-07-16 17:35:18 +02002560 if (ctx->afi && ctx->afi != afi)
2561 continue;
2562
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002563 if (cur_family) {
2564 if (afi->family != cur_family)
2565 continue;
2566
2567 cur_family = 0;
2568 }
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02002569 list_for_each_entry_rcu(table, &afi->tables, list) {
Pablo Neira Ayuso5b96af72014-07-16 17:35:18 +02002570 if (ctx->table && ctx->table != table)
2571 continue;
2572
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002573 if (cur_table) {
2574 if (cur_table != table)
2575 continue;
2576
2577 cur_table = NULL;
2578 }
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002579 idx = 0;
Pablo Neira Ayuso5b96af72014-07-16 17:35:18 +02002580 list_for_each_entry_rcu(set, &table->sets, list) {
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002581 if (idx < s_idx)
2582 goto cont;
Pablo Neira Ayuso5b96af72014-07-16 17:35:18 +02002583
2584 ctx_set = *ctx;
2585 ctx_set.table = table;
2586 ctx_set.afi = afi;
2587 if (nf_tables_fill_set(skb, &ctx_set, set,
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002588 NFT_MSG_NEWSET,
2589 NLM_F_MULTI) < 0) {
2590 cb->args[0] = idx;
2591 cb->args[2] = (unsigned long) table;
2592 cb->args[3] = afi->family;
2593 goto done;
2594 }
Pablo Neira Ayuso38e029f2014-07-01 12:23:12 +02002595 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002596cont:
2597 idx++;
2598 }
2599 if (s_idx)
2600 s_idx = 0;
2601 }
2602 }
2603 cb->args[1] = 1;
2604done:
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02002605 rcu_read_unlock();
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002606 return skb->len;
2607}
2608
Pablo Neira Ayuso5b96af72014-07-16 17:35:18 +02002609static int nf_tables_dump_sets_done(struct netlink_callback *cb)
Patrick McHardy20a69342013-10-11 12:06:22 +02002610{
Pablo Neira Ayuso5b96af72014-07-16 17:35:18 +02002611 kfree(cb->data);
2612 return 0;
Patrick McHardy20a69342013-10-11 12:06:22 +02002613}
2614
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01002615static int nf_tables_getset(struct net *net, struct sock *nlsk,
2616 struct sk_buff *skb, const struct nlmsghdr *nlh,
Patrick McHardy20a69342013-10-11 12:06:22 +02002617 const struct nlattr * const nla[])
2618{
2619 const struct nft_set *set;
2620 struct nft_ctx ctx;
2621 struct sk_buff *skb2;
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002622 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Patrick McHardy20a69342013-10-11 12:06:22 +02002623 int err;
2624
stephen hemminger01cfa0a2014-10-29 22:57:19 -07002625 /* Verify existence before starting dump */
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01002626 err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002627 if (err < 0)
2628 return err;
2629
2630 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2631 struct netlink_dump_control c = {
2632 .dump = nf_tables_dump_sets,
Pablo Neira Ayuso5b96af72014-07-16 17:35:18 +02002633 .done = nf_tables_dump_sets_done,
Patrick McHardy20a69342013-10-11 12:06:22 +02002634 };
Pablo Neira Ayuso5b96af72014-07-16 17:35:18 +02002635 struct nft_ctx *ctx_dump;
2636
2637 ctx_dump = kmalloc(sizeof(*ctx_dump), GFP_KERNEL);
2638 if (ctx_dump == NULL)
2639 return -ENOMEM;
2640
2641 *ctx_dump = ctx;
2642 c.data = ctx_dump;
2643
Patrick McHardy20a69342013-10-11 12:06:22 +02002644 return netlink_dump_start(nlsk, skb, nlh, &c);
2645 }
2646
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002647 /* Only accept unspec with dump */
2648 if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
2649 return -EAFNOSUPPORT;
Phil Turnbulleaa2bcd2016-05-27 13:34:04 -04002650 if (!nla[NFTA_SET_TABLE])
2651 return -EINVAL;
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002652
Patrick McHardy20a69342013-10-11 12:06:22 +02002653 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
2654 if (IS_ERR(set))
2655 return PTR_ERR(set);
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002656 if (set->flags & NFT_SET_INACTIVE)
2657 return -ENOENT;
Patrick McHardy20a69342013-10-11 12:06:22 +02002658
2659 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2660 if (skb2 == NULL)
2661 return -ENOMEM;
2662
2663 err = nf_tables_fill_set(skb2, &ctx, set, NFT_MSG_NEWSET, 0);
2664 if (err < 0)
2665 goto err;
2666
2667 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
2668
2669err:
2670 kfree_skb(skb2);
2671 return err;
2672}
2673
Patrick McHardyc50b9602014-03-28 10:19:47 +00002674static int nf_tables_set_desc_parse(const struct nft_ctx *ctx,
2675 struct nft_set_desc *desc,
2676 const struct nlattr *nla)
2677{
2678 struct nlattr *da[NFTA_SET_DESC_MAX + 1];
2679 int err;
2680
2681 err = nla_parse_nested(da, NFTA_SET_DESC_MAX, nla, nft_set_desc_policy);
2682 if (err < 0)
2683 return err;
2684
2685 if (da[NFTA_SET_DESC_SIZE] != NULL)
2686 desc->size = ntohl(nla_get_be32(da[NFTA_SET_DESC_SIZE]));
2687
2688 return 0;
2689}
2690
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01002691static int nf_tables_newset(struct net *net, struct sock *nlsk,
2692 struct sk_buff *skb, const struct nlmsghdr *nlh,
Patrick McHardy20a69342013-10-11 12:06:22 +02002693 const struct nlattr * const nla[])
2694{
2695 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
2696 const struct nft_set_ops *ops;
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02002697 struct nft_af_info *afi;
Patrick McHardy20a69342013-10-11 12:06:22 +02002698 struct nft_table *table;
2699 struct nft_set *set;
2700 struct nft_ctx ctx;
Pablo Neira Ayusocb39ad82016-05-04 17:49:53 +02002701 char name[NFT_SET_MAXNAMELEN];
Patrick McHardy20a69342013-10-11 12:06:22 +02002702 unsigned int size;
2703 bool create;
Patrick McHardy761da292015-03-26 12:39:36 +00002704 u64 timeout;
2705 u32 ktype, dtype, flags, policy, gc_int;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002706 struct nft_set_desc desc;
Carlos Falgueras Garcíae6d8eca2016-01-05 14:03:32 +01002707 unsigned char *udata;
2708 u16 udlen;
Patrick McHardy20a69342013-10-11 12:06:22 +02002709 int err;
2710
2711 if (nla[NFTA_SET_TABLE] == NULL ||
2712 nla[NFTA_SET_NAME] == NULL ||
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002713 nla[NFTA_SET_KEY_LEN] == NULL ||
2714 nla[NFTA_SET_ID] == NULL)
Patrick McHardy20a69342013-10-11 12:06:22 +02002715 return -EINVAL;
2716
Patrick McHardyc50b9602014-03-28 10:19:47 +00002717 memset(&desc, 0, sizeof(desc));
2718
Patrick McHardy20a69342013-10-11 12:06:22 +02002719 ktype = NFT_DATA_VALUE;
2720 if (nla[NFTA_SET_KEY_TYPE] != NULL) {
2721 ktype = ntohl(nla_get_be32(nla[NFTA_SET_KEY_TYPE]));
2722 if ((ktype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK)
2723 return -EINVAL;
2724 }
2725
Patrick McHardyc50b9602014-03-28 10:19:47 +00002726 desc.klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
Patrick McHardy7d740262015-04-11 02:27:39 +01002727 if (desc.klen == 0 || desc.klen > NFT_DATA_VALUE_MAXLEN)
Patrick McHardy20a69342013-10-11 12:06:22 +02002728 return -EINVAL;
2729
2730 flags = 0;
2731 if (nla[NFTA_SET_FLAGS] != NULL) {
2732 flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
2733 if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
Patrick McHardy7c6c6e92015-04-11 10:46:41 +01002734 NFT_SET_INTERVAL | NFT_SET_TIMEOUT |
2735 NFT_SET_MAP | NFT_SET_EVAL))
Patrick McHardy20a69342013-10-11 12:06:22 +02002736 return -EINVAL;
Patrick McHardy7c6c6e92015-04-11 10:46:41 +01002737 /* Only one of both operations is supported */
2738 if ((flags & (NFT_SET_MAP | NFT_SET_EVAL)) ==
2739 (NFT_SET_MAP | NFT_SET_EVAL))
2740 return -EOPNOTSUPP;
Patrick McHardy20a69342013-10-11 12:06:22 +02002741 }
2742
2743 dtype = 0;
Patrick McHardy20a69342013-10-11 12:06:22 +02002744 if (nla[NFTA_SET_DATA_TYPE] != NULL) {
2745 if (!(flags & NFT_SET_MAP))
2746 return -EINVAL;
2747
2748 dtype = ntohl(nla_get_be32(nla[NFTA_SET_DATA_TYPE]));
2749 if ((dtype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK &&
2750 dtype != NFT_DATA_VERDICT)
2751 return -EINVAL;
2752
2753 if (dtype != NFT_DATA_VERDICT) {
2754 if (nla[NFTA_SET_DATA_LEN] == NULL)
2755 return -EINVAL;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002756 desc.dlen = ntohl(nla_get_be32(nla[NFTA_SET_DATA_LEN]));
Patrick McHardy7d740262015-04-11 02:27:39 +01002757 if (desc.dlen == 0 || desc.dlen > NFT_DATA_VALUE_MAXLEN)
Patrick McHardy20a69342013-10-11 12:06:22 +02002758 return -EINVAL;
2759 } else
Patrick McHardy7d740262015-04-11 02:27:39 +01002760 desc.dlen = sizeof(struct nft_verdict);
Patrick McHardy20a69342013-10-11 12:06:22 +02002761 } else if (flags & NFT_SET_MAP)
2762 return -EINVAL;
2763
Patrick McHardy761da292015-03-26 12:39:36 +00002764 timeout = 0;
2765 if (nla[NFTA_SET_TIMEOUT] != NULL) {
2766 if (!(flags & NFT_SET_TIMEOUT))
2767 return -EINVAL;
2768 timeout = be64_to_cpu(nla_get_be64(nla[NFTA_SET_TIMEOUT]));
2769 }
2770 gc_int = 0;
2771 if (nla[NFTA_SET_GC_INTERVAL] != NULL) {
2772 if (!(flags & NFT_SET_TIMEOUT))
2773 return -EINVAL;
2774 gc_int = ntohl(nla_get_be32(nla[NFTA_SET_GC_INTERVAL]));
2775 }
2776
Patrick McHardyc50b9602014-03-28 10:19:47 +00002777 policy = NFT_SET_POL_PERFORMANCE;
2778 if (nla[NFTA_SET_POLICY] != NULL)
2779 policy = ntohl(nla_get_be32(nla[NFTA_SET_POLICY]));
2780
2781 if (nla[NFTA_SET_DESC] != NULL) {
2782 err = nf_tables_set_desc_parse(&ctx, &desc, nla[NFTA_SET_DESC]);
2783 if (err < 0)
2784 return err;
2785 }
2786
Patrick McHardy20a69342013-10-11 12:06:22 +02002787 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
2788
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002789 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
Patrick McHardy20a69342013-10-11 12:06:22 +02002790 if (IS_ERR(afi))
2791 return PTR_ERR(afi);
2792
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002793 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02002794 if (IS_ERR(table))
2795 return PTR_ERR(table);
2796
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01002797 nft_ctx_init(&ctx, net, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002798
2799 set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME]);
2800 if (IS_ERR(set)) {
2801 if (PTR_ERR(set) != -ENOENT)
2802 return PTR_ERR(set);
2803 set = NULL;
2804 }
2805
2806 if (set != NULL) {
2807 if (nlh->nlmsg_flags & NLM_F_EXCL)
2808 return -EEXIST;
2809 if (nlh->nlmsg_flags & NLM_F_REPLACE)
2810 return -EOPNOTSUPP;
2811 return 0;
2812 }
2813
2814 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
2815 return -ENOENT;
2816
Patrick McHardyc50b9602014-03-28 10:19:47 +00002817 ops = nft_select_set_ops(nla, &desc, policy);
Patrick McHardy20a69342013-10-11 12:06:22 +02002818 if (IS_ERR(ops))
2819 return PTR_ERR(ops);
2820
Carlos Falgueras Garcíae6d8eca2016-01-05 14:03:32 +01002821 udlen = 0;
2822 if (nla[NFTA_SET_USERDATA])
2823 udlen = nla_len(nla[NFTA_SET_USERDATA]);
2824
Patrick McHardy20a69342013-10-11 12:06:22 +02002825 size = 0;
2826 if (ops->privsize != NULL)
2827 size = ops->privsize(nla);
2828
2829 err = -ENOMEM;
Carlos Falgueras Garcíae6d8eca2016-01-05 14:03:32 +01002830 set = kzalloc(sizeof(*set) + size + udlen, GFP_KERNEL);
Patrick McHardy20a69342013-10-11 12:06:22 +02002831 if (set == NULL)
2832 goto err1;
2833
2834 nla_strlcpy(name, nla[NFTA_SET_NAME], sizeof(set->name));
2835 err = nf_tables_set_alloc_name(&ctx, set, name);
2836 if (err < 0)
2837 goto err2;
2838
Carlos Falgueras Garcíae6d8eca2016-01-05 14:03:32 +01002839 udata = NULL;
2840 if (udlen) {
2841 udata = set->data + size;
2842 nla_memcpy(udata, nla[NFTA_SET_USERDATA], udlen);
2843 }
2844
Patrick McHardy20a69342013-10-11 12:06:22 +02002845 INIT_LIST_HEAD(&set->bindings);
Patrick McHardycc02e452015-03-25 14:08:50 +00002846 write_pnet(&set->pnet, net);
Patrick McHardy20a69342013-10-11 12:06:22 +02002847 set->ops = ops;
2848 set->ktype = ktype;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002849 set->klen = desc.klen;
Patrick McHardy20a69342013-10-11 12:06:22 +02002850 set->dtype = dtype;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002851 set->dlen = desc.dlen;
Patrick McHardy20a69342013-10-11 12:06:22 +02002852 set->flags = flags;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002853 set->size = desc.size;
Arturo Borrero9363dc42014-09-23 13:30:41 +02002854 set->policy = policy;
Carlos Falgueras Garcíae6d8eca2016-01-05 14:03:32 +01002855 set->udlen = udlen;
2856 set->udata = udata;
Patrick McHardy761da292015-03-26 12:39:36 +00002857 set->timeout = timeout;
2858 set->gc_int = gc_int;
Patrick McHardy20a69342013-10-11 12:06:22 +02002859
Patrick McHardyc50b9602014-03-28 10:19:47 +00002860 err = ops->init(set, &desc, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002861 if (err < 0)
2862 goto err2;
2863
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002864 err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set);
Patrick McHardy20a69342013-10-11 12:06:22 +02002865 if (err < 0)
2866 goto err2;
2867
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02002868 list_add_tail_rcu(&set->list, &table->sets);
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +02002869 table->use++;
Patrick McHardy20a69342013-10-11 12:06:22 +02002870 return 0;
2871
2872err2:
2873 kfree(set);
2874err1:
2875 module_put(ops->owner);
2876 return err;
2877}
2878
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002879static void nft_set_destroy(struct nft_set *set)
2880{
2881 set->ops->destroy(set);
2882 module_put(set->ops->owner);
2883 kfree(set);
2884}
2885
Patrick McHardy20a69342013-10-11 12:06:22 +02002886static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
2887{
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02002888 list_del_rcu(&set->list);
Pablo Neira Ayuso31f84412014-05-29 10:29:58 +02002889 nf_tables_set_notify(ctx, set, NFT_MSG_DELSET, GFP_ATOMIC);
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002890 nft_set_destroy(set);
Patrick McHardy20a69342013-10-11 12:06:22 +02002891}
2892
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01002893static int nf_tables_delset(struct net *net, struct sock *nlsk,
2894 struct sk_buff *skb, const struct nlmsghdr *nlh,
Patrick McHardy20a69342013-10-11 12:06:22 +02002895 const struct nlattr * const nla[])
2896{
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002897 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Patrick McHardy20a69342013-10-11 12:06:22 +02002898 struct nft_set *set;
2899 struct nft_ctx ctx;
2900 int err;
2901
Patrick McHardyec2c9932014-02-05 15:03:35 +00002902 if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
2903 return -EAFNOSUPPORT;
Patrick McHardy20a69342013-10-11 12:06:22 +02002904 if (nla[NFTA_SET_TABLE] == NULL)
2905 return -EINVAL;
2906
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01002907 err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002908 if (err < 0)
2909 return err;
2910
2911 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
2912 if (IS_ERR(set))
2913 return PTR_ERR(set);
2914 if (!list_empty(&set->bindings))
2915 return -EBUSY;
2916
Arturo Borreroee01d542014-09-02 16:42:25 +02002917 return nft_delset(&ctx, set);
Patrick McHardy20a69342013-10-11 12:06:22 +02002918}
2919
2920static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
2921 const struct nft_set *set,
2922 const struct nft_set_iter *iter,
2923 const struct nft_set_elem *elem)
2924{
Patrick McHardyfe2811e2015-03-25 13:07:50 +00002925 const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
Patrick McHardy20a69342013-10-11 12:06:22 +02002926 enum nft_registers dreg;
2927
2928 dreg = nft_type_to_reg(set->dtype);
Patrick McHardy1ec10212015-04-11 02:27:27 +01002929 return nft_validate_register_store(ctx, dreg, nft_set_ext_data(ext),
2930 set->dtype == NFT_DATA_VERDICT ?
2931 NFT_DATA_VERDICT : NFT_DATA_VALUE,
2932 set->dlen);
Patrick McHardy20a69342013-10-11 12:06:22 +02002933}
2934
2935int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
2936 struct nft_set_binding *binding)
2937{
2938 struct nft_set_binding *i;
2939 struct nft_set_iter iter;
2940
2941 if (!list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
2942 return -EBUSY;
2943
Patrick McHardy11113e12015-04-05 14:41:07 +02002944 if (binding->flags & NFT_SET_MAP) {
Patrick McHardy20a69342013-10-11 12:06:22 +02002945 /* If the set is already bound to the same chain all
2946 * jumps are already validated for that chain.
2947 */
2948 list_for_each_entry(i, &set->bindings, list) {
Liping Zhanga4684402016-06-11 12:20:26 +08002949 if (i->flags & NFT_SET_MAP &&
Patrick McHardy11113e12015-04-05 14:41:07 +02002950 i->chain == binding->chain)
Patrick McHardy20a69342013-10-11 12:06:22 +02002951 goto bind;
2952 }
2953
Pablo Neira Ayuso8588ac02016-06-11 12:20:27 +08002954 iter.genmask = nft_genmask_next(ctx->net);
Patrick McHardy20a69342013-10-11 12:06:22 +02002955 iter.skip = 0;
2956 iter.count = 0;
2957 iter.err = 0;
2958 iter.fn = nf_tables_bind_check_setelem;
2959
2960 set->ops->walk(ctx, set, &iter);
2961 if (iter.err < 0) {
2962 /* Destroy anonymous sets if binding fails */
2963 if (set->flags & NFT_SET_ANONYMOUS)
2964 nf_tables_set_destroy(ctx, set);
2965
2966 return iter.err;
2967 }
2968 }
2969bind:
2970 binding->chain = ctx->chain;
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02002971 list_add_tail_rcu(&binding->list, &set->bindings);
Patrick McHardy20a69342013-10-11 12:06:22 +02002972 return 0;
2973}
2974
2975void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
2976 struct nft_set_binding *binding)
2977{
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02002978 list_del_rcu(&binding->list);
Patrick McHardy20a69342013-10-11 12:06:22 +02002979
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002980 if (list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS &&
2981 !(set->flags & NFT_SET_INACTIVE))
Patrick McHardy20a69342013-10-11 12:06:22 +02002982 nf_tables_set_destroy(ctx, set);
2983}
2984
Patrick McHardy3ac4c072015-03-25 13:07:49 +00002985const struct nft_set_ext_type nft_set_ext_types[] = {
2986 [NFT_SET_EXT_KEY] = {
Patrick McHardy7d740262015-04-11 02:27:39 +01002987 .align = __alignof__(u32),
Patrick McHardy3ac4c072015-03-25 13:07:49 +00002988 },
2989 [NFT_SET_EXT_DATA] = {
Patrick McHardy7d740262015-04-11 02:27:39 +01002990 .align = __alignof__(u32),
Patrick McHardy3ac4c072015-03-25 13:07:49 +00002991 },
Patrick McHardyf25ad2e2015-04-11 10:46:39 +01002992 [NFT_SET_EXT_EXPR] = {
2993 .align = __alignof__(struct nft_expr),
2994 },
Patrick McHardy3ac4c072015-03-25 13:07:49 +00002995 [NFT_SET_EXT_FLAGS] = {
2996 .len = sizeof(u8),
2997 .align = __alignof__(u8),
2998 },
Patrick McHardyc3e1b002015-03-26 12:39:37 +00002999 [NFT_SET_EXT_TIMEOUT] = {
3000 .len = sizeof(u64),
3001 .align = __alignof__(u64),
3002 },
3003 [NFT_SET_EXT_EXPIRATION] = {
3004 .len = sizeof(unsigned long),
3005 .align = __alignof__(unsigned long),
3006 },
Patrick McHardy68e942e2015-04-05 14:43:38 +02003007 [NFT_SET_EXT_USERDATA] = {
3008 .len = sizeof(struct nft_userdata),
3009 .align = __alignof__(struct nft_userdata),
3010 },
Patrick McHardy3ac4c072015-03-25 13:07:49 +00003011};
3012EXPORT_SYMBOL_GPL(nft_set_ext_types);
3013
Patrick McHardy20a69342013-10-11 12:06:22 +02003014/*
3015 * Set elements
3016 */
3017
3018static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
3019 [NFTA_SET_ELEM_KEY] = { .type = NLA_NESTED },
3020 [NFTA_SET_ELEM_DATA] = { .type = NLA_NESTED },
3021 [NFTA_SET_ELEM_FLAGS] = { .type = NLA_U32 },
Patrick McHardyc3e1b002015-03-26 12:39:37 +00003022 [NFTA_SET_ELEM_TIMEOUT] = { .type = NLA_U64 },
Patrick McHardy68e942e2015-04-05 14:43:38 +02003023 [NFTA_SET_ELEM_USERDATA] = { .type = NLA_BINARY,
3024 .len = NFT_USERDATA_MAXLEN },
Patrick McHardy20a69342013-10-11 12:06:22 +02003025};
3026
3027static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
3028 [NFTA_SET_ELEM_LIST_TABLE] = { .type = NLA_STRING },
3029 [NFTA_SET_ELEM_LIST_SET] = { .type = NLA_STRING },
3030 [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NLA_NESTED },
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003031 [NFTA_SET_ELEM_LIST_SET_ID] = { .type = NLA_U32 },
Patrick McHardy20a69342013-10-11 12:06:22 +02003032};
3033
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01003034static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, struct net *net,
Patrick McHardy20a69342013-10-11 12:06:22 +02003035 const struct sk_buff *skb,
3036 const struct nlmsghdr *nlh,
Pablo Neira Ayusof4c756b2015-12-15 19:40:50 +01003037 const struct nlattr * const nla[])
Patrick McHardy20a69342013-10-11 12:06:22 +02003038{
3039 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02003040 struct nft_af_info *afi;
3041 struct nft_table *table;
Patrick McHardy20a69342013-10-11 12:06:22 +02003042
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003043 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
Patrick McHardy20a69342013-10-11 12:06:22 +02003044 if (IS_ERR(afi))
3045 return PTR_ERR(afi);
3046
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02003047 table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02003048 if (IS_ERR(table))
3049 return PTR_ERR(table);
3050
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01003051 nft_ctx_init(ctx, net, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02003052 return 0;
3053}
3054
3055static int nf_tables_fill_setelem(struct sk_buff *skb,
3056 const struct nft_set *set,
3057 const struct nft_set_elem *elem)
3058{
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003059 const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
Patrick McHardy20a69342013-10-11 12:06:22 +02003060 unsigned char *b = skb_tail_pointer(skb);
3061 struct nlattr *nest;
3062
3063 nest = nla_nest_start(skb, NFTA_LIST_ELEM);
3064 if (nest == NULL)
3065 goto nla_put_failure;
3066
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003067 if (nft_data_dump(skb, NFTA_SET_ELEM_KEY, nft_set_ext_key(ext),
3068 NFT_DATA_VALUE, set->klen) < 0)
Patrick McHardy20a69342013-10-11 12:06:22 +02003069 goto nla_put_failure;
3070
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003071 if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) &&
3072 nft_data_dump(skb, NFTA_SET_ELEM_DATA, nft_set_ext_data(ext),
Patrick McHardy20a69342013-10-11 12:06:22 +02003073 set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE,
3074 set->dlen) < 0)
3075 goto nla_put_failure;
3076
Patrick McHardyf25ad2e2015-04-11 10:46:39 +01003077 if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPR) &&
3078 nft_expr_dump(skb, NFTA_SET_ELEM_EXPR, nft_set_ext_expr(ext)) < 0)
3079 goto nla_put_failure;
3080
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003081 if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
3082 nla_put_be32(skb, NFTA_SET_ELEM_FLAGS,
3083 htonl(*nft_set_ext_flags(ext))))
3084 goto nla_put_failure;
Patrick McHardy20a69342013-10-11 12:06:22 +02003085
Patrick McHardyc3e1b002015-03-26 12:39:37 +00003086 if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) &&
3087 nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT,
Nicolas Dichtelb46f6de2016-04-22 17:31:18 +02003088 cpu_to_be64(*nft_set_ext_timeout(ext)),
3089 NFTA_SET_ELEM_PAD))
Patrick McHardyc3e1b002015-03-26 12:39:37 +00003090 goto nla_put_failure;
3091
3092 if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
3093 unsigned long expires, now = jiffies;
3094
3095 expires = *nft_set_ext_expiration(ext);
3096 if (time_before(now, expires))
3097 expires -= now;
3098 else
3099 expires = 0;
3100
3101 if (nla_put_be64(skb, NFTA_SET_ELEM_EXPIRATION,
Nicolas Dichtelb46f6de2016-04-22 17:31:18 +02003102 cpu_to_be64(jiffies_to_msecs(expires)),
3103 NFTA_SET_ELEM_PAD))
Patrick McHardyc3e1b002015-03-26 12:39:37 +00003104 goto nla_put_failure;
3105 }
3106
Patrick McHardy68e942e2015-04-05 14:43:38 +02003107 if (nft_set_ext_exists(ext, NFT_SET_EXT_USERDATA)) {
3108 struct nft_userdata *udata;
3109
3110 udata = nft_set_ext_userdata(ext);
3111 if (nla_put(skb, NFTA_SET_ELEM_USERDATA,
3112 udata->len + 1, udata->data))
3113 goto nla_put_failure;
3114 }
3115
Patrick McHardy20a69342013-10-11 12:06:22 +02003116 nla_nest_end(skb, nest);
3117 return 0;
3118
3119nla_put_failure:
3120 nlmsg_trim(skb, b);
3121 return -EMSGSIZE;
3122}
3123
3124struct nft_set_dump_args {
3125 const struct netlink_callback *cb;
3126 struct nft_set_iter iter;
3127 struct sk_buff *skb;
3128};
3129
3130static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
3131 const struct nft_set *set,
3132 const struct nft_set_iter *iter,
3133 const struct nft_set_elem *elem)
3134{
3135 struct nft_set_dump_args *args;
3136
3137 args = container_of(iter, struct nft_set_dump_args, iter);
3138 return nf_tables_fill_setelem(args->skb, set, elem);
3139}
3140
3141static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
3142{
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01003143 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02003144 const struct nft_set *set;
3145 struct nft_set_dump_args args;
3146 struct nft_ctx ctx;
3147 struct nlattr *nla[NFTA_SET_ELEM_LIST_MAX + 1];
3148 struct nfgenmsg *nfmsg;
3149 struct nlmsghdr *nlh;
3150 struct nlattr *nest;
3151 u32 portid, seq;
3152 int event, err;
3153
Michal Nazarewicz720e0df2014-01-01 06:27:19 +01003154 err = nlmsg_parse(cb->nlh, sizeof(struct nfgenmsg), nla,
3155 NFTA_SET_ELEM_LIST_MAX, nft_set_elem_list_policy);
Patrick McHardy20a69342013-10-11 12:06:22 +02003156 if (err < 0)
3157 return err;
3158
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01003159 err = nft_ctx_init_from_elemattr(&ctx, net, cb->skb, cb->nlh,
Pablo Neira Ayusof4c756b2015-12-15 19:40:50 +01003160 (void *)nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02003161 if (err < 0)
3162 return err;
Pablo Neira Ayusof4c756b2015-12-15 19:40:50 +01003163 if (ctx.table->flags & NFT_TABLE_INACTIVE)
3164 return -ENOENT;
Patrick McHardy20a69342013-10-11 12:06:22 +02003165
3166 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
3167 if (IS_ERR(set))
3168 return PTR_ERR(set);
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003169 if (set->flags & NFT_SET_INACTIVE)
3170 return -ENOENT;
Patrick McHardy20a69342013-10-11 12:06:22 +02003171
3172 event = NFT_MSG_NEWSETELEM;
3173 event |= NFNL_SUBSYS_NFTABLES << 8;
3174 portid = NETLINK_CB(cb->skb).portid;
3175 seq = cb->nlh->nlmsg_seq;
3176
3177 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
3178 NLM_F_MULTI);
3179 if (nlh == NULL)
3180 goto nla_put_failure;
3181
3182 nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso6403d962014-06-11 19:05:28 +02003183 nfmsg->nfgen_family = ctx.afi->family;
Patrick McHardy20a69342013-10-11 12:06:22 +02003184 nfmsg->version = NFNETLINK_V0;
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02003185 nfmsg->res_id = htons(ctx.net->nft.base_seq & 0xffff);
Patrick McHardy20a69342013-10-11 12:06:22 +02003186
3187 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, ctx.table->name))
3188 goto nla_put_failure;
3189 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_SET, set->name))
3190 goto nla_put_failure;
3191
3192 nest = nla_nest_start(skb, NFTA_SET_ELEM_LIST_ELEMENTS);
3193 if (nest == NULL)
3194 goto nla_put_failure;
3195
Pablo Neira Ayuso8588ac02016-06-11 12:20:27 +08003196 args.cb = cb;
3197 args.skb = skb;
3198 args.iter.genmask = nft_genmask_cur(ctx.net);
3199 args.iter.skip = cb->args[0];
3200 args.iter.count = 0;
3201 args.iter.err = 0;
3202 args.iter.fn = nf_tables_dump_setelem;
Patrick McHardy20a69342013-10-11 12:06:22 +02003203 set->ops->walk(&ctx, set, &args.iter);
3204
3205 nla_nest_end(skb, nest);
3206 nlmsg_end(skb, nlh);
3207
3208 if (args.iter.err && args.iter.err != -EMSGSIZE)
3209 return args.iter.err;
3210 if (args.iter.count == cb->args[0])
3211 return 0;
3212
3213 cb->args[0] = args.iter.count;
3214 return skb->len;
3215
3216nla_put_failure:
3217 return -ENOSPC;
3218}
3219
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01003220static int nf_tables_getsetelem(struct net *net, struct sock *nlsk,
3221 struct sk_buff *skb, const struct nlmsghdr *nlh,
Patrick McHardy20a69342013-10-11 12:06:22 +02003222 const struct nlattr * const nla[])
3223{
3224 const struct nft_set *set;
3225 struct nft_ctx ctx;
3226 int err;
3227
Pablo Neira Ayusof4c756b2015-12-15 19:40:50 +01003228 err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02003229 if (err < 0)
3230 return err;
Pablo Neira Ayusof4c756b2015-12-15 19:40:50 +01003231 if (ctx.table->flags & NFT_TABLE_INACTIVE)
3232 return -ENOENT;
Patrick McHardy20a69342013-10-11 12:06:22 +02003233
3234 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
3235 if (IS_ERR(set))
3236 return PTR_ERR(set);
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003237 if (set->flags & NFT_SET_INACTIVE)
3238 return -ENOENT;
Patrick McHardy20a69342013-10-11 12:06:22 +02003239
3240 if (nlh->nlmsg_flags & NLM_F_DUMP) {
3241 struct netlink_dump_control c = {
3242 .dump = nf_tables_dump_set,
3243 };
3244 return netlink_dump_start(nlsk, skb, nlh, &c);
3245 }
3246 return -EOPNOTSUPP;
3247}
3248
Arturo Borrerod60ce622014-04-01 14:06:07 +02003249static int nf_tables_fill_setelem_info(struct sk_buff *skb,
3250 const struct nft_ctx *ctx, u32 seq,
3251 u32 portid, int event, u16 flags,
3252 const struct nft_set *set,
3253 const struct nft_set_elem *elem)
3254{
3255 struct nfgenmsg *nfmsg;
3256 struct nlmsghdr *nlh;
3257 struct nlattr *nest;
3258 int err;
3259
3260 event |= NFNL_SUBSYS_NFTABLES << 8;
3261 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
3262 flags);
3263 if (nlh == NULL)
3264 goto nla_put_failure;
3265
3266 nfmsg = nlmsg_data(nlh);
3267 nfmsg->nfgen_family = ctx->afi->family;
3268 nfmsg->version = NFNETLINK_V0;
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02003269 nfmsg->res_id = htons(ctx->net->nft.base_seq & 0xffff);
Arturo Borrerod60ce622014-04-01 14:06:07 +02003270
3271 if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
3272 goto nla_put_failure;
3273 if (nla_put_string(skb, NFTA_SET_NAME, set->name))
3274 goto nla_put_failure;
3275
3276 nest = nla_nest_start(skb, NFTA_SET_ELEM_LIST_ELEMENTS);
3277 if (nest == NULL)
3278 goto nla_put_failure;
3279
3280 err = nf_tables_fill_setelem(skb, set, elem);
3281 if (err < 0)
3282 goto nla_put_failure;
3283
3284 nla_nest_end(skb, nest);
3285
Johannes Berg053c0952015-01-16 22:09:00 +01003286 nlmsg_end(skb, nlh);
3287 return 0;
Arturo Borrerod60ce622014-04-01 14:06:07 +02003288
3289nla_put_failure:
3290 nlmsg_trim(skb, nlh);
3291 return -1;
3292}
3293
3294static int nf_tables_setelem_notify(const struct nft_ctx *ctx,
3295 const struct nft_set *set,
3296 const struct nft_set_elem *elem,
3297 int event, u16 flags)
3298{
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +02003299 struct net *net = ctx->net;
3300 u32 portid = ctx->portid;
Arturo Borrerod60ce622014-04-01 14:06:07 +02003301 struct sk_buff *skb;
3302 int err;
3303
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +02003304 if (!ctx->report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
Arturo Borrerod60ce622014-04-01 14:06:07 +02003305 return 0;
3306
3307 err = -ENOBUFS;
3308 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
3309 if (skb == NULL)
3310 goto err;
3311
3312 err = nf_tables_fill_setelem_info(skb, ctx, 0, portid, event, flags,
3313 set, elem);
3314 if (err < 0) {
3315 kfree_skb(skb);
3316 goto err;
3317 }
3318
Pablo Neira Ayuso128ad332014-05-09 17:14:24 +02003319 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, ctx->report,
Arturo Borrerod60ce622014-04-01 14:06:07 +02003320 GFP_KERNEL);
3321err:
3322 if (err < 0)
3323 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
3324 return err;
3325}
3326
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02003327static struct nft_trans *nft_trans_elem_alloc(struct nft_ctx *ctx,
3328 int msg_type,
3329 struct nft_set *set)
3330{
3331 struct nft_trans *trans;
3332
3333 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_elem));
3334 if (trans == NULL)
3335 return NULL;
3336
3337 nft_trans_elem_set(trans) = set;
3338 return trans;
3339}
3340
Patrick McHardy22fe54d2015-04-05 14:41:08 +02003341void *nft_set_elem_init(const struct nft_set *set,
3342 const struct nft_set_ext_tmpl *tmpl,
Patrick McHardy49499c32015-04-11 02:27:37 +01003343 const u32 *key, const u32 *data,
Patrick McHardy22fe54d2015-04-05 14:41:08 +02003344 u64 timeout, gfp_t gfp)
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003345{
3346 struct nft_set_ext *ext;
3347 void *elem;
3348
3349 elem = kzalloc(set->ops->elemsize + tmpl->len, gfp);
3350 if (elem == NULL)
3351 return NULL;
3352
3353 ext = nft_set_elem_ext(set, elem);
3354 nft_set_ext_init(ext, tmpl);
3355
3356 memcpy(nft_set_ext_key(ext), key, set->klen);
3357 if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
3358 memcpy(nft_set_ext_data(ext), data, set->dlen);
Patrick McHardyc3e1b002015-03-26 12:39:37 +00003359 if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION))
3360 *nft_set_ext_expiration(ext) =
3361 jiffies + msecs_to_jiffies(timeout);
3362 if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT))
3363 *nft_set_ext_timeout(ext) = timeout;
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003364
3365 return elem;
3366}
3367
Patrick McHardy61edafb2015-03-25 14:08:47 +00003368void nft_set_elem_destroy(const struct nft_set *set, void *elem)
3369{
3370 struct nft_set_ext *ext = nft_set_elem_ext(set, elem);
3371
3372 nft_data_uninit(nft_set_ext_key(ext), NFT_DATA_VALUE);
3373 if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
3374 nft_data_uninit(nft_set_ext_data(ext), set->dtype);
Patrick McHardyf25ad2e2015-04-11 10:46:39 +01003375 if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPR))
3376 nf_tables_expr_destroy(NULL, nft_set_ext_expr(ext));
Patrick McHardy61edafb2015-03-25 14:08:47 +00003377
3378 kfree(elem);
3379}
3380EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
3381
Pablo Neira Ayuso0e9091d2016-04-12 23:50:34 +02003382static int nft_setelem_parse_flags(const struct nft_set *set,
3383 const struct nlattr *attr, u32 *flags)
3384{
3385 if (attr == NULL)
3386 return 0;
3387
3388 *flags = ntohl(nla_get_be32(attr));
3389 if (*flags & ~NFT_SET_ELEM_INTERVAL_END)
3390 return -EINVAL;
3391 if (!(set->flags & NFT_SET_INTERVAL) &&
3392 *flags & NFT_SET_ELEM_INTERVAL_END)
3393 return -EINVAL;
3394
3395 return 0;
3396}
3397
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02003398static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
Patrick McHardy20a69342013-10-11 12:06:22 +02003399 const struct nlattr *attr)
3400{
3401 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
3402 struct nft_data_desc d1, d2;
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003403 struct nft_set_ext_tmpl tmpl;
3404 struct nft_set_ext *ext;
Patrick McHardy20a69342013-10-11 12:06:22 +02003405 struct nft_set_elem elem;
3406 struct nft_set_binding *binding;
Patrick McHardy68e942e2015-04-05 14:43:38 +02003407 struct nft_userdata *udata;
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003408 struct nft_data data;
Patrick McHardy20a69342013-10-11 12:06:22 +02003409 enum nft_registers dreg;
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02003410 struct nft_trans *trans;
Pablo Neira Ayuso0e9091d2016-04-12 23:50:34 +02003411 u32 flags = 0;
Patrick McHardyc3e1b002015-03-26 12:39:37 +00003412 u64 timeout;
Patrick McHardy68e942e2015-04-05 14:43:38 +02003413 u8 ulen;
Patrick McHardy20a69342013-10-11 12:06:22 +02003414 int err;
3415
3416 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
3417 nft_set_elem_policy);
3418 if (err < 0)
3419 return err;
3420
3421 if (nla[NFTA_SET_ELEM_KEY] == NULL)
3422 return -EINVAL;
3423
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003424 nft_set_ext_prepare(&tmpl);
3425
Pablo Neira Ayuso0e9091d2016-04-12 23:50:34 +02003426 err = nft_setelem_parse_flags(set, nla[NFTA_SET_ELEM_FLAGS], &flags);
3427 if (err < 0)
3428 return err;
3429 if (flags != 0)
3430 nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
Patrick McHardy20a69342013-10-11 12:06:22 +02003431
3432 if (set->flags & NFT_SET_MAP) {
3433 if (nla[NFTA_SET_ELEM_DATA] == NULL &&
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003434 !(flags & NFT_SET_ELEM_INTERVAL_END))
Patrick McHardy20a69342013-10-11 12:06:22 +02003435 return -EINVAL;
Pablo Neira Ayusobd7fc642014-02-07 12:53:07 +01003436 if (nla[NFTA_SET_ELEM_DATA] != NULL &&
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003437 flags & NFT_SET_ELEM_INTERVAL_END)
Pablo Neira Ayusobd7fc642014-02-07 12:53:07 +01003438 return -EINVAL;
Patrick McHardy20a69342013-10-11 12:06:22 +02003439 } else {
3440 if (nla[NFTA_SET_ELEM_DATA] != NULL)
3441 return -EINVAL;
3442 }
3443
Patrick McHardyc3e1b002015-03-26 12:39:37 +00003444 timeout = 0;
3445 if (nla[NFTA_SET_ELEM_TIMEOUT] != NULL) {
3446 if (!(set->flags & NFT_SET_TIMEOUT))
3447 return -EINVAL;
3448 timeout = be64_to_cpu(nla_get_be64(nla[NFTA_SET_ELEM_TIMEOUT]));
3449 } else if (set->flags & NFT_SET_TIMEOUT) {
3450 timeout = set->timeout;
3451 }
3452
Patrick McHardy7d740262015-04-11 02:27:39 +01003453 err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &d1,
Patrick McHardyd0a11fc2015-04-11 02:27:38 +01003454 nla[NFTA_SET_ELEM_KEY]);
Patrick McHardy20a69342013-10-11 12:06:22 +02003455 if (err < 0)
3456 goto err1;
3457 err = -EINVAL;
3458 if (d1.type != NFT_DATA_VALUE || d1.len != set->klen)
3459 goto err2;
3460
Patrick McHardy7d740262015-04-11 02:27:39 +01003461 nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, d1.len);
Patrick McHardyc3e1b002015-03-26 12:39:37 +00003462 if (timeout > 0) {
3463 nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION);
3464 if (timeout != set->timeout)
3465 nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
3466 }
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003467
Patrick McHardy20a69342013-10-11 12:06:22 +02003468 if (nla[NFTA_SET_ELEM_DATA] != NULL) {
Patrick McHardyd0a11fc2015-04-11 02:27:38 +01003469 err = nft_data_init(ctx, &data, sizeof(data), &d2,
3470 nla[NFTA_SET_ELEM_DATA]);
Patrick McHardy20a69342013-10-11 12:06:22 +02003471 if (err < 0)
3472 goto err2;
3473
3474 err = -EINVAL;
3475 if (set->dtype != NFT_DATA_VERDICT && d2.len != set->dlen)
3476 goto err3;
3477
3478 dreg = nft_type_to_reg(set->dtype);
3479 list_for_each_entry(binding, &set->bindings, list) {
3480 struct nft_ctx bind_ctx = {
3481 .afi = ctx->afi,
3482 .table = ctx->table,
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02003483 .chain = (struct nft_chain *)binding->chain,
Patrick McHardy20a69342013-10-11 12:06:22 +02003484 };
3485
Patrick McHardy11113e12015-04-05 14:41:07 +02003486 if (!(binding->flags & NFT_SET_MAP))
3487 continue;
3488
Patrick McHardy1ec10212015-04-11 02:27:27 +01003489 err = nft_validate_register_store(&bind_ctx, dreg,
3490 &data,
3491 d2.type, d2.len);
Patrick McHardy20a69342013-10-11 12:06:22 +02003492 if (err < 0)
3493 goto err3;
3494 }
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003495
Patrick McHardy7d740262015-04-11 02:27:39 +01003496 nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, d2.len);
Patrick McHardy20a69342013-10-11 12:06:22 +02003497 }
3498
Patrick McHardy68e942e2015-04-05 14:43:38 +02003499 /* The full maximum length of userdata can exceed the maximum
3500 * offset value (U8_MAX) for following extensions, therefor it
3501 * must be the last extension added.
3502 */
3503 ulen = 0;
3504 if (nla[NFTA_SET_ELEM_USERDATA] != NULL) {
3505 ulen = nla_len(nla[NFTA_SET_ELEM_USERDATA]);
3506 if (ulen > 0)
3507 nft_set_ext_add_length(&tmpl, NFT_SET_EXT_USERDATA,
3508 ulen);
3509 }
3510
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003511 err = -ENOMEM;
Patrick McHardy7d740262015-04-11 02:27:39 +01003512 elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, data.data,
Patrick McHardyc3e1b002015-03-26 12:39:37 +00003513 timeout, GFP_KERNEL);
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003514 if (elem.priv == NULL)
3515 goto err3;
3516
3517 ext = nft_set_elem_ext(set, elem.priv);
3518 if (flags)
3519 *nft_set_ext_flags(ext) = flags;
Patrick McHardy68e942e2015-04-05 14:43:38 +02003520 if (ulen > 0) {
3521 udata = nft_set_ext_userdata(ext);
3522 udata->len = ulen - 1;
3523 nla_memcpy(&udata->data, nla[NFTA_SET_ELEM_USERDATA], ulen);
3524 }
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003525
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02003526 trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set);
3527 if (trans == NULL)
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003528 goto err4;
Patrick McHardy20a69342013-10-11 12:06:22 +02003529
Patrick McHardy69086652015-03-26 12:39:39 +00003530 ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK;
Patrick McHardy20a69342013-10-11 12:06:22 +02003531 err = set->ops->insert(set, &elem);
3532 if (err < 0)
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003533 goto err5;
Patrick McHardy20a69342013-10-11 12:06:22 +02003534
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02003535 nft_trans_elem(trans) = elem;
Pablo Neira Ayuso46bbafc2014-05-22 12:36:03 +02003536 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
Patrick McHardy20a69342013-10-11 12:06:22 +02003537 return 0;
3538
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003539err5:
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02003540 kfree(trans);
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003541err4:
3542 kfree(elem.priv);
Patrick McHardy20a69342013-10-11 12:06:22 +02003543err3:
3544 if (nla[NFTA_SET_ELEM_DATA] != NULL)
Patrick McHardyfe2811e2015-03-25 13:07:50 +00003545 nft_data_uninit(&data, d2.type);
Patrick McHardy20a69342013-10-11 12:06:22 +02003546err2:
Patrick McHardy7d740262015-04-11 02:27:39 +01003547 nft_data_uninit(&elem.key.val, d1.type);
Patrick McHardy20a69342013-10-11 12:06:22 +02003548err1:
3549 return err;
3550}
3551
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01003552static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
3553 struct sk_buff *skb, const struct nlmsghdr *nlh,
Patrick McHardy20a69342013-10-11 12:06:22 +02003554 const struct nlattr * const nla[])
3555{
3556 const struct nlattr *attr;
3557 struct nft_set *set;
3558 struct nft_ctx ctx;
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02003559 int rem, err = 0;
Patrick McHardy20a69342013-10-11 12:06:22 +02003560
Pablo Neira Ayuso7d5570c2014-07-25 13:15:36 +02003561 if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
3562 return -EINVAL;
3563
Pablo Neira Ayusof4c756b2015-12-15 19:40:50 +01003564 err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02003565 if (err < 0)
3566 return err;
3567
3568 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003569 if (IS_ERR(set)) {
3570 if (nla[NFTA_SET_ELEM_LIST_SET_ID]) {
3571 set = nf_tables_set_lookup_byid(net,
3572 nla[NFTA_SET_ELEM_LIST_SET_ID]);
3573 }
3574 if (IS_ERR(set))
3575 return PTR_ERR(set);
3576 }
3577
Patrick McHardy20a69342013-10-11 12:06:22 +02003578 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
3579 return -EBUSY;
3580
3581 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
Patrick McHardy3dd06732015-04-05 14:41:06 +02003582 if (set->size &&
3583 !atomic_add_unless(&set->nelems, 1, set->size + set->ndeact))
3584 return -ENFILE;
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +02003585
Patrick McHardy3dd06732015-04-05 14:41:06 +02003586 err = nft_add_set_elem(&ctx, set, attr);
3587 if (err < 0) {
3588 atomic_dec(&set->nelems);
3589 break;
3590 }
Patrick McHardy20a69342013-10-11 12:06:22 +02003591 }
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02003592 return err;
Patrick McHardy20a69342013-10-11 12:06:22 +02003593}
3594
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02003595static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
Patrick McHardy20a69342013-10-11 12:06:22 +02003596 const struct nlattr *attr)
3597{
3598 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
Pablo Neira Ayuso3971ca12016-04-12 23:50:35 +02003599 struct nft_set_ext_tmpl tmpl;
Patrick McHardy20a69342013-10-11 12:06:22 +02003600 struct nft_data_desc desc;
3601 struct nft_set_elem elem;
Pablo Neira Ayuso3971ca12016-04-12 23:50:35 +02003602 struct nft_set_ext *ext;
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02003603 struct nft_trans *trans;
Pablo Neira Ayuso3971ca12016-04-12 23:50:35 +02003604 u32 flags = 0;
3605 void *priv;
Patrick McHardy20a69342013-10-11 12:06:22 +02003606 int err;
3607
3608 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
3609 nft_set_elem_policy);
3610 if (err < 0)
3611 goto err1;
3612
3613 err = -EINVAL;
3614 if (nla[NFTA_SET_ELEM_KEY] == NULL)
3615 goto err1;
3616
Pablo Neira Ayuso3971ca12016-04-12 23:50:35 +02003617 nft_set_ext_prepare(&tmpl);
3618
3619 err = nft_setelem_parse_flags(set, nla[NFTA_SET_ELEM_FLAGS], &flags);
3620 if (err < 0)
3621 return err;
3622 if (flags != 0)
3623 nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
3624
Patrick McHardy7d740262015-04-11 02:27:39 +01003625 err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &desc,
Patrick McHardyd0a11fc2015-04-11 02:27:38 +01003626 nla[NFTA_SET_ELEM_KEY]);
Patrick McHardy20a69342013-10-11 12:06:22 +02003627 if (err < 0)
3628 goto err1;
3629
3630 err = -EINVAL;
3631 if (desc.type != NFT_DATA_VALUE || desc.len != set->klen)
3632 goto err2;
3633
Pablo Neira Ayuso3971ca12016-04-12 23:50:35 +02003634 nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, desc.len);
3635
3636 err = -ENOMEM;
3637 elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, NULL, 0,
3638 GFP_KERNEL);
3639 if (elem.priv == NULL)
3640 goto err2;
3641
3642 ext = nft_set_elem_ext(set, elem.priv);
3643 if (flags)
3644 *nft_set_ext_flags(ext) = flags;
3645
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02003646 trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set);
Julia Lawall609ccf02014-08-07 14:49:08 +02003647 if (trans == NULL) {
3648 err = -ENOMEM;
Patrick McHardycc02e452015-03-25 14:08:50 +00003649 goto err3;
3650 }
3651
Pablo Neira Ayuso3971ca12016-04-12 23:50:35 +02003652 priv = set->ops->deactivate(set, &elem);
3653 if (priv == NULL) {
3654 err = -ENOENT;
3655 goto err4;
3656 }
3657 kfree(elem.priv);
3658 elem.priv = priv;
3659
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02003660 nft_trans_elem(trans) = elem;
Pablo Neira Ayuso46bbafc2014-05-22 12:36:03 +02003661 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
Thomas Graf0dc13622014-08-01 17:25:38 +02003662 return 0;
Patrick McHardycc02e452015-03-25 14:08:50 +00003663
Pablo Neira Ayuso3971ca12016-04-12 23:50:35 +02003664err4:
Patrick McHardycc02e452015-03-25 14:08:50 +00003665 kfree(trans);
Pablo Neira Ayuso3971ca12016-04-12 23:50:35 +02003666err3:
3667 kfree(elem.priv);
Patrick McHardy20a69342013-10-11 12:06:22 +02003668err2:
Patrick McHardy7d740262015-04-11 02:27:39 +01003669 nft_data_uninit(&elem.key.val, desc.type);
Patrick McHardy20a69342013-10-11 12:06:22 +02003670err1:
3671 return err;
3672}
3673
Pablo Neira Ayuso633c9a82015-12-09 12:08:26 +01003674static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
3675 struct sk_buff *skb, const struct nlmsghdr *nlh,
Patrick McHardy20a69342013-10-11 12:06:22 +02003676 const struct nlattr * const nla[])
3677{
3678 const struct nlattr *attr;
3679 struct nft_set *set;
3680 struct nft_ctx ctx;
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02003681 int rem, err = 0;
Patrick McHardy20a69342013-10-11 12:06:22 +02003682
Pablo Neira Ayuso7d5570c2014-07-25 13:15:36 +02003683 if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
3684 return -EINVAL;
3685
Pablo Neira Ayusof4c756b2015-12-15 19:40:50 +01003686 err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02003687 if (err < 0)
3688 return err;
3689
3690 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
3691 if (IS_ERR(set))
3692 return PTR_ERR(set);
3693 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
3694 return -EBUSY;
3695
3696 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
3697 err = nft_del_setelem(&ctx, set, attr);
3698 if (err < 0)
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02003699 break;
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +02003700
Patrick McHardy3dd06732015-04-05 14:41:06 +02003701 set->ndeact++;
Patrick McHardy20a69342013-10-11 12:06:22 +02003702 }
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02003703 return err;
Patrick McHardy20a69342013-10-11 12:06:22 +02003704}
3705
Patrick McHardycfed7e12015-03-26 12:39:38 +00003706void nft_set_gc_batch_release(struct rcu_head *rcu)
3707{
3708 struct nft_set_gc_batch *gcb;
3709 unsigned int i;
3710
3711 gcb = container_of(rcu, struct nft_set_gc_batch, head.rcu);
3712 for (i = 0; i < gcb->head.cnt; i++)
3713 nft_set_elem_destroy(gcb->head.set, gcb->elems[i]);
3714 kfree(gcb);
3715}
3716EXPORT_SYMBOL_GPL(nft_set_gc_batch_release);
3717
3718struct nft_set_gc_batch *nft_set_gc_batch_alloc(const struct nft_set *set,
3719 gfp_t gfp)
3720{
3721 struct nft_set_gc_batch *gcb;
3722
3723 gcb = kzalloc(sizeof(*gcb), gfp);
3724 if (gcb == NULL)
3725 return gcb;
3726 gcb->head.set = set;
3727 return gcb;
3728}
3729EXPORT_SYMBOL_GPL(nft_set_gc_batch_alloc);
3730
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02003731static int nf_tables_fill_gen_info(struct sk_buff *skb, struct net *net,
3732 u32 portid, u32 seq)
3733{
3734 struct nlmsghdr *nlh;
3735 struct nfgenmsg *nfmsg;
3736 int event = (NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_NEWGEN;
3737
3738 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), 0);
3739 if (nlh == NULL)
3740 goto nla_put_failure;
3741
3742 nfmsg = nlmsg_data(nlh);
3743 nfmsg->nfgen_family = AF_UNSPEC;
3744 nfmsg->version = NFNETLINK_V0;
3745 nfmsg->res_id = htons(net->nft.base_seq & 0xffff);
3746
3747 if (nla_put_be32(skb, NFTA_GEN_ID, htonl(net->nft.base_seq)))
3748 goto nla_put_failure;
3749
Johannes Berg053c0952015-01-16 22:09:00 +01003750 nlmsg_end(skb, nlh);
3751 return 0;
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02003752
3753nla_put_failure:
3754 nlmsg_trim(skb, nlh);
3755 return -EMSGSIZE;
3756}
3757
3758static int nf_tables_gen_notify(struct net *net, struct sk_buff *skb, int event)
3759{
3760 struct nlmsghdr *nlh = nlmsg_hdr(skb);
3761 struct sk_buff *skb2;
3762 int err;
3763
3764 if (nlmsg_report(nlh) &&
3765 !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
3766 return 0;
3767
3768 err = -ENOBUFS;
3769 skb2 = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
3770 if (skb2 == NULL)
3771 goto err;
3772
3773 err = nf_tables_fill_gen_info(skb2, net, NETLINK_CB(skb).portid,
3774 nlh->nlmsg_seq);
3775 if (err < 0) {
3776 kfree_skb(skb2);
3777 goto err;
3778 }
3779
3780 err = nfnetlink_send(skb2, net, NETLINK_CB(skb).portid,
3781 NFNLGRP_NFTABLES, nlmsg_report(nlh), GFP_KERNEL);
3782err:
3783 if (err < 0) {
3784 nfnetlink_set_err(net, NETLINK_CB(skb).portid, NFNLGRP_NFTABLES,
3785 err);
3786 }
3787 return err;
3788}
3789
Pablo Neira Ayuso7b8002a2015-12-15 18:41:56 +01003790static int nf_tables_getgen(struct net *net, struct sock *nlsk,
3791 struct sk_buff *skb, const struct nlmsghdr *nlh,
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02003792 const struct nlattr * const nla[])
3793{
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02003794 struct sk_buff *skb2;
3795 int err;
3796
3797 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
3798 if (skb2 == NULL)
3799 return -ENOMEM;
3800
3801 err = nf_tables_fill_gen_info(skb2, net, NETLINK_CB(skb).portid,
3802 nlh->nlmsg_seq);
3803 if (err < 0)
3804 goto err;
3805
3806 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
3807err:
3808 kfree_skb(skb2);
3809 return err;
3810}
3811
Patrick McHardy96518512013-10-14 11:00:02 +02003812static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
3813 [NFT_MSG_NEWTABLE] = {
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +02003814 .call_batch = nf_tables_newtable,
Patrick McHardy96518512013-10-14 11:00:02 +02003815 .attr_count = NFTA_TABLE_MAX,
3816 .policy = nft_table_policy,
3817 },
3818 [NFT_MSG_GETTABLE] = {
3819 .call = nf_tables_gettable,
3820 .attr_count = NFTA_TABLE_MAX,
3821 .policy = nft_table_policy,
3822 },
3823 [NFT_MSG_DELTABLE] = {
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +02003824 .call_batch = nf_tables_deltable,
Patrick McHardy96518512013-10-14 11:00:02 +02003825 .attr_count = NFTA_TABLE_MAX,
3826 .policy = nft_table_policy,
3827 },
3828 [NFT_MSG_NEWCHAIN] = {
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02003829 .call_batch = nf_tables_newchain,
Patrick McHardy96518512013-10-14 11:00:02 +02003830 .attr_count = NFTA_CHAIN_MAX,
3831 .policy = nft_chain_policy,
3832 },
3833 [NFT_MSG_GETCHAIN] = {
3834 .call = nf_tables_getchain,
3835 .attr_count = NFTA_CHAIN_MAX,
3836 .policy = nft_chain_policy,
3837 },
3838 [NFT_MSG_DELCHAIN] = {
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02003839 .call_batch = nf_tables_delchain,
Patrick McHardy96518512013-10-14 11:00:02 +02003840 .attr_count = NFTA_CHAIN_MAX,
3841 .policy = nft_chain_policy,
3842 },
3843 [NFT_MSG_NEWRULE] = {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02003844 .call_batch = nf_tables_newrule,
Patrick McHardy96518512013-10-14 11:00:02 +02003845 .attr_count = NFTA_RULE_MAX,
3846 .policy = nft_rule_policy,
3847 },
3848 [NFT_MSG_GETRULE] = {
3849 .call = nf_tables_getrule,
3850 .attr_count = NFTA_RULE_MAX,
3851 .policy = nft_rule_policy,
3852 },
3853 [NFT_MSG_DELRULE] = {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02003854 .call_batch = nf_tables_delrule,
Patrick McHardy96518512013-10-14 11:00:02 +02003855 .attr_count = NFTA_RULE_MAX,
3856 .policy = nft_rule_policy,
3857 },
Patrick McHardy20a69342013-10-11 12:06:22 +02003858 [NFT_MSG_NEWSET] = {
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003859 .call_batch = nf_tables_newset,
Patrick McHardy20a69342013-10-11 12:06:22 +02003860 .attr_count = NFTA_SET_MAX,
3861 .policy = nft_set_policy,
3862 },
3863 [NFT_MSG_GETSET] = {
3864 .call = nf_tables_getset,
3865 .attr_count = NFTA_SET_MAX,
3866 .policy = nft_set_policy,
3867 },
3868 [NFT_MSG_DELSET] = {
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003869 .call_batch = nf_tables_delset,
Patrick McHardy20a69342013-10-11 12:06:22 +02003870 .attr_count = NFTA_SET_MAX,
3871 .policy = nft_set_policy,
3872 },
3873 [NFT_MSG_NEWSETELEM] = {
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003874 .call_batch = nf_tables_newsetelem,
Patrick McHardy20a69342013-10-11 12:06:22 +02003875 .attr_count = NFTA_SET_ELEM_LIST_MAX,
3876 .policy = nft_set_elem_list_policy,
3877 },
3878 [NFT_MSG_GETSETELEM] = {
3879 .call = nf_tables_getsetelem,
3880 .attr_count = NFTA_SET_ELEM_LIST_MAX,
3881 .policy = nft_set_elem_list_policy,
3882 },
3883 [NFT_MSG_DELSETELEM] = {
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003884 .call_batch = nf_tables_delsetelem,
Patrick McHardy20a69342013-10-11 12:06:22 +02003885 .attr_count = NFTA_SET_ELEM_LIST_MAX,
3886 .policy = nft_set_elem_list_policy,
3887 },
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02003888 [NFT_MSG_GETGEN] = {
3889 .call = nf_tables_getgen,
3890 },
Patrick McHardy96518512013-10-14 11:00:02 +02003891};
3892
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02003893static void nft_chain_commit_update(struct nft_trans *trans)
3894{
3895 struct nft_base_chain *basechain;
3896
3897 if (nft_trans_chain_name(trans)[0])
3898 strcpy(trans->ctx.chain->name, nft_trans_chain_name(trans));
3899
3900 if (!(trans->ctx.chain->flags & NFT_BASE_CHAIN))
3901 return;
3902
3903 basechain = nft_base_chain(trans->ctx.chain);
3904 nft_chain_stats_replace(basechain, nft_trans_chain_stats(trans));
3905
3906 switch (nft_trans_chain_policy(trans)) {
3907 case NF_DROP:
3908 case NF_ACCEPT:
3909 basechain->policy = nft_trans_chain_policy(trans);
3910 break;
3911 }
3912}
3913
Pablo Neira Ayusob326dd32014-11-10 21:14:12 +01003914static void nf_tables_commit_release(struct nft_trans *trans)
Pablo Neira Ayusoc7c32e72014-04-10 00:31:10 +02003915{
Pablo Neira Ayusoc7c32e72014-04-10 00:31:10 +02003916 switch (trans->msg_type) {
3917 case NFT_MSG_DELTABLE:
3918 nf_tables_table_destroy(&trans->ctx);
3919 break;
3920 case NFT_MSG_DELCHAIN:
3921 nf_tables_chain_destroy(trans->ctx.chain);
3922 break;
3923 case NFT_MSG_DELRULE:
3924 nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans));
3925 break;
3926 case NFT_MSG_DELSET:
3927 nft_set_destroy(nft_trans_set(trans));
3928 break;
Patrick McHardy61edafb2015-03-25 14:08:47 +00003929 case NFT_MSG_DELSETELEM:
3930 nft_set_elem_destroy(nft_trans_elem_set(trans),
3931 nft_trans_elem(trans).priv);
3932 break;
Pablo Neira Ayusoc7c32e72014-04-10 00:31:10 +02003933 }
3934 kfree(trans);
3935}
3936
Pablo Neira Ayuso5913bea2015-12-15 19:41:57 +01003937static int nf_tables_commit(struct net *net, struct sk_buff *skb)
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003938{
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003939 struct nft_trans *trans, *next;
Pablo Neira Ayusoa3716e72014-08-01 19:32:41 +02003940 struct nft_trans_elem *te;
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003941
3942 /* Bump generation counter, invalidate any dump in progress */
Pablo Neira Ayuso38e029f2014-07-01 12:23:12 +02003943 while (++net->nft.base_seq == 0);
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003944
3945 /* A new generation has just started */
Patrick McHardyea4bd992015-03-25 14:08:49 +00003946 net->nft.gencursor = nft_gencursor_next(net);
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003947
3948 /* Make sure all packets have left the previous generation before
3949 * purging old rules.
3950 */
3951 synchronize_rcu();
3952
3953 list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003954 switch (trans->msg_type) {
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +02003955 case NFT_MSG_NEWTABLE:
3956 if (nft_trans_table_update(trans)) {
3957 if (!nft_trans_table_enable(trans)) {
3958 nf_tables_table_disable(trans->ctx.afi,
3959 trans->ctx.table);
3960 trans->ctx.table->flags |= NFT_TABLE_F_DORMANT;
3961 }
3962 } else {
3963 trans->ctx.table->flags &= ~NFT_TABLE_INACTIVE;
3964 }
Pablo Neira Ayuso35151d82014-05-05 17:12:40 +02003965 nf_tables_table_notify(&trans->ctx, NFT_MSG_NEWTABLE);
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +02003966 nft_trans_destroy(trans);
3967 break;
3968 case NFT_MSG_DELTABLE:
Pablo Neira Ayuso35151d82014-05-05 17:12:40 +02003969 nf_tables_table_notify(&trans->ctx, NFT_MSG_DELTABLE);
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +02003970 break;
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02003971 case NFT_MSG_NEWCHAIN:
3972 if (nft_trans_chain_update(trans))
3973 nft_chain_commit_update(trans);
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +02003974 else
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02003975 trans->ctx.chain->flags &= ~NFT_CHAIN_INACTIVE;
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +02003976
Pablo Neira Ayuso35151d82014-05-05 17:12:40 +02003977 nf_tables_chain_notify(&trans->ctx, NFT_MSG_NEWCHAIN);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02003978 nft_trans_destroy(trans);
3979 break;
3980 case NFT_MSG_DELCHAIN:
Pablo Neira Ayuso35151d82014-05-05 17:12:40 +02003981 nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN);
Arturo Borreroc5598792014-09-02 16:42:23 +02003982 nf_tables_unregister_hooks(trans->ctx.table,
3983 trans->ctx.chain,
3984 trans->ctx.afi->nops);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02003985 break;
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003986 case NFT_MSG_NEWRULE:
3987 nft_rule_clear(trans->ctx.net, nft_trans_rule(trans));
Pablo Neira Ayuso35151d82014-05-05 17:12:40 +02003988 nf_tables_rule_notify(&trans->ctx,
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003989 nft_trans_rule(trans),
Pablo Neira Ayuso35151d82014-05-05 17:12:40 +02003990 NFT_MSG_NEWRULE);
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003991 nft_trans_destroy(trans);
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003992 break;
3993 case NFT_MSG_DELRULE:
3994 list_del_rcu(&nft_trans_rule(trans)->list);
Pablo Neira Ayuso35151d82014-05-05 17:12:40 +02003995 nf_tables_rule_notify(&trans->ctx,
3996 nft_trans_rule(trans),
3997 NFT_MSG_DELRULE);
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003998 break;
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003999 case NFT_MSG_NEWSET:
4000 nft_trans_set(trans)->flags &= ~NFT_SET_INACTIVE;
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +02004001 /* This avoids hitting -EBUSY when deleting the table
4002 * from the transaction.
4003 */
4004 if (nft_trans_set(trans)->flags & NFT_SET_ANONYMOUS &&
4005 !list_empty(&nft_trans_set(trans)->bindings))
4006 trans->ctx.table->use--;
4007
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02004008 nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
Pablo Neira Ayuso31f84412014-05-29 10:29:58 +02004009 NFT_MSG_NEWSET, GFP_KERNEL);
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02004010 nft_trans_destroy(trans);
4011 break;
4012 case NFT_MSG_DELSET:
4013 nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
Pablo Neira Ayuso31f84412014-05-29 10:29:58 +02004014 NFT_MSG_DELSET, GFP_KERNEL);
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02004015 break;
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02004016 case NFT_MSG_NEWSETELEM:
Patrick McHardycc02e452015-03-25 14:08:50 +00004017 te = (struct nft_trans_elem *)trans->data;
4018
4019 te->set->ops->activate(te->set, &te->elem);
4020 nf_tables_setelem_notify(&trans->ctx, te->set,
4021 &te->elem,
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02004022 NFT_MSG_NEWSETELEM, 0);
4023 nft_trans_destroy(trans);
4024 break;
4025 case NFT_MSG_DELSETELEM:
Pablo Neira Ayusoa3716e72014-08-01 19:32:41 +02004026 te = (struct nft_trans_elem *)trans->data;
Patrick McHardyfe2811e2015-03-25 13:07:50 +00004027
Pablo Neira Ayusoa3716e72014-08-01 19:32:41 +02004028 nf_tables_setelem_notify(&trans->ctx, te->set,
4029 &te->elem,
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02004030 NFT_MSG_DELSETELEM, 0);
Pablo Neira Ayuso02263db2015-02-20 17:11:10 +01004031 te->set->ops->remove(te->set, &te->elem);
Patrick McHardy3dd06732015-04-05 14:41:06 +02004032 atomic_dec(&te->set->nelems);
4033 te->set->ndeact--;
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02004034 break;
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02004035 }
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02004036 }
4037
Pablo Neira Ayusob326dd32014-11-10 21:14:12 +01004038 synchronize_rcu();
4039
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02004040 list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
Pablo Neira Ayusoc7c32e72014-04-10 00:31:10 +02004041 list_del(&trans->list);
Pablo Neira Ayusob326dd32014-11-10 21:14:12 +01004042 nf_tables_commit_release(trans);
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02004043 }
4044
Pablo Neira Ayuso84d7fce2014-09-04 14:30:22 +02004045 nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
4046
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02004047 return 0;
4048}
4049
Pablo Neira Ayusob326dd32014-11-10 21:14:12 +01004050static void nf_tables_abort_release(struct nft_trans *trans)
Pablo Neira Ayusoc7c32e72014-04-10 00:31:10 +02004051{
Pablo Neira Ayusoc7c32e72014-04-10 00:31:10 +02004052 switch (trans->msg_type) {
4053 case NFT_MSG_NEWTABLE:
4054 nf_tables_table_destroy(&trans->ctx);
4055 break;
4056 case NFT_MSG_NEWCHAIN:
4057 nf_tables_chain_destroy(trans->ctx.chain);
4058 break;
4059 case NFT_MSG_NEWRULE:
4060 nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans));
4061 break;
4062 case NFT_MSG_NEWSET:
4063 nft_set_destroy(nft_trans_set(trans));
4064 break;
Patrick McHardy61edafb2015-03-25 14:08:47 +00004065 case NFT_MSG_NEWSETELEM:
4066 nft_set_elem_destroy(nft_trans_elem_set(trans),
4067 nft_trans_elem(trans).priv);
4068 break;
Pablo Neira Ayusoc7c32e72014-04-10 00:31:10 +02004069 }
4070 kfree(trans);
4071}
4072
Pablo Neira Ayuso5913bea2015-12-15 19:41:57 +01004073static int nf_tables_abort(struct net *net, struct sk_buff *skb)
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02004074{
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02004075 struct nft_trans *trans, *next;
Pablo Neira Ayuso02263db2015-02-20 17:11:10 +01004076 struct nft_trans_elem *te;
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02004077
Xin Longa907e362015-12-07 18:48:07 +08004078 list_for_each_entry_safe_reverse(trans, next, &net->nft.commit_list,
4079 list) {
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02004080 switch (trans->msg_type) {
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +02004081 case NFT_MSG_NEWTABLE:
4082 if (nft_trans_table_update(trans)) {
4083 if (nft_trans_table_enable(trans)) {
4084 nf_tables_table_disable(trans->ctx.afi,
4085 trans->ctx.table);
4086 trans->ctx.table->flags |= NFT_TABLE_F_DORMANT;
4087 }
4088 nft_trans_destroy(trans);
4089 } else {
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02004090 list_del_rcu(&trans->ctx.table->list);
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +02004091 }
4092 break;
4093 case NFT_MSG_DELTABLE:
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02004094 list_add_tail_rcu(&trans->ctx.table->list,
4095 &trans->ctx.afi->tables);
Pablo Neira Ayuso55dd6f92014-04-03 11:53:37 +02004096 nft_trans_destroy(trans);
4097 break;
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02004098 case NFT_MSG_NEWCHAIN:
4099 if (nft_trans_chain_update(trans)) {
Markus Elfring982f4052014-11-18 20:37:05 +01004100 free_percpu(nft_trans_chain_stats(trans));
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02004101
4102 nft_trans_destroy(trans);
4103 } else {
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +02004104 trans->ctx.table->use--;
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02004105 list_del_rcu(&trans->ctx.chain->list);
Arturo Borreroc5598792014-09-02 16:42:23 +02004106 nf_tables_unregister_hooks(trans->ctx.table,
4107 trans->ctx.chain,
4108 trans->ctx.afi->nops);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02004109 }
4110 break;
4111 case NFT_MSG_DELCHAIN:
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +02004112 trans->ctx.table->use++;
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02004113 list_add_tail_rcu(&trans->ctx.chain->list,
4114 &trans->ctx.table->chains);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02004115 nft_trans_destroy(trans);
4116 break;
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02004117 case NFT_MSG_NEWRULE:
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +02004118 trans->ctx.chain->use--;
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02004119 list_del_rcu(&nft_trans_rule(trans)->list);
4120 break;
4121 case NFT_MSG_DELRULE:
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +02004122 trans->ctx.chain->use++;
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02004123 nft_rule_clear(trans->ctx.net, nft_trans_rule(trans));
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02004124 nft_trans_destroy(trans);
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02004125 break;
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02004126 case NFT_MSG_NEWSET:
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +02004127 trans->ctx.table->use--;
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02004128 list_del_rcu(&nft_trans_set(trans)->list);
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02004129 break;
4130 case NFT_MSG_DELSET:
Pablo Neira Ayuso4fefee52014-05-23 12:39:26 +02004131 trans->ctx.table->use++;
Pablo Neira Ayusoe688a7f2014-07-01 11:49:18 +02004132 list_add_tail_rcu(&nft_trans_set(trans)->list,
4133 &trans->ctx.table->sets);
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02004134 nft_trans_destroy(trans);
4135 break;
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02004136 case NFT_MSG_NEWSETELEM:
Pablo Neira Ayuso02263db2015-02-20 17:11:10 +01004137 te = (struct nft_trans_elem *)trans->data;
Patrick McHardyfe2811e2015-03-25 13:07:50 +00004138
Pablo Neira Ayuso02263db2015-02-20 17:11:10 +01004139 te->set->ops->remove(te->set, &te->elem);
Patrick McHardy3dd06732015-04-05 14:41:06 +02004140 atomic_dec(&te->set->nelems);
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02004141 break;
4142 case NFT_MSG_DELSETELEM:
Patrick McHardycc02e452015-03-25 14:08:50 +00004143 te = (struct nft_trans_elem *)trans->data;
4144
Patrick McHardycc02e452015-03-25 14:08:50 +00004145 te->set->ops->activate(te->set, &te->elem);
Patrick McHardy3dd06732015-04-05 14:41:06 +02004146 te->set->ndeact--;
Patrick McHardycc02e452015-03-25 14:08:50 +00004147
Pablo Neira Ayuso60319eb2014-04-04 03:36:42 +02004148 nft_trans_destroy(trans);
4149 break;
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02004150 }
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02004151 }
4152
Pablo Neira Ayusob326dd32014-11-10 21:14:12 +01004153 synchronize_rcu();
4154
Pablo Neira Ayusoa1cee072014-05-23 11:09:42 +02004155 list_for_each_entry_safe_reverse(trans, next,
4156 &net->nft.commit_list, list) {
Pablo Neira Ayusoc7c32e72014-04-10 00:31:10 +02004157 list_del(&trans->list);
Pablo Neira Ayusob326dd32014-11-10 21:14:12 +01004158 nf_tables_abort_release(trans);
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02004159 }
4160
4161 return 0;
4162}
4163
Patrick McHardy96518512013-10-14 11:00:02 +02004164static const struct nfnetlink_subsystem nf_tables_subsys = {
4165 .name = "nf_tables",
4166 .subsys_id = NFNL_SUBSYS_NFTABLES,
4167 .cb_count = NFT_MSG_MAX,
4168 .cb = nf_tables_cb,
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02004169 .commit = nf_tables_commit,
4170 .abort = nf_tables_abort,
Patrick McHardy96518512013-10-14 11:00:02 +02004171};
4172
Pablo Neira Ayuso7210e4e2014-10-13 19:50:22 +02004173int nft_chain_validate_dependency(const struct nft_chain *chain,
4174 enum nft_chain_type type)
4175{
4176 const struct nft_base_chain *basechain;
4177
4178 if (chain->flags & NFT_BASE_CHAIN) {
4179 basechain = nft_base_chain(chain);
4180 if (basechain->type->type != type)
4181 return -EOPNOTSUPP;
4182 }
4183 return 0;
4184}
4185EXPORT_SYMBOL_GPL(nft_chain_validate_dependency);
4186
Pablo Neira Ayuso75e8d062015-01-14 15:33:57 +01004187int nft_chain_validate_hooks(const struct nft_chain *chain,
4188 unsigned int hook_flags)
4189{
4190 struct nft_base_chain *basechain;
4191
4192 if (chain->flags & NFT_BASE_CHAIN) {
4193 basechain = nft_base_chain(chain);
4194
4195 if ((1 << basechain->ops[0].hooknum) & hook_flags)
4196 return 0;
4197
4198 return -EOPNOTSUPP;
4199 }
4200
4201 return 0;
4202}
4203EXPORT_SYMBOL_GPL(nft_chain_validate_hooks);
4204
Patrick McHardy20a69342013-10-11 12:06:22 +02004205/*
4206 * Loop detection - walk through the ruleset beginning at the destination chain
4207 * of a new jump until either the source chain is reached (loop) or all
4208 * reachable chains have been traversed.
4209 *
4210 * The loop check is performed whenever a new jump verdict is added to an
4211 * expression or verdict map or a verdict map is bound to a new chain.
4212 */
4213
4214static int nf_tables_check_loops(const struct nft_ctx *ctx,
4215 const struct nft_chain *chain);
4216
4217static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
4218 const struct nft_set *set,
4219 const struct nft_set_iter *iter,
4220 const struct nft_set_elem *elem)
4221{
Patrick McHardyfe2811e2015-03-25 13:07:50 +00004222 const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
4223 const struct nft_data *data;
4224
4225 if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
4226 *nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END)
Pablo Neira Ayuso62f9c8b2014-02-07 14:45:01 +01004227 return 0;
4228
Patrick McHardyfe2811e2015-03-25 13:07:50 +00004229 data = nft_set_ext_data(ext);
Patrick McHardy1ca2e172015-04-11 02:27:32 +01004230 switch (data->verdict.code) {
Patrick McHardy20a69342013-10-11 12:06:22 +02004231 case NFT_JUMP:
4232 case NFT_GOTO:
Patrick McHardy1ca2e172015-04-11 02:27:32 +01004233 return nf_tables_check_loops(ctx, data->verdict.chain);
Patrick McHardy20a69342013-10-11 12:06:22 +02004234 default:
4235 return 0;
4236 }
4237}
4238
4239static int nf_tables_check_loops(const struct nft_ctx *ctx,
4240 const struct nft_chain *chain)
4241{
4242 const struct nft_rule *rule;
4243 const struct nft_expr *expr, *last;
Patrick McHardy20a69342013-10-11 12:06:22 +02004244 const struct nft_set *set;
4245 struct nft_set_binding *binding;
4246 struct nft_set_iter iter;
Patrick McHardy20a69342013-10-11 12:06:22 +02004247
4248 if (ctx->chain == chain)
4249 return -ELOOP;
4250
4251 list_for_each_entry(rule, &chain->rules, list) {
4252 nft_rule_for_each_expr(expr, last, rule) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02004253 const struct nft_data *data = NULL;
4254 int err;
4255
4256 if (!expr->ops->validate)
Patrick McHardy20a69342013-10-11 12:06:22 +02004257 continue;
4258
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02004259 err = expr->ops->validate(ctx, expr, &data);
4260 if (err < 0)
4261 return err;
4262
Patrick McHardy20a69342013-10-11 12:06:22 +02004263 if (data == NULL)
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02004264 continue;
Patrick McHardy20a69342013-10-11 12:06:22 +02004265
Patrick McHardy1ca2e172015-04-11 02:27:32 +01004266 switch (data->verdict.code) {
Patrick McHardy20a69342013-10-11 12:06:22 +02004267 case NFT_JUMP:
4268 case NFT_GOTO:
Patrick McHardy1ca2e172015-04-11 02:27:32 +01004269 err = nf_tables_check_loops(ctx,
4270 data->verdict.chain);
Patrick McHardy20a69342013-10-11 12:06:22 +02004271 if (err < 0)
4272 return err;
4273 default:
4274 break;
4275 }
4276 }
4277 }
4278
4279 list_for_each_entry(set, &ctx->table->sets, list) {
4280 if (!(set->flags & NFT_SET_MAP) ||
4281 set->dtype != NFT_DATA_VERDICT)
4282 continue;
4283
4284 list_for_each_entry(binding, &set->bindings, list) {
Patrick McHardy11113e12015-04-05 14:41:07 +02004285 if (!(binding->flags & NFT_SET_MAP) ||
4286 binding->chain != chain)
Patrick McHardy20a69342013-10-11 12:06:22 +02004287 continue;
4288
Pablo Neira Ayuso8588ac02016-06-11 12:20:27 +08004289 iter.genmask = nft_genmask_next(ctx->net);
Patrick McHardy20a69342013-10-11 12:06:22 +02004290 iter.skip = 0;
4291 iter.count = 0;
4292 iter.err = 0;
4293 iter.fn = nf_tables_loop_check_setelem;
4294
4295 set->ops->walk(ctx, set, &iter);
4296 if (iter.err < 0)
4297 return iter.err;
4298 }
4299 }
4300
4301 return 0;
4302}
4303
Patrick McHardy49499c32015-04-11 02:27:37 +01004304/**
4305 * nft_parse_register - parse a register value from a netlink attribute
4306 *
4307 * @attr: netlink attribute
4308 *
4309 * Parse and translate a register value from a netlink attribute.
4310 * Registers used to be 128 bit wide, these register numbers will be
4311 * mapped to the corresponding 32 bit register numbers.
4312 */
Patrick McHardyb1c96ed2015-04-11 02:27:36 +01004313unsigned int nft_parse_register(const struct nlattr *attr)
4314{
Patrick McHardy49499c32015-04-11 02:27:37 +01004315 unsigned int reg;
4316
4317 reg = ntohl(nla_get_be32(attr));
4318 switch (reg) {
4319 case NFT_REG_VERDICT...NFT_REG_4:
4320 return reg * NFT_REG_SIZE / NFT_REG32_SIZE;
4321 default:
4322 return reg + NFT_REG_SIZE / NFT_REG32_SIZE - NFT_REG32_00;
4323 }
Patrick McHardyb1c96ed2015-04-11 02:27:36 +01004324}
4325EXPORT_SYMBOL_GPL(nft_parse_register);
4326
Patrick McHardy49499c32015-04-11 02:27:37 +01004327/**
4328 * nft_dump_register - dump a register value to a netlink attribute
4329 *
4330 * @skb: socket buffer
4331 * @attr: attribute number
4332 * @reg: register number
4333 *
4334 * Construct a netlink attribute containing the register number. For
4335 * compatibility reasons, register numbers being a multiple of 4 are
4336 * translated to the corresponding 128 bit register numbers.
4337 */
Patrick McHardyb1c96ed2015-04-11 02:27:36 +01004338int nft_dump_register(struct sk_buff *skb, unsigned int attr, unsigned int reg)
4339{
Patrick McHardy49499c32015-04-11 02:27:37 +01004340 if (reg % (NFT_REG_SIZE / NFT_REG32_SIZE) == 0)
4341 reg = reg / (NFT_REG_SIZE / NFT_REG32_SIZE);
4342 else
4343 reg = reg - NFT_REG_SIZE / NFT_REG32_SIZE + NFT_REG32_00;
4344
Patrick McHardyb1c96ed2015-04-11 02:27:36 +01004345 return nla_put_be32(skb, attr, htonl(reg));
4346}
4347EXPORT_SYMBOL_GPL(nft_dump_register);
4348
Patrick McHardy96518512013-10-14 11:00:02 +02004349/**
Patrick McHardyd07db982015-04-11 02:27:30 +01004350 * nft_validate_register_load - validate a load from a register
Patrick McHardy96518512013-10-14 11:00:02 +02004351 *
4352 * @reg: the register number
Patrick McHardyd07db982015-04-11 02:27:30 +01004353 * @len: the length of the data
Patrick McHardy96518512013-10-14 11:00:02 +02004354 *
4355 * Validate that the input register is one of the general purpose
Patrick McHardyd07db982015-04-11 02:27:30 +01004356 * registers and that the length of the load is within the bounds.
Patrick McHardy96518512013-10-14 11:00:02 +02004357 */
Patrick McHardyd07db982015-04-11 02:27:30 +01004358int nft_validate_register_load(enum nft_registers reg, unsigned int len)
Patrick McHardy96518512013-10-14 11:00:02 +02004359{
Patrick McHardy49499c32015-04-11 02:27:37 +01004360 if (reg < NFT_REG_1 * NFT_REG_SIZE / NFT_REG32_SIZE)
Patrick McHardy96518512013-10-14 11:00:02 +02004361 return -EINVAL;
Patrick McHardyd07db982015-04-11 02:27:30 +01004362 if (len == 0)
4363 return -EINVAL;
Patrick McHardy49499c32015-04-11 02:27:37 +01004364 if (reg * NFT_REG32_SIZE + len > FIELD_SIZEOF(struct nft_regs, data))
Patrick McHardyd07db982015-04-11 02:27:30 +01004365 return -ERANGE;
Patrick McHardy49499c32015-04-11 02:27:37 +01004366
Patrick McHardy96518512013-10-14 11:00:02 +02004367 return 0;
4368}
Patrick McHardyd07db982015-04-11 02:27:30 +01004369EXPORT_SYMBOL_GPL(nft_validate_register_load);
Patrick McHardy96518512013-10-14 11:00:02 +02004370
4371/**
Patrick McHardy1ec10212015-04-11 02:27:27 +01004372 * nft_validate_register_store - validate an expressions' register store
Patrick McHardy96518512013-10-14 11:00:02 +02004373 *
4374 * @ctx: context of the expression performing the load
4375 * @reg: the destination register number
4376 * @data: the data to load
4377 * @type: the data type
Patrick McHardy45d9bcd2015-04-11 02:27:26 +01004378 * @len: the length of the data
Patrick McHardy96518512013-10-14 11:00:02 +02004379 *
4380 * Validate that a data load uses the appropriate data type for
Patrick McHardy45d9bcd2015-04-11 02:27:26 +01004381 * the destination register and the length is within the bounds.
4382 * A value of NULL for the data means that its runtime gathered
Patrick McHardy58f40ab2015-04-11 02:27:28 +01004383 * data.
Patrick McHardy96518512013-10-14 11:00:02 +02004384 */
Patrick McHardy1ec10212015-04-11 02:27:27 +01004385int nft_validate_register_store(const struct nft_ctx *ctx,
4386 enum nft_registers reg,
4387 const struct nft_data *data,
4388 enum nft_data_types type, unsigned int len)
Patrick McHardy96518512013-10-14 11:00:02 +02004389{
Patrick McHardy20a69342013-10-11 12:06:22 +02004390 int err;
4391
Patrick McHardy96518512013-10-14 11:00:02 +02004392 switch (reg) {
4393 case NFT_REG_VERDICT:
Patrick McHardy58f40ab2015-04-11 02:27:28 +01004394 if (type != NFT_DATA_VERDICT)
Patrick McHardy96518512013-10-14 11:00:02 +02004395 return -EINVAL;
Patrick McHardy20a69342013-10-11 12:06:22 +02004396
Patrick McHardy58f40ab2015-04-11 02:27:28 +01004397 if (data != NULL &&
Patrick McHardy1ca2e172015-04-11 02:27:32 +01004398 (data->verdict.code == NFT_GOTO ||
4399 data->verdict.code == NFT_JUMP)) {
4400 err = nf_tables_check_loops(ctx, data->verdict.chain);
Patrick McHardy20a69342013-10-11 12:06:22 +02004401 if (err < 0)
4402 return err;
4403
Patrick McHardy1ca2e172015-04-11 02:27:32 +01004404 if (ctx->chain->level + 1 >
4405 data->verdict.chain->level) {
Patrick McHardy20a69342013-10-11 12:06:22 +02004406 if (ctx->chain->level + 1 == NFT_JUMP_STACK_SIZE)
4407 return -EMLINK;
Patrick McHardy1ca2e172015-04-11 02:27:32 +01004408 data->verdict.chain->level = ctx->chain->level + 1;
Patrick McHardy20a69342013-10-11 12:06:22 +02004409 }
4410 }
4411
Patrick McHardy96518512013-10-14 11:00:02 +02004412 return 0;
4413 default:
Patrick McHardy49499c32015-04-11 02:27:37 +01004414 if (reg < NFT_REG_1 * NFT_REG_SIZE / NFT_REG32_SIZE)
Patrick McHardy27e6d202015-04-11 02:27:29 +01004415 return -EINVAL;
Patrick McHardy45d9bcd2015-04-11 02:27:26 +01004416 if (len == 0)
4417 return -EINVAL;
Patrick McHardy49499c32015-04-11 02:27:37 +01004418 if (reg * NFT_REG32_SIZE + len >
4419 FIELD_SIZEOF(struct nft_regs, data))
Patrick McHardy45d9bcd2015-04-11 02:27:26 +01004420 return -ERANGE;
Patrick McHardy27e6d202015-04-11 02:27:29 +01004421
Patrick McHardy96518512013-10-14 11:00:02 +02004422 if (data != NULL && type != NFT_DATA_VALUE)
4423 return -EINVAL;
4424 return 0;
4425 }
4426}
Patrick McHardy1ec10212015-04-11 02:27:27 +01004427EXPORT_SYMBOL_GPL(nft_validate_register_store);
Patrick McHardy96518512013-10-14 11:00:02 +02004428
4429static const struct nla_policy nft_verdict_policy[NFTA_VERDICT_MAX + 1] = {
4430 [NFTA_VERDICT_CODE] = { .type = NLA_U32 },
4431 [NFTA_VERDICT_CHAIN] = { .type = NLA_STRING,
4432 .len = NFT_CHAIN_MAXNAMELEN - 1 },
4433};
4434
4435static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
4436 struct nft_data_desc *desc, const struct nlattr *nla)
4437{
4438 struct nlattr *tb[NFTA_VERDICT_MAX + 1];
4439 struct nft_chain *chain;
4440 int err;
4441
4442 err = nla_parse_nested(tb, NFTA_VERDICT_MAX, nla, nft_verdict_policy);
4443 if (err < 0)
4444 return err;
4445
4446 if (!tb[NFTA_VERDICT_CODE])
4447 return -EINVAL;
Patrick McHardy1ca2e172015-04-11 02:27:32 +01004448 data->verdict.code = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE]));
Patrick McHardy96518512013-10-14 11:00:02 +02004449
Patrick McHardy1ca2e172015-04-11 02:27:32 +01004450 switch (data->verdict.code) {
Patrick McHardye0abdad2014-02-18 18:06:50 +00004451 default:
Patrick McHardy1ca2e172015-04-11 02:27:32 +01004452 switch (data->verdict.code & NF_VERDICT_MASK) {
Patrick McHardye0abdad2014-02-18 18:06:50 +00004453 case NF_ACCEPT:
4454 case NF_DROP:
4455 case NF_QUEUE:
4456 break;
4457 default:
4458 return -EINVAL;
4459 }
4460 /* fall through */
Patrick McHardy96518512013-10-14 11:00:02 +02004461 case NFT_CONTINUE:
4462 case NFT_BREAK:
4463 case NFT_RETURN:
Patrick McHardy96518512013-10-14 11:00:02 +02004464 break;
4465 case NFT_JUMP:
4466 case NFT_GOTO:
4467 if (!tb[NFTA_VERDICT_CHAIN])
4468 return -EINVAL;
4469 chain = nf_tables_chain_lookup(ctx->table,
4470 tb[NFTA_VERDICT_CHAIN]);
4471 if (IS_ERR(chain))
4472 return PTR_ERR(chain);
4473 if (chain->flags & NFT_BASE_CHAIN)
4474 return -EOPNOTSUPP;
4475
Patrick McHardy96518512013-10-14 11:00:02 +02004476 chain->use++;
Patrick McHardy1ca2e172015-04-11 02:27:32 +01004477 data->verdict.chain = chain;
Patrick McHardy96518512013-10-14 11:00:02 +02004478 break;
Patrick McHardy96518512013-10-14 11:00:02 +02004479 }
4480
Florian Westphal4c4ed072015-04-14 16:44:14 +02004481 desc->len = sizeof(data->verdict);
Patrick McHardy96518512013-10-14 11:00:02 +02004482 desc->type = NFT_DATA_VERDICT;
4483 return 0;
4484}
4485
4486static void nft_verdict_uninit(const struct nft_data *data)
4487{
Patrick McHardy1ca2e172015-04-11 02:27:32 +01004488 switch (data->verdict.code) {
Patrick McHardy96518512013-10-14 11:00:02 +02004489 case NFT_JUMP:
4490 case NFT_GOTO:
Patrick McHardy1ca2e172015-04-11 02:27:32 +01004491 data->verdict.chain->use--;
Patrick McHardy96518512013-10-14 11:00:02 +02004492 break;
4493 }
4494}
4495
Florian Westphal33d5a7b2015-11-28 21:53:04 +01004496int nft_verdict_dump(struct sk_buff *skb, int type, const struct nft_verdict *v)
Patrick McHardy96518512013-10-14 11:00:02 +02004497{
4498 struct nlattr *nest;
4499
Florian Westphal33d5a7b2015-11-28 21:53:04 +01004500 nest = nla_nest_start(skb, type);
Patrick McHardy96518512013-10-14 11:00:02 +02004501 if (!nest)
4502 goto nla_put_failure;
4503
Florian Westphal33d5a7b2015-11-28 21:53:04 +01004504 if (nla_put_be32(skb, NFTA_VERDICT_CODE, htonl(v->code)))
Patrick McHardy96518512013-10-14 11:00:02 +02004505 goto nla_put_failure;
4506
Florian Westphal33d5a7b2015-11-28 21:53:04 +01004507 switch (v->code) {
Patrick McHardy96518512013-10-14 11:00:02 +02004508 case NFT_JUMP:
4509 case NFT_GOTO:
Patrick McHardy1ca2e172015-04-11 02:27:32 +01004510 if (nla_put_string(skb, NFTA_VERDICT_CHAIN,
Florian Westphal33d5a7b2015-11-28 21:53:04 +01004511 v->chain->name))
Patrick McHardy96518512013-10-14 11:00:02 +02004512 goto nla_put_failure;
4513 }
4514 nla_nest_end(skb, nest);
4515 return 0;
4516
4517nla_put_failure:
4518 return -1;
4519}
4520
Patrick McHardyd0a11fc2015-04-11 02:27:38 +01004521static int nft_value_init(const struct nft_ctx *ctx,
4522 struct nft_data *data, unsigned int size,
Patrick McHardy96518512013-10-14 11:00:02 +02004523 struct nft_data_desc *desc, const struct nlattr *nla)
4524{
4525 unsigned int len;
4526
4527 len = nla_len(nla);
4528 if (len == 0)
4529 return -EINVAL;
Patrick McHardyd0a11fc2015-04-11 02:27:38 +01004530 if (len > size)
Patrick McHardy96518512013-10-14 11:00:02 +02004531 return -EOVERFLOW;
4532
Patrick McHardyd0a11fc2015-04-11 02:27:38 +01004533 nla_memcpy(data->data, nla, len);
Patrick McHardy96518512013-10-14 11:00:02 +02004534 desc->type = NFT_DATA_VALUE;
4535 desc->len = len;
4536 return 0;
4537}
4538
4539static int nft_value_dump(struct sk_buff *skb, const struct nft_data *data,
4540 unsigned int len)
4541{
4542 return nla_put(skb, NFTA_DATA_VALUE, len, data->data);
4543}
4544
4545static const struct nla_policy nft_data_policy[NFTA_DATA_MAX + 1] = {
Patrick McHardyd0a11fc2015-04-11 02:27:38 +01004546 [NFTA_DATA_VALUE] = { .type = NLA_BINARY },
Patrick McHardy96518512013-10-14 11:00:02 +02004547 [NFTA_DATA_VERDICT] = { .type = NLA_NESTED },
4548};
4549
4550/**
4551 * nft_data_init - parse nf_tables data netlink attributes
4552 *
4553 * @ctx: context of the expression using the data
4554 * @data: destination struct nft_data
Patrick McHardyd0a11fc2015-04-11 02:27:38 +01004555 * @size: maximum data length
Patrick McHardy96518512013-10-14 11:00:02 +02004556 * @desc: data description
4557 * @nla: netlink attribute containing data
4558 *
4559 * Parse the netlink data attributes and initialize a struct nft_data.
4560 * The type and length of data are returned in the data description.
4561 *
4562 * The caller can indicate that it only wants to accept data of type
4563 * NFT_DATA_VALUE by passing NULL for the ctx argument.
4564 */
Patrick McHardyd0a11fc2015-04-11 02:27:38 +01004565int nft_data_init(const struct nft_ctx *ctx,
4566 struct nft_data *data, unsigned int size,
Patrick McHardy96518512013-10-14 11:00:02 +02004567 struct nft_data_desc *desc, const struct nlattr *nla)
4568{
4569 struct nlattr *tb[NFTA_DATA_MAX + 1];
4570 int err;
4571
4572 err = nla_parse_nested(tb, NFTA_DATA_MAX, nla, nft_data_policy);
4573 if (err < 0)
4574 return err;
4575
4576 if (tb[NFTA_DATA_VALUE])
Patrick McHardyd0a11fc2015-04-11 02:27:38 +01004577 return nft_value_init(ctx, data, size, desc,
4578 tb[NFTA_DATA_VALUE]);
Patrick McHardy96518512013-10-14 11:00:02 +02004579 if (tb[NFTA_DATA_VERDICT] && ctx != NULL)
4580 return nft_verdict_init(ctx, data, desc, tb[NFTA_DATA_VERDICT]);
4581 return -EINVAL;
4582}
4583EXPORT_SYMBOL_GPL(nft_data_init);
4584
4585/**
4586 * nft_data_uninit - release a nft_data item
4587 *
4588 * @data: struct nft_data to release
4589 * @type: type of data
4590 *
4591 * Release a nft_data item. NFT_DATA_VALUE types can be silently discarded,
4592 * all others need to be released by calling this function.
4593 */
4594void nft_data_uninit(const struct nft_data *data, enum nft_data_types type)
4595{
Mirek Kratochvil960bd2c2015-05-15 21:15:29 +02004596 if (type < NFT_DATA_VERDICT)
Patrick McHardy96518512013-10-14 11:00:02 +02004597 return;
Mirek Kratochvil960bd2c2015-05-15 21:15:29 +02004598 switch (type) {
Patrick McHardy96518512013-10-14 11:00:02 +02004599 case NFT_DATA_VERDICT:
4600 return nft_verdict_uninit(data);
4601 default:
4602 WARN_ON(1);
4603 }
4604}
4605EXPORT_SYMBOL_GPL(nft_data_uninit);
4606
4607int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
4608 enum nft_data_types type, unsigned int len)
4609{
4610 struct nlattr *nest;
4611 int err;
4612
4613 nest = nla_nest_start(skb, attr);
4614 if (nest == NULL)
4615 return -1;
4616
4617 switch (type) {
4618 case NFT_DATA_VALUE:
4619 err = nft_value_dump(skb, data, len);
4620 break;
4621 case NFT_DATA_VERDICT:
Florian Westphal33d5a7b2015-11-28 21:53:04 +01004622 err = nft_verdict_dump(skb, NFTA_DATA_VERDICT, &data->verdict);
Patrick McHardy96518512013-10-14 11:00:02 +02004623 break;
4624 default:
4625 err = -EINVAL;
4626 WARN_ON(1);
4627 }
4628
4629 nla_nest_end(skb, nest);
4630 return err;
4631}
4632EXPORT_SYMBOL_GPL(nft_data_dump);
4633
Pablo Neira Ayusodf05ef82015-12-15 19:39:32 +01004634static int __net_init nf_tables_init_net(struct net *net)
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02004635{
4636 INIT_LIST_HEAD(&net->nft.af_info);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02004637 INIT_LIST_HEAD(&net->nft.commit_list);
Pablo Neira Ayuso38e029f2014-07-01 12:23:12 +02004638 net->nft.base_seq = 1;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02004639 return 0;
4640}
4641
Pablo Neira Ayuso5ebe0b02015-12-15 19:40:49 +01004642int __nft_release_basechain(struct nft_ctx *ctx)
4643{
4644 struct nft_rule *rule, *nr;
4645
4646 BUG_ON(!(ctx->chain->flags & NFT_BASE_CHAIN));
4647
4648 nf_tables_unregister_hooks(ctx->chain->table, ctx->chain,
4649 ctx->afi->nops);
4650 list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
4651 list_del(&rule->list);
4652 ctx->chain->use--;
4653 nf_tables_rule_destroy(ctx, rule);
4654 }
4655 list_del(&ctx->chain->list);
4656 ctx->table->use--;
4657 nf_tables_chain_destroy(ctx->chain);
4658
4659 return 0;
4660}
4661EXPORT_SYMBOL_GPL(__nft_release_basechain);
4662
Pablo Neira Ayusodf05ef82015-12-15 19:39:32 +01004663/* Called by nft_unregister_afinfo() from __net_exit path, nfnl_lock is held. */
4664static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi)
4665{
4666 struct nft_table *table, *nt;
4667 struct nft_chain *chain, *nc;
4668 struct nft_rule *rule, *nr;
4669 struct nft_set *set, *ns;
4670 struct nft_ctx ctx = {
4671 .net = net,
4672 .afi = afi,
4673 };
4674
4675 list_for_each_entry_safe(table, nt, &afi->tables, list) {
4676 list_for_each_entry(chain, &table->chains, list)
4677 nf_tables_unregister_hooks(table, chain, afi->nops);
4678 /* No packets are walking on these chains anymore. */
4679 ctx.table = table;
4680 list_for_each_entry(chain, &table->chains, list) {
4681 ctx.chain = chain;
4682 list_for_each_entry_safe(rule, nr, &chain->rules, list) {
4683 list_del(&rule->list);
4684 chain->use--;
4685 nf_tables_rule_destroy(&ctx, rule);
4686 }
4687 }
4688 list_for_each_entry_safe(set, ns, &table->sets, list) {
4689 list_del(&set->list);
4690 table->use--;
4691 nft_set_destroy(set);
4692 }
4693 list_for_each_entry_safe(chain, nc, &table->chains, list) {
4694 list_del(&chain->list);
4695 table->use--;
4696 nf_tables_chain_destroy(chain);
4697 }
4698 list_del(&table->list);
4699 nf_tables_table_destroy(&ctx);
4700 }
4701}
4702
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02004703static struct pernet_operations nf_tables_net_ops = {
4704 .init = nf_tables_init_net,
4705};
4706
Patrick McHardy96518512013-10-14 11:00:02 +02004707static int __init nf_tables_module_init(void)
4708{
4709 int err;
4710
4711 info = kmalloc(sizeof(struct nft_expr_info) * NFT_RULE_MAXEXPRS,
4712 GFP_KERNEL);
4713 if (info == NULL) {
4714 err = -ENOMEM;
4715 goto err1;
4716 }
4717
4718 err = nf_tables_core_module_init();
4719 if (err < 0)
4720 goto err2;
4721
4722 err = nfnetlink_subsys_register(&nf_tables_subsys);
4723 if (err < 0)
4724 goto err3;
4725
4726 pr_info("nf_tables: (c) 2007-2009 Patrick McHardy <kaber@trash.net>\n");
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02004727 return register_pernet_subsys(&nf_tables_net_ops);
Patrick McHardy96518512013-10-14 11:00:02 +02004728err3:
4729 nf_tables_core_module_exit();
4730err2:
4731 kfree(info);
4732err1:
4733 return err;
4734}
4735
4736static void __exit nf_tables_module_exit(void)
4737{
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02004738 unregister_pernet_subsys(&nf_tables_net_ops);
Patrick McHardy96518512013-10-14 11:00:02 +02004739 nfnetlink_subsys_unregister(&nf_tables_subsys);
Pablo Neira Ayuso1b1bc492014-10-01 13:53:20 +02004740 rcu_barrier();
Patrick McHardy96518512013-10-14 11:00:02 +02004741 nf_tables_core_module_exit();
4742 kfree(info);
4743}
4744
4745module_init(nf_tables_module_init);
4746module_exit(nf_tables_module_exit);
4747
4748MODULE_LICENSE("GPL");
4749MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
4750MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFTABLES);