blob: 572d88dd3e5fe027bf9beb4cc61438d9e10d737e [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
91/*
92 * Tables
93 */
94
95static struct nft_table *nft_table_lookup(const struct nft_af_info *afi,
96 const struct nlattr *nla)
97{
98 struct nft_table *table;
99
100 list_for_each_entry(table, &afi->tables, list) {
101 if (!nla_strcmp(nla, table->name))
102 return table;
103 }
104 return NULL;
105}
106
107static struct nft_table *nf_tables_table_lookup(const struct nft_af_info *afi,
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200108 const struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +0200109{
110 struct nft_table *table;
111
112 if (nla == NULL)
113 return ERR_PTR(-EINVAL);
114
115 table = nft_table_lookup(afi, nla);
116 if (table != NULL)
117 return table;
118
Patrick McHardy96518512013-10-14 11:00:02 +0200119 return ERR_PTR(-ENOENT);
120}
121
122static inline u64 nf_tables_alloc_handle(struct nft_table *table)
123{
124 return ++table->hgenerator;
125}
126
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200127static struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX];
128
129static int __nf_tables_chain_type_lookup(int family, const struct nlattr *nla)
130{
131 int i;
132
133 for (i=0; i<NFT_CHAIN_T_MAX; i++) {
134 if (chain_type[family][i] != NULL &&
135 !nla_strcmp(nla, chain_type[family][i]->name))
136 return i;
137 }
138 return -1;
139}
140
141static int nf_tables_chain_type_lookup(const struct nft_af_info *afi,
142 const struct nlattr *nla,
143 bool autoload)
144{
145 int type;
146
147 type = __nf_tables_chain_type_lookup(afi->family, nla);
148#ifdef CONFIG_MODULES
149 if (type < 0 && autoload) {
150 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
151 request_module("nft-chain-%u-%*.s", afi->family,
152 nla_len(nla)-1, (const char *)nla_data(nla));
153 nfnl_lock(NFNL_SUBSYS_NFTABLES);
154 type = __nf_tables_chain_type_lookup(afi->family, nla);
155 }
156#endif
157 return type;
158}
159
Patrick McHardy96518512013-10-14 11:00:02 +0200160static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
161 [NFTA_TABLE_NAME] = { .type = NLA_STRING },
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200162 [NFTA_TABLE_FLAGS] = { .type = NLA_U32 },
Patrick McHardy96518512013-10-14 11:00:02 +0200163};
164
165static int nf_tables_fill_table_info(struct sk_buff *skb, u32 portid, u32 seq,
166 int event, u32 flags, int family,
167 const struct nft_table *table)
168{
169 struct nlmsghdr *nlh;
170 struct nfgenmsg *nfmsg;
171
172 event |= NFNL_SUBSYS_NFTABLES << 8;
173 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
174 if (nlh == NULL)
175 goto nla_put_failure;
176
177 nfmsg = nlmsg_data(nlh);
178 nfmsg->nfgen_family = family;
179 nfmsg->version = NFNETLINK_V0;
180 nfmsg->res_id = 0;
181
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200182 if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
Tomasz Bursztykad8bcc7682013-12-12 15:00:42 +0200183 nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
184 nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)))
Patrick McHardy96518512013-10-14 11:00:02 +0200185 goto nla_put_failure;
186
187 return nlmsg_end(skb, nlh);
188
189nla_put_failure:
190 nlmsg_trim(skb, nlh);
191 return -1;
192}
193
194static int nf_tables_table_notify(const struct sk_buff *oskb,
195 const struct nlmsghdr *nlh,
196 const struct nft_table *table,
197 int event, int family)
198{
199 struct sk_buff *skb;
200 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
201 u32 seq = nlh ? nlh->nlmsg_seq : 0;
202 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
203 bool report;
204 int err;
205
206 report = nlh ? nlmsg_report(nlh) : false;
207 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
208 return 0;
209
210 err = -ENOBUFS;
211 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
212 if (skb == NULL)
213 goto err;
214
215 err = nf_tables_fill_table_info(skb, portid, seq, event, 0,
216 family, table);
217 if (err < 0) {
218 kfree_skb(skb);
219 goto err;
220 }
221
222 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
223 GFP_KERNEL);
224err:
225 if (err < 0)
226 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
227 return err;
228}
229
230static int nf_tables_dump_tables(struct sk_buff *skb,
231 struct netlink_callback *cb)
232{
233 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
234 const struct nft_af_info *afi;
235 const struct nft_table *table;
236 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200237 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200238 int family = nfmsg->nfgen_family;
239
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200240 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +0200241 if (family != NFPROTO_UNSPEC && family != afi->family)
242 continue;
243
244 list_for_each_entry(table, &afi->tables, list) {
245 if (idx < s_idx)
246 goto cont;
247 if (idx > s_idx)
248 memset(&cb->args[1], 0,
249 sizeof(cb->args) - sizeof(cb->args[0]));
250 if (nf_tables_fill_table_info(skb,
251 NETLINK_CB(cb->skb).portid,
252 cb->nlh->nlmsg_seq,
253 NFT_MSG_NEWTABLE,
254 NLM_F_MULTI,
255 afi->family, table) < 0)
256 goto done;
257cont:
258 idx++;
259 }
260 }
261done:
262 cb->args[0] = idx;
263 return skb->len;
264}
265
266static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb,
267 const struct nlmsghdr *nlh,
268 const struct nlattr * const nla[])
269{
270 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
271 const struct nft_af_info *afi;
272 const struct nft_table *table;
273 struct sk_buff *skb2;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200274 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200275 int family = nfmsg->nfgen_family;
276 int err;
277
278 if (nlh->nlmsg_flags & NLM_F_DUMP) {
279 struct netlink_dump_control c = {
280 .dump = nf_tables_dump_tables,
281 };
282 return netlink_dump_start(nlsk, skb, nlh, &c);
283 }
284
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200285 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200286 if (IS_ERR(afi))
287 return PTR_ERR(afi);
288
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200289 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
Patrick McHardy96518512013-10-14 11:00:02 +0200290 if (IS_ERR(table))
291 return PTR_ERR(table);
292
293 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
294 if (!skb2)
295 return -ENOMEM;
296
297 err = nf_tables_fill_table_info(skb2, NETLINK_CB(skb).portid,
298 nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0,
299 family, table);
300 if (err < 0)
301 goto err;
302
303 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
304
305err:
306 kfree_skb(skb2);
307 return err;
308}
309
Patrick McHardy115a60b2014-01-03 12:16:15 +0000310static int nf_tables_table_enable(const struct nft_af_info *afi,
311 struct nft_table *table)
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200312{
313 struct nft_chain *chain;
314 int err, i = 0;
315
316 list_for_each_entry(chain, &table->chains, list) {
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100317 if (!(chain->flags & NFT_BASE_CHAIN))
318 continue;
319
Patrick McHardy115a60b2014-01-03 12:16:15 +0000320 err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200321 if (err < 0)
322 goto err;
323
324 i++;
325 }
326 return 0;
327err:
328 list_for_each_entry(chain, &table->chains, list) {
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100329 if (!(chain->flags & NFT_BASE_CHAIN))
330 continue;
331
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200332 if (i-- <= 0)
333 break;
334
Patrick McHardy115a60b2014-01-03 12:16:15 +0000335 nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200336 }
337 return err;
338}
339
Patrick McHardy115a60b2014-01-03 12:16:15 +0000340static int nf_tables_table_disable(const struct nft_af_info *afi,
341 struct nft_table *table)
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200342{
343 struct nft_chain *chain;
344
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100345 list_for_each_entry(chain, &table->chains, list) {
346 if (chain->flags & NFT_BASE_CHAIN)
Patrick McHardy115a60b2014-01-03 12:16:15 +0000347 nf_unregister_hooks(nft_base_chain(chain)->ops,
348 afi->nops);
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100349 }
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200350
351 return 0;
352}
353
354static int nf_tables_updtable(struct sock *nlsk, struct sk_buff *skb,
355 const struct nlmsghdr *nlh,
356 const struct nlattr * const nla[],
357 struct nft_af_info *afi, struct nft_table *table)
358{
359 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
360 int family = nfmsg->nfgen_family, ret = 0;
361
362 if (nla[NFTA_TABLE_FLAGS]) {
363 __be32 flags;
364
365 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
366 if (flags & ~NFT_TABLE_F_DORMANT)
367 return -EINVAL;
368
369 if ((flags & NFT_TABLE_F_DORMANT) &&
370 !(table->flags & NFT_TABLE_F_DORMANT)) {
Patrick McHardy115a60b2014-01-03 12:16:15 +0000371 ret = nf_tables_table_disable(afi, table);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200372 if (ret >= 0)
373 table->flags |= NFT_TABLE_F_DORMANT;
374 } else if (!(flags & NFT_TABLE_F_DORMANT) &&
375 table->flags & NFT_TABLE_F_DORMANT) {
Patrick McHardy115a60b2014-01-03 12:16:15 +0000376 ret = nf_tables_table_enable(afi, table);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200377 if (ret >= 0)
378 table->flags &= ~NFT_TABLE_F_DORMANT;
379 }
380 if (ret < 0)
381 goto err;
382 }
383
384 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
385err:
386 return ret;
387}
388
Patrick McHardy96518512013-10-14 11:00:02 +0200389static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
390 const struct nlmsghdr *nlh,
391 const struct nlattr * const nla[])
392{
393 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
394 const struct nlattr *name;
395 struct nft_af_info *afi;
396 struct nft_table *table;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200397 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200398 int family = nfmsg->nfgen_family;
399
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200400 afi = nf_tables_afinfo_lookup(net, family, true);
Patrick McHardy96518512013-10-14 11:00:02 +0200401 if (IS_ERR(afi))
402 return PTR_ERR(afi);
403
404 name = nla[NFTA_TABLE_NAME];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200405 table = nf_tables_table_lookup(afi, name);
Patrick McHardy96518512013-10-14 11:00:02 +0200406 if (IS_ERR(table)) {
407 if (PTR_ERR(table) != -ENOENT)
408 return PTR_ERR(table);
409 table = NULL;
410 }
411
412 if (table != NULL) {
413 if (nlh->nlmsg_flags & NLM_F_EXCL)
414 return -EEXIST;
415 if (nlh->nlmsg_flags & NLM_F_REPLACE)
416 return -EOPNOTSUPP;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200417 return nf_tables_updtable(nlsk, skb, nlh, nla, afi, table);
Patrick McHardy96518512013-10-14 11:00:02 +0200418 }
419
420 table = kzalloc(sizeof(*table) + nla_len(name), GFP_KERNEL);
421 if (table == NULL)
422 return -ENOMEM;
423
424 nla_strlcpy(table->name, name, nla_len(name));
425 INIT_LIST_HEAD(&table->chains);
Patrick McHardy20a69342013-10-11 12:06:22 +0200426 INIT_LIST_HEAD(&table->sets);
Patrick McHardy96518512013-10-14 11:00:02 +0200427
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200428 if (nla[NFTA_TABLE_FLAGS]) {
429 __be32 flags;
430
431 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
432 if (flags & ~NFT_TABLE_F_DORMANT) {
433 kfree(table);
434 return -EINVAL;
435 }
436
437 table->flags |= flags;
438 }
439
Patrick McHardy96518512013-10-14 11:00:02 +0200440 list_add_tail(&table->list, &afi->tables);
441 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
442 return 0;
443}
444
445static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
446 const struct nlmsghdr *nlh,
447 const struct nlattr * const nla[])
448{
449 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
450 struct nft_af_info *afi;
451 struct nft_table *table;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200452 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200453 int family = nfmsg->nfgen_family;
454
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200455 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200456 if (IS_ERR(afi))
457 return PTR_ERR(afi);
458
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200459 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
Patrick McHardy96518512013-10-14 11:00:02 +0200460 if (IS_ERR(table))
461 return PTR_ERR(table);
462
Patrick McHardy96518512013-10-14 11:00:02 +0200463 if (table->use)
464 return -EBUSY;
465
466 list_del(&table->list);
467 nf_tables_table_notify(skb, nlh, table, NFT_MSG_DELTABLE, family);
468 kfree(table);
469 return 0;
470}
471
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200472int nft_register_chain_type(struct nf_chain_type *ctype)
Patrick McHardy96518512013-10-14 11:00:02 +0200473{
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200474 int err = 0;
Patrick McHardy96518512013-10-14 11:00:02 +0200475
476 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200477 if (chain_type[ctype->family][ctype->type] != NULL) {
478 err = -EBUSY;
479 goto out;
Patrick McHardy96518512013-10-14 11:00:02 +0200480 }
481
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200482 if (!try_module_get(ctype->me))
483 goto out;
Patrick McHardy96518512013-10-14 11:00:02 +0200484
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200485 chain_type[ctype->family][ctype->type] = ctype;
486out:
Patrick McHardy96518512013-10-14 11:00:02 +0200487 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
488 return err;
489}
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200490EXPORT_SYMBOL_GPL(nft_register_chain_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200491
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200492void nft_unregister_chain_type(struct nf_chain_type *ctype)
Patrick McHardy96518512013-10-14 11:00:02 +0200493{
Patrick McHardy96518512013-10-14 11:00:02 +0200494 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200495 chain_type[ctype->family][ctype->type] = NULL;
496 module_put(ctype->me);
Patrick McHardy96518512013-10-14 11:00:02 +0200497 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
498}
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200499EXPORT_SYMBOL_GPL(nft_unregister_chain_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200500
501/*
502 * Chains
503 */
504
505static struct nft_chain *
506nf_tables_chain_lookup_byhandle(const struct nft_table *table, u64 handle)
507{
508 struct nft_chain *chain;
509
510 list_for_each_entry(chain, &table->chains, list) {
511 if (chain->handle == handle)
512 return chain;
513 }
514
515 return ERR_PTR(-ENOENT);
516}
517
518static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table,
519 const struct nlattr *nla)
520{
521 struct nft_chain *chain;
522
523 if (nla == NULL)
524 return ERR_PTR(-EINVAL);
525
526 list_for_each_entry(chain, &table->chains, list) {
527 if (!nla_strcmp(nla, chain->name))
528 return chain;
529 }
530
531 return ERR_PTR(-ENOENT);
532}
533
534static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
535 [NFTA_CHAIN_TABLE] = { .type = NLA_STRING },
536 [NFTA_CHAIN_HANDLE] = { .type = NLA_U64 },
537 [NFTA_CHAIN_NAME] = { .type = NLA_STRING,
538 .len = NFT_CHAIN_MAXNAMELEN - 1 },
539 [NFTA_CHAIN_HOOK] = { .type = NLA_NESTED },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200540 [NFTA_CHAIN_POLICY] = { .type = NLA_U32 },
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200541 [NFTA_CHAIN_TYPE] = { .type = NLA_NUL_STRING },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200542 [NFTA_CHAIN_COUNTERS] = { .type = NLA_NESTED },
Patrick McHardy96518512013-10-14 11:00:02 +0200543};
544
545static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = {
546 [NFTA_HOOK_HOOKNUM] = { .type = NLA_U32 },
547 [NFTA_HOOK_PRIORITY] = { .type = NLA_U32 },
548};
549
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200550static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats)
551{
552 struct nft_stats *cpu_stats, total;
553 struct nlattr *nest;
554 int cpu;
555
556 memset(&total, 0, sizeof(total));
557 for_each_possible_cpu(cpu) {
558 cpu_stats = per_cpu_ptr(stats, cpu);
559 total.pkts += cpu_stats->pkts;
560 total.bytes += cpu_stats->bytes;
561 }
562 nest = nla_nest_start(skb, NFTA_CHAIN_COUNTERS);
563 if (nest == NULL)
564 goto nla_put_failure;
565
566 if (nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(total.pkts)) ||
567 nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes)))
568 goto nla_put_failure;
569
570 nla_nest_end(skb, nest);
571 return 0;
572
573nla_put_failure:
574 return -ENOSPC;
575}
576
Patrick McHardy96518512013-10-14 11:00:02 +0200577static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq,
578 int event, u32 flags, int family,
579 const struct nft_table *table,
580 const struct nft_chain *chain)
581{
582 struct nlmsghdr *nlh;
583 struct nfgenmsg *nfmsg;
584
585 event |= NFNL_SUBSYS_NFTABLES << 8;
586 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
587 if (nlh == NULL)
588 goto nla_put_failure;
589
590 nfmsg = nlmsg_data(nlh);
591 nfmsg->nfgen_family = family;
592 nfmsg->version = NFNETLINK_V0;
593 nfmsg->res_id = 0;
594
595 if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name))
596 goto nla_put_failure;
597 if (nla_put_be64(skb, NFTA_CHAIN_HANDLE, cpu_to_be64(chain->handle)))
598 goto nla_put_failure;
599 if (nla_put_string(skb, NFTA_CHAIN_NAME, chain->name))
600 goto nla_put_failure;
601
602 if (chain->flags & NFT_BASE_CHAIN) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200603 const struct nft_base_chain *basechain = nft_base_chain(chain);
Patrick McHardy115a60b2014-01-03 12:16:15 +0000604 const struct nf_hook_ops *ops = &basechain->ops[0];
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200605 struct nlattr *nest;
606
607 nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
Patrick McHardy96518512013-10-14 11:00:02 +0200608 if (nest == NULL)
609 goto nla_put_failure;
610 if (nla_put_be32(skb, NFTA_HOOK_HOOKNUM, htonl(ops->hooknum)))
611 goto nla_put_failure;
612 if (nla_put_be32(skb, NFTA_HOOK_PRIORITY, htonl(ops->priority)))
613 goto nla_put_failure;
614 nla_nest_end(skb, nest);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200615
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200616 if (nla_put_be32(skb, NFTA_CHAIN_POLICY,
617 htonl(basechain->policy)))
618 goto nla_put_failure;
619
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200620 if (nla_put_string(skb, NFTA_CHAIN_TYPE,
621 chain_type[ops->pf][nft_base_chain(chain)->type]->name))
622 goto nla_put_failure;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200623
624 if (nft_dump_stats(skb, nft_base_chain(chain)->stats))
625 goto nla_put_failure;
Patrick McHardy96518512013-10-14 11:00:02 +0200626 }
627
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200628 if (nla_put_be32(skb, NFTA_CHAIN_USE, htonl(chain->use)))
629 goto nla_put_failure;
630
Patrick McHardy96518512013-10-14 11:00:02 +0200631 return nlmsg_end(skb, nlh);
632
633nla_put_failure:
634 nlmsg_trim(skb, nlh);
635 return -1;
636}
637
638static int nf_tables_chain_notify(const struct sk_buff *oskb,
639 const struct nlmsghdr *nlh,
640 const struct nft_table *table,
641 const struct nft_chain *chain,
642 int event, int family)
643{
644 struct sk_buff *skb;
645 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
646 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
647 u32 seq = nlh ? nlh->nlmsg_seq : 0;
648 bool report;
649 int err;
650
651 report = nlh ? nlmsg_report(nlh) : false;
652 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
653 return 0;
654
655 err = -ENOBUFS;
656 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
657 if (skb == NULL)
658 goto err;
659
660 err = nf_tables_fill_chain_info(skb, portid, seq, event, 0, family,
661 table, chain);
662 if (err < 0) {
663 kfree_skb(skb);
664 goto err;
665 }
666
667 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
668 GFP_KERNEL);
669err:
670 if (err < 0)
671 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
672 return err;
673}
674
675static int nf_tables_dump_chains(struct sk_buff *skb,
676 struct netlink_callback *cb)
677{
678 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
679 const struct nft_af_info *afi;
680 const struct nft_table *table;
681 const struct nft_chain *chain;
682 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200683 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200684 int family = nfmsg->nfgen_family;
685
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200686 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +0200687 if (family != NFPROTO_UNSPEC && family != afi->family)
688 continue;
689
690 list_for_each_entry(table, &afi->tables, list) {
691 list_for_each_entry(chain, &table->chains, list) {
692 if (idx < s_idx)
693 goto cont;
694 if (idx > s_idx)
695 memset(&cb->args[1], 0,
696 sizeof(cb->args) - sizeof(cb->args[0]));
697 if (nf_tables_fill_chain_info(skb, NETLINK_CB(cb->skb).portid,
698 cb->nlh->nlmsg_seq,
699 NFT_MSG_NEWCHAIN,
700 NLM_F_MULTI,
701 afi->family, table, chain) < 0)
702 goto done;
703cont:
704 idx++;
705 }
706 }
707 }
708done:
709 cb->args[0] = idx;
710 return skb->len;
711}
712
713
714static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb,
715 const struct nlmsghdr *nlh,
716 const struct nlattr * const nla[])
717{
718 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
719 const struct nft_af_info *afi;
720 const struct nft_table *table;
721 const struct nft_chain *chain;
722 struct sk_buff *skb2;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200723 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200724 int family = nfmsg->nfgen_family;
725 int err;
726
727 if (nlh->nlmsg_flags & NLM_F_DUMP) {
728 struct netlink_dump_control c = {
729 .dump = nf_tables_dump_chains,
730 };
731 return netlink_dump_start(nlsk, skb, nlh, &c);
732 }
733
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200734 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200735 if (IS_ERR(afi))
736 return PTR_ERR(afi);
737
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200738 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +0200739 if (IS_ERR(table))
740 return PTR_ERR(table);
741
742 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
743 if (IS_ERR(chain))
744 return PTR_ERR(chain);
745
746 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
747 if (!skb2)
748 return -ENOMEM;
749
750 err = nf_tables_fill_chain_info(skb2, NETLINK_CB(skb).portid,
751 nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0,
752 family, table, chain);
753 if (err < 0)
754 goto err;
755
756 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
757
758err:
759 kfree_skb(skb2);
760 return err;
761}
762
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200763static int
764nf_tables_chain_policy(struct nft_base_chain *chain, const struct nlattr *attr)
765{
766 switch (ntohl(nla_get_be32(attr))) {
767 case NF_DROP:
768 chain->policy = NF_DROP;
769 break;
770 case NF_ACCEPT:
771 chain->policy = NF_ACCEPT;
772 break;
773 default:
774 return -EINVAL;
775 }
776 return 0;
777}
778
779static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = {
780 [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 },
781 [NFTA_COUNTER_BYTES] = { .type = NLA_U64 },
782};
783
784static int
785nf_tables_counters(struct nft_base_chain *chain, const struct nlattr *attr)
786{
787 struct nlattr *tb[NFTA_COUNTER_MAX+1];
788 struct nft_stats __percpu *newstats;
789 struct nft_stats *stats;
790 int err;
791
792 err = nla_parse_nested(tb, NFTA_COUNTER_MAX, attr, nft_counter_policy);
793 if (err < 0)
794 return err;
795
796 if (!tb[NFTA_COUNTER_BYTES] || !tb[NFTA_COUNTER_PACKETS])
797 return -EINVAL;
798
799 newstats = alloc_percpu(struct nft_stats);
800 if (newstats == NULL)
801 return -ENOMEM;
802
803 /* Restore old counters on this cpu, no problem. Per-cpu statistics
804 * are not exposed to userspace.
805 */
806 stats = this_cpu_ptr(newstats);
807 stats->bytes = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES]));
808 stats->pkts = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS]));
809
810 if (chain->stats) {
811 /* nfnl_lock is held, add some nfnl function for this, later */
812 struct nft_stats __percpu *oldstats =
813 rcu_dereference_protected(chain->stats, 1);
814
815 rcu_assign_pointer(chain->stats, newstats);
816 synchronize_rcu();
817 free_percpu(oldstats);
818 } else
819 rcu_assign_pointer(chain->stats, newstats);
820
821 return 0;
822}
823
Patrick McHardy96518512013-10-14 11:00:02 +0200824static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
825 const struct nlmsghdr *nlh,
826 const struct nlattr * const nla[])
827{
828 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
829 const struct nlattr * uninitialized_var(name);
830 const struct nft_af_info *afi;
831 struct nft_table *table;
832 struct nft_chain *chain;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200833 struct nft_base_chain *basechain = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +0200834 struct nlattr *ha[NFTA_HOOK_MAX + 1];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200835 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200836 int family = nfmsg->nfgen_family;
837 u64 handle = 0;
Patrick McHardy115a60b2014-01-03 12:16:15 +0000838 unsigned int i;
Patrick McHardy96518512013-10-14 11:00:02 +0200839 int err;
840 bool create;
841
842 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
843
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200844 afi = nf_tables_afinfo_lookup(net, family, true);
Patrick McHardy96518512013-10-14 11:00:02 +0200845 if (IS_ERR(afi))
846 return PTR_ERR(afi);
847
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200848 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +0200849 if (IS_ERR(table))
850 return PTR_ERR(table);
851
852 if (table->use == UINT_MAX)
853 return -EOVERFLOW;
854
855 chain = NULL;
856 name = nla[NFTA_CHAIN_NAME];
857
858 if (nla[NFTA_CHAIN_HANDLE]) {
859 handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
860 chain = nf_tables_chain_lookup_byhandle(table, handle);
861 if (IS_ERR(chain))
862 return PTR_ERR(chain);
863 } else {
864 chain = nf_tables_chain_lookup(table, name);
865 if (IS_ERR(chain)) {
866 if (PTR_ERR(chain) != -ENOENT)
867 return PTR_ERR(chain);
868 chain = NULL;
869 }
870 }
871
872 if (chain != NULL) {
873 if (nlh->nlmsg_flags & NLM_F_EXCL)
874 return -EEXIST;
875 if (nlh->nlmsg_flags & NLM_F_REPLACE)
876 return -EOPNOTSUPP;
877
878 if (nla[NFTA_CHAIN_HANDLE] && name &&
879 !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME])))
880 return -EEXIST;
881
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200882 if (nla[NFTA_CHAIN_POLICY]) {
883 if (!(chain->flags & NFT_BASE_CHAIN))
884 return -EOPNOTSUPP;
885
886 err = nf_tables_chain_policy(nft_base_chain(chain),
887 nla[NFTA_CHAIN_POLICY]);
888 if (err < 0)
889 return err;
890 }
891
892 if (nla[NFTA_CHAIN_COUNTERS]) {
893 if (!(chain->flags & NFT_BASE_CHAIN))
894 return -EOPNOTSUPP;
895
896 err = nf_tables_counters(nft_base_chain(chain),
897 nla[NFTA_CHAIN_COUNTERS]);
898 if (err < 0)
899 return err;
900 }
901
Patrick McHardy96518512013-10-14 11:00:02 +0200902 if (nla[NFTA_CHAIN_HANDLE] && name)
903 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
904
905 goto notify;
906 }
907
908 if (nla[NFTA_CHAIN_HOOK]) {
909 struct nf_hook_ops *ops;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200910 nf_hookfn *hookfn;
Patrick McHardy115a60b2014-01-03 12:16:15 +0000911 u32 hooknum, priority;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200912 int type = NFT_CHAIN_T_DEFAULT;
913
914 if (nla[NFTA_CHAIN_TYPE]) {
915 type = nf_tables_chain_type_lookup(afi,
916 nla[NFTA_CHAIN_TYPE],
917 create);
918 if (type < 0)
919 return -ENOENT;
920 }
Patrick McHardy96518512013-10-14 11:00:02 +0200921
922 err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK],
923 nft_hook_policy);
924 if (err < 0)
925 return err;
926 if (ha[NFTA_HOOK_HOOKNUM] == NULL ||
927 ha[NFTA_HOOK_PRIORITY] == NULL)
928 return -EINVAL;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200929
930 hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
931 if (hooknum >= afi->nhooks)
Patrick McHardy96518512013-10-14 11:00:02 +0200932 return -EINVAL;
Patrick McHardy115a60b2014-01-03 12:16:15 +0000933 priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
Patrick McHardy96518512013-10-14 11:00:02 +0200934
Patrick McHardy3b088c42014-01-03 12:16:13 +0000935 if (!(chain_type[family][type]->hook_mask & (1 << hooknum)))
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200936 return -EOPNOTSUPP;
Patrick McHardy3b088c42014-01-03 12:16:13 +0000937 hookfn = chain_type[family][type]->fn[hooknum];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200938
Patrick McHardy96518512013-10-14 11:00:02 +0200939 basechain = kzalloc(sizeof(*basechain), GFP_KERNEL);
940 if (basechain == NULL)
941 return -ENOMEM;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200942
943 basechain->type = type;
Patrick McHardy96518512013-10-14 11:00:02 +0200944 chain = &basechain->chain;
945
Patrick McHardy115a60b2014-01-03 12:16:15 +0000946 for (i = 0; i < afi->nops; i++) {
947 ops = &basechain->ops[i];
948 ops->pf = family;
949 ops->owner = afi->owner;
950 ops->hooknum = hooknum;
951 ops->priority = priority;
952 ops->priv = chain;
953 ops->hook = afi->hooks[ops->hooknum];
954 if (hookfn)
955 ops->hook = hookfn;
956 if (afi->hook_ops_init)
957 afi->hook_ops_init(ops, i);
958 }
Patrick McHardy96518512013-10-14 11:00:02 +0200959
960 chain->flags |= NFT_BASE_CHAIN;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200961
962 if (nla[NFTA_CHAIN_POLICY]) {
963 err = nf_tables_chain_policy(basechain,
964 nla[NFTA_CHAIN_POLICY]);
965 if (err < 0) {
966 free_percpu(basechain->stats);
967 kfree(basechain);
968 return err;
969 }
970 } else
971 basechain->policy = NF_ACCEPT;
972
973 if (nla[NFTA_CHAIN_COUNTERS]) {
974 err = nf_tables_counters(basechain,
975 nla[NFTA_CHAIN_COUNTERS]);
976 if (err < 0) {
977 free_percpu(basechain->stats);
978 kfree(basechain);
979 return err;
980 }
981 } else {
982 struct nft_stats __percpu *newstats;
983
984 newstats = alloc_percpu(struct nft_stats);
985 if (newstats == NULL)
986 return -ENOMEM;
987
988 rcu_assign_pointer(nft_base_chain(chain)->stats,
989 newstats);
990 }
Patrick McHardy96518512013-10-14 11:00:02 +0200991 } else {
992 chain = kzalloc(sizeof(*chain), GFP_KERNEL);
993 if (chain == NULL)
994 return -ENOMEM;
995 }
996
997 INIT_LIST_HEAD(&chain->rules);
998 chain->handle = nf_tables_alloc_handle(table);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +0200999 chain->net = net;
Pablo Neira Ayusob5bc89b2013-10-10 16:49:19 +02001000 chain->table = table;
Patrick McHardy96518512013-10-14 11:00:02 +02001001 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
1002
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +02001003 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
1004 chain->flags & NFT_BASE_CHAIN) {
Patrick McHardy115a60b2014-01-03 12:16:15 +00001005 err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001006 if (err < 0) {
1007 free_percpu(basechain->stats);
1008 kfree(basechain);
1009 return err;
1010 }
1011 }
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +02001012 list_add_tail(&chain->list, &table->chains);
1013 table->use++;
Patrick McHardy96518512013-10-14 11:00:02 +02001014notify:
1015 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_NEWCHAIN,
1016 family);
1017 return 0;
1018}
1019
1020static void nf_tables_rcu_chain_destroy(struct rcu_head *head)
1021{
1022 struct nft_chain *chain = container_of(head, struct nft_chain, rcu_head);
1023
1024 BUG_ON(chain->use > 0);
1025
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001026 if (chain->flags & NFT_BASE_CHAIN) {
1027 free_percpu(nft_base_chain(chain)->stats);
Patrick McHardy96518512013-10-14 11:00:02 +02001028 kfree(nft_base_chain(chain));
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001029 } else
Patrick McHardy96518512013-10-14 11:00:02 +02001030 kfree(chain);
1031}
1032
1033static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
1034 const struct nlmsghdr *nlh,
1035 const struct nlattr * const nla[])
1036{
1037 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1038 const struct nft_af_info *afi;
1039 struct nft_table *table;
1040 struct nft_chain *chain;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001041 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001042 int family = nfmsg->nfgen_family;
1043
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001044 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001045 if (IS_ERR(afi))
1046 return PTR_ERR(afi);
1047
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001048 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001049 if (IS_ERR(table))
1050 return PTR_ERR(table);
1051
1052 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
1053 if (IS_ERR(chain))
1054 return PTR_ERR(chain);
1055
Patrick McHardy96518512013-10-14 11:00:02 +02001056 if (!list_empty(&chain->rules))
1057 return -EBUSY;
1058
1059 list_del(&chain->list);
1060 table->use--;
1061
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +02001062 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
1063 chain->flags & NFT_BASE_CHAIN)
Patrick McHardy115a60b2014-01-03 12:16:15 +00001064 nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops);
Patrick McHardy96518512013-10-14 11:00:02 +02001065
1066 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN,
1067 family);
1068
1069 /* Make sure all rule references are gone before this is released */
1070 call_rcu(&chain->rcu_head, nf_tables_rcu_chain_destroy);
1071 return 0;
1072}
1073
1074static void nft_ctx_init(struct nft_ctx *ctx,
Patrick McHardy20a69342013-10-11 12:06:22 +02001075 const struct sk_buff *skb,
1076 const struct nlmsghdr *nlh,
Patrick McHardy96518512013-10-14 11:00:02 +02001077 const struct nft_af_info *afi,
1078 const struct nft_table *table,
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001079 const struct nft_chain *chain,
1080 const struct nlattr * const *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001081{
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001082 ctx->net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02001083 ctx->skb = skb;
1084 ctx->nlh = nlh;
Patrick McHardy96518512013-10-14 11:00:02 +02001085 ctx->afi = afi;
1086 ctx->table = table;
1087 ctx->chain = chain;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001088 ctx->nla = nla;
Patrick McHardy96518512013-10-14 11:00:02 +02001089}
1090
1091/*
1092 * Expressions
1093 */
1094
1095/**
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001096 * nft_register_expr - register nf_tables expr type
1097 * @ops: expr type
Patrick McHardy96518512013-10-14 11:00:02 +02001098 *
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001099 * Registers the expr type for use with nf_tables. Returns zero on
Patrick McHardy96518512013-10-14 11:00:02 +02001100 * success or a negative errno code otherwise.
1101 */
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001102int nft_register_expr(struct nft_expr_type *type)
Patrick McHardy96518512013-10-14 11:00:02 +02001103{
1104 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001105 list_add_tail(&type->list, &nf_tables_expressions);
Patrick McHardy96518512013-10-14 11:00:02 +02001106 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1107 return 0;
1108}
1109EXPORT_SYMBOL_GPL(nft_register_expr);
1110
1111/**
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001112 * nft_unregister_expr - unregister nf_tables expr type
1113 * @ops: expr type
Patrick McHardy96518512013-10-14 11:00:02 +02001114 *
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001115 * Unregisters the expr typefor use with nf_tables.
Patrick McHardy96518512013-10-14 11:00:02 +02001116 */
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001117void nft_unregister_expr(struct nft_expr_type *type)
Patrick McHardy96518512013-10-14 11:00:02 +02001118{
1119 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001120 list_del(&type->list);
Patrick McHardy96518512013-10-14 11:00:02 +02001121 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1122}
1123EXPORT_SYMBOL_GPL(nft_unregister_expr);
1124
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001125static const struct nft_expr_type *__nft_expr_type_get(struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001126{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001127 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001128
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001129 list_for_each_entry(type, &nf_tables_expressions, list) {
1130 if (!nla_strcmp(nla, type->name))
1131 return type;
Patrick McHardy96518512013-10-14 11:00:02 +02001132 }
1133 return NULL;
1134}
1135
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001136static const struct nft_expr_type *nft_expr_type_get(struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001137{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001138 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001139
1140 if (nla == NULL)
1141 return ERR_PTR(-EINVAL);
1142
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001143 type = __nft_expr_type_get(nla);
1144 if (type != NULL && try_module_get(type->owner))
1145 return type;
Patrick McHardy96518512013-10-14 11:00:02 +02001146
1147#ifdef CONFIG_MODULES
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001148 if (type == NULL) {
Patrick McHardy96518512013-10-14 11:00:02 +02001149 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1150 request_module("nft-expr-%.*s",
1151 nla_len(nla), (char *)nla_data(nla));
1152 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001153 if (__nft_expr_type_get(nla))
Patrick McHardy96518512013-10-14 11:00:02 +02001154 return ERR_PTR(-EAGAIN);
1155 }
1156#endif
1157 return ERR_PTR(-ENOENT);
1158}
1159
1160static const struct nla_policy nft_expr_policy[NFTA_EXPR_MAX + 1] = {
1161 [NFTA_EXPR_NAME] = { .type = NLA_STRING },
1162 [NFTA_EXPR_DATA] = { .type = NLA_NESTED },
1163};
1164
1165static int nf_tables_fill_expr_info(struct sk_buff *skb,
1166 const struct nft_expr *expr)
1167{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001168 if (nla_put_string(skb, NFTA_EXPR_NAME, expr->ops->type->name))
Patrick McHardy96518512013-10-14 11:00:02 +02001169 goto nla_put_failure;
1170
1171 if (expr->ops->dump) {
1172 struct nlattr *data = nla_nest_start(skb, NFTA_EXPR_DATA);
1173 if (data == NULL)
1174 goto nla_put_failure;
1175 if (expr->ops->dump(skb, expr) < 0)
1176 goto nla_put_failure;
1177 nla_nest_end(skb, data);
1178 }
1179
1180 return skb->len;
1181
1182nla_put_failure:
1183 return -1;
1184};
1185
1186struct nft_expr_info {
1187 const struct nft_expr_ops *ops;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001188 struct nlattr *tb[NFT_EXPR_MAXATTR + 1];
Patrick McHardy96518512013-10-14 11:00:02 +02001189};
1190
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001191static int nf_tables_expr_parse(const struct nft_ctx *ctx,
1192 const struct nlattr *nla,
Patrick McHardy96518512013-10-14 11:00:02 +02001193 struct nft_expr_info *info)
1194{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001195 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001196 const struct nft_expr_ops *ops;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001197 struct nlattr *tb[NFTA_EXPR_MAX + 1];
Patrick McHardy96518512013-10-14 11:00:02 +02001198 int err;
1199
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001200 err = nla_parse_nested(tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
Patrick McHardy96518512013-10-14 11:00:02 +02001201 if (err < 0)
1202 return err;
1203
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001204 type = nft_expr_type_get(tb[NFTA_EXPR_NAME]);
1205 if (IS_ERR(type))
1206 return PTR_ERR(type);
1207
1208 if (tb[NFTA_EXPR_DATA]) {
1209 err = nla_parse_nested(info->tb, type->maxattr,
1210 tb[NFTA_EXPR_DATA], type->policy);
1211 if (err < 0)
1212 goto err1;
1213 } else
1214 memset(info->tb, 0, sizeof(info->tb[0]) * (type->maxattr + 1));
1215
1216 if (type->select_ops != NULL) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001217 ops = type->select_ops(ctx,
1218 (const struct nlattr * const *)info->tb);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001219 if (IS_ERR(ops)) {
1220 err = PTR_ERR(ops);
1221 goto err1;
1222 }
1223 } else
1224 ops = type->ops;
1225
Patrick McHardy96518512013-10-14 11:00:02 +02001226 info->ops = ops;
1227 return 0;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001228
1229err1:
1230 module_put(type->owner);
1231 return err;
Patrick McHardy96518512013-10-14 11:00:02 +02001232}
1233
1234static int nf_tables_newexpr(const struct nft_ctx *ctx,
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001235 const struct nft_expr_info *info,
Patrick McHardy96518512013-10-14 11:00:02 +02001236 struct nft_expr *expr)
1237{
1238 const struct nft_expr_ops *ops = info->ops;
1239 int err;
1240
1241 expr->ops = ops;
1242 if (ops->init) {
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001243 err = ops->init(ctx, expr, (const struct nlattr **)info->tb);
Patrick McHardy96518512013-10-14 11:00:02 +02001244 if (err < 0)
1245 goto err1;
1246 }
1247
Patrick McHardy96518512013-10-14 11:00:02 +02001248 return 0;
1249
1250err1:
1251 expr->ops = NULL;
1252 return err;
1253}
1254
1255static void nf_tables_expr_destroy(struct nft_expr *expr)
1256{
1257 if (expr->ops->destroy)
1258 expr->ops->destroy(expr);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001259 module_put(expr->ops->type->owner);
Patrick McHardy96518512013-10-14 11:00:02 +02001260}
1261
1262/*
1263 * Rules
1264 */
1265
1266static struct nft_rule *__nf_tables_rule_lookup(const struct nft_chain *chain,
1267 u64 handle)
1268{
1269 struct nft_rule *rule;
1270
1271 // FIXME: this sucks
1272 list_for_each_entry(rule, &chain->rules, list) {
1273 if (handle == rule->handle)
1274 return rule;
1275 }
1276
1277 return ERR_PTR(-ENOENT);
1278}
1279
1280static struct nft_rule *nf_tables_rule_lookup(const struct nft_chain *chain,
1281 const struct nlattr *nla)
1282{
1283 if (nla == NULL)
1284 return ERR_PTR(-EINVAL);
1285
1286 return __nf_tables_rule_lookup(chain, be64_to_cpu(nla_get_be64(nla)));
1287}
1288
1289static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
1290 [NFTA_RULE_TABLE] = { .type = NLA_STRING },
1291 [NFTA_RULE_CHAIN] = { .type = NLA_STRING,
1292 .len = NFT_CHAIN_MAXNAMELEN - 1 },
1293 [NFTA_RULE_HANDLE] = { .type = NLA_U64 },
1294 [NFTA_RULE_EXPRESSIONS] = { .type = NLA_NESTED },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001295 [NFTA_RULE_COMPAT] = { .type = NLA_NESTED },
Eric Leblond5e948462013-10-10 13:41:44 +02001296 [NFTA_RULE_POSITION] = { .type = NLA_U64 },
Patrick McHardy96518512013-10-14 11:00:02 +02001297};
1298
1299static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
1300 int event, u32 flags, int family,
1301 const struct nft_table *table,
1302 const struct nft_chain *chain,
1303 const struct nft_rule *rule)
1304{
1305 struct nlmsghdr *nlh;
1306 struct nfgenmsg *nfmsg;
1307 const struct nft_expr *expr, *next;
1308 struct nlattr *list;
Eric Leblond5e948462013-10-10 13:41:44 +02001309 const struct nft_rule *prule;
1310 int type = event | NFNL_SUBSYS_NFTABLES << 8;
Patrick McHardy96518512013-10-14 11:00:02 +02001311
Eric Leblond5e948462013-10-10 13:41:44 +02001312 nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg),
Patrick McHardy96518512013-10-14 11:00:02 +02001313 flags);
1314 if (nlh == NULL)
1315 goto nla_put_failure;
1316
1317 nfmsg = nlmsg_data(nlh);
1318 nfmsg->nfgen_family = family;
1319 nfmsg->version = NFNETLINK_V0;
1320 nfmsg->res_id = 0;
1321
1322 if (nla_put_string(skb, NFTA_RULE_TABLE, table->name))
1323 goto nla_put_failure;
1324 if (nla_put_string(skb, NFTA_RULE_CHAIN, chain->name))
1325 goto nla_put_failure;
1326 if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
1327 goto nla_put_failure;
1328
Eric Leblond5e948462013-10-10 13:41:44 +02001329 if ((event != NFT_MSG_DELRULE) && (rule->list.prev != &chain->rules)) {
1330 prule = list_entry(rule->list.prev, struct nft_rule, list);
1331 if (nla_put_be64(skb, NFTA_RULE_POSITION,
1332 cpu_to_be64(prule->handle)))
1333 goto nla_put_failure;
1334 }
1335
Patrick McHardy96518512013-10-14 11:00:02 +02001336 list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
1337 if (list == NULL)
1338 goto nla_put_failure;
1339 nft_rule_for_each_expr(expr, next, rule) {
1340 struct nlattr *elem = nla_nest_start(skb, NFTA_LIST_ELEM);
1341 if (elem == NULL)
1342 goto nla_put_failure;
1343 if (nf_tables_fill_expr_info(skb, expr) < 0)
1344 goto nla_put_failure;
1345 nla_nest_end(skb, elem);
1346 }
1347 nla_nest_end(skb, list);
1348
1349 return nlmsg_end(skb, nlh);
1350
1351nla_put_failure:
1352 nlmsg_trim(skb, nlh);
1353 return -1;
1354}
1355
1356static int nf_tables_rule_notify(const struct sk_buff *oskb,
1357 const struct nlmsghdr *nlh,
1358 const struct nft_table *table,
1359 const struct nft_chain *chain,
1360 const struct nft_rule *rule,
1361 int event, u32 flags, int family)
1362{
1363 struct sk_buff *skb;
1364 u32 portid = NETLINK_CB(oskb).portid;
1365 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
1366 u32 seq = nlh->nlmsg_seq;
1367 bool report;
1368 int err;
1369
1370 report = nlmsg_report(nlh);
1371 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
1372 return 0;
1373
1374 err = -ENOBUFS;
1375 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1376 if (skb == NULL)
1377 goto err;
1378
1379 err = nf_tables_fill_rule_info(skb, portid, seq, event, flags,
1380 family, table, chain, rule);
1381 if (err < 0) {
1382 kfree_skb(skb);
1383 goto err;
1384 }
1385
1386 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
1387 GFP_KERNEL);
1388err:
1389 if (err < 0)
1390 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
1391 return err;
1392}
1393
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001394static inline bool
1395nft_rule_is_active(struct net *net, const struct nft_rule *rule)
1396{
1397 return (rule->genmask & (1 << net->nft.gencursor)) == 0;
1398}
1399
1400static inline int gencursor_next(struct net *net)
1401{
1402 return net->nft.gencursor+1 == 1 ? 1 : 0;
1403}
1404
1405static inline int
1406nft_rule_is_active_next(struct net *net, const struct nft_rule *rule)
1407{
1408 return (rule->genmask & (1 << gencursor_next(net))) == 0;
1409}
1410
1411static inline void
1412nft_rule_activate_next(struct net *net, struct nft_rule *rule)
1413{
1414 /* Now inactive, will be active in the future */
1415 rule->genmask = (1 << net->nft.gencursor);
1416}
1417
1418static inline void
1419nft_rule_disactivate_next(struct net *net, struct nft_rule *rule)
1420{
1421 rule->genmask = (1 << gencursor_next(net));
1422}
1423
1424static inline void nft_rule_clear(struct net *net, struct nft_rule *rule)
1425{
1426 rule->genmask = 0;
1427}
1428
Patrick McHardy96518512013-10-14 11:00:02 +02001429static int nf_tables_dump_rules(struct sk_buff *skb,
1430 struct netlink_callback *cb)
1431{
1432 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
1433 const struct nft_af_info *afi;
1434 const struct nft_table *table;
1435 const struct nft_chain *chain;
1436 const struct nft_rule *rule;
1437 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001438 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001439 int family = nfmsg->nfgen_family;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001440 u8 genctr = ACCESS_ONCE(net->nft.genctr);
1441 u8 gencursor = ACCESS_ONCE(net->nft.gencursor);
Patrick McHardy96518512013-10-14 11:00:02 +02001442
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001443 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +02001444 if (family != NFPROTO_UNSPEC && family != afi->family)
1445 continue;
1446
1447 list_for_each_entry(table, &afi->tables, list) {
1448 list_for_each_entry(chain, &table->chains, list) {
1449 list_for_each_entry(rule, &chain->rules, list) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001450 if (!nft_rule_is_active(net, rule))
1451 goto cont;
Patrick McHardy96518512013-10-14 11:00:02 +02001452 if (idx < s_idx)
1453 goto cont;
1454 if (idx > s_idx)
1455 memset(&cb->args[1], 0,
1456 sizeof(cb->args) - sizeof(cb->args[0]));
1457 if (nf_tables_fill_rule_info(skb, NETLINK_CB(cb->skb).portid,
1458 cb->nlh->nlmsg_seq,
1459 NFT_MSG_NEWRULE,
1460 NLM_F_MULTI | NLM_F_APPEND,
1461 afi->family, table, chain, rule) < 0)
1462 goto done;
1463cont:
1464 idx++;
1465 }
1466 }
1467 }
1468 }
1469done:
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001470 /* Invalidate this dump, a transition to the new generation happened */
1471 if (gencursor != net->nft.gencursor || genctr != net->nft.genctr)
1472 return -EBUSY;
1473
Patrick McHardy96518512013-10-14 11:00:02 +02001474 cb->args[0] = idx;
1475 return skb->len;
1476}
1477
1478static int nf_tables_getrule(struct sock *nlsk, struct sk_buff *skb,
1479 const struct nlmsghdr *nlh,
1480 const struct nlattr * const nla[])
1481{
1482 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1483 const struct nft_af_info *afi;
1484 const struct nft_table *table;
1485 const struct nft_chain *chain;
1486 const struct nft_rule *rule;
1487 struct sk_buff *skb2;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001488 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001489 int family = nfmsg->nfgen_family;
1490 int err;
1491
1492 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1493 struct netlink_dump_control c = {
1494 .dump = nf_tables_dump_rules,
1495 };
1496 return netlink_dump_start(nlsk, skb, nlh, &c);
1497 }
1498
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001499 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001500 if (IS_ERR(afi))
1501 return PTR_ERR(afi);
1502
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001503 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001504 if (IS_ERR(table))
1505 return PTR_ERR(table);
1506
1507 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1508 if (IS_ERR(chain))
1509 return PTR_ERR(chain);
1510
1511 rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
1512 if (IS_ERR(rule))
1513 return PTR_ERR(rule);
1514
1515 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1516 if (!skb2)
1517 return -ENOMEM;
1518
1519 err = nf_tables_fill_rule_info(skb2, NETLINK_CB(skb).portid,
1520 nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
1521 family, table, chain, rule);
1522 if (err < 0)
1523 goto err;
1524
1525 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
1526
1527err:
1528 kfree_skb(skb2);
1529 return err;
1530}
1531
1532static void nf_tables_rcu_rule_destroy(struct rcu_head *head)
1533{
1534 struct nft_rule *rule = container_of(head, struct nft_rule, rcu_head);
1535 struct nft_expr *expr;
1536
1537 /*
1538 * Careful: some expressions might not be initialized in case this
1539 * is called on error from nf_tables_newrule().
1540 */
1541 expr = nft_expr_first(rule);
1542 while (expr->ops && expr != nft_expr_last(rule)) {
1543 nf_tables_expr_destroy(expr);
1544 expr = nft_expr_next(expr);
1545 }
1546 kfree(rule);
1547}
1548
1549static void nf_tables_rule_destroy(struct nft_rule *rule)
1550{
1551 call_rcu(&rule->rcu_head, nf_tables_rcu_rule_destroy);
1552}
1553
1554#define NFT_RULE_MAXEXPRS 128
1555
1556static struct nft_expr_info *info;
1557
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001558static struct nft_rule_trans *
1559nf_tables_trans_add(struct nft_rule *rule, const struct nft_ctx *ctx)
1560{
1561 struct nft_rule_trans *rupd;
1562
1563 rupd = kmalloc(sizeof(struct nft_rule_trans), GFP_KERNEL);
1564 if (rupd == NULL)
1565 return NULL;
1566
1567 rupd->chain = ctx->chain;
1568 rupd->table = ctx->table;
1569 rupd->rule = rule;
1570 rupd->family = ctx->afi->family;
1571 rupd->nlh = ctx->nlh;
1572 list_add_tail(&rupd->list, &ctx->net->nft.commit_list);
1573
1574 return rupd;
1575}
1576
Patrick McHardy96518512013-10-14 11:00:02 +02001577static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
1578 const struct nlmsghdr *nlh,
1579 const struct nlattr * const nla[])
1580{
1581 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1582 const struct nft_af_info *afi;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001583 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001584 struct nft_table *table;
1585 struct nft_chain *chain;
1586 struct nft_rule *rule, *old_rule = NULL;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001587 struct nft_rule_trans *repl = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +02001588 struct nft_expr *expr;
1589 struct nft_ctx ctx;
1590 struct nlattr *tmp;
1591 unsigned int size, i, n;
1592 int err, rem;
1593 bool create;
Eric Leblond5e948462013-10-10 13:41:44 +02001594 u64 handle, pos_handle;
Patrick McHardy96518512013-10-14 11:00:02 +02001595
1596 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
1597
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001598 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
Patrick McHardy96518512013-10-14 11:00:02 +02001599 if (IS_ERR(afi))
1600 return PTR_ERR(afi);
1601
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001602 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001603 if (IS_ERR(table))
1604 return PTR_ERR(table);
1605
1606 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1607 if (IS_ERR(chain))
1608 return PTR_ERR(chain);
1609
1610 if (nla[NFTA_RULE_HANDLE]) {
1611 handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
1612 rule = __nf_tables_rule_lookup(chain, handle);
1613 if (IS_ERR(rule))
1614 return PTR_ERR(rule);
1615
1616 if (nlh->nlmsg_flags & NLM_F_EXCL)
1617 return -EEXIST;
1618 if (nlh->nlmsg_flags & NLM_F_REPLACE)
1619 old_rule = rule;
1620 else
1621 return -EOPNOTSUPP;
1622 } else {
1623 if (!create || nlh->nlmsg_flags & NLM_F_REPLACE)
1624 return -EINVAL;
1625 handle = nf_tables_alloc_handle(table);
1626 }
1627
Eric Leblond5e948462013-10-10 13:41:44 +02001628 if (nla[NFTA_RULE_POSITION]) {
1629 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
1630 return -EOPNOTSUPP;
1631
1632 pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
1633 old_rule = __nf_tables_rule_lookup(chain, pos_handle);
1634 if (IS_ERR(old_rule))
1635 return PTR_ERR(old_rule);
1636 }
1637
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001638 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1639
Patrick McHardy96518512013-10-14 11:00:02 +02001640 n = 0;
1641 size = 0;
1642 if (nla[NFTA_RULE_EXPRESSIONS]) {
1643 nla_for_each_nested(tmp, nla[NFTA_RULE_EXPRESSIONS], rem) {
1644 err = -EINVAL;
1645 if (nla_type(tmp) != NFTA_LIST_ELEM)
1646 goto err1;
1647 if (n == NFT_RULE_MAXEXPRS)
1648 goto err1;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001649 err = nf_tables_expr_parse(&ctx, tmp, &info[n]);
Patrick McHardy96518512013-10-14 11:00:02 +02001650 if (err < 0)
1651 goto err1;
1652 size += info[n].ops->size;
1653 n++;
1654 }
1655 }
1656
1657 err = -ENOMEM;
1658 rule = kzalloc(sizeof(*rule) + size, GFP_KERNEL);
1659 if (rule == NULL)
1660 goto err1;
1661
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001662 nft_rule_activate_next(net, rule);
1663
Patrick McHardy96518512013-10-14 11:00:02 +02001664 rule->handle = handle;
1665 rule->dlen = size;
1666
Patrick McHardy96518512013-10-14 11:00:02 +02001667 expr = nft_expr_first(rule);
1668 for (i = 0; i < n; i++) {
1669 err = nf_tables_newexpr(&ctx, &info[i], expr);
1670 if (err < 0)
1671 goto err2;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001672 info[i].ops = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +02001673 expr = nft_expr_next(expr);
1674 }
1675
Patrick McHardy96518512013-10-14 11:00:02 +02001676 if (nlh->nlmsg_flags & NLM_F_REPLACE) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001677 if (nft_rule_is_active_next(net, old_rule)) {
1678 repl = nf_tables_trans_add(old_rule, &ctx);
1679 if (repl == NULL) {
1680 err = -ENOMEM;
1681 goto err2;
1682 }
1683 nft_rule_disactivate_next(net, old_rule);
1684 list_add_tail(&rule->list, &old_rule->list);
1685 } else {
1686 err = -ENOENT;
1687 goto err2;
1688 }
Patrick McHardy96518512013-10-14 11:00:02 +02001689 } else if (nlh->nlmsg_flags & NLM_F_APPEND)
Eric Leblond5e948462013-10-10 13:41:44 +02001690 if (old_rule)
1691 list_add_rcu(&rule->list, &old_rule->list);
1692 else
1693 list_add_tail_rcu(&rule->list, &chain->rules);
1694 else {
1695 if (old_rule)
1696 list_add_tail_rcu(&rule->list, &old_rule->list);
1697 else
1698 list_add_rcu(&rule->list, &chain->rules);
1699 }
Patrick McHardy96518512013-10-14 11:00:02 +02001700
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001701 if (nf_tables_trans_add(rule, &ctx) == NULL) {
1702 err = -ENOMEM;
1703 goto err3;
1704 }
Patrick McHardy96518512013-10-14 11:00:02 +02001705 return 0;
1706
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001707err3:
1708 list_del_rcu(&rule->list);
1709 if (repl) {
1710 list_del_rcu(&repl->rule->list);
1711 list_del(&repl->list);
1712 nft_rule_clear(net, repl->rule);
1713 kfree(repl);
1714 }
Patrick McHardy96518512013-10-14 11:00:02 +02001715err2:
1716 nf_tables_rule_destroy(rule);
1717err1:
1718 for (i = 0; i < n; i++) {
1719 if (info[i].ops != NULL)
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001720 module_put(info[i].ops->type->owner);
Patrick McHardy96518512013-10-14 11:00:02 +02001721 }
1722 return err;
1723}
1724
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001725static int
1726nf_tables_delrule_one(struct nft_ctx *ctx, struct nft_rule *rule)
1727{
1728 /* You cannot delete the same rule twice */
1729 if (nft_rule_is_active_next(ctx->net, rule)) {
1730 if (nf_tables_trans_add(rule, ctx) == NULL)
1731 return -ENOMEM;
1732 nft_rule_disactivate_next(ctx->net, rule);
1733 return 0;
1734 }
1735 return -ENOENT;
1736}
1737
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001738static int nf_table_delrule_by_chain(struct nft_ctx *ctx)
1739{
1740 struct nft_rule *rule;
1741 int err;
1742
1743 list_for_each_entry(rule, &ctx->chain->rules, list) {
1744 err = nf_tables_delrule_one(ctx, rule);
1745 if (err < 0)
1746 return err;
1747 }
1748 return 0;
1749}
1750
Patrick McHardy96518512013-10-14 11:00:02 +02001751static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
1752 const struct nlmsghdr *nlh,
1753 const struct nlattr * const nla[])
1754{
1755 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1756 const struct nft_af_info *afi;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001757 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001758 const struct nft_table *table;
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001759 struct nft_chain *chain = NULL;
1760 struct nft_rule *rule;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001761 int family = nfmsg->nfgen_family, err = 0;
1762 struct nft_ctx ctx;
Patrick McHardy96518512013-10-14 11:00:02 +02001763
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001764 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001765 if (IS_ERR(afi))
1766 return PTR_ERR(afi);
1767
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001768 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001769 if (IS_ERR(table))
1770 return PTR_ERR(table);
1771
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001772 if (nla[NFTA_RULE_CHAIN]) {
1773 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1774 if (IS_ERR(chain))
1775 return PTR_ERR(chain);
1776 }
Patrick McHardy96518512013-10-14 11:00:02 +02001777
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001778 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1779
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001780 if (chain) {
1781 if (nla[NFTA_RULE_HANDLE]) {
1782 rule = nf_tables_rule_lookup(chain,
1783 nla[NFTA_RULE_HANDLE]);
1784 if (IS_ERR(rule))
1785 return PTR_ERR(rule);
Patrick McHardy96518512013-10-14 11:00:02 +02001786
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001787 err = nf_tables_delrule_one(&ctx, rule);
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001788 } else {
1789 err = nf_table_delrule_by_chain(&ctx);
1790 }
1791 } else {
1792 list_for_each_entry(chain, &table->chains, list) {
1793 ctx.chain = chain;
1794 err = nf_table_delrule_by_chain(&ctx);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001795 if (err < 0)
1796 break;
Patrick McHardy96518512013-10-14 11:00:02 +02001797 }
1798 }
1799
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001800 return err;
1801}
1802
1803static int nf_tables_commit(struct sk_buff *skb)
1804{
1805 struct net *net = sock_net(skb->sk);
1806 struct nft_rule_trans *rupd, *tmp;
1807
1808 /* Bump generation counter, invalidate any dump in progress */
1809 net->nft.genctr++;
1810
1811 /* A new generation has just started */
1812 net->nft.gencursor = gencursor_next(net);
1813
1814 /* Make sure all packets have left the previous generation before
1815 * purging old rules.
1816 */
1817 synchronize_rcu();
1818
1819 list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
1820 /* Delete this rule from the dirty list */
1821 list_del(&rupd->list);
1822
1823 /* This rule was inactive in the past and just became active.
1824 * Clear the next bit of the genmask since its meaning has
1825 * changed, now it is the future.
1826 */
1827 if (nft_rule_is_active(net, rupd->rule)) {
1828 nft_rule_clear(net, rupd->rule);
1829 nf_tables_rule_notify(skb, rupd->nlh, rupd->table,
1830 rupd->chain, rupd->rule,
1831 NFT_MSG_NEWRULE, 0,
1832 rupd->family);
1833 kfree(rupd);
1834 continue;
1835 }
1836
1837 /* This rule is in the past, get rid of it */
1838 list_del_rcu(&rupd->rule->list);
1839 nf_tables_rule_notify(skb, rupd->nlh, rupd->table, rupd->chain,
1840 rupd->rule, NFT_MSG_DELRULE, 0,
1841 rupd->family);
1842 nf_tables_rule_destroy(rupd->rule);
1843 kfree(rupd);
1844 }
1845
1846 return 0;
1847}
1848
1849static int nf_tables_abort(struct sk_buff *skb)
1850{
1851 struct net *net = sock_net(skb->sk);
1852 struct nft_rule_trans *rupd, *tmp;
1853
1854 list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
1855 /* Delete all rules from the dirty list */
1856 list_del(&rupd->list);
1857
1858 if (!nft_rule_is_active_next(net, rupd->rule)) {
1859 nft_rule_clear(net, rupd->rule);
1860 kfree(rupd);
1861 continue;
1862 }
1863
1864 /* This rule is inactive, get rid of it */
1865 list_del_rcu(&rupd->rule->list);
1866 nf_tables_rule_destroy(rupd->rule);
1867 kfree(rupd);
1868 }
Patrick McHardy96518512013-10-14 11:00:02 +02001869 return 0;
1870}
1871
Patrick McHardy20a69342013-10-11 12:06:22 +02001872/*
1873 * Sets
1874 */
1875
1876static LIST_HEAD(nf_tables_set_ops);
1877
1878int nft_register_set(struct nft_set_ops *ops)
1879{
1880 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1881 list_add_tail(&ops->list, &nf_tables_set_ops);
1882 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1883 return 0;
1884}
1885EXPORT_SYMBOL_GPL(nft_register_set);
1886
1887void nft_unregister_set(struct nft_set_ops *ops)
1888{
1889 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1890 list_del(&ops->list);
1891 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1892}
1893EXPORT_SYMBOL_GPL(nft_unregister_set);
1894
1895static const struct nft_set_ops *nft_select_set_ops(const struct nlattr * const nla[])
1896{
1897 const struct nft_set_ops *ops;
1898 u32 features;
1899
1900#ifdef CONFIG_MODULES
1901 if (list_empty(&nf_tables_set_ops)) {
1902 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1903 request_module("nft-set");
1904 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1905 if (!list_empty(&nf_tables_set_ops))
1906 return ERR_PTR(-EAGAIN);
1907 }
1908#endif
1909 features = 0;
1910 if (nla[NFTA_SET_FLAGS] != NULL) {
1911 features = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
1912 features &= NFT_SET_INTERVAL | NFT_SET_MAP;
1913 }
1914
1915 // FIXME: implement selection properly
1916 list_for_each_entry(ops, &nf_tables_set_ops, list) {
1917 if ((ops->features & features) != features)
1918 continue;
1919 if (!try_module_get(ops->owner))
1920 continue;
1921 return ops;
1922 }
1923
1924 return ERR_PTR(-EOPNOTSUPP);
1925}
1926
1927static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
1928 [NFTA_SET_TABLE] = { .type = NLA_STRING },
1929 [NFTA_SET_NAME] = { .type = NLA_STRING },
1930 [NFTA_SET_FLAGS] = { .type = NLA_U32 },
1931 [NFTA_SET_KEY_TYPE] = { .type = NLA_U32 },
1932 [NFTA_SET_KEY_LEN] = { .type = NLA_U32 },
1933 [NFTA_SET_DATA_TYPE] = { .type = NLA_U32 },
1934 [NFTA_SET_DATA_LEN] = { .type = NLA_U32 },
1935};
1936
1937static int nft_ctx_init_from_setattr(struct nft_ctx *ctx,
1938 const struct sk_buff *skb,
1939 const struct nlmsghdr *nlh,
1940 const struct nlattr * const nla[])
1941{
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001942 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02001943 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01001944 const struct nft_af_info *afi = NULL;
Patrick McHardy20a69342013-10-11 12:06:22 +02001945 const struct nft_table *table = NULL;
1946
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01001947 if (nfmsg->nfgen_family != NFPROTO_UNSPEC) {
1948 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
1949 if (IS_ERR(afi))
1950 return PTR_ERR(afi);
1951 }
Patrick McHardy20a69342013-10-11 12:06:22 +02001952
1953 if (nla[NFTA_SET_TABLE] != NULL) {
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001954 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02001955 if (IS_ERR(table))
1956 return PTR_ERR(table);
1957 }
1958
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001959 nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02001960 return 0;
1961}
1962
1963struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
1964 const struct nlattr *nla)
1965{
1966 struct nft_set *set;
1967
1968 if (nla == NULL)
1969 return ERR_PTR(-EINVAL);
1970
1971 list_for_each_entry(set, &table->sets, list) {
1972 if (!nla_strcmp(nla, set->name))
1973 return set;
1974 }
1975 return ERR_PTR(-ENOENT);
1976}
1977
1978static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
1979 const char *name)
1980{
1981 const struct nft_set *i;
1982 const char *p;
1983 unsigned long *inuse;
1984 unsigned int n = 0;
1985
1986 p = strnchr(name, IFNAMSIZ, '%');
1987 if (p != NULL) {
1988 if (p[1] != 'd' || strchr(p + 2, '%'))
1989 return -EINVAL;
1990
1991 inuse = (unsigned long *)get_zeroed_page(GFP_KERNEL);
1992 if (inuse == NULL)
1993 return -ENOMEM;
1994
1995 list_for_each_entry(i, &ctx->table->sets, list) {
Daniel Borkmann14662912013-12-31 12:40:05 +01001996 int tmp;
1997
1998 if (!sscanf(i->name, name, &tmp))
Patrick McHardy20a69342013-10-11 12:06:22 +02001999 continue;
Daniel Borkmann14662912013-12-31 12:40:05 +01002000 if (tmp < 0 || tmp > BITS_PER_LONG * PAGE_SIZE)
Patrick McHardy20a69342013-10-11 12:06:22 +02002001 continue;
Daniel Borkmann14662912013-12-31 12:40:05 +01002002
2003 set_bit(tmp, inuse);
Patrick McHardy20a69342013-10-11 12:06:22 +02002004 }
2005
2006 n = find_first_zero_bit(inuse, BITS_PER_LONG * PAGE_SIZE);
2007 free_page((unsigned long)inuse);
2008 }
2009
2010 snprintf(set->name, sizeof(set->name), name, n);
2011 list_for_each_entry(i, &ctx->table->sets, list) {
2012 if (!strcmp(set->name, i->name))
2013 return -ENFILE;
2014 }
2015 return 0;
2016}
2017
2018static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
2019 const struct nft_set *set, u16 event, u16 flags)
2020{
2021 struct nfgenmsg *nfmsg;
2022 struct nlmsghdr *nlh;
2023 u32 portid = NETLINK_CB(ctx->skb).portid;
2024 u32 seq = ctx->nlh->nlmsg_seq;
2025
2026 event |= NFNL_SUBSYS_NFTABLES << 8;
2027 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
2028 flags);
2029 if (nlh == NULL)
2030 goto nla_put_failure;
2031
2032 nfmsg = nlmsg_data(nlh);
2033 nfmsg->nfgen_family = ctx->afi->family;
2034 nfmsg->version = NFNETLINK_V0;
2035 nfmsg->res_id = 0;
2036
2037 if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
2038 goto nla_put_failure;
2039 if (nla_put_string(skb, NFTA_SET_NAME, set->name))
2040 goto nla_put_failure;
2041 if (set->flags != 0)
2042 if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
2043 goto nla_put_failure;
2044
2045 if (nla_put_be32(skb, NFTA_SET_KEY_TYPE, htonl(set->ktype)))
2046 goto nla_put_failure;
2047 if (nla_put_be32(skb, NFTA_SET_KEY_LEN, htonl(set->klen)))
2048 goto nla_put_failure;
2049 if (set->flags & NFT_SET_MAP) {
2050 if (nla_put_be32(skb, NFTA_SET_DATA_TYPE, htonl(set->dtype)))
2051 goto nla_put_failure;
2052 if (nla_put_be32(skb, NFTA_SET_DATA_LEN, htonl(set->dlen)))
2053 goto nla_put_failure;
2054 }
2055
2056 return nlmsg_end(skb, nlh);
2057
2058nla_put_failure:
2059 nlmsg_trim(skb, nlh);
2060 return -1;
2061}
2062
2063static int nf_tables_set_notify(const struct nft_ctx *ctx,
2064 const struct nft_set *set,
2065 int event)
2066{
2067 struct sk_buff *skb;
2068 u32 portid = NETLINK_CB(ctx->skb).portid;
Patrick McHardy20a69342013-10-11 12:06:22 +02002069 bool report;
2070 int err;
2071
2072 report = nlmsg_report(ctx->nlh);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002073 if (!report && !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
Patrick McHardy20a69342013-10-11 12:06:22 +02002074 return 0;
2075
2076 err = -ENOBUFS;
2077 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
2078 if (skb == NULL)
2079 goto err;
2080
2081 err = nf_tables_fill_set(skb, ctx, set, event, 0);
2082 if (err < 0) {
2083 kfree_skb(skb);
2084 goto err;
2085 }
2086
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002087 err = nfnetlink_send(skb, ctx->net, portid, NFNLGRP_NFTABLES, report,
Patrick McHardy20a69342013-10-11 12:06:22 +02002088 GFP_KERNEL);
2089err:
2090 if (err < 0)
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002091 nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, err);
Patrick McHardy20a69342013-10-11 12:06:22 +02002092 return err;
2093}
2094
2095static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb,
2096 struct netlink_callback *cb)
2097{
2098 const struct nft_set *set;
2099 unsigned int idx = 0, s_idx = cb->args[0];
2100
2101 if (cb->args[1])
2102 return skb->len;
2103
2104 list_for_each_entry(set, &ctx->table->sets, list) {
2105 if (idx < s_idx)
2106 goto cont;
2107 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
2108 NLM_F_MULTI) < 0) {
2109 cb->args[0] = idx;
2110 goto done;
2111 }
2112cont:
2113 idx++;
2114 }
2115 cb->args[1] = 1;
2116done:
2117 return skb->len;
2118}
2119
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002120static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb,
2121 struct netlink_callback *cb)
Patrick McHardy20a69342013-10-11 12:06:22 +02002122{
2123 const struct nft_set *set;
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002124 unsigned int idx, s_idx = cb->args[0];
Patrick McHardy20a69342013-10-11 12:06:22 +02002125 struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
2126
2127 if (cb->args[1])
2128 return skb->len;
2129
2130 list_for_each_entry(table, &ctx->afi->tables, list) {
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002131 if (cur_table) {
2132 if (cur_table != table)
2133 continue;
Patrick McHardy20a69342013-10-11 12:06:22 +02002134
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002135 cur_table = NULL;
2136 }
Patrick McHardy20a69342013-10-11 12:06:22 +02002137 ctx->table = table;
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002138 idx = 0;
Patrick McHardy20a69342013-10-11 12:06:22 +02002139 list_for_each_entry(set, &ctx->table->sets, list) {
2140 if (idx < s_idx)
2141 goto cont;
2142 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
2143 NLM_F_MULTI) < 0) {
2144 cb->args[0] = idx;
2145 cb->args[2] = (unsigned long) table;
2146 goto done;
2147 }
2148cont:
2149 idx++;
2150 }
2151 }
2152 cb->args[1] = 1;
2153done:
2154 return skb->len;
2155}
2156
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002157static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb,
2158 struct netlink_callback *cb)
2159{
2160 const struct nft_set *set;
2161 unsigned int idx, s_idx = cb->args[0];
2162 const struct nft_af_info *afi;
2163 struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
2164 struct net *net = sock_net(skb->sk);
2165 int cur_family = cb->args[3];
2166
2167 if (cb->args[1])
2168 return skb->len;
2169
2170 list_for_each_entry(afi, &net->nft.af_info, list) {
2171 if (cur_family) {
2172 if (afi->family != cur_family)
2173 continue;
2174
2175 cur_family = 0;
2176 }
2177
2178 list_for_each_entry(table, &afi->tables, list) {
2179 if (cur_table) {
2180 if (cur_table != table)
2181 continue;
2182
2183 cur_table = NULL;
2184 }
2185
2186 ctx->table = table;
2187 ctx->afi = afi;
2188 idx = 0;
2189 list_for_each_entry(set, &ctx->table->sets, list) {
2190 if (idx < s_idx)
2191 goto cont;
2192 if (nf_tables_fill_set(skb, ctx, set,
2193 NFT_MSG_NEWSET,
2194 NLM_F_MULTI) < 0) {
2195 cb->args[0] = idx;
2196 cb->args[2] = (unsigned long) table;
2197 cb->args[3] = afi->family;
2198 goto done;
2199 }
2200cont:
2201 idx++;
2202 }
2203 if (s_idx)
2204 s_idx = 0;
2205 }
2206 }
2207 cb->args[1] = 1;
2208done:
2209 return skb->len;
2210}
2211
Patrick McHardy20a69342013-10-11 12:06:22 +02002212static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
2213{
2214 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
2215 struct nlattr *nla[NFTA_SET_MAX + 1];
2216 struct nft_ctx ctx;
2217 int err, ret;
2218
2219 err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_MAX,
2220 nft_set_policy);
2221 if (err < 0)
2222 return err;
2223
2224 err = nft_ctx_init_from_setattr(&ctx, cb->skb, cb->nlh, (void *)nla);
2225 if (err < 0)
2226 return err;
2227
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002228 if (ctx.table == NULL) {
2229 if (ctx.afi == NULL)
2230 ret = nf_tables_dump_sets_all(&ctx, skb, cb);
2231 else
2232 ret = nf_tables_dump_sets_family(&ctx, skb, cb);
2233 } else
Patrick McHardy20a69342013-10-11 12:06:22 +02002234 ret = nf_tables_dump_sets_table(&ctx, skb, cb);
2235
2236 return ret;
2237}
2238
2239static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
2240 const struct nlmsghdr *nlh,
2241 const struct nlattr * const nla[])
2242{
2243 const struct nft_set *set;
2244 struct nft_ctx ctx;
2245 struct sk_buff *skb2;
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002246 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Patrick McHardy20a69342013-10-11 12:06:22 +02002247 int err;
2248
2249 /* Verify existance before starting dump */
2250 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
2251 if (err < 0)
2252 return err;
2253
2254 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2255 struct netlink_dump_control c = {
2256 .dump = nf_tables_dump_sets,
2257 };
2258 return netlink_dump_start(nlsk, skb, nlh, &c);
2259 }
2260
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002261 /* Only accept unspec with dump */
2262 if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
2263 return -EAFNOSUPPORT;
2264
Patrick McHardy20a69342013-10-11 12:06:22 +02002265 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
2266 if (IS_ERR(set))
2267 return PTR_ERR(set);
2268
2269 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2270 if (skb2 == NULL)
2271 return -ENOMEM;
2272
2273 err = nf_tables_fill_set(skb2, &ctx, set, NFT_MSG_NEWSET, 0);
2274 if (err < 0)
2275 goto err;
2276
2277 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
2278
2279err:
2280 kfree_skb(skb2);
2281 return err;
2282}
2283
2284static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
2285 const struct nlmsghdr *nlh,
2286 const struct nlattr * const nla[])
2287{
2288 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
2289 const struct nft_set_ops *ops;
2290 const struct nft_af_info *afi;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002291 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02002292 struct nft_table *table;
2293 struct nft_set *set;
2294 struct nft_ctx ctx;
2295 char name[IFNAMSIZ];
2296 unsigned int size;
2297 bool create;
2298 u32 ktype, klen, dlen, dtype, flags;
2299 int err;
2300
2301 if (nla[NFTA_SET_TABLE] == NULL ||
2302 nla[NFTA_SET_NAME] == NULL ||
2303 nla[NFTA_SET_KEY_LEN] == NULL)
2304 return -EINVAL;
2305
2306 ktype = NFT_DATA_VALUE;
2307 if (nla[NFTA_SET_KEY_TYPE] != NULL) {
2308 ktype = ntohl(nla_get_be32(nla[NFTA_SET_KEY_TYPE]));
2309 if ((ktype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK)
2310 return -EINVAL;
2311 }
2312
2313 klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
2314 if (klen == 0 || klen > FIELD_SIZEOF(struct nft_data, data))
2315 return -EINVAL;
2316
2317 flags = 0;
2318 if (nla[NFTA_SET_FLAGS] != NULL) {
2319 flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
2320 if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
2321 NFT_SET_INTERVAL | NFT_SET_MAP))
2322 return -EINVAL;
2323 }
2324
2325 dtype = 0;
2326 dlen = 0;
2327 if (nla[NFTA_SET_DATA_TYPE] != NULL) {
2328 if (!(flags & NFT_SET_MAP))
2329 return -EINVAL;
2330
2331 dtype = ntohl(nla_get_be32(nla[NFTA_SET_DATA_TYPE]));
2332 if ((dtype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK &&
2333 dtype != NFT_DATA_VERDICT)
2334 return -EINVAL;
2335
2336 if (dtype != NFT_DATA_VERDICT) {
2337 if (nla[NFTA_SET_DATA_LEN] == NULL)
2338 return -EINVAL;
2339 dlen = ntohl(nla_get_be32(nla[NFTA_SET_DATA_LEN]));
2340 if (dlen == 0 ||
2341 dlen > FIELD_SIZEOF(struct nft_data, data))
2342 return -EINVAL;
2343 } else
2344 dlen = sizeof(struct nft_data);
2345 } else if (flags & NFT_SET_MAP)
2346 return -EINVAL;
2347
2348 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
2349
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002350 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
Patrick McHardy20a69342013-10-11 12:06:22 +02002351 if (IS_ERR(afi))
2352 return PTR_ERR(afi);
2353
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002354 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02002355 if (IS_ERR(table))
2356 return PTR_ERR(table);
2357
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002358 nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002359
2360 set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME]);
2361 if (IS_ERR(set)) {
2362 if (PTR_ERR(set) != -ENOENT)
2363 return PTR_ERR(set);
2364 set = NULL;
2365 }
2366
2367 if (set != NULL) {
2368 if (nlh->nlmsg_flags & NLM_F_EXCL)
2369 return -EEXIST;
2370 if (nlh->nlmsg_flags & NLM_F_REPLACE)
2371 return -EOPNOTSUPP;
2372 return 0;
2373 }
2374
2375 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
2376 return -ENOENT;
2377
2378 ops = nft_select_set_ops(nla);
2379 if (IS_ERR(ops))
2380 return PTR_ERR(ops);
2381
2382 size = 0;
2383 if (ops->privsize != NULL)
2384 size = ops->privsize(nla);
2385
2386 err = -ENOMEM;
2387 set = kzalloc(sizeof(*set) + size, GFP_KERNEL);
2388 if (set == NULL)
2389 goto err1;
2390
2391 nla_strlcpy(name, nla[NFTA_SET_NAME], sizeof(set->name));
2392 err = nf_tables_set_alloc_name(&ctx, set, name);
2393 if (err < 0)
2394 goto err2;
2395
2396 INIT_LIST_HEAD(&set->bindings);
2397 set->ops = ops;
2398 set->ktype = ktype;
2399 set->klen = klen;
2400 set->dtype = dtype;
2401 set->dlen = dlen;
2402 set->flags = flags;
2403
2404 err = ops->init(set, nla);
2405 if (err < 0)
2406 goto err2;
2407
2408 list_add_tail(&set->list, &table->sets);
2409 nf_tables_set_notify(&ctx, set, NFT_MSG_NEWSET);
2410 return 0;
2411
2412err2:
2413 kfree(set);
2414err1:
2415 module_put(ops->owner);
2416 return err;
2417}
2418
2419static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
2420{
2421 list_del(&set->list);
2422 if (!(set->flags & NFT_SET_ANONYMOUS))
2423 nf_tables_set_notify(ctx, set, NFT_MSG_DELSET);
2424
2425 set->ops->destroy(set);
2426 module_put(set->ops->owner);
2427 kfree(set);
2428}
2429
2430static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
2431 const struct nlmsghdr *nlh,
2432 const struct nlattr * const nla[])
2433{
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002434 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Patrick McHardy20a69342013-10-11 12:06:22 +02002435 struct nft_set *set;
2436 struct nft_ctx ctx;
2437 int err;
2438
2439 if (nla[NFTA_SET_TABLE] == NULL)
2440 return -EINVAL;
2441
2442 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
2443 if (err < 0)
2444 return err;
2445
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002446 if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
2447 return -EAFNOSUPPORT;
2448
Patrick McHardy20a69342013-10-11 12:06:22 +02002449 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
2450 if (IS_ERR(set))
2451 return PTR_ERR(set);
2452 if (!list_empty(&set->bindings))
2453 return -EBUSY;
2454
2455 nf_tables_set_destroy(&ctx, set);
2456 return 0;
2457}
2458
2459static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
2460 const struct nft_set *set,
2461 const struct nft_set_iter *iter,
2462 const struct nft_set_elem *elem)
2463{
2464 enum nft_registers dreg;
2465
2466 dreg = nft_type_to_reg(set->dtype);
Pablo Neira Ayuso2ee0d3c2013-12-28 00:59:38 +01002467 return nft_validate_data_load(ctx, dreg, &elem->data,
2468 set->dtype == NFT_DATA_VERDICT ?
2469 NFT_DATA_VERDICT : NFT_DATA_VALUE);
Patrick McHardy20a69342013-10-11 12:06:22 +02002470}
2471
2472int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
2473 struct nft_set_binding *binding)
2474{
2475 struct nft_set_binding *i;
2476 struct nft_set_iter iter;
2477
2478 if (!list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
2479 return -EBUSY;
2480
2481 if (set->flags & NFT_SET_MAP) {
2482 /* If the set is already bound to the same chain all
2483 * jumps are already validated for that chain.
2484 */
2485 list_for_each_entry(i, &set->bindings, list) {
2486 if (i->chain == binding->chain)
2487 goto bind;
2488 }
2489
2490 iter.skip = 0;
2491 iter.count = 0;
2492 iter.err = 0;
2493 iter.fn = nf_tables_bind_check_setelem;
2494
2495 set->ops->walk(ctx, set, &iter);
2496 if (iter.err < 0) {
2497 /* Destroy anonymous sets if binding fails */
2498 if (set->flags & NFT_SET_ANONYMOUS)
2499 nf_tables_set_destroy(ctx, set);
2500
2501 return iter.err;
2502 }
2503 }
2504bind:
2505 binding->chain = ctx->chain;
2506 list_add_tail(&binding->list, &set->bindings);
2507 return 0;
2508}
2509
2510void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
2511 struct nft_set_binding *binding)
2512{
2513 list_del(&binding->list);
2514
2515 if (list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
2516 nf_tables_set_destroy(ctx, set);
2517}
2518
2519/*
2520 * Set elements
2521 */
2522
2523static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
2524 [NFTA_SET_ELEM_KEY] = { .type = NLA_NESTED },
2525 [NFTA_SET_ELEM_DATA] = { .type = NLA_NESTED },
2526 [NFTA_SET_ELEM_FLAGS] = { .type = NLA_U32 },
2527};
2528
2529static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
2530 [NFTA_SET_ELEM_LIST_TABLE] = { .type = NLA_STRING },
2531 [NFTA_SET_ELEM_LIST_SET] = { .type = NLA_STRING },
2532 [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NLA_NESTED },
2533};
2534
2535static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx,
2536 const struct sk_buff *skb,
2537 const struct nlmsghdr *nlh,
2538 const struct nlattr * const nla[])
2539{
2540 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
2541 const struct nft_af_info *afi;
2542 const struct nft_table *table;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002543 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02002544
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002545 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
Patrick McHardy20a69342013-10-11 12:06:22 +02002546 if (IS_ERR(afi))
2547 return PTR_ERR(afi);
2548
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002549 table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02002550 if (IS_ERR(table))
2551 return PTR_ERR(table);
2552
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002553 nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002554 return 0;
2555}
2556
2557static int nf_tables_fill_setelem(struct sk_buff *skb,
2558 const struct nft_set *set,
2559 const struct nft_set_elem *elem)
2560{
2561 unsigned char *b = skb_tail_pointer(skb);
2562 struct nlattr *nest;
2563
2564 nest = nla_nest_start(skb, NFTA_LIST_ELEM);
2565 if (nest == NULL)
2566 goto nla_put_failure;
2567
2568 if (nft_data_dump(skb, NFTA_SET_ELEM_KEY, &elem->key, NFT_DATA_VALUE,
2569 set->klen) < 0)
2570 goto nla_put_failure;
2571
2572 if (set->flags & NFT_SET_MAP &&
2573 !(elem->flags & NFT_SET_ELEM_INTERVAL_END) &&
2574 nft_data_dump(skb, NFTA_SET_ELEM_DATA, &elem->data,
2575 set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE,
2576 set->dlen) < 0)
2577 goto nla_put_failure;
2578
2579 if (elem->flags != 0)
2580 if (nla_put_be32(skb, NFTA_SET_ELEM_FLAGS, htonl(elem->flags)))
2581 goto nla_put_failure;
2582
2583 nla_nest_end(skb, nest);
2584 return 0;
2585
2586nla_put_failure:
2587 nlmsg_trim(skb, b);
2588 return -EMSGSIZE;
2589}
2590
2591struct nft_set_dump_args {
2592 const struct netlink_callback *cb;
2593 struct nft_set_iter iter;
2594 struct sk_buff *skb;
2595};
2596
2597static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
2598 const struct nft_set *set,
2599 const struct nft_set_iter *iter,
2600 const struct nft_set_elem *elem)
2601{
2602 struct nft_set_dump_args *args;
2603
2604 args = container_of(iter, struct nft_set_dump_args, iter);
2605 return nf_tables_fill_setelem(args->skb, set, elem);
2606}
2607
2608static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
2609{
2610 const struct nft_set *set;
2611 struct nft_set_dump_args args;
2612 struct nft_ctx ctx;
2613 struct nlattr *nla[NFTA_SET_ELEM_LIST_MAX + 1];
2614 struct nfgenmsg *nfmsg;
2615 struct nlmsghdr *nlh;
2616 struct nlattr *nest;
2617 u32 portid, seq;
2618 int event, err;
2619
Michal Nazarewicz720e0df2014-01-01 06:27:19 +01002620 err = nlmsg_parse(cb->nlh, sizeof(struct nfgenmsg), nla,
2621 NFTA_SET_ELEM_LIST_MAX, nft_set_elem_list_policy);
Patrick McHardy20a69342013-10-11 12:06:22 +02002622 if (err < 0)
2623 return err;
2624
2625 err = nft_ctx_init_from_elemattr(&ctx, cb->skb, cb->nlh, (void *)nla);
2626 if (err < 0)
2627 return err;
2628
2629 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2630 if (IS_ERR(set))
2631 return PTR_ERR(set);
2632
2633 event = NFT_MSG_NEWSETELEM;
2634 event |= NFNL_SUBSYS_NFTABLES << 8;
2635 portid = NETLINK_CB(cb->skb).portid;
2636 seq = cb->nlh->nlmsg_seq;
2637
2638 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
2639 NLM_F_MULTI);
2640 if (nlh == NULL)
2641 goto nla_put_failure;
2642
2643 nfmsg = nlmsg_data(nlh);
2644 nfmsg->nfgen_family = NFPROTO_UNSPEC;
2645 nfmsg->version = NFNETLINK_V0;
2646 nfmsg->res_id = 0;
2647
2648 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, ctx.table->name))
2649 goto nla_put_failure;
2650 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_SET, set->name))
2651 goto nla_put_failure;
2652
2653 nest = nla_nest_start(skb, NFTA_SET_ELEM_LIST_ELEMENTS);
2654 if (nest == NULL)
2655 goto nla_put_failure;
2656
2657 args.cb = cb;
2658 args.skb = skb;
2659 args.iter.skip = cb->args[0];
2660 args.iter.count = 0;
2661 args.iter.err = 0;
2662 args.iter.fn = nf_tables_dump_setelem;
2663 set->ops->walk(&ctx, set, &args.iter);
2664
2665 nla_nest_end(skb, nest);
2666 nlmsg_end(skb, nlh);
2667
2668 if (args.iter.err && args.iter.err != -EMSGSIZE)
2669 return args.iter.err;
2670 if (args.iter.count == cb->args[0])
2671 return 0;
2672
2673 cb->args[0] = args.iter.count;
2674 return skb->len;
2675
2676nla_put_failure:
2677 return -ENOSPC;
2678}
2679
2680static int nf_tables_getsetelem(struct sock *nlsk, struct sk_buff *skb,
2681 const struct nlmsghdr *nlh,
2682 const struct nlattr * const nla[])
2683{
2684 const struct nft_set *set;
2685 struct nft_ctx ctx;
2686 int err;
2687
2688 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2689 if (err < 0)
2690 return err;
2691
2692 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2693 if (IS_ERR(set))
2694 return PTR_ERR(set);
2695
2696 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2697 struct netlink_dump_control c = {
2698 .dump = nf_tables_dump_set,
2699 };
2700 return netlink_dump_start(nlsk, skb, nlh, &c);
2701 }
2702 return -EOPNOTSUPP;
2703}
2704
2705static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set,
2706 const struct nlattr *attr)
2707{
2708 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
2709 struct nft_data_desc d1, d2;
2710 struct nft_set_elem elem;
2711 struct nft_set_binding *binding;
2712 enum nft_registers dreg;
2713 int err;
2714
2715 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
2716 nft_set_elem_policy);
2717 if (err < 0)
2718 return err;
2719
2720 if (nla[NFTA_SET_ELEM_KEY] == NULL)
2721 return -EINVAL;
2722
2723 elem.flags = 0;
2724 if (nla[NFTA_SET_ELEM_FLAGS] != NULL) {
2725 elem.flags = ntohl(nla_get_be32(nla[NFTA_SET_ELEM_FLAGS]));
2726 if (elem.flags & ~NFT_SET_ELEM_INTERVAL_END)
2727 return -EINVAL;
2728 }
2729
2730 if (set->flags & NFT_SET_MAP) {
2731 if (nla[NFTA_SET_ELEM_DATA] == NULL &&
2732 !(elem.flags & NFT_SET_ELEM_INTERVAL_END))
2733 return -EINVAL;
2734 } else {
2735 if (nla[NFTA_SET_ELEM_DATA] != NULL)
2736 return -EINVAL;
2737 }
2738
2739 err = nft_data_init(ctx, &elem.key, &d1, nla[NFTA_SET_ELEM_KEY]);
2740 if (err < 0)
2741 goto err1;
2742 err = -EINVAL;
2743 if (d1.type != NFT_DATA_VALUE || d1.len != set->klen)
2744 goto err2;
2745
2746 err = -EEXIST;
2747 if (set->ops->get(set, &elem) == 0)
2748 goto err2;
2749
2750 if (nla[NFTA_SET_ELEM_DATA] != NULL) {
2751 err = nft_data_init(ctx, &elem.data, &d2, nla[NFTA_SET_ELEM_DATA]);
2752 if (err < 0)
2753 goto err2;
2754
2755 err = -EINVAL;
2756 if (set->dtype != NFT_DATA_VERDICT && d2.len != set->dlen)
2757 goto err3;
2758
2759 dreg = nft_type_to_reg(set->dtype);
2760 list_for_each_entry(binding, &set->bindings, list) {
2761 struct nft_ctx bind_ctx = {
2762 .afi = ctx->afi,
2763 .table = ctx->table,
2764 .chain = binding->chain,
2765 };
2766
2767 err = nft_validate_data_load(&bind_ctx, dreg,
2768 &elem.data, d2.type);
2769 if (err < 0)
2770 goto err3;
2771 }
2772 }
2773
2774 err = set->ops->insert(set, &elem);
2775 if (err < 0)
2776 goto err3;
2777
2778 return 0;
2779
2780err3:
2781 if (nla[NFTA_SET_ELEM_DATA] != NULL)
2782 nft_data_uninit(&elem.data, d2.type);
2783err2:
2784 nft_data_uninit(&elem.key, d1.type);
2785err1:
2786 return err;
2787}
2788
2789static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
2790 const struct nlmsghdr *nlh,
2791 const struct nlattr * const nla[])
2792{
2793 const struct nlattr *attr;
2794 struct nft_set *set;
2795 struct nft_ctx ctx;
2796 int rem, err;
2797
2798 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2799 if (err < 0)
2800 return err;
2801
2802 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2803 if (IS_ERR(set))
2804 return PTR_ERR(set);
2805 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
2806 return -EBUSY;
2807
2808 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
2809 err = nft_add_set_elem(&ctx, set, attr);
2810 if (err < 0)
2811 return err;
2812 }
2813 return 0;
2814}
2815
2816static int nft_del_setelem(const struct nft_ctx *ctx, struct nft_set *set,
2817 const struct nlattr *attr)
2818{
2819 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
2820 struct nft_data_desc desc;
2821 struct nft_set_elem elem;
2822 int err;
2823
2824 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
2825 nft_set_elem_policy);
2826 if (err < 0)
2827 goto err1;
2828
2829 err = -EINVAL;
2830 if (nla[NFTA_SET_ELEM_KEY] == NULL)
2831 goto err1;
2832
2833 err = nft_data_init(ctx, &elem.key, &desc, nla[NFTA_SET_ELEM_KEY]);
2834 if (err < 0)
2835 goto err1;
2836
2837 err = -EINVAL;
2838 if (desc.type != NFT_DATA_VALUE || desc.len != set->klen)
2839 goto err2;
2840
2841 err = set->ops->get(set, &elem);
2842 if (err < 0)
2843 goto err2;
2844
2845 set->ops->remove(set, &elem);
2846
2847 nft_data_uninit(&elem.key, NFT_DATA_VALUE);
2848 if (set->flags & NFT_SET_MAP)
2849 nft_data_uninit(&elem.data, set->dtype);
2850
2851err2:
2852 nft_data_uninit(&elem.key, desc.type);
2853err1:
2854 return err;
2855}
2856
2857static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
2858 const struct nlmsghdr *nlh,
2859 const struct nlattr * const nla[])
2860{
2861 const struct nlattr *attr;
2862 struct nft_set *set;
2863 struct nft_ctx ctx;
2864 int rem, err;
2865
2866 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2867 if (err < 0)
2868 return err;
2869
2870 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2871 if (IS_ERR(set))
2872 return PTR_ERR(set);
2873 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
2874 return -EBUSY;
2875
2876 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
2877 err = nft_del_setelem(&ctx, set, attr);
2878 if (err < 0)
2879 return err;
2880 }
2881 return 0;
2882}
2883
Patrick McHardy96518512013-10-14 11:00:02 +02002884static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
2885 [NFT_MSG_NEWTABLE] = {
2886 .call = nf_tables_newtable,
2887 .attr_count = NFTA_TABLE_MAX,
2888 .policy = nft_table_policy,
2889 },
2890 [NFT_MSG_GETTABLE] = {
2891 .call = nf_tables_gettable,
2892 .attr_count = NFTA_TABLE_MAX,
2893 .policy = nft_table_policy,
2894 },
2895 [NFT_MSG_DELTABLE] = {
2896 .call = nf_tables_deltable,
2897 .attr_count = NFTA_TABLE_MAX,
2898 .policy = nft_table_policy,
2899 },
2900 [NFT_MSG_NEWCHAIN] = {
2901 .call = nf_tables_newchain,
2902 .attr_count = NFTA_CHAIN_MAX,
2903 .policy = nft_chain_policy,
2904 },
2905 [NFT_MSG_GETCHAIN] = {
2906 .call = nf_tables_getchain,
2907 .attr_count = NFTA_CHAIN_MAX,
2908 .policy = nft_chain_policy,
2909 },
2910 [NFT_MSG_DELCHAIN] = {
2911 .call = nf_tables_delchain,
2912 .attr_count = NFTA_CHAIN_MAX,
2913 .policy = nft_chain_policy,
2914 },
2915 [NFT_MSG_NEWRULE] = {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002916 .call_batch = nf_tables_newrule,
Patrick McHardy96518512013-10-14 11:00:02 +02002917 .attr_count = NFTA_RULE_MAX,
2918 .policy = nft_rule_policy,
2919 },
2920 [NFT_MSG_GETRULE] = {
2921 .call = nf_tables_getrule,
2922 .attr_count = NFTA_RULE_MAX,
2923 .policy = nft_rule_policy,
2924 },
2925 [NFT_MSG_DELRULE] = {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002926 .call_batch = nf_tables_delrule,
Patrick McHardy96518512013-10-14 11:00:02 +02002927 .attr_count = NFTA_RULE_MAX,
2928 .policy = nft_rule_policy,
2929 },
Patrick McHardy20a69342013-10-11 12:06:22 +02002930 [NFT_MSG_NEWSET] = {
2931 .call = nf_tables_newset,
2932 .attr_count = NFTA_SET_MAX,
2933 .policy = nft_set_policy,
2934 },
2935 [NFT_MSG_GETSET] = {
2936 .call = nf_tables_getset,
2937 .attr_count = NFTA_SET_MAX,
2938 .policy = nft_set_policy,
2939 },
2940 [NFT_MSG_DELSET] = {
2941 .call = nf_tables_delset,
2942 .attr_count = NFTA_SET_MAX,
2943 .policy = nft_set_policy,
2944 },
2945 [NFT_MSG_NEWSETELEM] = {
2946 .call = nf_tables_newsetelem,
2947 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2948 .policy = nft_set_elem_list_policy,
2949 },
2950 [NFT_MSG_GETSETELEM] = {
2951 .call = nf_tables_getsetelem,
2952 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2953 .policy = nft_set_elem_list_policy,
2954 },
2955 [NFT_MSG_DELSETELEM] = {
2956 .call = nf_tables_delsetelem,
2957 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2958 .policy = nft_set_elem_list_policy,
2959 },
Patrick McHardy96518512013-10-14 11:00:02 +02002960};
2961
2962static const struct nfnetlink_subsystem nf_tables_subsys = {
2963 .name = "nf_tables",
2964 .subsys_id = NFNL_SUBSYS_NFTABLES,
2965 .cb_count = NFT_MSG_MAX,
2966 .cb = nf_tables_cb,
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002967 .commit = nf_tables_commit,
2968 .abort = nf_tables_abort,
Patrick McHardy96518512013-10-14 11:00:02 +02002969};
2970
Patrick McHardy20a69342013-10-11 12:06:22 +02002971/*
2972 * Loop detection - walk through the ruleset beginning at the destination chain
2973 * of a new jump until either the source chain is reached (loop) or all
2974 * reachable chains have been traversed.
2975 *
2976 * The loop check is performed whenever a new jump verdict is added to an
2977 * expression or verdict map or a verdict map is bound to a new chain.
2978 */
2979
2980static int nf_tables_check_loops(const struct nft_ctx *ctx,
2981 const struct nft_chain *chain);
2982
2983static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
2984 const struct nft_set *set,
2985 const struct nft_set_iter *iter,
2986 const struct nft_set_elem *elem)
2987{
2988 switch (elem->data.verdict) {
2989 case NFT_JUMP:
2990 case NFT_GOTO:
2991 return nf_tables_check_loops(ctx, elem->data.chain);
2992 default:
2993 return 0;
2994 }
2995}
2996
2997static int nf_tables_check_loops(const struct nft_ctx *ctx,
2998 const struct nft_chain *chain)
2999{
3000 const struct nft_rule *rule;
3001 const struct nft_expr *expr, *last;
Patrick McHardy20a69342013-10-11 12:06:22 +02003002 const struct nft_set *set;
3003 struct nft_set_binding *binding;
3004 struct nft_set_iter iter;
Patrick McHardy20a69342013-10-11 12:06:22 +02003005
3006 if (ctx->chain == chain)
3007 return -ELOOP;
3008
3009 list_for_each_entry(rule, &chain->rules, list) {
3010 nft_rule_for_each_expr(expr, last, rule) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02003011 const struct nft_data *data = NULL;
3012 int err;
3013
3014 if (!expr->ops->validate)
Patrick McHardy20a69342013-10-11 12:06:22 +02003015 continue;
3016
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02003017 err = expr->ops->validate(ctx, expr, &data);
3018 if (err < 0)
3019 return err;
3020
Patrick McHardy20a69342013-10-11 12:06:22 +02003021 if (data == NULL)
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02003022 continue;
Patrick McHardy20a69342013-10-11 12:06:22 +02003023
3024 switch (data->verdict) {
3025 case NFT_JUMP:
3026 case NFT_GOTO:
3027 err = nf_tables_check_loops(ctx, data->chain);
3028 if (err < 0)
3029 return err;
3030 default:
3031 break;
3032 }
3033 }
3034 }
3035
3036 list_for_each_entry(set, &ctx->table->sets, list) {
3037 if (!(set->flags & NFT_SET_MAP) ||
3038 set->dtype != NFT_DATA_VERDICT)
3039 continue;
3040
3041 list_for_each_entry(binding, &set->bindings, list) {
3042 if (binding->chain != chain)
3043 continue;
3044
3045 iter.skip = 0;
3046 iter.count = 0;
3047 iter.err = 0;
3048 iter.fn = nf_tables_loop_check_setelem;
3049
3050 set->ops->walk(ctx, set, &iter);
3051 if (iter.err < 0)
3052 return iter.err;
3053 }
3054 }
3055
3056 return 0;
3057}
3058
Patrick McHardy96518512013-10-14 11:00:02 +02003059/**
3060 * nft_validate_input_register - validate an expressions' input register
3061 *
3062 * @reg: the register number
3063 *
3064 * Validate that the input register is one of the general purpose
3065 * registers.
3066 */
3067int nft_validate_input_register(enum nft_registers reg)
3068{
3069 if (reg <= NFT_REG_VERDICT)
3070 return -EINVAL;
3071 if (reg > NFT_REG_MAX)
3072 return -ERANGE;
3073 return 0;
3074}
3075EXPORT_SYMBOL_GPL(nft_validate_input_register);
3076
3077/**
3078 * nft_validate_output_register - validate an expressions' output register
3079 *
3080 * @reg: the register number
3081 *
3082 * Validate that the output register is one of the general purpose
3083 * registers or the verdict register.
3084 */
3085int nft_validate_output_register(enum nft_registers reg)
3086{
3087 if (reg < NFT_REG_VERDICT)
3088 return -EINVAL;
3089 if (reg > NFT_REG_MAX)
3090 return -ERANGE;
3091 return 0;
3092}
3093EXPORT_SYMBOL_GPL(nft_validate_output_register);
3094
3095/**
3096 * nft_validate_data_load - validate an expressions' data load
3097 *
3098 * @ctx: context of the expression performing the load
3099 * @reg: the destination register number
3100 * @data: the data to load
3101 * @type: the data type
3102 *
3103 * Validate that a data load uses the appropriate data type for
3104 * the destination register. A value of NULL for the data means
3105 * that its runtime gathered data, which is always of type
3106 * NFT_DATA_VALUE.
3107 */
3108int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
3109 const struct nft_data *data,
3110 enum nft_data_types type)
3111{
Patrick McHardy20a69342013-10-11 12:06:22 +02003112 int err;
3113
Patrick McHardy96518512013-10-14 11:00:02 +02003114 switch (reg) {
3115 case NFT_REG_VERDICT:
3116 if (data == NULL || type != NFT_DATA_VERDICT)
3117 return -EINVAL;
Patrick McHardy20a69342013-10-11 12:06:22 +02003118
3119 if (data->verdict == NFT_GOTO || data->verdict == NFT_JUMP) {
3120 err = nf_tables_check_loops(ctx, data->chain);
3121 if (err < 0)
3122 return err;
3123
3124 if (ctx->chain->level + 1 > data->chain->level) {
3125 if (ctx->chain->level + 1 == NFT_JUMP_STACK_SIZE)
3126 return -EMLINK;
3127 data->chain->level = ctx->chain->level + 1;
3128 }
3129 }
3130
Patrick McHardy96518512013-10-14 11:00:02 +02003131 return 0;
3132 default:
3133 if (data != NULL && type != NFT_DATA_VALUE)
3134 return -EINVAL;
3135 return 0;
3136 }
3137}
3138EXPORT_SYMBOL_GPL(nft_validate_data_load);
3139
3140static const struct nla_policy nft_verdict_policy[NFTA_VERDICT_MAX + 1] = {
3141 [NFTA_VERDICT_CODE] = { .type = NLA_U32 },
3142 [NFTA_VERDICT_CHAIN] = { .type = NLA_STRING,
3143 .len = NFT_CHAIN_MAXNAMELEN - 1 },
3144};
3145
3146static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
3147 struct nft_data_desc *desc, const struct nlattr *nla)
3148{
3149 struct nlattr *tb[NFTA_VERDICT_MAX + 1];
3150 struct nft_chain *chain;
3151 int err;
3152
3153 err = nla_parse_nested(tb, NFTA_VERDICT_MAX, nla, nft_verdict_policy);
3154 if (err < 0)
3155 return err;
3156
3157 if (!tb[NFTA_VERDICT_CODE])
3158 return -EINVAL;
3159 data->verdict = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE]));
3160
3161 switch (data->verdict) {
3162 case NF_ACCEPT:
3163 case NF_DROP:
3164 case NF_QUEUE:
3165 case NFT_CONTINUE:
3166 case NFT_BREAK:
3167 case NFT_RETURN:
3168 desc->len = sizeof(data->verdict);
3169 break;
3170 case NFT_JUMP:
3171 case NFT_GOTO:
3172 if (!tb[NFTA_VERDICT_CHAIN])
3173 return -EINVAL;
3174 chain = nf_tables_chain_lookup(ctx->table,
3175 tb[NFTA_VERDICT_CHAIN]);
3176 if (IS_ERR(chain))
3177 return PTR_ERR(chain);
3178 if (chain->flags & NFT_BASE_CHAIN)
3179 return -EOPNOTSUPP;
3180
Patrick McHardy96518512013-10-14 11:00:02 +02003181 chain->use++;
3182 data->chain = chain;
3183 desc->len = sizeof(data);
3184 break;
3185 default:
3186 return -EINVAL;
3187 }
3188
3189 desc->type = NFT_DATA_VERDICT;
3190 return 0;
3191}
3192
3193static void nft_verdict_uninit(const struct nft_data *data)
3194{
3195 switch (data->verdict) {
3196 case NFT_JUMP:
3197 case NFT_GOTO:
3198 data->chain->use--;
3199 break;
3200 }
3201}
3202
3203static int nft_verdict_dump(struct sk_buff *skb, const struct nft_data *data)
3204{
3205 struct nlattr *nest;
3206
3207 nest = nla_nest_start(skb, NFTA_DATA_VERDICT);
3208 if (!nest)
3209 goto nla_put_failure;
3210
3211 if (nla_put_be32(skb, NFTA_VERDICT_CODE, htonl(data->verdict)))
3212 goto nla_put_failure;
3213
3214 switch (data->verdict) {
3215 case NFT_JUMP:
3216 case NFT_GOTO:
3217 if (nla_put_string(skb, NFTA_VERDICT_CHAIN, data->chain->name))
3218 goto nla_put_failure;
3219 }
3220 nla_nest_end(skb, nest);
3221 return 0;
3222
3223nla_put_failure:
3224 return -1;
3225}
3226
3227static int nft_value_init(const struct nft_ctx *ctx, struct nft_data *data,
3228 struct nft_data_desc *desc, const struct nlattr *nla)
3229{
3230 unsigned int len;
3231
3232 len = nla_len(nla);
3233 if (len == 0)
3234 return -EINVAL;
3235 if (len > sizeof(data->data))
3236 return -EOVERFLOW;
3237
3238 nla_memcpy(data->data, nla, sizeof(data->data));
3239 desc->type = NFT_DATA_VALUE;
3240 desc->len = len;
3241 return 0;
3242}
3243
3244static int nft_value_dump(struct sk_buff *skb, const struct nft_data *data,
3245 unsigned int len)
3246{
3247 return nla_put(skb, NFTA_DATA_VALUE, len, data->data);
3248}
3249
3250static const struct nla_policy nft_data_policy[NFTA_DATA_MAX + 1] = {
3251 [NFTA_DATA_VALUE] = { .type = NLA_BINARY,
3252 .len = FIELD_SIZEOF(struct nft_data, data) },
3253 [NFTA_DATA_VERDICT] = { .type = NLA_NESTED },
3254};
3255
3256/**
3257 * nft_data_init - parse nf_tables data netlink attributes
3258 *
3259 * @ctx: context of the expression using the data
3260 * @data: destination struct nft_data
3261 * @desc: data description
3262 * @nla: netlink attribute containing data
3263 *
3264 * Parse the netlink data attributes and initialize a struct nft_data.
3265 * The type and length of data are returned in the data description.
3266 *
3267 * The caller can indicate that it only wants to accept data of type
3268 * NFT_DATA_VALUE by passing NULL for the ctx argument.
3269 */
3270int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data,
3271 struct nft_data_desc *desc, const struct nlattr *nla)
3272{
3273 struct nlattr *tb[NFTA_DATA_MAX + 1];
3274 int err;
3275
3276 err = nla_parse_nested(tb, NFTA_DATA_MAX, nla, nft_data_policy);
3277 if (err < 0)
3278 return err;
3279
3280 if (tb[NFTA_DATA_VALUE])
3281 return nft_value_init(ctx, data, desc, tb[NFTA_DATA_VALUE]);
3282 if (tb[NFTA_DATA_VERDICT] && ctx != NULL)
3283 return nft_verdict_init(ctx, data, desc, tb[NFTA_DATA_VERDICT]);
3284 return -EINVAL;
3285}
3286EXPORT_SYMBOL_GPL(nft_data_init);
3287
3288/**
3289 * nft_data_uninit - release a nft_data item
3290 *
3291 * @data: struct nft_data to release
3292 * @type: type of data
3293 *
3294 * Release a nft_data item. NFT_DATA_VALUE types can be silently discarded,
3295 * all others need to be released by calling this function.
3296 */
3297void nft_data_uninit(const struct nft_data *data, enum nft_data_types type)
3298{
3299 switch (type) {
3300 case NFT_DATA_VALUE:
3301 return;
3302 case NFT_DATA_VERDICT:
3303 return nft_verdict_uninit(data);
3304 default:
3305 WARN_ON(1);
3306 }
3307}
3308EXPORT_SYMBOL_GPL(nft_data_uninit);
3309
3310int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
3311 enum nft_data_types type, unsigned int len)
3312{
3313 struct nlattr *nest;
3314 int err;
3315
3316 nest = nla_nest_start(skb, attr);
3317 if (nest == NULL)
3318 return -1;
3319
3320 switch (type) {
3321 case NFT_DATA_VALUE:
3322 err = nft_value_dump(skb, data, len);
3323 break;
3324 case NFT_DATA_VERDICT:
3325 err = nft_verdict_dump(skb, data);
3326 break;
3327 default:
3328 err = -EINVAL;
3329 WARN_ON(1);
3330 }
3331
3332 nla_nest_end(skb, nest);
3333 return err;
3334}
3335EXPORT_SYMBOL_GPL(nft_data_dump);
3336
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003337static int nf_tables_init_net(struct net *net)
3338{
3339 INIT_LIST_HEAD(&net->nft.af_info);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02003340 INIT_LIST_HEAD(&net->nft.commit_list);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003341 return 0;
3342}
3343
3344static struct pernet_operations nf_tables_net_ops = {
3345 .init = nf_tables_init_net,
3346};
3347
Patrick McHardy96518512013-10-14 11:00:02 +02003348static int __init nf_tables_module_init(void)
3349{
3350 int err;
3351
3352 info = kmalloc(sizeof(struct nft_expr_info) * NFT_RULE_MAXEXPRS,
3353 GFP_KERNEL);
3354 if (info == NULL) {
3355 err = -ENOMEM;
3356 goto err1;
3357 }
3358
3359 err = nf_tables_core_module_init();
3360 if (err < 0)
3361 goto err2;
3362
3363 err = nfnetlink_subsys_register(&nf_tables_subsys);
3364 if (err < 0)
3365 goto err3;
3366
3367 pr_info("nf_tables: (c) 2007-2009 Patrick McHardy <kaber@trash.net>\n");
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003368 return register_pernet_subsys(&nf_tables_net_ops);
Patrick McHardy96518512013-10-14 11:00:02 +02003369err3:
3370 nf_tables_core_module_exit();
3371err2:
3372 kfree(info);
3373err1:
3374 return err;
3375}
3376
3377static void __exit nf_tables_module_exit(void)
3378{
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003379 unregister_pernet_subsys(&nf_tables_net_ops);
Patrick McHardy96518512013-10-14 11:00:02 +02003380 nfnetlink_subsys_unregister(&nf_tables_subsys);
3381 nf_tables_core_module_exit();
3382 kfree(info);
3383}
3384
3385module_init(nf_tables_module_init);
3386module_exit(nf_tables_module_exit);
3387
3388MODULE_LICENSE("GPL");
3389MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
3390MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFTABLES);