blob: d913fb0ab0aaf9f6ced487fe36598c6e060281ff [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
Patrick McHardybaae3e62014-01-09 18:42:34 +0000129static struct nf_chain_type *
130__nf_tables_chain_type_lookup(int family, const struct nlattr *nla)
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200131{
132 int i;
133
Patrick McHardybaae3e62014-01-09 18:42:34 +0000134 for (i = 0; i < NFT_CHAIN_T_MAX; i++) {
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200135 if (chain_type[family][i] != NULL &&
136 !nla_strcmp(nla, chain_type[family][i]->name))
Patrick McHardybaae3e62014-01-09 18:42:34 +0000137 return chain_type[family][i];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200138 }
Patrick McHardybaae3e62014-01-09 18:42:34 +0000139 return NULL;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200140}
141
Patrick McHardybaae3e62014-01-09 18:42:34 +0000142static struct nf_chain_type *
143nf_tables_chain_type_lookup(const struct nft_af_info *afi,
144 const struct nlattr *nla,
145 bool autoload)
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200146{
Patrick McHardybaae3e62014-01-09 18:42:34 +0000147 struct nf_chain_type *type;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200148
149 type = __nf_tables_chain_type_lookup(afi->family, nla);
150#ifdef CONFIG_MODULES
Patrick McHardybaae3e62014-01-09 18:42:34 +0000151 if (type == NULL && autoload) {
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200152 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
153 request_module("nft-chain-%u-%*.s", afi->family,
154 nla_len(nla)-1, (const char *)nla_data(nla));
155 nfnl_lock(NFNL_SUBSYS_NFTABLES);
156 type = __nf_tables_chain_type_lookup(afi->family, nla);
157 }
158#endif
159 return type;
160}
161
Patrick McHardy96518512013-10-14 11:00:02 +0200162static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
163 [NFTA_TABLE_NAME] = { .type = NLA_STRING },
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200164 [NFTA_TABLE_FLAGS] = { .type = NLA_U32 },
Patrick McHardy96518512013-10-14 11:00:02 +0200165};
166
167static int nf_tables_fill_table_info(struct sk_buff *skb, u32 portid, u32 seq,
168 int event, u32 flags, int family,
169 const struct nft_table *table)
170{
171 struct nlmsghdr *nlh;
172 struct nfgenmsg *nfmsg;
173
174 event |= NFNL_SUBSYS_NFTABLES << 8;
175 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
176 if (nlh == NULL)
177 goto nla_put_failure;
178
179 nfmsg = nlmsg_data(nlh);
180 nfmsg->nfgen_family = family;
181 nfmsg->version = NFNETLINK_V0;
182 nfmsg->res_id = 0;
183
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200184 if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
Tomasz Bursztykad8bcc7682013-12-12 15:00:42 +0200185 nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
186 nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)))
Patrick McHardy96518512013-10-14 11:00:02 +0200187 goto nla_put_failure;
188
189 return nlmsg_end(skb, nlh);
190
191nla_put_failure:
192 nlmsg_trim(skb, nlh);
193 return -1;
194}
195
196static int nf_tables_table_notify(const struct sk_buff *oskb,
197 const struct nlmsghdr *nlh,
198 const struct nft_table *table,
199 int event, int family)
200{
201 struct sk_buff *skb;
202 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
203 u32 seq = nlh ? nlh->nlmsg_seq : 0;
204 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
205 bool report;
206 int err;
207
208 report = nlh ? nlmsg_report(nlh) : false;
209 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
210 return 0;
211
212 err = -ENOBUFS;
213 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
214 if (skb == NULL)
215 goto err;
216
217 err = nf_tables_fill_table_info(skb, portid, seq, event, 0,
218 family, table);
219 if (err < 0) {
220 kfree_skb(skb);
221 goto err;
222 }
223
224 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
225 GFP_KERNEL);
226err:
227 if (err < 0)
228 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
229 return err;
230}
231
232static int nf_tables_dump_tables(struct sk_buff *skb,
233 struct netlink_callback *cb)
234{
235 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
236 const struct nft_af_info *afi;
237 const struct nft_table *table;
238 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200239 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200240 int family = nfmsg->nfgen_family;
241
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200242 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +0200243 if (family != NFPROTO_UNSPEC && family != afi->family)
244 continue;
245
246 list_for_each_entry(table, &afi->tables, list) {
247 if (idx < s_idx)
248 goto cont;
249 if (idx > s_idx)
250 memset(&cb->args[1], 0,
251 sizeof(cb->args) - sizeof(cb->args[0]));
252 if (nf_tables_fill_table_info(skb,
253 NETLINK_CB(cb->skb).portid,
254 cb->nlh->nlmsg_seq,
255 NFT_MSG_NEWTABLE,
256 NLM_F_MULTI,
257 afi->family, table) < 0)
258 goto done;
259cont:
260 idx++;
261 }
262 }
263done:
264 cb->args[0] = idx;
265 return skb->len;
266}
267
268static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb,
269 const struct nlmsghdr *nlh,
270 const struct nlattr * const nla[])
271{
272 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
273 const struct nft_af_info *afi;
274 const struct nft_table *table;
275 struct sk_buff *skb2;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200276 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200277 int family = nfmsg->nfgen_family;
278 int err;
279
280 if (nlh->nlmsg_flags & NLM_F_DUMP) {
281 struct netlink_dump_control c = {
282 .dump = nf_tables_dump_tables,
283 };
284 return netlink_dump_start(nlsk, skb, nlh, &c);
285 }
286
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200287 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200288 if (IS_ERR(afi))
289 return PTR_ERR(afi);
290
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200291 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
Patrick McHardy96518512013-10-14 11:00:02 +0200292 if (IS_ERR(table))
293 return PTR_ERR(table);
294
295 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
296 if (!skb2)
297 return -ENOMEM;
298
299 err = nf_tables_fill_table_info(skb2, NETLINK_CB(skb).portid,
300 nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0,
301 family, table);
302 if (err < 0)
303 goto err;
304
305 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
306
307err:
308 kfree_skb(skb2);
309 return err;
310}
311
Patrick McHardy115a60b2014-01-03 12:16:15 +0000312static int nf_tables_table_enable(const struct nft_af_info *afi,
313 struct nft_table *table)
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200314{
315 struct nft_chain *chain;
316 int err, i = 0;
317
318 list_for_each_entry(chain, &table->chains, list) {
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100319 if (!(chain->flags & NFT_BASE_CHAIN))
320 continue;
321
Patrick McHardy115a60b2014-01-03 12:16:15 +0000322 err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200323 if (err < 0)
324 goto err;
325
326 i++;
327 }
328 return 0;
329err:
330 list_for_each_entry(chain, &table->chains, list) {
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100331 if (!(chain->flags & NFT_BASE_CHAIN))
332 continue;
333
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200334 if (i-- <= 0)
335 break;
336
Patrick McHardy115a60b2014-01-03 12:16:15 +0000337 nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200338 }
339 return err;
340}
341
Patrick McHardy115a60b2014-01-03 12:16:15 +0000342static int nf_tables_table_disable(const struct nft_af_info *afi,
343 struct nft_table *table)
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200344{
345 struct nft_chain *chain;
346
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100347 list_for_each_entry(chain, &table->chains, list) {
348 if (chain->flags & NFT_BASE_CHAIN)
Patrick McHardy115a60b2014-01-03 12:16:15 +0000349 nf_unregister_hooks(nft_base_chain(chain)->ops,
350 afi->nops);
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100351 }
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200352
353 return 0;
354}
355
356static int nf_tables_updtable(struct sock *nlsk, struct sk_buff *skb,
357 const struct nlmsghdr *nlh,
358 const struct nlattr * const nla[],
359 struct nft_af_info *afi, struct nft_table *table)
360{
361 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
362 int family = nfmsg->nfgen_family, ret = 0;
363
364 if (nla[NFTA_TABLE_FLAGS]) {
365 __be32 flags;
366
367 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
368 if (flags & ~NFT_TABLE_F_DORMANT)
369 return -EINVAL;
370
371 if ((flags & NFT_TABLE_F_DORMANT) &&
372 !(table->flags & NFT_TABLE_F_DORMANT)) {
Patrick McHardy115a60b2014-01-03 12:16:15 +0000373 ret = nf_tables_table_disable(afi, table);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200374 if (ret >= 0)
375 table->flags |= NFT_TABLE_F_DORMANT;
376 } else if (!(flags & NFT_TABLE_F_DORMANT) &&
377 table->flags & NFT_TABLE_F_DORMANT) {
Patrick McHardy115a60b2014-01-03 12:16:15 +0000378 ret = nf_tables_table_enable(afi, table);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200379 if (ret >= 0)
380 table->flags &= ~NFT_TABLE_F_DORMANT;
381 }
382 if (ret < 0)
383 goto err;
384 }
385
386 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
387err:
388 return ret;
389}
390
Patrick McHardy96518512013-10-14 11:00:02 +0200391static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
392 const struct nlmsghdr *nlh,
393 const struct nlattr * const nla[])
394{
395 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
396 const struct nlattr *name;
397 struct nft_af_info *afi;
398 struct nft_table *table;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200399 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200400 int family = nfmsg->nfgen_family;
401
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200402 afi = nf_tables_afinfo_lookup(net, family, true);
Patrick McHardy96518512013-10-14 11:00:02 +0200403 if (IS_ERR(afi))
404 return PTR_ERR(afi);
405
406 name = nla[NFTA_TABLE_NAME];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200407 table = nf_tables_table_lookup(afi, name);
Patrick McHardy96518512013-10-14 11:00:02 +0200408 if (IS_ERR(table)) {
409 if (PTR_ERR(table) != -ENOENT)
410 return PTR_ERR(table);
411 table = NULL;
412 }
413
414 if (table != NULL) {
415 if (nlh->nlmsg_flags & NLM_F_EXCL)
416 return -EEXIST;
417 if (nlh->nlmsg_flags & NLM_F_REPLACE)
418 return -EOPNOTSUPP;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200419 return nf_tables_updtable(nlsk, skb, nlh, nla, afi, table);
Patrick McHardy96518512013-10-14 11:00:02 +0200420 }
421
422 table = kzalloc(sizeof(*table) + nla_len(name), GFP_KERNEL);
423 if (table == NULL)
424 return -ENOMEM;
425
426 nla_strlcpy(table->name, name, nla_len(name));
427 INIT_LIST_HEAD(&table->chains);
Patrick McHardy20a69342013-10-11 12:06:22 +0200428 INIT_LIST_HEAD(&table->sets);
Patrick McHardy96518512013-10-14 11:00:02 +0200429
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200430 if (nla[NFTA_TABLE_FLAGS]) {
431 __be32 flags;
432
433 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
434 if (flags & ~NFT_TABLE_F_DORMANT) {
435 kfree(table);
436 return -EINVAL;
437 }
438
439 table->flags |= flags;
440 }
441
Patrick McHardy96518512013-10-14 11:00:02 +0200442 list_add_tail(&table->list, &afi->tables);
443 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
444 return 0;
445}
446
447static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
448 const struct nlmsghdr *nlh,
449 const struct nlattr * const nla[])
450{
451 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
452 struct nft_af_info *afi;
453 struct nft_table *table;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200454 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200455 int family = nfmsg->nfgen_family;
456
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200457 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200458 if (IS_ERR(afi))
459 return PTR_ERR(afi);
460
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200461 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
Patrick McHardy96518512013-10-14 11:00:02 +0200462 if (IS_ERR(table))
463 return PTR_ERR(table);
464
Patrick McHardy96518512013-10-14 11:00:02 +0200465 if (table->use)
466 return -EBUSY;
467
468 list_del(&table->list);
469 nf_tables_table_notify(skb, nlh, table, NFT_MSG_DELTABLE, family);
470 kfree(table);
471 return 0;
472}
473
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200474int nft_register_chain_type(struct nf_chain_type *ctype)
Patrick McHardy96518512013-10-14 11:00:02 +0200475{
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200476 int err = 0;
Patrick McHardy96518512013-10-14 11:00:02 +0200477
478 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200479 if (chain_type[ctype->family][ctype->type] != NULL) {
480 err = -EBUSY;
481 goto out;
Patrick McHardy96518512013-10-14 11:00:02 +0200482 }
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200483 chain_type[ctype->family][ctype->type] = ctype;
484out:
Patrick McHardy96518512013-10-14 11:00:02 +0200485 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
486 return err;
487}
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200488EXPORT_SYMBOL_GPL(nft_register_chain_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200489
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200490void nft_unregister_chain_type(struct nf_chain_type *ctype)
Patrick McHardy96518512013-10-14 11:00:02 +0200491{
Patrick McHardy96518512013-10-14 11:00:02 +0200492 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200493 chain_type[ctype->family][ctype->type] = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +0200494 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
495}
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200496EXPORT_SYMBOL_GPL(nft_unregister_chain_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200497
498/*
499 * Chains
500 */
501
502static struct nft_chain *
503nf_tables_chain_lookup_byhandle(const struct nft_table *table, u64 handle)
504{
505 struct nft_chain *chain;
506
507 list_for_each_entry(chain, &table->chains, list) {
508 if (chain->handle == handle)
509 return chain;
510 }
511
512 return ERR_PTR(-ENOENT);
513}
514
515static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table,
516 const struct nlattr *nla)
517{
518 struct nft_chain *chain;
519
520 if (nla == NULL)
521 return ERR_PTR(-EINVAL);
522
523 list_for_each_entry(chain, &table->chains, list) {
524 if (!nla_strcmp(nla, chain->name))
525 return chain;
526 }
527
528 return ERR_PTR(-ENOENT);
529}
530
531static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
532 [NFTA_CHAIN_TABLE] = { .type = NLA_STRING },
533 [NFTA_CHAIN_HANDLE] = { .type = NLA_U64 },
534 [NFTA_CHAIN_NAME] = { .type = NLA_STRING,
535 .len = NFT_CHAIN_MAXNAMELEN - 1 },
536 [NFTA_CHAIN_HOOK] = { .type = NLA_NESTED },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200537 [NFTA_CHAIN_POLICY] = { .type = NLA_U32 },
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200538 [NFTA_CHAIN_TYPE] = { .type = NLA_NUL_STRING },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200539 [NFTA_CHAIN_COUNTERS] = { .type = NLA_NESTED },
Patrick McHardy96518512013-10-14 11:00:02 +0200540};
541
542static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = {
543 [NFTA_HOOK_HOOKNUM] = { .type = NLA_U32 },
544 [NFTA_HOOK_PRIORITY] = { .type = NLA_U32 },
545};
546
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200547static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats)
548{
549 struct nft_stats *cpu_stats, total;
550 struct nlattr *nest;
551 int cpu;
552
553 memset(&total, 0, sizeof(total));
554 for_each_possible_cpu(cpu) {
555 cpu_stats = per_cpu_ptr(stats, cpu);
556 total.pkts += cpu_stats->pkts;
557 total.bytes += cpu_stats->bytes;
558 }
559 nest = nla_nest_start(skb, NFTA_CHAIN_COUNTERS);
560 if (nest == NULL)
561 goto nla_put_failure;
562
563 if (nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(total.pkts)) ||
564 nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes)))
565 goto nla_put_failure;
566
567 nla_nest_end(skb, nest);
568 return 0;
569
570nla_put_failure:
571 return -ENOSPC;
572}
573
Patrick McHardy96518512013-10-14 11:00:02 +0200574static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq,
575 int event, u32 flags, int family,
576 const struct nft_table *table,
577 const struct nft_chain *chain)
578{
579 struct nlmsghdr *nlh;
580 struct nfgenmsg *nfmsg;
581
582 event |= NFNL_SUBSYS_NFTABLES << 8;
583 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
584 if (nlh == NULL)
585 goto nla_put_failure;
586
587 nfmsg = nlmsg_data(nlh);
588 nfmsg->nfgen_family = family;
589 nfmsg->version = NFNETLINK_V0;
590 nfmsg->res_id = 0;
591
592 if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name))
593 goto nla_put_failure;
594 if (nla_put_be64(skb, NFTA_CHAIN_HANDLE, cpu_to_be64(chain->handle)))
595 goto nla_put_failure;
596 if (nla_put_string(skb, NFTA_CHAIN_NAME, chain->name))
597 goto nla_put_failure;
598
599 if (chain->flags & NFT_BASE_CHAIN) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200600 const struct nft_base_chain *basechain = nft_base_chain(chain);
Patrick McHardy115a60b2014-01-03 12:16:15 +0000601 const struct nf_hook_ops *ops = &basechain->ops[0];
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200602 struct nlattr *nest;
603
604 nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
Patrick McHardy96518512013-10-14 11:00:02 +0200605 if (nest == NULL)
606 goto nla_put_failure;
607 if (nla_put_be32(skb, NFTA_HOOK_HOOKNUM, htonl(ops->hooknum)))
608 goto nla_put_failure;
609 if (nla_put_be32(skb, NFTA_HOOK_PRIORITY, htonl(ops->priority)))
610 goto nla_put_failure;
611 nla_nest_end(skb, nest);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200612
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200613 if (nla_put_be32(skb, NFTA_CHAIN_POLICY,
614 htonl(basechain->policy)))
615 goto nla_put_failure;
616
Patrick McHardybaae3e62014-01-09 18:42:34 +0000617 if (nla_put_string(skb, NFTA_CHAIN_TYPE, basechain->type->name))
618 goto nla_put_failure;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200619
620 if (nft_dump_stats(skb, nft_base_chain(chain)->stats))
621 goto nla_put_failure;
Patrick McHardy96518512013-10-14 11:00:02 +0200622 }
623
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200624 if (nla_put_be32(skb, NFTA_CHAIN_USE, htonl(chain->use)))
625 goto nla_put_failure;
626
Patrick McHardy96518512013-10-14 11:00:02 +0200627 return nlmsg_end(skb, nlh);
628
629nla_put_failure:
630 nlmsg_trim(skb, nlh);
631 return -1;
632}
633
634static int nf_tables_chain_notify(const struct sk_buff *oskb,
635 const struct nlmsghdr *nlh,
636 const struct nft_table *table,
637 const struct nft_chain *chain,
638 int event, int family)
639{
640 struct sk_buff *skb;
641 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
642 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
643 u32 seq = nlh ? nlh->nlmsg_seq : 0;
644 bool report;
645 int err;
646
647 report = nlh ? nlmsg_report(nlh) : false;
648 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
649 return 0;
650
651 err = -ENOBUFS;
652 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
653 if (skb == NULL)
654 goto err;
655
656 err = nf_tables_fill_chain_info(skb, portid, seq, event, 0, family,
657 table, chain);
658 if (err < 0) {
659 kfree_skb(skb);
660 goto err;
661 }
662
663 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
664 GFP_KERNEL);
665err:
666 if (err < 0)
667 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
668 return err;
669}
670
671static int nf_tables_dump_chains(struct sk_buff *skb,
672 struct netlink_callback *cb)
673{
674 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
675 const struct nft_af_info *afi;
676 const struct nft_table *table;
677 const struct nft_chain *chain;
678 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200679 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200680 int family = nfmsg->nfgen_family;
681
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200682 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +0200683 if (family != NFPROTO_UNSPEC && family != afi->family)
684 continue;
685
686 list_for_each_entry(table, &afi->tables, list) {
687 list_for_each_entry(chain, &table->chains, list) {
688 if (idx < s_idx)
689 goto cont;
690 if (idx > s_idx)
691 memset(&cb->args[1], 0,
692 sizeof(cb->args) - sizeof(cb->args[0]));
693 if (nf_tables_fill_chain_info(skb, NETLINK_CB(cb->skb).portid,
694 cb->nlh->nlmsg_seq,
695 NFT_MSG_NEWCHAIN,
696 NLM_F_MULTI,
697 afi->family, table, chain) < 0)
698 goto done;
699cont:
700 idx++;
701 }
702 }
703 }
704done:
705 cb->args[0] = idx;
706 return skb->len;
707}
708
709
710static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb,
711 const struct nlmsghdr *nlh,
712 const struct nlattr * const nla[])
713{
714 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
715 const struct nft_af_info *afi;
716 const struct nft_table *table;
717 const struct nft_chain *chain;
718 struct sk_buff *skb2;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200719 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200720 int family = nfmsg->nfgen_family;
721 int err;
722
723 if (nlh->nlmsg_flags & NLM_F_DUMP) {
724 struct netlink_dump_control c = {
725 .dump = nf_tables_dump_chains,
726 };
727 return netlink_dump_start(nlsk, skb, nlh, &c);
728 }
729
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200730 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200731 if (IS_ERR(afi))
732 return PTR_ERR(afi);
733
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200734 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +0200735 if (IS_ERR(table))
736 return PTR_ERR(table);
737
738 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
739 if (IS_ERR(chain))
740 return PTR_ERR(chain);
741
742 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
743 if (!skb2)
744 return -ENOMEM;
745
746 err = nf_tables_fill_chain_info(skb2, NETLINK_CB(skb).portid,
747 nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0,
748 family, table, chain);
749 if (err < 0)
750 goto err;
751
752 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
753
754err:
755 kfree_skb(skb2);
756 return err;
757}
758
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200759static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = {
760 [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 },
761 [NFTA_COUNTER_BYTES] = { .type = NLA_U64 },
762};
763
764static int
765nf_tables_counters(struct nft_base_chain *chain, const struct nlattr *attr)
766{
767 struct nlattr *tb[NFTA_COUNTER_MAX+1];
768 struct nft_stats __percpu *newstats;
769 struct nft_stats *stats;
770 int err;
771
772 err = nla_parse_nested(tb, NFTA_COUNTER_MAX, attr, nft_counter_policy);
773 if (err < 0)
774 return err;
775
776 if (!tb[NFTA_COUNTER_BYTES] || !tb[NFTA_COUNTER_PACKETS])
777 return -EINVAL;
778
779 newstats = alloc_percpu(struct nft_stats);
780 if (newstats == NULL)
781 return -ENOMEM;
782
783 /* Restore old counters on this cpu, no problem. Per-cpu statistics
784 * are not exposed to userspace.
785 */
786 stats = this_cpu_ptr(newstats);
787 stats->bytes = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES]));
788 stats->pkts = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS]));
789
790 if (chain->stats) {
791 /* nfnl_lock is held, add some nfnl function for this, later */
792 struct nft_stats __percpu *oldstats =
793 rcu_dereference_protected(chain->stats, 1);
794
795 rcu_assign_pointer(chain->stats, newstats);
796 synchronize_rcu();
797 free_percpu(oldstats);
798 } else
799 rcu_assign_pointer(chain->stats, newstats);
800
801 return 0;
802}
803
Patrick McHardy96518512013-10-14 11:00:02 +0200804static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
805 const struct nlmsghdr *nlh,
806 const struct nlattr * const nla[])
807{
808 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
809 const struct nlattr * uninitialized_var(name);
810 const struct nft_af_info *afi;
811 struct nft_table *table;
812 struct nft_chain *chain;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200813 struct nft_base_chain *basechain = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +0200814 struct nlattr *ha[NFTA_HOOK_MAX + 1];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200815 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200816 int family = nfmsg->nfgen_family;
Patrick McHardy57de2a02014-01-09 18:42:31 +0000817 u8 policy = NF_ACCEPT;
Patrick McHardy96518512013-10-14 11:00:02 +0200818 u64 handle = 0;
Patrick McHardy115a60b2014-01-03 12:16:15 +0000819 unsigned int i;
Patrick McHardy96518512013-10-14 11:00:02 +0200820 int err;
821 bool create;
822
823 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
824
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200825 afi = nf_tables_afinfo_lookup(net, family, true);
Patrick McHardy96518512013-10-14 11:00:02 +0200826 if (IS_ERR(afi))
827 return PTR_ERR(afi);
828
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200829 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +0200830 if (IS_ERR(table))
831 return PTR_ERR(table);
832
Patrick McHardy96518512013-10-14 11:00:02 +0200833 chain = NULL;
834 name = nla[NFTA_CHAIN_NAME];
835
836 if (nla[NFTA_CHAIN_HANDLE]) {
837 handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
838 chain = nf_tables_chain_lookup_byhandle(table, handle);
839 if (IS_ERR(chain))
840 return PTR_ERR(chain);
841 } else {
842 chain = nf_tables_chain_lookup(table, name);
843 if (IS_ERR(chain)) {
844 if (PTR_ERR(chain) != -ENOENT)
845 return PTR_ERR(chain);
846 chain = NULL;
847 }
848 }
849
Patrick McHardy57de2a02014-01-09 18:42:31 +0000850 if (nla[NFTA_CHAIN_POLICY]) {
851 if ((chain != NULL &&
852 !(chain->flags & NFT_BASE_CHAIN)) ||
853 nla[NFTA_CHAIN_HOOK] == NULL)
854 return -EOPNOTSUPP;
855
856 policy = nla_get_be32(nla[NFTA_CHAIN_POLICY]);
857 switch (policy) {
858 case NF_DROP:
859 case NF_ACCEPT:
860 break;
861 default:
862 return -EINVAL;
863 }
864 }
865
Patrick McHardy96518512013-10-14 11:00:02 +0200866 if (chain != NULL) {
867 if (nlh->nlmsg_flags & NLM_F_EXCL)
868 return -EEXIST;
869 if (nlh->nlmsg_flags & NLM_F_REPLACE)
870 return -EOPNOTSUPP;
871
872 if (nla[NFTA_CHAIN_HANDLE] && name &&
873 !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME])))
874 return -EEXIST;
875
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200876 if (nla[NFTA_CHAIN_COUNTERS]) {
877 if (!(chain->flags & NFT_BASE_CHAIN))
878 return -EOPNOTSUPP;
879
880 err = nf_tables_counters(nft_base_chain(chain),
881 nla[NFTA_CHAIN_COUNTERS]);
882 if (err < 0)
883 return err;
884 }
885
Patrick McHardy4401a862014-01-09 18:42:32 +0000886 if (nla[NFTA_CHAIN_POLICY])
887 nft_base_chain(chain)->policy = policy;
888
Patrick McHardy96518512013-10-14 11:00:02 +0200889 if (nla[NFTA_CHAIN_HANDLE] && name)
890 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
891
892 goto notify;
893 }
894
Patrick McHardy75820672014-01-09 18:42:33 +0000895 if (table->use == UINT_MAX)
896 return -EOVERFLOW;
897
Patrick McHardy96518512013-10-14 11:00:02 +0200898 if (nla[NFTA_CHAIN_HOOK]) {
Patrick McHardybaae3e62014-01-09 18:42:34 +0000899 struct nf_chain_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +0200900 struct nf_hook_ops *ops;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200901 nf_hookfn *hookfn;
Patrick McHardy115a60b2014-01-03 12:16:15 +0000902 u32 hooknum, priority;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200903
Patrick McHardybaae3e62014-01-09 18:42:34 +0000904 type = chain_type[family][NFT_CHAIN_T_DEFAULT];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200905 if (nla[NFTA_CHAIN_TYPE]) {
906 type = nf_tables_chain_type_lookup(afi,
907 nla[NFTA_CHAIN_TYPE],
908 create);
Patrick McHardybaae3e62014-01-09 18:42:34 +0000909 if (type == NULL)
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200910 return -ENOENT;
911 }
Patrick McHardy96518512013-10-14 11:00:02 +0200912
913 err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK],
914 nft_hook_policy);
915 if (err < 0)
916 return err;
917 if (ha[NFTA_HOOK_HOOKNUM] == NULL ||
918 ha[NFTA_HOOK_PRIORITY] == NULL)
919 return -EINVAL;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200920
921 hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
922 if (hooknum >= afi->nhooks)
Patrick McHardy96518512013-10-14 11:00:02 +0200923 return -EINVAL;
Patrick McHardy115a60b2014-01-03 12:16:15 +0000924 priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
Patrick McHardy96518512013-10-14 11:00:02 +0200925
Patrick McHardybaae3e62014-01-09 18:42:34 +0000926 if (!(type->hook_mask & (1 << hooknum)))
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200927 return -EOPNOTSUPP;
Patrick McHardybaae3e62014-01-09 18:42:34 +0000928 if (!try_module_get(type->me))
929 return -ENOENT;
930 hookfn = type->fn[hooknum];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200931
Patrick McHardy96518512013-10-14 11:00:02 +0200932 basechain = kzalloc(sizeof(*basechain), GFP_KERNEL);
933 if (basechain == NULL)
934 return -ENOMEM;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200935
Patrick McHardy4401a862014-01-09 18:42:32 +0000936 if (nla[NFTA_CHAIN_COUNTERS]) {
937 err = nf_tables_counters(basechain,
938 nla[NFTA_CHAIN_COUNTERS]);
939 if (err < 0) {
Patrick McHardybaae3e62014-01-09 18:42:34 +0000940 module_put(type->me);
Patrick McHardy4401a862014-01-09 18:42:32 +0000941 kfree(basechain);
942 return err;
943 }
944 } else {
945 struct nft_stats __percpu *newstats;
946
947 newstats = alloc_percpu(struct nft_stats);
948 if (newstats == NULL) {
Patrick McHardybaae3e62014-01-09 18:42:34 +0000949 module_put(type->me);
Patrick McHardy4401a862014-01-09 18:42:32 +0000950 kfree(basechain);
951 return -ENOMEM;
952 }
953 rcu_assign_pointer(basechain->stats, newstats);
954 }
955
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200956 basechain->type = type;
Patrick McHardy96518512013-10-14 11:00:02 +0200957 chain = &basechain->chain;
958
Patrick McHardy115a60b2014-01-03 12:16:15 +0000959 for (i = 0; i < afi->nops; i++) {
960 ops = &basechain->ops[i];
961 ops->pf = family;
962 ops->owner = afi->owner;
963 ops->hooknum = hooknum;
964 ops->priority = priority;
965 ops->priv = chain;
966 ops->hook = afi->hooks[ops->hooknum];
967 if (hookfn)
968 ops->hook = hookfn;
969 if (afi->hook_ops_init)
970 afi->hook_ops_init(ops, i);
971 }
Patrick McHardy96518512013-10-14 11:00:02 +0200972
973 chain->flags |= NFT_BASE_CHAIN;
Patrick McHardy57de2a02014-01-09 18:42:31 +0000974 basechain->policy = policy;
Patrick McHardy96518512013-10-14 11:00:02 +0200975 } else {
976 chain = kzalloc(sizeof(*chain), GFP_KERNEL);
977 if (chain == NULL)
978 return -ENOMEM;
979 }
980
981 INIT_LIST_HEAD(&chain->rules);
982 chain->handle = nf_tables_alloc_handle(table);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +0200983 chain->net = net;
Pablo Neira Ayusob5bc89b2013-10-10 16:49:19 +0200984 chain->table = table;
Patrick McHardy96518512013-10-14 11:00:02 +0200985 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
986
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200987 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
988 chain->flags & NFT_BASE_CHAIN) {
Patrick McHardy115a60b2014-01-03 12:16:15 +0000989 err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200990 if (err < 0) {
Patrick McHardybaae3e62014-01-09 18:42:34 +0000991 module_put(basechain->type->me);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200992 free_percpu(basechain->stats);
993 kfree(basechain);
994 return err;
995 }
996 }
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200997 list_add_tail(&chain->list, &table->chains);
998 table->use++;
Patrick McHardy96518512013-10-14 11:00:02 +0200999notify:
1000 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_NEWCHAIN,
1001 family);
1002 return 0;
1003}
1004
1005static void nf_tables_rcu_chain_destroy(struct rcu_head *head)
1006{
1007 struct nft_chain *chain = container_of(head, struct nft_chain, rcu_head);
1008
1009 BUG_ON(chain->use > 0);
1010
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001011 if (chain->flags & NFT_BASE_CHAIN) {
Patrick McHardybaae3e62014-01-09 18:42:34 +00001012 module_put(nft_base_chain(chain)->type->me);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001013 free_percpu(nft_base_chain(chain)->stats);
Patrick McHardy96518512013-10-14 11:00:02 +02001014 kfree(nft_base_chain(chain));
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001015 } else
Patrick McHardy96518512013-10-14 11:00:02 +02001016 kfree(chain);
1017}
1018
1019static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
1020 const struct nlmsghdr *nlh,
1021 const struct nlattr * const nla[])
1022{
1023 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1024 const struct nft_af_info *afi;
1025 struct nft_table *table;
1026 struct nft_chain *chain;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001027 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001028 int family = nfmsg->nfgen_family;
1029
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001030 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001031 if (IS_ERR(afi))
1032 return PTR_ERR(afi);
1033
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001034 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001035 if (IS_ERR(table))
1036 return PTR_ERR(table);
1037
1038 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
1039 if (IS_ERR(chain))
1040 return PTR_ERR(chain);
1041
Patrick McHardy96518512013-10-14 11:00:02 +02001042 if (!list_empty(&chain->rules))
1043 return -EBUSY;
1044
1045 list_del(&chain->list);
1046 table->use--;
1047
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +02001048 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
1049 chain->flags & NFT_BASE_CHAIN)
Patrick McHardy115a60b2014-01-03 12:16:15 +00001050 nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops);
Patrick McHardy96518512013-10-14 11:00:02 +02001051
1052 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN,
1053 family);
1054
1055 /* Make sure all rule references are gone before this is released */
1056 call_rcu(&chain->rcu_head, nf_tables_rcu_chain_destroy);
1057 return 0;
1058}
1059
1060static void nft_ctx_init(struct nft_ctx *ctx,
Patrick McHardy20a69342013-10-11 12:06:22 +02001061 const struct sk_buff *skb,
1062 const struct nlmsghdr *nlh,
Patrick McHardy96518512013-10-14 11:00:02 +02001063 const struct nft_af_info *afi,
1064 const struct nft_table *table,
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001065 const struct nft_chain *chain,
1066 const struct nlattr * const *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001067{
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001068 ctx->net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02001069 ctx->skb = skb;
1070 ctx->nlh = nlh;
Patrick McHardy96518512013-10-14 11:00:02 +02001071 ctx->afi = afi;
1072 ctx->table = table;
1073 ctx->chain = chain;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001074 ctx->nla = nla;
Patrick McHardy96518512013-10-14 11:00:02 +02001075}
1076
1077/*
1078 * Expressions
1079 */
1080
1081/**
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001082 * nft_register_expr - register nf_tables expr type
1083 * @ops: expr type
Patrick McHardy96518512013-10-14 11:00:02 +02001084 *
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001085 * Registers the expr type for use with nf_tables. Returns zero on
Patrick McHardy96518512013-10-14 11:00:02 +02001086 * success or a negative errno code otherwise.
1087 */
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001088int nft_register_expr(struct nft_expr_type *type)
Patrick McHardy96518512013-10-14 11:00:02 +02001089{
1090 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001091 list_add_tail(&type->list, &nf_tables_expressions);
Patrick McHardy96518512013-10-14 11:00:02 +02001092 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1093 return 0;
1094}
1095EXPORT_SYMBOL_GPL(nft_register_expr);
1096
1097/**
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001098 * nft_unregister_expr - unregister nf_tables expr type
1099 * @ops: expr type
Patrick McHardy96518512013-10-14 11:00:02 +02001100 *
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001101 * Unregisters the expr typefor use with nf_tables.
Patrick McHardy96518512013-10-14 11:00:02 +02001102 */
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001103void nft_unregister_expr(struct nft_expr_type *type)
Patrick McHardy96518512013-10-14 11:00:02 +02001104{
1105 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001106 list_del(&type->list);
Patrick McHardy96518512013-10-14 11:00:02 +02001107 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1108}
1109EXPORT_SYMBOL_GPL(nft_unregister_expr);
1110
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001111static const struct nft_expr_type *__nft_expr_type_get(struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001112{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001113 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001114
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001115 list_for_each_entry(type, &nf_tables_expressions, list) {
1116 if (!nla_strcmp(nla, type->name))
1117 return type;
Patrick McHardy96518512013-10-14 11:00:02 +02001118 }
1119 return NULL;
1120}
1121
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001122static const struct nft_expr_type *nft_expr_type_get(struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001123{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001124 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001125
1126 if (nla == NULL)
1127 return ERR_PTR(-EINVAL);
1128
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001129 type = __nft_expr_type_get(nla);
1130 if (type != NULL && try_module_get(type->owner))
1131 return type;
Patrick McHardy96518512013-10-14 11:00:02 +02001132
1133#ifdef CONFIG_MODULES
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001134 if (type == NULL) {
Patrick McHardy96518512013-10-14 11:00:02 +02001135 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1136 request_module("nft-expr-%.*s",
1137 nla_len(nla), (char *)nla_data(nla));
1138 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001139 if (__nft_expr_type_get(nla))
Patrick McHardy96518512013-10-14 11:00:02 +02001140 return ERR_PTR(-EAGAIN);
1141 }
1142#endif
1143 return ERR_PTR(-ENOENT);
1144}
1145
1146static const struct nla_policy nft_expr_policy[NFTA_EXPR_MAX + 1] = {
1147 [NFTA_EXPR_NAME] = { .type = NLA_STRING },
1148 [NFTA_EXPR_DATA] = { .type = NLA_NESTED },
1149};
1150
1151static int nf_tables_fill_expr_info(struct sk_buff *skb,
1152 const struct nft_expr *expr)
1153{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001154 if (nla_put_string(skb, NFTA_EXPR_NAME, expr->ops->type->name))
Patrick McHardy96518512013-10-14 11:00:02 +02001155 goto nla_put_failure;
1156
1157 if (expr->ops->dump) {
1158 struct nlattr *data = nla_nest_start(skb, NFTA_EXPR_DATA);
1159 if (data == NULL)
1160 goto nla_put_failure;
1161 if (expr->ops->dump(skb, expr) < 0)
1162 goto nla_put_failure;
1163 nla_nest_end(skb, data);
1164 }
1165
1166 return skb->len;
1167
1168nla_put_failure:
1169 return -1;
1170};
1171
1172struct nft_expr_info {
1173 const struct nft_expr_ops *ops;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001174 struct nlattr *tb[NFT_EXPR_MAXATTR + 1];
Patrick McHardy96518512013-10-14 11:00:02 +02001175};
1176
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001177static int nf_tables_expr_parse(const struct nft_ctx *ctx,
1178 const struct nlattr *nla,
Patrick McHardy96518512013-10-14 11:00:02 +02001179 struct nft_expr_info *info)
1180{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001181 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001182 const struct nft_expr_ops *ops;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001183 struct nlattr *tb[NFTA_EXPR_MAX + 1];
Patrick McHardy96518512013-10-14 11:00:02 +02001184 int err;
1185
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001186 err = nla_parse_nested(tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
Patrick McHardy96518512013-10-14 11:00:02 +02001187 if (err < 0)
1188 return err;
1189
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001190 type = nft_expr_type_get(tb[NFTA_EXPR_NAME]);
1191 if (IS_ERR(type))
1192 return PTR_ERR(type);
1193
1194 if (tb[NFTA_EXPR_DATA]) {
1195 err = nla_parse_nested(info->tb, type->maxattr,
1196 tb[NFTA_EXPR_DATA], type->policy);
1197 if (err < 0)
1198 goto err1;
1199 } else
1200 memset(info->tb, 0, sizeof(info->tb[0]) * (type->maxattr + 1));
1201
1202 if (type->select_ops != NULL) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001203 ops = type->select_ops(ctx,
1204 (const struct nlattr * const *)info->tb);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001205 if (IS_ERR(ops)) {
1206 err = PTR_ERR(ops);
1207 goto err1;
1208 }
1209 } else
1210 ops = type->ops;
1211
Patrick McHardy96518512013-10-14 11:00:02 +02001212 info->ops = ops;
1213 return 0;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001214
1215err1:
1216 module_put(type->owner);
1217 return err;
Patrick McHardy96518512013-10-14 11:00:02 +02001218}
1219
1220static int nf_tables_newexpr(const struct nft_ctx *ctx,
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001221 const struct nft_expr_info *info,
Patrick McHardy96518512013-10-14 11:00:02 +02001222 struct nft_expr *expr)
1223{
1224 const struct nft_expr_ops *ops = info->ops;
1225 int err;
1226
1227 expr->ops = ops;
1228 if (ops->init) {
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001229 err = ops->init(ctx, expr, (const struct nlattr **)info->tb);
Patrick McHardy96518512013-10-14 11:00:02 +02001230 if (err < 0)
1231 goto err1;
1232 }
1233
Patrick McHardy96518512013-10-14 11:00:02 +02001234 return 0;
1235
1236err1:
1237 expr->ops = NULL;
1238 return err;
1239}
1240
1241static void nf_tables_expr_destroy(struct nft_expr *expr)
1242{
1243 if (expr->ops->destroy)
1244 expr->ops->destroy(expr);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001245 module_put(expr->ops->type->owner);
Patrick McHardy96518512013-10-14 11:00:02 +02001246}
1247
1248/*
1249 * Rules
1250 */
1251
1252static struct nft_rule *__nf_tables_rule_lookup(const struct nft_chain *chain,
1253 u64 handle)
1254{
1255 struct nft_rule *rule;
1256
1257 // FIXME: this sucks
1258 list_for_each_entry(rule, &chain->rules, list) {
1259 if (handle == rule->handle)
1260 return rule;
1261 }
1262
1263 return ERR_PTR(-ENOENT);
1264}
1265
1266static struct nft_rule *nf_tables_rule_lookup(const struct nft_chain *chain,
1267 const struct nlattr *nla)
1268{
1269 if (nla == NULL)
1270 return ERR_PTR(-EINVAL);
1271
1272 return __nf_tables_rule_lookup(chain, be64_to_cpu(nla_get_be64(nla)));
1273}
1274
1275static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
1276 [NFTA_RULE_TABLE] = { .type = NLA_STRING },
1277 [NFTA_RULE_CHAIN] = { .type = NLA_STRING,
1278 .len = NFT_CHAIN_MAXNAMELEN - 1 },
1279 [NFTA_RULE_HANDLE] = { .type = NLA_U64 },
1280 [NFTA_RULE_EXPRESSIONS] = { .type = NLA_NESTED },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001281 [NFTA_RULE_COMPAT] = { .type = NLA_NESTED },
Eric Leblond5e948462013-10-10 13:41:44 +02001282 [NFTA_RULE_POSITION] = { .type = NLA_U64 },
Patrick McHardy96518512013-10-14 11:00:02 +02001283};
1284
1285static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
1286 int event, u32 flags, int family,
1287 const struct nft_table *table,
1288 const struct nft_chain *chain,
1289 const struct nft_rule *rule)
1290{
1291 struct nlmsghdr *nlh;
1292 struct nfgenmsg *nfmsg;
1293 const struct nft_expr *expr, *next;
1294 struct nlattr *list;
Eric Leblond5e948462013-10-10 13:41:44 +02001295 const struct nft_rule *prule;
1296 int type = event | NFNL_SUBSYS_NFTABLES << 8;
Patrick McHardy96518512013-10-14 11:00:02 +02001297
Eric Leblond5e948462013-10-10 13:41:44 +02001298 nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg),
Patrick McHardy96518512013-10-14 11:00:02 +02001299 flags);
1300 if (nlh == NULL)
1301 goto nla_put_failure;
1302
1303 nfmsg = nlmsg_data(nlh);
1304 nfmsg->nfgen_family = family;
1305 nfmsg->version = NFNETLINK_V0;
1306 nfmsg->res_id = 0;
1307
1308 if (nla_put_string(skb, NFTA_RULE_TABLE, table->name))
1309 goto nla_put_failure;
1310 if (nla_put_string(skb, NFTA_RULE_CHAIN, chain->name))
1311 goto nla_put_failure;
1312 if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
1313 goto nla_put_failure;
1314
Eric Leblond5e948462013-10-10 13:41:44 +02001315 if ((event != NFT_MSG_DELRULE) && (rule->list.prev != &chain->rules)) {
1316 prule = list_entry(rule->list.prev, struct nft_rule, list);
1317 if (nla_put_be64(skb, NFTA_RULE_POSITION,
1318 cpu_to_be64(prule->handle)))
1319 goto nla_put_failure;
1320 }
1321
Patrick McHardy96518512013-10-14 11:00:02 +02001322 list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
1323 if (list == NULL)
1324 goto nla_put_failure;
1325 nft_rule_for_each_expr(expr, next, rule) {
1326 struct nlattr *elem = nla_nest_start(skb, NFTA_LIST_ELEM);
1327 if (elem == NULL)
1328 goto nla_put_failure;
1329 if (nf_tables_fill_expr_info(skb, expr) < 0)
1330 goto nla_put_failure;
1331 nla_nest_end(skb, elem);
1332 }
1333 nla_nest_end(skb, list);
1334
1335 return nlmsg_end(skb, nlh);
1336
1337nla_put_failure:
1338 nlmsg_trim(skb, nlh);
1339 return -1;
1340}
1341
1342static int nf_tables_rule_notify(const struct sk_buff *oskb,
1343 const struct nlmsghdr *nlh,
1344 const struct nft_table *table,
1345 const struct nft_chain *chain,
1346 const struct nft_rule *rule,
1347 int event, u32 flags, int family)
1348{
1349 struct sk_buff *skb;
1350 u32 portid = NETLINK_CB(oskb).portid;
1351 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
1352 u32 seq = nlh->nlmsg_seq;
1353 bool report;
1354 int err;
1355
1356 report = nlmsg_report(nlh);
1357 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
1358 return 0;
1359
1360 err = -ENOBUFS;
1361 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1362 if (skb == NULL)
1363 goto err;
1364
1365 err = nf_tables_fill_rule_info(skb, portid, seq, event, flags,
1366 family, table, chain, rule);
1367 if (err < 0) {
1368 kfree_skb(skb);
1369 goto err;
1370 }
1371
1372 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
1373 GFP_KERNEL);
1374err:
1375 if (err < 0)
1376 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
1377 return err;
1378}
1379
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001380static inline bool
1381nft_rule_is_active(struct net *net, const struct nft_rule *rule)
1382{
1383 return (rule->genmask & (1 << net->nft.gencursor)) == 0;
1384}
1385
1386static inline int gencursor_next(struct net *net)
1387{
1388 return net->nft.gencursor+1 == 1 ? 1 : 0;
1389}
1390
1391static inline int
1392nft_rule_is_active_next(struct net *net, const struct nft_rule *rule)
1393{
1394 return (rule->genmask & (1 << gencursor_next(net))) == 0;
1395}
1396
1397static inline void
1398nft_rule_activate_next(struct net *net, struct nft_rule *rule)
1399{
1400 /* Now inactive, will be active in the future */
1401 rule->genmask = (1 << net->nft.gencursor);
1402}
1403
1404static inline void
1405nft_rule_disactivate_next(struct net *net, struct nft_rule *rule)
1406{
1407 rule->genmask = (1 << gencursor_next(net));
1408}
1409
1410static inline void nft_rule_clear(struct net *net, struct nft_rule *rule)
1411{
1412 rule->genmask = 0;
1413}
1414
Patrick McHardy96518512013-10-14 11:00:02 +02001415static int nf_tables_dump_rules(struct sk_buff *skb,
1416 struct netlink_callback *cb)
1417{
1418 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
1419 const struct nft_af_info *afi;
1420 const struct nft_table *table;
1421 const struct nft_chain *chain;
1422 const struct nft_rule *rule;
1423 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001424 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001425 int family = nfmsg->nfgen_family;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001426 u8 genctr = ACCESS_ONCE(net->nft.genctr);
1427 u8 gencursor = ACCESS_ONCE(net->nft.gencursor);
Patrick McHardy96518512013-10-14 11:00:02 +02001428
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001429 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +02001430 if (family != NFPROTO_UNSPEC && family != afi->family)
1431 continue;
1432
1433 list_for_each_entry(table, &afi->tables, list) {
1434 list_for_each_entry(chain, &table->chains, list) {
1435 list_for_each_entry(rule, &chain->rules, list) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001436 if (!nft_rule_is_active(net, rule))
1437 goto cont;
Patrick McHardy96518512013-10-14 11:00:02 +02001438 if (idx < s_idx)
1439 goto cont;
1440 if (idx > s_idx)
1441 memset(&cb->args[1], 0,
1442 sizeof(cb->args) - sizeof(cb->args[0]));
1443 if (nf_tables_fill_rule_info(skb, NETLINK_CB(cb->skb).portid,
1444 cb->nlh->nlmsg_seq,
1445 NFT_MSG_NEWRULE,
1446 NLM_F_MULTI | NLM_F_APPEND,
1447 afi->family, table, chain, rule) < 0)
1448 goto done;
1449cont:
1450 idx++;
1451 }
1452 }
1453 }
1454 }
1455done:
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001456 /* Invalidate this dump, a transition to the new generation happened */
1457 if (gencursor != net->nft.gencursor || genctr != net->nft.genctr)
1458 return -EBUSY;
1459
Patrick McHardy96518512013-10-14 11:00:02 +02001460 cb->args[0] = idx;
1461 return skb->len;
1462}
1463
1464static int nf_tables_getrule(struct sock *nlsk, struct sk_buff *skb,
1465 const struct nlmsghdr *nlh,
1466 const struct nlattr * const nla[])
1467{
1468 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1469 const struct nft_af_info *afi;
1470 const struct nft_table *table;
1471 const struct nft_chain *chain;
1472 const struct nft_rule *rule;
1473 struct sk_buff *skb2;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001474 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001475 int family = nfmsg->nfgen_family;
1476 int err;
1477
1478 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1479 struct netlink_dump_control c = {
1480 .dump = nf_tables_dump_rules,
1481 };
1482 return netlink_dump_start(nlsk, skb, nlh, &c);
1483 }
1484
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001485 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001486 if (IS_ERR(afi))
1487 return PTR_ERR(afi);
1488
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001489 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001490 if (IS_ERR(table))
1491 return PTR_ERR(table);
1492
1493 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1494 if (IS_ERR(chain))
1495 return PTR_ERR(chain);
1496
1497 rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
1498 if (IS_ERR(rule))
1499 return PTR_ERR(rule);
1500
1501 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1502 if (!skb2)
1503 return -ENOMEM;
1504
1505 err = nf_tables_fill_rule_info(skb2, NETLINK_CB(skb).portid,
1506 nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
1507 family, table, chain, rule);
1508 if (err < 0)
1509 goto err;
1510
1511 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
1512
1513err:
1514 kfree_skb(skb2);
1515 return err;
1516}
1517
1518static void nf_tables_rcu_rule_destroy(struct rcu_head *head)
1519{
1520 struct nft_rule *rule = container_of(head, struct nft_rule, rcu_head);
1521 struct nft_expr *expr;
1522
1523 /*
1524 * Careful: some expressions might not be initialized in case this
1525 * is called on error from nf_tables_newrule().
1526 */
1527 expr = nft_expr_first(rule);
1528 while (expr->ops && expr != nft_expr_last(rule)) {
1529 nf_tables_expr_destroy(expr);
1530 expr = nft_expr_next(expr);
1531 }
1532 kfree(rule);
1533}
1534
1535static void nf_tables_rule_destroy(struct nft_rule *rule)
1536{
1537 call_rcu(&rule->rcu_head, nf_tables_rcu_rule_destroy);
1538}
1539
1540#define NFT_RULE_MAXEXPRS 128
1541
1542static struct nft_expr_info *info;
1543
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001544static struct nft_rule_trans *
1545nf_tables_trans_add(struct nft_rule *rule, const struct nft_ctx *ctx)
1546{
1547 struct nft_rule_trans *rupd;
1548
1549 rupd = kmalloc(sizeof(struct nft_rule_trans), GFP_KERNEL);
1550 if (rupd == NULL)
1551 return NULL;
1552
1553 rupd->chain = ctx->chain;
1554 rupd->table = ctx->table;
1555 rupd->rule = rule;
1556 rupd->family = ctx->afi->family;
1557 rupd->nlh = ctx->nlh;
1558 list_add_tail(&rupd->list, &ctx->net->nft.commit_list);
1559
1560 return rupd;
1561}
1562
Patrick McHardy96518512013-10-14 11:00:02 +02001563static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
1564 const struct nlmsghdr *nlh,
1565 const struct nlattr * const nla[])
1566{
1567 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1568 const struct nft_af_info *afi;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001569 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001570 struct nft_table *table;
1571 struct nft_chain *chain;
1572 struct nft_rule *rule, *old_rule = NULL;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001573 struct nft_rule_trans *repl = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +02001574 struct nft_expr *expr;
1575 struct nft_ctx ctx;
1576 struct nlattr *tmp;
1577 unsigned int size, i, n;
1578 int err, rem;
1579 bool create;
Eric Leblond5e948462013-10-10 13:41:44 +02001580 u64 handle, pos_handle;
Patrick McHardy96518512013-10-14 11:00:02 +02001581
1582 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
1583
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001584 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
Patrick McHardy96518512013-10-14 11:00:02 +02001585 if (IS_ERR(afi))
1586 return PTR_ERR(afi);
1587
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001588 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001589 if (IS_ERR(table))
1590 return PTR_ERR(table);
1591
1592 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1593 if (IS_ERR(chain))
1594 return PTR_ERR(chain);
1595
1596 if (nla[NFTA_RULE_HANDLE]) {
1597 handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
1598 rule = __nf_tables_rule_lookup(chain, handle);
1599 if (IS_ERR(rule))
1600 return PTR_ERR(rule);
1601
1602 if (nlh->nlmsg_flags & NLM_F_EXCL)
1603 return -EEXIST;
1604 if (nlh->nlmsg_flags & NLM_F_REPLACE)
1605 old_rule = rule;
1606 else
1607 return -EOPNOTSUPP;
1608 } else {
1609 if (!create || nlh->nlmsg_flags & NLM_F_REPLACE)
1610 return -EINVAL;
1611 handle = nf_tables_alloc_handle(table);
1612 }
1613
Eric Leblond5e948462013-10-10 13:41:44 +02001614 if (nla[NFTA_RULE_POSITION]) {
1615 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
1616 return -EOPNOTSUPP;
1617
1618 pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
1619 old_rule = __nf_tables_rule_lookup(chain, pos_handle);
1620 if (IS_ERR(old_rule))
1621 return PTR_ERR(old_rule);
1622 }
1623
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001624 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1625
Patrick McHardy96518512013-10-14 11:00:02 +02001626 n = 0;
1627 size = 0;
1628 if (nla[NFTA_RULE_EXPRESSIONS]) {
1629 nla_for_each_nested(tmp, nla[NFTA_RULE_EXPRESSIONS], rem) {
1630 err = -EINVAL;
1631 if (nla_type(tmp) != NFTA_LIST_ELEM)
1632 goto err1;
1633 if (n == NFT_RULE_MAXEXPRS)
1634 goto err1;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001635 err = nf_tables_expr_parse(&ctx, tmp, &info[n]);
Patrick McHardy96518512013-10-14 11:00:02 +02001636 if (err < 0)
1637 goto err1;
1638 size += info[n].ops->size;
1639 n++;
1640 }
1641 }
1642
1643 err = -ENOMEM;
1644 rule = kzalloc(sizeof(*rule) + size, GFP_KERNEL);
1645 if (rule == NULL)
1646 goto err1;
1647
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001648 nft_rule_activate_next(net, rule);
1649
Patrick McHardy96518512013-10-14 11:00:02 +02001650 rule->handle = handle;
1651 rule->dlen = size;
1652
Patrick McHardy96518512013-10-14 11:00:02 +02001653 expr = nft_expr_first(rule);
1654 for (i = 0; i < n; i++) {
1655 err = nf_tables_newexpr(&ctx, &info[i], expr);
1656 if (err < 0)
1657 goto err2;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001658 info[i].ops = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +02001659 expr = nft_expr_next(expr);
1660 }
1661
Patrick McHardy96518512013-10-14 11:00:02 +02001662 if (nlh->nlmsg_flags & NLM_F_REPLACE) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001663 if (nft_rule_is_active_next(net, old_rule)) {
1664 repl = nf_tables_trans_add(old_rule, &ctx);
1665 if (repl == NULL) {
1666 err = -ENOMEM;
1667 goto err2;
1668 }
1669 nft_rule_disactivate_next(net, old_rule);
1670 list_add_tail(&rule->list, &old_rule->list);
1671 } else {
1672 err = -ENOENT;
1673 goto err2;
1674 }
Patrick McHardy96518512013-10-14 11:00:02 +02001675 } else if (nlh->nlmsg_flags & NLM_F_APPEND)
Eric Leblond5e948462013-10-10 13:41:44 +02001676 if (old_rule)
1677 list_add_rcu(&rule->list, &old_rule->list);
1678 else
1679 list_add_tail_rcu(&rule->list, &chain->rules);
1680 else {
1681 if (old_rule)
1682 list_add_tail_rcu(&rule->list, &old_rule->list);
1683 else
1684 list_add_rcu(&rule->list, &chain->rules);
1685 }
Patrick McHardy96518512013-10-14 11:00:02 +02001686
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001687 if (nf_tables_trans_add(rule, &ctx) == NULL) {
1688 err = -ENOMEM;
1689 goto err3;
1690 }
Patrick McHardy96518512013-10-14 11:00:02 +02001691 return 0;
1692
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001693err3:
1694 list_del_rcu(&rule->list);
1695 if (repl) {
1696 list_del_rcu(&repl->rule->list);
1697 list_del(&repl->list);
1698 nft_rule_clear(net, repl->rule);
1699 kfree(repl);
1700 }
Patrick McHardy96518512013-10-14 11:00:02 +02001701err2:
1702 nf_tables_rule_destroy(rule);
1703err1:
1704 for (i = 0; i < n; i++) {
1705 if (info[i].ops != NULL)
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001706 module_put(info[i].ops->type->owner);
Patrick McHardy96518512013-10-14 11:00:02 +02001707 }
1708 return err;
1709}
1710
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001711static int
1712nf_tables_delrule_one(struct nft_ctx *ctx, struct nft_rule *rule)
1713{
1714 /* You cannot delete the same rule twice */
1715 if (nft_rule_is_active_next(ctx->net, rule)) {
1716 if (nf_tables_trans_add(rule, ctx) == NULL)
1717 return -ENOMEM;
1718 nft_rule_disactivate_next(ctx->net, rule);
1719 return 0;
1720 }
1721 return -ENOENT;
1722}
1723
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001724static int nf_table_delrule_by_chain(struct nft_ctx *ctx)
1725{
1726 struct nft_rule *rule;
1727 int err;
1728
1729 list_for_each_entry(rule, &ctx->chain->rules, list) {
1730 err = nf_tables_delrule_one(ctx, rule);
1731 if (err < 0)
1732 return err;
1733 }
1734 return 0;
1735}
1736
Patrick McHardy96518512013-10-14 11:00:02 +02001737static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
1738 const struct nlmsghdr *nlh,
1739 const struct nlattr * const nla[])
1740{
1741 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1742 const struct nft_af_info *afi;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001743 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001744 const struct nft_table *table;
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001745 struct nft_chain *chain = NULL;
1746 struct nft_rule *rule;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001747 int family = nfmsg->nfgen_family, err = 0;
1748 struct nft_ctx ctx;
Patrick McHardy96518512013-10-14 11:00:02 +02001749
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001750 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001751 if (IS_ERR(afi))
1752 return PTR_ERR(afi);
1753
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001754 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001755 if (IS_ERR(table))
1756 return PTR_ERR(table);
1757
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001758 if (nla[NFTA_RULE_CHAIN]) {
1759 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1760 if (IS_ERR(chain))
1761 return PTR_ERR(chain);
1762 }
Patrick McHardy96518512013-10-14 11:00:02 +02001763
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001764 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1765
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001766 if (chain) {
1767 if (nla[NFTA_RULE_HANDLE]) {
1768 rule = nf_tables_rule_lookup(chain,
1769 nla[NFTA_RULE_HANDLE]);
1770 if (IS_ERR(rule))
1771 return PTR_ERR(rule);
Patrick McHardy96518512013-10-14 11:00:02 +02001772
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001773 err = nf_tables_delrule_one(&ctx, rule);
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001774 } else {
1775 err = nf_table_delrule_by_chain(&ctx);
1776 }
1777 } else {
1778 list_for_each_entry(chain, &table->chains, list) {
1779 ctx.chain = chain;
1780 err = nf_table_delrule_by_chain(&ctx);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001781 if (err < 0)
1782 break;
Patrick McHardy96518512013-10-14 11:00:02 +02001783 }
1784 }
1785
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001786 return err;
1787}
1788
1789static int nf_tables_commit(struct sk_buff *skb)
1790{
1791 struct net *net = sock_net(skb->sk);
1792 struct nft_rule_trans *rupd, *tmp;
1793
1794 /* Bump generation counter, invalidate any dump in progress */
1795 net->nft.genctr++;
1796
1797 /* A new generation has just started */
1798 net->nft.gencursor = gencursor_next(net);
1799
1800 /* Make sure all packets have left the previous generation before
1801 * purging old rules.
1802 */
1803 synchronize_rcu();
1804
1805 list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
1806 /* Delete this rule from the dirty list */
1807 list_del(&rupd->list);
1808
1809 /* This rule was inactive in the past and just became active.
1810 * Clear the next bit of the genmask since its meaning has
1811 * changed, now it is the future.
1812 */
1813 if (nft_rule_is_active(net, rupd->rule)) {
1814 nft_rule_clear(net, rupd->rule);
1815 nf_tables_rule_notify(skb, rupd->nlh, rupd->table,
1816 rupd->chain, rupd->rule,
1817 NFT_MSG_NEWRULE, 0,
1818 rupd->family);
1819 kfree(rupd);
1820 continue;
1821 }
1822
1823 /* This rule is in the past, get rid of it */
1824 list_del_rcu(&rupd->rule->list);
1825 nf_tables_rule_notify(skb, rupd->nlh, rupd->table, rupd->chain,
1826 rupd->rule, NFT_MSG_DELRULE, 0,
1827 rupd->family);
1828 nf_tables_rule_destroy(rupd->rule);
1829 kfree(rupd);
1830 }
1831
1832 return 0;
1833}
1834
1835static int nf_tables_abort(struct sk_buff *skb)
1836{
1837 struct net *net = sock_net(skb->sk);
1838 struct nft_rule_trans *rupd, *tmp;
1839
1840 list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
1841 /* Delete all rules from the dirty list */
1842 list_del(&rupd->list);
1843
1844 if (!nft_rule_is_active_next(net, rupd->rule)) {
1845 nft_rule_clear(net, rupd->rule);
1846 kfree(rupd);
1847 continue;
1848 }
1849
1850 /* This rule is inactive, get rid of it */
1851 list_del_rcu(&rupd->rule->list);
1852 nf_tables_rule_destroy(rupd->rule);
1853 kfree(rupd);
1854 }
Patrick McHardy96518512013-10-14 11:00:02 +02001855 return 0;
1856}
1857
Patrick McHardy20a69342013-10-11 12:06:22 +02001858/*
1859 * Sets
1860 */
1861
1862static LIST_HEAD(nf_tables_set_ops);
1863
1864int nft_register_set(struct nft_set_ops *ops)
1865{
1866 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1867 list_add_tail(&ops->list, &nf_tables_set_ops);
1868 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1869 return 0;
1870}
1871EXPORT_SYMBOL_GPL(nft_register_set);
1872
1873void nft_unregister_set(struct nft_set_ops *ops)
1874{
1875 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1876 list_del(&ops->list);
1877 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1878}
1879EXPORT_SYMBOL_GPL(nft_unregister_set);
1880
1881static const struct nft_set_ops *nft_select_set_ops(const struct nlattr * const nla[])
1882{
1883 const struct nft_set_ops *ops;
1884 u32 features;
1885
1886#ifdef CONFIG_MODULES
1887 if (list_empty(&nf_tables_set_ops)) {
1888 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1889 request_module("nft-set");
1890 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1891 if (!list_empty(&nf_tables_set_ops))
1892 return ERR_PTR(-EAGAIN);
1893 }
1894#endif
1895 features = 0;
1896 if (nla[NFTA_SET_FLAGS] != NULL) {
1897 features = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
1898 features &= NFT_SET_INTERVAL | NFT_SET_MAP;
1899 }
1900
1901 // FIXME: implement selection properly
1902 list_for_each_entry(ops, &nf_tables_set_ops, list) {
1903 if ((ops->features & features) != features)
1904 continue;
1905 if (!try_module_get(ops->owner))
1906 continue;
1907 return ops;
1908 }
1909
1910 return ERR_PTR(-EOPNOTSUPP);
1911}
1912
1913static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
1914 [NFTA_SET_TABLE] = { .type = NLA_STRING },
1915 [NFTA_SET_NAME] = { .type = NLA_STRING },
1916 [NFTA_SET_FLAGS] = { .type = NLA_U32 },
1917 [NFTA_SET_KEY_TYPE] = { .type = NLA_U32 },
1918 [NFTA_SET_KEY_LEN] = { .type = NLA_U32 },
1919 [NFTA_SET_DATA_TYPE] = { .type = NLA_U32 },
1920 [NFTA_SET_DATA_LEN] = { .type = NLA_U32 },
1921};
1922
1923static int nft_ctx_init_from_setattr(struct nft_ctx *ctx,
1924 const struct sk_buff *skb,
1925 const struct nlmsghdr *nlh,
1926 const struct nlattr * const nla[])
1927{
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001928 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02001929 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01001930 const struct nft_af_info *afi = NULL;
Patrick McHardy20a69342013-10-11 12:06:22 +02001931 const struct nft_table *table = NULL;
1932
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01001933 if (nfmsg->nfgen_family != NFPROTO_UNSPEC) {
1934 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
1935 if (IS_ERR(afi))
1936 return PTR_ERR(afi);
1937 }
Patrick McHardy20a69342013-10-11 12:06:22 +02001938
1939 if (nla[NFTA_SET_TABLE] != NULL) {
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001940 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02001941 if (IS_ERR(table))
1942 return PTR_ERR(table);
1943 }
1944
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001945 nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02001946 return 0;
1947}
1948
1949struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
1950 const struct nlattr *nla)
1951{
1952 struct nft_set *set;
1953
1954 if (nla == NULL)
1955 return ERR_PTR(-EINVAL);
1956
1957 list_for_each_entry(set, &table->sets, list) {
1958 if (!nla_strcmp(nla, set->name))
1959 return set;
1960 }
1961 return ERR_PTR(-ENOENT);
1962}
1963
1964static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
1965 const char *name)
1966{
1967 const struct nft_set *i;
1968 const char *p;
1969 unsigned long *inuse;
1970 unsigned int n = 0;
1971
1972 p = strnchr(name, IFNAMSIZ, '%');
1973 if (p != NULL) {
1974 if (p[1] != 'd' || strchr(p + 2, '%'))
1975 return -EINVAL;
1976
1977 inuse = (unsigned long *)get_zeroed_page(GFP_KERNEL);
1978 if (inuse == NULL)
1979 return -ENOMEM;
1980
1981 list_for_each_entry(i, &ctx->table->sets, list) {
Daniel Borkmann14662912013-12-31 12:40:05 +01001982 int tmp;
1983
1984 if (!sscanf(i->name, name, &tmp))
Patrick McHardy20a69342013-10-11 12:06:22 +02001985 continue;
Daniel Borkmann14662912013-12-31 12:40:05 +01001986 if (tmp < 0 || tmp > BITS_PER_LONG * PAGE_SIZE)
Patrick McHardy20a69342013-10-11 12:06:22 +02001987 continue;
Daniel Borkmann14662912013-12-31 12:40:05 +01001988
1989 set_bit(tmp, inuse);
Patrick McHardy20a69342013-10-11 12:06:22 +02001990 }
1991
1992 n = find_first_zero_bit(inuse, BITS_PER_LONG * PAGE_SIZE);
1993 free_page((unsigned long)inuse);
1994 }
1995
1996 snprintf(set->name, sizeof(set->name), name, n);
1997 list_for_each_entry(i, &ctx->table->sets, list) {
1998 if (!strcmp(set->name, i->name))
1999 return -ENFILE;
2000 }
2001 return 0;
2002}
2003
2004static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
2005 const struct nft_set *set, u16 event, u16 flags)
2006{
2007 struct nfgenmsg *nfmsg;
2008 struct nlmsghdr *nlh;
2009 u32 portid = NETLINK_CB(ctx->skb).portid;
2010 u32 seq = ctx->nlh->nlmsg_seq;
2011
2012 event |= NFNL_SUBSYS_NFTABLES << 8;
2013 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
2014 flags);
2015 if (nlh == NULL)
2016 goto nla_put_failure;
2017
2018 nfmsg = nlmsg_data(nlh);
2019 nfmsg->nfgen_family = ctx->afi->family;
2020 nfmsg->version = NFNETLINK_V0;
2021 nfmsg->res_id = 0;
2022
2023 if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
2024 goto nla_put_failure;
2025 if (nla_put_string(skb, NFTA_SET_NAME, set->name))
2026 goto nla_put_failure;
2027 if (set->flags != 0)
2028 if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
2029 goto nla_put_failure;
2030
2031 if (nla_put_be32(skb, NFTA_SET_KEY_TYPE, htonl(set->ktype)))
2032 goto nla_put_failure;
2033 if (nla_put_be32(skb, NFTA_SET_KEY_LEN, htonl(set->klen)))
2034 goto nla_put_failure;
2035 if (set->flags & NFT_SET_MAP) {
2036 if (nla_put_be32(skb, NFTA_SET_DATA_TYPE, htonl(set->dtype)))
2037 goto nla_put_failure;
2038 if (nla_put_be32(skb, NFTA_SET_DATA_LEN, htonl(set->dlen)))
2039 goto nla_put_failure;
2040 }
2041
2042 return nlmsg_end(skb, nlh);
2043
2044nla_put_failure:
2045 nlmsg_trim(skb, nlh);
2046 return -1;
2047}
2048
2049static int nf_tables_set_notify(const struct nft_ctx *ctx,
2050 const struct nft_set *set,
2051 int event)
2052{
2053 struct sk_buff *skb;
2054 u32 portid = NETLINK_CB(ctx->skb).portid;
Patrick McHardy20a69342013-10-11 12:06:22 +02002055 bool report;
2056 int err;
2057
2058 report = nlmsg_report(ctx->nlh);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002059 if (!report && !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
Patrick McHardy20a69342013-10-11 12:06:22 +02002060 return 0;
2061
2062 err = -ENOBUFS;
2063 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
2064 if (skb == NULL)
2065 goto err;
2066
2067 err = nf_tables_fill_set(skb, ctx, set, event, 0);
2068 if (err < 0) {
2069 kfree_skb(skb);
2070 goto err;
2071 }
2072
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002073 err = nfnetlink_send(skb, ctx->net, portid, NFNLGRP_NFTABLES, report,
Patrick McHardy20a69342013-10-11 12:06:22 +02002074 GFP_KERNEL);
2075err:
2076 if (err < 0)
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002077 nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, err);
Patrick McHardy20a69342013-10-11 12:06:22 +02002078 return err;
2079}
2080
2081static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb,
2082 struct netlink_callback *cb)
2083{
2084 const struct nft_set *set;
2085 unsigned int idx = 0, s_idx = cb->args[0];
2086
2087 if (cb->args[1])
2088 return skb->len;
2089
2090 list_for_each_entry(set, &ctx->table->sets, list) {
2091 if (idx < s_idx)
2092 goto cont;
2093 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
2094 NLM_F_MULTI) < 0) {
2095 cb->args[0] = idx;
2096 goto done;
2097 }
2098cont:
2099 idx++;
2100 }
2101 cb->args[1] = 1;
2102done:
2103 return skb->len;
2104}
2105
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002106static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb,
2107 struct netlink_callback *cb)
Patrick McHardy20a69342013-10-11 12:06:22 +02002108{
2109 const struct nft_set *set;
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002110 unsigned int idx, s_idx = cb->args[0];
Patrick McHardy20a69342013-10-11 12:06:22 +02002111 struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
2112
2113 if (cb->args[1])
2114 return skb->len;
2115
2116 list_for_each_entry(table, &ctx->afi->tables, list) {
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002117 if (cur_table) {
2118 if (cur_table != table)
2119 continue;
Patrick McHardy20a69342013-10-11 12:06:22 +02002120
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002121 cur_table = NULL;
2122 }
Patrick McHardy20a69342013-10-11 12:06:22 +02002123 ctx->table = table;
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002124 idx = 0;
Patrick McHardy20a69342013-10-11 12:06:22 +02002125 list_for_each_entry(set, &ctx->table->sets, list) {
2126 if (idx < s_idx)
2127 goto cont;
2128 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
2129 NLM_F_MULTI) < 0) {
2130 cb->args[0] = idx;
2131 cb->args[2] = (unsigned long) table;
2132 goto done;
2133 }
2134cont:
2135 idx++;
2136 }
2137 }
2138 cb->args[1] = 1;
2139done:
2140 return skb->len;
2141}
2142
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002143static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb,
2144 struct netlink_callback *cb)
2145{
2146 const struct nft_set *set;
2147 unsigned int idx, s_idx = cb->args[0];
2148 const struct nft_af_info *afi;
2149 struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
2150 struct net *net = sock_net(skb->sk);
2151 int cur_family = cb->args[3];
2152
2153 if (cb->args[1])
2154 return skb->len;
2155
2156 list_for_each_entry(afi, &net->nft.af_info, list) {
2157 if (cur_family) {
2158 if (afi->family != cur_family)
2159 continue;
2160
2161 cur_family = 0;
2162 }
2163
2164 list_for_each_entry(table, &afi->tables, list) {
2165 if (cur_table) {
2166 if (cur_table != table)
2167 continue;
2168
2169 cur_table = NULL;
2170 }
2171
2172 ctx->table = table;
2173 ctx->afi = afi;
2174 idx = 0;
2175 list_for_each_entry(set, &ctx->table->sets, list) {
2176 if (idx < s_idx)
2177 goto cont;
2178 if (nf_tables_fill_set(skb, ctx, set,
2179 NFT_MSG_NEWSET,
2180 NLM_F_MULTI) < 0) {
2181 cb->args[0] = idx;
2182 cb->args[2] = (unsigned long) table;
2183 cb->args[3] = afi->family;
2184 goto done;
2185 }
2186cont:
2187 idx++;
2188 }
2189 if (s_idx)
2190 s_idx = 0;
2191 }
2192 }
2193 cb->args[1] = 1;
2194done:
2195 return skb->len;
2196}
2197
Patrick McHardy20a69342013-10-11 12:06:22 +02002198static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
2199{
2200 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
2201 struct nlattr *nla[NFTA_SET_MAX + 1];
2202 struct nft_ctx ctx;
2203 int err, ret;
2204
2205 err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_MAX,
2206 nft_set_policy);
2207 if (err < 0)
2208 return err;
2209
2210 err = nft_ctx_init_from_setattr(&ctx, cb->skb, cb->nlh, (void *)nla);
2211 if (err < 0)
2212 return err;
2213
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002214 if (ctx.table == NULL) {
2215 if (ctx.afi == NULL)
2216 ret = nf_tables_dump_sets_all(&ctx, skb, cb);
2217 else
2218 ret = nf_tables_dump_sets_family(&ctx, skb, cb);
2219 } else
Patrick McHardy20a69342013-10-11 12:06:22 +02002220 ret = nf_tables_dump_sets_table(&ctx, skb, cb);
2221
2222 return ret;
2223}
2224
2225static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
2226 const struct nlmsghdr *nlh,
2227 const struct nlattr * const nla[])
2228{
2229 const struct nft_set *set;
2230 struct nft_ctx ctx;
2231 struct sk_buff *skb2;
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002232 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Patrick McHardy20a69342013-10-11 12:06:22 +02002233 int err;
2234
2235 /* Verify existance before starting dump */
2236 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
2237 if (err < 0)
2238 return err;
2239
2240 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2241 struct netlink_dump_control c = {
2242 .dump = nf_tables_dump_sets,
2243 };
2244 return netlink_dump_start(nlsk, skb, nlh, &c);
2245 }
2246
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002247 /* Only accept unspec with dump */
2248 if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
2249 return -EAFNOSUPPORT;
2250
Patrick McHardy20a69342013-10-11 12:06:22 +02002251 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
2252 if (IS_ERR(set))
2253 return PTR_ERR(set);
2254
2255 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2256 if (skb2 == NULL)
2257 return -ENOMEM;
2258
2259 err = nf_tables_fill_set(skb2, &ctx, set, NFT_MSG_NEWSET, 0);
2260 if (err < 0)
2261 goto err;
2262
2263 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
2264
2265err:
2266 kfree_skb(skb2);
2267 return err;
2268}
2269
2270static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
2271 const struct nlmsghdr *nlh,
2272 const struct nlattr * const nla[])
2273{
2274 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
2275 const struct nft_set_ops *ops;
2276 const struct nft_af_info *afi;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002277 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02002278 struct nft_table *table;
2279 struct nft_set *set;
2280 struct nft_ctx ctx;
2281 char name[IFNAMSIZ];
2282 unsigned int size;
2283 bool create;
2284 u32 ktype, klen, dlen, dtype, flags;
2285 int err;
2286
2287 if (nla[NFTA_SET_TABLE] == NULL ||
2288 nla[NFTA_SET_NAME] == NULL ||
2289 nla[NFTA_SET_KEY_LEN] == NULL)
2290 return -EINVAL;
2291
2292 ktype = NFT_DATA_VALUE;
2293 if (nla[NFTA_SET_KEY_TYPE] != NULL) {
2294 ktype = ntohl(nla_get_be32(nla[NFTA_SET_KEY_TYPE]));
2295 if ((ktype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK)
2296 return -EINVAL;
2297 }
2298
2299 klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
2300 if (klen == 0 || klen > FIELD_SIZEOF(struct nft_data, data))
2301 return -EINVAL;
2302
2303 flags = 0;
2304 if (nla[NFTA_SET_FLAGS] != NULL) {
2305 flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
2306 if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
2307 NFT_SET_INTERVAL | NFT_SET_MAP))
2308 return -EINVAL;
2309 }
2310
2311 dtype = 0;
2312 dlen = 0;
2313 if (nla[NFTA_SET_DATA_TYPE] != NULL) {
2314 if (!(flags & NFT_SET_MAP))
2315 return -EINVAL;
2316
2317 dtype = ntohl(nla_get_be32(nla[NFTA_SET_DATA_TYPE]));
2318 if ((dtype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK &&
2319 dtype != NFT_DATA_VERDICT)
2320 return -EINVAL;
2321
2322 if (dtype != NFT_DATA_VERDICT) {
2323 if (nla[NFTA_SET_DATA_LEN] == NULL)
2324 return -EINVAL;
2325 dlen = ntohl(nla_get_be32(nla[NFTA_SET_DATA_LEN]));
2326 if (dlen == 0 ||
2327 dlen > FIELD_SIZEOF(struct nft_data, data))
2328 return -EINVAL;
2329 } else
2330 dlen = sizeof(struct nft_data);
2331 } else if (flags & NFT_SET_MAP)
2332 return -EINVAL;
2333
2334 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
2335
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002336 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
Patrick McHardy20a69342013-10-11 12:06:22 +02002337 if (IS_ERR(afi))
2338 return PTR_ERR(afi);
2339
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002340 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02002341 if (IS_ERR(table))
2342 return PTR_ERR(table);
2343
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002344 nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002345
2346 set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME]);
2347 if (IS_ERR(set)) {
2348 if (PTR_ERR(set) != -ENOENT)
2349 return PTR_ERR(set);
2350 set = NULL;
2351 }
2352
2353 if (set != NULL) {
2354 if (nlh->nlmsg_flags & NLM_F_EXCL)
2355 return -EEXIST;
2356 if (nlh->nlmsg_flags & NLM_F_REPLACE)
2357 return -EOPNOTSUPP;
2358 return 0;
2359 }
2360
2361 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
2362 return -ENOENT;
2363
2364 ops = nft_select_set_ops(nla);
2365 if (IS_ERR(ops))
2366 return PTR_ERR(ops);
2367
2368 size = 0;
2369 if (ops->privsize != NULL)
2370 size = ops->privsize(nla);
2371
2372 err = -ENOMEM;
2373 set = kzalloc(sizeof(*set) + size, GFP_KERNEL);
2374 if (set == NULL)
2375 goto err1;
2376
2377 nla_strlcpy(name, nla[NFTA_SET_NAME], sizeof(set->name));
2378 err = nf_tables_set_alloc_name(&ctx, set, name);
2379 if (err < 0)
2380 goto err2;
2381
2382 INIT_LIST_HEAD(&set->bindings);
2383 set->ops = ops;
2384 set->ktype = ktype;
2385 set->klen = klen;
2386 set->dtype = dtype;
2387 set->dlen = dlen;
2388 set->flags = flags;
2389
2390 err = ops->init(set, nla);
2391 if (err < 0)
2392 goto err2;
2393
2394 list_add_tail(&set->list, &table->sets);
2395 nf_tables_set_notify(&ctx, set, NFT_MSG_NEWSET);
2396 return 0;
2397
2398err2:
2399 kfree(set);
2400err1:
2401 module_put(ops->owner);
2402 return err;
2403}
2404
2405static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
2406{
2407 list_del(&set->list);
2408 if (!(set->flags & NFT_SET_ANONYMOUS))
2409 nf_tables_set_notify(ctx, set, NFT_MSG_DELSET);
2410
2411 set->ops->destroy(set);
2412 module_put(set->ops->owner);
2413 kfree(set);
2414}
2415
2416static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
2417 const struct nlmsghdr *nlh,
2418 const struct nlattr * const nla[])
2419{
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002420 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Patrick McHardy20a69342013-10-11 12:06:22 +02002421 struct nft_set *set;
2422 struct nft_ctx ctx;
2423 int err;
2424
2425 if (nla[NFTA_SET_TABLE] == NULL)
2426 return -EINVAL;
2427
2428 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
2429 if (err < 0)
2430 return err;
2431
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002432 if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
2433 return -EAFNOSUPPORT;
2434
Patrick McHardy20a69342013-10-11 12:06:22 +02002435 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
2436 if (IS_ERR(set))
2437 return PTR_ERR(set);
2438 if (!list_empty(&set->bindings))
2439 return -EBUSY;
2440
2441 nf_tables_set_destroy(&ctx, set);
2442 return 0;
2443}
2444
2445static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
2446 const struct nft_set *set,
2447 const struct nft_set_iter *iter,
2448 const struct nft_set_elem *elem)
2449{
2450 enum nft_registers dreg;
2451
2452 dreg = nft_type_to_reg(set->dtype);
Pablo Neira Ayuso2ee0d3c2013-12-28 00:59:38 +01002453 return nft_validate_data_load(ctx, dreg, &elem->data,
2454 set->dtype == NFT_DATA_VERDICT ?
2455 NFT_DATA_VERDICT : NFT_DATA_VALUE);
Patrick McHardy20a69342013-10-11 12:06:22 +02002456}
2457
2458int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
2459 struct nft_set_binding *binding)
2460{
2461 struct nft_set_binding *i;
2462 struct nft_set_iter iter;
2463
2464 if (!list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
2465 return -EBUSY;
2466
2467 if (set->flags & NFT_SET_MAP) {
2468 /* If the set is already bound to the same chain all
2469 * jumps are already validated for that chain.
2470 */
2471 list_for_each_entry(i, &set->bindings, list) {
2472 if (i->chain == binding->chain)
2473 goto bind;
2474 }
2475
2476 iter.skip = 0;
2477 iter.count = 0;
2478 iter.err = 0;
2479 iter.fn = nf_tables_bind_check_setelem;
2480
2481 set->ops->walk(ctx, set, &iter);
2482 if (iter.err < 0) {
2483 /* Destroy anonymous sets if binding fails */
2484 if (set->flags & NFT_SET_ANONYMOUS)
2485 nf_tables_set_destroy(ctx, set);
2486
2487 return iter.err;
2488 }
2489 }
2490bind:
2491 binding->chain = ctx->chain;
2492 list_add_tail(&binding->list, &set->bindings);
2493 return 0;
2494}
2495
2496void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
2497 struct nft_set_binding *binding)
2498{
2499 list_del(&binding->list);
2500
2501 if (list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
2502 nf_tables_set_destroy(ctx, set);
2503}
2504
2505/*
2506 * Set elements
2507 */
2508
2509static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
2510 [NFTA_SET_ELEM_KEY] = { .type = NLA_NESTED },
2511 [NFTA_SET_ELEM_DATA] = { .type = NLA_NESTED },
2512 [NFTA_SET_ELEM_FLAGS] = { .type = NLA_U32 },
2513};
2514
2515static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
2516 [NFTA_SET_ELEM_LIST_TABLE] = { .type = NLA_STRING },
2517 [NFTA_SET_ELEM_LIST_SET] = { .type = NLA_STRING },
2518 [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NLA_NESTED },
2519};
2520
2521static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx,
2522 const struct sk_buff *skb,
2523 const struct nlmsghdr *nlh,
2524 const struct nlattr * const nla[])
2525{
2526 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
2527 const struct nft_af_info *afi;
2528 const struct nft_table *table;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002529 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02002530
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002531 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
Patrick McHardy20a69342013-10-11 12:06:22 +02002532 if (IS_ERR(afi))
2533 return PTR_ERR(afi);
2534
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002535 table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02002536 if (IS_ERR(table))
2537 return PTR_ERR(table);
2538
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002539 nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002540 return 0;
2541}
2542
2543static int nf_tables_fill_setelem(struct sk_buff *skb,
2544 const struct nft_set *set,
2545 const struct nft_set_elem *elem)
2546{
2547 unsigned char *b = skb_tail_pointer(skb);
2548 struct nlattr *nest;
2549
2550 nest = nla_nest_start(skb, NFTA_LIST_ELEM);
2551 if (nest == NULL)
2552 goto nla_put_failure;
2553
2554 if (nft_data_dump(skb, NFTA_SET_ELEM_KEY, &elem->key, NFT_DATA_VALUE,
2555 set->klen) < 0)
2556 goto nla_put_failure;
2557
2558 if (set->flags & NFT_SET_MAP &&
2559 !(elem->flags & NFT_SET_ELEM_INTERVAL_END) &&
2560 nft_data_dump(skb, NFTA_SET_ELEM_DATA, &elem->data,
2561 set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE,
2562 set->dlen) < 0)
2563 goto nla_put_failure;
2564
2565 if (elem->flags != 0)
2566 if (nla_put_be32(skb, NFTA_SET_ELEM_FLAGS, htonl(elem->flags)))
2567 goto nla_put_failure;
2568
2569 nla_nest_end(skb, nest);
2570 return 0;
2571
2572nla_put_failure:
2573 nlmsg_trim(skb, b);
2574 return -EMSGSIZE;
2575}
2576
2577struct nft_set_dump_args {
2578 const struct netlink_callback *cb;
2579 struct nft_set_iter iter;
2580 struct sk_buff *skb;
2581};
2582
2583static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
2584 const struct nft_set *set,
2585 const struct nft_set_iter *iter,
2586 const struct nft_set_elem *elem)
2587{
2588 struct nft_set_dump_args *args;
2589
2590 args = container_of(iter, struct nft_set_dump_args, iter);
2591 return nf_tables_fill_setelem(args->skb, set, elem);
2592}
2593
2594static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
2595{
2596 const struct nft_set *set;
2597 struct nft_set_dump_args args;
2598 struct nft_ctx ctx;
2599 struct nlattr *nla[NFTA_SET_ELEM_LIST_MAX + 1];
2600 struct nfgenmsg *nfmsg;
2601 struct nlmsghdr *nlh;
2602 struct nlattr *nest;
2603 u32 portid, seq;
2604 int event, err;
2605
Michal Nazarewicz720e0df2014-01-01 06:27:19 +01002606 err = nlmsg_parse(cb->nlh, sizeof(struct nfgenmsg), nla,
2607 NFTA_SET_ELEM_LIST_MAX, nft_set_elem_list_policy);
Patrick McHardy20a69342013-10-11 12:06:22 +02002608 if (err < 0)
2609 return err;
2610
2611 err = nft_ctx_init_from_elemattr(&ctx, cb->skb, cb->nlh, (void *)nla);
2612 if (err < 0)
2613 return err;
2614
2615 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2616 if (IS_ERR(set))
2617 return PTR_ERR(set);
2618
2619 event = NFT_MSG_NEWSETELEM;
2620 event |= NFNL_SUBSYS_NFTABLES << 8;
2621 portid = NETLINK_CB(cb->skb).portid;
2622 seq = cb->nlh->nlmsg_seq;
2623
2624 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
2625 NLM_F_MULTI);
2626 if (nlh == NULL)
2627 goto nla_put_failure;
2628
2629 nfmsg = nlmsg_data(nlh);
2630 nfmsg->nfgen_family = NFPROTO_UNSPEC;
2631 nfmsg->version = NFNETLINK_V0;
2632 nfmsg->res_id = 0;
2633
2634 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, ctx.table->name))
2635 goto nla_put_failure;
2636 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_SET, set->name))
2637 goto nla_put_failure;
2638
2639 nest = nla_nest_start(skb, NFTA_SET_ELEM_LIST_ELEMENTS);
2640 if (nest == NULL)
2641 goto nla_put_failure;
2642
2643 args.cb = cb;
2644 args.skb = skb;
2645 args.iter.skip = cb->args[0];
2646 args.iter.count = 0;
2647 args.iter.err = 0;
2648 args.iter.fn = nf_tables_dump_setelem;
2649 set->ops->walk(&ctx, set, &args.iter);
2650
2651 nla_nest_end(skb, nest);
2652 nlmsg_end(skb, nlh);
2653
2654 if (args.iter.err && args.iter.err != -EMSGSIZE)
2655 return args.iter.err;
2656 if (args.iter.count == cb->args[0])
2657 return 0;
2658
2659 cb->args[0] = args.iter.count;
2660 return skb->len;
2661
2662nla_put_failure:
2663 return -ENOSPC;
2664}
2665
2666static int nf_tables_getsetelem(struct sock *nlsk, struct sk_buff *skb,
2667 const struct nlmsghdr *nlh,
2668 const struct nlattr * const nla[])
2669{
2670 const struct nft_set *set;
2671 struct nft_ctx ctx;
2672 int err;
2673
2674 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2675 if (err < 0)
2676 return err;
2677
2678 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2679 if (IS_ERR(set))
2680 return PTR_ERR(set);
2681
2682 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2683 struct netlink_dump_control c = {
2684 .dump = nf_tables_dump_set,
2685 };
2686 return netlink_dump_start(nlsk, skb, nlh, &c);
2687 }
2688 return -EOPNOTSUPP;
2689}
2690
2691static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set,
2692 const struct nlattr *attr)
2693{
2694 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
2695 struct nft_data_desc d1, d2;
2696 struct nft_set_elem elem;
2697 struct nft_set_binding *binding;
2698 enum nft_registers dreg;
2699 int err;
2700
2701 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
2702 nft_set_elem_policy);
2703 if (err < 0)
2704 return err;
2705
2706 if (nla[NFTA_SET_ELEM_KEY] == NULL)
2707 return -EINVAL;
2708
2709 elem.flags = 0;
2710 if (nla[NFTA_SET_ELEM_FLAGS] != NULL) {
2711 elem.flags = ntohl(nla_get_be32(nla[NFTA_SET_ELEM_FLAGS]));
2712 if (elem.flags & ~NFT_SET_ELEM_INTERVAL_END)
2713 return -EINVAL;
2714 }
2715
2716 if (set->flags & NFT_SET_MAP) {
2717 if (nla[NFTA_SET_ELEM_DATA] == NULL &&
2718 !(elem.flags & NFT_SET_ELEM_INTERVAL_END))
2719 return -EINVAL;
2720 } else {
2721 if (nla[NFTA_SET_ELEM_DATA] != NULL)
2722 return -EINVAL;
2723 }
2724
2725 err = nft_data_init(ctx, &elem.key, &d1, nla[NFTA_SET_ELEM_KEY]);
2726 if (err < 0)
2727 goto err1;
2728 err = -EINVAL;
2729 if (d1.type != NFT_DATA_VALUE || d1.len != set->klen)
2730 goto err2;
2731
2732 err = -EEXIST;
2733 if (set->ops->get(set, &elem) == 0)
2734 goto err2;
2735
2736 if (nla[NFTA_SET_ELEM_DATA] != NULL) {
2737 err = nft_data_init(ctx, &elem.data, &d2, nla[NFTA_SET_ELEM_DATA]);
2738 if (err < 0)
2739 goto err2;
2740
2741 err = -EINVAL;
2742 if (set->dtype != NFT_DATA_VERDICT && d2.len != set->dlen)
2743 goto err3;
2744
2745 dreg = nft_type_to_reg(set->dtype);
2746 list_for_each_entry(binding, &set->bindings, list) {
2747 struct nft_ctx bind_ctx = {
2748 .afi = ctx->afi,
2749 .table = ctx->table,
2750 .chain = binding->chain,
2751 };
2752
2753 err = nft_validate_data_load(&bind_ctx, dreg,
2754 &elem.data, d2.type);
2755 if (err < 0)
2756 goto err3;
2757 }
2758 }
2759
2760 err = set->ops->insert(set, &elem);
2761 if (err < 0)
2762 goto err3;
2763
2764 return 0;
2765
2766err3:
2767 if (nla[NFTA_SET_ELEM_DATA] != NULL)
2768 nft_data_uninit(&elem.data, d2.type);
2769err2:
2770 nft_data_uninit(&elem.key, d1.type);
2771err1:
2772 return err;
2773}
2774
2775static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
2776 const struct nlmsghdr *nlh,
2777 const struct nlattr * const nla[])
2778{
2779 const struct nlattr *attr;
2780 struct nft_set *set;
2781 struct nft_ctx ctx;
2782 int rem, err;
2783
2784 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2785 if (err < 0)
2786 return err;
2787
2788 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2789 if (IS_ERR(set))
2790 return PTR_ERR(set);
2791 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
2792 return -EBUSY;
2793
2794 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
2795 err = nft_add_set_elem(&ctx, set, attr);
2796 if (err < 0)
2797 return err;
2798 }
2799 return 0;
2800}
2801
2802static int nft_del_setelem(const struct nft_ctx *ctx, struct nft_set *set,
2803 const struct nlattr *attr)
2804{
2805 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
2806 struct nft_data_desc desc;
2807 struct nft_set_elem elem;
2808 int err;
2809
2810 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
2811 nft_set_elem_policy);
2812 if (err < 0)
2813 goto err1;
2814
2815 err = -EINVAL;
2816 if (nla[NFTA_SET_ELEM_KEY] == NULL)
2817 goto err1;
2818
2819 err = nft_data_init(ctx, &elem.key, &desc, nla[NFTA_SET_ELEM_KEY]);
2820 if (err < 0)
2821 goto err1;
2822
2823 err = -EINVAL;
2824 if (desc.type != NFT_DATA_VALUE || desc.len != set->klen)
2825 goto err2;
2826
2827 err = set->ops->get(set, &elem);
2828 if (err < 0)
2829 goto err2;
2830
2831 set->ops->remove(set, &elem);
2832
2833 nft_data_uninit(&elem.key, NFT_DATA_VALUE);
2834 if (set->flags & NFT_SET_MAP)
2835 nft_data_uninit(&elem.data, set->dtype);
2836
2837err2:
2838 nft_data_uninit(&elem.key, desc.type);
2839err1:
2840 return err;
2841}
2842
2843static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
2844 const struct nlmsghdr *nlh,
2845 const struct nlattr * const nla[])
2846{
2847 const struct nlattr *attr;
2848 struct nft_set *set;
2849 struct nft_ctx ctx;
2850 int rem, err;
2851
2852 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2853 if (err < 0)
2854 return err;
2855
2856 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2857 if (IS_ERR(set))
2858 return PTR_ERR(set);
2859 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
2860 return -EBUSY;
2861
2862 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
2863 err = nft_del_setelem(&ctx, set, attr);
2864 if (err < 0)
2865 return err;
2866 }
2867 return 0;
2868}
2869
Patrick McHardy96518512013-10-14 11:00:02 +02002870static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
2871 [NFT_MSG_NEWTABLE] = {
2872 .call = nf_tables_newtable,
2873 .attr_count = NFTA_TABLE_MAX,
2874 .policy = nft_table_policy,
2875 },
2876 [NFT_MSG_GETTABLE] = {
2877 .call = nf_tables_gettable,
2878 .attr_count = NFTA_TABLE_MAX,
2879 .policy = nft_table_policy,
2880 },
2881 [NFT_MSG_DELTABLE] = {
2882 .call = nf_tables_deltable,
2883 .attr_count = NFTA_TABLE_MAX,
2884 .policy = nft_table_policy,
2885 },
2886 [NFT_MSG_NEWCHAIN] = {
2887 .call = nf_tables_newchain,
2888 .attr_count = NFTA_CHAIN_MAX,
2889 .policy = nft_chain_policy,
2890 },
2891 [NFT_MSG_GETCHAIN] = {
2892 .call = nf_tables_getchain,
2893 .attr_count = NFTA_CHAIN_MAX,
2894 .policy = nft_chain_policy,
2895 },
2896 [NFT_MSG_DELCHAIN] = {
2897 .call = nf_tables_delchain,
2898 .attr_count = NFTA_CHAIN_MAX,
2899 .policy = nft_chain_policy,
2900 },
2901 [NFT_MSG_NEWRULE] = {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002902 .call_batch = nf_tables_newrule,
Patrick McHardy96518512013-10-14 11:00:02 +02002903 .attr_count = NFTA_RULE_MAX,
2904 .policy = nft_rule_policy,
2905 },
2906 [NFT_MSG_GETRULE] = {
2907 .call = nf_tables_getrule,
2908 .attr_count = NFTA_RULE_MAX,
2909 .policy = nft_rule_policy,
2910 },
2911 [NFT_MSG_DELRULE] = {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002912 .call_batch = nf_tables_delrule,
Patrick McHardy96518512013-10-14 11:00:02 +02002913 .attr_count = NFTA_RULE_MAX,
2914 .policy = nft_rule_policy,
2915 },
Patrick McHardy20a69342013-10-11 12:06:22 +02002916 [NFT_MSG_NEWSET] = {
2917 .call = nf_tables_newset,
2918 .attr_count = NFTA_SET_MAX,
2919 .policy = nft_set_policy,
2920 },
2921 [NFT_MSG_GETSET] = {
2922 .call = nf_tables_getset,
2923 .attr_count = NFTA_SET_MAX,
2924 .policy = nft_set_policy,
2925 },
2926 [NFT_MSG_DELSET] = {
2927 .call = nf_tables_delset,
2928 .attr_count = NFTA_SET_MAX,
2929 .policy = nft_set_policy,
2930 },
2931 [NFT_MSG_NEWSETELEM] = {
2932 .call = nf_tables_newsetelem,
2933 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2934 .policy = nft_set_elem_list_policy,
2935 },
2936 [NFT_MSG_GETSETELEM] = {
2937 .call = nf_tables_getsetelem,
2938 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2939 .policy = nft_set_elem_list_policy,
2940 },
2941 [NFT_MSG_DELSETELEM] = {
2942 .call = nf_tables_delsetelem,
2943 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2944 .policy = nft_set_elem_list_policy,
2945 },
Patrick McHardy96518512013-10-14 11:00:02 +02002946};
2947
2948static const struct nfnetlink_subsystem nf_tables_subsys = {
2949 .name = "nf_tables",
2950 .subsys_id = NFNL_SUBSYS_NFTABLES,
2951 .cb_count = NFT_MSG_MAX,
2952 .cb = nf_tables_cb,
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002953 .commit = nf_tables_commit,
2954 .abort = nf_tables_abort,
Patrick McHardy96518512013-10-14 11:00:02 +02002955};
2956
Patrick McHardy20a69342013-10-11 12:06:22 +02002957/*
2958 * Loop detection - walk through the ruleset beginning at the destination chain
2959 * of a new jump until either the source chain is reached (loop) or all
2960 * reachable chains have been traversed.
2961 *
2962 * The loop check is performed whenever a new jump verdict is added to an
2963 * expression or verdict map or a verdict map is bound to a new chain.
2964 */
2965
2966static int nf_tables_check_loops(const struct nft_ctx *ctx,
2967 const struct nft_chain *chain);
2968
2969static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
2970 const struct nft_set *set,
2971 const struct nft_set_iter *iter,
2972 const struct nft_set_elem *elem)
2973{
2974 switch (elem->data.verdict) {
2975 case NFT_JUMP:
2976 case NFT_GOTO:
2977 return nf_tables_check_loops(ctx, elem->data.chain);
2978 default:
2979 return 0;
2980 }
2981}
2982
2983static int nf_tables_check_loops(const struct nft_ctx *ctx,
2984 const struct nft_chain *chain)
2985{
2986 const struct nft_rule *rule;
2987 const struct nft_expr *expr, *last;
Patrick McHardy20a69342013-10-11 12:06:22 +02002988 const struct nft_set *set;
2989 struct nft_set_binding *binding;
2990 struct nft_set_iter iter;
Patrick McHardy20a69342013-10-11 12:06:22 +02002991
2992 if (ctx->chain == chain)
2993 return -ELOOP;
2994
2995 list_for_each_entry(rule, &chain->rules, list) {
2996 nft_rule_for_each_expr(expr, last, rule) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002997 const struct nft_data *data = NULL;
2998 int err;
2999
3000 if (!expr->ops->validate)
Patrick McHardy20a69342013-10-11 12:06:22 +02003001 continue;
3002
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02003003 err = expr->ops->validate(ctx, expr, &data);
3004 if (err < 0)
3005 return err;
3006
Patrick McHardy20a69342013-10-11 12:06:22 +02003007 if (data == NULL)
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02003008 continue;
Patrick McHardy20a69342013-10-11 12:06:22 +02003009
3010 switch (data->verdict) {
3011 case NFT_JUMP:
3012 case NFT_GOTO:
3013 err = nf_tables_check_loops(ctx, data->chain);
3014 if (err < 0)
3015 return err;
3016 default:
3017 break;
3018 }
3019 }
3020 }
3021
3022 list_for_each_entry(set, &ctx->table->sets, list) {
3023 if (!(set->flags & NFT_SET_MAP) ||
3024 set->dtype != NFT_DATA_VERDICT)
3025 continue;
3026
3027 list_for_each_entry(binding, &set->bindings, list) {
3028 if (binding->chain != chain)
3029 continue;
3030
3031 iter.skip = 0;
3032 iter.count = 0;
3033 iter.err = 0;
3034 iter.fn = nf_tables_loop_check_setelem;
3035
3036 set->ops->walk(ctx, set, &iter);
3037 if (iter.err < 0)
3038 return iter.err;
3039 }
3040 }
3041
3042 return 0;
3043}
3044
Patrick McHardy96518512013-10-14 11:00:02 +02003045/**
3046 * nft_validate_input_register - validate an expressions' input register
3047 *
3048 * @reg: the register number
3049 *
3050 * Validate that the input register is one of the general purpose
3051 * registers.
3052 */
3053int nft_validate_input_register(enum nft_registers reg)
3054{
3055 if (reg <= NFT_REG_VERDICT)
3056 return -EINVAL;
3057 if (reg > NFT_REG_MAX)
3058 return -ERANGE;
3059 return 0;
3060}
3061EXPORT_SYMBOL_GPL(nft_validate_input_register);
3062
3063/**
3064 * nft_validate_output_register - validate an expressions' output register
3065 *
3066 * @reg: the register number
3067 *
3068 * Validate that the output register is one of the general purpose
3069 * registers or the verdict register.
3070 */
3071int nft_validate_output_register(enum nft_registers reg)
3072{
3073 if (reg < NFT_REG_VERDICT)
3074 return -EINVAL;
3075 if (reg > NFT_REG_MAX)
3076 return -ERANGE;
3077 return 0;
3078}
3079EXPORT_SYMBOL_GPL(nft_validate_output_register);
3080
3081/**
3082 * nft_validate_data_load - validate an expressions' data load
3083 *
3084 * @ctx: context of the expression performing the load
3085 * @reg: the destination register number
3086 * @data: the data to load
3087 * @type: the data type
3088 *
3089 * Validate that a data load uses the appropriate data type for
3090 * the destination register. A value of NULL for the data means
3091 * that its runtime gathered data, which is always of type
3092 * NFT_DATA_VALUE.
3093 */
3094int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
3095 const struct nft_data *data,
3096 enum nft_data_types type)
3097{
Patrick McHardy20a69342013-10-11 12:06:22 +02003098 int err;
3099
Patrick McHardy96518512013-10-14 11:00:02 +02003100 switch (reg) {
3101 case NFT_REG_VERDICT:
3102 if (data == NULL || type != NFT_DATA_VERDICT)
3103 return -EINVAL;
Patrick McHardy20a69342013-10-11 12:06:22 +02003104
3105 if (data->verdict == NFT_GOTO || data->verdict == NFT_JUMP) {
3106 err = nf_tables_check_loops(ctx, data->chain);
3107 if (err < 0)
3108 return err;
3109
3110 if (ctx->chain->level + 1 > data->chain->level) {
3111 if (ctx->chain->level + 1 == NFT_JUMP_STACK_SIZE)
3112 return -EMLINK;
3113 data->chain->level = ctx->chain->level + 1;
3114 }
3115 }
3116
Patrick McHardy96518512013-10-14 11:00:02 +02003117 return 0;
3118 default:
3119 if (data != NULL && type != NFT_DATA_VALUE)
3120 return -EINVAL;
3121 return 0;
3122 }
3123}
3124EXPORT_SYMBOL_GPL(nft_validate_data_load);
3125
3126static const struct nla_policy nft_verdict_policy[NFTA_VERDICT_MAX + 1] = {
3127 [NFTA_VERDICT_CODE] = { .type = NLA_U32 },
3128 [NFTA_VERDICT_CHAIN] = { .type = NLA_STRING,
3129 .len = NFT_CHAIN_MAXNAMELEN - 1 },
3130};
3131
3132static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
3133 struct nft_data_desc *desc, const struct nlattr *nla)
3134{
3135 struct nlattr *tb[NFTA_VERDICT_MAX + 1];
3136 struct nft_chain *chain;
3137 int err;
3138
3139 err = nla_parse_nested(tb, NFTA_VERDICT_MAX, nla, nft_verdict_policy);
3140 if (err < 0)
3141 return err;
3142
3143 if (!tb[NFTA_VERDICT_CODE])
3144 return -EINVAL;
3145 data->verdict = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE]));
3146
3147 switch (data->verdict) {
3148 case NF_ACCEPT:
3149 case NF_DROP:
3150 case NF_QUEUE:
3151 case NFT_CONTINUE:
3152 case NFT_BREAK:
3153 case NFT_RETURN:
3154 desc->len = sizeof(data->verdict);
3155 break;
3156 case NFT_JUMP:
3157 case NFT_GOTO:
3158 if (!tb[NFTA_VERDICT_CHAIN])
3159 return -EINVAL;
3160 chain = nf_tables_chain_lookup(ctx->table,
3161 tb[NFTA_VERDICT_CHAIN]);
3162 if (IS_ERR(chain))
3163 return PTR_ERR(chain);
3164 if (chain->flags & NFT_BASE_CHAIN)
3165 return -EOPNOTSUPP;
3166
Patrick McHardy96518512013-10-14 11:00:02 +02003167 chain->use++;
3168 data->chain = chain;
3169 desc->len = sizeof(data);
3170 break;
3171 default:
3172 return -EINVAL;
3173 }
3174
3175 desc->type = NFT_DATA_VERDICT;
3176 return 0;
3177}
3178
3179static void nft_verdict_uninit(const struct nft_data *data)
3180{
3181 switch (data->verdict) {
3182 case NFT_JUMP:
3183 case NFT_GOTO:
3184 data->chain->use--;
3185 break;
3186 }
3187}
3188
3189static int nft_verdict_dump(struct sk_buff *skb, const struct nft_data *data)
3190{
3191 struct nlattr *nest;
3192
3193 nest = nla_nest_start(skb, NFTA_DATA_VERDICT);
3194 if (!nest)
3195 goto nla_put_failure;
3196
3197 if (nla_put_be32(skb, NFTA_VERDICT_CODE, htonl(data->verdict)))
3198 goto nla_put_failure;
3199
3200 switch (data->verdict) {
3201 case NFT_JUMP:
3202 case NFT_GOTO:
3203 if (nla_put_string(skb, NFTA_VERDICT_CHAIN, data->chain->name))
3204 goto nla_put_failure;
3205 }
3206 nla_nest_end(skb, nest);
3207 return 0;
3208
3209nla_put_failure:
3210 return -1;
3211}
3212
3213static int nft_value_init(const struct nft_ctx *ctx, struct nft_data *data,
3214 struct nft_data_desc *desc, const struct nlattr *nla)
3215{
3216 unsigned int len;
3217
3218 len = nla_len(nla);
3219 if (len == 0)
3220 return -EINVAL;
3221 if (len > sizeof(data->data))
3222 return -EOVERFLOW;
3223
3224 nla_memcpy(data->data, nla, sizeof(data->data));
3225 desc->type = NFT_DATA_VALUE;
3226 desc->len = len;
3227 return 0;
3228}
3229
3230static int nft_value_dump(struct sk_buff *skb, const struct nft_data *data,
3231 unsigned int len)
3232{
3233 return nla_put(skb, NFTA_DATA_VALUE, len, data->data);
3234}
3235
3236static const struct nla_policy nft_data_policy[NFTA_DATA_MAX + 1] = {
3237 [NFTA_DATA_VALUE] = { .type = NLA_BINARY,
3238 .len = FIELD_SIZEOF(struct nft_data, data) },
3239 [NFTA_DATA_VERDICT] = { .type = NLA_NESTED },
3240};
3241
3242/**
3243 * nft_data_init - parse nf_tables data netlink attributes
3244 *
3245 * @ctx: context of the expression using the data
3246 * @data: destination struct nft_data
3247 * @desc: data description
3248 * @nla: netlink attribute containing data
3249 *
3250 * Parse the netlink data attributes and initialize a struct nft_data.
3251 * The type and length of data are returned in the data description.
3252 *
3253 * The caller can indicate that it only wants to accept data of type
3254 * NFT_DATA_VALUE by passing NULL for the ctx argument.
3255 */
3256int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data,
3257 struct nft_data_desc *desc, const struct nlattr *nla)
3258{
3259 struct nlattr *tb[NFTA_DATA_MAX + 1];
3260 int err;
3261
3262 err = nla_parse_nested(tb, NFTA_DATA_MAX, nla, nft_data_policy);
3263 if (err < 0)
3264 return err;
3265
3266 if (tb[NFTA_DATA_VALUE])
3267 return nft_value_init(ctx, data, desc, tb[NFTA_DATA_VALUE]);
3268 if (tb[NFTA_DATA_VERDICT] && ctx != NULL)
3269 return nft_verdict_init(ctx, data, desc, tb[NFTA_DATA_VERDICT]);
3270 return -EINVAL;
3271}
3272EXPORT_SYMBOL_GPL(nft_data_init);
3273
3274/**
3275 * nft_data_uninit - release a nft_data item
3276 *
3277 * @data: struct nft_data to release
3278 * @type: type of data
3279 *
3280 * Release a nft_data item. NFT_DATA_VALUE types can be silently discarded,
3281 * all others need to be released by calling this function.
3282 */
3283void nft_data_uninit(const struct nft_data *data, enum nft_data_types type)
3284{
3285 switch (type) {
3286 case NFT_DATA_VALUE:
3287 return;
3288 case NFT_DATA_VERDICT:
3289 return nft_verdict_uninit(data);
3290 default:
3291 WARN_ON(1);
3292 }
3293}
3294EXPORT_SYMBOL_GPL(nft_data_uninit);
3295
3296int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
3297 enum nft_data_types type, unsigned int len)
3298{
3299 struct nlattr *nest;
3300 int err;
3301
3302 nest = nla_nest_start(skb, attr);
3303 if (nest == NULL)
3304 return -1;
3305
3306 switch (type) {
3307 case NFT_DATA_VALUE:
3308 err = nft_value_dump(skb, data, len);
3309 break;
3310 case NFT_DATA_VERDICT:
3311 err = nft_verdict_dump(skb, data);
3312 break;
3313 default:
3314 err = -EINVAL;
3315 WARN_ON(1);
3316 }
3317
3318 nla_nest_end(skb, nest);
3319 return err;
3320}
3321EXPORT_SYMBOL_GPL(nft_data_dump);
3322
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003323static int nf_tables_init_net(struct net *net)
3324{
3325 INIT_LIST_HEAD(&net->nft.af_info);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02003326 INIT_LIST_HEAD(&net->nft.commit_list);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003327 return 0;
3328}
3329
3330static struct pernet_operations nf_tables_net_ops = {
3331 .init = nf_tables_init_net,
3332};
3333
Patrick McHardy96518512013-10-14 11:00:02 +02003334static int __init nf_tables_module_init(void)
3335{
3336 int err;
3337
3338 info = kmalloc(sizeof(struct nft_expr_info) * NFT_RULE_MAXEXPRS,
3339 GFP_KERNEL);
3340 if (info == NULL) {
3341 err = -ENOMEM;
3342 goto err1;
3343 }
3344
3345 err = nf_tables_core_module_init();
3346 if (err < 0)
3347 goto err2;
3348
3349 err = nfnetlink_subsys_register(&nf_tables_subsys);
3350 if (err < 0)
3351 goto err3;
3352
3353 pr_info("nf_tables: (c) 2007-2009 Patrick McHardy <kaber@trash.net>\n");
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003354 return register_pernet_subsys(&nf_tables_net_ops);
Patrick McHardy96518512013-10-14 11:00:02 +02003355err3:
3356 nf_tables_core_module_exit();
3357err2:
3358 kfree(info);
3359err1:
3360 return err;
3361}
3362
3363static void __exit nf_tables_module_exit(void)
3364{
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003365 unregister_pernet_subsys(&nf_tables_net_ops);
Patrick McHardy96518512013-10-14 11:00:02 +02003366 nfnetlink_subsys_unregister(&nf_tables_subsys);
3367 nf_tables_core_module_exit();
3368 kfree(info);
3369}
3370
3371module_init(nf_tables_module_init);
3372module_exit(nf_tables_module_exit);
3373
3374MODULE_LICENSE("GPL");
3375MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
3376MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFTABLES);