blob: 424a6f3cb6c559c3ddaf8761ca9264368bc4864f [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 Ayuso99633ab2013-10-10 23:28:33 +020038 list_add_tail(&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
44/**
45 * nft_unregister_afinfo - unregister nf_tables address family info
46 *
47 * @afi: address family info to unregister
48 *
49 * Unregister the address family for use with nf_tables.
50 */
51void nft_unregister_afinfo(struct nft_af_info *afi)
52{
53 nfnl_lock(NFNL_SUBSYS_NFTABLES);
54 list_del(&afi->list);
55 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
56}
57EXPORT_SYMBOL_GPL(nft_unregister_afinfo);
58
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020059static struct nft_af_info *nft_afinfo_lookup(struct net *net, int family)
Patrick McHardy96518512013-10-14 11:00:02 +020060{
61 struct nft_af_info *afi;
62
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020063 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +020064 if (afi->family == family)
65 return afi;
66 }
67 return NULL;
68}
69
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020070static struct nft_af_info *
71nf_tables_afinfo_lookup(struct net *net, int family, bool autoload)
Patrick McHardy96518512013-10-14 11:00:02 +020072{
73 struct nft_af_info *afi;
74
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020075 afi = nft_afinfo_lookup(net, family);
Patrick McHardy96518512013-10-14 11:00:02 +020076 if (afi != NULL)
77 return afi;
78#ifdef CONFIG_MODULES
79 if (autoload) {
80 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
81 request_module("nft-afinfo-%u", family);
82 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020083 afi = nft_afinfo_lookup(net, family);
Patrick McHardy96518512013-10-14 11:00:02 +020084 if (afi != NULL)
85 return ERR_PTR(-EAGAIN);
86 }
87#endif
88 return ERR_PTR(-EAFNOSUPPORT);
89}
90
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +020091static void nft_ctx_init(struct nft_ctx *ctx,
92 const struct sk_buff *skb,
93 const struct nlmsghdr *nlh,
94 struct nft_af_info *afi,
95 struct nft_table *table,
96 struct nft_chain *chain,
97 const struct nlattr * const *nla)
98{
99 ctx->net = sock_net(skb->sk);
100 ctx->skb = skb;
101 ctx->nlh = nlh;
102 ctx->afi = afi;
103 ctx->table = table;
104 ctx->chain = chain;
105 ctx->nla = nla;
106}
107
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +0200108static struct nft_trans *nft_trans_alloc(struct nft_ctx *ctx, u32 size)
109{
110 struct nft_trans *trans;
111
112 trans = kzalloc(sizeof(struct nft_trans) + size, GFP_KERNEL);
113 if (trans == NULL)
114 return NULL;
115
116 trans->ctx = *ctx;
117
118 return trans;
119}
120
121static void nft_trans_destroy(struct nft_trans *trans)
122{
123 list_del(&trans->list);
124 kfree(trans);
125}
126
Patrick McHardy96518512013-10-14 11:00:02 +0200127/*
128 * Tables
129 */
130
131static struct nft_table *nft_table_lookup(const struct nft_af_info *afi,
132 const struct nlattr *nla)
133{
134 struct nft_table *table;
135
136 list_for_each_entry(table, &afi->tables, list) {
137 if (!nla_strcmp(nla, table->name))
138 return table;
139 }
140 return NULL;
141}
142
143static struct nft_table *nf_tables_table_lookup(const struct nft_af_info *afi,
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200144 const struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +0200145{
146 struct nft_table *table;
147
148 if (nla == NULL)
149 return ERR_PTR(-EINVAL);
150
151 table = nft_table_lookup(afi, nla);
152 if (table != NULL)
153 return table;
154
Patrick McHardy96518512013-10-14 11:00:02 +0200155 return ERR_PTR(-ENOENT);
156}
157
158static inline u64 nf_tables_alloc_handle(struct nft_table *table)
159{
160 return ++table->hgenerator;
161}
162
Patrick McHardy2a37d752014-01-09 18:42:37 +0000163static const struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200164
Patrick McHardy2a37d752014-01-09 18:42:37 +0000165static const struct nf_chain_type *
Patrick McHardybaae3e62014-01-09 18:42:34 +0000166__nf_tables_chain_type_lookup(int family, const struct nlattr *nla)
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200167{
168 int i;
169
Patrick McHardybaae3e62014-01-09 18:42:34 +0000170 for (i = 0; i < NFT_CHAIN_T_MAX; i++) {
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200171 if (chain_type[family][i] != NULL &&
172 !nla_strcmp(nla, chain_type[family][i]->name))
Patrick McHardybaae3e62014-01-09 18:42:34 +0000173 return chain_type[family][i];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200174 }
Patrick McHardybaae3e62014-01-09 18:42:34 +0000175 return NULL;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200176}
177
Patrick McHardy2a37d752014-01-09 18:42:37 +0000178static const struct nf_chain_type *
Patrick McHardybaae3e62014-01-09 18:42:34 +0000179nf_tables_chain_type_lookup(const struct nft_af_info *afi,
180 const struct nlattr *nla,
181 bool autoload)
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200182{
Patrick McHardy2a37d752014-01-09 18:42:37 +0000183 const struct nf_chain_type *type;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200184
185 type = __nf_tables_chain_type_lookup(afi->family, nla);
Patrick McHardy93b08062014-01-09 18:42:36 +0000186 if (type != NULL)
187 return type;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200188#ifdef CONFIG_MODULES
Patrick McHardy93b08062014-01-09 18:42:36 +0000189 if (autoload) {
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200190 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
191 request_module("nft-chain-%u-%*.s", afi->family,
192 nla_len(nla)-1, (const char *)nla_data(nla));
193 nfnl_lock(NFNL_SUBSYS_NFTABLES);
194 type = __nf_tables_chain_type_lookup(afi->family, nla);
Patrick McHardy93b08062014-01-09 18:42:36 +0000195 if (type != NULL)
196 return ERR_PTR(-EAGAIN);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200197 }
198#endif
Patrick McHardy93b08062014-01-09 18:42:36 +0000199 return ERR_PTR(-ENOENT);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200200}
201
Patrick McHardy96518512013-10-14 11:00:02 +0200202static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
203 [NFTA_TABLE_NAME] = { .type = NLA_STRING },
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200204 [NFTA_TABLE_FLAGS] = { .type = NLA_U32 },
Patrick McHardy96518512013-10-14 11:00:02 +0200205};
206
207static int nf_tables_fill_table_info(struct sk_buff *skb, u32 portid, u32 seq,
208 int event, u32 flags, int family,
209 const struct nft_table *table)
210{
211 struct nlmsghdr *nlh;
212 struct nfgenmsg *nfmsg;
213
214 event |= NFNL_SUBSYS_NFTABLES << 8;
215 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
216 if (nlh == NULL)
217 goto nla_put_failure;
218
219 nfmsg = nlmsg_data(nlh);
220 nfmsg->nfgen_family = family;
221 nfmsg->version = NFNETLINK_V0;
222 nfmsg->res_id = 0;
223
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200224 if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
Tomasz Bursztykad8bcc7682013-12-12 15:00:42 +0200225 nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
226 nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)))
Patrick McHardy96518512013-10-14 11:00:02 +0200227 goto nla_put_failure;
228
229 return nlmsg_end(skb, nlh);
230
231nla_put_failure:
232 nlmsg_trim(skb, nlh);
233 return -1;
234}
235
236static int nf_tables_table_notify(const struct sk_buff *oskb,
237 const struct nlmsghdr *nlh,
238 const struct nft_table *table,
239 int event, int family)
240{
241 struct sk_buff *skb;
242 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
243 u32 seq = nlh ? nlh->nlmsg_seq : 0;
244 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
245 bool report;
246 int err;
247
248 report = nlh ? nlmsg_report(nlh) : false;
249 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
250 return 0;
251
252 err = -ENOBUFS;
253 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
254 if (skb == NULL)
255 goto err;
256
257 err = nf_tables_fill_table_info(skb, portid, seq, event, 0,
258 family, table);
259 if (err < 0) {
260 kfree_skb(skb);
261 goto err;
262 }
263
264 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
265 GFP_KERNEL);
266err:
267 if (err < 0)
268 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
269 return err;
270}
271
272static int nf_tables_dump_tables(struct sk_buff *skb,
273 struct netlink_callback *cb)
274{
275 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
276 const struct nft_af_info *afi;
277 const struct nft_table *table;
278 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200279 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200280 int family = nfmsg->nfgen_family;
281
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200282 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +0200283 if (family != NFPROTO_UNSPEC && family != afi->family)
284 continue;
285
286 list_for_each_entry(table, &afi->tables, list) {
287 if (idx < s_idx)
288 goto cont;
289 if (idx > s_idx)
290 memset(&cb->args[1], 0,
291 sizeof(cb->args) - sizeof(cb->args[0]));
292 if (nf_tables_fill_table_info(skb,
293 NETLINK_CB(cb->skb).portid,
294 cb->nlh->nlmsg_seq,
295 NFT_MSG_NEWTABLE,
296 NLM_F_MULTI,
297 afi->family, table) < 0)
298 goto done;
299cont:
300 idx++;
301 }
302 }
303done:
304 cb->args[0] = idx;
305 return skb->len;
306}
307
308static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb,
309 const struct nlmsghdr *nlh,
310 const struct nlattr * const nla[])
311{
312 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
313 const struct nft_af_info *afi;
314 const struct nft_table *table;
315 struct sk_buff *skb2;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200316 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200317 int family = nfmsg->nfgen_family;
318 int err;
319
320 if (nlh->nlmsg_flags & NLM_F_DUMP) {
321 struct netlink_dump_control c = {
322 .dump = nf_tables_dump_tables,
323 };
324 return netlink_dump_start(nlsk, skb, nlh, &c);
325 }
326
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200327 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200328 if (IS_ERR(afi))
329 return PTR_ERR(afi);
330
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200331 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
Patrick McHardy96518512013-10-14 11:00:02 +0200332 if (IS_ERR(table))
333 return PTR_ERR(table);
334
335 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
336 if (!skb2)
337 return -ENOMEM;
338
339 err = nf_tables_fill_table_info(skb2, NETLINK_CB(skb).portid,
340 nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0,
341 family, table);
342 if (err < 0)
343 goto err;
344
345 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
346
347err:
348 kfree_skb(skb2);
349 return err;
350}
351
Patrick McHardy115a60b2014-01-03 12:16:15 +0000352static int nf_tables_table_enable(const struct nft_af_info *afi,
353 struct nft_table *table)
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200354{
355 struct nft_chain *chain;
356 int err, i = 0;
357
358 list_for_each_entry(chain, &table->chains, list) {
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100359 if (!(chain->flags & NFT_BASE_CHAIN))
360 continue;
361
Patrick McHardy115a60b2014-01-03 12:16:15 +0000362 err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200363 if (err < 0)
364 goto err;
365
366 i++;
367 }
368 return 0;
369err:
370 list_for_each_entry(chain, &table->chains, list) {
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100371 if (!(chain->flags & NFT_BASE_CHAIN))
372 continue;
373
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200374 if (i-- <= 0)
375 break;
376
Patrick McHardy115a60b2014-01-03 12:16:15 +0000377 nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200378 }
379 return err;
380}
381
Patrick McHardy115a60b2014-01-03 12:16:15 +0000382static int nf_tables_table_disable(const struct nft_af_info *afi,
383 struct nft_table *table)
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200384{
385 struct nft_chain *chain;
386
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100387 list_for_each_entry(chain, &table->chains, list) {
388 if (chain->flags & NFT_BASE_CHAIN)
Patrick McHardy115a60b2014-01-03 12:16:15 +0000389 nf_unregister_hooks(nft_base_chain(chain)->ops,
390 afi->nops);
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100391 }
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200392
393 return 0;
394}
395
396static int nf_tables_updtable(struct sock *nlsk, struct sk_buff *skb,
397 const struct nlmsghdr *nlh,
398 const struct nlattr * const nla[],
399 struct nft_af_info *afi, struct nft_table *table)
400{
401 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
402 int family = nfmsg->nfgen_family, ret = 0;
403
404 if (nla[NFTA_TABLE_FLAGS]) {
Patrick McHardyc5c1f972014-01-09 18:42:39 +0000405 u32 flags;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200406
407 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
408 if (flags & ~NFT_TABLE_F_DORMANT)
409 return -EINVAL;
410
411 if ((flags & NFT_TABLE_F_DORMANT) &&
412 !(table->flags & NFT_TABLE_F_DORMANT)) {
Patrick McHardy115a60b2014-01-03 12:16:15 +0000413 ret = nf_tables_table_disable(afi, table);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200414 if (ret >= 0)
415 table->flags |= NFT_TABLE_F_DORMANT;
416 } else if (!(flags & NFT_TABLE_F_DORMANT) &&
417 table->flags & NFT_TABLE_F_DORMANT) {
Patrick McHardy115a60b2014-01-03 12:16:15 +0000418 ret = nf_tables_table_enable(afi, table);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200419 if (ret >= 0)
420 table->flags &= ~NFT_TABLE_F_DORMANT;
421 }
422 if (ret < 0)
423 goto err;
424 }
425
426 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
427err:
428 return ret;
429}
430
Patrick McHardy96518512013-10-14 11:00:02 +0200431static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
432 const struct nlmsghdr *nlh,
433 const struct nlattr * const nla[])
434{
435 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
436 const struct nlattr *name;
437 struct nft_af_info *afi;
438 struct nft_table *table;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200439 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200440 int family = nfmsg->nfgen_family;
Patrick McHardyc5c1f972014-01-09 18:42:39 +0000441 u32 flags = 0;
Patrick McHardy96518512013-10-14 11:00:02 +0200442
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200443 afi = nf_tables_afinfo_lookup(net, family, true);
Patrick McHardy96518512013-10-14 11:00:02 +0200444 if (IS_ERR(afi))
445 return PTR_ERR(afi);
446
447 name = nla[NFTA_TABLE_NAME];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200448 table = nf_tables_table_lookup(afi, name);
Patrick McHardy96518512013-10-14 11:00:02 +0200449 if (IS_ERR(table)) {
450 if (PTR_ERR(table) != -ENOENT)
451 return PTR_ERR(table);
452 table = NULL;
453 }
454
455 if (table != NULL) {
456 if (nlh->nlmsg_flags & NLM_F_EXCL)
457 return -EEXIST;
458 if (nlh->nlmsg_flags & NLM_F_REPLACE)
459 return -EOPNOTSUPP;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200460 return nf_tables_updtable(nlsk, skb, nlh, nla, afi, table);
Patrick McHardy96518512013-10-14 11:00:02 +0200461 }
462
Patrick McHardyc5c1f972014-01-09 18:42:39 +0000463 if (nla[NFTA_TABLE_FLAGS]) {
464 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
465 if (flags & ~NFT_TABLE_F_DORMANT)
466 return -EINVAL;
467 }
468
Patrick McHardy7047f9d2014-01-09 18:42:40 +0000469 if (!try_module_get(afi->owner))
470 return -EAFNOSUPPORT;
471
Patrick McHardy96518512013-10-14 11:00:02 +0200472 table = kzalloc(sizeof(*table) + nla_len(name), GFP_KERNEL);
Patrick McHardy7047f9d2014-01-09 18:42:40 +0000473 if (table == NULL) {
474 module_put(afi->owner);
Patrick McHardy96518512013-10-14 11:00:02 +0200475 return -ENOMEM;
Patrick McHardy7047f9d2014-01-09 18:42:40 +0000476 }
Patrick McHardy96518512013-10-14 11:00:02 +0200477
478 nla_strlcpy(table->name, name, nla_len(name));
479 INIT_LIST_HEAD(&table->chains);
Patrick McHardy20a69342013-10-11 12:06:22 +0200480 INIT_LIST_HEAD(&table->sets);
Patrick McHardyc5c1f972014-01-09 18:42:39 +0000481 table->flags = flags;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200482
Patrick McHardy96518512013-10-14 11:00:02 +0200483 list_add_tail(&table->list, &afi->tables);
484 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
485 return 0;
486}
487
488static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
489 const struct nlmsghdr *nlh,
490 const struct nlattr * const nla[])
491{
492 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
493 struct nft_af_info *afi;
494 struct nft_table *table;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200495 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200496 int family = nfmsg->nfgen_family;
497
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200498 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200499 if (IS_ERR(afi))
500 return PTR_ERR(afi);
501
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200502 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
Patrick McHardy96518512013-10-14 11:00:02 +0200503 if (IS_ERR(table))
504 return PTR_ERR(table);
505
Patrick McHardy44a6f0d2014-01-09 18:42:41 +0000506 if (!list_empty(&table->chains) || !list_empty(&table->sets))
Patrick McHardy96518512013-10-14 11:00:02 +0200507 return -EBUSY;
508
509 list_del(&table->list);
510 nf_tables_table_notify(skb, nlh, table, NFT_MSG_DELTABLE, family);
511 kfree(table);
Patrick McHardy7047f9d2014-01-09 18:42:40 +0000512 module_put(afi->owner);
Patrick McHardy96518512013-10-14 11:00:02 +0200513 return 0;
514}
515
Patrick McHardy2a37d752014-01-09 18:42:37 +0000516int nft_register_chain_type(const struct nf_chain_type *ctype)
Patrick McHardy96518512013-10-14 11:00:02 +0200517{
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200518 int err = 0;
Patrick McHardy96518512013-10-14 11:00:02 +0200519
520 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200521 if (chain_type[ctype->family][ctype->type] != NULL) {
522 err = -EBUSY;
523 goto out;
Patrick McHardy96518512013-10-14 11:00:02 +0200524 }
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200525 chain_type[ctype->family][ctype->type] = ctype;
526out:
Patrick McHardy96518512013-10-14 11:00:02 +0200527 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
528 return err;
529}
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200530EXPORT_SYMBOL_GPL(nft_register_chain_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200531
Patrick McHardy2a37d752014-01-09 18:42:37 +0000532void nft_unregister_chain_type(const struct nf_chain_type *ctype)
Patrick McHardy96518512013-10-14 11:00:02 +0200533{
Patrick McHardy96518512013-10-14 11:00:02 +0200534 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200535 chain_type[ctype->family][ctype->type] = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +0200536 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
537}
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200538EXPORT_SYMBOL_GPL(nft_unregister_chain_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200539
540/*
541 * Chains
542 */
543
544static struct nft_chain *
545nf_tables_chain_lookup_byhandle(const struct nft_table *table, u64 handle)
546{
547 struct nft_chain *chain;
548
549 list_for_each_entry(chain, &table->chains, list) {
550 if (chain->handle == handle)
551 return chain;
552 }
553
554 return ERR_PTR(-ENOENT);
555}
556
557static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table,
558 const struct nlattr *nla)
559{
560 struct nft_chain *chain;
561
562 if (nla == NULL)
563 return ERR_PTR(-EINVAL);
564
565 list_for_each_entry(chain, &table->chains, list) {
566 if (!nla_strcmp(nla, chain->name))
567 return chain;
568 }
569
570 return ERR_PTR(-ENOENT);
571}
572
573static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
574 [NFTA_CHAIN_TABLE] = { .type = NLA_STRING },
575 [NFTA_CHAIN_HANDLE] = { .type = NLA_U64 },
576 [NFTA_CHAIN_NAME] = { .type = NLA_STRING,
577 .len = NFT_CHAIN_MAXNAMELEN - 1 },
578 [NFTA_CHAIN_HOOK] = { .type = NLA_NESTED },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200579 [NFTA_CHAIN_POLICY] = { .type = NLA_U32 },
Pablo Neira4c1f7812014-03-31 17:43:47 +0200580 [NFTA_CHAIN_TYPE] = { .type = NLA_STRING },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200581 [NFTA_CHAIN_COUNTERS] = { .type = NLA_NESTED },
Patrick McHardy96518512013-10-14 11:00:02 +0200582};
583
584static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = {
585 [NFTA_HOOK_HOOKNUM] = { .type = NLA_U32 },
586 [NFTA_HOOK_PRIORITY] = { .type = NLA_U32 },
587};
588
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200589static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats)
590{
591 struct nft_stats *cpu_stats, total;
592 struct nlattr *nest;
593 int cpu;
594
595 memset(&total, 0, sizeof(total));
596 for_each_possible_cpu(cpu) {
597 cpu_stats = per_cpu_ptr(stats, cpu);
598 total.pkts += cpu_stats->pkts;
599 total.bytes += cpu_stats->bytes;
600 }
601 nest = nla_nest_start(skb, NFTA_CHAIN_COUNTERS);
602 if (nest == NULL)
603 goto nla_put_failure;
604
605 if (nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(total.pkts)) ||
606 nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes)))
607 goto nla_put_failure;
608
609 nla_nest_end(skb, nest);
610 return 0;
611
612nla_put_failure:
613 return -ENOSPC;
614}
615
Patrick McHardy96518512013-10-14 11:00:02 +0200616static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq,
617 int event, u32 flags, int family,
618 const struct nft_table *table,
619 const struct nft_chain *chain)
620{
621 struct nlmsghdr *nlh;
622 struct nfgenmsg *nfmsg;
623
624 event |= NFNL_SUBSYS_NFTABLES << 8;
625 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
626 if (nlh == NULL)
627 goto nla_put_failure;
628
629 nfmsg = nlmsg_data(nlh);
630 nfmsg->nfgen_family = family;
631 nfmsg->version = NFNETLINK_V0;
632 nfmsg->res_id = 0;
633
634 if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name))
635 goto nla_put_failure;
636 if (nla_put_be64(skb, NFTA_CHAIN_HANDLE, cpu_to_be64(chain->handle)))
637 goto nla_put_failure;
638 if (nla_put_string(skb, NFTA_CHAIN_NAME, chain->name))
639 goto nla_put_failure;
640
641 if (chain->flags & NFT_BASE_CHAIN) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200642 const struct nft_base_chain *basechain = nft_base_chain(chain);
Patrick McHardy115a60b2014-01-03 12:16:15 +0000643 const struct nf_hook_ops *ops = &basechain->ops[0];
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200644 struct nlattr *nest;
645
646 nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
Patrick McHardy96518512013-10-14 11:00:02 +0200647 if (nest == NULL)
648 goto nla_put_failure;
649 if (nla_put_be32(skb, NFTA_HOOK_HOOKNUM, htonl(ops->hooknum)))
650 goto nla_put_failure;
651 if (nla_put_be32(skb, NFTA_HOOK_PRIORITY, htonl(ops->priority)))
652 goto nla_put_failure;
653 nla_nest_end(skb, nest);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200654
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200655 if (nla_put_be32(skb, NFTA_CHAIN_POLICY,
656 htonl(basechain->policy)))
657 goto nla_put_failure;
658
Patrick McHardybaae3e62014-01-09 18:42:34 +0000659 if (nla_put_string(skb, NFTA_CHAIN_TYPE, basechain->type->name))
660 goto nla_put_failure;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200661
662 if (nft_dump_stats(skb, nft_base_chain(chain)->stats))
663 goto nla_put_failure;
Patrick McHardy96518512013-10-14 11:00:02 +0200664 }
665
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200666 if (nla_put_be32(skb, NFTA_CHAIN_USE, htonl(chain->use)))
667 goto nla_put_failure;
668
Patrick McHardy96518512013-10-14 11:00:02 +0200669 return nlmsg_end(skb, nlh);
670
671nla_put_failure:
672 nlmsg_trim(skb, nlh);
673 return -1;
674}
675
676static int nf_tables_chain_notify(const struct sk_buff *oskb,
677 const struct nlmsghdr *nlh,
678 const struct nft_table *table,
679 const struct nft_chain *chain,
680 int event, int family)
681{
682 struct sk_buff *skb;
683 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
684 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
685 u32 seq = nlh ? nlh->nlmsg_seq : 0;
686 bool report;
687 int err;
688
689 report = nlh ? nlmsg_report(nlh) : false;
690 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
691 return 0;
692
693 err = -ENOBUFS;
694 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
695 if (skb == NULL)
696 goto err;
697
698 err = nf_tables_fill_chain_info(skb, portid, seq, event, 0, family,
699 table, chain);
700 if (err < 0) {
701 kfree_skb(skb);
702 goto err;
703 }
704
705 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
706 GFP_KERNEL);
707err:
708 if (err < 0)
709 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
710 return err;
711}
712
713static int nf_tables_dump_chains(struct sk_buff *skb,
714 struct netlink_callback *cb)
715{
716 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
717 const struct nft_af_info *afi;
718 const struct nft_table *table;
719 const struct nft_chain *chain;
720 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200721 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200722 int family = nfmsg->nfgen_family;
723
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200724 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +0200725 if (family != NFPROTO_UNSPEC && family != afi->family)
726 continue;
727
728 list_for_each_entry(table, &afi->tables, list) {
729 list_for_each_entry(chain, &table->chains, list) {
730 if (idx < s_idx)
731 goto cont;
732 if (idx > s_idx)
733 memset(&cb->args[1], 0,
734 sizeof(cb->args) - sizeof(cb->args[0]));
735 if (nf_tables_fill_chain_info(skb, NETLINK_CB(cb->skb).portid,
736 cb->nlh->nlmsg_seq,
737 NFT_MSG_NEWCHAIN,
738 NLM_F_MULTI,
739 afi->family, table, chain) < 0)
740 goto done;
741cont:
742 idx++;
743 }
744 }
745 }
746done:
747 cb->args[0] = idx;
748 return skb->len;
749}
750
751
752static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb,
753 const struct nlmsghdr *nlh,
754 const struct nlattr * const nla[])
755{
756 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
757 const struct nft_af_info *afi;
758 const struct nft_table *table;
759 const struct nft_chain *chain;
760 struct sk_buff *skb2;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200761 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200762 int family = nfmsg->nfgen_family;
763 int err;
764
765 if (nlh->nlmsg_flags & NLM_F_DUMP) {
766 struct netlink_dump_control c = {
767 .dump = nf_tables_dump_chains,
768 };
769 return netlink_dump_start(nlsk, skb, nlh, &c);
770 }
771
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200772 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200773 if (IS_ERR(afi))
774 return PTR_ERR(afi);
775
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200776 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +0200777 if (IS_ERR(table))
778 return PTR_ERR(table);
779
780 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
781 if (IS_ERR(chain))
782 return PTR_ERR(chain);
783
784 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
785 if (!skb2)
786 return -ENOMEM;
787
788 err = nf_tables_fill_chain_info(skb2, NETLINK_CB(skb).portid,
789 nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0,
790 family, table, chain);
791 if (err < 0)
792 goto err;
793
794 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
795
796err:
797 kfree_skb(skb2);
798 return err;
799}
800
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200801static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = {
802 [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 },
803 [NFTA_COUNTER_BYTES] = { .type = NLA_U64 },
804};
805
806static int
807nf_tables_counters(struct nft_base_chain *chain, const struct nlattr *attr)
808{
809 struct nlattr *tb[NFTA_COUNTER_MAX+1];
810 struct nft_stats __percpu *newstats;
811 struct nft_stats *stats;
812 int err;
813
814 err = nla_parse_nested(tb, NFTA_COUNTER_MAX, attr, nft_counter_policy);
815 if (err < 0)
816 return err;
817
818 if (!tb[NFTA_COUNTER_BYTES] || !tb[NFTA_COUNTER_PACKETS])
819 return -EINVAL;
820
821 newstats = alloc_percpu(struct nft_stats);
822 if (newstats == NULL)
823 return -ENOMEM;
824
825 /* Restore old counters on this cpu, no problem. Per-cpu statistics
826 * are not exposed to userspace.
827 */
828 stats = this_cpu_ptr(newstats);
829 stats->bytes = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES]));
830 stats->pkts = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS]));
831
832 if (chain->stats) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200833 struct nft_stats __percpu *oldstats =
Patrick McHardy67a8fc22014-02-18 18:06:49 +0000834 nft_dereference(chain->stats);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200835
836 rcu_assign_pointer(chain->stats, newstats);
837 synchronize_rcu();
838 free_percpu(oldstats);
839 } else
840 rcu_assign_pointer(chain->stats, newstats);
841
842 return 0;
843}
844
Patrick McHardy96518512013-10-14 11:00:02 +0200845static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
846 const struct nlmsghdr *nlh,
847 const struct nlattr * const nla[])
848{
849 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
850 const struct nlattr * uninitialized_var(name);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +0200851 struct nft_af_info *afi;
Patrick McHardy96518512013-10-14 11:00:02 +0200852 struct nft_table *table;
853 struct nft_chain *chain;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200854 struct nft_base_chain *basechain = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +0200855 struct nlattr *ha[NFTA_HOOK_MAX + 1];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200856 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200857 int family = nfmsg->nfgen_family;
Patrick McHardy57de2a02014-01-09 18:42:31 +0000858 u8 policy = NF_ACCEPT;
Patrick McHardy96518512013-10-14 11:00:02 +0200859 u64 handle = 0;
Patrick McHardy115a60b2014-01-03 12:16:15 +0000860 unsigned int i;
Patrick McHardy96518512013-10-14 11:00:02 +0200861 int err;
862 bool create;
863
864 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
865
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200866 afi = nf_tables_afinfo_lookup(net, family, true);
Patrick McHardy96518512013-10-14 11:00:02 +0200867 if (IS_ERR(afi))
868 return PTR_ERR(afi);
869
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200870 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +0200871 if (IS_ERR(table))
872 return PTR_ERR(table);
873
Patrick McHardy96518512013-10-14 11:00:02 +0200874 chain = NULL;
875 name = nla[NFTA_CHAIN_NAME];
876
877 if (nla[NFTA_CHAIN_HANDLE]) {
878 handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
879 chain = nf_tables_chain_lookup_byhandle(table, handle);
880 if (IS_ERR(chain))
881 return PTR_ERR(chain);
882 } else {
883 chain = nf_tables_chain_lookup(table, name);
884 if (IS_ERR(chain)) {
885 if (PTR_ERR(chain) != -ENOENT)
886 return PTR_ERR(chain);
887 chain = NULL;
888 }
889 }
890
Patrick McHardy57de2a02014-01-09 18:42:31 +0000891 if (nla[NFTA_CHAIN_POLICY]) {
892 if ((chain != NULL &&
893 !(chain->flags & NFT_BASE_CHAIN)) ||
894 nla[NFTA_CHAIN_HOOK] == NULL)
895 return -EOPNOTSUPP;
896
Pablo Neira Ayuso8f46df12014-01-10 15:11:25 +0100897 policy = ntohl(nla_get_be32(nla[NFTA_CHAIN_POLICY]));
Patrick McHardy57de2a02014-01-09 18:42:31 +0000898 switch (policy) {
899 case NF_DROP:
900 case NF_ACCEPT:
901 break;
902 default:
903 return -EINVAL;
904 }
905 }
906
Patrick McHardy96518512013-10-14 11:00:02 +0200907 if (chain != NULL) {
908 if (nlh->nlmsg_flags & NLM_F_EXCL)
909 return -EEXIST;
910 if (nlh->nlmsg_flags & NLM_F_REPLACE)
911 return -EOPNOTSUPP;
912
913 if (nla[NFTA_CHAIN_HANDLE] && name &&
914 !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME])))
915 return -EEXIST;
916
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200917 if (nla[NFTA_CHAIN_COUNTERS]) {
918 if (!(chain->flags & NFT_BASE_CHAIN))
919 return -EOPNOTSUPP;
920
921 err = nf_tables_counters(nft_base_chain(chain),
922 nla[NFTA_CHAIN_COUNTERS]);
923 if (err < 0)
924 return err;
925 }
926
Patrick McHardy4401a862014-01-09 18:42:32 +0000927 if (nla[NFTA_CHAIN_POLICY])
928 nft_base_chain(chain)->policy = policy;
929
Patrick McHardy96518512013-10-14 11:00:02 +0200930 if (nla[NFTA_CHAIN_HANDLE] && name)
931 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
932
933 goto notify;
934 }
935
Patrick McHardy75820672014-01-09 18:42:33 +0000936 if (table->use == UINT_MAX)
937 return -EOVERFLOW;
938
Patrick McHardy96518512013-10-14 11:00:02 +0200939 if (nla[NFTA_CHAIN_HOOK]) {
Patrick McHardy2a37d752014-01-09 18:42:37 +0000940 const struct nf_chain_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +0200941 struct nf_hook_ops *ops;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200942 nf_hookfn *hookfn;
Patrick McHardy115a60b2014-01-03 12:16:15 +0000943 u32 hooknum, priority;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200944
Patrick McHardybaae3e62014-01-09 18:42:34 +0000945 type = chain_type[family][NFT_CHAIN_T_DEFAULT];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200946 if (nla[NFTA_CHAIN_TYPE]) {
947 type = nf_tables_chain_type_lookup(afi,
948 nla[NFTA_CHAIN_TYPE],
949 create);
Patrick McHardy93b08062014-01-09 18:42:36 +0000950 if (IS_ERR(type))
951 return PTR_ERR(type);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200952 }
Patrick McHardy96518512013-10-14 11:00:02 +0200953
954 err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK],
955 nft_hook_policy);
956 if (err < 0)
957 return err;
958 if (ha[NFTA_HOOK_HOOKNUM] == NULL ||
959 ha[NFTA_HOOK_PRIORITY] == NULL)
960 return -EINVAL;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200961
962 hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
963 if (hooknum >= afi->nhooks)
Patrick McHardy96518512013-10-14 11:00:02 +0200964 return -EINVAL;
Patrick McHardy115a60b2014-01-03 12:16:15 +0000965 priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
Patrick McHardy96518512013-10-14 11:00:02 +0200966
Patrick McHardybaae3e62014-01-09 18:42:34 +0000967 if (!(type->hook_mask & (1 << hooknum)))
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200968 return -EOPNOTSUPP;
Patrick McHardyfa2c1de2014-01-09 18:42:38 +0000969 if (!try_module_get(type->owner))
Patrick McHardybaae3e62014-01-09 18:42:34 +0000970 return -ENOENT;
Patrick McHardyfa2c1de2014-01-09 18:42:38 +0000971 hookfn = type->hooks[hooknum];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200972
Patrick McHardy96518512013-10-14 11:00:02 +0200973 basechain = kzalloc(sizeof(*basechain), GFP_KERNEL);
974 if (basechain == NULL)
975 return -ENOMEM;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200976
Patrick McHardy4401a862014-01-09 18:42:32 +0000977 if (nla[NFTA_CHAIN_COUNTERS]) {
978 err = nf_tables_counters(basechain,
979 nla[NFTA_CHAIN_COUNTERS]);
980 if (err < 0) {
Patrick McHardyfa2c1de2014-01-09 18:42:38 +0000981 module_put(type->owner);
Patrick McHardy4401a862014-01-09 18:42:32 +0000982 kfree(basechain);
983 return err;
984 }
985 } else {
986 struct nft_stats __percpu *newstats;
987
988 newstats = alloc_percpu(struct nft_stats);
989 if (newstats == NULL) {
Patrick McHardyfa2c1de2014-01-09 18:42:38 +0000990 module_put(type->owner);
Patrick McHardy4401a862014-01-09 18:42:32 +0000991 kfree(basechain);
992 return -ENOMEM;
993 }
994 rcu_assign_pointer(basechain->stats, newstats);
995 }
996
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200997 basechain->type = type;
Patrick McHardy96518512013-10-14 11:00:02 +0200998 chain = &basechain->chain;
999
Patrick McHardy115a60b2014-01-03 12:16:15 +00001000 for (i = 0; i < afi->nops; i++) {
1001 ops = &basechain->ops[i];
1002 ops->pf = family;
1003 ops->owner = afi->owner;
1004 ops->hooknum = hooknum;
1005 ops->priority = priority;
1006 ops->priv = chain;
1007 ops->hook = afi->hooks[ops->hooknum];
1008 if (hookfn)
1009 ops->hook = hookfn;
1010 if (afi->hook_ops_init)
1011 afi->hook_ops_init(ops, i);
1012 }
Patrick McHardy96518512013-10-14 11:00:02 +02001013
1014 chain->flags |= NFT_BASE_CHAIN;
Patrick McHardy57de2a02014-01-09 18:42:31 +00001015 basechain->policy = policy;
Patrick McHardy96518512013-10-14 11:00:02 +02001016 } else {
1017 chain = kzalloc(sizeof(*chain), GFP_KERNEL);
1018 if (chain == NULL)
1019 return -ENOMEM;
1020 }
1021
1022 INIT_LIST_HEAD(&chain->rules);
1023 chain->handle = nf_tables_alloc_handle(table);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001024 chain->net = net;
Pablo Neira Ayusob5bc89b2013-10-10 16:49:19 +02001025 chain->table = table;
Patrick McHardy96518512013-10-14 11:00:02 +02001026 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
1027
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +02001028 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
1029 chain->flags & NFT_BASE_CHAIN) {
Patrick McHardy115a60b2014-01-03 12:16:15 +00001030 err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001031 if (err < 0) {
Patrick McHardyfa2c1de2014-01-09 18:42:38 +00001032 module_put(basechain->type->owner);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001033 free_percpu(basechain->stats);
1034 kfree(basechain);
1035 return err;
1036 }
1037 }
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +02001038 list_add_tail(&chain->list, &table->chains);
1039 table->use++;
Patrick McHardy96518512013-10-14 11:00:02 +02001040notify:
1041 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_NEWCHAIN,
1042 family);
1043 return 0;
1044}
1045
Pablo Neira Ayuso0165d932014-01-25 14:03:51 +01001046static void nf_tables_chain_destroy(struct nft_chain *chain)
Patrick McHardy96518512013-10-14 11:00:02 +02001047{
Patrick McHardy96518512013-10-14 11:00:02 +02001048 BUG_ON(chain->use > 0);
1049
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001050 if (chain->flags & NFT_BASE_CHAIN) {
Patrick McHardyfa2c1de2014-01-09 18:42:38 +00001051 module_put(nft_base_chain(chain)->type->owner);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001052 free_percpu(nft_base_chain(chain)->stats);
Patrick McHardy96518512013-10-14 11:00:02 +02001053 kfree(nft_base_chain(chain));
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001054 } else
Patrick McHardy96518512013-10-14 11:00:02 +02001055 kfree(chain);
1056}
1057
1058static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
1059 const struct nlmsghdr *nlh,
1060 const struct nlattr * const nla[])
1061{
1062 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02001063 struct nft_af_info *afi;
Patrick McHardy96518512013-10-14 11:00:02 +02001064 struct nft_table *table;
1065 struct nft_chain *chain;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001066 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001067 int family = nfmsg->nfgen_family;
1068
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001069 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001070 if (IS_ERR(afi))
1071 return PTR_ERR(afi);
1072
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001073 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001074 if (IS_ERR(table))
1075 return PTR_ERR(table);
1076
1077 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
1078 if (IS_ERR(chain))
1079 return PTR_ERR(chain);
1080
Patrick McHardy3dd72792014-01-25 08:04:07 +00001081 if (!list_empty(&chain->rules) || chain->use > 0)
Patrick McHardy96518512013-10-14 11:00:02 +02001082 return -EBUSY;
1083
1084 list_del(&chain->list);
1085 table->use--;
1086
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +02001087 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
1088 chain->flags & NFT_BASE_CHAIN)
Patrick McHardy115a60b2014-01-03 12:16:15 +00001089 nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops);
Patrick McHardy96518512013-10-14 11:00:02 +02001090
1091 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN,
1092 family);
1093
1094 /* Make sure all rule references are gone before this is released */
Pablo Neira Ayuso0165d932014-01-25 14:03:51 +01001095 synchronize_rcu();
1096
1097 nf_tables_chain_destroy(chain);
Patrick McHardy96518512013-10-14 11:00:02 +02001098 return 0;
1099}
1100
Patrick McHardy96518512013-10-14 11:00:02 +02001101/*
1102 * Expressions
1103 */
1104
1105/**
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001106 * nft_register_expr - register nf_tables expr type
1107 * @ops: expr type
Patrick McHardy96518512013-10-14 11:00:02 +02001108 *
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001109 * Registers the expr type for use with nf_tables. Returns zero on
Patrick McHardy96518512013-10-14 11:00:02 +02001110 * success or a negative errno code otherwise.
1111 */
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001112int nft_register_expr(struct nft_expr_type *type)
Patrick McHardy96518512013-10-14 11:00:02 +02001113{
1114 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Tomasz Bursztyka758dbce2014-04-14 15:41:26 +03001115 if (type->family == NFPROTO_UNSPEC)
1116 list_add_tail(&type->list, &nf_tables_expressions);
1117 else
1118 list_add(&type->list, &nf_tables_expressions);
Patrick McHardy96518512013-10-14 11:00:02 +02001119 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1120 return 0;
1121}
1122EXPORT_SYMBOL_GPL(nft_register_expr);
1123
1124/**
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001125 * nft_unregister_expr - unregister nf_tables expr type
1126 * @ops: expr type
Patrick McHardy96518512013-10-14 11:00:02 +02001127 *
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001128 * Unregisters the expr typefor use with nf_tables.
Patrick McHardy96518512013-10-14 11:00:02 +02001129 */
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001130void nft_unregister_expr(struct nft_expr_type *type)
Patrick McHardy96518512013-10-14 11:00:02 +02001131{
1132 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001133 list_del(&type->list);
Patrick McHardy96518512013-10-14 11:00:02 +02001134 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1135}
1136EXPORT_SYMBOL_GPL(nft_unregister_expr);
1137
Patrick McHardy64d46802014-02-05 15:03:37 +00001138static const struct nft_expr_type *__nft_expr_type_get(u8 family,
1139 struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001140{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001141 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001142
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001143 list_for_each_entry(type, &nf_tables_expressions, list) {
Patrick McHardy64d46802014-02-05 15:03:37 +00001144 if (!nla_strcmp(nla, type->name) &&
1145 (!type->family || type->family == family))
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001146 return type;
Patrick McHardy96518512013-10-14 11:00:02 +02001147 }
1148 return NULL;
1149}
1150
Patrick McHardy64d46802014-02-05 15:03:37 +00001151static const struct nft_expr_type *nft_expr_type_get(u8 family,
1152 struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001153{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001154 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001155
1156 if (nla == NULL)
1157 return ERR_PTR(-EINVAL);
1158
Patrick McHardy64d46802014-02-05 15:03:37 +00001159 type = __nft_expr_type_get(family, nla);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001160 if (type != NULL && try_module_get(type->owner))
1161 return type;
Patrick McHardy96518512013-10-14 11:00:02 +02001162
1163#ifdef CONFIG_MODULES
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001164 if (type == NULL) {
Patrick McHardy96518512013-10-14 11:00:02 +02001165 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
Patrick McHardy64d46802014-02-05 15:03:37 +00001166 request_module("nft-expr-%u-%.*s", family,
1167 nla_len(nla), (char *)nla_data(nla));
1168 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1169 if (__nft_expr_type_get(family, nla))
1170 return ERR_PTR(-EAGAIN);
1171
1172 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
Patrick McHardy96518512013-10-14 11:00:02 +02001173 request_module("nft-expr-%.*s",
1174 nla_len(nla), (char *)nla_data(nla));
1175 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardy64d46802014-02-05 15:03:37 +00001176 if (__nft_expr_type_get(family, nla))
Patrick McHardy96518512013-10-14 11:00:02 +02001177 return ERR_PTR(-EAGAIN);
1178 }
1179#endif
1180 return ERR_PTR(-ENOENT);
1181}
1182
1183static const struct nla_policy nft_expr_policy[NFTA_EXPR_MAX + 1] = {
1184 [NFTA_EXPR_NAME] = { .type = NLA_STRING },
1185 [NFTA_EXPR_DATA] = { .type = NLA_NESTED },
1186};
1187
1188static int nf_tables_fill_expr_info(struct sk_buff *skb,
1189 const struct nft_expr *expr)
1190{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001191 if (nla_put_string(skb, NFTA_EXPR_NAME, expr->ops->type->name))
Patrick McHardy96518512013-10-14 11:00:02 +02001192 goto nla_put_failure;
1193
1194 if (expr->ops->dump) {
1195 struct nlattr *data = nla_nest_start(skb, NFTA_EXPR_DATA);
1196 if (data == NULL)
1197 goto nla_put_failure;
1198 if (expr->ops->dump(skb, expr) < 0)
1199 goto nla_put_failure;
1200 nla_nest_end(skb, data);
1201 }
1202
1203 return skb->len;
1204
1205nla_put_failure:
1206 return -1;
1207};
1208
1209struct nft_expr_info {
1210 const struct nft_expr_ops *ops;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001211 struct nlattr *tb[NFT_EXPR_MAXATTR + 1];
Patrick McHardy96518512013-10-14 11:00:02 +02001212};
1213
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001214static int nf_tables_expr_parse(const struct nft_ctx *ctx,
1215 const struct nlattr *nla,
Patrick McHardy96518512013-10-14 11:00:02 +02001216 struct nft_expr_info *info)
1217{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001218 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001219 const struct nft_expr_ops *ops;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001220 struct nlattr *tb[NFTA_EXPR_MAX + 1];
Patrick McHardy96518512013-10-14 11:00:02 +02001221 int err;
1222
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001223 err = nla_parse_nested(tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
Patrick McHardy96518512013-10-14 11:00:02 +02001224 if (err < 0)
1225 return err;
1226
Patrick McHardy64d46802014-02-05 15:03:37 +00001227 type = nft_expr_type_get(ctx->afi->family, tb[NFTA_EXPR_NAME]);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001228 if (IS_ERR(type))
1229 return PTR_ERR(type);
1230
1231 if (tb[NFTA_EXPR_DATA]) {
1232 err = nla_parse_nested(info->tb, type->maxattr,
1233 tb[NFTA_EXPR_DATA], type->policy);
1234 if (err < 0)
1235 goto err1;
1236 } else
1237 memset(info->tb, 0, sizeof(info->tb[0]) * (type->maxattr + 1));
1238
1239 if (type->select_ops != NULL) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001240 ops = type->select_ops(ctx,
1241 (const struct nlattr * const *)info->tb);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001242 if (IS_ERR(ops)) {
1243 err = PTR_ERR(ops);
1244 goto err1;
1245 }
1246 } else
1247 ops = type->ops;
1248
Patrick McHardy96518512013-10-14 11:00:02 +02001249 info->ops = ops;
1250 return 0;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001251
1252err1:
1253 module_put(type->owner);
1254 return err;
Patrick McHardy96518512013-10-14 11:00:02 +02001255}
1256
1257static int nf_tables_newexpr(const struct nft_ctx *ctx,
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001258 const struct nft_expr_info *info,
Patrick McHardy96518512013-10-14 11:00:02 +02001259 struct nft_expr *expr)
1260{
1261 const struct nft_expr_ops *ops = info->ops;
1262 int err;
1263
1264 expr->ops = ops;
1265 if (ops->init) {
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001266 err = ops->init(ctx, expr, (const struct nlattr **)info->tb);
Patrick McHardy96518512013-10-14 11:00:02 +02001267 if (err < 0)
1268 goto err1;
1269 }
1270
Patrick McHardy96518512013-10-14 11:00:02 +02001271 return 0;
1272
1273err1:
1274 expr->ops = NULL;
1275 return err;
1276}
1277
Patrick McHardy62472bc2014-03-07 19:08:30 +01001278static void nf_tables_expr_destroy(const struct nft_ctx *ctx,
1279 struct nft_expr *expr)
Patrick McHardy96518512013-10-14 11:00:02 +02001280{
1281 if (expr->ops->destroy)
Patrick McHardy62472bc2014-03-07 19:08:30 +01001282 expr->ops->destroy(ctx, expr);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001283 module_put(expr->ops->type->owner);
Patrick McHardy96518512013-10-14 11:00:02 +02001284}
1285
1286/*
1287 * Rules
1288 */
1289
1290static struct nft_rule *__nf_tables_rule_lookup(const struct nft_chain *chain,
1291 u64 handle)
1292{
1293 struct nft_rule *rule;
1294
1295 // FIXME: this sucks
1296 list_for_each_entry(rule, &chain->rules, list) {
1297 if (handle == rule->handle)
1298 return rule;
1299 }
1300
1301 return ERR_PTR(-ENOENT);
1302}
1303
1304static struct nft_rule *nf_tables_rule_lookup(const struct nft_chain *chain,
1305 const struct nlattr *nla)
1306{
1307 if (nla == NULL)
1308 return ERR_PTR(-EINVAL);
1309
1310 return __nf_tables_rule_lookup(chain, be64_to_cpu(nla_get_be64(nla)));
1311}
1312
1313static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
1314 [NFTA_RULE_TABLE] = { .type = NLA_STRING },
1315 [NFTA_RULE_CHAIN] = { .type = NLA_STRING,
1316 .len = NFT_CHAIN_MAXNAMELEN - 1 },
1317 [NFTA_RULE_HANDLE] = { .type = NLA_U64 },
1318 [NFTA_RULE_EXPRESSIONS] = { .type = NLA_NESTED },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001319 [NFTA_RULE_COMPAT] = { .type = NLA_NESTED },
Eric Leblond5e948462013-10-10 13:41:44 +02001320 [NFTA_RULE_POSITION] = { .type = NLA_U64 },
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01001321 [NFTA_RULE_USERDATA] = { .type = NLA_BINARY,
1322 .len = NFT_USERDATA_MAXLEN },
Patrick McHardy96518512013-10-14 11:00:02 +02001323};
1324
1325static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
1326 int event, u32 flags, int family,
1327 const struct nft_table *table,
1328 const struct nft_chain *chain,
1329 const struct nft_rule *rule)
1330{
1331 struct nlmsghdr *nlh;
1332 struct nfgenmsg *nfmsg;
1333 const struct nft_expr *expr, *next;
1334 struct nlattr *list;
Eric Leblond5e948462013-10-10 13:41:44 +02001335 const struct nft_rule *prule;
1336 int type = event | NFNL_SUBSYS_NFTABLES << 8;
Patrick McHardy96518512013-10-14 11:00:02 +02001337
Eric Leblond5e948462013-10-10 13:41:44 +02001338 nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg),
Patrick McHardy96518512013-10-14 11:00:02 +02001339 flags);
1340 if (nlh == NULL)
1341 goto nla_put_failure;
1342
1343 nfmsg = nlmsg_data(nlh);
1344 nfmsg->nfgen_family = family;
1345 nfmsg->version = NFNETLINK_V0;
1346 nfmsg->res_id = 0;
1347
1348 if (nla_put_string(skb, NFTA_RULE_TABLE, table->name))
1349 goto nla_put_failure;
1350 if (nla_put_string(skb, NFTA_RULE_CHAIN, chain->name))
1351 goto nla_put_failure;
1352 if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
1353 goto nla_put_failure;
1354
Eric Leblond5e948462013-10-10 13:41:44 +02001355 if ((event != NFT_MSG_DELRULE) && (rule->list.prev != &chain->rules)) {
1356 prule = list_entry(rule->list.prev, struct nft_rule, list);
1357 if (nla_put_be64(skb, NFTA_RULE_POSITION,
1358 cpu_to_be64(prule->handle)))
1359 goto nla_put_failure;
1360 }
1361
Patrick McHardy96518512013-10-14 11:00:02 +02001362 list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
1363 if (list == NULL)
1364 goto nla_put_failure;
1365 nft_rule_for_each_expr(expr, next, rule) {
1366 struct nlattr *elem = nla_nest_start(skb, NFTA_LIST_ELEM);
1367 if (elem == NULL)
1368 goto nla_put_failure;
1369 if (nf_tables_fill_expr_info(skb, expr) < 0)
1370 goto nla_put_failure;
1371 nla_nest_end(skb, elem);
1372 }
1373 nla_nest_end(skb, list);
1374
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01001375 if (rule->ulen &&
1376 nla_put(skb, NFTA_RULE_USERDATA, rule->ulen, nft_userdata(rule)))
1377 goto nla_put_failure;
1378
Patrick McHardy96518512013-10-14 11:00:02 +02001379 return nlmsg_end(skb, nlh);
1380
1381nla_put_failure:
1382 nlmsg_trim(skb, nlh);
1383 return -1;
1384}
1385
1386static int nf_tables_rule_notify(const struct sk_buff *oskb,
1387 const struct nlmsghdr *nlh,
1388 const struct nft_table *table,
1389 const struct nft_chain *chain,
1390 const struct nft_rule *rule,
1391 int event, u32 flags, int family)
1392{
1393 struct sk_buff *skb;
1394 u32 portid = NETLINK_CB(oskb).portid;
1395 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
1396 u32 seq = nlh->nlmsg_seq;
1397 bool report;
1398 int err;
1399
1400 report = nlmsg_report(nlh);
1401 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
1402 return 0;
1403
1404 err = -ENOBUFS;
1405 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1406 if (skb == NULL)
1407 goto err;
1408
1409 err = nf_tables_fill_rule_info(skb, portid, seq, event, flags,
1410 family, table, chain, rule);
1411 if (err < 0) {
1412 kfree_skb(skb);
1413 goto err;
1414 }
1415
1416 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
1417 GFP_KERNEL);
1418err:
1419 if (err < 0)
1420 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
1421 return err;
1422}
1423
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001424static inline bool
1425nft_rule_is_active(struct net *net, const struct nft_rule *rule)
1426{
1427 return (rule->genmask & (1 << net->nft.gencursor)) == 0;
1428}
1429
1430static inline int gencursor_next(struct net *net)
1431{
1432 return net->nft.gencursor+1 == 1 ? 1 : 0;
1433}
1434
1435static inline int
1436nft_rule_is_active_next(struct net *net, const struct nft_rule *rule)
1437{
1438 return (rule->genmask & (1 << gencursor_next(net))) == 0;
1439}
1440
1441static inline void
1442nft_rule_activate_next(struct net *net, struct nft_rule *rule)
1443{
1444 /* Now inactive, will be active in the future */
1445 rule->genmask = (1 << net->nft.gencursor);
1446}
1447
1448static inline void
1449nft_rule_disactivate_next(struct net *net, struct nft_rule *rule)
1450{
1451 rule->genmask = (1 << gencursor_next(net));
1452}
1453
1454static inline void nft_rule_clear(struct net *net, struct nft_rule *rule)
1455{
1456 rule->genmask = 0;
1457}
1458
Patrick McHardy96518512013-10-14 11:00:02 +02001459static int nf_tables_dump_rules(struct sk_buff *skb,
1460 struct netlink_callback *cb)
1461{
1462 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
1463 const struct nft_af_info *afi;
1464 const struct nft_table *table;
1465 const struct nft_chain *chain;
1466 const struct nft_rule *rule;
1467 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001468 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001469 int family = nfmsg->nfgen_family;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001470 u8 genctr = ACCESS_ONCE(net->nft.genctr);
1471 u8 gencursor = ACCESS_ONCE(net->nft.gencursor);
Patrick McHardy96518512013-10-14 11:00:02 +02001472
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001473 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +02001474 if (family != NFPROTO_UNSPEC && family != afi->family)
1475 continue;
1476
1477 list_for_each_entry(table, &afi->tables, list) {
1478 list_for_each_entry(chain, &table->chains, list) {
1479 list_for_each_entry(rule, &chain->rules, list) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001480 if (!nft_rule_is_active(net, rule))
1481 goto cont;
Patrick McHardy96518512013-10-14 11:00:02 +02001482 if (idx < s_idx)
1483 goto cont;
1484 if (idx > s_idx)
1485 memset(&cb->args[1], 0,
1486 sizeof(cb->args) - sizeof(cb->args[0]));
1487 if (nf_tables_fill_rule_info(skb, NETLINK_CB(cb->skb).portid,
1488 cb->nlh->nlmsg_seq,
1489 NFT_MSG_NEWRULE,
1490 NLM_F_MULTI | NLM_F_APPEND,
1491 afi->family, table, chain, rule) < 0)
1492 goto done;
1493cont:
1494 idx++;
1495 }
1496 }
1497 }
1498 }
1499done:
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001500 /* Invalidate this dump, a transition to the new generation happened */
1501 if (gencursor != net->nft.gencursor || genctr != net->nft.genctr)
1502 return -EBUSY;
1503
Patrick McHardy96518512013-10-14 11:00:02 +02001504 cb->args[0] = idx;
1505 return skb->len;
1506}
1507
1508static int nf_tables_getrule(struct sock *nlsk, struct sk_buff *skb,
1509 const struct nlmsghdr *nlh,
1510 const struct nlattr * const nla[])
1511{
1512 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1513 const struct nft_af_info *afi;
1514 const struct nft_table *table;
1515 const struct nft_chain *chain;
1516 const struct nft_rule *rule;
1517 struct sk_buff *skb2;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001518 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001519 int family = nfmsg->nfgen_family;
1520 int err;
1521
1522 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1523 struct netlink_dump_control c = {
1524 .dump = nf_tables_dump_rules,
1525 };
1526 return netlink_dump_start(nlsk, skb, nlh, &c);
1527 }
1528
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001529 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001530 if (IS_ERR(afi))
1531 return PTR_ERR(afi);
1532
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001533 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001534 if (IS_ERR(table))
1535 return PTR_ERR(table);
1536
1537 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1538 if (IS_ERR(chain))
1539 return PTR_ERR(chain);
1540
1541 rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
1542 if (IS_ERR(rule))
1543 return PTR_ERR(rule);
1544
1545 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1546 if (!skb2)
1547 return -ENOMEM;
1548
1549 err = nf_tables_fill_rule_info(skb2, NETLINK_CB(skb).portid,
1550 nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
1551 family, table, chain, rule);
1552 if (err < 0)
1553 goto err;
1554
1555 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
1556
1557err:
1558 kfree_skb(skb2);
1559 return err;
1560}
1561
Patrick McHardy62472bc2014-03-07 19:08:30 +01001562static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
1563 struct nft_rule *rule)
Patrick McHardy96518512013-10-14 11:00:02 +02001564{
Patrick McHardy96518512013-10-14 11:00:02 +02001565 struct nft_expr *expr;
1566
1567 /*
1568 * Careful: some expressions might not be initialized in case this
1569 * is called on error from nf_tables_newrule().
1570 */
1571 expr = nft_expr_first(rule);
1572 while (expr->ops && expr != nft_expr_last(rule)) {
Patrick McHardy62472bc2014-03-07 19:08:30 +01001573 nf_tables_expr_destroy(ctx, expr);
Patrick McHardy96518512013-10-14 11:00:02 +02001574 expr = nft_expr_next(expr);
1575 }
1576 kfree(rule);
1577}
1578
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001579static struct nft_trans *nft_trans_rule_add(struct nft_ctx *ctx,
1580 struct nft_rule *rule)
1581{
1582 struct nft_trans *trans;
1583
1584 trans = nft_trans_alloc(ctx, sizeof(struct nft_trans_rule));
1585 if (trans == NULL)
1586 return NULL;
1587
1588 nft_trans_rule(trans) = rule;
1589 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
1590
1591 return trans;
1592}
1593
Patrick McHardy96518512013-10-14 11:00:02 +02001594#define NFT_RULE_MAXEXPRS 128
1595
1596static struct nft_expr_info *info;
1597
1598static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
1599 const struct nlmsghdr *nlh,
1600 const struct nlattr * const nla[])
1601{
1602 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02001603 struct nft_af_info *afi;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001604 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001605 struct nft_table *table;
1606 struct nft_chain *chain;
1607 struct nft_rule *rule, *old_rule = NULL;
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001608 struct nft_trans *trans = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +02001609 struct nft_expr *expr;
1610 struct nft_ctx ctx;
1611 struct nlattr *tmp;
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01001612 unsigned int size, i, n, ulen = 0;
Patrick McHardy96518512013-10-14 11:00:02 +02001613 int err, rem;
1614 bool create;
Eric Leblond5e948462013-10-10 13:41:44 +02001615 u64 handle, pos_handle;
Patrick McHardy96518512013-10-14 11:00:02 +02001616
1617 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
1618
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001619 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
Patrick McHardy96518512013-10-14 11:00:02 +02001620 if (IS_ERR(afi))
1621 return PTR_ERR(afi);
1622
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001623 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001624 if (IS_ERR(table))
1625 return PTR_ERR(table);
1626
1627 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1628 if (IS_ERR(chain))
1629 return PTR_ERR(chain);
1630
1631 if (nla[NFTA_RULE_HANDLE]) {
1632 handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
1633 rule = __nf_tables_rule_lookup(chain, handle);
1634 if (IS_ERR(rule))
1635 return PTR_ERR(rule);
1636
1637 if (nlh->nlmsg_flags & NLM_F_EXCL)
1638 return -EEXIST;
1639 if (nlh->nlmsg_flags & NLM_F_REPLACE)
1640 old_rule = rule;
1641 else
1642 return -EOPNOTSUPP;
1643 } else {
1644 if (!create || nlh->nlmsg_flags & NLM_F_REPLACE)
1645 return -EINVAL;
1646 handle = nf_tables_alloc_handle(table);
1647 }
1648
Eric Leblond5e948462013-10-10 13:41:44 +02001649 if (nla[NFTA_RULE_POSITION]) {
1650 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
1651 return -EOPNOTSUPP;
1652
1653 pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
1654 old_rule = __nf_tables_rule_lookup(chain, pos_handle);
1655 if (IS_ERR(old_rule))
1656 return PTR_ERR(old_rule);
1657 }
1658
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001659 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1660
Patrick McHardy96518512013-10-14 11:00:02 +02001661 n = 0;
1662 size = 0;
1663 if (nla[NFTA_RULE_EXPRESSIONS]) {
1664 nla_for_each_nested(tmp, nla[NFTA_RULE_EXPRESSIONS], rem) {
1665 err = -EINVAL;
1666 if (nla_type(tmp) != NFTA_LIST_ELEM)
1667 goto err1;
1668 if (n == NFT_RULE_MAXEXPRS)
1669 goto err1;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001670 err = nf_tables_expr_parse(&ctx, tmp, &info[n]);
Patrick McHardy96518512013-10-14 11:00:02 +02001671 if (err < 0)
1672 goto err1;
1673 size += info[n].ops->size;
1674 n++;
1675 }
1676 }
1677
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01001678 if (nla[NFTA_RULE_USERDATA])
1679 ulen = nla_len(nla[NFTA_RULE_USERDATA]);
1680
Patrick McHardy96518512013-10-14 11:00:02 +02001681 err = -ENOMEM;
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01001682 rule = kzalloc(sizeof(*rule) + size + ulen, GFP_KERNEL);
Patrick McHardy96518512013-10-14 11:00:02 +02001683 if (rule == NULL)
1684 goto err1;
1685
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001686 nft_rule_activate_next(net, rule);
1687
Patrick McHardy96518512013-10-14 11:00:02 +02001688 rule->handle = handle;
1689 rule->dlen = size;
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01001690 rule->ulen = ulen;
1691
1692 if (ulen)
1693 nla_memcpy(nft_userdata(rule), nla[NFTA_RULE_USERDATA], ulen);
Patrick McHardy96518512013-10-14 11:00:02 +02001694
Patrick McHardy96518512013-10-14 11:00:02 +02001695 expr = nft_expr_first(rule);
1696 for (i = 0; i < n; i++) {
1697 err = nf_tables_newexpr(&ctx, &info[i], expr);
1698 if (err < 0)
1699 goto err2;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001700 info[i].ops = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +02001701 expr = nft_expr_next(expr);
1702 }
1703
Patrick McHardy96518512013-10-14 11:00:02 +02001704 if (nlh->nlmsg_flags & NLM_F_REPLACE) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001705 if (nft_rule_is_active_next(net, old_rule)) {
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001706 trans = nft_trans_rule_add(&ctx, old_rule);
1707 if (trans == NULL) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001708 err = -ENOMEM;
1709 goto err2;
1710 }
1711 nft_rule_disactivate_next(net, old_rule);
1712 list_add_tail(&rule->list, &old_rule->list);
1713 } else {
1714 err = -ENOENT;
1715 goto err2;
1716 }
Patrick McHardy96518512013-10-14 11:00:02 +02001717 } else if (nlh->nlmsg_flags & NLM_F_APPEND)
Eric Leblond5e948462013-10-10 13:41:44 +02001718 if (old_rule)
1719 list_add_rcu(&rule->list, &old_rule->list);
1720 else
1721 list_add_tail_rcu(&rule->list, &chain->rules);
1722 else {
1723 if (old_rule)
1724 list_add_tail_rcu(&rule->list, &old_rule->list);
1725 else
1726 list_add_rcu(&rule->list, &chain->rules);
1727 }
Patrick McHardy96518512013-10-14 11:00:02 +02001728
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001729 if (nft_trans_rule_add(&ctx, rule) == NULL) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001730 err = -ENOMEM;
1731 goto err3;
1732 }
Patrick McHardy96518512013-10-14 11:00:02 +02001733 return 0;
1734
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001735err3:
1736 list_del_rcu(&rule->list);
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001737 if (trans) {
1738 list_del_rcu(&nft_trans_rule(trans)->list);
1739 nft_rule_clear(net, nft_trans_rule(trans));
1740 nft_trans_destroy(trans);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001741 }
Patrick McHardy96518512013-10-14 11:00:02 +02001742err2:
Patrick McHardy62472bc2014-03-07 19:08:30 +01001743 nf_tables_rule_destroy(&ctx, rule);
Patrick McHardy96518512013-10-14 11:00:02 +02001744err1:
1745 for (i = 0; i < n; i++) {
1746 if (info[i].ops != NULL)
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001747 module_put(info[i].ops->type->owner);
Patrick McHardy96518512013-10-14 11:00:02 +02001748 }
1749 return err;
1750}
1751
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001752static int
1753nf_tables_delrule_one(struct nft_ctx *ctx, struct nft_rule *rule)
1754{
1755 /* You cannot delete the same rule twice */
1756 if (nft_rule_is_active_next(ctx->net, rule)) {
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001757 if (nft_trans_rule_add(ctx, rule) == NULL)
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001758 return -ENOMEM;
1759 nft_rule_disactivate_next(ctx->net, rule);
1760 return 0;
1761 }
1762 return -ENOENT;
1763}
1764
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001765static int nf_table_delrule_by_chain(struct nft_ctx *ctx)
1766{
1767 struct nft_rule *rule;
1768 int err;
1769
1770 list_for_each_entry(rule, &ctx->chain->rules, list) {
1771 err = nf_tables_delrule_one(ctx, rule);
1772 if (err < 0)
1773 return err;
1774 }
1775 return 0;
1776}
1777
Patrick McHardy96518512013-10-14 11:00:02 +02001778static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
1779 const struct nlmsghdr *nlh,
1780 const struct nlattr * const nla[])
1781{
1782 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02001783 struct nft_af_info *afi;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001784 struct net *net = sock_net(skb->sk);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02001785 struct nft_table *table;
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001786 struct nft_chain *chain = NULL;
1787 struct nft_rule *rule;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001788 int family = nfmsg->nfgen_family, err = 0;
1789 struct nft_ctx ctx;
Patrick McHardy96518512013-10-14 11:00:02 +02001790
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001791 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001792 if (IS_ERR(afi))
1793 return PTR_ERR(afi);
1794
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001795 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001796 if (IS_ERR(table))
1797 return PTR_ERR(table);
1798
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001799 if (nla[NFTA_RULE_CHAIN]) {
1800 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1801 if (IS_ERR(chain))
1802 return PTR_ERR(chain);
1803 }
Patrick McHardy96518512013-10-14 11:00:02 +02001804
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001805 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1806
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001807 if (chain) {
1808 if (nla[NFTA_RULE_HANDLE]) {
1809 rule = nf_tables_rule_lookup(chain,
1810 nla[NFTA_RULE_HANDLE]);
1811 if (IS_ERR(rule))
1812 return PTR_ERR(rule);
Patrick McHardy96518512013-10-14 11:00:02 +02001813
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001814 err = nf_tables_delrule_one(&ctx, rule);
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001815 } else {
1816 err = nf_table_delrule_by_chain(&ctx);
1817 }
1818 } else {
1819 list_for_each_entry(chain, &table->chains, list) {
1820 ctx.chain = chain;
1821 err = nf_table_delrule_by_chain(&ctx);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001822 if (err < 0)
1823 break;
Patrick McHardy96518512013-10-14 11:00:02 +02001824 }
1825 }
1826
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001827 return err;
1828}
1829
1830static int nf_tables_commit(struct sk_buff *skb)
1831{
1832 struct net *net = sock_net(skb->sk);
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001833 struct nft_trans *trans, *next;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001834
1835 /* Bump generation counter, invalidate any dump in progress */
1836 net->nft.genctr++;
1837
1838 /* A new generation has just started */
1839 net->nft.gencursor = gencursor_next(net);
1840
1841 /* Make sure all packets have left the previous generation before
1842 * purging old rules.
1843 */
1844 synchronize_rcu();
1845
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001846 list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001847 /* This rule was inactive in the past and just became active.
1848 * Clear the next bit of the genmask since its meaning has
1849 * changed, now it is the future.
1850 */
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001851 if (nft_rule_is_active(net, nft_trans_rule(trans))) {
1852 nft_rule_clear(net, nft_trans_rule(trans));
1853 nf_tables_rule_notify(skb, trans->ctx.nlh,
1854 trans->ctx.table,
1855 trans->ctx.chain,
1856 nft_trans_rule(trans),
1857 NFT_MSG_NEWRULE, 0,
1858 trans->ctx.afi->family);
1859 nft_trans_destroy(trans);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001860 continue;
1861 }
1862
1863 /* This rule is in the past, get rid of it */
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001864 list_del_rcu(&nft_trans_rule(trans)->list);
1865 nf_tables_rule_notify(skb, trans->ctx.nlh,
1866 trans->ctx.table, trans->ctx.chain,
1867 nft_trans_rule(trans), NFT_MSG_DELRULE,
1868 0, trans->ctx.afi->family);
Pablo Neira Ayuso0165d932014-01-25 14:03:51 +01001869 }
1870
1871 /* Make sure we don't see any packet traversing old rules */
1872 synchronize_rcu();
1873
1874 /* Now we can safely release unused old rules */
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001875 list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
1876 nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans));
1877 nft_trans_destroy(trans);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001878 }
1879
1880 return 0;
1881}
1882
1883static int nf_tables_abort(struct sk_buff *skb)
1884{
1885 struct net *net = sock_net(skb->sk);
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001886 struct nft_trans *trans, *next;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001887
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001888 list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
1889 if (!nft_rule_is_active_next(net, nft_trans_rule(trans))) {
1890 nft_rule_clear(net, nft_trans_rule(trans));
1891 nft_trans_destroy(trans);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001892 continue;
1893 }
1894
1895 /* This rule is inactive, get rid of it */
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001896 list_del_rcu(&nft_trans_rule(trans)->list);
Pablo Neira Ayuso0165d932014-01-25 14:03:51 +01001897 }
1898
1899 /* Make sure we don't see any packet accessing aborted rules */
1900 synchronize_rcu();
1901
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001902 list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
1903 nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans));
1904 nft_trans_destroy(trans);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001905 }
Pablo Neira Ayuso0165d932014-01-25 14:03:51 +01001906
Patrick McHardy96518512013-10-14 11:00:02 +02001907 return 0;
1908}
1909
Patrick McHardy20a69342013-10-11 12:06:22 +02001910/*
1911 * Sets
1912 */
1913
1914static LIST_HEAD(nf_tables_set_ops);
1915
1916int nft_register_set(struct nft_set_ops *ops)
1917{
1918 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1919 list_add_tail(&ops->list, &nf_tables_set_ops);
1920 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1921 return 0;
1922}
1923EXPORT_SYMBOL_GPL(nft_register_set);
1924
1925void nft_unregister_set(struct nft_set_ops *ops)
1926{
1927 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1928 list_del(&ops->list);
1929 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1930}
1931EXPORT_SYMBOL_GPL(nft_unregister_set);
1932
Patrick McHardyc50b9602014-03-28 10:19:47 +00001933/*
1934 * Select a set implementation based on the data characteristics and the
1935 * given policy. The total memory use might not be known if no size is
1936 * given, in that case the amount of memory per element is used.
1937 */
1938static const struct nft_set_ops *
1939nft_select_set_ops(const struct nlattr * const nla[],
1940 const struct nft_set_desc *desc,
1941 enum nft_set_policies policy)
Patrick McHardy20a69342013-10-11 12:06:22 +02001942{
Patrick McHardyc50b9602014-03-28 10:19:47 +00001943 const struct nft_set_ops *ops, *bops;
1944 struct nft_set_estimate est, best;
Patrick McHardy20a69342013-10-11 12:06:22 +02001945 u32 features;
1946
1947#ifdef CONFIG_MODULES
1948 if (list_empty(&nf_tables_set_ops)) {
1949 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1950 request_module("nft-set");
1951 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1952 if (!list_empty(&nf_tables_set_ops))
1953 return ERR_PTR(-EAGAIN);
1954 }
1955#endif
1956 features = 0;
1957 if (nla[NFTA_SET_FLAGS] != NULL) {
1958 features = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
1959 features &= NFT_SET_INTERVAL | NFT_SET_MAP;
1960 }
1961
Patrick McHardyc50b9602014-03-28 10:19:47 +00001962 bops = NULL;
1963 best.size = ~0;
1964 best.class = ~0;
1965
Patrick McHardy20a69342013-10-11 12:06:22 +02001966 list_for_each_entry(ops, &nf_tables_set_ops, list) {
1967 if ((ops->features & features) != features)
1968 continue;
Patrick McHardyc50b9602014-03-28 10:19:47 +00001969 if (!ops->estimate(desc, features, &est))
1970 continue;
1971
1972 switch (policy) {
1973 case NFT_SET_POL_PERFORMANCE:
1974 if (est.class < best.class)
1975 break;
1976 if (est.class == best.class && est.size < best.size)
1977 break;
1978 continue;
1979 case NFT_SET_POL_MEMORY:
1980 if (est.size < best.size)
1981 break;
1982 if (est.size == best.size && est.class < best.class)
1983 break;
1984 continue;
1985 default:
1986 break;
1987 }
1988
Patrick McHardy20a69342013-10-11 12:06:22 +02001989 if (!try_module_get(ops->owner))
1990 continue;
Patrick McHardyc50b9602014-03-28 10:19:47 +00001991 if (bops != NULL)
1992 module_put(bops->owner);
1993
1994 bops = ops;
1995 best = est;
Patrick McHardy20a69342013-10-11 12:06:22 +02001996 }
1997
Patrick McHardyc50b9602014-03-28 10:19:47 +00001998 if (bops != NULL)
1999 return bops;
2000
Patrick McHardy20a69342013-10-11 12:06:22 +02002001 return ERR_PTR(-EOPNOTSUPP);
2002}
2003
2004static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
2005 [NFTA_SET_TABLE] = { .type = NLA_STRING },
2006 [NFTA_SET_NAME] = { .type = NLA_STRING },
2007 [NFTA_SET_FLAGS] = { .type = NLA_U32 },
2008 [NFTA_SET_KEY_TYPE] = { .type = NLA_U32 },
2009 [NFTA_SET_KEY_LEN] = { .type = NLA_U32 },
2010 [NFTA_SET_DATA_TYPE] = { .type = NLA_U32 },
2011 [NFTA_SET_DATA_LEN] = { .type = NLA_U32 },
Patrick McHardyc50b9602014-03-28 10:19:47 +00002012 [NFTA_SET_POLICY] = { .type = NLA_U32 },
2013 [NFTA_SET_DESC] = { .type = NLA_NESTED },
2014};
2015
2016static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
2017 [NFTA_SET_DESC_SIZE] = { .type = NLA_U32 },
Patrick McHardy20a69342013-10-11 12:06:22 +02002018};
2019
2020static int nft_ctx_init_from_setattr(struct nft_ctx *ctx,
2021 const struct sk_buff *skb,
2022 const struct nlmsghdr *nlh,
2023 const struct nlattr * const nla[])
2024{
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002025 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02002026 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02002027 struct nft_af_info *afi = NULL;
2028 struct nft_table *table = NULL;
Patrick McHardy20a69342013-10-11 12:06:22 +02002029
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002030 if (nfmsg->nfgen_family != NFPROTO_UNSPEC) {
2031 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
2032 if (IS_ERR(afi))
2033 return PTR_ERR(afi);
2034 }
Patrick McHardy20a69342013-10-11 12:06:22 +02002035
2036 if (nla[NFTA_SET_TABLE] != NULL) {
Patrick McHardyec2c9932014-02-05 15:03:35 +00002037 if (afi == NULL)
2038 return -EAFNOSUPPORT;
2039
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002040 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02002041 if (IS_ERR(table))
2042 return PTR_ERR(table);
2043 }
2044
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002045 nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002046 return 0;
2047}
2048
2049struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
2050 const struct nlattr *nla)
2051{
2052 struct nft_set *set;
2053
2054 if (nla == NULL)
2055 return ERR_PTR(-EINVAL);
2056
2057 list_for_each_entry(set, &table->sets, list) {
2058 if (!nla_strcmp(nla, set->name))
2059 return set;
2060 }
2061 return ERR_PTR(-ENOENT);
2062}
2063
2064static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
2065 const char *name)
2066{
2067 const struct nft_set *i;
2068 const char *p;
2069 unsigned long *inuse;
Patrick McHardy60eb1892014-03-07 12:34:05 +01002070 unsigned int n = 0, min = 0;
Patrick McHardy20a69342013-10-11 12:06:22 +02002071
2072 p = strnchr(name, IFNAMSIZ, '%');
2073 if (p != NULL) {
2074 if (p[1] != 'd' || strchr(p + 2, '%'))
2075 return -EINVAL;
2076
2077 inuse = (unsigned long *)get_zeroed_page(GFP_KERNEL);
2078 if (inuse == NULL)
2079 return -ENOMEM;
Patrick McHardy60eb1892014-03-07 12:34:05 +01002080cont:
Patrick McHardy20a69342013-10-11 12:06:22 +02002081 list_for_each_entry(i, &ctx->table->sets, list) {
Daniel Borkmann14662912013-12-31 12:40:05 +01002082 int tmp;
2083
2084 if (!sscanf(i->name, name, &tmp))
Patrick McHardy20a69342013-10-11 12:06:22 +02002085 continue;
Patrick McHardy60eb1892014-03-07 12:34:05 +01002086 if (tmp < min || tmp >= min + BITS_PER_BYTE * PAGE_SIZE)
Patrick McHardy20a69342013-10-11 12:06:22 +02002087 continue;
Daniel Borkmann14662912013-12-31 12:40:05 +01002088
Patrick McHardy60eb1892014-03-07 12:34:05 +01002089 set_bit(tmp - min, inuse);
Patrick McHardy20a69342013-10-11 12:06:22 +02002090 }
2091
Patrick McHardy53b70282014-02-05 12:26:22 +01002092 n = find_first_zero_bit(inuse, BITS_PER_BYTE * PAGE_SIZE);
Patrick McHardy60eb1892014-03-07 12:34:05 +01002093 if (n >= BITS_PER_BYTE * PAGE_SIZE) {
2094 min += BITS_PER_BYTE * PAGE_SIZE;
2095 memset(inuse, 0, PAGE_SIZE);
2096 goto cont;
2097 }
Patrick McHardy20a69342013-10-11 12:06:22 +02002098 free_page((unsigned long)inuse);
2099 }
2100
Patrick McHardy60eb1892014-03-07 12:34:05 +01002101 snprintf(set->name, sizeof(set->name), name, min + n);
Patrick McHardy20a69342013-10-11 12:06:22 +02002102 list_for_each_entry(i, &ctx->table->sets, list) {
2103 if (!strcmp(set->name, i->name))
2104 return -ENFILE;
2105 }
2106 return 0;
2107}
2108
2109static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
2110 const struct nft_set *set, u16 event, u16 flags)
2111{
2112 struct nfgenmsg *nfmsg;
2113 struct nlmsghdr *nlh;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002114 struct nlattr *desc;
Patrick McHardy20a69342013-10-11 12:06:22 +02002115 u32 portid = NETLINK_CB(ctx->skb).portid;
2116 u32 seq = ctx->nlh->nlmsg_seq;
2117
2118 event |= NFNL_SUBSYS_NFTABLES << 8;
2119 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
2120 flags);
2121 if (nlh == NULL)
2122 goto nla_put_failure;
2123
2124 nfmsg = nlmsg_data(nlh);
2125 nfmsg->nfgen_family = ctx->afi->family;
2126 nfmsg->version = NFNETLINK_V0;
2127 nfmsg->res_id = 0;
2128
2129 if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
2130 goto nla_put_failure;
2131 if (nla_put_string(skb, NFTA_SET_NAME, set->name))
2132 goto nla_put_failure;
2133 if (set->flags != 0)
2134 if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
2135 goto nla_put_failure;
2136
2137 if (nla_put_be32(skb, NFTA_SET_KEY_TYPE, htonl(set->ktype)))
2138 goto nla_put_failure;
2139 if (nla_put_be32(skb, NFTA_SET_KEY_LEN, htonl(set->klen)))
2140 goto nla_put_failure;
2141 if (set->flags & NFT_SET_MAP) {
2142 if (nla_put_be32(skb, NFTA_SET_DATA_TYPE, htonl(set->dtype)))
2143 goto nla_put_failure;
2144 if (nla_put_be32(skb, NFTA_SET_DATA_LEN, htonl(set->dlen)))
2145 goto nla_put_failure;
2146 }
2147
Patrick McHardyc50b9602014-03-28 10:19:47 +00002148 desc = nla_nest_start(skb, NFTA_SET_DESC);
2149 if (desc == NULL)
2150 goto nla_put_failure;
2151 if (set->size &&
2152 nla_put_be32(skb, NFTA_SET_DESC_SIZE, htonl(set->size)))
2153 goto nla_put_failure;
2154 nla_nest_end(skb, desc);
2155
Patrick McHardy20a69342013-10-11 12:06:22 +02002156 return nlmsg_end(skb, nlh);
2157
2158nla_put_failure:
2159 nlmsg_trim(skb, nlh);
2160 return -1;
2161}
2162
2163static int nf_tables_set_notify(const struct nft_ctx *ctx,
2164 const struct nft_set *set,
2165 int event)
2166{
2167 struct sk_buff *skb;
2168 u32 portid = NETLINK_CB(ctx->skb).portid;
Patrick McHardy20a69342013-10-11 12:06:22 +02002169 bool report;
2170 int err;
2171
2172 report = nlmsg_report(ctx->nlh);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002173 if (!report && !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
Patrick McHardy20a69342013-10-11 12:06:22 +02002174 return 0;
2175
2176 err = -ENOBUFS;
2177 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
2178 if (skb == NULL)
2179 goto err;
2180
2181 err = nf_tables_fill_set(skb, ctx, set, event, 0);
2182 if (err < 0) {
2183 kfree_skb(skb);
2184 goto err;
2185 }
2186
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002187 err = nfnetlink_send(skb, ctx->net, portid, NFNLGRP_NFTABLES, report,
Patrick McHardy20a69342013-10-11 12:06:22 +02002188 GFP_KERNEL);
2189err:
2190 if (err < 0)
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002191 nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, err);
Patrick McHardy20a69342013-10-11 12:06:22 +02002192 return err;
2193}
2194
2195static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb,
2196 struct netlink_callback *cb)
2197{
2198 const struct nft_set *set;
2199 unsigned int idx = 0, s_idx = cb->args[0];
2200
2201 if (cb->args[1])
2202 return skb->len;
2203
2204 list_for_each_entry(set, &ctx->table->sets, list) {
2205 if (idx < s_idx)
2206 goto cont;
2207 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
2208 NLM_F_MULTI) < 0) {
2209 cb->args[0] = idx;
2210 goto done;
2211 }
2212cont:
2213 idx++;
2214 }
2215 cb->args[1] = 1;
2216done:
2217 return skb->len;
2218}
2219
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002220static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb,
2221 struct netlink_callback *cb)
Patrick McHardy20a69342013-10-11 12:06:22 +02002222{
2223 const struct nft_set *set;
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002224 unsigned int idx, s_idx = cb->args[0];
Patrick McHardy20a69342013-10-11 12:06:22 +02002225 struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
2226
2227 if (cb->args[1])
2228 return skb->len;
2229
2230 list_for_each_entry(table, &ctx->afi->tables, list) {
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002231 if (cur_table) {
2232 if (cur_table != table)
2233 continue;
Patrick McHardy20a69342013-10-11 12:06:22 +02002234
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002235 cur_table = NULL;
2236 }
Patrick McHardy20a69342013-10-11 12:06:22 +02002237 ctx->table = table;
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002238 idx = 0;
Patrick McHardy20a69342013-10-11 12:06:22 +02002239 list_for_each_entry(set, &ctx->table->sets, list) {
2240 if (idx < s_idx)
2241 goto cont;
2242 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
2243 NLM_F_MULTI) < 0) {
2244 cb->args[0] = idx;
2245 cb->args[2] = (unsigned long) table;
2246 goto done;
2247 }
2248cont:
2249 idx++;
2250 }
2251 }
2252 cb->args[1] = 1;
2253done:
2254 return skb->len;
2255}
2256
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002257static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb,
2258 struct netlink_callback *cb)
2259{
2260 const struct nft_set *set;
2261 unsigned int idx, s_idx = cb->args[0];
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02002262 struct nft_af_info *afi;
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002263 struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
2264 struct net *net = sock_net(skb->sk);
2265 int cur_family = cb->args[3];
2266
2267 if (cb->args[1])
2268 return skb->len;
2269
2270 list_for_each_entry(afi, &net->nft.af_info, list) {
2271 if (cur_family) {
2272 if (afi->family != cur_family)
2273 continue;
2274
2275 cur_family = 0;
2276 }
2277
2278 list_for_each_entry(table, &afi->tables, list) {
2279 if (cur_table) {
2280 if (cur_table != table)
2281 continue;
2282
2283 cur_table = NULL;
2284 }
2285
2286 ctx->table = table;
2287 ctx->afi = afi;
2288 idx = 0;
2289 list_for_each_entry(set, &ctx->table->sets, list) {
2290 if (idx < s_idx)
2291 goto cont;
2292 if (nf_tables_fill_set(skb, ctx, set,
2293 NFT_MSG_NEWSET,
2294 NLM_F_MULTI) < 0) {
2295 cb->args[0] = idx;
2296 cb->args[2] = (unsigned long) table;
2297 cb->args[3] = afi->family;
2298 goto done;
2299 }
2300cont:
2301 idx++;
2302 }
2303 if (s_idx)
2304 s_idx = 0;
2305 }
2306 }
2307 cb->args[1] = 1;
2308done:
2309 return skb->len;
2310}
2311
Patrick McHardy20a69342013-10-11 12:06:22 +02002312static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
2313{
2314 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
2315 struct nlattr *nla[NFTA_SET_MAX + 1];
2316 struct nft_ctx ctx;
2317 int err, ret;
2318
2319 err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_MAX,
2320 nft_set_policy);
2321 if (err < 0)
2322 return err;
2323
2324 err = nft_ctx_init_from_setattr(&ctx, cb->skb, cb->nlh, (void *)nla);
2325 if (err < 0)
2326 return err;
2327
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002328 if (ctx.table == NULL) {
2329 if (ctx.afi == NULL)
2330 ret = nf_tables_dump_sets_all(&ctx, skb, cb);
2331 else
2332 ret = nf_tables_dump_sets_family(&ctx, skb, cb);
2333 } else
Patrick McHardy20a69342013-10-11 12:06:22 +02002334 ret = nf_tables_dump_sets_table(&ctx, skb, cb);
2335
2336 return ret;
2337}
2338
2339static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
2340 const struct nlmsghdr *nlh,
2341 const struct nlattr * const nla[])
2342{
2343 const struct nft_set *set;
2344 struct nft_ctx ctx;
2345 struct sk_buff *skb2;
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002346 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Patrick McHardy20a69342013-10-11 12:06:22 +02002347 int err;
2348
2349 /* Verify existance before starting dump */
2350 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
2351 if (err < 0)
2352 return err;
2353
2354 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2355 struct netlink_dump_control c = {
2356 .dump = nf_tables_dump_sets,
2357 };
2358 return netlink_dump_start(nlsk, skb, nlh, &c);
2359 }
2360
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002361 /* Only accept unspec with dump */
2362 if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
2363 return -EAFNOSUPPORT;
2364
Patrick McHardy20a69342013-10-11 12:06:22 +02002365 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
2366 if (IS_ERR(set))
2367 return PTR_ERR(set);
2368
2369 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2370 if (skb2 == NULL)
2371 return -ENOMEM;
2372
2373 err = nf_tables_fill_set(skb2, &ctx, set, NFT_MSG_NEWSET, 0);
2374 if (err < 0)
2375 goto err;
2376
2377 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
2378
2379err:
2380 kfree_skb(skb2);
2381 return err;
2382}
2383
Patrick McHardyc50b9602014-03-28 10:19:47 +00002384static int nf_tables_set_desc_parse(const struct nft_ctx *ctx,
2385 struct nft_set_desc *desc,
2386 const struct nlattr *nla)
2387{
2388 struct nlattr *da[NFTA_SET_DESC_MAX + 1];
2389 int err;
2390
2391 err = nla_parse_nested(da, NFTA_SET_DESC_MAX, nla, nft_set_desc_policy);
2392 if (err < 0)
2393 return err;
2394
2395 if (da[NFTA_SET_DESC_SIZE] != NULL)
2396 desc->size = ntohl(nla_get_be32(da[NFTA_SET_DESC_SIZE]));
2397
2398 return 0;
2399}
2400
Patrick McHardy20a69342013-10-11 12:06:22 +02002401static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
2402 const struct nlmsghdr *nlh,
2403 const struct nlattr * const nla[])
2404{
2405 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
2406 const struct nft_set_ops *ops;
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02002407 struct nft_af_info *afi;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002408 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02002409 struct nft_table *table;
2410 struct nft_set *set;
2411 struct nft_ctx ctx;
2412 char name[IFNAMSIZ];
2413 unsigned int size;
2414 bool create;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002415 u32 ktype, dtype, flags, policy;
2416 struct nft_set_desc desc;
Patrick McHardy20a69342013-10-11 12:06:22 +02002417 int err;
2418
2419 if (nla[NFTA_SET_TABLE] == NULL ||
2420 nla[NFTA_SET_NAME] == NULL ||
2421 nla[NFTA_SET_KEY_LEN] == NULL)
2422 return -EINVAL;
2423
Patrick McHardyc50b9602014-03-28 10:19:47 +00002424 memset(&desc, 0, sizeof(desc));
2425
Patrick McHardy20a69342013-10-11 12:06:22 +02002426 ktype = NFT_DATA_VALUE;
2427 if (nla[NFTA_SET_KEY_TYPE] != NULL) {
2428 ktype = ntohl(nla_get_be32(nla[NFTA_SET_KEY_TYPE]));
2429 if ((ktype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK)
2430 return -EINVAL;
2431 }
2432
Patrick McHardyc50b9602014-03-28 10:19:47 +00002433 desc.klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
2434 if (desc.klen == 0 || desc.klen > FIELD_SIZEOF(struct nft_data, data))
Patrick McHardy20a69342013-10-11 12:06:22 +02002435 return -EINVAL;
2436
2437 flags = 0;
2438 if (nla[NFTA_SET_FLAGS] != NULL) {
2439 flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
2440 if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
2441 NFT_SET_INTERVAL | NFT_SET_MAP))
2442 return -EINVAL;
2443 }
2444
2445 dtype = 0;
Patrick McHardy20a69342013-10-11 12:06:22 +02002446 if (nla[NFTA_SET_DATA_TYPE] != NULL) {
2447 if (!(flags & NFT_SET_MAP))
2448 return -EINVAL;
2449
2450 dtype = ntohl(nla_get_be32(nla[NFTA_SET_DATA_TYPE]));
2451 if ((dtype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK &&
2452 dtype != NFT_DATA_VERDICT)
2453 return -EINVAL;
2454
2455 if (dtype != NFT_DATA_VERDICT) {
2456 if (nla[NFTA_SET_DATA_LEN] == NULL)
2457 return -EINVAL;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002458 desc.dlen = ntohl(nla_get_be32(nla[NFTA_SET_DATA_LEN]));
2459 if (desc.dlen == 0 ||
2460 desc.dlen > FIELD_SIZEOF(struct nft_data, data))
Patrick McHardy20a69342013-10-11 12:06:22 +02002461 return -EINVAL;
2462 } else
Patrick McHardyc50b9602014-03-28 10:19:47 +00002463 desc.dlen = sizeof(struct nft_data);
Patrick McHardy20a69342013-10-11 12:06:22 +02002464 } else if (flags & NFT_SET_MAP)
2465 return -EINVAL;
2466
Patrick McHardyc50b9602014-03-28 10:19:47 +00002467 policy = NFT_SET_POL_PERFORMANCE;
2468 if (nla[NFTA_SET_POLICY] != NULL)
2469 policy = ntohl(nla_get_be32(nla[NFTA_SET_POLICY]));
2470
2471 if (nla[NFTA_SET_DESC] != NULL) {
2472 err = nf_tables_set_desc_parse(&ctx, &desc, nla[NFTA_SET_DESC]);
2473 if (err < 0)
2474 return err;
2475 }
2476
Patrick McHardy20a69342013-10-11 12:06:22 +02002477 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
2478
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002479 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
Patrick McHardy20a69342013-10-11 12:06:22 +02002480 if (IS_ERR(afi))
2481 return PTR_ERR(afi);
2482
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002483 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02002484 if (IS_ERR(table))
2485 return PTR_ERR(table);
2486
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002487 nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002488
2489 set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME]);
2490 if (IS_ERR(set)) {
2491 if (PTR_ERR(set) != -ENOENT)
2492 return PTR_ERR(set);
2493 set = NULL;
2494 }
2495
2496 if (set != NULL) {
2497 if (nlh->nlmsg_flags & NLM_F_EXCL)
2498 return -EEXIST;
2499 if (nlh->nlmsg_flags & NLM_F_REPLACE)
2500 return -EOPNOTSUPP;
2501 return 0;
2502 }
2503
2504 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
2505 return -ENOENT;
2506
Patrick McHardyc50b9602014-03-28 10:19:47 +00002507 ops = nft_select_set_ops(nla, &desc, policy);
Patrick McHardy20a69342013-10-11 12:06:22 +02002508 if (IS_ERR(ops))
2509 return PTR_ERR(ops);
2510
2511 size = 0;
2512 if (ops->privsize != NULL)
2513 size = ops->privsize(nla);
2514
2515 err = -ENOMEM;
2516 set = kzalloc(sizeof(*set) + size, GFP_KERNEL);
2517 if (set == NULL)
2518 goto err1;
2519
2520 nla_strlcpy(name, nla[NFTA_SET_NAME], sizeof(set->name));
2521 err = nf_tables_set_alloc_name(&ctx, set, name);
2522 if (err < 0)
2523 goto err2;
2524
2525 INIT_LIST_HEAD(&set->bindings);
2526 set->ops = ops;
2527 set->ktype = ktype;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002528 set->klen = desc.klen;
Patrick McHardy20a69342013-10-11 12:06:22 +02002529 set->dtype = dtype;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002530 set->dlen = desc.dlen;
Patrick McHardy20a69342013-10-11 12:06:22 +02002531 set->flags = flags;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002532 set->size = desc.size;
Patrick McHardy20a69342013-10-11 12:06:22 +02002533
Patrick McHardyc50b9602014-03-28 10:19:47 +00002534 err = ops->init(set, &desc, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002535 if (err < 0)
2536 goto err2;
2537
2538 list_add_tail(&set->list, &table->sets);
2539 nf_tables_set_notify(&ctx, set, NFT_MSG_NEWSET);
2540 return 0;
2541
2542err2:
2543 kfree(set);
2544err1:
2545 module_put(ops->owner);
2546 return err;
2547}
2548
2549static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
2550{
2551 list_del(&set->list);
Patrick McHardyab9da5c12014-03-07 19:08:31 +01002552 nf_tables_set_notify(ctx, set, NFT_MSG_DELSET);
Patrick McHardy20a69342013-10-11 12:06:22 +02002553
2554 set->ops->destroy(set);
2555 module_put(set->ops->owner);
2556 kfree(set);
2557}
2558
2559static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
2560 const struct nlmsghdr *nlh,
2561 const struct nlattr * const nla[])
2562{
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002563 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Patrick McHardy20a69342013-10-11 12:06:22 +02002564 struct nft_set *set;
2565 struct nft_ctx ctx;
2566 int err;
2567
Patrick McHardyec2c9932014-02-05 15:03:35 +00002568 if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
2569 return -EAFNOSUPPORT;
Patrick McHardy20a69342013-10-11 12:06:22 +02002570 if (nla[NFTA_SET_TABLE] == NULL)
2571 return -EINVAL;
2572
2573 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
2574 if (err < 0)
2575 return err;
2576
2577 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
2578 if (IS_ERR(set))
2579 return PTR_ERR(set);
2580 if (!list_empty(&set->bindings))
2581 return -EBUSY;
2582
2583 nf_tables_set_destroy(&ctx, set);
2584 return 0;
2585}
2586
2587static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
2588 const struct nft_set *set,
2589 const struct nft_set_iter *iter,
2590 const struct nft_set_elem *elem)
2591{
2592 enum nft_registers dreg;
2593
2594 dreg = nft_type_to_reg(set->dtype);
Pablo Neira Ayuso2ee0d3c2013-12-28 00:59:38 +01002595 return nft_validate_data_load(ctx, dreg, &elem->data,
2596 set->dtype == NFT_DATA_VERDICT ?
2597 NFT_DATA_VERDICT : NFT_DATA_VALUE);
Patrick McHardy20a69342013-10-11 12:06:22 +02002598}
2599
2600int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
2601 struct nft_set_binding *binding)
2602{
2603 struct nft_set_binding *i;
2604 struct nft_set_iter iter;
2605
2606 if (!list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
2607 return -EBUSY;
2608
2609 if (set->flags & NFT_SET_MAP) {
2610 /* If the set is already bound to the same chain all
2611 * jumps are already validated for that chain.
2612 */
2613 list_for_each_entry(i, &set->bindings, list) {
2614 if (i->chain == binding->chain)
2615 goto bind;
2616 }
2617
2618 iter.skip = 0;
2619 iter.count = 0;
2620 iter.err = 0;
2621 iter.fn = nf_tables_bind_check_setelem;
2622
2623 set->ops->walk(ctx, set, &iter);
2624 if (iter.err < 0) {
2625 /* Destroy anonymous sets if binding fails */
2626 if (set->flags & NFT_SET_ANONYMOUS)
2627 nf_tables_set_destroy(ctx, set);
2628
2629 return iter.err;
2630 }
2631 }
2632bind:
2633 binding->chain = ctx->chain;
2634 list_add_tail(&binding->list, &set->bindings);
2635 return 0;
2636}
2637
2638void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
2639 struct nft_set_binding *binding)
2640{
2641 list_del(&binding->list);
2642
2643 if (list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
2644 nf_tables_set_destroy(ctx, set);
2645}
2646
2647/*
2648 * Set elements
2649 */
2650
2651static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
2652 [NFTA_SET_ELEM_KEY] = { .type = NLA_NESTED },
2653 [NFTA_SET_ELEM_DATA] = { .type = NLA_NESTED },
2654 [NFTA_SET_ELEM_FLAGS] = { .type = NLA_U32 },
2655};
2656
2657static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
2658 [NFTA_SET_ELEM_LIST_TABLE] = { .type = NLA_STRING },
2659 [NFTA_SET_ELEM_LIST_SET] = { .type = NLA_STRING },
2660 [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NLA_NESTED },
2661};
2662
2663static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx,
2664 const struct sk_buff *skb,
2665 const struct nlmsghdr *nlh,
2666 const struct nlattr * const nla[])
2667{
2668 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02002669 struct nft_af_info *afi;
2670 struct nft_table *table;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002671 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02002672
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002673 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
Patrick McHardy20a69342013-10-11 12:06:22 +02002674 if (IS_ERR(afi))
2675 return PTR_ERR(afi);
2676
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002677 table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02002678 if (IS_ERR(table))
2679 return PTR_ERR(table);
2680
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002681 nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002682 return 0;
2683}
2684
2685static int nf_tables_fill_setelem(struct sk_buff *skb,
2686 const struct nft_set *set,
2687 const struct nft_set_elem *elem)
2688{
2689 unsigned char *b = skb_tail_pointer(skb);
2690 struct nlattr *nest;
2691
2692 nest = nla_nest_start(skb, NFTA_LIST_ELEM);
2693 if (nest == NULL)
2694 goto nla_put_failure;
2695
2696 if (nft_data_dump(skb, NFTA_SET_ELEM_KEY, &elem->key, NFT_DATA_VALUE,
2697 set->klen) < 0)
2698 goto nla_put_failure;
2699
2700 if (set->flags & NFT_SET_MAP &&
2701 !(elem->flags & NFT_SET_ELEM_INTERVAL_END) &&
2702 nft_data_dump(skb, NFTA_SET_ELEM_DATA, &elem->data,
2703 set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE,
2704 set->dlen) < 0)
2705 goto nla_put_failure;
2706
2707 if (elem->flags != 0)
2708 if (nla_put_be32(skb, NFTA_SET_ELEM_FLAGS, htonl(elem->flags)))
2709 goto nla_put_failure;
2710
2711 nla_nest_end(skb, nest);
2712 return 0;
2713
2714nla_put_failure:
2715 nlmsg_trim(skb, b);
2716 return -EMSGSIZE;
2717}
2718
2719struct nft_set_dump_args {
2720 const struct netlink_callback *cb;
2721 struct nft_set_iter iter;
2722 struct sk_buff *skb;
2723};
2724
2725static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
2726 const struct nft_set *set,
2727 const struct nft_set_iter *iter,
2728 const struct nft_set_elem *elem)
2729{
2730 struct nft_set_dump_args *args;
2731
2732 args = container_of(iter, struct nft_set_dump_args, iter);
2733 return nf_tables_fill_setelem(args->skb, set, elem);
2734}
2735
2736static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
2737{
2738 const struct nft_set *set;
2739 struct nft_set_dump_args args;
2740 struct nft_ctx ctx;
2741 struct nlattr *nla[NFTA_SET_ELEM_LIST_MAX + 1];
2742 struct nfgenmsg *nfmsg;
2743 struct nlmsghdr *nlh;
2744 struct nlattr *nest;
2745 u32 portid, seq;
2746 int event, err;
2747
Michal Nazarewicz720e0df2014-01-01 06:27:19 +01002748 err = nlmsg_parse(cb->nlh, sizeof(struct nfgenmsg), nla,
2749 NFTA_SET_ELEM_LIST_MAX, nft_set_elem_list_policy);
Patrick McHardy20a69342013-10-11 12:06:22 +02002750 if (err < 0)
2751 return err;
2752
2753 err = nft_ctx_init_from_elemattr(&ctx, cb->skb, cb->nlh, (void *)nla);
2754 if (err < 0)
2755 return err;
2756
2757 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2758 if (IS_ERR(set))
2759 return PTR_ERR(set);
2760
2761 event = NFT_MSG_NEWSETELEM;
2762 event |= NFNL_SUBSYS_NFTABLES << 8;
2763 portid = NETLINK_CB(cb->skb).portid;
2764 seq = cb->nlh->nlmsg_seq;
2765
2766 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
2767 NLM_F_MULTI);
2768 if (nlh == NULL)
2769 goto nla_put_failure;
2770
2771 nfmsg = nlmsg_data(nlh);
2772 nfmsg->nfgen_family = NFPROTO_UNSPEC;
2773 nfmsg->version = NFNETLINK_V0;
2774 nfmsg->res_id = 0;
2775
2776 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, ctx.table->name))
2777 goto nla_put_failure;
2778 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_SET, set->name))
2779 goto nla_put_failure;
2780
2781 nest = nla_nest_start(skb, NFTA_SET_ELEM_LIST_ELEMENTS);
2782 if (nest == NULL)
2783 goto nla_put_failure;
2784
2785 args.cb = cb;
2786 args.skb = skb;
2787 args.iter.skip = cb->args[0];
2788 args.iter.count = 0;
2789 args.iter.err = 0;
2790 args.iter.fn = nf_tables_dump_setelem;
2791 set->ops->walk(&ctx, set, &args.iter);
2792
2793 nla_nest_end(skb, nest);
2794 nlmsg_end(skb, nlh);
2795
2796 if (args.iter.err && args.iter.err != -EMSGSIZE)
2797 return args.iter.err;
2798 if (args.iter.count == cb->args[0])
2799 return 0;
2800
2801 cb->args[0] = args.iter.count;
2802 return skb->len;
2803
2804nla_put_failure:
2805 return -ENOSPC;
2806}
2807
2808static int nf_tables_getsetelem(struct sock *nlsk, struct sk_buff *skb,
2809 const struct nlmsghdr *nlh,
2810 const struct nlattr * const nla[])
2811{
2812 const struct nft_set *set;
2813 struct nft_ctx ctx;
2814 int err;
2815
2816 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2817 if (err < 0)
2818 return err;
2819
2820 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2821 if (IS_ERR(set))
2822 return PTR_ERR(set);
2823
2824 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2825 struct netlink_dump_control c = {
2826 .dump = nf_tables_dump_set,
2827 };
2828 return netlink_dump_start(nlsk, skb, nlh, &c);
2829 }
2830 return -EOPNOTSUPP;
2831}
2832
Arturo Borrerod60ce622014-04-01 14:06:07 +02002833static int nf_tables_fill_setelem_info(struct sk_buff *skb,
2834 const struct nft_ctx *ctx, u32 seq,
2835 u32 portid, int event, u16 flags,
2836 const struct nft_set *set,
2837 const struct nft_set_elem *elem)
2838{
2839 struct nfgenmsg *nfmsg;
2840 struct nlmsghdr *nlh;
2841 struct nlattr *nest;
2842 int err;
2843
2844 event |= NFNL_SUBSYS_NFTABLES << 8;
2845 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
2846 flags);
2847 if (nlh == NULL)
2848 goto nla_put_failure;
2849
2850 nfmsg = nlmsg_data(nlh);
2851 nfmsg->nfgen_family = ctx->afi->family;
2852 nfmsg->version = NFNETLINK_V0;
2853 nfmsg->res_id = 0;
2854
2855 if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
2856 goto nla_put_failure;
2857 if (nla_put_string(skb, NFTA_SET_NAME, set->name))
2858 goto nla_put_failure;
2859
2860 nest = nla_nest_start(skb, NFTA_SET_ELEM_LIST_ELEMENTS);
2861 if (nest == NULL)
2862 goto nla_put_failure;
2863
2864 err = nf_tables_fill_setelem(skb, set, elem);
2865 if (err < 0)
2866 goto nla_put_failure;
2867
2868 nla_nest_end(skb, nest);
2869
2870 return nlmsg_end(skb, nlh);
2871
2872nla_put_failure:
2873 nlmsg_trim(skb, nlh);
2874 return -1;
2875}
2876
2877static int nf_tables_setelem_notify(const struct nft_ctx *ctx,
2878 const struct nft_set *set,
2879 const struct nft_set_elem *elem,
2880 int event, u16 flags)
2881{
2882 const struct sk_buff *oskb = ctx->skb;
2883 struct net *net = sock_net(oskb->sk);
2884 u32 portid = NETLINK_CB(oskb).portid;
2885 bool report = nlmsg_report(ctx->nlh);
2886 struct sk_buff *skb;
2887 int err;
2888
2889 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
2890 return 0;
2891
2892 err = -ENOBUFS;
2893 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
2894 if (skb == NULL)
2895 goto err;
2896
2897 err = nf_tables_fill_setelem_info(skb, ctx, 0, portid, event, flags,
2898 set, elem);
2899 if (err < 0) {
2900 kfree_skb(skb);
2901 goto err;
2902 }
2903
2904 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
2905 GFP_KERNEL);
2906err:
2907 if (err < 0)
2908 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
2909 return err;
2910}
2911
Patrick McHardy20a69342013-10-11 12:06:22 +02002912static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set,
2913 const struct nlattr *attr)
2914{
2915 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
2916 struct nft_data_desc d1, d2;
2917 struct nft_set_elem elem;
2918 struct nft_set_binding *binding;
2919 enum nft_registers dreg;
2920 int err;
2921
Patrick McHardyc50b9602014-03-28 10:19:47 +00002922 if (set->size && set->nelems == set->size)
2923 return -ENFILE;
2924
Patrick McHardy20a69342013-10-11 12:06:22 +02002925 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
2926 nft_set_elem_policy);
2927 if (err < 0)
2928 return err;
2929
2930 if (nla[NFTA_SET_ELEM_KEY] == NULL)
2931 return -EINVAL;
2932
2933 elem.flags = 0;
2934 if (nla[NFTA_SET_ELEM_FLAGS] != NULL) {
2935 elem.flags = ntohl(nla_get_be32(nla[NFTA_SET_ELEM_FLAGS]));
2936 if (elem.flags & ~NFT_SET_ELEM_INTERVAL_END)
2937 return -EINVAL;
2938 }
2939
2940 if (set->flags & NFT_SET_MAP) {
2941 if (nla[NFTA_SET_ELEM_DATA] == NULL &&
2942 !(elem.flags & NFT_SET_ELEM_INTERVAL_END))
2943 return -EINVAL;
Pablo Neira Ayusobd7fc642014-02-07 12:53:07 +01002944 if (nla[NFTA_SET_ELEM_DATA] != NULL &&
2945 elem.flags & NFT_SET_ELEM_INTERVAL_END)
2946 return -EINVAL;
Patrick McHardy20a69342013-10-11 12:06:22 +02002947 } else {
2948 if (nla[NFTA_SET_ELEM_DATA] != NULL)
2949 return -EINVAL;
2950 }
2951
2952 err = nft_data_init(ctx, &elem.key, &d1, nla[NFTA_SET_ELEM_KEY]);
2953 if (err < 0)
2954 goto err1;
2955 err = -EINVAL;
2956 if (d1.type != NFT_DATA_VALUE || d1.len != set->klen)
2957 goto err2;
2958
2959 err = -EEXIST;
2960 if (set->ops->get(set, &elem) == 0)
2961 goto err2;
2962
2963 if (nla[NFTA_SET_ELEM_DATA] != NULL) {
2964 err = nft_data_init(ctx, &elem.data, &d2, nla[NFTA_SET_ELEM_DATA]);
2965 if (err < 0)
2966 goto err2;
2967
2968 err = -EINVAL;
2969 if (set->dtype != NFT_DATA_VERDICT && d2.len != set->dlen)
2970 goto err3;
2971
2972 dreg = nft_type_to_reg(set->dtype);
2973 list_for_each_entry(binding, &set->bindings, list) {
2974 struct nft_ctx bind_ctx = {
2975 .afi = ctx->afi,
2976 .table = ctx->table,
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02002977 .chain = (struct nft_chain *)binding->chain,
Patrick McHardy20a69342013-10-11 12:06:22 +02002978 };
2979
2980 err = nft_validate_data_load(&bind_ctx, dreg,
2981 &elem.data, d2.type);
2982 if (err < 0)
2983 goto err3;
2984 }
2985 }
2986
2987 err = set->ops->insert(set, &elem);
2988 if (err < 0)
2989 goto err3;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002990 set->nelems++;
Patrick McHardy20a69342013-10-11 12:06:22 +02002991
Arturo Borrerod60ce622014-04-01 14:06:07 +02002992 nf_tables_setelem_notify(ctx, set, &elem, NFT_MSG_NEWSETELEM, 0);
Patrick McHardy20a69342013-10-11 12:06:22 +02002993 return 0;
2994
2995err3:
2996 if (nla[NFTA_SET_ELEM_DATA] != NULL)
2997 nft_data_uninit(&elem.data, d2.type);
2998err2:
2999 nft_data_uninit(&elem.key, d1.type);
3000err1:
3001 return err;
3002}
3003
3004static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
3005 const struct nlmsghdr *nlh,
3006 const struct nlattr * const nla[])
3007{
3008 const struct nlattr *attr;
3009 struct nft_set *set;
3010 struct nft_ctx ctx;
3011 int rem, err;
3012
3013 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
3014 if (err < 0)
3015 return err;
3016
3017 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
3018 if (IS_ERR(set))
3019 return PTR_ERR(set);
3020 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
3021 return -EBUSY;
3022
3023 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
3024 err = nft_add_set_elem(&ctx, set, attr);
3025 if (err < 0)
3026 return err;
3027 }
3028 return 0;
3029}
3030
3031static int nft_del_setelem(const struct nft_ctx *ctx, struct nft_set *set,
3032 const struct nlattr *attr)
3033{
3034 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
3035 struct nft_data_desc desc;
3036 struct nft_set_elem elem;
3037 int err;
3038
3039 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
3040 nft_set_elem_policy);
3041 if (err < 0)
3042 goto err1;
3043
3044 err = -EINVAL;
3045 if (nla[NFTA_SET_ELEM_KEY] == NULL)
3046 goto err1;
3047
3048 err = nft_data_init(ctx, &elem.key, &desc, nla[NFTA_SET_ELEM_KEY]);
3049 if (err < 0)
3050 goto err1;
3051
3052 err = -EINVAL;
3053 if (desc.type != NFT_DATA_VALUE || desc.len != set->klen)
3054 goto err2;
3055
3056 err = set->ops->get(set, &elem);
3057 if (err < 0)
3058 goto err2;
3059
3060 set->ops->remove(set, &elem);
Patrick McHardyc50b9602014-03-28 10:19:47 +00003061 set->nelems--;
Patrick McHardy20a69342013-10-11 12:06:22 +02003062
Arturo Borrerod60ce622014-04-01 14:06:07 +02003063 nf_tables_setelem_notify(ctx, set, &elem, NFT_MSG_DELSETELEM, 0);
3064
Patrick McHardy20a69342013-10-11 12:06:22 +02003065 nft_data_uninit(&elem.key, NFT_DATA_VALUE);
3066 if (set->flags & NFT_SET_MAP)
3067 nft_data_uninit(&elem.data, set->dtype);
3068
3069err2:
3070 nft_data_uninit(&elem.key, desc.type);
3071err1:
3072 return err;
3073}
3074
3075static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
3076 const struct nlmsghdr *nlh,
3077 const struct nlattr * const nla[])
3078{
3079 const struct nlattr *attr;
3080 struct nft_set *set;
3081 struct nft_ctx ctx;
3082 int rem, err;
3083
3084 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
3085 if (err < 0)
3086 return err;
3087
3088 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
3089 if (IS_ERR(set))
3090 return PTR_ERR(set);
3091 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
3092 return -EBUSY;
3093
3094 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
3095 err = nft_del_setelem(&ctx, set, attr);
3096 if (err < 0)
3097 return err;
3098 }
3099 return 0;
3100}
3101
Patrick McHardy96518512013-10-14 11:00:02 +02003102static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
3103 [NFT_MSG_NEWTABLE] = {
3104 .call = nf_tables_newtable,
3105 .attr_count = NFTA_TABLE_MAX,
3106 .policy = nft_table_policy,
3107 },
3108 [NFT_MSG_GETTABLE] = {
3109 .call = nf_tables_gettable,
3110 .attr_count = NFTA_TABLE_MAX,
3111 .policy = nft_table_policy,
3112 },
3113 [NFT_MSG_DELTABLE] = {
3114 .call = nf_tables_deltable,
3115 .attr_count = NFTA_TABLE_MAX,
3116 .policy = nft_table_policy,
3117 },
3118 [NFT_MSG_NEWCHAIN] = {
3119 .call = nf_tables_newchain,
3120 .attr_count = NFTA_CHAIN_MAX,
3121 .policy = nft_chain_policy,
3122 },
3123 [NFT_MSG_GETCHAIN] = {
3124 .call = nf_tables_getchain,
3125 .attr_count = NFTA_CHAIN_MAX,
3126 .policy = nft_chain_policy,
3127 },
3128 [NFT_MSG_DELCHAIN] = {
3129 .call = nf_tables_delchain,
3130 .attr_count = NFTA_CHAIN_MAX,
3131 .policy = nft_chain_policy,
3132 },
3133 [NFT_MSG_NEWRULE] = {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02003134 .call_batch = nf_tables_newrule,
Patrick McHardy96518512013-10-14 11:00:02 +02003135 .attr_count = NFTA_RULE_MAX,
3136 .policy = nft_rule_policy,
3137 },
3138 [NFT_MSG_GETRULE] = {
3139 .call = nf_tables_getrule,
3140 .attr_count = NFTA_RULE_MAX,
3141 .policy = nft_rule_policy,
3142 },
3143 [NFT_MSG_DELRULE] = {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02003144 .call_batch = nf_tables_delrule,
Patrick McHardy96518512013-10-14 11:00:02 +02003145 .attr_count = NFTA_RULE_MAX,
3146 .policy = nft_rule_policy,
3147 },
Patrick McHardy20a69342013-10-11 12:06:22 +02003148 [NFT_MSG_NEWSET] = {
3149 .call = nf_tables_newset,
3150 .attr_count = NFTA_SET_MAX,
3151 .policy = nft_set_policy,
3152 },
3153 [NFT_MSG_GETSET] = {
3154 .call = nf_tables_getset,
3155 .attr_count = NFTA_SET_MAX,
3156 .policy = nft_set_policy,
3157 },
3158 [NFT_MSG_DELSET] = {
3159 .call = nf_tables_delset,
3160 .attr_count = NFTA_SET_MAX,
3161 .policy = nft_set_policy,
3162 },
3163 [NFT_MSG_NEWSETELEM] = {
3164 .call = nf_tables_newsetelem,
3165 .attr_count = NFTA_SET_ELEM_LIST_MAX,
3166 .policy = nft_set_elem_list_policy,
3167 },
3168 [NFT_MSG_GETSETELEM] = {
3169 .call = nf_tables_getsetelem,
3170 .attr_count = NFTA_SET_ELEM_LIST_MAX,
3171 .policy = nft_set_elem_list_policy,
3172 },
3173 [NFT_MSG_DELSETELEM] = {
3174 .call = nf_tables_delsetelem,
3175 .attr_count = NFTA_SET_ELEM_LIST_MAX,
3176 .policy = nft_set_elem_list_policy,
3177 },
Patrick McHardy96518512013-10-14 11:00:02 +02003178};
3179
3180static const struct nfnetlink_subsystem nf_tables_subsys = {
3181 .name = "nf_tables",
3182 .subsys_id = NFNL_SUBSYS_NFTABLES,
3183 .cb_count = NFT_MSG_MAX,
3184 .cb = nf_tables_cb,
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02003185 .commit = nf_tables_commit,
3186 .abort = nf_tables_abort,
Patrick McHardy96518512013-10-14 11:00:02 +02003187};
3188
Patrick McHardy20a69342013-10-11 12:06:22 +02003189/*
3190 * Loop detection - walk through the ruleset beginning at the destination chain
3191 * of a new jump until either the source chain is reached (loop) or all
3192 * reachable chains have been traversed.
3193 *
3194 * The loop check is performed whenever a new jump verdict is added to an
3195 * expression or verdict map or a verdict map is bound to a new chain.
3196 */
3197
3198static int nf_tables_check_loops(const struct nft_ctx *ctx,
3199 const struct nft_chain *chain);
3200
3201static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
3202 const struct nft_set *set,
3203 const struct nft_set_iter *iter,
3204 const struct nft_set_elem *elem)
3205{
Pablo Neira Ayuso62f9c8b2014-02-07 14:45:01 +01003206 if (elem->flags & NFT_SET_ELEM_INTERVAL_END)
3207 return 0;
3208
Patrick McHardy20a69342013-10-11 12:06:22 +02003209 switch (elem->data.verdict) {
3210 case NFT_JUMP:
3211 case NFT_GOTO:
3212 return nf_tables_check_loops(ctx, elem->data.chain);
3213 default:
3214 return 0;
3215 }
3216}
3217
3218static int nf_tables_check_loops(const struct nft_ctx *ctx,
3219 const struct nft_chain *chain)
3220{
3221 const struct nft_rule *rule;
3222 const struct nft_expr *expr, *last;
Patrick McHardy20a69342013-10-11 12:06:22 +02003223 const struct nft_set *set;
3224 struct nft_set_binding *binding;
3225 struct nft_set_iter iter;
Patrick McHardy20a69342013-10-11 12:06:22 +02003226
3227 if (ctx->chain == chain)
3228 return -ELOOP;
3229
3230 list_for_each_entry(rule, &chain->rules, list) {
3231 nft_rule_for_each_expr(expr, last, rule) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02003232 const struct nft_data *data = NULL;
3233 int err;
3234
3235 if (!expr->ops->validate)
Patrick McHardy20a69342013-10-11 12:06:22 +02003236 continue;
3237
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02003238 err = expr->ops->validate(ctx, expr, &data);
3239 if (err < 0)
3240 return err;
3241
Patrick McHardy20a69342013-10-11 12:06:22 +02003242 if (data == NULL)
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02003243 continue;
Patrick McHardy20a69342013-10-11 12:06:22 +02003244
3245 switch (data->verdict) {
3246 case NFT_JUMP:
3247 case NFT_GOTO:
3248 err = nf_tables_check_loops(ctx, data->chain);
3249 if (err < 0)
3250 return err;
3251 default:
3252 break;
3253 }
3254 }
3255 }
3256
3257 list_for_each_entry(set, &ctx->table->sets, list) {
3258 if (!(set->flags & NFT_SET_MAP) ||
3259 set->dtype != NFT_DATA_VERDICT)
3260 continue;
3261
3262 list_for_each_entry(binding, &set->bindings, list) {
3263 if (binding->chain != chain)
3264 continue;
3265
3266 iter.skip = 0;
3267 iter.count = 0;
3268 iter.err = 0;
3269 iter.fn = nf_tables_loop_check_setelem;
3270
3271 set->ops->walk(ctx, set, &iter);
3272 if (iter.err < 0)
3273 return iter.err;
3274 }
3275 }
3276
3277 return 0;
3278}
3279
Patrick McHardy96518512013-10-14 11:00:02 +02003280/**
3281 * nft_validate_input_register - validate an expressions' input register
3282 *
3283 * @reg: the register number
3284 *
3285 * Validate that the input register is one of the general purpose
3286 * registers.
3287 */
3288int nft_validate_input_register(enum nft_registers reg)
3289{
3290 if (reg <= NFT_REG_VERDICT)
3291 return -EINVAL;
3292 if (reg > NFT_REG_MAX)
3293 return -ERANGE;
3294 return 0;
3295}
3296EXPORT_SYMBOL_GPL(nft_validate_input_register);
3297
3298/**
3299 * nft_validate_output_register - validate an expressions' output register
3300 *
3301 * @reg: the register number
3302 *
3303 * Validate that the output register is one of the general purpose
3304 * registers or the verdict register.
3305 */
3306int nft_validate_output_register(enum nft_registers reg)
3307{
3308 if (reg < NFT_REG_VERDICT)
3309 return -EINVAL;
3310 if (reg > NFT_REG_MAX)
3311 return -ERANGE;
3312 return 0;
3313}
3314EXPORT_SYMBOL_GPL(nft_validate_output_register);
3315
3316/**
3317 * nft_validate_data_load - validate an expressions' data load
3318 *
3319 * @ctx: context of the expression performing the load
3320 * @reg: the destination register number
3321 * @data: the data to load
3322 * @type: the data type
3323 *
3324 * Validate that a data load uses the appropriate data type for
3325 * the destination register. A value of NULL for the data means
3326 * that its runtime gathered data, which is always of type
3327 * NFT_DATA_VALUE.
3328 */
3329int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
3330 const struct nft_data *data,
3331 enum nft_data_types type)
3332{
Patrick McHardy20a69342013-10-11 12:06:22 +02003333 int err;
3334
Patrick McHardy96518512013-10-14 11:00:02 +02003335 switch (reg) {
3336 case NFT_REG_VERDICT:
3337 if (data == NULL || type != NFT_DATA_VERDICT)
3338 return -EINVAL;
Patrick McHardy20a69342013-10-11 12:06:22 +02003339
3340 if (data->verdict == NFT_GOTO || data->verdict == NFT_JUMP) {
3341 err = nf_tables_check_loops(ctx, data->chain);
3342 if (err < 0)
3343 return err;
3344
3345 if (ctx->chain->level + 1 > data->chain->level) {
3346 if (ctx->chain->level + 1 == NFT_JUMP_STACK_SIZE)
3347 return -EMLINK;
3348 data->chain->level = ctx->chain->level + 1;
3349 }
3350 }
3351
Patrick McHardy96518512013-10-14 11:00:02 +02003352 return 0;
3353 default:
3354 if (data != NULL && type != NFT_DATA_VALUE)
3355 return -EINVAL;
3356 return 0;
3357 }
3358}
3359EXPORT_SYMBOL_GPL(nft_validate_data_load);
3360
3361static const struct nla_policy nft_verdict_policy[NFTA_VERDICT_MAX + 1] = {
3362 [NFTA_VERDICT_CODE] = { .type = NLA_U32 },
3363 [NFTA_VERDICT_CHAIN] = { .type = NLA_STRING,
3364 .len = NFT_CHAIN_MAXNAMELEN - 1 },
3365};
3366
3367static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
3368 struct nft_data_desc *desc, const struct nlattr *nla)
3369{
3370 struct nlattr *tb[NFTA_VERDICT_MAX + 1];
3371 struct nft_chain *chain;
3372 int err;
3373
3374 err = nla_parse_nested(tb, NFTA_VERDICT_MAX, nla, nft_verdict_policy);
3375 if (err < 0)
3376 return err;
3377
3378 if (!tb[NFTA_VERDICT_CODE])
3379 return -EINVAL;
3380 data->verdict = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE]));
3381
3382 switch (data->verdict) {
Patrick McHardye0abdad2014-02-18 18:06:50 +00003383 default:
3384 switch (data->verdict & NF_VERDICT_MASK) {
3385 case NF_ACCEPT:
3386 case NF_DROP:
3387 case NF_QUEUE:
3388 break;
3389 default:
3390 return -EINVAL;
3391 }
3392 /* fall through */
Patrick McHardy96518512013-10-14 11:00:02 +02003393 case NFT_CONTINUE:
3394 case NFT_BREAK:
3395 case NFT_RETURN:
3396 desc->len = sizeof(data->verdict);
3397 break;
3398 case NFT_JUMP:
3399 case NFT_GOTO:
3400 if (!tb[NFTA_VERDICT_CHAIN])
3401 return -EINVAL;
3402 chain = nf_tables_chain_lookup(ctx->table,
3403 tb[NFTA_VERDICT_CHAIN]);
3404 if (IS_ERR(chain))
3405 return PTR_ERR(chain);
3406 if (chain->flags & NFT_BASE_CHAIN)
3407 return -EOPNOTSUPP;
3408
Patrick McHardy96518512013-10-14 11:00:02 +02003409 chain->use++;
3410 data->chain = chain;
3411 desc->len = sizeof(data);
3412 break;
Patrick McHardy96518512013-10-14 11:00:02 +02003413 }
3414
3415 desc->type = NFT_DATA_VERDICT;
3416 return 0;
3417}
3418
3419static void nft_verdict_uninit(const struct nft_data *data)
3420{
3421 switch (data->verdict) {
3422 case NFT_JUMP:
3423 case NFT_GOTO:
3424 data->chain->use--;
3425 break;
3426 }
3427}
3428
3429static int nft_verdict_dump(struct sk_buff *skb, const struct nft_data *data)
3430{
3431 struct nlattr *nest;
3432
3433 nest = nla_nest_start(skb, NFTA_DATA_VERDICT);
3434 if (!nest)
3435 goto nla_put_failure;
3436
3437 if (nla_put_be32(skb, NFTA_VERDICT_CODE, htonl(data->verdict)))
3438 goto nla_put_failure;
3439
3440 switch (data->verdict) {
3441 case NFT_JUMP:
3442 case NFT_GOTO:
3443 if (nla_put_string(skb, NFTA_VERDICT_CHAIN, data->chain->name))
3444 goto nla_put_failure;
3445 }
3446 nla_nest_end(skb, nest);
3447 return 0;
3448
3449nla_put_failure:
3450 return -1;
3451}
3452
3453static int nft_value_init(const struct nft_ctx *ctx, struct nft_data *data,
3454 struct nft_data_desc *desc, const struct nlattr *nla)
3455{
3456 unsigned int len;
3457
3458 len = nla_len(nla);
3459 if (len == 0)
3460 return -EINVAL;
3461 if (len > sizeof(data->data))
3462 return -EOVERFLOW;
3463
3464 nla_memcpy(data->data, nla, sizeof(data->data));
3465 desc->type = NFT_DATA_VALUE;
3466 desc->len = len;
3467 return 0;
3468}
3469
3470static int nft_value_dump(struct sk_buff *skb, const struct nft_data *data,
3471 unsigned int len)
3472{
3473 return nla_put(skb, NFTA_DATA_VALUE, len, data->data);
3474}
3475
3476static const struct nla_policy nft_data_policy[NFTA_DATA_MAX + 1] = {
3477 [NFTA_DATA_VALUE] = { .type = NLA_BINARY,
3478 .len = FIELD_SIZEOF(struct nft_data, data) },
3479 [NFTA_DATA_VERDICT] = { .type = NLA_NESTED },
3480};
3481
3482/**
3483 * nft_data_init - parse nf_tables data netlink attributes
3484 *
3485 * @ctx: context of the expression using the data
3486 * @data: destination struct nft_data
3487 * @desc: data description
3488 * @nla: netlink attribute containing data
3489 *
3490 * Parse the netlink data attributes and initialize a struct nft_data.
3491 * The type and length of data are returned in the data description.
3492 *
3493 * The caller can indicate that it only wants to accept data of type
3494 * NFT_DATA_VALUE by passing NULL for the ctx argument.
3495 */
3496int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data,
3497 struct nft_data_desc *desc, const struct nlattr *nla)
3498{
3499 struct nlattr *tb[NFTA_DATA_MAX + 1];
3500 int err;
3501
3502 err = nla_parse_nested(tb, NFTA_DATA_MAX, nla, nft_data_policy);
3503 if (err < 0)
3504 return err;
3505
3506 if (tb[NFTA_DATA_VALUE])
3507 return nft_value_init(ctx, data, desc, tb[NFTA_DATA_VALUE]);
3508 if (tb[NFTA_DATA_VERDICT] && ctx != NULL)
3509 return nft_verdict_init(ctx, data, desc, tb[NFTA_DATA_VERDICT]);
3510 return -EINVAL;
3511}
3512EXPORT_SYMBOL_GPL(nft_data_init);
3513
3514/**
3515 * nft_data_uninit - release a nft_data item
3516 *
3517 * @data: struct nft_data to release
3518 * @type: type of data
3519 *
3520 * Release a nft_data item. NFT_DATA_VALUE types can be silently discarded,
3521 * all others need to be released by calling this function.
3522 */
3523void nft_data_uninit(const struct nft_data *data, enum nft_data_types type)
3524{
3525 switch (type) {
3526 case NFT_DATA_VALUE:
3527 return;
3528 case NFT_DATA_VERDICT:
3529 return nft_verdict_uninit(data);
3530 default:
3531 WARN_ON(1);
3532 }
3533}
3534EXPORT_SYMBOL_GPL(nft_data_uninit);
3535
3536int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
3537 enum nft_data_types type, unsigned int len)
3538{
3539 struct nlattr *nest;
3540 int err;
3541
3542 nest = nla_nest_start(skb, attr);
3543 if (nest == NULL)
3544 return -1;
3545
3546 switch (type) {
3547 case NFT_DATA_VALUE:
3548 err = nft_value_dump(skb, data, len);
3549 break;
3550 case NFT_DATA_VERDICT:
3551 err = nft_verdict_dump(skb, data);
3552 break;
3553 default:
3554 err = -EINVAL;
3555 WARN_ON(1);
3556 }
3557
3558 nla_nest_end(skb, nest);
3559 return err;
3560}
3561EXPORT_SYMBOL_GPL(nft_data_dump);
3562
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003563static int nf_tables_init_net(struct net *net)
3564{
3565 INIT_LIST_HEAD(&net->nft.af_info);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02003566 INIT_LIST_HEAD(&net->nft.commit_list);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003567 return 0;
3568}
3569
3570static struct pernet_operations nf_tables_net_ops = {
3571 .init = nf_tables_init_net,
3572};
3573
Patrick McHardy96518512013-10-14 11:00:02 +02003574static int __init nf_tables_module_init(void)
3575{
3576 int err;
3577
3578 info = kmalloc(sizeof(struct nft_expr_info) * NFT_RULE_MAXEXPRS,
3579 GFP_KERNEL);
3580 if (info == NULL) {
3581 err = -ENOMEM;
3582 goto err1;
3583 }
3584
3585 err = nf_tables_core_module_init();
3586 if (err < 0)
3587 goto err2;
3588
3589 err = nfnetlink_subsys_register(&nf_tables_subsys);
3590 if (err < 0)
3591 goto err3;
3592
3593 pr_info("nf_tables: (c) 2007-2009 Patrick McHardy <kaber@trash.net>\n");
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003594 return register_pernet_subsys(&nf_tables_net_ops);
Patrick McHardy96518512013-10-14 11:00:02 +02003595err3:
3596 nf_tables_core_module_exit();
3597err2:
3598 kfree(info);
3599err1:
3600 return err;
3601}
3602
3603static void __exit nf_tables_module_exit(void)
3604{
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003605 unregister_pernet_subsys(&nf_tables_net_ops);
Patrick McHardy96518512013-10-14 11:00:02 +02003606 nfnetlink_subsys_unregister(&nf_tables_subsys);
3607 nf_tables_core_module_exit();
3608 kfree(info);
3609}
3610
3611module_init(nf_tables_module_init);
3612module_exit(nf_tables_module_exit);
3613
3614MODULE_LICENSE("GPL");
3615MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
3616MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFTABLES);