blob: d71125a0a34123102881837461b8ffec05c8b4cc [file] [log] [blame]
Patrick McHardy96518512013-10-14 11:00:02 +02001/*
Patrick McHardy20a69342013-10-11 12:06:22 +02002 * Copyright (c) 2007-2009 Patrick McHardy <kaber@trash.net>
Patrick McHardy96518512013-10-14 11:00:02 +02003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/module.h>
12#include <linux/init.h>
13#include <linux/list.h>
14#include <linux/skbuff.h>
15#include <linux/netlink.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter/nfnetlink.h>
18#include <linux/netfilter/nf_tables.h>
19#include <net/netfilter/nf_tables_core.h>
20#include <net/netfilter/nf_tables.h>
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020021#include <net/net_namespace.h>
Patrick McHardy96518512013-10-14 11:00:02 +020022#include <net/sock.h>
23
Patrick McHardy96518512013-10-14 11:00:02 +020024static LIST_HEAD(nf_tables_expressions);
25
26/**
27 * nft_register_afinfo - register nf_tables address family info
28 *
29 * @afi: address family info to register
30 *
31 * Register the address family for use with nf_tables. Returns zero on
32 * success or a negative errno code otherwise.
33 */
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020034int nft_register_afinfo(struct net *net, struct nft_af_info *afi)
Patrick McHardy96518512013-10-14 11:00:02 +020035{
36 INIT_LIST_HEAD(&afi->tables);
37 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020038 list_add_tail(&afi->list, &net->nft.af_info);
Patrick McHardy96518512013-10-14 11:00:02 +020039 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
40 return 0;
41}
42EXPORT_SYMBOL_GPL(nft_register_afinfo);
43
44/**
45 * nft_unregister_afinfo - unregister nf_tables address family info
46 *
47 * @afi: address family info to unregister
48 *
49 * Unregister the address family for use with nf_tables.
50 */
51void nft_unregister_afinfo(struct nft_af_info *afi)
52{
53 nfnl_lock(NFNL_SUBSYS_NFTABLES);
54 list_del(&afi->list);
55 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
56}
57EXPORT_SYMBOL_GPL(nft_unregister_afinfo);
58
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020059static struct nft_af_info *nft_afinfo_lookup(struct net *net, int family)
Patrick McHardy96518512013-10-14 11:00:02 +020060{
61 struct nft_af_info *afi;
62
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020063 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +020064 if (afi->family == family)
65 return afi;
66 }
67 return NULL;
68}
69
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020070static struct nft_af_info *
71nf_tables_afinfo_lookup(struct net *net, int family, bool autoload)
Patrick McHardy96518512013-10-14 11:00:02 +020072{
73 struct nft_af_info *afi;
74
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020075 afi = nft_afinfo_lookup(net, family);
Patrick McHardy96518512013-10-14 11:00:02 +020076 if (afi != NULL)
77 return afi;
78#ifdef CONFIG_MODULES
79 if (autoload) {
80 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
81 request_module("nft-afinfo-%u", family);
82 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +020083 afi = nft_afinfo_lookup(net, family);
Patrick McHardy96518512013-10-14 11:00:02 +020084 if (afi != NULL)
85 return ERR_PTR(-EAGAIN);
86 }
87#endif
88 return ERR_PTR(-EAFNOSUPPORT);
89}
90
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +020091static void nft_ctx_init(struct nft_ctx *ctx,
92 const struct sk_buff *skb,
93 const struct nlmsghdr *nlh,
94 struct nft_af_info *afi,
95 struct nft_table *table,
96 struct nft_chain *chain,
97 const struct nlattr * const *nla)
98{
99 ctx->net = sock_net(skb->sk);
100 ctx->skb = skb;
101 ctx->nlh = nlh;
102 ctx->afi = afi;
103 ctx->table = table;
104 ctx->chain = chain;
105 ctx->nla = nla;
106}
107
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +0200108static struct nft_trans *nft_trans_alloc(struct nft_ctx *ctx, int msg_type,
109 u32 size)
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +0200110{
111 struct nft_trans *trans;
112
113 trans = kzalloc(sizeof(struct nft_trans) + size, GFP_KERNEL);
114 if (trans == NULL)
115 return NULL;
116
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +0200117 trans->msg_type = msg_type;
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +0200118 trans->ctx = *ctx;
119
120 return trans;
121}
122
123static void nft_trans_destroy(struct nft_trans *trans)
124{
125 list_del(&trans->list);
126 kfree(trans);
127}
128
Patrick McHardy96518512013-10-14 11:00:02 +0200129/*
130 * Tables
131 */
132
133static struct nft_table *nft_table_lookup(const struct nft_af_info *afi,
134 const struct nlattr *nla)
135{
136 struct nft_table *table;
137
138 list_for_each_entry(table, &afi->tables, list) {
139 if (!nla_strcmp(nla, table->name))
140 return table;
141 }
142 return NULL;
143}
144
145static struct nft_table *nf_tables_table_lookup(const struct nft_af_info *afi,
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200146 const struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +0200147{
148 struct nft_table *table;
149
150 if (nla == NULL)
151 return ERR_PTR(-EINVAL);
152
153 table = nft_table_lookup(afi, nla);
154 if (table != NULL)
155 return table;
156
Patrick McHardy96518512013-10-14 11:00:02 +0200157 return ERR_PTR(-ENOENT);
158}
159
160static inline u64 nf_tables_alloc_handle(struct nft_table *table)
161{
162 return ++table->hgenerator;
163}
164
Patrick McHardy2a37d752014-01-09 18:42:37 +0000165static const struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200166
Patrick McHardy2a37d752014-01-09 18:42:37 +0000167static const struct nf_chain_type *
Patrick McHardybaae3e62014-01-09 18:42:34 +0000168__nf_tables_chain_type_lookup(int family, const struct nlattr *nla)
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200169{
170 int i;
171
Patrick McHardybaae3e62014-01-09 18:42:34 +0000172 for (i = 0; i < NFT_CHAIN_T_MAX; i++) {
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200173 if (chain_type[family][i] != NULL &&
174 !nla_strcmp(nla, chain_type[family][i]->name))
Patrick McHardybaae3e62014-01-09 18:42:34 +0000175 return chain_type[family][i];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200176 }
Patrick McHardybaae3e62014-01-09 18:42:34 +0000177 return NULL;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200178}
179
Patrick McHardy2a37d752014-01-09 18:42:37 +0000180static const struct nf_chain_type *
Patrick McHardybaae3e62014-01-09 18:42:34 +0000181nf_tables_chain_type_lookup(const struct nft_af_info *afi,
182 const struct nlattr *nla,
183 bool autoload)
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200184{
Patrick McHardy2a37d752014-01-09 18:42:37 +0000185 const struct nf_chain_type *type;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200186
187 type = __nf_tables_chain_type_lookup(afi->family, nla);
Patrick McHardy93b08062014-01-09 18:42:36 +0000188 if (type != NULL)
189 return type;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200190#ifdef CONFIG_MODULES
Patrick McHardy93b08062014-01-09 18:42:36 +0000191 if (autoload) {
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200192 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
193 request_module("nft-chain-%u-%*.s", afi->family,
194 nla_len(nla)-1, (const char *)nla_data(nla));
195 nfnl_lock(NFNL_SUBSYS_NFTABLES);
196 type = __nf_tables_chain_type_lookup(afi->family, nla);
Patrick McHardy93b08062014-01-09 18:42:36 +0000197 if (type != NULL)
198 return ERR_PTR(-EAGAIN);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200199 }
200#endif
Patrick McHardy93b08062014-01-09 18:42:36 +0000201 return ERR_PTR(-ENOENT);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200202}
203
Patrick McHardy96518512013-10-14 11:00:02 +0200204static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
205 [NFTA_TABLE_NAME] = { .type = NLA_STRING },
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200206 [NFTA_TABLE_FLAGS] = { .type = NLA_U32 },
Patrick McHardy96518512013-10-14 11:00:02 +0200207};
208
209static int nf_tables_fill_table_info(struct sk_buff *skb, u32 portid, u32 seq,
210 int event, u32 flags, int family,
211 const struct nft_table *table)
212{
213 struct nlmsghdr *nlh;
214 struct nfgenmsg *nfmsg;
215
216 event |= NFNL_SUBSYS_NFTABLES << 8;
217 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
218 if (nlh == NULL)
219 goto nla_put_failure;
220
221 nfmsg = nlmsg_data(nlh);
222 nfmsg->nfgen_family = family;
223 nfmsg->version = NFNETLINK_V0;
224 nfmsg->res_id = 0;
225
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200226 if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
Tomasz Bursztykad8bcc7682013-12-12 15:00:42 +0200227 nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
228 nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)))
Patrick McHardy96518512013-10-14 11:00:02 +0200229 goto nla_put_failure;
230
231 return nlmsg_end(skb, nlh);
232
233nla_put_failure:
234 nlmsg_trim(skb, nlh);
235 return -1;
236}
237
238static int nf_tables_table_notify(const struct sk_buff *oskb,
239 const struct nlmsghdr *nlh,
240 const struct nft_table *table,
241 int event, int family)
242{
243 struct sk_buff *skb;
244 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
245 u32 seq = nlh ? nlh->nlmsg_seq : 0;
246 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
247 bool report;
248 int err;
249
250 report = nlh ? nlmsg_report(nlh) : false;
251 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
252 return 0;
253
254 err = -ENOBUFS;
255 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
256 if (skb == NULL)
257 goto err;
258
259 err = nf_tables_fill_table_info(skb, portid, seq, event, 0,
260 family, table);
261 if (err < 0) {
262 kfree_skb(skb);
263 goto err;
264 }
265
266 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
267 GFP_KERNEL);
268err:
269 if (err < 0)
270 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
271 return err;
272}
273
274static int nf_tables_dump_tables(struct sk_buff *skb,
275 struct netlink_callback *cb)
276{
277 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
278 const struct nft_af_info *afi;
279 const struct nft_table *table;
280 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200281 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200282 int family = nfmsg->nfgen_family;
283
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200284 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +0200285 if (family != NFPROTO_UNSPEC && family != afi->family)
286 continue;
287
288 list_for_each_entry(table, &afi->tables, list) {
289 if (idx < s_idx)
290 goto cont;
291 if (idx > s_idx)
292 memset(&cb->args[1], 0,
293 sizeof(cb->args) - sizeof(cb->args[0]));
294 if (nf_tables_fill_table_info(skb,
295 NETLINK_CB(cb->skb).portid,
296 cb->nlh->nlmsg_seq,
297 NFT_MSG_NEWTABLE,
298 NLM_F_MULTI,
299 afi->family, table) < 0)
300 goto done;
301cont:
302 idx++;
303 }
304 }
305done:
306 cb->args[0] = idx;
307 return skb->len;
308}
309
310static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb,
311 const struct nlmsghdr *nlh,
312 const struct nlattr * const nla[])
313{
314 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
315 const struct nft_af_info *afi;
316 const struct nft_table *table;
317 struct sk_buff *skb2;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200318 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200319 int family = nfmsg->nfgen_family;
320 int err;
321
322 if (nlh->nlmsg_flags & NLM_F_DUMP) {
323 struct netlink_dump_control c = {
324 .dump = nf_tables_dump_tables,
325 };
326 return netlink_dump_start(nlsk, skb, nlh, &c);
327 }
328
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200329 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200330 if (IS_ERR(afi))
331 return PTR_ERR(afi);
332
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200333 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
Patrick McHardy96518512013-10-14 11:00:02 +0200334 if (IS_ERR(table))
335 return PTR_ERR(table);
336
337 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
338 if (!skb2)
339 return -ENOMEM;
340
341 err = nf_tables_fill_table_info(skb2, NETLINK_CB(skb).portid,
342 nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0,
343 family, table);
344 if (err < 0)
345 goto err;
346
347 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
348
349err:
350 kfree_skb(skb2);
351 return err;
352}
353
Patrick McHardy115a60b2014-01-03 12:16:15 +0000354static int nf_tables_table_enable(const struct nft_af_info *afi,
355 struct nft_table *table)
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200356{
357 struct nft_chain *chain;
358 int err, i = 0;
359
360 list_for_each_entry(chain, &table->chains, list) {
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100361 if (!(chain->flags & NFT_BASE_CHAIN))
362 continue;
363
Patrick McHardy115a60b2014-01-03 12:16:15 +0000364 err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200365 if (err < 0)
366 goto err;
367
368 i++;
369 }
370 return 0;
371err:
372 list_for_each_entry(chain, &table->chains, list) {
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100373 if (!(chain->flags & NFT_BASE_CHAIN))
374 continue;
375
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200376 if (i-- <= 0)
377 break;
378
Patrick McHardy115a60b2014-01-03 12:16:15 +0000379 nf_unregister_hooks(nft_base_chain(chain)->ops, afi->nops);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200380 }
381 return err;
382}
383
Pablo Neira Ayusof75edf52014-03-30 14:04:52 +0200384static void nf_tables_table_disable(const struct nft_af_info *afi,
Patrick McHardy115a60b2014-01-03 12:16:15 +0000385 struct nft_table *table)
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200386{
387 struct nft_chain *chain;
388
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100389 list_for_each_entry(chain, &table->chains, list) {
390 if (chain->flags & NFT_BASE_CHAIN)
Patrick McHardy115a60b2014-01-03 12:16:15 +0000391 nf_unregister_hooks(nft_base_chain(chain)->ops,
392 afi->nops);
Pablo Neira Ayusod2012972013-12-27 10:44:23 +0100393 }
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200394}
395
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200396static int nf_tables_updtable(struct nft_ctx *ctx)
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200397{
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200398 const struct nfgenmsg *nfmsg = nlmsg_data(ctx->nlh);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200399 int family = nfmsg->nfgen_family, ret = 0;
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200400 u32 flags;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200401
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200402 if (!ctx->nla[NFTA_TABLE_FLAGS])
403 return 0;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200404
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200405 flags = ntohl(nla_get_be32(ctx->nla[NFTA_TABLE_FLAGS]));
406 if (flags & ~NFT_TABLE_F_DORMANT)
407 return -EINVAL;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200408
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200409 if ((flags & NFT_TABLE_F_DORMANT) &&
410 !(ctx->table->flags & NFT_TABLE_F_DORMANT)) {
411 nf_tables_table_disable(ctx->afi, ctx->table);
412 ctx->table->flags |= NFT_TABLE_F_DORMANT;
413 } else if (!(flags & NFT_TABLE_F_DORMANT) &&
414 ctx->table->flags & NFT_TABLE_F_DORMANT) {
415 ret = nf_tables_table_enable(ctx->afi, ctx->table);
416 if (ret >= 0)
417 ctx->table->flags &= ~NFT_TABLE_F_DORMANT;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200418 }
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200419 if (ret < 0)
420 goto err;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200421
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200422 nf_tables_table_notify(ctx->skb, ctx->nlh, ctx->table,
423 NFT_MSG_NEWTABLE, family);
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200424err:
425 return ret;
426}
427
Patrick McHardy96518512013-10-14 11:00:02 +0200428static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
429 const struct nlmsghdr *nlh,
430 const struct nlattr * const nla[])
431{
432 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
433 const struct nlattr *name;
434 struct nft_af_info *afi;
435 struct nft_table *table;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200436 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200437 int family = nfmsg->nfgen_family;
Patrick McHardyc5c1f972014-01-09 18:42:39 +0000438 u32 flags = 0;
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200439 struct nft_ctx ctx;
Patrick McHardy96518512013-10-14 11:00:02 +0200440
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200441 afi = nf_tables_afinfo_lookup(net, family, true);
Patrick McHardy96518512013-10-14 11:00:02 +0200442 if (IS_ERR(afi))
443 return PTR_ERR(afi);
444
445 name = nla[NFTA_TABLE_NAME];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200446 table = nf_tables_table_lookup(afi, name);
Patrick McHardy96518512013-10-14 11:00:02 +0200447 if (IS_ERR(table)) {
448 if (PTR_ERR(table) != -ENOENT)
449 return PTR_ERR(table);
450 table = NULL;
451 }
452
453 if (table != NULL) {
454 if (nlh->nlmsg_flags & NLM_F_EXCL)
455 return -EEXIST;
456 if (nlh->nlmsg_flags & NLM_F_REPLACE)
457 return -EOPNOTSUPP;
Pablo Neira Ayusoe1aaca92014-03-30 14:04:53 +0200458
459 nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
460 return nf_tables_updtable(&ctx);
Patrick McHardy96518512013-10-14 11:00:02 +0200461 }
462
Patrick McHardyc5c1f972014-01-09 18:42:39 +0000463 if (nla[NFTA_TABLE_FLAGS]) {
464 flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
465 if (flags & ~NFT_TABLE_F_DORMANT)
466 return -EINVAL;
467 }
468
Patrick McHardy7047f9d2014-01-09 18:42:40 +0000469 if (!try_module_get(afi->owner))
470 return -EAFNOSUPPORT;
471
Patrick McHardy96518512013-10-14 11:00:02 +0200472 table = kzalloc(sizeof(*table) + nla_len(name), GFP_KERNEL);
Patrick McHardy7047f9d2014-01-09 18:42:40 +0000473 if (table == NULL) {
474 module_put(afi->owner);
Patrick McHardy96518512013-10-14 11:00:02 +0200475 return -ENOMEM;
Patrick McHardy7047f9d2014-01-09 18:42:40 +0000476 }
Patrick McHardy96518512013-10-14 11:00:02 +0200477
478 nla_strlcpy(table->name, name, nla_len(name));
479 INIT_LIST_HEAD(&table->chains);
Patrick McHardy20a69342013-10-11 12:06:22 +0200480 INIT_LIST_HEAD(&table->sets);
Patrick McHardyc5c1f972014-01-09 18:42:39 +0000481 table->flags = flags;
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +0200482
Patrick McHardy96518512013-10-14 11:00:02 +0200483 list_add_tail(&table->list, &afi->tables);
484 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
485 return 0;
486}
487
488static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
489 const struct nlmsghdr *nlh,
490 const struct nlattr * const nla[])
491{
492 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
493 struct nft_af_info *afi;
494 struct nft_table *table;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200495 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200496 int family = nfmsg->nfgen_family;
497
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200498 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200499 if (IS_ERR(afi))
500 return PTR_ERR(afi);
501
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200502 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
Patrick McHardy96518512013-10-14 11:00:02 +0200503 if (IS_ERR(table))
504 return PTR_ERR(table);
505
Patrick McHardy44a6f0d2014-01-09 18:42:41 +0000506 if (!list_empty(&table->chains) || !list_empty(&table->sets))
Patrick McHardy96518512013-10-14 11:00:02 +0200507 return -EBUSY;
508
509 list_del(&table->list);
510 nf_tables_table_notify(skb, nlh, table, NFT_MSG_DELTABLE, family);
511 kfree(table);
Patrick McHardy7047f9d2014-01-09 18:42:40 +0000512 module_put(afi->owner);
Patrick McHardy96518512013-10-14 11:00:02 +0200513 return 0;
514}
515
Patrick McHardy2a37d752014-01-09 18:42:37 +0000516int nft_register_chain_type(const struct nf_chain_type *ctype)
Patrick McHardy96518512013-10-14 11:00:02 +0200517{
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200518 int err = 0;
Patrick McHardy96518512013-10-14 11:00:02 +0200519
520 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200521 if (chain_type[ctype->family][ctype->type] != NULL) {
522 err = -EBUSY;
523 goto out;
Patrick McHardy96518512013-10-14 11:00:02 +0200524 }
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200525 chain_type[ctype->family][ctype->type] = ctype;
526out:
Patrick McHardy96518512013-10-14 11:00:02 +0200527 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
528 return err;
529}
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200530EXPORT_SYMBOL_GPL(nft_register_chain_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200531
Patrick McHardy2a37d752014-01-09 18:42:37 +0000532void nft_unregister_chain_type(const struct nf_chain_type *ctype)
Patrick McHardy96518512013-10-14 11:00:02 +0200533{
Patrick McHardy96518512013-10-14 11:00:02 +0200534 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200535 chain_type[ctype->family][ctype->type] = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +0200536 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
537}
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200538EXPORT_SYMBOL_GPL(nft_unregister_chain_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200539
540/*
541 * Chains
542 */
543
544static struct nft_chain *
545nf_tables_chain_lookup_byhandle(const struct nft_table *table, u64 handle)
546{
547 struct nft_chain *chain;
548
549 list_for_each_entry(chain, &table->chains, list) {
550 if (chain->handle == handle)
551 return chain;
552 }
553
554 return ERR_PTR(-ENOENT);
555}
556
557static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table,
558 const struct nlattr *nla)
559{
560 struct nft_chain *chain;
561
562 if (nla == NULL)
563 return ERR_PTR(-EINVAL);
564
565 list_for_each_entry(chain, &table->chains, list) {
566 if (!nla_strcmp(nla, chain->name))
567 return chain;
568 }
569
570 return ERR_PTR(-ENOENT);
571}
572
573static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
574 [NFTA_CHAIN_TABLE] = { .type = NLA_STRING },
575 [NFTA_CHAIN_HANDLE] = { .type = NLA_U64 },
576 [NFTA_CHAIN_NAME] = { .type = NLA_STRING,
577 .len = NFT_CHAIN_MAXNAMELEN - 1 },
578 [NFTA_CHAIN_HOOK] = { .type = NLA_NESTED },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200579 [NFTA_CHAIN_POLICY] = { .type = NLA_U32 },
Pablo Neira4c1f7812014-03-31 17:43:47 +0200580 [NFTA_CHAIN_TYPE] = { .type = NLA_STRING },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200581 [NFTA_CHAIN_COUNTERS] = { .type = NLA_NESTED },
Patrick McHardy96518512013-10-14 11:00:02 +0200582};
583
584static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = {
585 [NFTA_HOOK_HOOKNUM] = { .type = NLA_U32 },
586 [NFTA_HOOK_PRIORITY] = { .type = NLA_U32 },
587};
588
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200589static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats)
590{
591 struct nft_stats *cpu_stats, total;
592 struct nlattr *nest;
593 int cpu;
594
595 memset(&total, 0, sizeof(total));
596 for_each_possible_cpu(cpu) {
597 cpu_stats = per_cpu_ptr(stats, cpu);
598 total.pkts += cpu_stats->pkts;
599 total.bytes += cpu_stats->bytes;
600 }
601 nest = nla_nest_start(skb, NFTA_CHAIN_COUNTERS);
602 if (nest == NULL)
603 goto nla_put_failure;
604
605 if (nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(total.pkts)) ||
606 nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes)))
607 goto nla_put_failure;
608
609 nla_nest_end(skb, nest);
610 return 0;
611
612nla_put_failure:
613 return -ENOSPC;
614}
615
Patrick McHardy96518512013-10-14 11:00:02 +0200616static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq,
617 int event, u32 flags, int family,
618 const struct nft_table *table,
619 const struct nft_chain *chain)
620{
621 struct nlmsghdr *nlh;
622 struct nfgenmsg *nfmsg;
623
624 event |= NFNL_SUBSYS_NFTABLES << 8;
625 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
626 if (nlh == NULL)
627 goto nla_put_failure;
628
629 nfmsg = nlmsg_data(nlh);
630 nfmsg->nfgen_family = family;
631 nfmsg->version = NFNETLINK_V0;
632 nfmsg->res_id = 0;
633
634 if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name))
635 goto nla_put_failure;
636 if (nla_put_be64(skb, NFTA_CHAIN_HANDLE, cpu_to_be64(chain->handle)))
637 goto nla_put_failure;
638 if (nla_put_string(skb, NFTA_CHAIN_NAME, chain->name))
639 goto nla_put_failure;
640
641 if (chain->flags & NFT_BASE_CHAIN) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200642 const struct nft_base_chain *basechain = nft_base_chain(chain);
Patrick McHardy115a60b2014-01-03 12:16:15 +0000643 const struct nf_hook_ops *ops = &basechain->ops[0];
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200644 struct nlattr *nest;
645
646 nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
Patrick McHardy96518512013-10-14 11:00:02 +0200647 if (nest == NULL)
648 goto nla_put_failure;
649 if (nla_put_be32(skb, NFTA_HOOK_HOOKNUM, htonl(ops->hooknum)))
650 goto nla_put_failure;
651 if (nla_put_be32(skb, NFTA_HOOK_PRIORITY, htonl(ops->priority)))
652 goto nla_put_failure;
653 nla_nest_end(skb, nest);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200654
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200655 if (nla_put_be32(skb, NFTA_CHAIN_POLICY,
656 htonl(basechain->policy)))
657 goto nla_put_failure;
658
Patrick McHardybaae3e62014-01-09 18:42:34 +0000659 if (nla_put_string(skb, NFTA_CHAIN_TYPE, basechain->type->name))
660 goto nla_put_failure;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200661
662 if (nft_dump_stats(skb, nft_base_chain(chain)->stats))
663 goto nla_put_failure;
Patrick McHardy96518512013-10-14 11:00:02 +0200664 }
665
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200666 if (nla_put_be32(skb, NFTA_CHAIN_USE, htonl(chain->use)))
667 goto nla_put_failure;
668
Patrick McHardy96518512013-10-14 11:00:02 +0200669 return nlmsg_end(skb, nlh);
670
671nla_put_failure:
672 nlmsg_trim(skb, nlh);
673 return -1;
674}
675
676static int nf_tables_chain_notify(const struct sk_buff *oskb,
677 const struct nlmsghdr *nlh,
678 const struct nft_table *table,
679 const struct nft_chain *chain,
680 int event, int family)
681{
682 struct sk_buff *skb;
683 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
684 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
685 u32 seq = nlh ? nlh->nlmsg_seq : 0;
686 bool report;
687 int err;
688
689 report = nlh ? nlmsg_report(nlh) : false;
690 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
691 return 0;
692
693 err = -ENOBUFS;
694 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
695 if (skb == NULL)
696 goto err;
697
698 err = nf_tables_fill_chain_info(skb, portid, seq, event, 0, family,
699 table, chain);
700 if (err < 0) {
701 kfree_skb(skb);
702 goto err;
703 }
704
705 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
706 GFP_KERNEL);
707err:
708 if (err < 0)
709 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
710 return err;
711}
712
713static int nf_tables_dump_chains(struct sk_buff *skb,
714 struct netlink_callback *cb)
715{
716 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
717 const struct nft_af_info *afi;
718 const struct nft_table *table;
719 const struct nft_chain *chain;
720 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200721 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200722 int family = nfmsg->nfgen_family;
723
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200724 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +0200725 if (family != NFPROTO_UNSPEC && family != afi->family)
726 continue;
727
728 list_for_each_entry(table, &afi->tables, list) {
729 list_for_each_entry(chain, &table->chains, list) {
730 if (idx < s_idx)
731 goto cont;
732 if (idx > s_idx)
733 memset(&cb->args[1], 0,
734 sizeof(cb->args) - sizeof(cb->args[0]));
735 if (nf_tables_fill_chain_info(skb, NETLINK_CB(cb->skb).portid,
736 cb->nlh->nlmsg_seq,
737 NFT_MSG_NEWCHAIN,
738 NLM_F_MULTI,
739 afi->family, table, chain) < 0)
740 goto done;
741cont:
742 idx++;
743 }
744 }
745 }
746done:
747 cb->args[0] = idx;
748 return skb->len;
749}
750
751
752static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb,
753 const struct nlmsghdr *nlh,
754 const struct nlattr * const nla[])
755{
756 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
757 const struct nft_af_info *afi;
758 const struct nft_table *table;
759 const struct nft_chain *chain;
760 struct sk_buff *skb2;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200761 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200762 int family = nfmsg->nfgen_family;
763 int err;
764
765 if (nlh->nlmsg_flags & NLM_F_DUMP) {
766 struct netlink_dump_control c = {
767 .dump = nf_tables_dump_chains,
768 };
769 return netlink_dump_start(nlsk, skb, nlh, &c);
770 }
771
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200772 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +0200773 if (IS_ERR(afi))
774 return PTR_ERR(afi);
775
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200776 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +0200777 if (IS_ERR(table))
778 return PTR_ERR(table);
779
780 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
781 if (IS_ERR(chain))
782 return PTR_ERR(chain);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +0200783 if (chain->flags & NFT_CHAIN_INACTIVE)
784 return -ENOENT;
Patrick McHardy96518512013-10-14 11:00:02 +0200785
786 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
787 if (!skb2)
788 return -ENOMEM;
789
790 err = nf_tables_fill_chain_info(skb2, NETLINK_CB(skb).portid,
791 nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0,
792 family, table, chain);
793 if (err < 0)
794 goto err;
795
796 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
797
798err:
799 kfree_skb(skb2);
800 return err;
801}
802
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200803static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = {
804 [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 },
805 [NFTA_COUNTER_BYTES] = { .type = NLA_U64 },
806};
807
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +0200808static struct nft_stats __percpu *nft_stats_alloc(const struct nlattr *attr)
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200809{
810 struct nlattr *tb[NFTA_COUNTER_MAX+1];
811 struct nft_stats __percpu *newstats;
812 struct nft_stats *stats;
813 int err;
814
815 err = nla_parse_nested(tb, NFTA_COUNTER_MAX, attr, nft_counter_policy);
816 if (err < 0)
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +0200817 return ERR_PTR(err);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200818
819 if (!tb[NFTA_COUNTER_BYTES] || !tb[NFTA_COUNTER_PACKETS])
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +0200820 return ERR_PTR(-EINVAL);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200821
822 newstats = alloc_percpu(struct nft_stats);
823 if (newstats == NULL)
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +0200824 return ERR_PTR(-ENOMEM);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200825
826 /* Restore old counters on this cpu, no problem. Per-cpu statistics
827 * are not exposed to userspace.
828 */
829 stats = this_cpu_ptr(newstats);
830 stats->bytes = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES]));
831 stats->pkts = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS]));
832
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +0200833 return newstats;
834}
835
836static void nft_chain_stats_replace(struct nft_base_chain *chain,
837 struct nft_stats __percpu *newstats)
838{
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200839 if (chain->stats) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200840 struct nft_stats __percpu *oldstats =
Patrick McHardy67a8fc22014-02-18 18:06:49 +0000841 nft_dereference(chain->stats);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200842
843 rcu_assign_pointer(chain->stats, newstats);
844 synchronize_rcu();
845 free_percpu(oldstats);
846 } else
847 rcu_assign_pointer(chain->stats, newstats);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200848}
849
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +0200850static int nft_trans_chain_add(struct nft_ctx *ctx, int msg_type)
851{
852 struct nft_trans *trans;
853
854 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_chain));
855 if (trans == NULL)
856 return -ENOMEM;
857
858 if (msg_type == NFT_MSG_NEWCHAIN)
859 ctx->chain->flags |= NFT_CHAIN_INACTIVE;
860
861 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
862 return 0;
863}
864
865static void nf_tables_chain_destroy(struct nft_chain *chain)
866{
867 BUG_ON(chain->use > 0);
868
869 if (chain->flags & NFT_BASE_CHAIN) {
870 module_put(nft_base_chain(chain)->type->owner);
871 free_percpu(nft_base_chain(chain)->stats);
872 kfree(nft_base_chain(chain));
873 } else {
874 kfree(chain);
875 }
876}
877
Patrick McHardy96518512013-10-14 11:00:02 +0200878static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
879 const struct nlmsghdr *nlh,
880 const struct nlattr * const nla[])
881{
882 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
883 const struct nlattr * uninitialized_var(name);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +0200884 struct nft_af_info *afi;
Patrick McHardy96518512013-10-14 11:00:02 +0200885 struct nft_table *table;
886 struct nft_chain *chain;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200887 struct nft_base_chain *basechain = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +0200888 struct nlattr *ha[NFTA_HOOK_MAX + 1];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200889 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +0200890 int family = nfmsg->nfgen_family;
Patrick McHardy57de2a02014-01-09 18:42:31 +0000891 u8 policy = NF_ACCEPT;
Patrick McHardy96518512013-10-14 11:00:02 +0200892 u64 handle = 0;
Patrick McHardy115a60b2014-01-03 12:16:15 +0000893 unsigned int i;
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +0200894 struct nft_stats __percpu *stats;
Patrick McHardy96518512013-10-14 11:00:02 +0200895 int err;
896 bool create;
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +0200897 struct nft_ctx ctx;
Patrick McHardy96518512013-10-14 11:00:02 +0200898
899 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
900
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +0200901 afi = nf_tables_afinfo_lookup(net, family, true);
Patrick McHardy96518512013-10-14 11:00:02 +0200902 if (IS_ERR(afi))
903 return PTR_ERR(afi);
904
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200905 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +0200906 if (IS_ERR(table))
907 return PTR_ERR(table);
908
Patrick McHardy96518512013-10-14 11:00:02 +0200909 chain = NULL;
910 name = nla[NFTA_CHAIN_NAME];
911
912 if (nla[NFTA_CHAIN_HANDLE]) {
913 handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
914 chain = nf_tables_chain_lookup_byhandle(table, handle);
915 if (IS_ERR(chain))
916 return PTR_ERR(chain);
917 } else {
918 chain = nf_tables_chain_lookup(table, name);
919 if (IS_ERR(chain)) {
920 if (PTR_ERR(chain) != -ENOENT)
921 return PTR_ERR(chain);
922 chain = NULL;
923 }
924 }
925
Patrick McHardy57de2a02014-01-09 18:42:31 +0000926 if (nla[NFTA_CHAIN_POLICY]) {
927 if ((chain != NULL &&
928 !(chain->flags & NFT_BASE_CHAIN)) ||
929 nla[NFTA_CHAIN_HOOK] == NULL)
930 return -EOPNOTSUPP;
931
Pablo Neira Ayuso8f46df12014-01-10 15:11:25 +0100932 policy = ntohl(nla_get_be32(nla[NFTA_CHAIN_POLICY]));
Patrick McHardy57de2a02014-01-09 18:42:31 +0000933 switch (policy) {
934 case NF_DROP:
935 case NF_ACCEPT:
936 break;
937 default:
938 return -EINVAL;
939 }
940 }
941
Patrick McHardy96518512013-10-14 11:00:02 +0200942 if (chain != NULL) {
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +0200943 struct nft_stats *stats = NULL;
944 struct nft_trans *trans;
945
946 if (chain->flags & NFT_CHAIN_INACTIVE)
947 return -ENOENT;
Patrick McHardy96518512013-10-14 11:00:02 +0200948 if (nlh->nlmsg_flags & NLM_F_EXCL)
949 return -EEXIST;
950 if (nlh->nlmsg_flags & NLM_F_REPLACE)
951 return -EOPNOTSUPP;
952
953 if (nla[NFTA_CHAIN_HANDLE] && name &&
954 !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME])))
955 return -EEXIST;
956
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200957 if (nla[NFTA_CHAIN_COUNTERS]) {
958 if (!(chain->flags & NFT_BASE_CHAIN))
959 return -EOPNOTSUPP;
960
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +0200961 stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]);
962 if (IS_ERR(stats))
963 return PTR_ERR(stats);
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200964 }
965
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +0200966 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
967 trans = nft_trans_alloc(&ctx, NFT_MSG_NEWCHAIN,
968 sizeof(struct nft_trans_chain));
969 if (trans == NULL)
970 return -ENOMEM;
971
972 nft_trans_chain_stats(trans) = stats;
973 nft_trans_chain_update(trans) = true;
974
Patrick McHardy4401a862014-01-09 18:42:32 +0000975 if (nla[NFTA_CHAIN_POLICY])
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +0200976 nft_trans_chain_policy(trans) = policy;
977 else
978 nft_trans_chain_policy(trans) = -1;
Patrick McHardy4401a862014-01-09 18:42:32 +0000979
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +0200980 if (nla[NFTA_CHAIN_HANDLE] && name) {
981 nla_strlcpy(nft_trans_chain_name(trans), name,
982 NFT_CHAIN_MAXNAMELEN);
983 }
984 list_add_tail(&trans->list, &net->nft.commit_list);
985 return 0;
Patrick McHardy96518512013-10-14 11:00:02 +0200986 }
987
Patrick McHardy75820672014-01-09 18:42:33 +0000988 if (table->use == UINT_MAX)
989 return -EOVERFLOW;
990
Patrick McHardy96518512013-10-14 11:00:02 +0200991 if (nla[NFTA_CHAIN_HOOK]) {
Patrick McHardy2a37d752014-01-09 18:42:37 +0000992 const struct nf_chain_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +0200993 struct nf_hook_ops *ops;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200994 nf_hookfn *hookfn;
Patrick McHardy115a60b2014-01-03 12:16:15 +0000995 u32 hooknum, priority;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200996
Patrick McHardybaae3e62014-01-09 18:42:34 +0000997 type = chain_type[family][NFT_CHAIN_T_DEFAULT];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200998 if (nla[NFTA_CHAIN_TYPE]) {
999 type = nf_tables_chain_type_lookup(afi,
1000 nla[NFTA_CHAIN_TYPE],
1001 create);
Patrick McHardy93b08062014-01-09 18:42:36 +00001002 if (IS_ERR(type))
1003 return PTR_ERR(type);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001004 }
Patrick McHardy96518512013-10-14 11:00:02 +02001005
1006 err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK],
1007 nft_hook_policy);
1008 if (err < 0)
1009 return err;
1010 if (ha[NFTA_HOOK_HOOKNUM] == NULL ||
1011 ha[NFTA_HOOK_PRIORITY] == NULL)
1012 return -EINVAL;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001013
1014 hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
1015 if (hooknum >= afi->nhooks)
Patrick McHardy96518512013-10-14 11:00:02 +02001016 return -EINVAL;
Patrick McHardy115a60b2014-01-03 12:16:15 +00001017 priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
Patrick McHardy96518512013-10-14 11:00:02 +02001018
Patrick McHardybaae3e62014-01-09 18:42:34 +00001019 if (!(type->hook_mask & (1 << hooknum)))
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001020 return -EOPNOTSUPP;
Patrick McHardyfa2c1de2014-01-09 18:42:38 +00001021 if (!try_module_get(type->owner))
Patrick McHardybaae3e62014-01-09 18:42:34 +00001022 return -ENOENT;
Patrick McHardyfa2c1de2014-01-09 18:42:38 +00001023 hookfn = type->hooks[hooknum];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001024
Patrick McHardy96518512013-10-14 11:00:02 +02001025 basechain = kzalloc(sizeof(*basechain), GFP_KERNEL);
1026 if (basechain == NULL)
1027 return -ENOMEM;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001028
Patrick McHardy4401a862014-01-09 18:42:32 +00001029 if (nla[NFTA_CHAIN_COUNTERS]) {
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001030 stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]);
1031 if (IS_ERR(stats)) {
Patrick McHardyfa2c1de2014-01-09 18:42:38 +00001032 module_put(type->owner);
Patrick McHardy4401a862014-01-09 18:42:32 +00001033 kfree(basechain);
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001034 return PTR_ERR(stats);
Patrick McHardy4401a862014-01-09 18:42:32 +00001035 }
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001036 basechain->stats = stats;
Patrick McHardy4401a862014-01-09 18:42:32 +00001037 } else {
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001038 stats = alloc_percpu(struct nft_stats);
1039 if (IS_ERR(stats)) {
Patrick McHardyfa2c1de2014-01-09 18:42:38 +00001040 module_put(type->owner);
Patrick McHardy4401a862014-01-09 18:42:32 +00001041 kfree(basechain);
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001042 return PTR_ERR(stats);
Patrick McHardy4401a862014-01-09 18:42:32 +00001043 }
Pablo Neira Ayusoff3cd7b2014-04-09 11:53:06 +02001044 rcu_assign_pointer(basechain->stats, stats);
Patrick McHardy4401a862014-01-09 18:42:32 +00001045 }
1046
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001047 basechain->type = type;
Patrick McHardy96518512013-10-14 11:00:02 +02001048 chain = &basechain->chain;
1049
Patrick McHardy115a60b2014-01-03 12:16:15 +00001050 for (i = 0; i < afi->nops; i++) {
1051 ops = &basechain->ops[i];
1052 ops->pf = family;
1053 ops->owner = afi->owner;
1054 ops->hooknum = hooknum;
1055 ops->priority = priority;
1056 ops->priv = chain;
1057 ops->hook = afi->hooks[ops->hooknum];
1058 if (hookfn)
1059 ops->hook = hookfn;
1060 if (afi->hook_ops_init)
1061 afi->hook_ops_init(ops, i);
1062 }
Patrick McHardy96518512013-10-14 11:00:02 +02001063
1064 chain->flags |= NFT_BASE_CHAIN;
Patrick McHardy57de2a02014-01-09 18:42:31 +00001065 basechain->policy = policy;
Patrick McHardy96518512013-10-14 11:00:02 +02001066 } else {
1067 chain = kzalloc(sizeof(*chain), GFP_KERNEL);
1068 if (chain == NULL)
1069 return -ENOMEM;
1070 }
1071
1072 INIT_LIST_HEAD(&chain->rules);
1073 chain->handle = nf_tables_alloc_handle(table);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001074 chain->net = net;
Pablo Neira Ayusob5bc89b2013-10-10 16:49:19 +02001075 chain->table = table;
Patrick McHardy96518512013-10-14 11:00:02 +02001076 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
1077
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +02001078 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
1079 chain->flags & NFT_BASE_CHAIN) {
Patrick McHardy115a60b2014-01-03 12:16:15 +00001080 err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001081 if (err < 0)
1082 goto err1;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001083 }
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001084
1085 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1086 err = nft_trans_chain_add(&ctx, NFT_MSG_NEWCHAIN);
1087 if (err < 0)
1088 goto err2;
1089
Pablo Neira Ayuso9ddf6322013-10-10 13:26:33 +02001090 list_add_tail(&chain->list, &table->chains);
Patrick McHardy96518512013-10-14 11:00:02 +02001091 return 0;
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001092err2:
1093 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
1094 chain->flags & NFT_BASE_CHAIN) {
1095 nf_unregister_hooks(nft_base_chain(chain)->ops,
1096 afi->nops);
1097 }
1098err1:
1099 nf_tables_chain_destroy(chain);
1100 return err;
Patrick McHardy96518512013-10-14 11:00:02 +02001101}
1102
1103static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
1104 const struct nlmsghdr *nlh,
1105 const struct nlattr * const nla[])
1106{
1107 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02001108 struct nft_af_info *afi;
Patrick McHardy96518512013-10-14 11:00:02 +02001109 struct nft_table *table;
1110 struct nft_chain *chain;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001111 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001112 int family = nfmsg->nfgen_family;
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001113 struct nft_ctx ctx;
1114 int err;
Patrick McHardy96518512013-10-14 11:00:02 +02001115
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001116 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001117 if (IS_ERR(afi))
1118 return PTR_ERR(afi);
1119
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001120 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001121 if (IS_ERR(table))
1122 return PTR_ERR(table);
1123
1124 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
1125 if (IS_ERR(chain))
1126 return PTR_ERR(chain);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001127 if (chain->flags & NFT_CHAIN_INACTIVE)
1128 return -ENOENT;
Patrick McHardy3dd72792014-01-25 08:04:07 +00001129 if (!list_empty(&chain->rules) || chain->use > 0)
Patrick McHardy96518512013-10-14 11:00:02 +02001130 return -EBUSY;
1131
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001132 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1133 err = nft_trans_chain_add(&ctx, NFT_MSG_DELCHAIN);
1134 if (err < 0)
1135 return err;
1136
Patrick McHardy96518512013-10-14 11:00:02 +02001137 list_del(&chain->list);
Patrick McHardy96518512013-10-14 11:00:02 +02001138 return 0;
1139}
1140
Patrick McHardy96518512013-10-14 11:00:02 +02001141/*
1142 * Expressions
1143 */
1144
1145/**
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001146 * nft_register_expr - register nf_tables expr type
1147 * @ops: expr type
Patrick McHardy96518512013-10-14 11:00:02 +02001148 *
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001149 * Registers the expr type for use with nf_tables. Returns zero on
Patrick McHardy96518512013-10-14 11:00:02 +02001150 * success or a negative errno code otherwise.
1151 */
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001152int nft_register_expr(struct nft_expr_type *type)
Patrick McHardy96518512013-10-14 11:00:02 +02001153{
1154 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Tomasz Bursztyka758dbce2014-04-14 15:41:26 +03001155 if (type->family == NFPROTO_UNSPEC)
1156 list_add_tail(&type->list, &nf_tables_expressions);
1157 else
1158 list_add(&type->list, &nf_tables_expressions);
Patrick McHardy96518512013-10-14 11:00:02 +02001159 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1160 return 0;
1161}
1162EXPORT_SYMBOL_GPL(nft_register_expr);
1163
1164/**
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001165 * nft_unregister_expr - unregister nf_tables expr type
1166 * @ops: expr type
Patrick McHardy96518512013-10-14 11:00:02 +02001167 *
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001168 * Unregisters the expr typefor use with nf_tables.
Patrick McHardy96518512013-10-14 11:00:02 +02001169 */
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001170void nft_unregister_expr(struct nft_expr_type *type)
Patrick McHardy96518512013-10-14 11:00:02 +02001171{
1172 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001173 list_del(&type->list);
Patrick McHardy96518512013-10-14 11:00:02 +02001174 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1175}
1176EXPORT_SYMBOL_GPL(nft_unregister_expr);
1177
Patrick McHardy64d46802014-02-05 15:03:37 +00001178static const struct nft_expr_type *__nft_expr_type_get(u8 family,
1179 struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001180{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001181 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001182
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001183 list_for_each_entry(type, &nf_tables_expressions, list) {
Patrick McHardy64d46802014-02-05 15:03:37 +00001184 if (!nla_strcmp(nla, type->name) &&
1185 (!type->family || type->family == family))
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001186 return type;
Patrick McHardy96518512013-10-14 11:00:02 +02001187 }
1188 return NULL;
1189}
1190
Patrick McHardy64d46802014-02-05 15:03:37 +00001191static const struct nft_expr_type *nft_expr_type_get(u8 family,
1192 struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001193{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001194 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001195
1196 if (nla == NULL)
1197 return ERR_PTR(-EINVAL);
1198
Patrick McHardy64d46802014-02-05 15:03:37 +00001199 type = __nft_expr_type_get(family, nla);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001200 if (type != NULL && try_module_get(type->owner))
1201 return type;
Patrick McHardy96518512013-10-14 11:00:02 +02001202
1203#ifdef CONFIG_MODULES
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001204 if (type == NULL) {
Patrick McHardy96518512013-10-14 11:00:02 +02001205 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
Patrick McHardy64d46802014-02-05 15:03:37 +00001206 request_module("nft-expr-%u-%.*s", family,
1207 nla_len(nla), (char *)nla_data(nla));
1208 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1209 if (__nft_expr_type_get(family, nla))
1210 return ERR_PTR(-EAGAIN);
1211
1212 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
Patrick McHardy96518512013-10-14 11:00:02 +02001213 request_module("nft-expr-%.*s",
1214 nla_len(nla), (char *)nla_data(nla));
1215 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardy64d46802014-02-05 15:03:37 +00001216 if (__nft_expr_type_get(family, nla))
Patrick McHardy96518512013-10-14 11:00:02 +02001217 return ERR_PTR(-EAGAIN);
1218 }
1219#endif
1220 return ERR_PTR(-ENOENT);
1221}
1222
1223static const struct nla_policy nft_expr_policy[NFTA_EXPR_MAX + 1] = {
1224 [NFTA_EXPR_NAME] = { .type = NLA_STRING },
1225 [NFTA_EXPR_DATA] = { .type = NLA_NESTED },
1226};
1227
1228static int nf_tables_fill_expr_info(struct sk_buff *skb,
1229 const struct nft_expr *expr)
1230{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001231 if (nla_put_string(skb, NFTA_EXPR_NAME, expr->ops->type->name))
Patrick McHardy96518512013-10-14 11:00:02 +02001232 goto nla_put_failure;
1233
1234 if (expr->ops->dump) {
1235 struct nlattr *data = nla_nest_start(skb, NFTA_EXPR_DATA);
1236 if (data == NULL)
1237 goto nla_put_failure;
1238 if (expr->ops->dump(skb, expr) < 0)
1239 goto nla_put_failure;
1240 nla_nest_end(skb, data);
1241 }
1242
1243 return skb->len;
1244
1245nla_put_failure:
1246 return -1;
1247};
1248
1249struct nft_expr_info {
1250 const struct nft_expr_ops *ops;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001251 struct nlattr *tb[NFT_EXPR_MAXATTR + 1];
Patrick McHardy96518512013-10-14 11:00:02 +02001252};
1253
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001254static int nf_tables_expr_parse(const struct nft_ctx *ctx,
1255 const struct nlattr *nla,
Patrick McHardy96518512013-10-14 11:00:02 +02001256 struct nft_expr_info *info)
1257{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001258 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001259 const struct nft_expr_ops *ops;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001260 struct nlattr *tb[NFTA_EXPR_MAX + 1];
Patrick McHardy96518512013-10-14 11:00:02 +02001261 int err;
1262
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001263 err = nla_parse_nested(tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
Patrick McHardy96518512013-10-14 11:00:02 +02001264 if (err < 0)
1265 return err;
1266
Patrick McHardy64d46802014-02-05 15:03:37 +00001267 type = nft_expr_type_get(ctx->afi->family, tb[NFTA_EXPR_NAME]);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001268 if (IS_ERR(type))
1269 return PTR_ERR(type);
1270
1271 if (tb[NFTA_EXPR_DATA]) {
1272 err = nla_parse_nested(info->tb, type->maxattr,
1273 tb[NFTA_EXPR_DATA], type->policy);
1274 if (err < 0)
1275 goto err1;
1276 } else
1277 memset(info->tb, 0, sizeof(info->tb[0]) * (type->maxattr + 1));
1278
1279 if (type->select_ops != NULL) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001280 ops = type->select_ops(ctx,
1281 (const struct nlattr * const *)info->tb);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001282 if (IS_ERR(ops)) {
1283 err = PTR_ERR(ops);
1284 goto err1;
1285 }
1286 } else
1287 ops = type->ops;
1288
Patrick McHardy96518512013-10-14 11:00:02 +02001289 info->ops = ops;
1290 return 0;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001291
1292err1:
1293 module_put(type->owner);
1294 return err;
Patrick McHardy96518512013-10-14 11:00:02 +02001295}
1296
1297static int nf_tables_newexpr(const struct nft_ctx *ctx,
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001298 const struct nft_expr_info *info,
Patrick McHardy96518512013-10-14 11:00:02 +02001299 struct nft_expr *expr)
1300{
1301 const struct nft_expr_ops *ops = info->ops;
1302 int err;
1303
1304 expr->ops = ops;
1305 if (ops->init) {
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001306 err = ops->init(ctx, expr, (const struct nlattr **)info->tb);
Patrick McHardy96518512013-10-14 11:00:02 +02001307 if (err < 0)
1308 goto err1;
1309 }
1310
Patrick McHardy96518512013-10-14 11:00:02 +02001311 return 0;
1312
1313err1:
1314 expr->ops = NULL;
1315 return err;
1316}
1317
Patrick McHardy62472bc2014-03-07 19:08:30 +01001318static void nf_tables_expr_destroy(const struct nft_ctx *ctx,
1319 struct nft_expr *expr)
Patrick McHardy96518512013-10-14 11:00:02 +02001320{
1321 if (expr->ops->destroy)
Patrick McHardy62472bc2014-03-07 19:08:30 +01001322 expr->ops->destroy(ctx, expr);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001323 module_put(expr->ops->type->owner);
Patrick McHardy96518512013-10-14 11:00:02 +02001324}
1325
1326/*
1327 * Rules
1328 */
1329
1330static struct nft_rule *__nf_tables_rule_lookup(const struct nft_chain *chain,
1331 u64 handle)
1332{
1333 struct nft_rule *rule;
1334
1335 // FIXME: this sucks
1336 list_for_each_entry(rule, &chain->rules, list) {
1337 if (handle == rule->handle)
1338 return rule;
1339 }
1340
1341 return ERR_PTR(-ENOENT);
1342}
1343
1344static struct nft_rule *nf_tables_rule_lookup(const struct nft_chain *chain,
1345 const struct nlattr *nla)
1346{
1347 if (nla == NULL)
1348 return ERR_PTR(-EINVAL);
1349
1350 return __nf_tables_rule_lookup(chain, be64_to_cpu(nla_get_be64(nla)));
1351}
1352
1353static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
1354 [NFTA_RULE_TABLE] = { .type = NLA_STRING },
1355 [NFTA_RULE_CHAIN] = { .type = NLA_STRING,
1356 .len = NFT_CHAIN_MAXNAMELEN - 1 },
1357 [NFTA_RULE_HANDLE] = { .type = NLA_U64 },
1358 [NFTA_RULE_EXPRESSIONS] = { .type = NLA_NESTED },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001359 [NFTA_RULE_COMPAT] = { .type = NLA_NESTED },
Eric Leblond5e948462013-10-10 13:41:44 +02001360 [NFTA_RULE_POSITION] = { .type = NLA_U64 },
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01001361 [NFTA_RULE_USERDATA] = { .type = NLA_BINARY,
1362 .len = NFT_USERDATA_MAXLEN },
Patrick McHardy96518512013-10-14 11:00:02 +02001363};
1364
1365static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
1366 int event, u32 flags, int family,
1367 const struct nft_table *table,
1368 const struct nft_chain *chain,
1369 const struct nft_rule *rule)
1370{
1371 struct nlmsghdr *nlh;
1372 struct nfgenmsg *nfmsg;
1373 const struct nft_expr *expr, *next;
1374 struct nlattr *list;
Eric Leblond5e948462013-10-10 13:41:44 +02001375 const struct nft_rule *prule;
1376 int type = event | NFNL_SUBSYS_NFTABLES << 8;
Patrick McHardy96518512013-10-14 11:00:02 +02001377
Eric Leblond5e948462013-10-10 13:41:44 +02001378 nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg),
Patrick McHardy96518512013-10-14 11:00:02 +02001379 flags);
1380 if (nlh == NULL)
1381 goto nla_put_failure;
1382
1383 nfmsg = nlmsg_data(nlh);
1384 nfmsg->nfgen_family = family;
1385 nfmsg->version = NFNETLINK_V0;
1386 nfmsg->res_id = 0;
1387
1388 if (nla_put_string(skb, NFTA_RULE_TABLE, table->name))
1389 goto nla_put_failure;
1390 if (nla_put_string(skb, NFTA_RULE_CHAIN, chain->name))
1391 goto nla_put_failure;
1392 if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
1393 goto nla_put_failure;
1394
Eric Leblond5e948462013-10-10 13:41:44 +02001395 if ((event != NFT_MSG_DELRULE) && (rule->list.prev != &chain->rules)) {
1396 prule = list_entry(rule->list.prev, struct nft_rule, list);
1397 if (nla_put_be64(skb, NFTA_RULE_POSITION,
1398 cpu_to_be64(prule->handle)))
1399 goto nla_put_failure;
1400 }
1401
Patrick McHardy96518512013-10-14 11:00:02 +02001402 list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
1403 if (list == NULL)
1404 goto nla_put_failure;
1405 nft_rule_for_each_expr(expr, next, rule) {
1406 struct nlattr *elem = nla_nest_start(skb, NFTA_LIST_ELEM);
1407 if (elem == NULL)
1408 goto nla_put_failure;
1409 if (nf_tables_fill_expr_info(skb, expr) < 0)
1410 goto nla_put_failure;
1411 nla_nest_end(skb, elem);
1412 }
1413 nla_nest_end(skb, list);
1414
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01001415 if (rule->ulen &&
1416 nla_put(skb, NFTA_RULE_USERDATA, rule->ulen, nft_userdata(rule)))
1417 goto nla_put_failure;
1418
Patrick McHardy96518512013-10-14 11:00:02 +02001419 return nlmsg_end(skb, nlh);
1420
1421nla_put_failure:
1422 nlmsg_trim(skb, nlh);
1423 return -1;
1424}
1425
1426static int nf_tables_rule_notify(const struct sk_buff *oskb,
1427 const struct nlmsghdr *nlh,
1428 const struct nft_table *table,
1429 const struct nft_chain *chain,
1430 const struct nft_rule *rule,
1431 int event, u32 flags, int family)
1432{
1433 struct sk_buff *skb;
1434 u32 portid = NETLINK_CB(oskb).portid;
1435 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
1436 u32 seq = nlh->nlmsg_seq;
1437 bool report;
1438 int err;
1439
1440 report = nlmsg_report(nlh);
1441 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
1442 return 0;
1443
1444 err = -ENOBUFS;
1445 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1446 if (skb == NULL)
1447 goto err;
1448
1449 err = nf_tables_fill_rule_info(skb, portid, seq, event, flags,
1450 family, table, chain, rule);
1451 if (err < 0) {
1452 kfree_skb(skb);
1453 goto err;
1454 }
1455
1456 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
1457 GFP_KERNEL);
1458err:
1459 if (err < 0)
1460 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
1461 return err;
1462}
1463
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001464static inline bool
1465nft_rule_is_active(struct net *net, const struct nft_rule *rule)
1466{
1467 return (rule->genmask & (1 << net->nft.gencursor)) == 0;
1468}
1469
1470static inline int gencursor_next(struct net *net)
1471{
1472 return net->nft.gencursor+1 == 1 ? 1 : 0;
1473}
1474
1475static inline int
1476nft_rule_is_active_next(struct net *net, const struct nft_rule *rule)
1477{
1478 return (rule->genmask & (1 << gencursor_next(net))) == 0;
1479}
1480
1481static inline void
1482nft_rule_activate_next(struct net *net, struct nft_rule *rule)
1483{
1484 /* Now inactive, will be active in the future */
1485 rule->genmask = (1 << net->nft.gencursor);
1486}
1487
1488static inline void
1489nft_rule_disactivate_next(struct net *net, struct nft_rule *rule)
1490{
1491 rule->genmask = (1 << gencursor_next(net));
1492}
1493
1494static inline void nft_rule_clear(struct net *net, struct nft_rule *rule)
1495{
1496 rule->genmask = 0;
1497}
1498
Patrick McHardy96518512013-10-14 11:00:02 +02001499static int nf_tables_dump_rules(struct sk_buff *skb,
1500 struct netlink_callback *cb)
1501{
1502 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
1503 const struct nft_af_info *afi;
1504 const struct nft_table *table;
1505 const struct nft_chain *chain;
1506 const struct nft_rule *rule;
1507 unsigned int idx = 0, s_idx = cb->args[0];
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001508 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001509 int family = nfmsg->nfgen_family;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001510 u8 genctr = ACCESS_ONCE(net->nft.genctr);
1511 u8 gencursor = ACCESS_ONCE(net->nft.gencursor);
Patrick McHardy96518512013-10-14 11:00:02 +02001512
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001513 list_for_each_entry(afi, &net->nft.af_info, list) {
Patrick McHardy96518512013-10-14 11:00:02 +02001514 if (family != NFPROTO_UNSPEC && family != afi->family)
1515 continue;
1516
1517 list_for_each_entry(table, &afi->tables, list) {
1518 list_for_each_entry(chain, &table->chains, list) {
1519 list_for_each_entry(rule, &chain->rules, list) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001520 if (!nft_rule_is_active(net, rule))
1521 goto cont;
Patrick McHardy96518512013-10-14 11:00:02 +02001522 if (idx < s_idx)
1523 goto cont;
1524 if (idx > s_idx)
1525 memset(&cb->args[1], 0,
1526 sizeof(cb->args) - sizeof(cb->args[0]));
1527 if (nf_tables_fill_rule_info(skb, NETLINK_CB(cb->skb).portid,
1528 cb->nlh->nlmsg_seq,
1529 NFT_MSG_NEWRULE,
1530 NLM_F_MULTI | NLM_F_APPEND,
1531 afi->family, table, chain, rule) < 0)
1532 goto done;
1533cont:
1534 idx++;
1535 }
1536 }
1537 }
1538 }
1539done:
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001540 /* Invalidate this dump, a transition to the new generation happened */
1541 if (gencursor != net->nft.gencursor || genctr != net->nft.genctr)
1542 return -EBUSY;
1543
Patrick McHardy96518512013-10-14 11:00:02 +02001544 cb->args[0] = idx;
1545 return skb->len;
1546}
1547
1548static int nf_tables_getrule(struct sock *nlsk, struct sk_buff *skb,
1549 const struct nlmsghdr *nlh,
1550 const struct nlattr * const nla[])
1551{
1552 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1553 const struct nft_af_info *afi;
1554 const struct nft_table *table;
1555 const struct nft_chain *chain;
1556 const struct nft_rule *rule;
1557 struct sk_buff *skb2;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001558 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001559 int family = nfmsg->nfgen_family;
1560 int err;
1561
1562 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1563 struct netlink_dump_control c = {
1564 .dump = nf_tables_dump_rules,
1565 };
1566 return netlink_dump_start(nlsk, skb, nlh, &c);
1567 }
1568
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001569 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001570 if (IS_ERR(afi))
1571 return PTR_ERR(afi);
1572
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001573 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001574 if (IS_ERR(table))
1575 return PTR_ERR(table);
1576
1577 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1578 if (IS_ERR(chain))
1579 return PTR_ERR(chain);
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02001580 if (chain->flags & NFT_CHAIN_INACTIVE)
1581 return -ENOENT;
Patrick McHardy96518512013-10-14 11:00:02 +02001582
1583 rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
1584 if (IS_ERR(rule))
1585 return PTR_ERR(rule);
1586
1587 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1588 if (!skb2)
1589 return -ENOMEM;
1590
1591 err = nf_tables_fill_rule_info(skb2, NETLINK_CB(skb).portid,
1592 nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
1593 family, table, chain, rule);
1594 if (err < 0)
1595 goto err;
1596
1597 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
1598
1599err:
1600 kfree_skb(skb2);
1601 return err;
1602}
1603
Patrick McHardy62472bc2014-03-07 19:08:30 +01001604static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
1605 struct nft_rule *rule)
Patrick McHardy96518512013-10-14 11:00:02 +02001606{
Patrick McHardy96518512013-10-14 11:00:02 +02001607 struct nft_expr *expr;
1608
1609 /*
1610 * Careful: some expressions might not be initialized in case this
1611 * is called on error from nf_tables_newrule().
1612 */
1613 expr = nft_expr_first(rule);
1614 while (expr->ops && expr != nft_expr_last(rule)) {
Patrick McHardy62472bc2014-03-07 19:08:30 +01001615 nf_tables_expr_destroy(ctx, expr);
Patrick McHardy96518512013-10-14 11:00:02 +02001616 expr = nft_expr_next(expr);
1617 }
1618 kfree(rule);
1619}
1620
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02001621static struct nft_trans *nft_trans_rule_add(struct nft_ctx *ctx, int msg_type,
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001622 struct nft_rule *rule)
1623{
1624 struct nft_trans *trans;
1625
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02001626 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_rule));
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001627 if (trans == NULL)
1628 return NULL;
1629
1630 nft_trans_rule(trans) = rule;
1631 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
1632
1633 return trans;
1634}
1635
Patrick McHardy96518512013-10-14 11:00:02 +02001636#define NFT_RULE_MAXEXPRS 128
1637
1638static struct nft_expr_info *info;
1639
1640static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
1641 const struct nlmsghdr *nlh,
1642 const struct nlattr * const nla[])
1643{
1644 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02001645 struct nft_af_info *afi;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001646 struct net *net = sock_net(skb->sk);
Patrick McHardy96518512013-10-14 11:00:02 +02001647 struct nft_table *table;
1648 struct nft_chain *chain;
1649 struct nft_rule *rule, *old_rule = NULL;
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001650 struct nft_trans *trans = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +02001651 struct nft_expr *expr;
1652 struct nft_ctx ctx;
1653 struct nlattr *tmp;
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01001654 unsigned int size, i, n, ulen = 0;
Patrick McHardy96518512013-10-14 11:00:02 +02001655 int err, rem;
1656 bool create;
Eric Leblond5e948462013-10-10 13:41:44 +02001657 u64 handle, pos_handle;
Patrick McHardy96518512013-10-14 11:00:02 +02001658
1659 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
1660
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001661 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
Patrick McHardy96518512013-10-14 11:00:02 +02001662 if (IS_ERR(afi))
1663 return PTR_ERR(afi);
1664
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001665 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001666 if (IS_ERR(table))
1667 return PTR_ERR(table);
1668
1669 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1670 if (IS_ERR(chain))
1671 return PTR_ERR(chain);
1672
1673 if (nla[NFTA_RULE_HANDLE]) {
1674 handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
1675 rule = __nf_tables_rule_lookup(chain, handle);
1676 if (IS_ERR(rule))
1677 return PTR_ERR(rule);
1678
1679 if (nlh->nlmsg_flags & NLM_F_EXCL)
1680 return -EEXIST;
1681 if (nlh->nlmsg_flags & NLM_F_REPLACE)
1682 old_rule = rule;
1683 else
1684 return -EOPNOTSUPP;
1685 } else {
1686 if (!create || nlh->nlmsg_flags & NLM_F_REPLACE)
1687 return -EINVAL;
1688 handle = nf_tables_alloc_handle(table);
1689 }
1690
Eric Leblond5e948462013-10-10 13:41:44 +02001691 if (nla[NFTA_RULE_POSITION]) {
1692 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
1693 return -EOPNOTSUPP;
1694
1695 pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
1696 old_rule = __nf_tables_rule_lookup(chain, pos_handle);
1697 if (IS_ERR(old_rule))
1698 return PTR_ERR(old_rule);
1699 }
1700
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001701 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1702
Patrick McHardy96518512013-10-14 11:00:02 +02001703 n = 0;
1704 size = 0;
1705 if (nla[NFTA_RULE_EXPRESSIONS]) {
1706 nla_for_each_nested(tmp, nla[NFTA_RULE_EXPRESSIONS], rem) {
1707 err = -EINVAL;
1708 if (nla_type(tmp) != NFTA_LIST_ELEM)
1709 goto err1;
1710 if (n == NFT_RULE_MAXEXPRS)
1711 goto err1;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001712 err = nf_tables_expr_parse(&ctx, tmp, &info[n]);
Patrick McHardy96518512013-10-14 11:00:02 +02001713 if (err < 0)
1714 goto err1;
1715 size += info[n].ops->size;
1716 n++;
1717 }
1718 }
1719
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01001720 if (nla[NFTA_RULE_USERDATA])
1721 ulen = nla_len(nla[NFTA_RULE_USERDATA]);
1722
Patrick McHardy96518512013-10-14 11:00:02 +02001723 err = -ENOMEM;
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01001724 rule = kzalloc(sizeof(*rule) + size + ulen, GFP_KERNEL);
Patrick McHardy96518512013-10-14 11:00:02 +02001725 if (rule == NULL)
1726 goto err1;
1727
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001728 nft_rule_activate_next(net, rule);
1729
Patrick McHardy96518512013-10-14 11:00:02 +02001730 rule->handle = handle;
1731 rule->dlen = size;
Pablo Neira Ayuso0768b3b2014-02-19 17:27:06 +01001732 rule->ulen = ulen;
1733
1734 if (ulen)
1735 nla_memcpy(nft_userdata(rule), nla[NFTA_RULE_USERDATA], ulen);
Patrick McHardy96518512013-10-14 11:00:02 +02001736
Patrick McHardy96518512013-10-14 11:00:02 +02001737 expr = nft_expr_first(rule);
1738 for (i = 0; i < n; i++) {
1739 err = nf_tables_newexpr(&ctx, &info[i], expr);
1740 if (err < 0)
1741 goto err2;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001742 info[i].ops = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +02001743 expr = nft_expr_next(expr);
1744 }
1745
Patrick McHardy96518512013-10-14 11:00:02 +02001746 if (nlh->nlmsg_flags & NLM_F_REPLACE) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001747 if (nft_rule_is_active_next(net, old_rule)) {
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02001748 trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE,
1749 old_rule);
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001750 if (trans == NULL) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001751 err = -ENOMEM;
1752 goto err2;
1753 }
1754 nft_rule_disactivate_next(net, old_rule);
1755 list_add_tail(&rule->list, &old_rule->list);
1756 } else {
1757 err = -ENOENT;
1758 goto err2;
1759 }
Patrick McHardy96518512013-10-14 11:00:02 +02001760 } else if (nlh->nlmsg_flags & NLM_F_APPEND)
Eric Leblond5e948462013-10-10 13:41:44 +02001761 if (old_rule)
1762 list_add_rcu(&rule->list, &old_rule->list);
1763 else
1764 list_add_tail_rcu(&rule->list, &chain->rules);
1765 else {
1766 if (old_rule)
1767 list_add_tail_rcu(&rule->list, &old_rule->list);
1768 else
1769 list_add_rcu(&rule->list, &chain->rules);
1770 }
Patrick McHardy96518512013-10-14 11:00:02 +02001771
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02001772 if (nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule) == NULL) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001773 err = -ENOMEM;
1774 goto err3;
1775 }
Patrick McHardy96518512013-10-14 11:00:02 +02001776 return 0;
1777
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001778err3:
1779 list_del_rcu(&rule->list);
Pablo Neira Ayuso1081d112014-04-04 01:24:07 +02001780 if (trans) {
1781 list_del_rcu(&nft_trans_rule(trans)->list);
1782 nft_rule_clear(net, nft_trans_rule(trans));
1783 nft_trans_destroy(trans);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001784 }
Patrick McHardy96518512013-10-14 11:00:02 +02001785err2:
Patrick McHardy62472bc2014-03-07 19:08:30 +01001786 nf_tables_rule_destroy(&ctx, rule);
Patrick McHardy96518512013-10-14 11:00:02 +02001787err1:
1788 for (i = 0; i < n; i++) {
1789 if (info[i].ops != NULL)
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001790 module_put(info[i].ops->type->owner);
Patrick McHardy96518512013-10-14 11:00:02 +02001791 }
1792 return err;
1793}
1794
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001795static int
1796nf_tables_delrule_one(struct nft_ctx *ctx, struct nft_rule *rule)
1797{
1798 /* You cannot delete the same rule twice */
1799 if (nft_rule_is_active_next(ctx->net, rule)) {
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02001800 if (nft_trans_rule_add(ctx, NFT_MSG_DELRULE, rule) == NULL)
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001801 return -ENOMEM;
1802 nft_rule_disactivate_next(ctx->net, rule);
1803 return 0;
1804 }
1805 return -ENOENT;
1806}
1807
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001808static int nf_table_delrule_by_chain(struct nft_ctx *ctx)
1809{
1810 struct nft_rule *rule;
1811 int err;
1812
1813 list_for_each_entry(rule, &ctx->chain->rules, list) {
1814 err = nf_tables_delrule_one(ctx, rule);
1815 if (err < 0)
1816 return err;
1817 }
1818 return 0;
1819}
1820
Patrick McHardy96518512013-10-14 11:00:02 +02001821static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
1822 const struct nlmsghdr *nlh,
1823 const struct nlattr * const nla[])
1824{
1825 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02001826 struct nft_af_info *afi;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001827 struct net *net = sock_net(skb->sk);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02001828 struct nft_table *table;
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001829 struct nft_chain *chain = NULL;
1830 struct nft_rule *rule;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001831 int family = nfmsg->nfgen_family, err = 0;
1832 struct nft_ctx ctx;
Patrick McHardy96518512013-10-14 11:00:02 +02001833
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001834 afi = nf_tables_afinfo_lookup(net, family, false);
Patrick McHardy96518512013-10-14 11:00:02 +02001835 if (IS_ERR(afi))
1836 return PTR_ERR(afi);
1837
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001838 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001839 if (IS_ERR(table))
1840 return PTR_ERR(table);
1841
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001842 if (nla[NFTA_RULE_CHAIN]) {
1843 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1844 if (IS_ERR(chain))
1845 return PTR_ERR(chain);
1846 }
Patrick McHardy96518512013-10-14 11:00:02 +02001847
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001848 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1849
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001850 if (chain) {
1851 if (nla[NFTA_RULE_HANDLE]) {
1852 rule = nf_tables_rule_lookup(chain,
1853 nla[NFTA_RULE_HANDLE]);
1854 if (IS_ERR(rule))
1855 return PTR_ERR(rule);
Patrick McHardy96518512013-10-14 11:00:02 +02001856
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001857 err = nf_tables_delrule_one(&ctx, rule);
Pablo Neira Ayusocf9dc092013-11-24 20:39:10 +01001858 } else {
1859 err = nf_table_delrule_by_chain(&ctx);
1860 }
1861 } else {
1862 list_for_each_entry(chain, &table->chains, list) {
1863 ctx.chain = chain;
1864 err = nf_table_delrule_by_chain(&ctx);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001865 if (err < 0)
1866 break;
Patrick McHardy96518512013-10-14 11:00:02 +02001867 }
1868 }
1869
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02001870 return err;
1871}
1872
Patrick McHardy20a69342013-10-11 12:06:22 +02001873/*
1874 * Sets
1875 */
1876
1877static LIST_HEAD(nf_tables_set_ops);
1878
1879int nft_register_set(struct nft_set_ops *ops)
1880{
1881 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1882 list_add_tail(&ops->list, &nf_tables_set_ops);
1883 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1884 return 0;
1885}
1886EXPORT_SYMBOL_GPL(nft_register_set);
1887
1888void nft_unregister_set(struct nft_set_ops *ops)
1889{
1890 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1891 list_del(&ops->list);
1892 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1893}
1894EXPORT_SYMBOL_GPL(nft_unregister_set);
1895
Patrick McHardyc50b9602014-03-28 10:19:47 +00001896/*
1897 * Select a set implementation based on the data characteristics and the
1898 * given policy. The total memory use might not be known if no size is
1899 * given, in that case the amount of memory per element is used.
1900 */
1901static const struct nft_set_ops *
1902nft_select_set_ops(const struct nlattr * const nla[],
1903 const struct nft_set_desc *desc,
1904 enum nft_set_policies policy)
Patrick McHardy20a69342013-10-11 12:06:22 +02001905{
Patrick McHardyc50b9602014-03-28 10:19:47 +00001906 const struct nft_set_ops *ops, *bops;
1907 struct nft_set_estimate est, best;
Patrick McHardy20a69342013-10-11 12:06:22 +02001908 u32 features;
1909
1910#ifdef CONFIG_MODULES
1911 if (list_empty(&nf_tables_set_ops)) {
1912 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1913 request_module("nft-set");
1914 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1915 if (!list_empty(&nf_tables_set_ops))
1916 return ERR_PTR(-EAGAIN);
1917 }
1918#endif
1919 features = 0;
1920 if (nla[NFTA_SET_FLAGS] != NULL) {
1921 features = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
1922 features &= NFT_SET_INTERVAL | NFT_SET_MAP;
1923 }
1924
Patrick McHardyc50b9602014-03-28 10:19:47 +00001925 bops = NULL;
1926 best.size = ~0;
1927 best.class = ~0;
1928
Patrick McHardy20a69342013-10-11 12:06:22 +02001929 list_for_each_entry(ops, &nf_tables_set_ops, list) {
1930 if ((ops->features & features) != features)
1931 continue;
Patrick McHardyc50b9602014-03-28 10:19:47 +00001932 if (!ops->estimate(desc, features, &est))
1933 continue;
1934
1935 switch (policy) {
1936 case NFT_SET_POL_PERFORMANCE:
1937 if (est.class < best.class)
1938 break;
1939 if (est.class == best.class && est.size < best.size)
1940 break;
1941 continue;
1942 case NFT_SET_POL_MEMORY:
1943 if (est.size < best.size)
1944 break;
1945 if (est.size == best.size && est.class < best.class)
1946 break;
1947 continue;
1948 default:
1949 break;
1950 }
1951
Patrick McHardy20a69342013-10-11 12:06:22 +02001952 if (!try_module_get(ops->owner))
1953 continue;
Patrick McHardyc50b9602014-03-28 10:19:47 +00001954 if (bops != NULL)
1955 module_put(bops->owner);
1956
1957 bops = ops;
1958 best = est;
Patrick McHardy20a69342013-10-11 12:06:22 +02001959 }
1960
Patrick McHardyc50b9602014-03-28 10:19:47 +00001961 if (bops != NULL)
1962 return bops;
1963
Patrick McHardy20a69342013-10-11 12:06:22 +02001964 return ERR_PTR(-EOPNOTSUPP);
1965}
1966
1967static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
1968 [NFTA_SET_TABLE] = { .type = NLA_STRING },
1969 [NFTA_SET_NAME] = { .type = NLA_STRING },
1970 [NFTA_SET_FLAGS] = { .type = NLA_U32 },
1971 [NFTA_SET_KEY_TYPE] = { .type = NLA_U32 },
1972 [NFTA_SET_KEY_LEN] = { .type = NLA_U32 },
1973 [NFTA_SET_DATA_TYPE] = { .type = NLA_U32 },
1974 [NFTA_SET_DATA_LEN] = { .type = NLA_U32 },
Patrick McHardyc50b9602014-03-28 10:19:47 +00001975 [NFTA_SET_POLICY] = { .type = NLA_U32 },
1976 [NFTA_SET_DESC] = { .type = NLA_NESTED },
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02001977 [NFTA_SET_ID] = { .type = NLA_U32 },
Patrick McHardyc50b9602014-03-28 10:19:47 +00001978};
1979
1980static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
1981 [NFTA_SET_DESC_SIZE] = { .type = NLA_U32 },
Patrick McHardy20a69342013-10-11 12:06:22 +02001982};
1983
1984static int nft_ctx_init_from_setattr(struct nft_ctx *ctx,
1985 const struct sk_buff *skb,
1986 const struct nlmsghdr *nlh,
1987 const struct nlattr * const nla[])
1988{
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02001989 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02001990 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02001991 struct nft_af_info *afi = NULL;
1992 struct nft_table *table = NULL;
Patrick McHardy20a69342013-10-11 12:06:22 +02001993
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01001994 if (nfmsg->nfgen_family != NFPROTO_UNSPEC) {
1995 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
1996 if (IS_ERR(afi))
1997 return PTR_ERR(afi);
1998 }
Patrick McHardy20a69342013-10-11 12:06:22 +02001999
2000 if (nla[NFTA_SET_TABLE] != NULL) {
Patrick McHardyec2c9932014-02-05 15:03:35 +00002001 if (afi == NULL)
2002 return -EAFNOSUPPORT;
2003
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002004 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02002005 if (IS_ERR(table))
2006 return PTR_ERR(table);
2007 }
2008
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002009 nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002010 return 0;
2011}
2012
2013struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
2014 const struct nlattr *nla)
2015{
2016 struct nft_set *set;
2017
2018 if (nla == NULL)
2019 return ERR_PTR(-EINVAL);
2020
2021 list_for_each_entry(set, &table->sets, list) {
2022 if (!nla_strcmp(nla, set->name))
2023 return set;
2024 }
2025 return ERR_PTR(-ENOENT);
2026}
2027
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002028struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
2029 const struct nlattr *nla)
2030{
2031 struct nft_trans *trans;
2032 u32 id = ntohl(nla_get_be32(nla));
2033
2034 list_for_each_entry(trans, &net->nft.commit_list, list) {
2035 if (trans->msg_type == NFT_MSG_NEWSET &&
2036 id == nft_trans_set_id(trans))
2037 return nft_trans_set(trans);
2038 }
2039 return ERR_PTR(-ENOENT);
2040}
2041
Patrick McHardy20a69342013-10-11 12:06:22 +02002042static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
2043 const char *name)
2044{
2045 const struct nft_set *i;
2046 const char *p;
2047 unsigned long *inuse;
Patrick McHardy60eb1892014-03-07 12:34:05 +01002048 unsigned int n = 0, min = 0;
Patrick McHardy20a69342013-10-11 12:06:22 +02002049
2050 p = strnchr(name, IFNAMSIZ, '%');
2051 if (p != NULL) {
2052 if (p[1] != 'd' || strchr(p + 2, '%'))
2053 return -EINVAL;
2054
2055 inuse = (unsigned long *)get_zeroed_page(GFP_KERNEL);
2056 if (inuse == NULL)
2057 return -ENOMEM;
Patrick McHardy60eb1892014-03-07 12:34:05 +01002058cont:
Patrick McHardy20a69342013-10-11 12:06:22 +02002059 list_for_each_entry(i, &ctx->table->sets, list) {
Daniel Borkmann14662912013-12-31 12:40:05 +01002060 int tmp;
2061
2062 if (!sscanf(i->name, name, &tmp))
Patrick McHardy20a69342013-10-11 12:06:22 +02002063 continue;
Patrick McHardy60eb1892014-03-07 12:34:05 +01002064 if (tmp < min || tmp >= min + BITS_PER_BYTE * PAGE_SIZE)
Patrick McHardy20a69342013-10-11 12:06:22 +02002065 continue;
Daniel Borkmann14662912013-12-31 12:40:05 +01002066
Patrick McHardy60eb1892014-03-07 12:34:05 +01002067 set_bit(tmp - min, inuse);
Patrick McHardy20a69342013-10-11 12:06:22 +02002068 }
2069
Patrick McHardy53b70282014-02-05 12:26:22 +01002070 n = find_first_zero_bit(inuse, BITS_PER_BYTE * PAGE_SIZE);
Patrick McHardy60eb1892014-03-07 12:34:05 +01002071 if (n >= BITS_PER_BYTE * PAGE_SIZE) {
2072 min += BITS_PER_BYTE * PAGE_SIZE;
2073 memset(inuse, 0, PAGE_SIZE);
2074 goto cont;
2075 }
Patrick McHardy20a69342013-10-11 12:06:22 +02002076 free_page((unsigned long)inuse);
2077 }
2078
Patrick McHardy60eb1892014-03-07 12:34:05 +01002079 snprintf(set->name, sizeof(set->name), name, min + n);
Patrick McHardy20a69342013-10-11 12:06:22 +02002080 list_for_each_entry(i, &ctx->table->sets, list) {
2081 if (!strcmp(set->name, i->name))
2082 return -ENFILE;
2083 }
2084 return 0;
2085}
2086
2087static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
2088 const struct nft_set *set, u16 event, u16 flags)
2089{
2090 struct nfgenmsg *nfmsg;
2091 struct nlmsghdr *nlh;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002092 struct nlattr *desc;
Patrick McHardy20a69342013-10-11 12:06:22 +02002093 u32 portid = NETLINK_CB(ctx->skb).portid;
2094 u32 seq = ctx->nlh->nlmsg_seq;
2095
2096 event |= NFNL_SUBSYS_NFTABLES << 8;
2097 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
2098 flags);
2099 if (nlh == NULL)
2100 goto nla_put_failure;
2101
2102 nfmsg = nlmsg_data(nlh);
2103 nfmsg->nfgen_family = ctx->afi->family;
2104 nfmsg->version = NFNETLINK_V0;
2105 nfmsg->res_id = 0;
2106
2107 if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
2108 goto nla_put_failure;
2109 if (nla_put_string(skb, NFTA_SET_NAME, set->name))
2110 goto nla_put_failure;
2111 if (set->flags != 0)
2112 if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
2113 goto nla_put_failure;
2114
2115 if (nla_put_be32(skb, NFTA_SET_KEY_TYPE, htonl(set->ktype)))
2116 goto nla_put_failure;
2117 if (nla_put_be32(skb, NFTA_SET_KEY_LEN, htonl(set->klen)))
2118 goto nla_put_failure;
2119 if (set->flags & NFT_SET_MAP) {
2120 if (nla_put_be32(skb, NFTA_SET_DATA_TYPE, htonl(set->dtype)))
2121 goto nla_put_failure;
2122 if (nla_put_be32(skb, NFTA_SET_DATA_LEN, htonl(set->dlen)))
2123 goto nla_put_failure;
2124 }
2125
Patrick McHardyc50b9602014-03-28 10:19:47 +00002126 desc = nla_nest_start(skb, NFTA_SET_DESC);
2127 if (desc == NULL)
2128 goto nla_put_failure;
2129 if (set->size &&
2130 nla_put_be32(skb, NFTA_SET_DESC_SIZE, htonl(set->size)))
2131 goto nla_put_failure;
2132 nla_nest_end(skb, desc);
2133
Patrick McHardy20a69342013-10-11 12:06:22 +02002134 return nlmsg_end(skb, nlh);
2135
2136nla_put_failure:
2137 nlmsg_trim(skb, nlh);
2138 return -1;
2139}
2140
2141static int nf_tables_set_notify(const struct nft_ctx *ctx,
2142 const struct nft_set *set,
2143 int event)
2144{
2145 struct sk_buff *skb;
2146 u32 portid = NETLINK_CB(ctx->skb).portid;
Patrick McHardy20a69342013-10-11 12:06:22 +02002147 bool report;
2148 int err;
2149
2150 report = nlmsg_report(ctx->nlh);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002151 if (!report && !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
Patrick McHardy20a69342013-10-11 12:06:22 +02002152 return 0;
2153
2154 err = -ENOBUFS;
2155 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
2156 if (skb == NULL)
2157 goto err;
2158
2159 err = nf_tables_fill_set(skb, ctx, set, event, 0);
2160 if (err < 0) {
2161 kfree_skb(skb);
2162 goto err;
2163 }
2164
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002165 err = nfnetlink_send(skb, ctx->net, portid, NFNLGRP_NFTABLES, report,
Patrick McHardy20a69342013-10-11 12:06:22 +02002166 GFP_KERNEL);
2167err:
2168 if (err < 0)
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002169 nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, err);
Patrick McHardy20a69342013-10-11 12:06:22 +02002170 return err;
2171}
2172
2173static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb,
2174 struct netlink_callback *cb)
2175{
2176 const struct nft_set *set;
2177 unsigned int idx = 0, s_idx = cb->args[0];
2178
2179 if (cb->args[1])
2180 return skb->len;
2181
2182 list_for_each_entry(set, &ctx->table->sets, list) {
2183 if (idx < s_idx)
2184 goto cont;
2185 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
2186 NLM_F_MULTI) < 0) {
2187 cb->args[0] = idx;
2188 goto done;
2189 }
2190cont:
2191 idx++;
2192 }
2193 cb->args[1] = 1;
2194done:
2195 return skb->len;
2196}
2197
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002198static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb,
2199 struct netlink_callback *cb)
Patrick McHardy20a69342013-10-11 12:06:22 +02002200{
2201 const struct nft_set *set;
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002202 unsigned int idx, s_idx = cb->args[0];
Patrick McHardy20a69342013-10-11 12:06:22 +02002203 struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
2204
2205 if (cb->args[1])
2206 return skb->len;
2207
2208 list_for_each_entry(table, &ctx->afi->tables, list) {
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002209 if (cur_table) {
2210 if (cur_table != table)
2211 continue;
Patrick McHardy20a69342013-10-11 12:06:22 +02002212
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002213 cur_table = NULL;
2214 }
Patrick McHardy20a69342013-10-11 12:06:22 +02002215 ctx->table = table;
Pablo Neira Ayusoe38195b2013-12-24 18:32:35 +01002216 idx = 0;
Patrick McHardy20a69342013-10-11 12:06:22 +02002217 list_for_each_entry(set, &ctx->table->sets, list) {
2218 if (idx < s_idx)
2219 goto cont;
2220 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
2221 NLM_F_MULTI) < 0) {
2222 cb->args[0] = idx;
2223 cb->args[2] = (unsigned long) table;
2224 goto done;
2225 }
2226cont:
2227 idx++;
2228 }
2229 }
2230 cb->args[1] = 1;
2231done:
2232 return skb->len;
2233}
2234
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002235static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb,
2236 struct netlink_callback *cb)
2237{
2238 const struct nft_set *set;
2239 unsigned int idx, s_idx = cb->args[0];
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02002240 struct nft_af_info *afi;
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002241 struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
2242 struct net *net = sock_net(skb->sk);
2243 int cur_family = cb->args[3];
2244
2245 if (cb->args[1])
2246 return skb->len;
2247
2248 list_for_each_entry(afi, &net->nft.af_info, list) {
2249 if (cur_family) {
2250 if (afi->family != cur_family)
2251 continue;
2252
2253 cur_family = 0;
2254 }
2255
2256 list_for_each_entry(table, &afi->tables, list) {
2257 if (cur_table) {
2258 if (cur_table != table)
2259 continue;
2260
2261 cur_table = NULL;
2262 }
2263
2264 ctx->table = table;
2265 ctx->afi = afi;
2266 idx = 0;
2267 list_for_each_entry(set, &ctx->table->sets, list) {
2268 if (idx < s_idx)
2269 goto cont;
2270 if (nf_tables_fill_set(skb, ctx, set,
2271 NFT_MSG_NEWSET,
2272 NLM_F_MULTI) < 0) {
2273 cb->args[0] = idx;
2274 cb->args[2] = (unsigned long) table;
2275 cb->args[3] = afi->family;
2276 goto done;
2277 }
2278cont:
2279 idx++;
2280 }
2281 if (s_idx)
2282 s_idx = 0;
2283 }
2284 }
2285 cb->args[1] = 1;
2286done:
2287 return skb->len;
2288}
2289
Patrick McHardy20a69342013-10-11 12:06:22 +02002290static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
2291{
2292 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
2293 struct nlattr *nla[NFTA_SET_MAX + 1];
2294 struct nft_ctx ctx;
2295 int err, ret;
2296
2297 err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_MAX,
2298 nft_set_policy);
2299 if (err < 0)
2300 return err;
2301
2302 err = nft_ctx_init_from_setattr(&ctx, cb->skb, cb->nlh, (void *)nla);
2303 if (err < 0)
2304 return err;
2305
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002306 if (ctx.table == NULL) {
2307 if (ctx.afi == NULL)
2308 ret = nf_tables_dump_sets_all(&ctx, skb, cb);
2309 else
2310 ret = nf_tables_dump_sets_family(&ctx, skb, cb);
2311 } else
Patrick McHardy20a69342013-10-11 12:06:22 +02002312 ret = nf_tables_dump_sets_table(&ctx, skb, cb);
2313
2314 return ret;
2315}
2316
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002317#define NFT_SET_INACTIVE (1 << 15) /* Internal set flag */
2318
Patrick McHardy20a69342013-10-11 12:06:22 +02002319static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
2320 const struct nlmsghdr *nlh,
2321 const struct nlattr * const nla[])
2322{
2323 const struct nft_set *set;
2324 struct nft_ctx ctx;
2325 struct sk_buff *skb2;
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002326 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Patrick McHardy20a69342013-10-11 12:06:22 +02002327 int err;
2328
2329 /* Verify existance before starting dump */
2330 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
2331 if (err < 0)
2332 return err;
2333
2334 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2335 struct netlink_dump_control c = {
2336 .dump = nf_tables_dump_sets,
2337 };
2338 return netlink_dump_start(nlsk, skb, nlh, &c);
2339 }
2340
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002341 /* Only accept unspec with dump */
2342 if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
2343 return -EAFNOSUPPORT;
2344
Patrick McHardy20a69342013-10-11 12:06:22 +02002345 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
2346 if (IS_ERR(set))
2347 return PTR_ERR(set);
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002348 if (set->flags & NFT_SET_INACTIVE)
2349 return -ENOENT;
Patrick McHardy20a69342013-10-11 12:06:22 +02002350
2351 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2352 if (skb2 == NULL)
2353 return -ENOMEM;
2354
2355 err = nf_tables_fill_set(skb2, &ctx, set, NFT_MSG_NEWSET, 0);
2356 if (err < 0)
2357 goto err;
2358
2359 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
2360
2361err:
2362 kfree_skb(skb2);
2363 return err;
2364}
2365
Patrick McHardyc50b9602014-03-28 10:19:47 +00002366static int nf_tables_set_desc_parse(const struct nft_ctx *ctx,
2367 struct nft_set_desc *desc,
2368 const struct nlattr *nla)
2369{
2370 struct nlattr *da[NFTA_SET_DESC_MAX + 1];
2371 int err;
2372
2373 err = nla_parse_nested(da, NFTA_SET_DESC_MAX, nla, nft_set_desc_policy);
2374 if (err < 0)
2375 return err;
2376
2377 if (da[NFTA_SET_DESC_SIZE] != NULL)
2378 desc->size = ntohl(nla_get_be32(da[NFTA_SET_DESC_SIZE]));
2379
2380 return 0;
2381}
2382
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002383static int nft_trans_set_add(struct nft_ctx *ctx, int msg_type,
2384 struct nft_set *set)
2385{
2386 struct nft_trans *trans;
2387
2388 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_set));
2389 if (trans == NULL)
2390 return -ENOMEM;
2391
2392 if (msg_type == NFT_MSG_NEWSET && ctx->nla[NFTA_SET_ID] != NULL) {
2393 nft_trans_set_id(trans) =
2394 ntohl(nla_get_be32(ctx->nla[NFTA_SET_ID]));
2395 set->flags |= NFT_SET_INACTIVE;
2396 }
2397 nft_trans_set(trans) = set;
2398 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
2399
2400 return 0;
2401}
2402
Patrick McHardy20a69342013-10-11 12:06:22 +02002403static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
2404 const struct nlmsghdr *nlh,
2405 const struct nlattr * const nla[])
2406{
2407 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
2408 const struct nft_set_ops *ops;
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02002409 struct nft_af_info *afi;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002410 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02002411 struct nft_table *table;
2412 struct nft_set *set;
2413 struct nft_ctx ctx;
2414 char name[IFNAMSIZ];
2415 unsigned int size;
2416 bool create;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002417 u32 ktype, dtype, flags, policy;
2418 struct nft_set_desc desc;
Patrick McHardy20a69342013-10-11 12:06:22 +02002419 int err;
2420
2421 if (nla[NFTA_SET_TABLE] == NULL ||
2422 nla[NFTA_SET_NAME] == NULL ||
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002423 nla[NFTA_SET_KEY_LEN] == NULL ||
2424 nla[NFTA_SET_ID] == NULL)
Patrick McHardy20a69342013-10-11 12:06:22 +02002425 return -EINVAL;
2426
Patrick McHardyc50b9602014-03-28 10:19:47 +00002427 memset(&desc, 0, sizeof(desc));
2428
Patrick McHardy20a69342013-10-11 12:06:22 +02002429 ktype = NFT_DATA_VALUE;
2430 if (nla[NFTA_SET_KEY_TYPE] != NULL) {
2431 ktype = ntohl(nla_get_be32(nla[NFTA_SET_KEY_TYPE]));
2432 if ((ktype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK)
2433 return -EINVAL;
2434 }
2435
Patrick McHardyc50b9602014-03-28 10:19:47 +00002436 desc.klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
2437 if (desc.klen == 0 || desc.klen > FIELD_SIZEOF(struct nft_data, data))
Patrick McHardy20a69342013-10-11 12:06:22 +02002438 return -EINVAL;
2439
2440 flags = 0;
2441 if (nla[NFTA_SET_FLAGS] != NULL) {
2442 flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
2443 if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
2444 NFT_SET_INTERVAL | NFT_SET_MAP))
2445 return -EINVAL;
2446 }
2447
2448 dtype = 0;
Patrick McHardy20a69342013-10-11 12:06:22 +02002449 if (nla[NFTA_SET_DATA_TYPE] != NULL) {
2450 if (!(flags & NFT_SET_MAP))
2451 return -EINVAL;
2452
2453 dtype = ntohl(nla_get_be32(nla[NFTA_SET_DATA_TYPE]));
2454 if ((dtype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK &&
2455 dtype != NFT_DATA_VERDICT)
2456 return -EINVAL;
2457
2458 if (dtype != NFT_DATA_VERDICT) {
2459 if (nla[NFTA_SET_DATA_LEN] == NULL)
2460 return -EINVAL;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002461 desc.dlen = ntohl(nla_get_be32(nla[NFTA_SET_DATA_LEN]));
2462 if (desc.dlen == 0 ||
2463 desc.dlen > FIELD_SIZEOF(struct nft_data, data))
Patrick McHardy20a69342013-10-11 12:06:22 +02002464 return -EINVAL;
2465 } else
Patrick McHardyc50b9602014-03-28 10:19:47 +00002466 desc.dlen = sizeof(struct nft_data);
Patrick McHardy20a69342013-10-11 12:06:22 +02002467 } else if (flags & NFT_SET_MAP)
2468 return -EINVAL;
2469
Patrick McHardyc50b9602014-03-28 10:19:47 +00002470 policy = NFT_SET_POL_PERFORMANCE;
2471 if (nla[NFTA_SET_POLICY] != NULL)
2472 policy = ntohl(nla_get_be32(nla[NFTA_SET_POLICY]));
2473
2474 if (nla[NFTA_SET_DESC] != NULL) {
2475 err = nf_tables_set_desc_parse(&ctx, &desc, nla[NFTA_SET_DESC]);
2476 if (err < 0)
2477 return err;
2478 }
2479
Patrick McHardy20a69342013-10-11 12:06:22 +02002480 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
2481
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002482 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
Patrick McHardy20a69342013-10-11 12:06:22 +02002483 if (IS_ERR(afi))
2484 return PTR_ERR(afi);
2485
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002486 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02002487 if (IS_ERR(table))
2488 return PTR_ERR(table);
2489
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002490 nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002491
2492 set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME]);
2493 if (IS_ERR(set)) {
2494 if (PTR_ERR(set) != -ENOENT)
2495 return PTR_ERR(set);
2496 set = NULL;
2497 }
2498
2499 if (set != NULL) {
2500 if (nlh->nlmsg_flags & NLM_F_EXCL)
2501 return -EEXIST;
2502 if (nlh->nlmsg_flags & NLM_F_REPLACE)
2503 return -EOPNOTSUPP;
2504 return 0;
2505 }
2506
2507 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
2508 return -ENOENT;
2509
Patrick McHardyc50b9602014-03-28 10:19:47 +00002510 ops = nft_select_set_ops(nla, &desc, policy);
Patrick McHardy20a69342013-10-11 12:06:22 +02002511 if (IS_ERR(ops))
2512 return PTR_ERR(ops);
2513
2514 size = 0;
2515 if (ops->privsize != NULL)
2516 size = ops->privsize(nla);
2517
2518 err = -ENOMEM;
2519 set = kzalloc(sizeof(*set) + size, GFP_KERNEL);
2520 if (set == NULL)
2521 goto err1;
2522
2523 nla_strlcpy(name, nla[NFTA_SET_NAME], sizeof(set->name));
2524 err = nf_tables_set_alloc_name(&ctx, set, name);
2525 if (err < 0)
2526 goto err2;
2527
2528 INIT_LIST_HEAD(&set->bindings);
2529 set->ops = ops;
2530 set->ktype = ktype;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002531 set->klen = desc.klen;
Patrick McHardy20a69342013-10-11 12:06:22 +02002532 set->dtype = dtype;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002533 set->dlen = desc.dlen;
Patrick McHardy20a69342013-10-11 12:06:22 +02002534 set->flags = flags;
Patrick McHardyc50b9602014-03-28 10:19:47 +00002535 set->size = desc.size;
Patrick McHardy20a69342013-10-11 12:06:22 +02002536
Patrick McHardyc50b9602014-03-28 10:19:47 +00002537 err = ops->init(set, &desc, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002538 if (err < 0)
2539 goto err2;
2540
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002541 err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set);
2542 if (err < 0)
2543 goto err2;
2544
Patrick McHardy20a69342013-10-11 12:06:22 +02002545 list_add_tail(&set->list, &table->sets);
Patrick McHardy20a69342013-10-11 12:06:22 +02002546 return 0;
2547
2548err2:
2549 kfree(set);
2550err1:
2551 module_put(ops->owner);
2552 return err;
2553}
2554
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002555static void nft_set_destroy(struct nft_set *set)
2556{
2557 set->ops->destroy(set);
2558 module_put(set->ops->owner);
2559 kfree(set);
2560}
2561
Patrick McHardy20a69342013-10-11 12:06:22 +02002562static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
2563{
2564 list_del(&set->list);
Patrick McHardyab9da5c12014-03-07 19:08:31 +01002565 nf_tables_set_notify(ctx, set, NFT_MSG_DELSET);
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002566 nft_set_destroy(set);
Patrick McHardy20a69342013-10-11 12:06:22 +02002567}
2568
2569static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
2570 const struct nlmsghdr *nlh,
2571 const struct nlattr * const nla[])
2572{
Pablo Neira Ayusoc9c8e482013-12-26 16:49:03 +01002573 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Patrick McHardy20a69342013-10-11 12:06:22 +02002574 struct nft_set *set;
2575 struct nft_ctx ctx;
2576 int err;
2577
Patrick McHardyec2c9932014-02-05 15:03:35 +00002578 if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
2579 return -EAFNOSUPPORT;
Patrick McHardy20a69342013-10-11 12:06:22 +02002580 if (nla[NFTA_SET_TABLE] == NULL)
2581 return -EINVAL;
2582
2583 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
2584 if (err < 0)
2585 return err;
2586
2587 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
2588 if (IS_ERR(set))
2589 return PTR_ERR(set);
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002590 if (set->flags & NFT_SET_INACTIVE)
2591 return -ENOENT;
Patrick McHardy20a69342013-10-11 12:06:22 +02002592 if (!list_empty(&set->bindings))
2593 return -EBUSY;
2594
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002595 err = nft_trans_set_add(&ctx, NFT_MSG_DELSET, set);
2596 if (err < 0)
2597 return err;
2598
2599 list_del(&set->list);
Patrick McHardy20a69342013-10-11 12:06:22 +02002600 return 0;
2601}
2602
2603static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
2604 const struct nft_set *set,
2605 const struct nft_set_iter *iter,
2606 const struct nft_set_elem *elem)
2607{
2608 enum nft_registers dreg;
2609
2610 dreg = nft_type_to_reg(set->dtype);
Pablo Neira Ayuso2ee0d3c2013-12-28 00:59:38 +01002611 return nft_validate_data_load(ctx, dreg, &elem->data,
2612 set->dtype == NFT_DATA_VERDICT ?
2613 NFT_DATA_VERDICT : NFT_DATA_VALUE);
Patrick McHardy20a69342013-10-11 12:06:22 +02002614}
2615
2616int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
2617 struct nft_set_binding *binding)
2618{
2619 struct nft_set_binding *i;
2620 struct nft_set_iter iter;
2621
2622 if (!list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
2623 return -EBUSY;
2624
2625 if (set->flags & NFT_SET_MAP) {
2626 /* If the set is already bound to the same chain all
2627 * jumps are already validated for that chain.
2628 */
2629 list_for_each_entry(i, &set->bindings, list) {
2630 if (i->chain == binding->chain)
2631 goto bind;
2632 }
2633
2634 iter.skip = 0;
2635 iter.count = 0;
2636 iter.err = 0;
2637 iter.fn = nf_tables_bind_check_setelem;
2638
2639 set->ops->walk(ctx, set, &iter);
2640 if (iter.err < 0) {
2641 /* Destroy anonymous sets if binding fails */
2642 if (set->flags & NFT_SET_ANONYMOUS)
2643 nf_tables_set_destroy(ctx, set);
2644
2645 return iter.err;
2646 }
2647 }
2648bind:
2649 binding->chain = ctx->chain;
2650 list_add_tail(&binding->list, &set->bindings);
2651 return 0;
2652}
2653
2654void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
2655 struct nft_set_binding *binding)
2656{
2657 list_del(&binding->list);
2658
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002659 if (list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS &&
2660 !(set->flags & NFT_SET_INACTIVE))
Patrick McHardy20a69342013-10-11 12:06:22 +02002661 nf_tables_set_destroy(ctx, set);
2662}
2663
2664/*
2665 * Set elements
2666 */
2667
2668static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
2669 [NFTA_SET_ELEM_KEY] = { .type = NLA_NESTED },
2670 [NFTA_SET_ELEM_DATA] = { .type = NLA_NESTED },
2671 [NFTA_SET_ELEM_FLAGS] = { .type = NLA_U32 },
2672};
2673
2674static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
2675 [NFTA_SET_ELEM_LIST_TABLE] = { .type = NLA_STRING },
2676 [NFTA_SET_ELEM_LIST_SET] = { .type = NLA_STRING },
2677 [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NLA_NESTED },
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002678 [NFTA_SET_ELEM_LIST_SET_ID] = { .type = NLA_U32 },
Patrick McHardy20a69342013-10-11 12:06:22 +02002679};
2680
2681static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx,
2682 const struct sk_buff *skb,
2683 const struct nlmsghdr *nlh,
2684 const struct nlattr * const nla[])
2685{
2686 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02002687 struct nft_af_info *afi;
2688 struct nft_table *table;
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002689 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02002690
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02002691 afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
Patrick McHardy20a69342013-10-11 12:06:22 +02002692 if (IS_ERR(afi))
2693 return PTR_ERR(afi);
2694
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002695 table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02002696 if (IS_ERR(table))
2697 return PTR_ERR(table);
2698
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002699 nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002700 return 0;
2701}
2702
2703static int nf_tables_fill_setelem(struct sk_buff *skb,
2704 const struct nft_set *set,
2705 const struct nft_set_elem *elem)
2706{
2707 unsigned char *b = skb_tail_pointer(skb);
2708 struct nlattr *nest;
2709
2710 nest = nla_nest_start(skb, NFTA_LIST_ELEM);
2711 if (nest == NULL)
2712 goto nla_put_failure;
2713
2714 if (nft_data_dump(skb, NFTA_SET_ELEM_KEY, &elem->key, NFT_DATA_VALUE,
2715 set->klen) < 0)
2716 goto nla_put_failure;
2717
2718 if (set->flags & NFT_SET_MAP &&
2719 !(elem->flags & NFT_SET_ELEM_INTERVAL_END) &&
2720 nft_data_dump(skb, NFTA_SET_ELEM_DATA, &elem->data,
2721 set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE,
2722 set->dlen) < 0)
2723 goto nla_put_failure;
2724
2725 if (elem->flags != 0)
2726 if (nla_put_be32(skb, NFTA_SET_ELEM_FLAGS, htonl(elem->flags)))
2727 goto nla_put_failure;
2728
2729 nla_nest_end(skb, nest);
2730 return 0;
2731
2732nla_put_failure:
2733 nlmsg_trim(skb, b);
2734 return -EMSGSIZE;
2735}
2736
2737struct nft_set_dump_args {
2738 const struct netlink_callback *cb;
2739 struct nft_set_iter iter;
2740 struct sk_buff *skb;
2741};
2742
2743static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
2744 const struct nft_set *set,
2745 const struct nft_set_iter *iter,
2746 const struct nft_set_elem *elem)
2747{
2748 struct nft_set_dump_args *args;
2749
2750 args = container_of(iter, struct nft_set_dump_args, iter);
2751 return nf_tables_fill_setelem(args->skb, set, elem);
2752}
2753
2754static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
2755{
2756 const struct nft_set *set;
2757 struct nft_set_dump_args args;
2758 struct nft_ctx ctx;
2759 struct nlattr *nla[NFTA_SET_ELEM_LIST_MAX + 1];
2760 struct nfgenmsg *nfmsg;
2761 struct nlmsghdr *nlh;
2762 struct nlattr *nest;
2763 u32 portid, seq;
2764 int event, err;
2765
Michal Nazarewicz720e0df2014-01-01 06:27:19 +01002766 err = nlmsg_parse(cb->nlh, sizeof(struct nfgenmsg), nla,
2767 NFTA_SET_ELEM_LIST_MAX, nft_set_elem_list_policy);
Patrick McHardy20a69342013-10-11 12:06:22 +02002768 if (err < 0)
2769 return err;
2770
2771 err = nft_ctx_init_from_elemattr(&ctx, cb->skb, cb->nlh, (void *)nla);
2772 if (err < 0)
2773 return err;
2774
2775 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2776 if (IS_ERR(set))
2777 return PTR_ERR(set);
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002778 if (set->flags & NFT_SET_INACTIVE)
2779 return -ENOENT;
Patrick McHardy20a69342013-10-11 12:06:22 +02002780
2781 event = NFT_MSG_NEWSETELEM;
2782 event |= NFNL_SUBSYS_NFTABLES << 8;
2783 portid = NETLINK_CB(cb->skb).portid;
2784 seq = cb->nlh->nlmsg_seq;
2785
2786 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
2787 NLM_F_MULTI);
2788 if (nlh == NULL)
2789 goto nla_put_failure;
2790
2791 nfmsg = nlmsg_data(nlh);
2792 nfmsg->nfgen_family = NFPROTO_UNSPEC;
2793 nfmsg->version = NFNETLINK_V0;
2794 nfmsg->res_id = 0;
2795
2796 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, ctx.table->name))
2797 goto nla_put_failure;
2798 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_SET, set->name))
2799 goto nla_put_failure;
2800
2801 nest = nla_nest_start(skb, NFTA_SET_ELEM_LIST_ELEMENTS);
2802 if (nest == NULL)
2803 goto nla_put_failure;
2804
2805 args.cb = cb;
2806 args.skb = skb;
2807 args.iter.skip = cb->args[0];
2808 args.iter.count = 0;
2809 args.iter.err = 0;
2810 args.iter.fn = nf_tables_dump_setelem;
2811 set->ops->walk(&ctx, set, &args.iter);
2812
2813 nla_nest_end(skb, nest);
2814 nlmsg_end(skb, nlh);
2815
2816 if (args.iter.err && args.iter.err != -EMSGSIZE)
2817 return args.iter.err;
2818 if (args.iter.count == cb->args[0])
2819 return 0;
2820
2821 cb->args[0] = args.iter.count;
2822 return skb->len;
2823
2824nla_put_failure:
2825 return -ENOSPC;
2826}
2827
2828static int nf_tables_getsetelem(struct sock *nlsk, struct sk_buff *skb,
2829 const struct nlmsghdr *nlh,
2830 const struct nlattr * const nla[])
2831{
2832 const struct nft_set *set;
2833 struct nft_ctx ctx;
2834 int err;
2835
2836 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2837 if (err < 0)
2838 return err;
2839
2840 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2841 if (IS_ERR(set))
2842 return PTR_ERR(set);
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02002843 if (set->flags & NFT_SET_INACTIVE)
2844 return -ENOENT;
Patrick McHardy20a69342013-10-11 12:06:22 +02002845
2846 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2847 struct netlink_dump_control c = {
2848 .dump = nf_tables_dump_set,
2849 };
2850 return netlink_dump_start(nlsk, skb, nlh, &c);
2851 }
2852 return -EOPNOTSUPP;
2853}
2854
Arturo Borrerod60ce622014-04-01 14:06:07 +02002855static int nf_tables_fill_setelem_info(struct sk_buff *skb,
2856 const struct nft_ctx *ctx, u32 seq,
2857 u32 portid, int event, u16 flags,
2858 const struct nft_set *set,
2859 const struct nft_set_elem *elem)
2860{
2861 struct nfgenmsg *nfmsg;
2862 struct nlmsghdr *nlh;
2863 struct nlattr *nest;
2864 int err;
2865
2866 event |= NFNL_SUBSYS_NFTABLES << 8;
2867 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
2868 flags);
2869 if (nlh == NULL)
2870 goto nla_put_failure;
2871
2872 nfmsg = nlmsg_data(nlh);
2873 nfmsg->nfgen_family = ctx->afi->family;
2874 nfmsg->version = NFNETLINK_V0;
2875 nfmsg->res_id = 0;
2876
2877 if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
2878 goto nla_put_failure;
2879 if (nla_put_string(skb, NFTA_SET_NAME, set->name))
2880 goto nla_put_failure;
2881
2882 nest = nla_nest_start(skb, NFTA_SET_ELEM_LIST_ELEMENTS);
2883 if (nest == NULL)
2884 goto nla_put_failure;
2885
2886 err = nf_tables_fill_setelem(skb, set, elem);
2887 if (err < 0)
2888 goto nla_put_failure;
2889
2890 nla_nest_end(skb, nest);
2891
2892 return nlmsg_end(skb, nlh);
2893
2894nla_put_failure:
2895 nlmsg_trim(skb, nlh);
2896 return -1;
2897}
2898
2899static int nf_tables_setelem_notify(const struct nft_ctx *ctx,
2900 const struct nft_set *set,
2901 const struct nft_set_elem *elem,
2902 int event, u16 flags)
2903{
2904 const struct sk_buff *oskb = ctx->skb;
2905 struct net *net = sock_net(oskb->sk);
2906 u32 portid = NETLINK_CB(oskb).portid;
2907 bool report = nlmsg_report(ctx->nlh);
2908 struct sk_buff *skb;
2909 int err;
2910
2911 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
2912 return 0;
2913
2914 err = -ENOBUFS;
2915 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
2916 if (skb == NULL)
2917 goto err;
2918
2919 err = nf_tables_fill_setelem_info(skb, ctx, 0, portid, event, flags,
2920 set, elem);
2921 if (err < 0) {
2922 kfree_skb(skb);
2923 goto err;
2924 }
2925
2926 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
2927 GFP_KERNEL);
2928err:
2929 if (err < 0)
2930 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
2931 return err;
2932}
2933
Patrick McHardy20a69342013-10-11 12:06:22 +02002934static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set,
2935 const struct nlattr *attr)
2936{
2937 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
2938 struct nft_data_desc d1, d2;
2939 struct nft_set_elem elem;
2940 struct nft_set_binding *binding;
2941 enum nft_registers dreg;
2942 int err;
2943
Patrick McHardyc50b9602014-03-28 10:19:47 +00002944 if (set->size && set->nelems == set->size)
2945 return -ENFILE;
2946
Patrick McHardy20a69342013-10-11 12:06:22 +02002947 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
2948 nft_set_elem_policy);
2949 if (err < 0)
2950 return err;
2951
2952 if (nla[NFTA_SET_ELEM_KEY] == NULL)
2953 return -EINVAL;
2954
2955 elem.flags = 0;
2956 if (nla[NFTA_SET_ELEM_FLAGS] != NULL) {
2957 elem.flags = ntohl(nla_get_be32(nla[NFTA_SET_ELEM_FLAGS]));
2958 if (elem.flags & ~NFT_SET_ELEM_INTERVAL_END)
2959 return -EINVAL;
2960 }
2961
2962 if (set->flags & NFT_SET_MAP) {
2963 if (nla[NFTA_SET_ELEM_DATA] == NULL &&
2964 !(elem.flags & NFT_SET_ELEM_INTERVAL_END))
2965 return -EINVAL;
Pablo Neira Ayusobd7fc642014-02-07 12:53:07 +01002966 if (nla[NFTA_SET_ELEM_DATA] != NULL &&
2967 elem.flags & NFT_SET_ELEM_INTERVAL_END)
2968 return -EINVAL;
Patrick McHardy20a69342013-10-11 12:06:22 +02002969 } else {
2970 if (nla[NFTA_SET_ELEM_DATA] != NULL)
2971 return -EINVAL;
2972 }
2973
2974 err = nft_data_init(ctx, &elem.key, &d1, nla[NFTA_SET_ELEM_KEY]);
2975 if (err < 0)
2976 goto err1;
2977 err = -EINVAL;
2978 if (d1.type != NFT_DATA_VALUE || d1.len != set->klen)
2979 goto err2;
2980
2981 err = -EEXIST;
2982 if (set->ops->get(set, &elem) == 0)
2983 goto err2;
2984
2985 if (nla[NFTA_SET_ELEM_DATA] != NULL) {
2986 err = nft_data_init(ctx, &elem.data, &d2, nla[NFTA_SET_ELEM_DATA]);
2987 if (err < 0)
2988 goto err2;
2989
2990 err = -EINVAL;
2991 if (set->dtype != NFT_DATA_VERDICT && d2.len != set->dlen)
2992 goto err3;
2993
2994 dreg = nft_type_to_reg(set->dtype);
2995 list_for_each_entry(binding, &set->bindings, list) {
2996 struct nft_ctx bind_ctx = {
2997 .afi = ctx->afi,
2998 .table = ctx->table,
Pablo Neira Ayuso7c95f6d2014-04-04 01:22:45 +02002999 .chain = (struct nft_chain *)binding->chain,
Patrick McHardy20a69342013-10-11 12:06:22 +02003000 };
3001
3002 err = nft_validate_data_load(&bind_ctx, dreg,
3003 &elem.data, d2.type);
3004 if (err < 0)
3005 goto err3;
3006 }
3007 }
3008
3009 err = set->ops->insert(set, &elem);
3010 if (err < 0)
3011 goto err3;
Patrick McHardyc50b9602014-03-28 10:19:47 +00003012 set->nelems++;
Patrick McHardy20a69342013-10-11 12:06:22 +02003013
Arturo Borrerod60ce622014-04-01 14:06:07 +02003014 nf_tables_setelem_notify(ctx, set, &elem, NFT_MSG_NEWSETELEM, 0);
Patrick McHardy20a69342013-10-11 12:06:22 +02003015 return 0;
3016
3017err3:
3018 if (nla[NFTA_SET_ELEM_DATA] != NULL)
3019 nft_data_uninit(&elem.data, d2.type);
3020err2:
3021 nft_data_uninit(&elem.key, d1.type);
3022err1:
3023 return err;
3024}
3025
3026static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
3027 const struct nlmsghdr *nlh,
3028 const struct nlattr * const nla[])
3029{
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003030 struct net *net = sock_net(skb->sk);
Patrick McHardy20a69342013-10-11 12:06:22 +02003031 const struct nlattr *attr;
3032 struct nft_set *set;
3033 struct nft_ctx ctx;
3034 int rem, err;
3035
3036 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
3037 if (err < 0)
3038 return err;
3039
3040 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003041 if (IS_ERR(set)) {
3042 if (nla[NFTA_SET_ELEM_LIST_SET_ID]) {
3043 set = nf_tables_set_lookup_byid(net,
3044 nla[NFTA_SET_ELEM_LIST_SET_ID]);
3045 }
3046 if (IS_ERR(set))
3047 return PTR_ERR(set);
3048 }
3049
Patrick McHardy20a69342013-10-11 12:06:22 +02003050 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
3051 return -EBUSY;
3052
3053 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
3054 err = nft_add_set_elem(&ctx, set, attr);
3055 if (err < 0)
3056 return err;
3057 }
3058 return 0;
3059}
3060
3061static int nft_del_setelem(const struct nft_ctx *ctx, struct nft_set *set,
3062 const struct nlattr *attr)
3063{
3064 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
3065 struct nft_data_desc desc;
3066 struct nft_set_elem elem;
3067 int err;
3068
3069 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
3070 nft_set_elem_policy);
3071 if (err < 0)
3072 goto err1;
3073
3074 err = -EINVAL;
3075 if (nla[NFTA_SET_ELEM_KEY] == NULL)
3076 goto err1;
3077
3078 err = nft_data_init(ctx, &elem.key, &desc, nla[NFTA_SET_ELEM_KEY]);
3079 if (err < 0)
3080 goto err1;
3081
3082 err = -EINVAL;
3083 if (desc.type != NFT_DATA_VALUE || desc.len != set->klen)
3084 goto err2;
3085
3086 err = set->ops->get(set, &elem);
3087 if (err < 0)
3088 goto err2;
3089
3090 set->ops->remove(set, &elem);
Patrick McHardyc50b9602014-03-28 10:19:47 +00003091 set->nelems--;
Patrick McHardy20a69342013-10-11 12:06:22 +02003092
Arturo Borrerod60ce622014-04-01 14:06:07 +02003093 nf_tables_setelem_notify(ctx, set, &elem, NFT_MSG_DELSETELEM, 0);
3094
Patrick McHardy20a69342013-10-11 12:06:22 +02003095 nft_data_uninit(&elem.key, NFT_DATA_VALUE);
3096 if (set->flags & NFT_SET_MAP)
3097 nft_data_uninit(&elem.data, set->dtype);
3098
3099err2:
3100 nft_data_uninit(&elem.key, desc.type);
3101err1:
3102 return err;
3103}
3104
3105static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
3106 const struct nlmsghdr *nlh,
3107 const struct nlattr * const nla[])
3108{
3109 const struct nlattr *attr;
3110 struct nft_set *set;
3111 struct nft_ctx ctx;
3112 int rem, err;
3113
3114 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
3115 if (err < 0)
3116 return err;
3117
3118 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
3119 if (IS_ERR(set))
3120 return PTR_ERR(set);
3121 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
3122 return -EBUSY;
3123
3124 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
3125 err = nft_del_setelem(&ctx, set, attr);
3126 if (err < 0)
3127 return err;
3128 }
3129 return 0;
3130}
3131
Patrick McHardy96518512013-10-14 11:00:02 +02003132static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
3133 [NFT_MSG_NEWTABLE] = {
3134 .call = nf_tables_newtable,
3135 .attr_count = NFTA_TABLE_MAX,
3136 .policy = nft_table_policy,
3137 },
3138 [NFT_MSG_GETTABLE] = {
3139 .call = nf_tables_gettable,
3140 .attr_count = NFTA_TABLE_MAX,
3141 .policy = nft_table_policy,
3142 },
3143 [NFT_MSG_DELTABLE] = {
3144 .call = nf_tables_deltable,
3145 .attr_count = NFTA_TABLE_MAX,
3146 .policy = nft_table_policy,
3147 },
3148 [NFT_MSG_NEWCHAIN] = {
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02003149 .call_batch = nf_tables_newchain,
Patrick McHardy96518512013-10-14 11:00:02 +02003150 .attr_count = NFTA_CHAIN_MAX,
3151 .policy = nft_chain_policy,
3152 },
3153 [NFT_MSG_GETCHAIN] = {
3154 .call = nf_tables_getchain,
3155 .attr_count = NFTA_CHAIN_MAX,
3156 .policy = nft_chain_policy,
3157 },
3158 [NFT_MSG_DELCHAIN] = {
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02003159 .call_batch = nf_tables_delchain,
Patrick McHardy96518512013-10-14 11:00:02 +02003160 .attr_count = NFTA_CHAIN_MAX,
3161 .policy = nft_chain_policy,
3162 },
3163 [NFT_MSG_NEWRULE] = {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02003164 .call_batch = nf_tables_newrule,
Patrick McHardy96518512013-10-14 11:00:02 +02003165 .attr_count = NFTA_RULE_MAX,
3166 .policy = nft_rule_policy,
3167 },
3168 [NFT_MSG_GETRULE] = {
3169 .call = nf_tables_getrule,
3170 .attr_count = NFTA_RULE_MAX,
3171 .policy = nft_rule_policy,
3172 },
3173 [NFT_MSG_DELRULE] = {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02003174 .call_batch = nf_tables_delrule,
Patrick McHardy96518512013-10-14 11:00:02 +02003175 .attr_count = NFTA_RULE_MAX,
3176 .policy = nft_rule_policy,
3177 },
Patrick McHardy20a69342013-10-11 12:06:22 +02003178 [NFT_MSG_NEWSET] = {
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003179 .call_batch = nf_tables_newset,
Patrick McHardy20a69342013-10-11 12:06:22 +02003180 .attr_count = NFTA_SET_MAX,
3181 .policy = nft_set_policy,
3182 },
3183 [NFT_MSG_GETSET] = {
3184 .call = nf_tables_getset,
3185 .attr_count = NFTA_SET_MAX,
3186 .policy = nft_set_policy,
3187 },
3188 [NFT_MSG_DELSET] = {
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003189 .call_batch = nf_tables_delset,
Patrick McHardy20a69342013-10-11 12:06:22 +02003190 .attr_count = NFTA_SET_MAX,
3191 .policy = nft_set_policy,
3192 },
3193 [NFT_MSG_NEWSETELEM] = {
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003194 .call_batch = nf_tables_newsetelem,
Patrick McHardy20a69342013-10-11 12:06:22 +02003195 .attr_count = NFTA_SET_ELEM_LIST_MAX,
3196 .policy = nft_set_elem_list_policy,
3197 },
3198 [NFT_MSG_GETSETELEM] = {
3199 .call = nf_tables_getsetelem,
3200 .attr_count = NFTA_SET_ELEM_LIST_MAX,
3201 .policy = nft_set_elem_list_policy,
3202 },
3203 [NFT_MSG_DELSETELEM] = {
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003204 .call_batch = nf_tables_delsetelem,
Patrick McHardy20a69342013-10-11 12:06:22 +02003205 .attr_count = NFTA_SET_ELEM_LIST_MAX,
3206 .policy = nft_set_elem_list_policy,
3207 },
Patrick McHardy96518512013-10-14 11:00:02 +02003208};
3209
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02003210static void nft_chain_commit_update(struct nft_trans *trans)
3211{
3212 struct nft_base_chain *basechain;
3213
3214 if (nft_trans_chain_name(trans)[0])
3215 strcpy(trans->ctx.chain->name, nft_trans_chain_name(trans));
3216
3217 if (!(trans->ctx.chain->flags & NFT_BASE_CHAIN))
3218 return;
3219
3220 basechain = nft_base_chain(trans->ctx.chain);
3221 nft_chain_stats_replace(basechain, nft_trans_chain_stats(trans));
3222
3223 switch (nft_trans_chain_policy(trans)) {
3224 case NF_DROP:
3225 case NF_ACCEPT:
3226 basechain->policy = nft_trans_chain_policy(trans);
3227 break;
3228 }
3229}
3230
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003231static int nf_tables_commit(struct sk_buff *skb)
3232{
3233 struct net *net = sock_net(skb->sk);
3234 struct nft_trans *trans, *next;
3235
3236 /* Bump generation counter, invalidate any dump in progress */
3237 net->nft.genctr++;
3238
3239 /* A new generation has just started */
3240 net->nft.gencursor = gencursor_next(net);
3241
3242 /* Make sure all packets have left the previous generation before
3243 * purging old rules.
3244 */
3245 synchronize_rcu();
3246
3247 list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003248 switch (trans->msg_type) {
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02003249 case NFT_MSG_NEWCHAIN:
3250 if (nft_trans_chain_update(trans))
3251 nft_chain_commit_update(trans);
3252 else {
3253 trans->ctx.chain->flags &= ~NFT_CHAIN_INACTIVE;
3254 trans->ctx.table->use++;
3255 }
3256 nf_tables_chain_notify(trans->ctx.skb, trans->ctx.nlh,
3257 trans->ctx.table,
3258 trans->ctx.chain,
3259 NFT_MSG_NEWCHAIN,
3260 trans->ctx.afi->family);
3261 nft_trans_destroy(trans);
3262 break;
3263 case NFT_MSG_DELCHAIN:
3264 trans->ctx.table->use--;
3265 nf_tables_chain_notify(trans->ctx.skb, trans->ctx.nlh,
3266 trans->ctx.table,
3267 trans->ctx.chain,
3268 NFT_MSG_DELCHAIN,
3269 trans->ctx.afi->family);
3270 if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) &&
3271 trans->ctx.chain->flags & NFT_BASE_CHAIN) {
3272 nf_unregister_hooks(nft_base_chain(trans->ctx.chain)->ops,
3273 trans->ctx.afi->nops);
3274 }
3275 break;
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003276 case NFT_MSG_NEWRULE:
3277 nft_rule_clear(trans->ctx.net, nft_trans_rule(trans));
3278 nf_tables_rule_notify(trans->ctx.skb, trans->ctx.nlh,
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003279 trans->ctx.table,
3280 trans->ctx.chain,
3281 nft_trans_rule(trans),
3282 NFT_MSG_NEWRULE, 0,
3283 trans->ctx.afi->family);
3284 nft_trans_destroy(trans);
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003285 break;
3286 case NFT_MSG_DELRULE:
3287 list_del_rcu(&nft_trans_rule(trans)->list);
3288 nf_tables_rule_notify(trans->ctx.skb, trans->ctx.nlh,
3289 trans->ctx.table,
3290 trans->ctx.chain,
3291 nft_trans_rule(trans), NFT_MSG_DELRULE, 0,
3292 trans->ctx.afi->family);
3293 break;
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003294 case NFT_MSG_NEWSET:
3295 nft_trans_set(trans)->flags &= ~NFT_SET_INACTIVE;
3296 nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
3297 NFT_MSG_NEWSET);
3298 nft_trans_destroy(trans);
3299 break;
3300 case NFT_MSG_DELSET:
3301 nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
3302 NFT_MSG_DELSET);
3303 break;
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003304 }
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003305 }
3306
3307 /* Make sure we don't see any packet traversing old rules */
3308 synchronize_rcu();
3309
3310 /* Now we can safely release unused old rules */
3311 list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003312 switch (trans->msg_type) {
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02003313 case NFT_MSG_DELCHAIN:
3314 nf_tables_chain_destroy(trans->ctx.chain);
3315 break;
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003316 case NFT_MSG_DELRULE:
3317 nf_tables_rule_destroy(&trans->ctx,
3318 nft_trans_rule(trans));
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003319 break;
3320 case NFT_MSG_DELSET:
3321 nft_set_destroy(nft_trans_set(trans));
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003322 break;
3323 }
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003324 nft_trans_destroy(trans);
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003325 }
3326
3327 return 0;
3328}
3329
3330static int nf_tables_abort(struct sk_buff *skb)
3331{
3332 struct net *net = sock_net(skb->sk);
3333 struct nft_trans *trans, *next;
3334
3335 list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003336 switch (trans->msg_type) {
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02003337 case NFT_MSG_NEWCHAIN:
3338 if (nft_trans_chain_update(trans)) {
3339 if (nft_trans_chain_stats(trans))
3340 free_percpu(nft_trans_chain_stats(trans));
3341
3342 nft_trans_destroy(trans);
3343 } else {
3344 list_del(&trans->ctx.chain->list);
3345 if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) &&
3346 trans->ctx.chain->flags & NFT_BASE_CHAIN) {
3347 nf_unregister_hooks(nft_base_chain(trans->ctx.chain)->ops,
3348 trans->ctx.afi->nops);
3349 }
3350 }
3351 break;
3352 case NFT_MSG_DELCHAIN:
3353 list_add_tail(&trans->ctx.chain->list,
3354 &trans->ctx.table->chains);
3355 nft_trans_destroy(trans);
3356 break;
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003357 case NFT_MSG_NEWRULE:
3358 list_del_rcu(&nft_trans_rule(trans)->list);
3359 break;
3360 case NFT_MSG_DELRULE:
3361 nft_rule_clear(trans->ctx.net, nft_trans_rule(trans));
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003362 nft_trans_destroy(trans);
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003363 break;
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003364 case NFT_MSG_NEWSET:
3365 list_del(&nft_trans_set(trans)->list);
3366 break;
3367 case NFT_MSG_DELSET:
3368 list_add_tail(&nft_trans_set(trans)->list,
3369 &trans->ctx.table->sets);
3370 nft_trans_destroy(trans);
3371 break;
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003372 }
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003373 }
3374
3375 /* Make sure we don't see any packet accessing aborted rules */
3376 synchronize_rcu();
3377
3378 list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003379 switch (trans->msg_type) {
Pablo Neira Ayuso91c7b382014-04-09 11:58:08 +02003380 case NFT_MSG_NEWCHAIN:
3381 nf_tables_chain_destroy(trans->ctx.chain);
3382 break;
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003383 case NFT_MSG_NEWRULE:
3384 nf_tables_rule_destroy(&trans->ctx,
3385 nft_trans_rule(trans));
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003386 break;
3387 case NFT_MSG_NEWSET:
3388 nft_set_destroy(nft_trans_set(trans));
Pablo Neira Ayusob380e5c2014-04-04 01:38:51 +02003389 break;
3390 }
Pablo Neira Ayuso958bee12014-04-03 11:48:44 +02003391 nft_trans_destroy(trans);
Pablo Neira Ayuso37082f92014-04-03 11:56:37 +02003392 }
3393
3394 return 0;
3395}
3396
Patrick McHardy96518512013-10-14 11:00:02 +02003397static const struct nfnetlink_subsystem nf_tables_subsys = {
3398 .name = "nf_tables",
3399 .subsys_id = NFNL_SUBSYS_NFTABLES,
3400 .cb_count = NFT_MSG_MAX,
3401 .cb = nf_tables_cb,
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02003402 .commit = nf_tables_commit,
3403 .abort = nf_tables_abort,
Patrick McHardy96518512013-10-14 11:00:02 +02003404};
3405
Patrick McHardy20a69342013-10-11 12:06:22 +02003406/*
3407 * Loop detection - walk through the ruleset beginning at the destination chain
3408 * of a new jump until either the source chain is reached (loop) or all
3409 * reachable chains have been traversed.
3410 *
3411 * The loop check is performed whenever a new jump verdict is added to an
3412 * expression or verdict map or a verdict map is bound to a new chain.
3413 */
3414
3415static int nf_tables_check_loops(const struct nft_ctx *ctx,
3416 const struct nft_chain *chain);
3417
3418static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
3419 const struct nft_set *set,
3420 const struct nft_set_iter *iter,
3421 const struct nft_set_elem *elem)
3422{
Pablo Neira Ayuso62f9c8b2014-02-07 14:45:01 +01003423 if (elem->flags & NFT_SET_ELEM_INTERVAL_END)
3424 return 0;
3425
Patrick McHardy20a69342013-10-11 12:06:22 +02003426 switch (elem->data.verdict) {
3427 case NFT_JUMP:
3428 case NFT_GOTO:
3429 return nf_tables_check_loops(ctx, elem->data.chain);
3430 default:
3431 return 0;
3432 }
3433}
3434
3435static int nf_tables_check_loops(const struct nft_ctx *ctx,
3436 const struct nft_chain *chain)
3437{
3438 const struct nft_rule *rule;
3439 const struct nft_expr *expr, *last;
Patrick McHardy20a69342013-10-11 12:06:22 +02003440 const struct nft_set *set;
3441 struct nft_set_binding *binding;
3442 struct nft_set_iter iter;
Patrick McHardy20a69342013-10-11 12:06:22 +02003443
3444 if (ctx->chain == chain)
3445 return -ELOOP;
3446
3447 list_for_each_entry(rule, &chain->rules, list) {
3448 nft_rule_for_each_expr(expr, last, rule) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02003449 const struct nft_data *data = NULL;
3450 int err;
3451
3452 if (!expr->ops->validate)
Patrick McHardy20a69342013-10-11 12:06:22 +02003453 continue;
3454
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02003455 err = expr->ops->validate(ctx, expr, &data);
3456 if (err < 0)
3457 return err;
3458
Patrick McHardy20a69342013-10-11 12:06:22 +02003459 if (data == NULL)
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02003460 continue;
Patrick McHardy20a69342013-10-11 12:06:22 +02003461
3462 switch (data->verdict) {
3463 case NFT_JUMP:
3464 case NFT_GOTO:
3465 err = nf_tables_check_loops(ctx, data->chain);
3466 if (err < 0)
3467 return err;
3468 default:
3469 break;
3470 }
3471 }
3472 }
3473
3474 list_for_each_entry(set, &ctx->table->sets, list) {
3475 if (!(set->flags & NFT_SET_MAP) ||
3476 set->dtype != NFT_DATA_VERDICT)
3477 continue;
3478
3479 list_for_each_entry(binding, &set->bindings, list) {
3480 if (binding->chain != chain)
3481 continue;
3482
3483 iter.skip = 0;
3484 iter.count = 0;
3485 iter.err = 0;
3486 iter.fn = nf_tables_loop_check_setelem;
3487
3488 set->ops->walk(ctx, set, &iter);
3489 if (iter.err < 0)
3490 return iter.err;
3491 }
3492 }
3493
3494 return 0;
3495}
3496
Patrick McHardy96518512013-10-14 11:00:02 +02003497/**
3498 * nft_validate_input_register - validate an expressions' input register
3499 *
3500 * @reg: the register number
3501 *
3502 * Validate that the input register is one of the general purpose
3503 * registers.
3504 */
3505int nft_validate_input_register(enum nft_registers reg)
3506{
3507 if (reg <= NFT_REG_VERDICT)
3508 return -EINVAL;
3509 if (reg > NFT_REG_MAX)
3510 return -ERANGE;
3511 return 0;
3512}
3513EXPORT_SYMBOL_GPL(nft_validate_input_register);
3514
3515/**
3516 * nft_validate_output_register - validate an expressions' output register
3517 *
3518 * @reg: the register number
3519 *
3520 * Validate that the output register is one of the general purpose
3521 * registers or the verdict register.
3522 */
3523int nft_validate_output_register(enum nft_registers reg)
3524{
3525 if (reg < NFT_REG_VERDICT)
3526 return -EINVAL;
3527 if (reg > NFT_REG_MAX)
3528 return -ERANGE;
3529 return 0;
3530}
3531EXPORT_SYMBOL_GPL(nft_validate_output_register);
3532
3533/**
3534 * nft_validate_data_load - validate an expressions' data load
3535 *
3536 * @ctx: context of the expression performing the load
3537 * @reg: the destination register number
3538 * @data: the data to load
3539 * @type: the data type
3540 *
3541 * Validate that a data load uses the appropriate data type for
3542 * the destination register. A value of NULL for the data means
3543 * that its runtime gathered data, which is always of type
3544 * NFT_DATA_VALUE.
3545 */
3546int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
3547 const struct nft_data *data,
3548 enum nft_data_types type)
3549{
Patrick McHardy20a69342013-10-11 12:06:22 +02003550 int err;
3551
Patrick McHardy96518512013-10-14 11:00:02 +02003552 switch (reg) {
3553 case NFT_REG_VERDICT:
3554 if (data == NULL || type != NFT_DATA_VERDICT)
3555 return -EINVAL;
Patrick McHardy20a69342013-10-11 12:06:22 +02003556
3557 if (data->verdict == NFT_GOTO || data->verdict == NFT_JUMP) {
3558 err = nf_tables_check_loops(ctx, data->chain);
3559 if (err < 0)
3560 return err;
3561
3562 if (ctx->chain->level + 1 > data->chain->level) {
3563 if (ctx->chain->level + 1 == NFT_JUMP_STACK_SIZE)
3564 return -EMLINK;
3565 data->chain->level = ctx->chain->level + 1;
3566 }
3567 }
3568
Patrick McHardy96518512013-10-14 11:00:02 +02003569 return 0;
3570 default:
3571 if (data != NULL && type != NFT_DATA_VALUE)
3572 return -EINVAL;
3573 return 0;
3574 }
3575}
3576EXPORT_SYMBOL_GPL(nft_validate_data_load);
3577
3578static const struct nla_policy nft_verdict_policy[NFTA_VERDICT_MAX + 1] = {
3579 [NFTA_VERDICT_CODE] = { .type = NLA_U32 },
3580 [NFTA_VERDICT_CHAIN] = { .type = NLA_STRING,
3581 .len = NFT_CHAIN_MAXNAMELEN - 1 },
3582};
3583
3584static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
3585 struct nft_data_desc *desc, const struct nlattr *nla)
3586{
3587 struct nlattr *tb[NFTA_VERDICT_MAX + 1];
3588 struct nft_chain *chain;
3589 int err;
3590
3591 err = nla_parse_nested(tb, NFTA_VERDICT_MAX, nla, nft_verdict_policy);
3592 if (err < 0)
3593 return err;
3594
3595 if (!tb[NFTA_VERDICT_CODE])
3596 return -EINVAL;
3597 data->verdict = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE]));
3598
3599 switch (data->verdict) {
Patrick McHardye0abdad2014-02-18 18:06:50 +00003600 default:
3601 switch (data->verdict & NF_VERDICT_MASK) {
3602 case NF_ACCEPT:
3603 case NF_DROP:
3604 case NF_QUEUE:
3605 break;
3606 default:
3607 return -EINVAL;
3608 }
3609 /* fall through */
Patrick McHardy96518512013-10-14 11:00:02 +02003610 case NFT_CONTINUE:
3611 case NFT_BREAK:
3612 case NFT_RETURN:
3613 desc->len = sizeof(data->verdict);
3614 break;
3615 case NFT_JUMP:
3616 case NFT_GOTO:
3617 if (!tb[NFTA_VERDICT_CHAIN])
3618 return -EINVAL;
3619 chain = nf_tables_chain_lookup(ctx->table,
3620 tb[NFTA_VERDICT_CHAIN]);
3621 if (IS_ERR(chain))
3622 return PTR_ERR(chain);
3623 if (chain->flags & NFT_BASE_CHAIN)
3624 return -EOPNOTSUPP;
3625
Patrick McHardy96518512013-10-14 11:00:02 +02003626 chain->use++;
3627 data->chain = chain;
3628 desc->len = sizeof(data);
3629 break;
Patrick McHardy96518512013-10-14 11:00:02 +02003630 }
3631
3632 desc->type = NFT_DATA_VERDICT;
3633 return 0;
3634}
3635
3636static void nft_verdict_uninit(const struct nft_data *data)
3637{
3638 switch (data->verdict) {
3639 case NFT_JUMP:
3640 case NFT_GOTO:
3641 data->chain->use--;
3642 break;
3643 }
3644}
3645
3646static int nft_verdict_dump(struct sk_buff *skb, const struct nft_data *data)
3647{
3648 struct nlattr *nest;
3649
3650 nest = nla_nest_start(skb, NFTA_DATA_VERDICT);
3651 if (!nest)
3652 goto nla_put_failure;
3653
3654 if (nla_put_be32(skb, NFTA_VERDICT_CODE, htonl(data->verdict)))
3655 goto nla_put_failure;
3656
3657 switch (data->verdict) {
3658 case NFT_JUMP:
3659 case NFT_GOTO:
3660 if (nla_put_string(skb, NFTA_VERDICT_CHAIN, data->chain->name))
3661 goto nla_put_failure;
3662 }
3663 nla_nest_end(skb, nest);
3664 return 0;
3665
3666nla_put_failure:
3667 return -1;
3668}
3669
3670static int nft_value_init(const struct nft_ctx *ctx, struct nft_data *data,
3671 struct nft_data_desc *desc, const struct nlattr *nla)
3672{
3673 unsigned int len;
3674
3675 len = nla_len(nla);
3676 if (len == 0)
3677 return -EINVAL;
3678 if (len > sizeof(data->data))
3679 return -EOVERFLOW;
3680
3681 nla_memcpy(data->data, nla, sizeof(data->data));
3682 desc->type = NFT_DATA_VALUE;
3683 desc->len = len;
3684 return 0;
3685}
3686
3687static int nft_value_dump(struct sk_buff *skb, const struct nft_data *data,
3688 unsigned int len)
3689{
3690 return nla_put(skb, NFTA_DATA_VALUE, len, data->data);
3691}
3692
3693static const struct nla_policy nft_data_policy[NFTA_DATA_MAX + 1] = {
3694 [NFTA_DATA_VALUE] = { .type = NLA_BINARY,
3695 .len = FIELD_SIZEOF(struct nft_data, data) },
3696 [NFTA_DATA_VERDICT] = { .type = NLA_NESTED },
3697};
3698
3699/**
3700 * nft_data_init - parse nf_tables data netlink attributes
3701 *
3702 * @ctx: context of the expression using the data
3703 * @data: destination struct nft_data
3704 * @desc: data description
3705 * @nla: netlink attribute containing data
3706 *
3707 * Parse the netlink data attributes and initialize a struct nft_data.
3708 * The type and length of data are returned in the data description.
3709 *
3710 * The caller can indicate that it only wants to accept data of type
3711 * NFT_DATA_VALUE by passing NULL for the ctx argument.
3712 */
3713int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data,
3714 struct nft_data_desc *desc, const struct nlattr *nla)
3715{
3716 struct nlattr *tb[NFTA_DATA_MAX + 1];
3717 int err;
3718
3719 err = nla_parse_nested(tb, NFTA_DATA_MAX, nla, nft_data_policy);
3720 if (err < 0)
3721 return err;
3722
3723 if (tb[NFTA_DATA_VALUE])
3724 return nft_value_init(ctx, data, desc, tb[NFTA_DATA_VALUE]);
3725 if (tb[NFTA_DATA_VERDICT] && ctx != NULL)
3726 return nft_verdict_init(ctx, data, desc, tb[NFTA_DATA_VERDICT]);
3727 return -EINVAL;
3728}
3729EXPORT_SYMBOL_GPL(nft_data_init);
3730
3731/**
3732 * nft_data_uninit - release a nft_data item
3733 *
3734 * @data: struct nft_data to release
3735 * @type: type of data
3736 *
3737 * Release a nft_data item. NFT_DATA_VALUE types can be silently discarded,
3738 * all others need to be released by calling this function.
3739 */
3740void nft_data_uninit(const struct nft_data *data, enum nft_data_types type)
3741{
3742 switch (type) {
3743 case NFT_DATA_VALUE:
3744 return;
3745 case NFT_DATA_VERDICT:
3746 return nft_verdict_uninit(data);
3747 default:
3748 WARN_ON(1);
3749 }
3750}
3751EXPORT_SYMBOL_GPL(nft_data_uninit);
3752
3753int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
3754 enum nft_data_types type, unsigned int len)
3755{
3756 struct nlattr *nest;
3757 int err;
3758
3759 nest = nla_nest_start(skb, attr);
3760 if (nest == NULL)
3761 return -1;
3762
3763 switch (type) {
3764 case NFT_DATA_VALUE:
3765 err = nft_value_dump(skb, data, len);
3766 break;
3767 case NFT_DATA_VERDICT:
3768 err = nft_verdict_dump(skb, data);
3769 break;
3770 default:
3771 err = -EINVAL;
3772 WARN_ON(1);
3773 }
3774
3775 nla_nest_end(skb, nest);
3776 return err;
3777}
3778EXPORT_SYMBOL_GPL(nft_data_dump);
3779
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003780static int nf_tables_init_net(struct net *net)
3781{
3782 INIT_LIST_HEAD(&net->nft.af_info);
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +02003783 INIT_LIST_HEAD(&net->nft.commit_list);
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003784 return 0;
3785}
3786
3787static struct pernet_operations nf_tables_net_ops = {
3788 .init = nf_tables_init_net,
3789};
3790
Patrick McHardy96518512013-10-14 11:00:02 +02003791static int __init nf_tables_module_init(void)
3792{
3793 int err;
3794
3795 info = kmalloc(sizeof(struct nft_expr_info) * NFT_RULE_MAXEXPRS,
3796 GFP_KERNEL);
3797 if (info == NULL) {
3798 err = -ENOMEM;
3799 goto err1;
3800 }
3801
3802 err = nf_tables_core_module_init();
3803 if (err < 0)
3804 goto err2;
3805
3806 err = nfnetlink_subsys_register(&nf_tables_subsys);
3807 if (err < 0)
3808 goto err3;
3809
3810 pr_info("nf_tables: (c) 2007-2009 Patrick McHardy <kaber@trash.net>\n");
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003811 return register_pernet_subsys(&nf_tables_net_ops);
Patrick McHardy96518512013-10-14 11:00:02 +02003812err3:
3813 nf_tables_core_module_exit();
3814err2:
3815 kfree(info);
3816err1:
3817 return err;
3818}
3819
3820static void __exit nf_tables_module_exit(void)
3821{
Pablo Neira Ayuso99633ab2013-10-10 23:28:33 +02003822 unregister_pernet_subsys(&nf_tables_net_ops);
Patrick McHardy96518512013-10-14 11:00:02 +02003823 nfnetlink_subsys_unregister(&nf_tables_subsys);
3824 nf_tables_core_module_exit();
3825 kfree(info);
3826}
3827
3828module_init(nf_tables_module_init);
3829module_exit(nf_tables_module_exit);
3830
3831MODULE_LICENSE("GPL");
3832MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
3833MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFTABLES);