blob: 79e1418a6043984313e83dc83c60860639550794 [file] [log] [blame]
Patrick McHardy96518512013-10-14 11:00:02 +02001/*
Patrick McHardy20a69342013-10-11 12:06:22 +02002 * Copyright (c) 2007-2009 Patrick McHardy <kaber@trash.net>
Patrick McHardy96518512013-10-14 11:00:02 +02003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/module.h>
12#include <linux/init.h>
13#include <linux/list.h>
14#include <linux/skbuff.h>
15#include <linux/netlink.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter/nfnetlink.h>
18#include <linux/netfilter/nf_tables.h>
19#include <net/netfilter/nf_tables_core.h>
20#include <net/netfilter/nf_tables.h>
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020021#include <net/net_namespace.h>
Patrick McHardy96518512013-10-14 11:00:02 +020022#include <net/sock.h>
23
Patrick McHardy96518512013-10-14 11:00:02 +020024static LIST_HEAD(nf_tables_expressions);
25
26/**
27 * nft_register_afinfo - register nf_tables address family info
28 *
29 * @afi: address family info to register
30 *
31 * Register the address family for use with nf_tables. Returns zero on
32 * success or a negative errno code otherwise.
33 */
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020034int nft_register_afinfo(struct net *net, struct nft_af_info *afi)
Patrick McHardy96518512013-10-14 11:00:02 +020035{
36 INIT_LIST_HEAD(&afi->tables);
37 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020038 list_add_tail(&afi->list, &net->nft.af_info);
Patrick McHardy96518512013-10-14 11:00:02 +020039 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
40 return 0;
41}
42EXPORT_SYMBOL_GPL(nft_register_afinfo);
43
44/**
45 * nft_unregister_afinfo - unregister nf_tables address family info
46 *
47 * @afi: address family info to unregister
48 *
49 * Unregister the address family for use with nf_tables.
50 */
51void nft_unregister_afinfo(struct nft_af_info *afi)
52{
53 nfnl_lock(NFNL_SUBSYS_NFTABLES);
54 list_del(&afi->list);
55 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
56}
57EXPORT_SYMBOL_GPL(nft_unregister_afinfo);
58
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020059static struct nft_af_info *nft_afinfo_lookup(struct net *net, int family)
Patrick McHardy96518512013-10-14 11:00:02 +020060{
61 struct nft_af_info *afi;
62
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020063 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +020064 if (afi->family == family)
65 return afi;
66 }
67 return NULL;
68}
69
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020070static struct nft_af_info *
71nf_tables_afinfo_lookup(struct net *net, int family, bool autoload)
Patrick McHardy96518512013-10-14 11:00:02 +020072{
73 struct nft_af_info *afi;
74
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020075 afi = nft_afinfo_lookup(net, family);
Patrick McHardy96518512013-10-14 11:00:02 +020076 if (afi != NULL)
77 return afi;
78#ifdef CONFIG_MODULES
79 if (autoload) {
80 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
81 request_module("nft-afinfo-%u", family);
82 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020083 afi = nft_afinfo_lookup(net, family);
Patrick McHardy96518512013-10-14 11:00:02 +020084 if (afi != NULL)
85 return ERR_PTR(-EAGAIN);
86 }
87#endif
88 return ERR_PTR(-EAFNOSUPPORT);
89}
90
91/*
92 * Tables
93 */
94
95static struct nft_table *nft_table_lookup(const struct nft_af_info *afi,
96 const struct nlattr *nla)
97{
98 struct nft_table *table;
99
100 list_for_each_entry(table, &afi->tables, list) {
101 if (!nla_strcmp(nla, table->name))
102 return table;
103 }
104 return NULL;
105}
106
107static struct nft_table *nf_tables_table_lookup(const struct nft_af_info *afi,
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200108 const struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +0200109{
110 struct nft_table *table;
111
112 if (nla == NULL)
113 return ERR_PTR(-EINVAL);
114
115 table = nft_table_lookup(afi, nla);
116 if (table != NULL)
117 return table;
118
Patrick McHardy96518512013-10-14 11:00:02 +0200119 return ERR_PTR(-ENOENT);
120}
121
122static inline u64 nf_tables_alloc_handle(struct nft_table *table)
123{
124 return ++table->hgenerator;
125}
126
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200127static struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX];
128
129static int __nf_tables_chain_type_lookup(int family, const struct nlattr *nla)
130{
131 int i;
132
133 for (i=0; i<NFT_CHAIN_T_MAX; i++) {
134 if (chain_type[family][i] != NULL &&
135 !nla_strcmp(nla, chain_type[family][i]->name))
136 return i;
137 }
138 return -1;
139}
140
141static int nf_tables_chain_type_lookup(const struct nft_af_info *afi,
142 const struct nlattr *nla,
143 bool autoload)
144{
145 int type;
146
147 type = __nf_tables_chain_type_lookup(afi->family, nla);
148#ifdef CONFIG_MODULES
149 if (type < 0 && autoload) {
150 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
151 request_module("nft-chain-%u-%*.s", afi->family,
152 nla_len(nla)-1, (const char *)nla_data(nla));
153 nfnl_lock(NFNL_SUBSYS_NFTABLES);
154 type = __nf_tables_chain_type_lookup(afi->family, nla);
155 }
156#endif
157 return type;
158}
159
Patrick McHardy96518512013-10-14 11:00:02 +0200160static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
161 [NFTA_TABLE_NAME] = { .type = NLA_STRING },
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200162 [NFTA_TABLE_FLAGS] = { .type = NLA_U32 },
Patrick McHardy96518512013-10-14 11:00:02 +0200163};
164
165static int nf_tables_fill_table_info(struct sk_buff *skb, u32 portid, u32 seq,
166 int event, u32 flags, int family,
167 const struct nft_table *table)
168{
169 struct nlmsghdr *nlh;
170 struct nfgenmsg *nfmsg;
171
172 event |= NFNL_SUBSYS_NFTABLES << 8;
173 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
174 if (nlh == NULL)
175 goto nla_put_failure;
176
177 nfmsg = nlmsg_data(nlh);
178 nfmsg->nfgen_family = family;
179 nfmsg->version = NFNETLINK_V0;
180 nfmsg->res_id = 0;
181
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200182 if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
183 nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)))
Patrick McHardy96518512013-10-14 11:00:02 +0200184 goto nla_put_failure;
185
186 return nlmsg_end(skb, nlh);
187
188nla_put_failure:
189 nlmsg_trim(skb, nlh);
190 return -1;
191}
192
193static int nf_tables_table_notify(const struct sk_buff *oskb,
194 const struct nlmsghdr *nlh,
195 const struct nft_table *table,
196 int event, int family)
197{
198 struct sk_buff *skb;
199 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
200 u32 seq = nlh ? nlh->nlmsg_seq : 0;
201 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
202 bool report;
203 int err;
204
205 report = nlh ? nlmsg_report(nlh) : false;
206 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
207 return 0;
208
209 err = -ENOBUFS;
210 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
211 if (skb == NULL)
212 goto err;
213
214 err = nf_tables_fill_table_info(skb, portid, seq, event, 0,
215 family, table);
216 if (err < 0) {
217 kfree_skb(skb);
218 goto err;
219 }
220
221 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
222 GFP_KERNEL);
223err:
224 if (err < 0)
225 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
226 return err;
227}
228
229static int nf_tables_dump_tables(struct sk_buff *skb,
230 struct netlink_callback *cb)
231{
232 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
233 const struct nft_af_info *afi;
234 const struct nft_table *table;
235 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200236 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200237 int family = nfmsg->nfgen_family;
238
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200239 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +0200240 if (family != NFPROTO_UNSPEC && family != afi->family)
241 continue;
242
243 list_for_each_entry(table, &afi->tables, list) {
244 if (idx < s_idx)
245 goto cont;
246 if (idx > s_idx)
247 memset(&cb->args[1], 0,
248 sizeof(cb->args) - sizeof(cb->args[0]));
249 if (nf_tables_fill_table_info(skb,
250 NETLINK_CB(cb->skb).portid,
251 cb->nlh->nlmsg_seq,
252 NFT_MSG_NEWTABLE,
253 NLM_F_MULTI,
254 afi->family, table) < 0)
255 goto done;
256cont:
257 idx++;
258 }
259 }
260done:
261 cb->args[0] = idx;
262 return skb->len;
263}
264
265static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb,
266 const struct nlmsghdr *nlh,
267 const struct nlattr * const nla[])
268{
269 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
270 const struct nft_af_info *afi;
271 const struct nft_table *table;
272 struct sk_buff *skb2;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200273 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200274 int family = nfmsg->nfgen_family;
275 int err;
276
277 if (nlh->nlmsg_flags & NLM_F_DUMP) {
278 struct netlink_dump_control c = {
279 .dump = nf_tables_dump_tables,
280 };
281 return netlink_dump_start(nlsk, skb, nlh, &c);
282 }
283
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200284 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200285 if (IS_ERR(afi))
286 return PTR_ERR(afi);
287
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200288 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
Patrick McHardy96518512013-10-14 11:00:02 +0200289 if (IS_ERR(table))
290 return PTR_ERR(table);
291
292 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
293 if (!skb2)
294 return -ENOMEM;
295
296 err = nf_tables_fill_table_info(skb2, NETLINK_CB(skb).portid,
297 nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0,
298 family, table);
299 if (err < 0)
300 goto err;
301
302 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
303
304err:
305 kfree_skb(skb2);
306 return err;
307}
308
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200309static int nf_tables_table_enable(struct nft_table *table)
310{
311 struct nft_chain *chain;
312 int err, i = 0;
313
314 list_for_each_entry(chain, &table->chains, list) {
315 err = nf_register_hook(&nft_base_chain(chain)->ops);
316 if (err < 0)
317 goto err;
318
319 i++;
320 }
321 return 0;
322err:
323 list_for_each_entry(chain, &table->chains, list) {
324 if (i-- <= 0)
325 break;
326
327 nf_unregister_hook(&nft_base_chain(chain)->ops);
328 }
329 return err;
330}
331
332static int nf_tables_table_disable(struct nft_table *table)
333{
334 struct nft_chain *chain;
335
336 list_for_each_entry(chain, &table->chains, list)
337 nf_unregister_hook(&nft_base_chain(chain)->ops);
338
339 return 0;
340}
341
342static int nf_tables_updtable(struct sock *nlsk, struct sk_buff *skb,
343 const struct nlmsghdr *nlh,
344 const struct nlattr * const nla[],
345 struct nft_af_info *afi, struct nft_table *table)
346{
347 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
348 int family = nfmsg->nfgen_family, ret = 0;
349
350 if (nla[NFTA_TABLE_FLAGS]) {
351 __be32 flags;
352
353 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
354 if (flags & ~NFT_TABLE_F_DORMANT)
355 return -EINVAL;
356
357 if ((flags & NFT_TABLE_F_DORMANT) &&
358 !(table->flags & NFT_TABLE_F_DORMANT)) {
359 ret = nf_tables_table_disable(table);
360 if (ret >= 0)
361 table->flags |= NFT_TABLE_F_DORMANT;
362 } else if (!(flags & NFT_TABLE_F_DORMANT) &&
363 table->flags & NFT_TABLE_F_DORMANT) {
364 ret = nf_tables_table_enable(table);
365 if (ret >= 0)
366 table->flags &= ~NFT_TABLE_F_DORMANT;
367 }
368 if (ret < 0)
369 goto err;
370 }
371
372 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
373err:
374 return ret;
375}
376
Patrick McHardy96518512013-10-14 11:00:02 +0200377static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
378 const struct nlmsghdr *nlh,
379 const struct nlattr * const nla[])
380{
381 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
382 const struct nlattr *name;
383 struct nft_af_info *afi;
384 struct nft_table *table;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200385 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200386 int family = nfmsg->nfgen_family;
387
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200388 afi = nf_tables_afinfo_lookup(net, family, true);
Patrick McHardy96518512013-10-14 11:00:02 +0200389 if (IS_ERR(afi))
390 return PTR_ERR(afi);
391
392 name = nla[NFTA_TABLE_NAME];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200393 table = nf_tables_table_lookup(afi, name);
Patrick McHardy96518512013-10-14 11:00:02 +0200394 if (IS_ERR(table)) {
395 if (PTR_ERR(table) != -ENOENT)
396 return PTR_ERR(table);
397 table = NULL;
398 }
399
400 if (table != NULL) {
401 if (nlh->nlmsg_flags & NLM_F_EXCL)
402 return -EEXIST;
403 if (nlh->nlmsg_flags & NLM_F_REPLACE)
404 return -EOPNOTSUPP;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200405 return nf_tables_updtable(nlsk, skb, nlh, nla, afi, table);
Patrick McHardy96518512013-10-14 11:00:02 +0200406 }
407
408 table = kzalloc(sizeof(*table) + nla_len(name), GFP_KERNEL);
409 if (table == NULL)
410 return -ENOMEM;
411
412 nla_strlcpy(table->name, name, nla_len(name));
413 INIT_LIST_HEAD(&table->chains);
Patrick McHardy20a69342013-10-11 12:06:22 +0200414 INIT_LIST_HEAD(&table->sets);
Patrick McHardy96518512013-10-14 11:00:02 +0200415
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200416 if (nla[NFTA_TABLE_FLAGS]) {
417 __be32 flags;
418
419 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
420 if (flags & ~NFT_TABLE_F_DORMANT) {
421 kfree(table);
422 return -EINVAL;
423 }
424
425 table->flags |= flags;
426 }
427
Patrick McHardy96518512013-10-14 11:00:02 +0200428 list_add_tail(&table->list, &afi->tables);
429 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
430 return 0;
431}
432
433static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
434 const struct nlmsghdr *nlh,
435 const struct nlattr * const nla[])
436{
437 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
438 struct nft_af_info *afi;
439 struct nft_table *table;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200440 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200441 int family = nfmsg->nfgen_family;
442
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200443 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200444 if (IS_ERR(afi))
445 return PTR_ERR(afi);
446
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200447 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
Patrick McHardy96518512013-10-14 11:00:02 +0200448 if (IS_ERR(table))
449 return PTR_ERR(table);
450
Patrick McHardy96518512013-10-14 11:00:02 +0200451 if (table->use)
452 return -EBUSY;
453
454 list_del(&table->list);
455 nf_tables_table_notify(skb, nlh, table, NFT_MSG_DELTABLE, family);
456 kfree(table);
457 return 0;
458}
459
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200460int nft_register_chain_type(struct nf_chain_type *ctype)
Patrick McHardy96518512013-10-14 11:00:02 +0200461{
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200462 int err = 0;
Patrick McHardy96518512013-10-14 11:00:02 +0200463
464 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200465 if (chain_type[ctype->family][ctype->type] != NULL) {
466 err = -EBUSY;
467 goto out;
Patrick McHardy96518512013-10-14 11:00:02 +0200468 }
469
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200470 if (!try_module_get(ctype->me))
471 goto out;
Patrick McHardy96518512013-10-14 11:00:02 +0200472
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200473 chain_type[ctype->family][ctype->type] = ctype;
474out:
Patrick McHardy96518512013-10-14 11:00:02 +0200475 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
476 return err;
477}
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200478EXPORT_SYMBOL_GPL(nft_register_chain_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200479
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200480void nft_unregister_chain_type(struct nf_chain_type *ctype)
Patrick McHardy96518512013-10-14 11:00:02 +0200481{
Patrick McHardy96518512013-10-14 11:00:02 +0200482 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200483 chain_type[ctype->family][ctype->type] = NULL;
484 module_put(ctype->me);
Patrick McHardy96518512013-10-14 11:00:02 +0200485 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
486}
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200487EXPORT_SYMBOL_GPL(nft_unregister_chain_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200488
489/*
490 * Chains
491 */
492
493static struct nft_chain *
494nf_tables_chain_lookup_byhandle(const struct nft_table *table, u64 handle)
495{
496 struct nft_chain *chain;
497
498 list_for_each_entry(chain, &table->chains, list) {
499 if (chain->handle == handle)
500 return chain;
501 }
502
503 return ERR_PTR(-ENOENT);
504}
505
506static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table,
507 const struct nlattr *nla)
508{
509 struct nft_chain *chain;
510
511 if (nla == NULL)
512 return ERR_PTR(-EINVAL);
513
514 list_for_each_entry(chain, &table->chains, list) {
515 if (!nla_strcmp(nla, chain->name))
516 return chain;
517 }
518
519 return ERR_PTR(-ENOENT);
520}
521
522static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
523 [NFTA_CHAIN_TABLE] = { .type = NLA_STRING },
524 [NFTA_CHAIN_HANDLE] = { .type = NLA_U64 },
525 [NFTA_CHAIN_NAME] = { .type = NLA_STRING,
526 .len = NFT_CHAIN_MAXNAMELEN - 1 },
527 [NFTA_CHAIN_HOOK] = { .type = NLA_NESTED },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200528 [NFTA_CHAIN_POLICY] = { .type = NLA_U32 },
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200529 [NFTA_CHAIN_TYPE] = { .type = NLA_NUL_STRING },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200530 [NFTA_CHAIN_COUNTERS] = { .type = NLA_NESTED },
Patrick McHardy96518512013-10-14 11:00:02 +0200531};
532
533static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = {
534 [NFTA_HOOK_HOOKNUM] = { .type = NLA_U32 },
535 [NFTA_HOOK_PRIORITY] = { .type = NLA_U32 },
536};
537
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200538static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats)
539{
540 struct nft_stats *cpu_stats, total;
541 struct nlattr *nest;
542 int cpu;
543
544 memset(&total, 0, sizeof(total));
545 for_each_possible_cpu(cpu) {
546 cpu_stats = per_cpu_ptr(stats, cpu);
547 total.pkts += cpu_stats->pkts;
548 total.bytes += cpu_stats->bytes;
549 }
550 nest = nla_nest_start(skb, NFTA_CHAIN_COUNTERS);
551 if (nest == NULL)
552 goto nla_put_failure;
553
554 if (nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(total.pkts)) ||
555 nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes)))
556 goto nla_put_failure;
557
558 nla_nest_end(skb, nest);
559 return 0;
560
561nla_put_failure:
562 return -ENOSPC;
563}
564
Patrick McHardy96518512013-10-14 11:00:02 +0200565static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq,
566 int event, u32 flags, int family,
567 const struct nft_table *table,
568 const struct nft_chain *chain)
569{
570 struct nlmsghdr *nlh;
571 struct nfgenmsg *nfmsg;
572
573 event |= NFNL_SUBSYS_NFTABLES << 8;
574 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
575 if (nlh == NULL)
576 goto nla_put_failure;
577
578 nfmsg = nlmsg_data(nlh);
579 nfmsg->nfgen_family = family;
580 nfmsg->version = NFNETLINK_V0;
581 nfmsg->res_id = 0;
582
583 if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name))
584 goto nla_put_failure;
585 if (nla_put_be64(skb, NFTA_CHAIN_HANDLE, cpu_to_be64(chain->handle)))
586 goto nla_put_failure;
587 if (nla_put_string(skb, NFTA_CHAIN_NAME, chain->name))
588 goto nla_put_failure;
589
590 if (chain->flags & NFT_BASE_CHAIN) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200591 const struct nft_base_chain *basechain = nft_base_chain(chain);
592 const struct nf_hook_ops *ops = &basechain->ops;
593 struct nlattr *nest;
594
595 nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
Patrick McHardy96518512013-10-14 11:00:02 +0200596 if (nest == NULL)
597 goto nla_put_failure;
598 if (nla_put_be32(skb, NFTA_HOOK_HOOKNUM, htonl(ops->hooknum)))
599 goto nla_put_failure;
600 if (nla_put_be32(skb, NFTA_HOOK_PRIORITY, htonl(ops->priority)))
601 goto nla_put_failure;
602 nla_nest_end(skb, nest);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200603
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200604 if (nla_put_be32(skb, NFTA_CHAIN_POLICY,
605 htonl(basechain->policy)))
606 goto nla_put_failure;
607
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200608 if (nla_put_string(skb, NFTA_CHAIN_TYPE,
609 chain_type[ops->pf][nft_base_chain(chain)->type]->name))
610 goto nla_put_failure;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200611
612 if (nft_dump_stats(skb, nft_base_chain(chain)->stats))
613 goto nla_put_failure;
Patrick McHardy96518512013-10-14 11:00:02 +0200614 }
615
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200616 if (nla_put_be32(skb, NFTA_CHAIN_USE, htonl(chain->use)))
617 goto nla_put_failure;
618
Patrick McHardy96518512013-10-14 11:00:02 +0200619 return nlmsg_end(skb, nlh);
620
621nla_put_failure:
622 nlmsg_trim(skb, nlh);
623 return -1;
624}
625
626static int nf_tables_chain_notify(const struct sk_buff *oskb,
627 const struct nlmsghdr *nlh,
628 const struct nft_table *table,
629 const struct nft_chain *chain,
630 int event, int family)
631{
632 struct sk_buff *skb;
633 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
634 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
635 u32 seq = nlh ? nlh->nlmsg_seq : 0;
636 bool report;
637 int err;
638
639 report = nlh ? nlmsg_report(nlh) : false;
640 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
641 return 0;
642
643 err = -ENOBUFS;
644 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
645 if (skb == NULL)
646 goto err;
647
648 err = nf_tables_fill_chain_info(skb, portid, seq, event, 0, family,
649 table, chain);
650 if (err < 0) {
651 kfree_skb(skb);
652 goto err;
653 }
654
655 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
656 GFP_KERNEL);
657err:
658 if (err < 0)
659 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
660 return err;
661}
662
663static int nf_tables_dump_chains(struct sk_buff *skb,
664 struct netlink_callback *cb)
665{
666 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
667 const struct nft_af_info *afi;
668 const struct nft_table *table;
669 const struct nft_chain *chain;
670 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200671 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200672 int family = nfmsg->nfgen_family;
673
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200674 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +0200675 if (family != NFPROTO_UNSPEC && family != afi->family)
676 continue;
677
678 list_for_each_entry(table, &afi->tables, list) {
679 list_for_each_entry(chain, &table->chains, list) {
680 if (idx < s_idx)
681 goto cont;
682 if (idx > s_idx)
683 memset(&cb->args[1], 0,
684 sizeof(cb->args) - sizeof(cb->args[0]));
685 if (nf_tables_fill_chain_info(skb, NETLINK_CB(cb->skb).portid,
686 cb->nlh->nlmsg_seq,
687 NFT_MSG_NEWCHAIN,
688 NLM_F_MULTI,
689 afi->family, table, chain) < 0)
690 goto done;
691cont:
692 idx++;
693 }
694 }
695 }
696done:
697 cb->args[0] = idx;
698 return skb->len;
699}
700
701
702static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb,
703 const struct nlmsghdr *nlh,
704 const struct nlattr * const nla[])
705{
706 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
707 const struct nft_af_info *afi;
708 const struct nft_table *table;
709 const struct nft_chain *chain;
710 struct sk_buff *skb2;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200711 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200712 int family = nfmsg->nfgen_family;
713 int err;
714
715 if (nlh->nlmsg_flags & NLM_F_DUMP) {
716 struct netlink_dump_control c = {
717 .dump = nf_tables_dump_chains,
718 };
719 return netlink_dump_start(nlsk, skb, nlh, &c);
720 }
721
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200722 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200723 if (IS_ERR(afi))
724 return PTR_ERR(afi);
725
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200726 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +0200727 if (IS_ERR(table))
728 return PTR_ERR(table);
729
730 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
731 if (IS_ERR(chain))
732 return PTR_ERR(chain);
733
734 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
735 if (!skb2)
736 return -ENOMEM;
737
738 err = nf_tables_fill_chain_info(skb2, NETLINK_CB(skb).portid,
739 nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0,
740 family, table, chain);
741 if (err < 0)
742 goto err;
743
744 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
745
746err:
747 kfree_skb(skb2);
748 return err;
749}
750
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200751static int
752nf_tables_chain_policy(struct nft_base_chain *chain, const struct nlattr *attr)
753{
754 switch (ntohl(nla_get_be32(attr))) {
755 case NF_DROP:
756 chain->policy = NF_DROP;
757 break;
758 case NF_ACCEPT:
759 chain->policy = NF_ACCEPT;
760 break;
761 default:
762 return -EINVAL;
763 }
764 return 0;
765}
766
767static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = {
768 [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 },
769 [NFTA_COUNTER_BYTES] = { .type = NLA_U64 },
770};
771
772static int
773nf_tables_counters(struct nft_base_chain *chain, const struct nlattr *attr)
774{
775 struct nlattr *tb[NFTA_COUNTER_MAX+1];
776 struct nft_stats __percpu *newstats;
777 struct nft_stats *stats;
778 int err;
779
780 err = nla_parse_nested(tb, NFTA_COUNTER_MAX, attr, nft_counter_policy);
781 if (err < 0)
782 return err;
783
784 if (!tb[NFTA_COUNTER_BYTES] || !tb[NFTA_COUNTER_PACKETS])
785 return -EINVAL;
786
787 newstats = alloc_percpu(struct nft_stats);
788 if (newstats == NULL)
789 return -ENOMEM;
790
791 /* Restore old counters on this cpu, no problem. Per-cpu statistics
792 * are not exposed to userspace.
793 */
794 stats = this_cpu_ptr(newstats);
795 stats->bytes = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES]));
796 stats->pkts = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS]));
797
798 if (chain->stats) {
799 /* nfnl_lock is held, add some nfnl function for this, later */
800 struct nft_stats __percpu *oldstats =
801 rcu_dereference_protected(chain->stats, 1);
802
803 rcu_assign_pointer(chain->stats, newstats);
804 synchronize_rcu();
805 free_percpu(oldstats);
806 } else
807 rcu_assign_pointer(chain->stats, newstats);
808
809 return 0;
810}
811
Patrick McHardy96518512013-10-14 11:00:02 +0200812static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
813 const struct nlmsghdr *nlh,
814 const struct nlattr * const nla[])
815{
816 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
817 const struct nlattr * uninitialized_var(name);
818 const struct nft_af_info *afi;
819 struct nft_table *table;
820 struct nft_chain *chain;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200821 struct nft_base_chain *basechain = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +0200822 struct nlattr *ha[NFTA_HOOK_MAX + 1];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200823 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200824 int family = nfmsg->nfgen_family;
825 u64 handle = 0;
826 int err;
827 bool create;
828
829 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
830
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200831 afi = nf_tables_afinfo_lookup(net, family, true);
Patrick McHardy96518512013-10-14 11:00:02 +0200832 if (IS_ERR(afi))
833 return PTR_ERR(afi);
834
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200835 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +0200836 if (IS_ERR(table))
837 return PTR_ERR(table);
838
839 if (table->use == UINT_MAX)
840 return -EOVERFLOW;
841
842 chain = NULL;
843 name = nla[NFTA_CHAIN_NAME];
844
845 if (nla[NFTA_CHAIN_HANDLE]) {
846 handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
847 chain = nf_tables_chain_lookup_byhandle(table, handle);
848 if (IS_ERR(chain))
849 return PTR_ERR(chain);
850 } else {
851 chain = nf_tables_chain_lookup(table, name);
852 if (IS_ERR(chain)) {
853 if (PTR_ERR(chain) != -ENOENT)
854 return PTR_ERR(chain);
855 chain = NULL;
856 }
857 }
858
859 if (chain != NULL) {
860 if (nlh->nlmsg_flags & NLM_F_EXCL)
861 return -EEXIST;
862 if (nlh->nlmsg_flags & NLM_F_REPLACE)
863 return -EOPNOTSUPP;
864
865 if (nla[NFTA_CHAIN_HANDLE] && name &&
866 !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME])))
867 return -EEXIST;
868
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200869 if (nla[NFTA_CHAIN_POLICY]) {
870 if (!(chain->flags & NFT_BASE_CHAIN))
871 return -EOPNOTSUPP;
872
873 err = nf_tables_chain_policy(nft_base_chain(chain),
874 nla[NFTA_CHAIN_POLICY]);
875 if (err < 0)
876 return err;
877 }
878
879 if (nla[NFTA_CHAIN_COUNTERS]) {
880 if (!(chain->flags & NFT_BASE_CHAIN))
881 return -EOPNOTSUPP;
882
883 err = nf_tables_counters(nft_base_chain(chain),
884 nla[NFTA_CHAIN_COUNTERS]);
885 if (err < 0)
886 return err;
887 }
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
895 if (nla[NFTA_CHAIN_HOOK]) {
896 struct nf_hook_ops *ops;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200897 nf_hookfn *hookfn;
898 u32 hooknum;
899 int type = NFT_CHAIN_T_DEFAULT;
900
901 if (nla[NFTA_CHAIN_TYPE]) {
902 type = nf_tables_chain_type_lookup(afi,
903 nla[NFTA_CHAIN_TYPE],
904 create);
905 if (type < 0)
906 return -ENOENT;
907 }
Patrick McHardy96518512013-10-14 11:00:02 +0200908
909 err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK],
910 nft_hook_policy);
911 if (err < 0)
912 return err;
913 if (ha[NFTA_HOOK_HOOKNUM] == NULL ||
914 ha[NFTA_HOOK_PRIORITY] == NULL)
915 return -EINVAL;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200916
917 hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
918 if (hooknum >= afi->nhooks)
Patrick McHardy96518512013-10-14 11:00:02 +0200919 return -EINVAL;
920
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200921 hookfn = chain_type[family][type]->fn[hooknum];
922 if (hookfn == NULL)
923 return -EOPNOTSUPP;
924
Patrick McHardy96518512013-10-14 11:00:02 +0200925 basechain = kzalloc(sizeof(*basechain), GFP_KERNEL);
926 if (basechain == NULL)
927 return -ENOMEM;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200928
929 basechain->type = type;
Patrick McHardy96518512013-10-14 11:00:02 +0200930 chain = &basechain->chain;
931
932 ops = &basechain->ops;
933 ops->pf = family;
934 ops->owner = afi->owner;
935 ops->hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
936 ops->priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
937 ops->priv = chain;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200938 ops->hook = hookfn;
Patrick McHardy96518512013-10-14 11:00:02 +0200939 if (afi->hooks[ops->hooknum])
940 ops->hook = afi->hooks[ops->hooknum];
941
942 chain->flags |= NFT_BASE_CHAIN;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200943
944 if (nla[NFTA_CHAIN_POLICY]) {
945 err = nf_tables_chain_policy(basechain,
946 nla[NFTA_CHAIN_POLICY]);
947 if (err < 0) {
948 free_percpu(basechain->stats);
949 kfree(basechain);
950 return err;
951 }
952 } else
953 basechain->policy = NF_ACCEPT;
954
955 if (nla[NFTA_CHAIN_COUNTERS]) {
956 err = nf_tables_counters(basechain,
957 nla[NFTA_CHAIN_COUNTERS]);
958 if (err < 0) {
959 free_percpu(basechain->stats);
960 kfree(basechain);
961 return err;
962 }
963 } else {
964 struct nft_stats __percpu *newstats;
965
966 newstats = alloc_percpu(struct nft_stats);
967 if (newstats == NULL)
968 return -ENOMEM;
969
970 rcu_assign_pointer(nft_base_chain(chain)->stats,
971 newstats);
972 }
Patrick McHardy96518512013-10-14 11:00:02 +0200973 } else {
974 chain = kzalloc(sizeof(*chain), GFP_KERNEL);
975 if (chain == NULL)
976 return -ENOMEM;
977 }
978
979 INIT_LIST_HEAD(&chain->rules);
980 chain->handle = nf_tables_alloc_handle(table);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +0200981 chain->net = net;
Patrick McHardy96518512013-10-14 11:00:02 +0200982 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
983
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200984 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
985 chain->flags & NFT_BASE_CHAIN) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200986 err = nf_register_hook(&nft_base_chain(chain)->ops);
987 if (err < 0) {
988 free_percpu(basechain->stats);
989 kfree(basechain);
990 return err;
991 }
992 }
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200993 list_add_tail(&chain->list, &table->chains);
994 table->use++;
Patrick McHardy96518512013-10-14 11:00:02 +0200995notify:
996 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_NEWCHAIN,
997 family);
998 return 0;
999}
1000
1001static void nf_tables_rcu_chain_destroy(struct rcu_head *head)
1002{
1003 struct nft_chain *chain = container_of(head, struct nft_chain, rcu_head);
1004
1005 BUG_ON(chain->use > 0);
1006
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001007 if (chain->flags & NFT_BASE_CHAIN) {
1008 free_percpu(nft_base_chain(chain)->stats);
Patrick McHardy96518512013-10-14 11:00:02 +02001009 kfree(nft_base_chain(chain));
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001010 } else
Patrick McHardy96518512013-10-14 11:00:02 +02001011 kfree(chain);
1012}
1013
1014static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
1015 const struct nlmsghdr *nlh,
1016 const struct nlattr * const nla[])
1017{
1018 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1019 const struct nft_af_info *afi;
1020 struct nft_table *table;
1021 struct nft_chain *chain;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001022 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001023 int family = nfmsg->nfgen_family;
1024
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001025 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001026 if (IS_ERR(afi))
1027 return PTR_ERR(afi);
1028
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001029 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001030 if (IS_ERR(table))
1031 return PTR_ERR(table);
1032
1033 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
1034 if (IS_ERR(chain))
1035 return PTR_ERR(chain);
1036
Patrick McHardy96518512013-10-14 11:00:02 +02001037 if (!list_empty(&chain->rules))
1038 return -EBUSY;
1039
1040 list_del(&chain->list);
1041 table->use--;
1042
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +02001043 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
1044 chain->flags & NFT_BASE_CHAIN)
Patrick McHardy96518512013-10-14 11:00:02 +02001045 nf_unregister_hook(&nft_base_chain(chain)->ops);
1046
1047 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN,
1048 family);
1049
1050 /* Make sure all rule references are gone before this is released */
1051 call_rcu(&chain->rcu_head, nf_tables_rcu_chain_destroy);
1052 return 0;
1053}
1054
1055static void nft_ctx_init(struct nft_ctx *ctx,
Patrick McHardy20a69342013-10-11 12:06:22 +02001056 const struct sk_buff *skb,
1057 const struct nlmsghdr *nlh,
Patrick McHardy96518512013-10-14 11:00:02 +02001058 const struct nft_af_info *afi,
1059 const struct nft_table *table,
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001060 const struct nft_chain *chain,
1061 const struct nlattr * const *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001062{
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001063 ctx->net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02001064 ctx->skb = skb;
1065 ctx->nlh = nlh;
Patrick McHardy96518512013-10-14 11:00:02 +02001066 ctx->afi = afi;
1067 ctx->table = table;
1068 ctx->chain = chain;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001069 ctx->nla = nla;
Patrick McHardy96518512013-10-14 11:00:02 +02001070}
1071
1072/*
1073 * Expressions
1074 */
1075
1076/**
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001077 * nft_register_expr - register nf_tables expr type
1078 * @ops: expr type
Patrick McHardy96518512013-10-14 11:00:02 +02001079 *
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001080 * Registers the expr type for use with nf_tables. Returns zero on
Patrick McHardy96518512013-10-14 11:00:02 +02001081 * success or a negative errno code otherwise.
1082 */
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001083int nft_register_expr(struct nft_expr_type *type)
Patrick McHardy96518512013-10-14 11:00:02 +02001084{
1085 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001086 list_add_tail(&type->list, &nf_tables_expressions);
Patrick McHardy96518512013-10-14 11:00:02 +02001087 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1088 return 0;
1089}
1090EXPORT_SYMBOL_GPL(nft_register_expr);
1091
1092/**
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001093 * nft_unregister_expr - unregister nf_tables expr type
1094 * @ops: expr type
Patrick McHardy96518512013-10-14 11:00:02 +02001095 *
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001096 * Unregisters the expr typefor use with nf_tables.
Patrick McHardy96518512013-10-14 11:00:02 +02001097 */
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001098void nft_unregister_expr(struct nft_expr_type *type)
Patrick McHardy96518512013-10-14 11:00:02 +02001099{
1100 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001101 list_del(&type->list);
Patrick McHardy96518512013-10-14 11:00:02 +02001102 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1103}
1104EXPORT_SYMBOL_GPL(nft_unregister_expr);
1105
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001106static const struct nft_expr_type *__nft_expr_type_get(struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001107{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001108 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001109
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001110 list_for_each_entry(type, &nf_tables_expressions, list) {
1111 if (!nla_strcmp(nla, type->name))
1112 return type;
Patrick McHardy96518512013-10-14 11:00:02 +02001113 }
1114 return NULL;
1115}
1116
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001117static const struct nft_expr_type *nft_expr_type_get(struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001118{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001119 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001120
1121 if (nla == NULL)
1122 return ERR_PTR(-EINVAL);
1123
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001124 type = __nft_expr_type_get(nla);
1125 if (type != NULL && try_module_get(type->owner))
1126 return type;
Patrick McHardy96518512013-10-14 11:00:02 +02001127
1128#ifdef CONFIG_MODULES
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001129 if (type == NULL) {
Patrick McHardy96518512013-10-14 11:00:02 +02001130 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1131 request_module("nft-expr-%.*s",
1132 nla_len(nla), (char *)nla_data(nla));
1133 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001134 if (__nft_expr_type_get(nla))
Patrick McHardy96518512013-10-14 11:00:02 +02001135 return ERR_PTR(-EAGAIN);
1136 }
1137#endif
1138 return ERR_PTR(-ENOENT);
1139}
1140
1141static const struct nla_policy nft_expr_policy[NFTA_EXPR_MAX + 1] = {
1142 [NFTA_EXPR_NAME] = { .type = NLA_STRING },
1143 [NFTA_EXPR_DATA] = { .type = NLA_NESTED },
1144};
1145
1146static int nf_tables_fill_expr_info(struct sk_buff *skb,
1147 const struct nft_expr *expr)
1148{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001149 if (nla_put_string(skb, NFTA_EXPR_NAME, expr->ops->type->name))
Patrick McHardy96518512013-10-14 11:00:02 +02001150 goto nla_put_failure;
1151
1152 if (expr->ops->dump) {
1153 struct nlattr *data = nla_nest_start(skb, NFTA_EXPR_DATA);
1154 if (data == NULL)
1155 goto nla_put_failure;
1156 if (expr->ops->dump(skb, expr) < 0)
1157 goto nla_put_failure;
1158 nla_nest_end(skb, data);
1159 }
1160
1161 return skb->len;
1162
1163nla_put_failure:
1164 return -1;
1165};
1166
1167struct nft_expr_info {
1168 const struct nft_expr_ops *ops;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001169 struct nlattr *tb[NFT_EXPR_MAXATTR + 1];
Patrick McHardy96518512013-10-14 11:00:02 +02001170};
1171
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001172static int nf_tables_expr_parse(const struct nft_ctx *ctx,
1173 const struct nlattr *nla,
Patrick McHardy96518512013-10-14 11:00:02 +02001174 struct nft_expr_info *info)
1175{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001176 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001177 const struct nft_expr_ops *ops;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001178 struct nlattr *tb[NFTA_EXPR_MAX + 1];
Patrick McHardy96518512013-10-14 11:00:02 +02001179 int err;
1180
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001181 err = nla_parse_nested(tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
Patrick McHardy96518512013-10-14 11:00:02 +02001182 if (err < 0)
1183 return err;
1184
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001185 type = nft_expr_type_get(tb[NFTA_EXPR_NAME]);
1186 if (IS_ERR(type))
1187 return PTR_ERR(type);
1188
1189 if (tb[NFTA_EXPR_DATA]) {
1190 err = nla_parse_nested(info->tb, type->maxattr,
1191 tb[NFTA_EXPR_DATA], type->policy);
1192 if (err < 0)
1193 goto err1;
1194 } else
1195 memset(info->tb, 0, sizeof(info->tb[0]) * (type->maxattr + 1));
1196
1197 if (type->select_ops != NULL) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001198 ops = type->select_ops(ctx,
1199 (const struct nlattr * const *)info->tb);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001200 if (IS_ERR(ops)) {
1201 err = PTR_ERR(ops);
1202 goto err1;
1203 }
1204 } else
1205 ops = type->ops;
1206
Patrick McHardy96518512013-10-14 11:00:02 +02001207 info->ops = ops;
1208 return 0;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001209
1210err1:
1211 module_put(type->owner);
1212 return err;
Patrick McHardy96518512013-10-14 11:00:02 +02001213}
1214
1215static int nf_tables_newexpr(const struct nft_ctx *ctx,
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001216 const struct nft_expr_info *info,
Patrick McHardy96518512013-10-14 11:00:02 +02001217 struct nft_expr *expr)
1218{
1219 const struct nft_expr_ops *ops = info->ops;
1220 int err;
1221
1222 expr->ops = ops;
1223 if (ops->init) {
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001224 err = ops->init(ctx, expr, (const struct nlattr **)info->tb);
Patrick McHardy96518512013-10-14 11:00:02 +02001225 if (err < 0)
1226 goto err1;
1227 }
1228
Patrick McHardy96518512013-10-14 11:00:02 +02001229 return 0;
1230
1231err1:
1232 expr->ops = NULL;
1233 return err;
1234}
1235
1236static void nf_tables_expr_destroy(struct nft_expr *expr)
1237{
1238 if (expr->ops->destroy)
1239 expr->ops->destroy(expr);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001240 module_put(expr->ops->type->owner);
Patrick McHardy96518512013-10-14 11:00:02 +02001241}
1242
1243/*
1244 * Rules
1245 */
1246
1247static struct nft_rule *__nf_tables_rule_lookup(const struct nft_chain *chain,
1248 u64 handle)
1249{
1250 struct nft_rule *rule;
1251
1252 // FIXME: this sucks
1253 list_for_each_entry(rule, &chain->rules, list) {
1254 if (handle == rule->handle)
1255 return rule;
1256 }
1257
1258 return ERR_PTR(-ENOENT);
1259}
1260
1261static struct nft_rule *nf_tables_rule_lookup(const struct nft_chain *chain,
1262 const struct nlattr *nla)
1263{
1264 if (nla == NULL)
1265 return ERR_PTR(-EINVAL);
1266
1267 return __nf_tables_rule_lookup(chain, be64_to_cpu(nla_get_be64(nla)));
1268}
1269
1270static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
1271 [NFTA_RULE_TABLE] = { .type = NLA_STRING },
1272 [NFTA_RULE_CHAIN] = { .type = NLA_STRING,
1273 .len = NFT_CHAIN_MAXNAMELEN - 1 },
1274 [NFTA_RULE_HANDLE] = { .type = NLA_U64 },
1275 [NFTA_RULE_EXPRESSIONS] = { .type = NLA_NESTED },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001276 [NFTA_RULE_COMPAT] = { .type = NLA_NESTED },
Eric Leblond5e948462013-10-10 13:41:44 +02001277 [NFTA_RULE_POSITION] = { .type = NLA_U64 },
Patrick McHardy96518512013-10-14 11:00:02 +02001278};
1279
1280static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
1281 int event, u32 flags, int family,
1282 const struct nft_table *table,
1283 const struct nft_chain *chain,
1284 const struct nft_rule *rule)
1285{
1286 struct nlmsghdr *nlh;
1287 struct nfgenmsg *nfmsg;
1288 const struct nft_expr *expr, *next;
1289 struct nlattr *list;
Eric Leblond5e948462013-10-10 13:41:44 +02001290 const struct nft_rule *prule;
1291 int type = event | NFNL_SUBSYS_NFTABLES << 8;
Patrick McHardy96518512013-10-14 11:00:02 +02001292
Eric Leblond5e948462013-10-10 13:41:44 +02001293 nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg),
Patrick McHardy96518512013-10-14 11:00:02 +02001294 flags);
1295 if (nlh == NULL)
1296 goto nla_put_failure;
1297
1298 nfmsg = nlmsg_data(nlh);
1299 nfmsg->nfgen_family = family;
1300 nfmsg->version = NFNETLINK_V0;
1301 nfmsg->res_id = 0;
1302
1303 if (nla_put_string(skb, NFTA_RULE_TABLE, table->name))
1304 goto nla_put_failure;
1305 if (nla_put_string(skb, NFTA_RULE_CHAIN, chain->name))
1306 goto nla_put_failure;
1307 if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
1308 goto nla_put_failure;
1309
Eric Leblond5e948462013-10-10 13:41:44 +02001310 if ((event != NFT_MSG_DELRULE) && (rule->list.prev != &chain->rules)) {
1311 prule = list_entry(rule->list.prev, struct nft_rule, list);
1312 if (nla_put_be64(skb, NFTA_RULE_POSITION,
1313 cpu_to_be64(prule->handle)))
1314 goto nla_put_failure;
1315 }
1316
Patrick McHardy96518512013-10-14 11:00:02 +02001317 list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
1318 if (list == NULL)
1319 goto nla_put_failure;
1320 nft_rule_for_each_expr(expr, next, rule) {
1321 struct nlattr *elem = nla_nest_start(skb, NFTA_LIST_ELEM);
1322 if (elem == NULL)
1323 goto nla_put_failure;
1324 if (nf_tables_fill_expr_info(skb, expr) < 0)
1325 goto nla_put_failure;
1326 nla_nest_end(skb, elem);
1327 }
1328 nla_nest_end(skb, list);
1329
1330 return nlmsg_end(skb, nlh);
1331
1332nla_put_failure:
1333 nlmsg_trim(skb, nlh);
1334 return -1;
1335}
1336
1337static int nf_tables_rule_notify(const struct sk_buff *oskb,
1338 const struct nlmsghdr *nlh,
1339 const struct nft_table *table,
1340 const struct nft_chain *chain,
1341 const struct nft_rule *rule,
1342 int event, u32 flags, int family)
1343{
1344 struct sk_buff *skb;
1345 u32 portid = NETLINK_CB(oskb).portid;
1346 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
1347 u32 seq = nlh->nlmsg_seq;
1348 bool report;
1349 int err;
1350
1351 report = nlmsg_report(nlh);
1352 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
1353 return 0;
1354
1355 err = -ENOBUFS;
1356 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1357 if (skb == NULL)
1358 goto err;
1359
1360 err = nf_tables_fill_rule_info(skb, portid, seq, event, flags,
1361 family, table, chain, rule);
1362 if (err < 0) {
1363 kfree_skb(skb);
1364 goto err;
1365 }
1366
1367 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
1368 GFP_KERNEL);
1369err:
1370 if (err < 0)
1371 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
1372 return err;
1373}
1374
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001375static inline bool
1376nft_rule_is_active(struct net *net, const struct nft_rule *rule)
1377{
1378 return (rule->genmask & (1 << net->nft.gencursor)) == 0;
1379}
1380
1381static inline int gencursor_next(struct net *net)
1382{
1383 return net->nft.gencursor+1 == 1 ? 1 : 0;
1384}
1385
1386static inline int
1387nft_rule_is_active_next(struct net *net, const struct nft_rule *rule)
1388{
1389 return (rule->genmask & (1 << gencursor_next(net))) == 0;
1390}
1391
1392static inline void
1393nft_rule_activate_next(struct net *net, struct nft_rule *rule)
1394{
1395 /* Now inactive, will be active in the future */
1396 rule->genmask = (1 << net->nft.gencursor);
1397}
1398
1399static inline void
1400nft_rule_disactivate_next(struct net *net, struct nft_rule *rule)
1401{
1402 rule->genmask = (1 << gencursor_next(net));
1403}
1404
1405static inline void nft_rule_clear(struct net *net, struct nft_rule *rule)
1406{
1407 rule->genmask = 0;
1408}
1409
Patrick McHardy96518512013-10-14 11:00:02 +02001410static int nf_tables_dump_rules(struct sk_buff *skb,
1411 struct netlink_callback *cb)
1412{
1413 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
1414 const struct nft_af_info *afi;
1415 const struct nft_table *table;
1416 const struct nft_chain *chain;
1417 const struct nft_rule *rule;
1418 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001419 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001420 int family = nfmsg->nfgen_family;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001421 u8 genctr = ACCESS_ONCE(net->nft.genctr);
1422 u8 gencursor = ACCESS_ONCE(net->nft.gencursor);
Patrick McHardy96518512013-10-14 11:00:02 +02001423
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001424 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +02001425 if (family != NFPROTO_UNSPEC && family != afi->family)
1426 continue;
1427
1428 list_for_each_entry(table, &afi->tables, list) {
1429 list_for_each_entry(chain, &table->chains, list) {
1430 list_for_each_entry(rule, &chain->rules, list) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001431 if (!nft_rule_is_active(net, rule))
1432 goto cont;
Patrick McHardy96518512013-10-14 11:00:02 +02001433 if (idx < s_idx)
1434 goto cont;
1435 if (idx > s_idx)
1436 memset(&cb->args[1], 0,
1437 sizeof(cb->args) - sizeof(cb->args[0]));
1438 if (nf_tables_fill_rule_info(skb, NETLINK_CB(cb->skb).portid,
1439 cb->nlh->nlmsg_seq,
1440 NFT_MSG_NEWRULE,
1441 NLM_F_MULTI | NLM_F_APPEND,
1442 afi->family, table, chain, rule) < 0)
1443 goto done;
1444cont:
1445 idx++;
1446 }
1447 }
1448 }
1449 }
1450done:
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001451 /* Invalidate this dump, a transition to the new generation happened */
1452 if (gencursor != net->nft.gencursor || genctr != net->nft.genctr)
1453 return -EBUSY;
1454
Patrick McHardy96518512013-10-14 11:00:02 +02001455 cb->args[0] = idx;
1456 return skb->len;
1457}
1458
1459static int nf_tables_getrule(struct sock *nlsk, struct sk_buff *skb,
1460 const struct nlmsghdr *nlh,
1461 const struct nlattr * const nla[])
1462{
1463 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1464 const struct nft_af_info *afi;
1465 const struct nft_table *table;
1466 const struct nft_chain *chain;
1467 const struct nft_rule *rule;
1468 struct sk_buff *skb2;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001469 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001470 int family = nfmsg->nfgen_family;
1471 int err;
1472
1473 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1474 struct netlink_dump_control c = {
1475 .dump = nf_tables_dump_rules,
1476 };
1477 return netlink_dump_start(nlsk, skb, nlh, &c);
1478 }
1479
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001480 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001481 if (IS_ERR(afi))
1482 return PTR_ERR(afi);
1483
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001484 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001485 if (IS_ERR(table))
1486 return PTR_ERR(table);
1487
1488 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1489 if (IS_ERR(chain))
1490 return PTR_ERR(chain);
1491
1492 rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
1493 if (IS_ERR(rule))
1494 return PTR_ERR(rule);
1495
1496 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1497 if (!skb2)
1498 return -ENOMEM;
1499
1500 err = nf_tables_fill_rule_info(skb2, NETLINK_CB(skb).portid,
1501 nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
1502 family, table, chain, rule);
1503 if (err < 0)
1504 goto err;
1505
1506 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
1507
1508err:
1509 kfree_skb(skb2);
1510 return err;
1511}
1512
1513static void nf_tables_rcu_rule_destroy(struct rcu_head *head)
1514{
1515 struct nft_rule *rule = container_of(head, struct nft_rule, rcu_head);
1516 struct nft_expr *expr;
1517
1518 /*
1519 * Careful: some expressions might not be initialized in case this
1520 * is called on error from nf_tables_newrule().
1521 */
1522 expr = nft_expr_first(rule);
1523 while (expr->ops && expr != nft_expr_last(rule)) {
1524 nf_tables_expr_destroy(expr);
1525 expr = nft_expr_next(expr);
1526 }
1527 kfree(rule);
1528}
1529
1530static void nf_tables_rule_destroy(struct nft_rule *rule)
1531{
1532 call_rcu(&rule->rcu_head, nf_tables_rcu_rule_destroy);
1533}
1534
1535#define NFT_RULE_MAXEXPRS 128
1536
1537static struct nft_expr_info *info;
1538
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001539static struct nft_rule_trans *
1540nf_tables_trans_add(struct nft_rule *rule, const struct nft_ctx *ctx)
1541{
1542 struct nft_rule_trans *rupd;
1543
1544 rupd = kmalloc(sizeof(struct nft_rule_trans), GFP_KERNEL);
1545 if (rupd == NULL)
1546 return NULL;
1547
1548 rupd->chain = ctx->chain;
1549 rupd->table = ctx->table;
1550 rupd->rule = rule;
1551 rupd->family = ctx->afi->family;
1552 rupd->nlh = ctx->nlh;
1553 list_add_tail(&rupd->list, &ctx->net->nft.commit_list);
1554
1555 return rupd;
1556}
1557
Patrick McHardy96518512013-10-14 11:00:02 +02001558static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
1559 const struct nlmsghdr *nlh,
1560 const struct nlattr * const nla[])
1561{
1562 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1563 const struct nft_af_info *afi;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001564 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001565 struct nft_table *table;
1566 struct nft_chain *chain;
1567 struct nft_rule *rule, *old_rule = NULL;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001568 struct nft_rule_trans *repl = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +02001569 struct nft_expr *expr;
1570 struct nft_ctx ctx;
1571 struct nlattr *tmp;
1572 unsigned int size, i, n;
1573 int err, rem;
1574 bool create;
Eric Leblond5e948462013-10-10 13:41:44 +02001575 u64 handle, pos_handle;
Patrick McHardy96518512013-10-14 11:00:02 +02001576
1577 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
1578
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001579 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
Patrick McHardy96518512013-10-14 11:00:02 +02001580 if (IS_ERR(afi))
1581 return PTR_ERR(afi);
1582
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001583 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001584 if (IS_ERR(table))
1585 return PTR_ERR(table);
1586
1587 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1588 if (IS_ERR(chain))
1589 return PTR_ERR(chain);
1590
1591 if (nla[NFTA_RULE_HANDLE]) {
1592 handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
1593 rule = __nf_tables_rule_lookup(chain, handle);
1594 if (IS_ERR(rule))
1595 return PTR_ERR(rule);
1596
1597 if (nlh->nlmsg_flags & NLM_F_EXCL)
1598 return -EEXIST;
1599 if (nlh->nlmsg_flags & NLM_F_REPLACE)
1600 old_rule = rule;
1601 else
1602 return -EOPNOTSUPP;
1603 } else {
1604 if (!create || nlh->nlmsg_flags & NLM_F_REPLACE)
1605 return -EINVAL;
1606 handle = nf_tables_alloc_handle(table);
1607 }
1608
Eric Leblond5e948462013-10-10 13:41:44 +02001609 if (nla[NFTA_RULE_POSITION]) {
1610 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
1611 return -EOPNOTSUPP;
1612
1613 pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
1614 old_rule = __nf_tables_rule_lookup(chain, pos_handle);
1615 if (IS_ERR(old_rule))
1616 return PTR_ERR(old_rule);
1617 }
1618
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001619 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1620
Patrick McHardy96518512013-10-14 11:00:02 +02001621 n = 0;
1622 size = 0;
1623 if (nla[NFTA_RULE_EXPRESSIONS]) {
1624 nla_for_each_nested(tmp, nla[NFTA_RULE_EXPRESSIONS], rem) {
1625 err = -EINVAL;
1626 if (nla_type(tmp) != NFTA_LIST_ELEM)
1627 goto err1;
1628 if (n == NFT_RULE_MAXEXPRS)
1629 goto err1;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001630 err = nf_tables_expr_parse(&ctx, tmp, &info[n]);
Patrick McHardy96518512013-10-14 11:00:02 +02001631 if (err < 0)
1632 goto err1;
1633 size += info[n].ops->size;
1634 n++;
1635 }
1636 }
1637
1638 err = -ENOMEM;
1639 rule = kzalloc(sizeof(*rule) + size, GFP_KERNEL);
1640 if (rule == NULL)
1641 goto err1;
1642
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001643 nft_rule_activate_next(net, rule);
1644
Patrick McHardy96518512013-10-14 11:00:02 +02001645 rule->handle = handle;
1646 rule->dlen = size;
1647
Patrick McHardy96518512013-10-14 11:00:02 +02001648 expr = nft_expr_first(rule);
1649 for (i = 0; i < n; i++) {
1650 err = nf_tables_newexpr(&ctx, &info[i], expr);
1651 if (err < 0)
1652 goto err2;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001653 info[i].ops = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +02001654 expr = nft_expr_next(expr);
1655 }
1656
Patrick McHardy96518512013-10-14 11:00:02 +02001657 if (nlh->nlmsg_flags & NLM_F_REPLACE) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001658 if (nft_rule_is_active_next(net, old_rule)) {
1659 repl = nf_tables_trans_add(old_rule, &ctx);
1660 if (repl == NULL) {
1661 err = -ENOMEM;
1662 goto err2;
1663 }
1664 nft_rule_disactivate_next(net, old_rule);
1665 list_add_tail(&rule->list, &old_rule->list);
1666 } else {
1667 err = -ENOENT;
1668 goto err2;
1669 }
Patrick McHardy96518512013-10-14 11:00:02 +02001670 } else if (nlh->nlmsg_flags & NLM_F_APPEND)
Eric Leblond5e948462013-10-10 13:41:44 +02001671 if (old_rule)
1672 list_add_rcu(&rule->list, &old_rule->list);
1673 else
1674 list_add_tail_rcu(&rule->list, &chain->rules);
1675 else {
1676 if (old_rule)
1677 list_add_tail_rcu(&rule->list, &old_rule->list);
1678 else
1679 list_add_rcu(&rule->list, &chain->rules);
1680 }
Patrick McHardy96518512013-10-14 11:00:02 +02001681
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001682 if (nf_tables_trans_add(rule, &ctx) == NULL) {
1683 err = -ENOMEM;
1684 goto err3;
1685 }
Patrick McHardy96518512013-10-14 11:00:02 +02001686 return 0;
1687
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001688err3:
1689 list_del_rcu(&rule->list);
1690 if (repl) {
1691 list_del_rcu(&repl->rule->list);
1692 list_del(&repl->list);
1693 nft_rule_clear(net, repl->rule);
1694 kfree(repl);
1695 }
Patrick McHardy96518512013-10-14 11:00:02 +02001696err2:
1697 nf_tables_rule_destroy(rule);
1698err1:
1699 for (i = 0; i < n; i++) {
1700 if (info[i].ops != NULL)
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001701 module_put(info[i].ops->type->owner);
Patrick McHardy96518512013-10-14 11:00:02 +02001702 }
1703 return err;
1704}
1705
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001706static int
1707nf_tables_delrule_one(struct nft_ctx *ctx, struct nft_rule *rule)
1708{
1709 /* You cannot delete the same rule twice */
1710 if (nft_rule_is_active_next(ctx->net, rule)) {
1711 if (nf_tables_trans_add(rule, ctx) == NULL)
1712 return -ENOMEM;
1713 nft_rule_disactivate_next(ctx->net, rule);
1714 return 0;
1715 }
1716 return -ENOENT;
1717}
1718
Patrick McHardy96518512013-10-14 11:00:02 +02001719static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
1720 const struct nlmsghdr *nlh,
1721 const struct nlattr * const nla[])
1722{
1723 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1724 const struct nft_af_info *afi;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001725 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001726 const struct nft_table *table;
1727 struct nft_chain *chain;
1728 struct nft_rule *rule, *tmp;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001729 int family = nfmsg->nfgen_family, err = 0;
1730 struct nft_ctx ctx;
Patrick McHardy96518512013-10-14 11:00:02 +02001731
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001732 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001733 if (IS_ERR(afi))
1734 return PTR_ERR(afi);
1735
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001736 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001737 if (IS_ERR(table))
1738 return PTR_ERR(table);
1739
1740 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1741 if (IS_ERR(chain))
1742 return PTR_ERR(chain);
1743
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001744 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1745
Patrick McHardy96518512013-10-14 11:00:02 +02001746 if (nla[NFTA_RULE_HANDLE]) {
1747 rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
1748 if (IS_ERR(rule))
1749 return PTR_ERR(rule);
1750
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001751 err = nf_tables_delrule_one(&ctx, rule);
Patrick McHardy96518512013-10-14 11:00:02 +02001752 } else {
1753 /* Remove all rules in this chain */
1754 list_for_each_entry_safe(rule, tmp, &chain->rules, list) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001755 err = nf_tables_delrule_one(&ctx, rule);
1756 if (err < 0)
1757 break;
Patrick McHardy96518512013-10-14 11:00:02 +02001758 }
1759 }
1760
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001761 return err;
1762}
1763
1764static int nf_tables_commit(struct sk_buff *skb)
1765{
1766 struct net *net = sock_net(skb->sk);
1767 struct nft_rule_trans *rupd, *tmp;
1768
1769 /* Bump generation counter, invalidate any dump in progress */
1770 net->nft.genctr++;
1771
1772 /* A new generation has just started */
1773 net->nft.gencursor = gencursor_next(net);
1774
1775 /* Make sure all packets have left the previous generation before
1776 * purging old rules.
1777 */
1778 synchronize_rcu();
1779
1780 list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
1781 /* Delete this rule from the dirty list */
1782 list_del(&rupd->list);
1783
1784 /* This rule was inactive in the past and just became active.
1785 * Clear the next bit of the genmask since its meaning has
1786 * changed, now it is the future.
1787 */
1788 if (nft_rule_is_active(net, rupd->rule)) {
1789 nft_rule_clear(net, rupd->rule);
1790 nf_tables_rule_notify(skb, rupd->nlh, rupd->table,
1791 rupd->chain, rupd->rule,
1792 NFT_MSG_NEWRULE, 0,
1793 rupd->family);
1794 kfree(rupd);
1795 continue;
1796 }
1797
1798 /* This rule is in the past, get rid of it */
1799 list_del_rcu(&rupd->rule->list);
1800 nf_tables_rule_notify(skb, rupd->nlh, rupd->table, rupd->chain,
1801 rupd->rule, NFT_MSG_DELRULE, 0,
1802 rupd->family);
1803 nf_tables_rule_destroy(rupd->rule);
1804 kfree(rupd);
1805 }
1806
1807 return 0;
1808}
1809
1810static int nf_tables_abort(struct sk_buff *skb)
1811{
1812 struct net *net = sock_net(skb->sk);
1813 struct nft_rule_trans *rupd, *tmp;
1814
1815 list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
1816 /* Delete all rules from the dirty list */
1817 list_del(&rupd->list);
1818
1819 if (!nft_rule_is_active_next(net, rupd->rule)) {
1820 nft_rule_clear(net, rupd->rule);
1821 kfree(rupd);
1822 continue;
1823 }
1824
1825 /* This rule is inactive, get rid of it */
1826 list_del_rcu(&rupd->rule->list);
1827 nf_tables_rule_destroy(rupd->rule);
1828 kfree(rupd);
1829 }
Patrick McHardy96518512013-10-14 11:00:02 +02001830 return 0;
1831}
1832
Patrick McHardy20a69342013-10-11 12:06:22 +02001833/*
1834 * Sets
1835 */
1836
1837static LIST_HEAD(nf_tables_set_ops);
1838
1839int nft_register_set(struct nft_set_ops *ops)
1840{
1841 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1842 list_add_tail(&ops->list, &nf_tables_set_ops);
1843 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1844 return 0;
1845}
1846EXPORT_SYMBOL_GPL(nft_register_set);
1847
1848void nft_unregister_set(struct nft_set_ops *ops)
1849{
1850 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1851 list_del(&ops->list);
1852 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1853}
1854EXPORT_SYMBOL_GPL(nft_unregister_set);
1855
1856static const struct nft_set_ops *nft_select_set_ops(const struct nlattr * const nla[])
1857{
1858 const struct nft_set_ops *ops;
1859 u32 features;
1860
1861#ifdef CONFIG_MODULES
1862 if (list_empty(&nf_tables_set_ops)) {
1863 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1864 request_module("nft-set");
1865 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1866 if (!list_empty(&nf_tables_set_ops))
1867 return ERR_PTR(-EAGAIN);
1868 }
1869#endif
1870 features = 0;
1871 if (nla[NFTA_SET_FLAGS] != NULL) {
1872 features = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
1873 features &= NFT_SET_INTERVAL | NFT_SET_MAP;
1874 }
1875
1876 // FIXME: implement selection properly
1877 list_for_each_entry(ops, &nf_tables_set_ops, list) {
1878 if ((ops->features & features) != features)
1879 continue;
1880 if (!try_module_get(ops->owner))
1881 continue;
1882 return ops;
1883 }
1884
1885 return ERR_PTR(-EOPNOTSUPP);
1886}
1887
1888static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
1889 [NFTA_SET_TABLE] = { .type = NLA_STRING },
1890 [NFTA_SET_NAME] = { .type = NLA_STRING },
1891 [NFTA_SET_FLAGS] = { .type = NLA_U32 },
1892 [NFTA_SET_KEY_TYPE] = { .type = NLA_U32 },
1893 [NFTA_SET_KEY_LEN] = { .type = NLA_U32 },
1894 [NFTA_SET_DATA_TYPE] = { .type = NLA_U32 },
1895 [NFTA_SET_DATA_LEN] = { .type = NLA_U32 },
1896};
1897
1898static int nft_ctx_init_from_setattr(struct nft_ctx *ctx,
1899 const struct sk_buff *skb,
1900 const struct nlmsghdr *nlh,
1901 const struct nlattr * const nla[])
1902{
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001903 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02001904 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1905 const struct nft_af_info *afi;
1906 const struct nft_table *table = NULL;
1907
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001908 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
Patrick McHardy20a69342013-10-11 12:06:22 +02001909 if (IS_ERR(afi))
1910 return PTR_ERR(afi);
1911
1912 if (nla[NFTA_SET_TABLE] != NULL) {
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001913 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02001914 if (IS_ERR(table))
1915 return PTR_ERR(table);
1916 }
1917
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001918 nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02001919 return 0;
1920}
1921
1922struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
1923 const struct nlattr *nla)
1924{
1925 struct nft_set *set;
1926
1927 if (nla == NULL)
1928 return ERR_PTR(-EINVAL);
1929
1930 list_for_each_entry(set, &table->sets, list) {
1931 if (!nla_strcmp(nla, set->name))
1932 return set;
1933 }
1934 return ERR_PTR(-ENOENT);
1935}
1936
1937static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
1938 const char *name)
1939{
1940 const struct nft_set *i;
1941 const char *p;
1942 unsigned long *inuse;
1943 unsigned int n = 0;
1944
1945 p = strnchr(name, IFNAMSIZ, '%');
1946 if (p != NULL) {
1947 if (p[1] != 'd' || strchr(p + 2, '%'))
1948 return -EINVAL;
1949
1950 inuse = (unsigned long *)get_zeroed_page(GFP_KERNEL);
1951 if (inuse == NULL)
1952 return -ENOMEM;
1953
1954 list_for_each_entry(i, &ctx->table->sets, list) {
1955 if (!sscanf(i->name, name, &n))
1956 continue;
1957 if (n < 0 || n > BITS_PER_LONG * PAGE_SIZE)
1958 continue;
1959 set_bit(n, inuse);
1960 }
1961
1962 n = find_first_zero_bit(inuse, BITS_PER_LONG * PAGE_SIZE);
1963 free_page((unsigned long)inuse);
1964 }
1965
1966 snprintf(set->name, sizeof(set->name), name, n);
1967 list_for_each_entry(i, &ctx->table->sets, list) {
1968 if (!strcmp(set->name, i->name))
1969 return -ENFILE;
1970 }
1971 return 0;
1972}
1973
1974static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
1975 const struct nft_set *set, u16 event, u16 flags)
1976{
1977 struct nfgenmsg *nfmsg;
1978 struct nlmsghdr *nlh;
1979 u32 portid = NETLINK_CB(ctx->skb).portid;
1980 u32 seq = ctx->nlh->nlmsg_seq;
1981
1982 event |= NFNL_SUBSYS_NFTABLES << 8;
1983 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
1984 flags);
1985 if (nlh == NULL)
1986 goto nla_put_failure;
1987
1988 nfmsg = nlmsg_data(nlh);
1989 nfmsg->nfgen_family = ctx->afi->family;
1990 nfmsg->version = NFNETLINK_V0;
1991 nfmsg->res_id = 0;
1992
1993 if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
1994 goto nla_put_failure;
1995 if (nla_put_string(skb, NFTA_SET_NAME, set->name))
1996 goto nla_put_failure;
1997 if (set->flags != 0)
1998 if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
1999 goto nla_put_failure;
2000
2001 if (nla_put_be32(skb, NFTA_SET_KEY_TYPE, htonl(set->ktype)))
2002 goto nla_put_failure;
2003 if (nla_put_be32(skb, NFTA_SET_KEY_LEN, htonl(set->klen)))
2004 goto nla_put_failure;
2005 if (set->flags & NFT_SET_MAP) {
2006 if (nla_put_be32(skb, NFTA_SET_DATA_TYPE, htonl(set->dtype)))
2007 goto nla_put_failure;
2008 if (nla_put_be32(skb, NFTA_SET_DATA_LEN, htonl(set->dlen)))
2009 goto nla_put_failure;
2010 }
2011
2012 return nlmsg_end(skb, nlh);
2013
2014nla_put_failure:
2015 nlmsg_trim(skb, nlh);
2016 return -1;
2017}
2018
2019static int nf_tables_set_notify(const struct nft_ctx *ctx,
2020 const struct nft_set *set,
2021 int event)
2022{
2023 struct sk_buff *skb;
2024 u32 portid = NETLINK_CB(ctx->skb).portid;
Patrick McHardy20a69342013-10-11 12:06:22 +02002025 bool report;
2026 int err;
2027
2028 report = nlmsg_report(ctx->nlh);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002029 if (!report && !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
Patrick McHardy20a69342013-10-11 12:06:22 +02002030 return 0;
2031
2032 err = -ENOBUFS;
2033 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
2034 if (skb == NULL)
2035 goto err;
2036
2037 err = nf_tables_fill_set(skb, ctx, set, event, 0);
2038 if (err < 0) {
2039 kfree_skb(skb);
2040 goto err;
2041 }
2042
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002043 err = nfnetlink_send(skb, ctx->net, portid, NFNLGRP_NFTABLES, report,
Patrick McHardy20a69342013-10-11 12:06:22 +02002044 GFP_KERNEL);
2045err:
2046 if (err < 0)
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002047 nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, err);
Patrick McHardy20a69342013-10-11 12:06:22 +02002048 return err;
2049}
2050
2051static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb,
2052 struct netlink_callback *cb)
2053{
2054 const struct nft_set *set;
2055 unsigned int idx = 0, s_idx = cb->args[0];
2056
2057 if (cb->args[1])
2058 return skb->len;
2059
2060 list_for_each_entry(set, &ctx->table->sets, list) {
2061 if (idx < s_idx)
2062 goto cont;
2063 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
2064 NLM_F_MULTI) < 0) {
2065 cb->args[0] = idx;
2066 goto done;
2067 }
2068cont:
2069 idx++;
2070 }
2071 cb->args[1] = 1;
2072done:
2073 return skb->len;
2074}
2075
2076static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb,
2077 struct netlink_callback *cb)
2078{
2079 const struct nft_set *set;
2080 unsigned int idx = 0, s_idx = cb->args[0];
2081 struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
2082
2083 if (cb->args[1])
2084 return skb->len;
2085
2086 list_for_each_entry(table, &ctx->afi->tables, list) {
2087 if (cur_table && cur_table != table)
2088 continue;
2089
2090 ctx->table = table;
2091 list_for_each_entry(set, &ctx->table->sets, list) {
2092 if (idx < s_idx)
2093 goto cont;
2094 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
2095 NLM_F_MULTI) < 0) {
2096 cb->args[0] = idx;
2097 cb->args[2] = (unsigned long) table;
2098 goto done;
2099 }
2100cont:
2101 idx++;
2102 }
2103 }
2104 cb->args[1] = 1;
2105done:
2106 return skb->len;
2107}
2108
2109static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
2110{
2111 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
2112 struct nlattr *nla[NFTA_SET_MAX + 1];
2113 struct nft_ctx ctx;
2114 int err, ret;
2115
2116 err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_MAX,
2117 nft_set_policy);
2118 if (err < 0)
2119 return err;
2120
2121 err = nft_ctx_init_from_setattr(&ctx, cb->skb, cb->nlh, (void *)nla);
2122 if (err < 0)
2123 return err;
2124
2125 if (ctx.table == NULL)
2126 ret = nf_tables_dump_sets_all(&ctx, skb, cb);
2127 else
2128 ret = nf_tables_dump_sets_table(&ctx, skb, cb);
2129
2130 return ret;
2131}
2132
2133static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
2134 const struct nlmsghdr *nlh,
2135 const struct nlattr * const nla[])
2136{
2137 const struct nft_set *set;
2138 struct nft_ctx ctx;
2139 struct sk_buff *skb2;
2140 int err;
2141
2142 /* Verify existance before starting dump */
2143 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
2144 if (err < 0)
2145 return err;
2146
2147 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2148 struct netlink_dump_control c = {
2149 .dump = nf_tables_dump_sets,
2150 };
2151 return netlink_dump_start(nlsk, skb, nlh, &c);
2152 }
2153
2154 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
2155 if (IS_ERR(set))
2156 return PTR_ERR(set);
2157
2158 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2159 if (skb2 == NULL)
2160 return -ENOMEM;
2161
2162 err = nf_tables_fill_set(skb2, &ctx, set, NFT_MSG_NEWSET, 0);
2163 if (err < 0)
2164 goto err;
2165
2166 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
2167
2168err:
2169 kfree_skb(skb2);
2170 return err;
2171}
2172
2173static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
2174 const struct nlmsghdr *nlh,
2175 const struct nlattr * const nla[])
2176{
2177 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
2178 const struct nft_set_ops *ops;
2179 const struct nft_af_info *afi;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002180 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02002181 struct nft_table *table;
2182 struct nft_set *set;
2183 struct nft_ctx ctx;
2184 char name[IFNAMSIZ];
2185 unsigned int size;
2186 bool create;
2187 u32 ktype, klen, dlen, dtype, flags;
2188 int err;
2189
2190 if (nla[NFTA_SET_TABLE] == NULL ||
2191 nla[NFTA_SET_NAME] == NULL ||
2192 nla[NFTA_SET_KEY_LEN] == NULL)
2193 return -EINVAL;
2194
2195 ktype = NFT_DATA_VALUE;
2196 if (nla[NFTA_SET_KEY_TYPE] != NULL) {
2197 ktype = ntohl(nla_get_be32(nla[NFTA_SET_KEY_TYPE]));
2198 if ((ktype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK)
2199 return -EINVAL;
2200 }
2201
2202 klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
2203 if (klen == 0 || klen > FIELD_SIZEOF(struct nft_data, data))
2204 return -EINVAL;
2205
2206 flags = 0;
2207 if (nla[NFTA_SET_FLAGS] != NULL) {
2208 flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
2209 if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
2210 NFT_SET_INTERVAL | NFT_SET_MAP))
2211 return -EINVAL;
2212 }
2213
2214 dtype = 0;
2215 dlen = 0;
2216 if (nla[NFTA_SET_DATA_TYPE] != NULL) {
2217 if (!(flags & NFT_SET_MAP))
2218 return -EINVAL;
2219
2220 dtype = ntohl(nla_get_be32(nla[NFTA_SET_DATA_TYPE]));
2221 if ((dtype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK &&
2222 dtype != NFT_DATA_VERDICT)
2223 return -EINVAL;
2224
2225 if (dtype != NFT_DATA_VERDICT) {
2226 if (nla[NFTA_SET_DATA_LEN] == NULL)
2227 return -EINVAL;
2228 dlen = ntohl(nla_get_be32(nla[NFTA_SET_DATA_LEN]));
2229 if (dlen == 0 ||
2230 dlen > FIELD_SIZEOF(struct nft_data, data))
2231 return -EINVAL;
2232 } else
2233 dlen = sizeof(struct nft_data);
2234 } else if (flags & NFT_SET_MAP)
2235 return -EINVAL;
2236
2237 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
2238
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002239 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
Patrick McHardy20a69342013-10-11 12:06:22 +02002240 if (IS_ERR(afi))
2241 return PTR_ERR(afi);
2242
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002243 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02002244 if (IS_ERR(table))
2245 return PTR_ERR(table);
2246
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002247 nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002248
2249 set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME]);
2250 if (IS_ERR(set)) {
2251 if (PTR_ERR(set) != -ENOENT)
2252 return PTR_ERR(set);
2253 set = NULL;
2254 }
2255
2256 if (set != NULL) {
2257 if (nlh->nlmsg_flags & NLM_F_EXCL)
2258 return -EEXIST;
2259 if (nlh->nlmsg_flags & NLM_F_REPLACE)
2260 return -EOPNOTSUPP;
2261 return 0;
2262 }
2263
2264 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
2265 return -ENOENT;
2266
2267 ops = nft_select_set_ops(nla);
2268 if (IS_ERR(ops))
2269 return PTR_ERR(ops);
2270
2271 size = 0;
2272 if (ops->privsize != NULL)
2273 size = ops->privsize(nla);
2274
2275 err = -ENOMEM;
2276 set = kzalloc(sizeof(*set) + size, GFP_KERNEL);
2277 if (set == NULL)
2278 goto err1;
2279
2280 nla_strlcpy(name, nla[NFTA_SET_NAME], sizeof(set->name));
2281 err = nf_tables_set_alloc_name(&ctx, set, name);
2282 if (err < 0)
2283 goto err2;
2284
2285 INIT_LIST_HEAD(&set->bindings);
2286 set->ops = ops;
2287 set->ktype = ktype;
2288 set->klen = klen;
2289 set->dtype = dtype;
2290 set->dlen = dlen;
2291 set->flags = flags;
2292
2293 err = ops->init(set, nla);
2294 if (err < 0)
2295 goto err2;
2296
2297 list_add_tail(&set->list, &table->sets);
2298 nf_tables_set_notify(&ctx, set, NFT_MSG_NEWSET);
2299 return 0;
2300
2301err2:
2302 kfree(set);
2303err1:
2304 module_put(ops->owner);
2305 return err;
2306}
2307
2308static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
2309{
2310 list_del(&set->list);
2311 if (!(set->flags & NFT_SET_ANONYMOUS))
2312 nf_tables_set_notify(ctx, set, NFT_MSG_DELSET);
2313
2314 set->ops->destroy(set);
2315 module_put(set->ops->owner);
2316 kfree(set);
2317}
2318
2319static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
2320 const struct nlmsghdr *nlh,
2321 const struct nlattr * const nla[])
2322{
2323 struct nft_set *set;
2324 struct nft_ctx ctx;
2325 int err;
2326
2327 if (nla[NFTA_SET_TABLE] == NULL)
2328 return -EINVAL;
2329
2330 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
2331 if (err < 0)
2332 return err;
2333
2334 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
2335 if (IS_ERR(set))
2336 return PTR_ERR(set);
2337 if (!list_empty(&set->bindings))
2338 return -EBUSY;
2339
2340 nf_tables_set_destroy(&ctx, set);
2341 return 0;
2342}
2343
2344static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
2345 const struct nft_set *set,
2346 const struct nft_set_iter *iter,
2347 const struct nft_set_elem *elem)
2348{
2349 enum nft_registers dreg;
2350
2351 dreg = nft_type_to_reg(set->dtype);
2352 return nft_validate_data_load(ctx, dreg, &elem->data, set->dtype);
2353}
2354
2355int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
2356 struct nft_set_binding *binding)
2357{
2358 struct nft_set_binding *i;
2359 struct nft_set_iter iter;
2360
2361 if (!list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
2362 return -EBUSY;
2363
2364 if (set->flags & NFT_SET_MAP) {
2365 /* If the set is already bound to the same chain all
2366 * jumps are already validated for that chain.
2367 */
2368 list_for_each_entry(i, &set->bindings, list) {
2369 if (i->chain == binding->chain)
2370 goto bind;
2371 }
2372
2373 iter.skip = 0;
2374 iter.count = 0;
2375 iter.err = 0;
2376 iter.fn = nf_tables_bind_check_setelem;
2377
2378 set->ops->walk(ctx, set, &iter);
2379 if (iter.err < 0) {
2380 /* Destroy anonymous sets if binding fails */
2381 if (set->flags & NFT_SET_ANONYMOUS)
2382 nf_tables_set_destroy(ctx, set);
2383
2384 return iter.err;
2385 }
2386 }
2387bind:
2388 binding->chain = ctx->chain;
2389 list_add_tail(&binding->list, &set->bindings);
2390 return 0;
2391}
2392
2393void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
2394 struct nft_set_binding *binding)
2395{
2396 list_del(&binding->list);
2397
2398 if (list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
2399 nf_tables_set_destroy(ctx, set);
2400}
2401
2402/*
2403 * Set elements
2404 */
2405
2406static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
2407 [NFTA_SET_ELEM_KEY] = { .type = NLA_NESTED },
2408 [NFTA_SET_ELEM_DATA] = { .type = NLA_NESTED },
2409 [NFTA_SET_ELEM_FLAGS] = { .type = NLA_U32 },
2410};
2411
2412static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
2413 [NFTA_SET_ELEM_LIST_TABLE] = { .type = NLA_STRING },
2414 [NFTA_SET_ELEM_LIST_SET] = { .type = NLA_STRING },
2415 [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NLA_NESTED },
2416};
2417
2418static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx,
2419 const struct sk_buff *skb,
2420 const struct nlmsghdr *nlh,
2421 const struct nlattr * const nla[])
2422{
2423 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
2424 const struct nft_af_info *afi;
2425 const struct nft_table *table;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002426 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02002427
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002428 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
Patrick McHardy20a69342013-10-11 12:06:22 +02002429 if (IS_ERR(afi))
2430 return PTR_ERR(afi);
2431
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002432 table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02002433 if (IS_ERR(table))
2434 return PTR_ERR(table);
2435
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002436 nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002437 return 0;
2438}
2439
2440static int nf_tables_fill_setelem(struct sk_buff *skb,
2441 const struct nft_set *set,
2442 const struct nft_set_elem *elem)
2443{
2444 unsigned char *b = skb_tail_pointer(skb);
2445 struct nlattr *nest;
2446
2447 nest = nla_nest_start(skb, NFTA_LIST_ELEM);
2448 if (nest == NULL)
2449 goto nla_put_failure;
2450
2451 if (nft_data_dump(skb, NFTA_SET_ELEM_KEY, &elem->key, NFT_DATA_VALUE,
2452 set->klen) < 0)
2453 goto nla_put_failure;
2454
2455 if (set->flags & NFT_SET_MAP &&
2456 !(elem->flags & NFT_SET_ELEM_INTERVAL_END) &&
2457 nft_data_dump(skb, NFTA_SET_ELEM_DATA, &elem->data,
2458 set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE,
2459 set->dlen) < 0)
2460 goto nla_put_failure;
2461
2462 if (elem->flags != 0)
2463 if (nla_put_be32(skb, NFTA_SET_ELEM_FLAGS, htonl(elem->flags)))
2464 goto nla_put_failure;
2465
2466 nla_nest_end(skb, nest);
2467 return 0;
2468
2469nla_put_failure:
2470 nlmsg_trim(skb, b);
2471 return -EMSGSIZE;
2472}
2473
2474struct nft_set_dump_args {
2475 const struct netlink_callback *cb;
2476 struct nft_set_iter iter;
2477 struct sk_buff *skb;
2478};
2479
2480static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
2481 const struct nft_set *set,
2482 const struct nft_set_iter *iter,
2483 const struct nft_set_elem *elem)
2484{
2485 struct nft_set_dump_args *args;
2486
2487 args = container_of(iter, struct nft_set_dump_args, iter);
2488 return nf_tables_fill_setelem(args->skb, set, elem);
2489}
2490
2491static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
2492{
2493 const struct nft_set *set;
2494 struct nft_set_dump_args args;
2495 struct nft_ctx ctx;
2496 struct nlattr *nla[NFTA_SET_ELEM_LIST_MAX + 1];
2497 struct nfgenmsg *nfmsg;
2498 struct nlmsghdr *nlh;
2499 struct nlattr *nest;
2500 u32 portid, seq;
2501 int event, err;
2502
2503 nfmsg = nlmsg_data(cb->nlh);
2504 err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_ELEM_LIST_MAX,
2505 nft_set_elem_list_policy);
2506 if (err < 0)
2507 return err;
2508
2509 err = nft_ctx_init_from_elemattr(&ctx, cb->skb, cb->nlh, (void *)nla);
2510 if (err < 0)
2511 return err;
2512
2513 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2514 if (IS_ERR(set))
2515 return PTR_ERR(set);
2516
2517 event = NFT_MSG_NEWSETELEM;
2518 event |= NFNL_SUBSYS_NFTABLES << 8;
2519 portid = NETLINK_CB(cb->skb).portid;
2520 seq = cb->nlh->nlmsg_seq;
2521
2522 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
2523 NLM_F_MULTI);
2524 if (nlh == NULL)
2525 goto nla_put_failure;
2526
2527 nfmsg = nlmsg_data(nlh);
2528 nfmsg->nfgen_family = NFPROTO_UNSPEC;
2529 nfmsg->version = NFNETLINK_V0;
2530 nfmsg->res_id = 0;
2531
2532 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, ctx.table->name))
2533 goto nla_put_failure;
2534 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_SET, set->name))
2535 goto nla_put_failure;
2536
2537 nest = nla_nest_start(skb, NFTA_SET_ELEM_LIST_ELEMENTS);
2538 if (nest == NULL)
2539 goto nla_put_failure;
2540
2541 args.cb = cb;
2542 args.skb = skb;
2543 args.iter.skip = cb->args[0];
2544 args.iter.count = 0;
2545 args.iter.err = 0;
2546 args.iter.fn = nf_tables_dump_setelem;
2547 set->ops->walk(&ctx, set, &args.iter);
2548
2549 nla_nest_end(skb, nest);
2550 nlmsg_end(skb, nlh);
2551
2552 if (args.iter.err && args.iter.err != -EMSGSIZE)
2553 return args.iter.err;
2554 if (args.iter.count == cb->args[0])
2555 return 0;
2556
2557 cb->args[0] = args.iter.count;
2558 return skb->len;
2559
2560nla_put_failure:
2561 return -ENOSPC;
2562}
2563
2564static int nf_tables_getsetelem(struct sock *nlsk, struct sk_buff *skb,
2565 const struct nlmsghdr *nlh,
2566 const struct nlattr * const nla[])
2567{
2568 const struct nft_set *set;
2569 struct nft_ctx ctx;
2570 int err;
2571
2572 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2573 if (err < 0)
2574 return err;
2575
2576 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2577 if (IS_ERR(set))
2578 return PTR_ERR(set);
2579
2580 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2581 struct netlink_dump_control c = {
2582 .dump = nf_tables_dump_set,
2583 };
2584 return netlink_dump_start(nlsk, skb, nlh, &c);
2585 }
2586 return -EOPNOTSUPP;
2587}
2588
2589static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set,
2590 const struct nlattr *attr)
2591{
2592 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
2593 struct nft_data_desc d1, d2;
2594 struct nft_set_elem elem;
2595 struct nft_set_binding *binding;
2596 enum nft_registers dreg;
2597 int err;
2598
2599 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
2600 nft_set_elem_policy);
2601 if (err < 0)
2602 return err;
2603
2604 if (nla[NFTA_SET_ELEM_KEY] == NULL)
2605 return -EINVAL;
2606
2607 elem.flags = 0;
2608 if (nla[NFTA_SET_ELEM_FLAGS] != NULL) {
2609 elem.flags = ntohl(nla_get_be32(nla[NFTA_SET_ELEM_FLAGS]));
2610 if (elem.flags & ~NFT_SET_ELEM_INTERVAL_END)
2611 return -EINVAL;
2612 }
2613
2614 if (set->flags & NFT_SET_MAP) {
2615 if (nla[NFTA_SET_ELEM_DATA] == NULL &&
2616 !(elem.flags & NFT_SET_ELEM_INTERVAL_END))
2617 return -EINVAL;
2618 } else {
2619 if (nla[NFTA_SET_ELEM_DATA] != NULL)
2620 return -EINVAL;
2621 }
2622
2623 err = nft_data_init(ctx, &elem.key, &d1, nla[NFTA_SET_ELEM_KEY]);
2624 if (err < 0)
2625 goto err1;
2626 err = -EINVAL;
2627 if (d1.type != NFT_DATA_VALUE || d1.len != set->klen)
2628 goto err2;
2629
2630 err = -EEXIST;
2631 if (set->ops->get(set, &elem) == 0)
2632 goto err2;
2633
2634 if (nla[NFTA_SET_ELEM_DATA] != NULL) {
2635 err = nft_data_init(ctx, &elem.data, &d2, nla[NFTA_SET_ELEM_DATA]);
2636 if (err < 0)
2637 goto err2;
2638
2639 err = -EINVAL;
2640 if (set->dtype != NFT_DATA_VERDICT && d2.len != set->dlen)
2641 goto err3;
2642
2643 dreg = nft_type_to_reg(set->dtype);
2644 list_for_each_entry(binding, &set->bindings, list) {
2645 struct nft_ctx bind_ctx = {
2646 .afi = ctx->afi,
2647 .table = ctx->table,
2648 .chain = binding->chain,
2649 };
2650
2651 err = nft_validate_data_load(&bind_ctx, dreg,
2652 &elem.data, d2.type);
2653 if (err < 0)
2654 goto err3;
2655 }
2656 }
2657
2658 err = set->ops->insert(set, &elem);
2659 if (err < 0)
2660 goto err3;
2661
2662 return 0;
2663
2664err3:
2665 if (nla[NFTA_SET_ELEM_DATA] != NULL)
2666 nft_data_uninit(&elem.data, d2.type);
2667err2:
2668 nft_data_uninit(&elem.key, d1.type);
2669err1:
2670 return err;
2671}
2672
2673static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
2674 const struct nlmsghdr *nlh,
2675 const struct nlattr * const nla[])
2676{
2677 const struct nlattr *attr;
2678 struct nft_set *set;
2679 struct nft_ctx ctx;
2680 int rem, err;
2681
2682 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2683 if (err < 0)
2684 return err;
2685
2686 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2687 if (IS_ERR(set))
2688 return PTR_ERR(set);
2689 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
2690 return -EBUSY;
2691
2692 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
2693 err = nft_add_set_elem(&ctx, set, attr);
2694 if (err < 0)
2695 return err;
2696 }
2697 return 0;
2698}
2699
2700static int nft_del_setelem(const struct nft_ctx *ctx, struct nft_set *set,
2701 const struct nlattr *attr)
2702{
2703 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
2704 struct nft_data_desc desc;
2705 struct nft_set_elem elem;
2706 int err;
2707
2708 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
2709 nft_set_elem_policy);
2710 if (err < 0)
2711 goto err1;
2712
2713 err = -EINVAL;
2714 if (nla[NFTA_SET_ELEM_KEY] == NULL)
2715 goto err1;
2716
2717 err = nft_data_init(ctx, &elem.key, &desc, nla[NFTA_SET_ELEM_KEY]);
2718 if (err < 0)
2719 goto err1;
2720
2721 err = -EINVAL;
2722 if (desc.type != NFT_DATA_VALUE || desc.len != set->klen)
2723 goto err2;
2724
2725 err = set->ops->get(set, &elem);
2726 if (err < 0)
2727 goto err2;
2728
2729 set->ops->remove(set, &elem);
2730
2731 nft_data_uninit(&elem.key, NFT_DATA_VALUE);
2732 if (set->flags & NFT_SET_MAP)
2733 nft_data_uninit(&elem.data, set->dtype);
2734
2735err2:
2736 nft_data_uninit(&elem.key, desc.type);
2737err1:
2738 return err;
2739}
2740
2741static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
2742 const struct nlmsghdr *nlh,
2743 const struct nlattr * const nla[])
2744{
2745 const struct nlattr *attr;
2746 struct nft_set *set;
2747 struct nft_ctx ctx;
2748 int rem, err;
2749
2750 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2751 if (err < 0)
2752 return err;
2753
2754 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2755 if (IS_ERR(set))
2756 return PTR_ERR(set);
2757 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
2758 return -EBUSY;
2759
2760 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
2761 err = nft_del_setelem(&ctx, set, attr);
2762 if (err < 0)
2763 return err;
2764 }
2765 return 0;
2766}
2767
Patrick McHardy96518512013-10-14 11:00:02 +02002768static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
2769 [NFT_MSG_NEWTABLE] = {
2770 .call = nf_tables_newtable,
2771 .attr_count = NFTA_TABLE_MAX,
2772 .policy = nft_table_policy,
2773 },
2774 [NFT_MSG_GETTABLE] = {
2775 .call = nf_tables_gettable,
2776 .attr_count = NFTA_TABLE_MAX,
2777 .policy = nft_table_policy,
2778 },
2779 [NFT_MSG_DELTABLE] = {
2780 .call = nf_tables_deltable,
2781 .attr_count = NFTA_TABLE_MAX,
2782 .policy = nft_table_policy,
2783 },
2784 [NFT_MSG_NEWCHAIN] = {
2785 .call = nf_tables_newchain,
2786 .attr_count = NFTA_CHAIN_MAX,
2787 .policy = nft_chain_policy,
2788 },
2789 [NFT_MSG_GETCHAIN] = {
2790 .call = nf_tables_getchain,
2791 .attr_count = NFTA_CHAIN_MAX,
2792 .policy = nft_chain_policy,
2793 },
2794 [NFT_MSG_DELCHAIN] = {
2795 .call = nf_tables_delchain,
2796 .attr_count = NFTA_CHAIN_MAX,
2797 .policy = nft_chain_policy,
2798 },
2799 [NFT_MSG_NEWRULE] = {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002800 .call_batch = nf_tables_newrule,
Patrick McHardy96518512013-10-14 11:00:02 +02002801 .attr_count = NFTA_RULE_MAX,
2802 .policy = nft_rule_policy,
2803 },
2804 [NFT_MSG_GETRULE] = {
2805 .call = nf_tables_getrule,
2806 .attr_count = NFTA_RULE_MAX,
2807 .policy = nft_rule_policy,
2808 },
2809 [NFT_MSG_DELRULE] = {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002810 .call_batch = nf_tables_delrule,
Patrick McHardy96518512013-10-14 11:00:02 +02002811 .attr_count = NFTA_RULE_MAX,
2812 .policy = nft_rule_policy,
2813 },
Patrick McHardy20a69342013-10-11 12:06:22 +02002814 [NFT_MSG_NEWSET] = {
2815 .call = nf_tables_newset,
2816 .attr_count = NFTA_SET_MAX,
2817 .policy = nft_set_policy,
2818 },
2819 [NFT_MSG_GETSET] = {
2820 .call = nf_tables_getset,
2821 .attr_count = NFTA_SET_MAX,
2822 .policy = nft_set_policy,
2823 },
2824 [NFT_MSG_DELSET] = {
2825 .call = nf_tables_delset,
2826 .attr_count = NFTA_SET_MAX,
2827 .policy = nft_set_policy,
2828 },
2829 [NFT_MSG_NEWSETELEM] = {
2830 .call = nf_tables_newsetelem,
2831 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2832 .policy = nft_set_elem_list_policy,
2833 },
2834 [NFT_MSG_GETSETELEM] = {
2835 .call = nf_tables_getsetelem,
2836 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2837 .policy = nft_set_elem_list_policy,
2838 },
2839 [NFT_MSG_DELSETELEM] = {
2840 .call = nf_tables_delsetelem,
2841 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2842 .policy = nft_set_elem_list_policy,
2843 },
Patrick McHardy96518512013-10-14 11:00:02 +02002844};
2845
2846static const struct nfnetlink_subsystem nf_tables_subsys = {
2847 .name = "nf_tables",
2848 .subsys_id = NFNL_SUBSYS_NFTABLES,
2849 .cb_count = NFT_MSG_MAX,
2850 .cb = nf_tables_cb,
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02002851 .commit = nf_tables_commit,
2852 .abort = nf_tables_abort,
Patrick McHardy96518512013-10-14 11:00:02 +02002853};
2854
Patrick McHardy20a69342013-10-11 12:06:22 +02002855/*
2856 * Loop detection - walk through the ruleset beginning at the destination chain
2857 * of a new jump until either the source chain is reached (loop) or all
2858 * reachable chains have been traversed.
2859 *
2860 * The loop check is performed whenever a new jump verdict is added to an
2861 * expression or verdict map or a verdict map is bound to a new chain.
2862 */
2863
2864static int nf_tables_check_loops(const struct nft_ctx *ctx,
2865 const struct nft_chain *chain);
2866
2867static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
2868 const struct nft_set *set,
2869 const struct nft_set_iter *iter,
2870 const struct nft_set_elem *elem)
2871{
2872 switch (elem->data.verdict) {
2873 case NFT_JUMP:
2874 case NFT_GOTO:
2875 return nf_tables_check_loops(ctx, elem->data.chain);
2876 default:
2877 return 0;
2878 }
2879}
2880
2881static int nf_tables_check_loops(const struct nft_ctx *ctx,
2882 const struct nft_chain *chain)
2883{
2884 const struct nft_rule *rule;
2885 const struct nft_expr *expr, *last;
Patrick McHardy20a69342013-10-11 12:06:22 +02002886 const struct nft_set *set;
2887 struct nft_set_binding *binding;
2888 struct nft_set_iter iter;
Patrick McHardy20a69342013-10-11 12:06:22 +02002889
2890 if (ctx->chain == chain)
2891 return -ELOOP;
2892
2893 list_for_each_entry(rule, &chain->rules, list) {
2894 nft_rule_for_each_expr(expr, last, rule) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002895 const struct nft_data *data = NULL;
2896 int err;
2897
2898 if (!expr->ops->validate)
Patrick McHardy20a69342013-10-11 12:06:22 +02002899 continue;
2900
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002901 err = expr->ops->validate(ctx, expr, &data);
2902 if (err < 0)
2903 return err;
2904
Patrick McHardy20a69342013-10-11 12:06:22 +02002905 if (data == NULL)
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002906 continue;
Patrick McHardy20a69342013-10-11 12:06:22 +02002907
2908 switch (data->verdict) {
2909 case NFT_JUMP:
2910 case NFT_GOTO:
2911 err = nf_tables_check_loops(ctx, data->chain);
2912 if (err < 0)
2913 return err;
2914 default:
2915 break;
2916 }
2917 }
2918 }
2919
2920 list_for_each_entry(set, &ctx->table->sets, list) {
2921 if (!(set->flags & NFT_SET_MAP) ||
2922 set->dtype != NFT_DATA_VERDICT)
2923 continue;
2924
2925 list_for_each_entry(binding, &set->bindings, list) {
2926 if (binding->chain != chain)
2927 continue;
2928
2929 iter.skip = 0;
2930 iter.count = 0;
2931 iter.err = 0;
2932 iter.fn = nf_tables_loop_check_setelem;
2933
2934 set->ops->walk(ctx, set, &iter);
2935 if (iter.err < 0)
2936 return iter.err;
2937 }
2938 }
2939
2940 return 0;
2941}
2942
Patrick McHardy96518512013-10-14 11:00:02 +02002943/**
2944 * nft_validate_input_register - validate an expressions' input register
2945 *
2946 * @reg: the register number
2947 *
2948 * Validate that the input register is one of the general purpose
2949 * registers.
2950 */
2951int nft_validate_input_register(enum nft_registers reg)
2952{
2953 if (reg <= NFT_REG_VERDICT)
2954 return -EINVAL;
2955 if (reg > NFT_REG_MAX)
2956 return -ERANGE;
2957 return 0;
2958}
2959EXPORT_SYMBOL_GPL(nft_validate_input_register);
2960
2961/**
2962 * nft_validate_output_register - validate an expressions' output register
2963 *
2964 * @reg: the register number
2965 *
2966 * Validate that the output register is one of the general purpose
2967 * registers or the verdict register.
2968 */
2969int nft_validate_output_register(enum nft_registers reg)
2970{
2971 if (reg < NFT_REG_VERDICT)
2972 return -EINVAL;
2973 if (reg > NFT_REG_MAX)
2974 return -ERANGE;
2975 return 0;
2976}
2977EXPORT_SYMBOL_GPL(nft_validate_output_register);
2978
2979/**
2980 * nft_validate_data_load - validate an expressions' data load
2981 *
2982 * @ctx: context of the expression performing the load
2983 * @reg: the destination register number
2984 * @data: the data to load
2985 * @type: the data type
2986 *
2987 * Validate that a data load uses the appropriate data type for
2988 * the destination register. A value of NULL for the data means
2989 * that its runtime gathered data, which is always of type
2990 * NFT_DATA_VALUE.
2991 */
2992int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
2993 const struct nft_data *data,
2994 enum nft_data_types type)
2995{
Patrick McHardy20a69342013-10-11 12:06:22 +02002996 int err;
2997
Patrick McHardy96518512013-10-14 11:00:02 +02002998 switch (reg) {
2999 case NFT_REG_VERDICT:
3000 if (data == NULL || type != NFT_DATA_VERDICT)
3001 return -EINVAL;
Patrick McHardy20a69342013-10-11 12:06:22 +02003002
3003 if (data->verdict == NFT_GOTO || data->verdict == NFT_JUMP) {
3004 err = nf_tables_check_loops(ctx, data->chain);
3005 if (err < 0)
3006 return err;
3007
3008 if (ctx->chain->level + 1 > data->chain->level) {
3009 if (ctx->chain->level + 1 == NFT_JUMP_STACK_SIZE)
3010 return -EMLINK;
3011 data->chain->level = ctx->chain->level + 1;
3012 }
3013 }
3014
Patrick McHardy96518512013-10-14 11:00:02 +02003015 return 0;
3016 default:
3017 if (data != NULL && type != NFT_DATA_VALUE)
3018 return -EINVAL;
3019 return 0;
3020 }
3021}
3022EXPORT_SYMBOL_GPL(nft_validate_data_load);
3023
3024static const struct nla_policy nft_verdict_policy[NFTA_VERDICT_MAX + 1] = {
3025 [NFTA_VERDICT_CODE] = { .type = NLA_U32 },
3026 [NFTA_VERDICT_CHAIN] = { .type = NLA_STRING,
3027 .len = NFT_CHAIN_MAXNAMELEN - 1 },
3028};
3029
3030static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
3031 struct nft_data_desc *desc, const struct nlattr *nla)
3032{
3033 struct nlattr *tb[NFTA_VERDICT_MAX + 1];
3034 struct nft_chain *chain;
3035 int err;
3036
3037 err = nla_parse_nested(tb, NFTA_VERDICT_MAX, nla, nft_verdict_policy);
3038 if (err < 0)
3039 return err;
3040
3041 if (!tb[NFTA_VERDICT_CODE])
3042 return -EINVAL;
3043 data->verdict = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE]));
3044
3045 switch (data->verdict) {
3046 case NF_ACCEPT:
3047 case NF_DROP:
3048 case NF_QUEUE:
3049 case NFT_CONTINUE:
3050 case NFT_BREAK:
3051 case NFT_RETURN:
3052 desc->len = sizeof(data->verdict);
3053 break;
3054 case NFT_JUMP:
3055 case NFT_GOTO:
3056 if (!tb[NFTA_VERDICT_CHAIN])
3057 return -EINVAL;
3058 chain = nf_tables_chain_lookup(ctx->table,
3059 tb[NFTA_VERDICT_CHAIN]);
3060 if (IS_ERR(chain))
3061 return PTR_ERR(chain);
3062 if (chain->flags & NFT_BASE_CHAIN)
3063 return -EOPNOTSUPP;
3064
Patrick McHardy96518512013-10-14 11:00:02 +02003065 chain->use++;
3066 data->chain = chain;
3067 desc->len = sizeof(data);
3068 break;
3069 default:
3070 return -EINVAL;
3071 }
3072
3073 desc->type = NFT_DATA_VERDICT;
3074 return 0;
3075}
3076
3077static void nft_verdict_uninit(const struct nft_data *data)
3078{
3079 switch (data->verdict) {
3080 case NFT_JUMP:
3081 case NFT_GOTO:
3082 data->chain->use--;
3083 break;
3084 }
3085}
3086
3087static int nft_verdict_dump(struct sk_buff *skb, const struct nft_data *data)
3088{
3089 struct nlattr *nest;
3090
3091 nest = nla_nest_start(skb, NFTA_DATA_VERDICT);
3092 if (!nest)
3093 goto nla_put_failure;
3094
3095 if (nla_put_be32(skb, NFTA_VERDICT_CODE, htonl(data->verdict)))
3096 goto nla_put_failure;
3097
3098 switch (data->verdict) {
3099 case NFT_JUMP:
3100 case NFT_GOTO:
3101 if (nla_put_string(skb, NFTA_VERDICT_CHAIN, data->chain->name))
3102 goto nla_put_failure;
3103 }
3104 nla_nest_end(skb, nest);
3105 return 0;
3106
3107nla_put_failure:
3108 return -1;
3109}
3110
3111static int nft_value_init(const struct nft_ctx *ctx, struct nft_data *data,
3112 struct nft_data_desc *desc, const struct nlattr *nla)
3113{
3114 unsigned int len;
3115
3116 len = nla_len(nla);
3117 if (len == 0)
3118 return -EINVAL;
3119 if (len > sizeof(data->data))
3120 return -EOVERFLOW;
3121
3122 nla_memcpy(data->data, nla, sizeof(data->data));
3123 desc->type = NFT_DATA_VALUE;
3124 desc->len = len;
3125 return 0;
3126}
3127
3128static int nft_value_dump(struct sk_buff *skb, const struct nft_data *data,
3129 unsigned int len)
3130{
3131 return nla_put(skb, NFTA_DATA_VALUE, len, data->data);
3132}
3133
3134static const struct nla_policy nft_data_policy[NFTA_DATA_MAX + 1] = {
3135 [NFTA_DATA_VALUE] = { .type = NLA_BINARY,
3136 .len = FIELD_SIZEOF(struct nft_data, data) },
3137 [NFTA_DATA_VERDICT] = { .type = NLA_NESTED },
3138};
3139
3140/**
3141 * nft_data_init - parse nf_tables data netlink attributes
3142 *
3143 * @ctx: context of the expression using the data
3144 * @data: destination struct nft_data
3145 * @desc: data description
3146 * @nla: netlink attribute containing data
3147 *
3148 * Parse the netlink data attributes and initialize a struct nft_data.
3149 * The type and length of data are returned in the data description.
3150 *
3151 * The caller can indicate that it only wants to accept data of type
3152 * NFT_DATA_VALUE by passing NULL for the ctx argument.
3153 */
3154int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data,
3155 struct nft_data_desc *desc, const struct nlattr *nla)
3156{
3157 struct nlattr *tb[NFTA_DATA_MAX + 1];
3158 int err;
3159
3160 err = nla_parse_nested(tb, NFTA_DATA_MAX, nla, nft_data_policy);
3161 if (err < 0)
3162 return err;
3163
3164 if (tb[NFTA_DATA_VALUE])
3165 return nft_value_init(ctx, data, desc, tb[NFTA_DATA_VALUE]);
3166 if (tb[NFTA_DATA_VERDICT] && ctx != NULL)
3167 return nft_verdict_init(ctx, data, desc, tb[NFTA_DATA_VERDICT]);
3168 return -EINVAL;
3169}
3170EXPORT_SYMBOL_GPL(nft_data_init);
3171
3172/**
3173 * nft_data_uninit - release a nft_data item
3174 *
3175 * @data: struct nft_data to release
3176 * @type: type of data
3177 *
3178 * Release a nft_data item. NFT_DATA_VALUE types can be silently discarded,
3179 * all others need to be released by calling this function.
3180 */
3181void nft_data_uninit(const struct nft_data *data, enum nft_data_types type)
3182{
3183 switch (type) {
3184 case NFT_DATA_VALUE:
3185 return;
3186 case NFT_DATA_VERDICT:
3187 return nft_verdict_uninit(data);
3188 default:
3189 WARN_ON(1);
3190 }
3191}
3192EXPORT_SYMBOL_GPL(nft_data_uninit);
3193
3194int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
3195 enum nft_data_types type, unsigned int len)
3196{
3197 struct nlattr *nest;
3198 int err;
3199
3200 nest = nla_nest_start(skb, attr);
3201 if (nest == NULL)
3202 return -1;
3203
3204 switch (type) {
3205 case NFT_DATA_VALUE:
3206 err = nft_value_dump(skb, data, len);
3207 break;
3208 case NFT_DATA_VERDICT:
3209 err = nft_verdict_dump(skb, data);
3210 break;
3211 default:
3212 err = -EINVAL;
3213 WARN_ON(1);
3214 }
3215
3216 nla_nest_end(skb, nest);
3217 return err;
3218}
3219EXPORT_SYMBOL_GPL(nft_data_dump);
3220
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003221static int nf_tables_init_net(struct net *net)
3222{
3223 INIT_LIST_HEAD(&net->nft.af_info);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02003224 INIT_LIST_HEAD(&net->nft.commit_list);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003225 return 0;
3226}
3227
3228static struct pernet_operations nf_tables_net_ops = {
3229 .init = nf_tables_init_net,
3230};
3231
Patrick McHardy96518512013-10-14 11:00:02 +02003232static int __init nf_tables_module_init(void)
3233{
3234 int err;
3235
3236 info = kmalloc(sizeof(struct nft_expr_info) * NFT_RULE_MAXEXPRS,
3237 GFP_KERNEL);
3238 if (info == NULL) {
3239 err = -ENOMEM;
3240 goto err1;
3241 }
3242
3243 err = nf_tables_core_module_init();
3244 if (err < 0)
3245 goto err2;
3246
3247 err = nfnetlink_subsys_register(&nf_tables_subsys);
3248 if (err < 0)
3249 goto err3;
3250
3251 pr_info("nf_tables: (c) 2007-2009 Patrick McHardy <kaber@trash.net>\n");
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003252 return register_pernet_subsys(&nf_tables_net_ops);
Patrick McHardy96518512013-10-14 11:00:02 +02003253err3:
3254 nf_tables_core_module_exit();
3255err2:
3256 kfree(info);
3257err1:
3258 return err;
3259}
3260
3261static void __exit nf_tables_module_exit(void)
3262{
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003263 unregister_pernet_subsys(&nf_tables_net_ops);
Patrick McHardy96518512013-10-14 11:00:02 +02003264 nfnetlink_subsys_unregister(&nf_tables_subsys);
3265 nf_tables_core_module_exit();
3266 kfree(info);
3267}
3268
3269module_init(nf_tables_module_init);
3270module_exit(nf_tables_module_exit);
3271
3272MODULE_LICENSE("GPL");
3273MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
3274MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFTABLES);