blob: 61e017b349cba32af632cf3f2c7fb505953ed1c4 [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>
21#include <net/sock.h>
22
23static LIST_HEAD(nf_tables_afinfo);
24static 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 */
34int nft_register_afinfo(struct nft_af_info *afi)
35{
36 INIT_LIST_HEAD(&afi->tables);
37 nfnl_lock(NFNL_SUBSYS_NFTABLES);
38 list_add_tail(&afi->list, &nf_tables_afinfo);
39 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
59static struct nft_af_info *nft_afinfo_lookup(int family)
60{
61 struct nft_af_info *afi;
62
63 list_for_each_entry(afi, &nf_tables_afinfo, list) {
64 if (afi->family == family)
65 return afi;
66 }
67 return NULL;
68}
69
70static struct nft_af_info *nf_tables_afinfo_lookup(int family, bool autoload)
71{
72 struct nft_af_info *afi;
73
74 afi = nft_afinfo_lookup(family);
75 if (afi != NULL)
76 return afi;
77#ifdef CONFIG_MODULES
78 if (autoload) {
79 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
80 request_module("nft-afinfo-%u", family);
81 nfnl_lock(NFNL_SUBSYS_NFTABLES);
82 afi = nft_afinfo_lookup(family);
83 if (afi != NULL)
84 return ERR_PTR(-EAGAIN);
85 }
86#endif
87 return ERR_PTR(-EAFNOSUPPORT);
88}
89
90/*
91 * Tables
92 */
93
94static struct nft_table *nft_table_lookup(const struct nft_af_info *afi,
95 const struct nlattr *nla)
96{
97 struct nft_table *table;
98
99 list_for_each_entry(table, &afi->tables, list) {
100 if (!nla_strcmp(nla, table->name))
101 return table;
102 }
103 return NULL;
104}
105
106static struct nft_table *nf_tables_table_lookup(const struct nft_af_info *afi,
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200107 const struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +0200108{
109 struct nft_table *table;
110
111 if (nla == NULL)
112 return ERR_PTR(-EINVAL);
113
114 table = nft_table_lookup(afi, nla);
115 if (table != NULL)
116 return table;
117
Patrick McHardy96518512013-10-14 11:00:02 +0200118 return ERR_PTR(-ENOENT);
119}
120
121static inline u64 nf_tables_alloc_handle(struct nft_table *table)
122{
123 return ++table->hgenerator;
124}
125
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200126static struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX];
127
128static int __nf_tables_chain_type_lookup(int family, const struct nlattr *nla)
129{
130 int i;
131
132 for (i=0; i<NFT_CHAIN_T_MAX; i++) {
133 if (chain_type[family][i] != NULL &&
134 !nla_strcmp(nla, chain_type[family][i]->name))
135 return i;
136 }
137 return -1;
138}
139
140static int nf_tables_chain_type_lookup(const struct nft_af_info *afi,
141 const struct nlattr *nla,
142 bool autoload)
143{
144 int type;
145
146 type = __nf_tables_chain_type_lookup(afi->family, nla);
147#ifdef CONFIG_MODULES
148 if (type < 0 && autoload) {
149 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
150 request_module("nft-chain-%u-%*.s", afi->family,
151 nla_len(nla)-1, (const char *)nla_data(nla));
152 nfnl_lock(NFNL_SUBSYS_NFTABLES);
153 type = __nf_tables_chain_type_lookup(afi->family, nla);
154 }
155#endif
156 return type;
157}
158
Patrick McHardy96518512013-10-14 11:00:02 +0200159static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
160 [NFTA_TABLE_NAME] = { .type = NLA_STRING },
161};
162
163static int nf_tables_fill_table_info(struct sk_buff *skb, u32 portid, u32 seq,
164 int event, u32 flags, int family,
165 const struct nft_table *table)
166{
167 struct nlmsghdr *nlh;
168 struct nfgenmsg *nfmsg;
169
170 event |= NFNL_SUBSYS_NFTABLES << 8;
171 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
172 if (nlh == NULL)
173 goto nla_put_failure;
174
175 nfmsg = nlmsg_data(nlh);
176 nfmsg->nfgen_family = family;
177 nfmsg->version = NFNETLINK_V0;
178 nfmsg->res_id = 0;
179
180 if (nla_put_string(skb, NFTA_TABLE_NAME, table->name))
181 goto nla_put_failure;
182
183 return nlmsg_end(skb, nlh);
184
185nla_put_failure:
186 nlmsg_trim(skb, nlh);
187 return -1;
188}
189
190static int nf_tables_table_notify(const struct sk_buff *oskb,
191 const struct nlmsghdr *nlh,
192 const struct nft_table *table,
193 int event, int family)
194{
195 struct sk_buff *skb;
196 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
197 u32 seq = nlh ? nlh->nlmsg_seq : 0;
198 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
199 bool report;
200 int err;
201
202 report = nlh ? nlmsg_report(nlh) : false;
203 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
204 return 0;
205
206 err = -ENOBUFS;
207 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
208 if (skb == NULL)
209 goto err;
210
211 err = nf_tables_fill_table_info(skb, portid, seq, event, 0,
212 family, table);
213 if (err < 0) {
214 kfree_skb(skb);
215 goto err;
216 }
217
218 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
219 GFP_KERNEL);
220err:
221 if (err < 0)
222 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
223 return err;
224}
225
226static int nf_tables_dump_tables(struct sk_buff *skb,
227 struct netlink_callback *cb)
228{
229 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
230 const struct nft_af_info *afi;
231 const struct nft_table *table;
232 unsigned int idx = 0, s_idx = cb->args[0];
233 int family = nfmsg->nfgen_family;
234
235 list_for_each_entry(afi, &nf_tables_afinfo, list) {
236 if (family != NFPROTO_UNSPEC && family != afi->family)
237 continue;
238
239 list_for_each_entry(table, &afi->tables, list) {
240 if (idx < s_idx)
241 goto cont;
242 if (idx > s_idx)
243 memset(&cb->args[1], 0,
244 sizeof(cb->args) - sizeof(cb->args[0]));
245 if (nf_tables_fill_table_info(skb,
246 NETLINK_CB(cb->skb).portid,
247 cb->nlh->nlmsg_seq,
248 NFT_MSG_NEWTABLE,
249 NLM_F_MULTI,
250 afi->family, table) < 0)
251 goto done;
252cont:
253 idx++;
254 }
255 }
256done:
257 cb->args[0] = idx;
258 return skb->len;
259}
260
261static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb,
262 const struct nlmsghdr *nlh,
263 const struct nlattr * const nla[])
264{
265 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
266 const struct nft_af_info *afi;
267 const struct nft_table *table;
268 struct sk_buff *skb2;
269 int family = nfmsg->nfgen_family;
270 int err;
271
272 if (nlh->nlmsg_flags & NLM_F_DUMP) {
273 struct netlink_dump_control c = {
274 .dump = nf_tables_dump_tables,
275 };
276 return netlink_dump_start(nlsk, skb, nlh, &c);
277 }
278
279 afi = nf_tables_afinfo_lookup(family, false);
280 if (IS_ERR(afi))
281 return PTR_ERR(afi);
282
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200283 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
Patrick McHardy96518512013-10-14 11:00:02 +0200284 if (IS_ERR(table))
285 return PTR_ERR(table);
286
287 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
288 if (!skb2)
289 return -ENOMEM;
290
291 err = nf_tables_fill_table_info(skb2, NETLINK_CB(skb).portid,
292 nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0,
293 family, table);
294 if (err < 0)
295 goto err;
296
297 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
298
299err:
300 kfree_skb(skb2);
301 return err;
302}
303
304static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
305 const struct nlmsghdr *nlh,
306 const struct nlattr * const nla[])
307{
308 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
309 const struct nlattr *name;
310 struct nft_af_info *afi;
311 struct nft_table *table;
312 int family = nfmsg->nfgen_family;
313
314 afi = nf_tables_afinfo_lookup(family, true);
315 if (IS_ERR(afi))
316 return PTR_ERR(afi);
317
318 name = nla[NFTA_TABLE_NAME];
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200319 table = nf_tables_table_lookup(afi, name);
Patrick McHardy96518512013-10-14 11:00:02 +0200320 if (IS_ERR(table)) {
321 if (PTR_ERR(table) != -ENOENT)
322 return PTR_ERR(table);
323 table = NULL;
324 }
325
326 if (table != NULL) {
327 if (nlh->nlmsg_flags & NLM_F_EXCL)
328 return -EEXIST;
329 if (nlh->nlmsg_flags & NLM_F_REPLACE)
330 return -EOPNOTSUPP;
331 return 0;
332 }
333
334 table = kzalloc(sizeof(*table) + nla_len(name), GFP_KERNEL);
335 if (table == NULL)
336 return -ENOMEM;
337
338 nla_strlcpy(table->name, name, nla_len(name));
339 INIT_LIST_HEAD(&table->chains);
Patrick McHardy20a69342013-10-11 12:06:22 +0200340 INIT_LIST_HEAD(&table->sets);
Patrick McHardy96518512013-10-14 11:00:02 +0200341
342 list_add_tail(&table->list, &afi->tables);
343 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
344 return 0;
345}
346
347static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
348 const struct nlmsghdr *nlh,
349 const struct nlattr * const nla[])
350{
351 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
352 struct nft_af_info *afi;
353 struct nft_table *table;
354 int family = nfmsg->nfgen_family;
355
356 afi = nf_tables_afinfo_lookup(family, false);
357 if (IS_ERR(afi))
358 return PTR_ERR(afi);
359
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200360 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
Patrick McHardy96518512013-10-14 11:00:02 +0200361 if (IS_ERR(table))
362 return PTR_ERR(table);
363
Patrick McHardy96518512013-10-14 11:00:02 +0200364 if (table->use)
365 return -EBUSY;
366
367 list_del(&table->list);
368 nf_tables_table_notify(skb, nlh, table, NFT_MSG_DELTABLE, family);
369 kfree(table);
370 return 0;
371}
372
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200373int nft_register_chain_type(struct nf_chain_type *ctype)
Patrick McHardy96518512013-10-14 11:00:02 +0200374{
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200375 int err = 0;
Patrick McHardy96518512013-10-14 11:00:02 +0200376
377 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200378 if (chain_type[ctype->family][ctype->type] != NULL) {
379 err = -EBUSY;
380 goto out;
Patrick McHardy96518512013-10-14 11:00:02 +0200381 }
382
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200383 if (!try_module_get(ctype->me))
384 goto out;
Patrick McHardy96518512013-10-14 11:00:02 +0200385
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200386 chain_type[ctype->family][ctype->type] = ctype;
387out:
Patrick McHardy96518512013-10-14 11:00:02 +0200388 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
389 return err;
390}
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200391EXPORT_SYMBOL_GPL(nft_register_chain_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200392
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200393void nft_unregister_chain_type(struct nf_chain_type *ctype)
Patrick McHardy96518512013-10-14 11:00:02 +0200394{
Patrick McHardy96518512013-10-14 11:00:02 +0200395 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200396 chain_type[ctype->family][ctype->type] = NULL;
397 module_put(ctype->me);
Patrick McHardy96518512013-10-14 11:00:02 +0200398 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
399}
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200400EXPORT_SYMBOL_GPL(nft_unregister_chain_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200401
402/*
403 * Chains
404 */
405
406static struct nft_chain *
407nf_tables_chain_lookup_byhandle(const struct nft_table *table, u64 handle)
408{
409 struct nft_chain *chain;
410
411 list_for_each_entry(chain, &table->chains, list) {
412 if (chain->handle == handle)
413 return chain;
414 }
415
416 return ERR_PTR(-ENOENT);
417}
418
419static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table,
420 const struct nlattr *nla)
421{
422 struct nft_chain *chain;
423
424 if (nla == NULL)
425 return ERR_PTR(-EINVAL);
426
427 list_for_each_entry(chain, &table->chains, list) {
428 if (!nla_strcmp(nla, chain->name))
429 return chain;
430 }
431
432 return ERR_PTR(-ENOENT);
433}
434
435static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
436 [NFTA_CHAIN_TABLE] = { .type = NLA_STRING },
437 [NFTA_CHAIN_HANDLE] = { .type = NLA_U64 },
438 [NFTA_CHAIN_NAME] = { .type = NLA_STRING,
439 .len = NFT_CHAIN_MAXNAMELEN - 1 },
440 [NFTA_CHAIN_HOOK] = { .type = NLA_NESTED },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200441 [NFTA_CHAIN_POLICY] = { .type = NLA_U32 },
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200442 [NFTA_CHAIN_TYPE] = { .type = NLA_NUL_STRING },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200443 [NFTA_CHAIN_COUNTERS] = { .type = NLA_NESTED },
Patrick McHardy96518512013-10-14 11:00:02 +0200444};
445
446static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = {
447 [NFTA_HOOK_HOOKNUM] = { .type = NLA_U32 },
448 [NFTA_HOOK_PRIORITY] = { .type = NLA_U32 },
449};
450
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200451static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats)
452{
453 struct nft_stats *cpu_stats, total;
454 struct nlattr *nest;
455 int cpu;
456
457 memset(&total, 0, sizeof(total));
458 for_each_possible_cpu(cpu) {
459 cpu_stats = per_cpu_ptr(stats, cpu);
460 total.pkts += cpu_stats->pkts;
461 total.bytes += cpu_stats->bytes;
462 }
463 nest = nla_nest_start(skb, NFTA_CHAIN_COUNTERS);
464 if (nest == NULL)
465 goto nla_put_failure;
466
467 if (nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(total.pkts)) ||
468 nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes)))
469 goto nla_put_failure;
470
471 nla_nest_end(skb, nest);
472 return 0;
473
474nla_put_failure:
475 return -ENOSPC;
476}
477
Patrick McHardy96518512013-10-14 11:00:02 +0200478static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq,
479 int event, u32 flags, int family,
480 const struct nft_table *table,
481 const struct nft_chain *chain)
482{
483 struct nlmsghdr *nlh;
484 struct nfgenmsg *nfmsg;
485
486 event |= NFNL_SUBSYS_NFTABLES << 8;
487 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
488 if (nlh == NULL)
489 goto nla_put_failure;
490
491 nfmsg = nlmsg_data(nlh);
492 nfmsg->nfgen_family = family;
493 nfmsg->version = NFNETLINK_V0;
494 nfmsg->res_id = 0;
495
496 if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name))
497 goto nla_put_failure;
498 if (nla_put_be64(skb, NFTA_CHAIN_HANDLE, cpu_to_be64(chain->handle)))
499 goto nla_put_failure;
500 if (nla_put_string(skb, NFTA_CHAIN_NAME, chain->name))
501 goto nla_put_failure;
502
503 if (chain->flags & NFT_BASE_CHAIN) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200504 const struct nft_base_chain *basechain = nft_base_chain(chain);
505 const struct nf_hook_ops *ops = &basechain->ops;
506 struct nlattr *nest;
507
508 nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
Patrick McHardy96518512013-10-14 11:00:02 +0200509 if (nest == NULL)
510 goto nla_put_failure;
511 if (nla_put_be32(skb, NFTA_HOOK_HOOKNUM, htonl(ops->hooknum)))
512 goto nla_put_failure;
513 if (nla_put_be32(skb, NFTA_HOOK_PRIORITY, htonl(ops->priority)))
514 goto nla_put_failure;
515 nla_nest_end(skb, nest);
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200516
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200517 if (nla_put_be32(skb, NFTA_CHAIN_POLICY,
518 htonl(basechain->policy)))
519 goto nla_put_failure;
520
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200521 if (nla_put_string(skb, NFTA_CHAIN_TYPE,
522 chain_type[ops->pf][nft_base_chain(chain)->type]->name))
523 goto nla_put_failure;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200524
525 if (nft_dump_stats(skb, nft_base_chain(chain)->stats))
526 goto nla_put_failure;
Patrick McHardy96518512013-10-14 11:00:02 +0200527 }
528
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200529 if (nla_put_be32(skb, NFTA_CHAIN_USE, htonl(chain->use)))
530 goto nla_put_failure;
531
Patrick McHardy96518512013-10-14 11:00:02 +0200532 return nlmsg_end(skb, nlh);
533
534nla_put_failure:
535 nlmsg_trim(skb, nlh);
536 return -1;
537}
538
539static int nf_tables_chain_notify(const struct sk_buff *oskb,
540 const struct nlmsghdr *nlh,
541 const struct nft_table *table,
542 const struct nft_chain *chain,
543 int event, int family)
544{
545 struct sk_buff *skb;
546 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
547 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
548 u32 seq = nlh ? nlh->nlmsg_seq : 0;
549 bool report;
550 int err;
551
552 report = nlh ? nlmsg_report(nlh) : false;
553 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
554 return 0;
555
556 err = -ENOBUFS;
557 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
558 if (skb == NULL)
559 goto err;
560
561 err = nf_tables_fill_chain_info(skb, portid, seq, event, 0, family,
562 table, chain);
563 if (err < 0) {
564 kfree_skb(skb);
565 goto err;
566 }
567
568 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
569 GFP_KERNEL);
570err:
571 if (err < 0)
572 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
573 return err;
574}
575
576static int nf_tables_dump_chains(struct sk_buff *skb,
577 struct netlink_callback *cb)
578{
579 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
580 const struct nft_af_info *afi;
581 const struct nft_table *table;
582 const struct nft_chain *chain;
583 unsigned int idx = 0, s_idx = cb->args[0];
584 int family = nfmsg->nfgen_family;
585
586 list_for_each_entry(afi, &nf_tables_afinfo, list) {
587 if (family != NFPROTO_UNSPEC && family != afi->family)
588 continue;
589
590 list_for_each_entry(table, &afi->tables, list) {
591 list_for_each_entry(chain, &table->chains, list) {
592 if (idx < s_idx)
593 goto cont;
594 if (idx > s_idx)
595 memset(&cb->args[1], 0,
596 sizeof(cb->args) - sizeof(cb->args[0]));
597 if (nf_tables_fill_chain_info(skb, NETLINK_CB(cb->skb).portid,
598 cb->nlh->nlmsg_seq,
599 NFT_MSG_NEWCHAIN,
600 NLM_F_MULTI,
601 afi->family, table, chain) < 0)
602 goto done;
603cont:
604 idx++;
605 }
606 }
607 }
608done:
609 cb->args[0] = idx;
610 return skb->len;
611}
612
613
614static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb,
615 const struct nlmsghdr *nlh,
616 const struct nlattr * const nla[])
617{
618 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
619 const struct nft_af_info *afi;
620 const struct nft_table *table;
621 const struct nft_chain *chain;
622 struct sk_buff *skb2;
623 int family = nfmsg->nfgen_family;
624 int err;
625
626 if (nlh->nlmsg_flags & NLM_F_DUMP) {
627 struct netlink_dump_control c = {
628 .dump = nf_tables_dump_chains,
629 };
630 return netlink_dump_start(nlsk, skb, nlh, &c);
631 }
632
633 afi = nf_tables_afinfo_lookup(family, false);
634 if (IS_ERR(afi))
635 return PTR_ERR(afi);
636
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200637 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +0200638 if (IS_ERR(table))
639 return PTR_ERR(table);
640
641 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
642 if (IS_ERR(chain))
643 return PTR_ERR(chain);
644
645 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
646 if (!skb2)
647 return -ENOMEM;
648
649 err = nf_tables_fill_chain_info(skb2, NETLINK_CB(skb).portid,
650 nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0,
651 family, table, chain);
652 if (err < 0)
653 goto err;
654
655 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
656
657err:
658 kfree_skb(skb2);
659 return err;
660}
661
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200662static int
663nf_tables_chain_policy(struct nft_base_chain *chain, const struct nlattr *attr)
664{
665 switch (ntohl(nla_get_be32(attr))) {
666 case NF_DROP:
667 chain->policy = NF_DROP;
668 break;
669 case NF_ACCEPT:
670 chain->policy = NF_ACCEPT;
671 break;
672 default:
673 return -EINVAL;
674 }
675 return 0;
676}
677
678static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = {
679 [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 },
680 [NFTA_COUNTER_BYTES] = { .type = NLA_U64 },
681};
682
683static int
684nf_tables_counters(struct nft_base_chain *chain, const struct nlattr *attr)
685{
686 struct nlattr *tb[NFTA_COUNTER_MAX+1];
687 struct nft_stats __percpu *newstats;
688 struct nft_stats *stats;
689 int err;
690
691 err = nla_parse_nested(tb, NFTA_COUNTER_MAX, attr, nft_counter_policy);
692 if (err < 0)
693 return err;
694
695 if (!tb[NFTA_COUNTER_BYTES] || !tb[NFTA_COUNTER_PACKETS])
696 return -EINVAL;
697
698 newstats = alloc_percpu(struct nft_stats);
699 if (newstats == NULL)
700 return -ENOMEM;
701
702 /* Restore old counters on this cpu, no problem. Per-cpu statistics
703 * are not exposed to userspace.
704 */
705 stats = this_cpu_ptr(newstats);
706 stats->bytes = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES]));
707 stats->pkts = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS]));
708
709 if (chain->stats) {
710 /* nfnl_lock is held, add some nfnl function for this, later */
711 struct nft_stats __percpu *oldstats =
712 rcu_dereference_protected(chain->stats, 1);
713
714 rcu_assign_pointer(chain->stats, newstats);
715 synchronize_rcu();
716 free_percpu(oldstats);
717 } else
718 rcu_assign_pointer(chain->stats, newstats);
719
720 return 0;
721}
722
Patrick McHardy96518512013-10-14 11:00:02 +0200723static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
724 const struct nlmsghdr *nlh,
725 const struct nlattr * const nla[])
726{
727 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
728 const struct nlattr * uninitialized_var(name);
729 const struct nft_af_info *afi;
730 struct nft_table *table;
731 struct nft_chain *chain;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200732 struct nft_base_chain *basechain = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +0200733 struct nlattr *ha[NFTA_HOOK_MAX + 1];
734 int family = nfmsg->nfgen_family;
735 u64 handle = 0;
736 int err;
737 bool create;
738
739 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
740
741 afi = nf_tables_afinfo_lookup(family, true);
742 if (IS_ERR(afi))
743 return PTR_ERR(afi);
744
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200745 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +0200746 if (IS_ERR(table))
747 return PTR_ERR(table);
748
749 if (table->use == UINT_MAX)
750 return -EOVERFLOW;
751
752 chain = NULL;
753 name = nla[NFTA_CHAIN_NAME];
754
755 if (nla[NFTA_CHAIN_HANDLE]) {
756 handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
757 chain = nf_tables_chain_lookup_byhandle(table, handle);
758 if (IS_ERR(chain))
759 return PTR_ERR(chain);
760 } else {
761 chain = nf_tables_chain_lookup(table, name);
762 if (IS_ERR(chain)) {
763 if (PTR_ERR(chain) != -ENOENT)
764 return PTR_ERR(chain);
765 chain = NULL;
766 }
767 }
768
769 if (chain != NULL) {
770 if (nlh->nlmsg_flags & NLM_F_EXCL)
771 return -EEXIST;
772 if (nlh->nlmsg_flags & NLM_F_REPLACE)
773 return -EOPNOTSUPP;
774
775 if (nla[NFTA_CHAIN_HANDLE] && name &&
776 !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME])))
777 return -EEXIST;
778
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200779 if (nla[NFTA_CHAIN_POLICY]) {
780 if (!(chain->flags & NFT_BASE_CHAIN))
781 return -EOPNOTSUPP;
782
783 err = nf_tables_chain_policy(nft_base_chain(chain),
784 nla[NFTA_CHAIN_POLICY]);
785 if (err < 0)
786 return err;
787 }
788
789 if (nla[NFTA_CHAIN_COUNTERS]) {
790 if (!(chain->flags & NFT_BASE_CHAIN))
791 return -EOPNOTSUPP;
792
793 err = nf_tables_counters(nft_base_chain(chain),
794 nla[NFTA_CHAIN_COUNTERS]);
795 if (err < 0)
796 return err;
797 }
798
Patrick McHardy96518512013-10-14 11:00:02 +0200799 if (nla[NFTA_CHAIN_HANDLE] && name)
800 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
801
802 goto notify;
803 }
804
805 if (nla[NFTA_CHAIN_HOOK]) {
806 struct nf_hook_ops *ops;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200807 nf_hookfn *hookfn;
808 u32 hooknum;
809 int type = NFT_CHAIN_T_DEFAULT;
810
811 if (nla[NFTA_CHAIN_TYPE]) {
812 type = nf_tables_chain_type_lookup(afi,
813 nla[NFTA_CHAIN_TYPE],
814 create);
815 if (type < 0)
816 return -ENOENT;
817 }
Patrick McHardy96518512013-10-14 11:00:02 +0200818
819 err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK],
820 nft_hook_policy);
821 if (err < 0)
822 return err;
823 if (ha[NFTA_HOOK_HOOKNUM] == NULL ||
824 ha[NFTA_HOOK_PRIORITY] == NULL)
825 return -EINVAL;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200826
827 hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
828 if (hooknum >= afi->nhooks)
Patrick McHardy96518512013-10-14 11:00:02 +0200829 return -EINVAL;
830
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200831 hookfn = chain_type[family][type]->fn[hooknum];
832 if (hookfn == NULL)
833 return -EOPNOTSUPP;
834
Patrick McHardy96518512013-10-14 11:00:02 +0200835 basechain = kzalloc(sizeof(*basechain), GFP_KERNEL);
836 if (basechain == NULL)
837 return -ENOMEM;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200838
839 basechain->type = type;
Patrick McHardy96518512013-10-14 11:00:02 +0200840 chain = &basechain->chain;
841
842 ops = &basechain->ops;
843 ops->pf = family;
844 ops->owner = afi->owner;
845 ops->hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
846 ops->priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
847 ops->priv = chain;
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200848 ops->hook = hookfn;
Patrick McHardy96518512013-10-14 11:00:02 +0200849 if (afi->hooks[ops->hooknum])
850 ops->hook = afi->hooks[ops->hooknum];
851
852 chain->flags |= NFT_BASE_CHAIN;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200853
854 if (nla[NFTA_CHAIN_POLICY]) {
855 err = nf_tables_chain_policy(basechain,
856 nla[NFTA_CHAIN_POLICY]);
857 if (err < 0) {
858 free_percpu(basechain->stats);
859 kfree(basechain);
860 return err;
861 }
862 } else
863 basechain->policy = NF_ACCEPT;
864
865 if (nla[NFTA_CHAIN_COUNTERS]) {
866 err = nf_tables_counters(basechain,
867 nla[NFTA_CHAIN_COUNTERS]);
868 if (err < 0) {
869 free_percpu(basechain->stats);
870 kfree(basechain);
871 return err;
872 }
873 } else {
874 struct nft_stats __percpu *newstats;
875
876 newstats = alloc_percpu(struct nft_stats);
877 if (newstats == NULL)
878 return -ENOMEM;
879
880 rcu_assign_pointer(nft_base_chain(chain)->stats,
881 newstats);
882 }
Patrick McHardy96518512013-10-14 11:00:02 +0200883 } else {
884 chain = kzalloc(sizeof(*chain), GFP_KERNEL);
885 if (chain == NULL)
886 return -ENOMEM;
887 }
888
889 INIT_LIST_HEAD(&chain->rules);
890 chain->handle = nf_tables_alloc_handle(table);
891 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
892
893 list_add_tail(&chain->list, &table->chains);
894 table->use++;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200895
896 if (chain->flags & NFT_BASE_CHAIN) {
897 err = nf_register_hook(&nft_base_chain(chain)->ops);
898 if (err < 0) {
899 free_percpu(basechain->stats);
900 kfree(basechain);
901 return err;
902 }
903 }
Patrick McHardy96518512013-10-14 11:00:02 +0200904notify:
905 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_NEWCHAIN,
906 family);
907 return 0;
908}
909
910static void nf_tables_rcu_chain_destroy(struct rcu_head *head)
911{
912 struct nft_chain *chain = container_of(head, struct nft_chain, rcu_head);
913
914 BUG_ON(chain->use > 0);
915
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200916 if (chain->flags & NFT_BASE_CHAIN) {
917 free_percpu(nft_base_chain(chain)->stats);
Patrick McHardy96518512013-10-14 11:00:02 +0200918 kfree(nft_base_chain(chain));
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200919 } else
Patrick McHardy96518512013-10-14 11:00:02 +0200920 kfree(chain);
921}
922
923static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
924 const struct nlmsghdr *nlh,
925 const struct nlattr * const nla[])
926{
927 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
928 const struct nft_af_info *afi;
929 struct nft_table *table;
930 struct nft_chain *chain;
931 int family = nfmsg->nfgen_family;
932
933 afi = nf_tables_afinfo_lookup(family, false);
934 if (IS_ERR(afi))
935 return PTR_ERR(afi);
936
Pablo Neira Ayuso93707612013-10-10 23:21:26 +0200937 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +0200938 if (IS_ERR(table))
939 return PTR_ERR(table);
940
941 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
942 if (IS_ERR(chain))
943 return PTR_ERR(chain);
944
Patrick McHardy96518512013-10-14 11:00:02 +0200945 if (!list_empty(&chain->rules))
946 return -EBUSY;
947
948 list_del(&chain->list);
949 table->use--;
950
951 if (chain->flags & NFT_BASE_CHAIN)
952 nf_unregister_hook(&nft_base_chain(chain)->ops);
953
954 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN,
955 family);
956
957 /* Make sure all rule references are gone before this is released */
958 call_rcu(&chain->rcu_head, nf_tables_rcu_chain_destroy);
959 return 0;
960}
961
962static void nft_ctx_init(struct nft_ctx *ctx,
Patrick McHardy20a69342013-10-11 12:06:22 +0200963 const struct sk_buff *skb,
964 const struct nlmsghdr *nlh,
Patrick McHardy96518512013-10-14 11:00:02 +0200965 const struct nft_af_info *afi,
966 const struct nft_table *table,
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200967 const struct nft_chain *chain,
968 const struct nlattr * const *nla)
Patrick McHardy96518512013-10-14 11:00:02 +0200969{
Patrick McHardy20a69342013-10-11 12:06:22 +0200970 ctx->skb = skb;
971 ctx->nlh = nlh;
Patrick McHardy96518512013-10-14 11:00:02 +0200972 ctx->afi = afi;
973 ctx->table = table;
974 ctx->chain = chain;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200975 ctx->nla = nla;
Patrick McHardy96518512013-10-14 11:00:02 +0200976}
977
978/*
979 * Expressions
980 */
981
982/**
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200983 * nft_register_expr - register nf_tables expr type
984 * @ops: expr type
Patrick McHardy96518512013-10-14 11:00:02 +0200985 *
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200986 * Registers the expr type for use with nf_tables. Returns zero on
Patrick McHardy96518512013-10-14 11:00:02 +0200987 * success or a negative errno code otherwise.
988 */
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200989int nft_register_expr(struct nft_expr_type *type)
Patrick McHardy96518512013-10-14 11:00:02 +0200990{
991 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200992 list_add_tail(&type->list, &nf_tables_expressions);
Patrick McHardy96518512013-10-14 11:00:02 +0200993 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
994 return 0;
995}
996EXPORT_SYMBOL_GPL(nft_register_expr);
997
998/**
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200999 * nft_unregister_expr - unregister nf_tables expr type
1000 * @ops: expr type
Patrick McHardy96518512013-10-14 11:00:02 +02001001 *
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001002 * Unregisters the expr typefor use with nf_tables.
Patrick McHardy96518512013-10-14 11:00:02 +02001003 */
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001004void nft_unregister_expr(struct nft_expr_type *type)
Patrick McHardy96518512013-10-14 11:00:02 +02001005{
1006 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001007 list_del(&type->list);
Patrick McHardy96518512013-10-14 11:00:02 +02001008 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1009}
1010EXPORT_SYMBOL_GPL(nft_unregister_expr);
1011
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001012static const struct nft_expr_type *__nft_expr_type_get(struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001013{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001014 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001015
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001016 list_for_each_entry(type, &nf_tables_expressions, list) {
1017 if (!nla_strcmp(nla, type->name))
1018 return type;
Patrick McHardy96518512013-10-14 11:00:02 +02001019 }
1020 return NULL;
1021}
1022
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001023static const struct nft_expr_type *nft_expr_type_get(struct nlattr *nla)
Patrick McHardy96518512013-10-14 11:00:02 +02001024{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001025 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001026
1027 if (nla == NULL)
1028 return ERR_PTR(-EINVAL);
1029
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001030 type = __nft_expr_type_get(nla);
1031 if (type != NULL && try_module_get(type->owner))
1032 return type;
Patrick McHardy96518512013-10-14 11:00:02 +02001033
1034#ifdef CONFIG_MODULES
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001035 if (type == NULL) {
Patrick McHardy96518512013-10-14 11:00:02 +02001036 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1037 request_module("nft-expr-%.*s",
1038 nla_len(nla), (char *)nla_data(nla));
1039 nfnl_lock(NFNL_SUBSYS_NFTABLES);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001040 if (__nft_expr_type_get(nla))
Patrick McHardy96518512013-10-14 11:00:02 +02001041 return ERR_PTR(-EAGAIN);
1042 }
1043#endif
1044 return ERR_PTR(-ENOENT);
1045}
1046
1047static const struct nla_policy nft_expr_policy[NFTA_EXPR_MAX + 1] = {
1048 [NFTA_EXPR_NAME] = { .type = NLA_STRING },
1049 [NFTA_EXPR_DATA] = { .type = NLA_NESTED },
1050};
1051
1052static int nf_tables_fill_expr_info(struct sk_buff *skb,
1053 const struct nft_expr *expr)
1054{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001055 if (nla_put_string(skb, NFTA_EXPR_NAME, expr->ops->type->name))
Patrick McHardy96518512013-10-14 11:00:02 +02001056 goto nla_put_failure;
1057
1058 if (expr->ops->dump) {
1059 struct nlattr *data = nla_nest_start(skb, NFTA_EXPR_DATA);
1060 if (data == NULL)
1061 goto nla_put_failure;
1062 if (expr->ops->dump(skb, expr) < 0)
1063 goto nla_put_failure;
1064 nla_nest_end(skb, data);
1065 }
1066
1067 return skb->len;
1068
1069nla_put_failure:
1070 return -1;
1071};
1072
1073struct nft_expr_info {
1074 const struct nft_expr_ops *ops;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001075 struct nlattr *tb[NFT_EXPR_MAXATTR + 1];
Patrick McHardy96518512013-10-14 11:00:02 +02001076};
1077
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001078static int nf_tables_expr_parse(const struct nft_ctx *ctx,
1079 const struct nlattr *nla,
Patrick McHardy96518512013-10-14 11:00:02 +02001080 struct nft_expr_info *info)
1081{
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001082 const struct nft_expr_type *type;
Patrick McHardy96518512013-10-14 11:00:02 +02001083 const struct nft_expr_ops *ops;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001084 struct nlattr *tb[NFTA_EXPR_MAX + 1];
Patrick McHardy96518512013-10-14 11:00:02 +02001085 int err;
1086
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001087 err = nla_parse_nested(tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
Patrick McHardy96518512013-10-14 11:00:02 +02001088 if (err < 0)
1089 return err;
1090
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001091 type = nft_expr_type_get(tb[NFTA_EXPR_NAME]);
1092 if (IS_ERR(type))
1093 return PTR_ERR(type);
1094
1095 if (tb[NFTA_EXPR_DATA]) {
1096 err = nla_parse_nested(info->tb, type->maxattr,
1097 tb[NFTA_EXPR_DATA], type->policy);
1098 if (err < 0)
1099 goto err1;
1100 } else
1101 memset(info->tb, 0, sizeof(info->tb[0]) * (type->maxattr + 1));
1102
1103 if (type->select_ops != NULL) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001104 ops = type->select_ops(ctx,
1105 (const struct nlattr * const *)info->tb);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001106 if (IS_ERR(ops)) {
1107 err = PTR_ERR(ops);
1108 goto err1;
1109 }
1110 } else
1111 ops = type->ops;
1112
Patrick McHardy96518512013-10-14 11:00:02 +02001113 info->ops = ops;
1114 return 0;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001115
1116err1:
1117 module_put(type->owner);
1118 return err;
Patrick McHardy96518512013-10-14 11:00:02 +02001119}
1120
1121static int nf_tables_newexpr(const struct nft_ctx *ctx,
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001122 const struct nft_expr_info *info,
Patrick McHardy96518512013-10-14 11:00:02 +02001123 struct nft_expr *expr)
1124{
1125 const struct nft_expr_ops *ops = info->ops;
1126 int err;
1127
1128 expr->ops = ops;
1129 if (ops->init) {
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001130 err = ops->init(ctx, expr, (const struct nlattr **)info->tb);
Patrick McHardy96518512013-10-14 11:00:02 +02001131 if (err < 0)
1132 goto err1;
1133 }
1134
Patrick McHardy96518512013-10-14 11:00:02 +02001135 return 0;
1136
1137err1:
1138 expr->ops = NULL;
1139 return err;
1140}
1141
1142static void nf_tables_expr_destroy(struct nft_expr *expr)
1143{
1144 if (expr->ops->destroy)
1145 expr->ops->destroy(expr);
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001146 module_put(expr->ops->type->owner);
Patrick McHardy96518512013-10-14 11:00:02 +02001147}
1148
1149/*
1150 * Rules
1151 */
1152
1153static struct nft_rule *__nf_tables_rule_lookup(const struct nft_chain *chain,
1154 u64 handle)
1155{
1156 struct nft_rule *rule;
1157
1158 // FIXME: this sucks
1159 list_for_each_entry(rule, &chain->rules, list) {
1160 if (handle == rule->handle)
1161 return rule;
1162 }
1163
1164 return ERR_PTR(-ENOENT);
1165}
1166
1167static struct nft_rule *nf_tables_rule_lookup(const struct nft_chain *chain,
1168 const struct nlattr *nla)
1169{
1170 if (nla == NULL)
1171 return ERR_PTR(-EINVAL);
1172
1173 return __nf_tables_rule_lookup(chain, be64_to_cpu(nla_get_be64(nla)));
1174}
1175
1176static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
1177 [NFTA_RULE_TABLE] = { .type = NLA_STRING },
1178 [NFTA_RULE_CHAIN] = { .type = NLA_STRING,
1179 .len = NFT_CHAIN_MAXNAMELEN - 1 },
1180 [NFTA_RULE_HANDLE] = { .type = NLA_U64 },
1181 [NFTA_RULE_EXPRESSIONS] = { .type = NLA_NESTED },
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001182 [NFTA_RULE_COMPAT] = { .type = NLA_NESTED },
Patrick McHardy96518512013-10-14 11:00:02 +02001183};
1184
1185static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
1186 int event, u32 flags, int family,
1187 const struct nft_table *table,
1188 const struct nft_chain *chain,
1189 const struct nft_rule *rule)
1190{
1191 struct nlmsghdr *nlh;
1192 struct nfgenmsg *nfmsg;
1193 const struct nft_expr *expr, *next;
1194 struct nlattr *list;
1195
1196 event |= NFNL_SUBSYS_NFTABLES << 8;
1197 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
1198 flags);
1199 if (nlh == NULL)
1200 goto nla_put_failure;
1201
1202 nfmsg = nlmsg_data(nlh);
1203 nfmsg->nfgen_family = family;
1204 nfmsg->version = NFNETLINK_V0;
1205 nfmsg->res_id = 0;
1206
1207 if (nla_put_string(skb, NFTA_RULE_TABLE, table->name))
1208 goto nla_put_failure;
1209 if (nla_put_string(skb, NFTA_RULE_CHAIN, chain->name))
1210 goto nla_put_failure;
1211 if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
1212 goto nla_put_failure;
1213
1214 list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
1215 if (list == NULL)
1216 goto nla_put_failure;
1217 nft_rule_for_each_expr(expr, next, rule) {
1218 struct nlattr *elem = nla_nest_start(skb, NFTA_LIST_ELEM);
1219 if (elem == NULL)
1220 goto nla_put_failure;
1221 if (nf_tables_fill_expr_info(skb, expr) < 0)
1222 goto nla_put_failure;
1223 nla_nest_end(skb, elem);
1224 }
1225 nla_nest_end(skb, list);
1226
1227 return nlmsg_end(skb, nlh);
1228
1229nla_put_failure:
1230 nlmsg_trim(skb, nlh);
1231 return -1;
1232}
1233
1234static int nf_tables_rule_notify(const struct sk_buff *oskb,
1235 const struct nlmsghdr *nlh,
1236 const struct nft_table *table,
1237 const struct nft_chain *chain,
1238 const struct nft_rule *rule,
1239 int event, u32 flags, int family)
1240{
1241 struct sk_buff *skb;
1242 u32 portid = NETLINK_CB(oskb).portid;
1243 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
1244 u32 seq = nlh->nlmsg_seq;
1245 bool report;
1246 int err;
1247
1248 report = nlmsg_report(nlh);
1249 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
1250 return 0;
1251
1252 err = -ENOBUFS;
1253 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1254 if (skb == NULL)
1255 goto err;
1256
1257 err = nf_tables_fill_rule_info(skb, portid, seq, event, flags,
1258 family, table, chain, rule);
1259 if (err < 0) {
1260 kfree_skb(skb);
1261 goto err;
1262 }
1263
1264 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
1265 GFP_KERNEL);
1266err:
1267 if (err < 0)
1268 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
1269 return err;
1270}
1271
1272static int nf_tables_dump_rules(struct sk_buff *skb,
1273 struct netlink_callback *cb)
1274{
1275 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
1276 const struct nft_af_info *afi;
1277 const struct nft_table *table;
1278 const struct nft_chain *chain;
1279 const struct nft_rule *rule;
1280 unsigned int idx = 0, s_idx = cb->args[0];
1281 int family = nfmsg->nfgen_family;
1282
1283 list_for_each_entry(afi, &nf_tables_afinfo, list) {
1284 if (family != NFPROTO_UNSPEC && family != afi->family)
1285 continue;
1286
1287 list_for_each_entry(table, &afi->tables, list) {
1288 list_for_each_entry(chain, &table->chains, list) {
1289 list_for_each_entry(rule, &chain->rules, list) {
1290 if (idx < s_idx)
1291 goto cont;
1292 if (idx > s_idx)
1293 memset(&cb->args[1], 0,
1294 sizeof(cb->args) - sizeof(cb->args[0]));
1295 if (nf_tables_fill_rule_info(skb, NETLINK_CB(cb->skb).portid,
1296 cb->nlh->nlmsg_seq,
1297 NFT_MSG_NEWRULE,
1298 NLM_F_MULTI | NLM_F_APPEND,
1299 afi->family, table, chain, rule) < 0)
1300 goto done;
1301cont:
1302 idx++;
1303 }
1304 }
1305 }
1306 }
1307done:
1308 cb->args[0] = idx;
1309 return skb->len;
1310}
1311
1312static int nf_tables_getrule(struct sock *nlsk, struct sk_buff *skb,
1313 const struct nlmsghdr *nlh,
1314 const struct nlattr * const nla[])
1315{
1316 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1317 const struct nft_af_info *afi;
1318 const struct nft_table *table;
1319 const struct nft_chain *chain;
1320 const struct nft_rule *rule;
1321 struct sk_buff *skb2;
1322 int family = nfmsg->nfgen_family;
1323 int err;
1324
1325 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1326 struct netlink_dump_control c = {
1327 .dump = nf_tables_dump_rules,
1328 };
1329 return netlink_dump_start(nlsk, skb, nlh, &c);
1330 }
1331
1332 afi = nf_tables_afinfo_lookup(family, false);
1333 if (IS_ERR(afi))
1334 return PTR_ERR(afi);
1335
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001336 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001337 if (IS_ERR(table))
1338 return PTR_ERR(table);
1339
1340 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1341 if (IS_ERR(chain))
1342 return PTR_ERR(chain);
1343
1344 rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
1345 if (IS_ERR(rule))
1346 return PTR_ERR(rule);
1347
1348 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1349 if (!skb2)
1350 return -ENOMEM;
1351
1352 err = nf_tables_fill_rule_info(skb2, NETLINK_CB(skb).portid,
1353 nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
1354 family, table, chain, rule);
1355 if (err < 0)
1356 goto err;
1357
1358 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
1359
1360err:
1361 kfree_skb(skb2);
1362 return err;
1363}
1364
1365static void nf_tables_rcu_rule_destroy(struct rcu_head *head)
1366{
1367 struct nft_rule *rule = container_of(head, struct nft_rule, rcu_head);
1368 struct nft_expr *expr;
1369
1370 /*
1371 * Careful: some expressions might not be initialized in case this
1372 * is called on error from nf_tables_newrule().
1373 */
1374 expr = nft_expr_first(rule);
1375 while (expr->ops && expr != nft_expr_last(rule)) {
1376 nf_tables_expr_destroy(expr);
1377 expr = nft_expr_next(expr);
1378 }
1379 kfree(rule);
1380}
1381
1382static void nf_tables_rule_destroy(struct nft_rule *rule)
1383{
1384 call_rcu(&rule->rcu_head, nf_tables_rcu_rule_destroy);
1385}
1386
1387#define NFT_RULE_MAXEXPRS 128
1388
1389static struct nft_expr_info *info;
1390
1391static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
1392 const struct nlmsghdr *nlh,
1393 const struct nlattr * const nla[])
1394{
1395 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1396 const struct nft_af_info *afi;
1397 struct nft_table *table;
1398 struct nft_chain *chain;
1399 struct nft_rule *rule, *old_rule = NULL;
1400 struct nft_expr *expr;
1401 struct nft_ctx ctx;
1402 struct nlattr *tmp;
1403 unsigned int size, i, n;
1404 int err, rem;
1405 bool create;
1406 u64 handle;
1407
1408 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
1409
1410 afi = nf_tables_afinfo_lookup(nfmsg->nfgen_family, create);
1411 if (IS_ERR(afi))
1412 return PTR_ERR(afi);
1413
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001414 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001415 if (IS_ERR(table))
1416 return PTR_ERR(table);
1417
1418 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1419 if (IS_ERR(chain))
1420 return PTR_ERR(chain);
1421
1422 if (nla[NFTA_RULE_HANDLE]) {
1423 handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
1424 rule = __nf_tables_rule_lookup(chain, handle);
1425 if (IS_ERR(rule))
1426 return PTR_ERR(rule);
1427
1428 if (nlh->nlmsg_flags & NLM_F_EXCL)
1429 return -EEXIST;
1430 if (nlh->nlmsg_flags & NLM_F_REPLACE)
1431 old_rule = rule;
1432 else
1433 return -EOPNOTSUPP;
1434 } else {
1435 if (!create || nlh->nlmsg_flags & NLM_F_REPLACE)
1436 return -EINVAL;
1437 handle = nf_tables_alloc_handle(table);
1438 }
1439
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001440 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1441
Patrick McHardy96518512013-10-14 11:00:02 +02001442 n = 0;
1443 size = 0;
1444 if (nla[NFTA_RULE_EXPRESSIONS]) {
1445 nla_for_each_nested(tmp, nla[NFTA_RULE_EXPRESSIONS], rem) {
1446 err = -EINVAL;
1447 if (nla_type(tmp) != NFTA_LIST_ELEM)
1448 goto err1;
1449 if (n == NFT_RULE_MAXEXPRS)
1450 goto err1;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001451 err = nf_tables_expr_parse(&ctx, tmp, &info[n]);
Patrick McHardy96518512013-10-14 11:00:02 +02001452 if (err < 0)
1453 goto err1;
1454 size += info[n].ops->size;
1455 n++;
1456 }
1457 }
1458
1459 err = -ENOMEM;
1460 rule = kzalloc(sizeof(*rule) + size, GFP_KERNEL);
1461 if (rule == NULL)
1462 goto err1;
1463
1464 rule->handle = handle;
1465 rule->dlen = size;
1466
Patrick McHardy96518512013-10-14 11:00:02 +02001467 expr = nft_expr_first(rule);
1468 for (i = 0; i < n; i++) {
1469 err = nf_tables_newexpr(&ctx, &info[i], expr);
1470 if (err < 0)
1471 goto err2;
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001472 info[i].ops = NULL;
Patrick McHardy96518512013-10-14 11:00:02 +02001473 expr = nft_expr_next(expr);
1474 }
1475
Patrick McHardy96518512013-10-14 11:00:02 +02001476 if (nlh->nlmsg_flags & NLM_F_REPLACE) {
1477 list_replace_rcu(&old_rule->list, &rule->list);
1478 nf_tables_rule_destroy(old_rule);
1479 } else if (nlh->nlmsg_flags & NLM_F_APPEND)
1480 list_add_tail_rcu(&rule->list, &chain->rules);
1481 else
1482 list_add_rcu(&rule->list, &chain->rules);
1483
1484 nf_tables_rule_notify(skb, nlh, table, chain, rule, NFT_MSG_NEWRULE,
1485 nlh->nlmsg_flags & (NLM_F_APPEND | NLM_F_REPLACE),
1486 nfmsg->nfgen_family);
1487 return 0;
1488
1489err2:
1490 nf_tables_rule_destroy(rule);
1491err1:
1492 for (i = 0; i < n; i++) {
1493 if (info[i].ops != NULL)
Patrick McHardyef1f7df2013-10-10 11:41:20 +02001494 module_put(info[i].ops->type->owner);
Patrick McHardy96518512013-10-14 11:00:02 +02001495 }
1496 return err;
1497}
1498
1499static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
1500 const struct nlmsghdr *nlh,
1501 const struct nlattr * const nla[])
1502{
1503 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1504 const struct nft_af_info *afi;
1505 const struct nft_table *table;
1506 struct nft_chain *chain;
1507 struct nft_rule *rule, *tmp;
1508 int family = nfmsg->nfgen_family;
1509
1510 afi = nf_tables_afinfo_lookup(family, false);
1511 if (IS_ERR(afi))
1512 return PTR_ERR(afi);
1513
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001514 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
Patrick McHardy96518512013-10-14 11:00:02 +02001515 if (IS_ERR(table))
1516 return PTR_ERR(table);
1517
1518 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1519 if (IS_ERR(chain))
1520 return PTR_ERR(chain);
1521
1522 if (nla[NFTA_RULE_HANDLE]) {
1523 rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
1524 if (IS_ERR(rule))
1525 return PTR_ERR(rule);
1526
1527 /* List removal must be visible before destroying expressions */
1528 list_del_rcu(&rule->list);
1529
1530 nf_tables_rule_notify(skb, nlh, table, chain, rule,
1531 NFT_MSG_DELRULE, 0, family);
1532 nf_tables_rule_destroy(rule);
1533 } else {
1534 /* Remove all rules in this chain */
1535 list_for_each_entry_safe(rule, tmp, &chain->rules, list) {
1536 list_del_rcu(&rule->list);
1537
1538 nf_tables_rule_notify(skb, nlh, table, chain, rule,
1539 NFT_MSG_DELRULE, 0, family);
1540 nf_tables_rule_destroy(rule);
1541 }
1542 }
1543
Patrick McHardy96518512013-10-14 11:00:02 +02001544 return 0;
1545}
1546
Patrick McHardy20a69342013-10-11 12:06:22 +02001547/*
1548 * Sets
1549 */
1550
1551static LIST_HEAD(nf_tables_set_ops);
1552
1553int nft_register_set(struct nft_set_ops *ops)
1554{
1555 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1556 list_add_tail(&ops->list, &nf_tables_set_ops);
1557 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1558 return 0;
1559}
1560EXPORT_SYMBOL_GPL(nft_register_set);
1561
1562void nft_unregister_set(struct nft_set_ops *ops)
1563{
1564 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1565 list_del(&ops->list);
1566 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1567}
1568EXPORT_SYMBOL_GPL(nft_unregister_set);
1569
1570static const struct nft_set_ops *nft_select_set_ops(const struct nlattr * const nla[])
1571{
1572 const struct nft_set_ops *ops;
1573 u32 features;
1574
1575#ifdef CONFIG_MODULES
1576 if (list_empty(&nf_tables_set_ops)) {
1577 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1578 request_module("nft-set");
1579 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1580 if (!list_empty(&nf_tables_set_ops))
1581 return ERR_PTR(-EAGAIN);
1582 }
1583#endif
1584 features = 0;
1585 if (nla[NFTA_SET_FLAGS] != NULL) {
1586 features = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
1587 features &= NFT_SET_INTERVAL | NFT_SET_MAP;
1588 }
1589
1590 // FIXME: implement selection properly
1591 list_for_each_entry(ops, &nf_tables_set_ops, list) {
1592 if ((ops->features & features) != features)
1593 continue;
1594 if (!try_module_get(ops->owner))
1595 continue;
1596 return ops;
1597 }
1598
1599 return ERR_PTR(-EOPNOTSUPP);
1600}
1601
1602static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
1603 [NFTA_SET_TABLE] = { .type = NLA_STRING },
1604 [NFTA_SET_NAME] = { .type = NLA_STRING },
1605 [NFTA_SET_FLAGS] = { .type = NLA_U32 },
1606 [NFTA_SET_KEY_TYPE] = { .type = NLA_U32 },
1607 [NFTA_SET_KEY_LEN] = { .type = NLA_U32 },
1608 [NFTA_SET_DATA_TYPE] = { .type = NLA_U32 },
1609 [NFTA_SET_DATA_LEN] = { .type = NLA_U32 },
1610};
1611
1612static int nft_ctx_init_from_setattr(struct nft_ctx *ctx,
1613 const struct sk_buff *skb,
1614 const struct nlmsghdr *nlh,
1615 const struct nlattr * const nla[])
1616{
1617 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1618 const struct nft_af_info *afi;
1619 const struct nft_table *table = NULL;
1620
1621 afi = nf_tables_afinfo_lookup(nfmsg->nfgen_family, false);
1622 if (IS_ERR(afi))
1623 return PTR_ERR(afi);
1624
1625 if (nla[NFTA_SET_TABLE] != NULL) {
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001626 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02001627 if (IS_ERR(table))
1628 return PTR_ERR(table);
1629 }
1630
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001631 nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02001632 return 0;
1633}
1634
1635struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
1636 const struct nlattr *nla)
1637{
1638 struct nft_set *set;
1639
1640 if (nla == NULL)
1641 return ERR_PTR(-EINVAL);
1642
1643 list_for_each_entry(set, &table->sets, list) {
1644 if (!nla_strcmp(nla, set->name))
1645 return set;
1646 }
1647 return ERR_PTR(-ENOENT);
1648}
1649
1650static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
1651 const char *name)
1652{
1653 const struct nft_set *i;
1654 const char *p;
1655 unsigned long *inuse;
1656 unsigned int n = 0;
1657
1658 p = strnchr(name, IFNAMSIZ, '%');
1659 if (p != NULL) {
1660 if (p[1] != 'd' || strchr(p + 2, '%'))
1661 return -EINVAL;
1662
1663 inuse = (unsigned long *)get_zeroed_page(GFP_KERNEL);
1664 if (inuse == NULL)
1665 return -ENOMEM;
1666
1667 list_for_each_entry(i, &ctx->table->sets, list) {
1668 if (!sscanf(i->name, name, &n))
1669 continue;
1670 if (n < 0 || n > BITS_PER_LONG * PAGE_SIZE)
1671 continue;
1672 set_bit(n, inuse);
1673 }
1674
1675 n = find_first_zero_bit(inuse, BITS_PER_LONG * PAGE_SIZE);
1676 free_page((unsigned long)inuse);
1677 }
1678
1679 snprintf(set->name, sizeof(set->name), name, n);
1680 list_for_each_entry(i, &ctx->table->sets, list) {
1681 if (!strcmp(set->name, i->name))
1682 return -ENFILE;
1683 }
1684 return 0;
1685}
1686
1687static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
1688 const struct nft_set *set, u16 event, u16 flags)
1689{
1690 struct nfgenmsg *nfmsg;
1691 struct nlmsghdr *nlh;
1692 u32 portid = NETLINK_CB(ctx->skb).portid;
1693 u32 seq = ctx->nlh->nlmsg_seq;
1694
1695 event |= NFNL_SUBSYS_NFTABLES << 8;
1696 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
1697 flags);
1698 if (nlh == NULL)
1699 goto nla_put_failure;
1700
1701 nfmsg = nlmsg_data(nlh);
1702 nfmsg->nfgen_family = ctx->afi->family;
1703 nfmsg->version = NFNETLINK_V0;
1704 nfmsg->res_id = 0;
1705
1706 if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
1707 goto nla_put_failure;
1708 if (nla_put_string(skb, NFTA_SET_NAME, set->name))
1709 goto nla_put_failure;
1710 if (set->flags != 0)
1711 if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
1712 goto nla_put_failure;
1713
1714 if (nla_put_be32(skb, NFTA_SET_KEY_TYPE, htonl(set->ktype)))
1715 goto nla_put_failure;
1716 if (nla_put_be32(skb, NFTA_SET_KEY_LEN, htonl(set->klen)))
1717 goto nla_put_failure;
1718 if (set->flags & NFT_SET_MAP) {
1719 if (nla_put_be32(skb, NFTA_SET_DATA_TYPE, htonl(set->dtype)))
1720 goto nla_put_failure;
1721 if (nla_put_be32(skb, NFTA_SET_DATA_LEN, htonl(set->dlen)))
1722 goto nla_put_failure;
1723 }
1724
1725 return nlmsg_end(skb, nlh);
1726
1727nla_put_failure:
1728 nlmsg_trim(skb, nlh);
1729 return -1;
1730}
1731
1732static int nf_tables_set_notify(const struct nft_ctx *ctx,
1733 const struct nft_set *set,
1734 int event)
1735{
1736 struct sk_buff *skb;
1737 u32 portid = NETLINK_CB(ctx->skb).portid;
1738 struct net *net = sock_net(ctx->skb->sk);
1739 bool report;
1740 int err;
1741
1742 report = nlmsg_report(ctx->nlh);
1743 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
1744 return 0;
1745
1746 err = -ENOBUFS;
1747 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1748 if (skb == NULL)
1749 goto err;
1750
1751 err = nf_tables_fill_set(skb, ctx, set, event, 0);
1752 if (err < 0) {
1753 kfree_skb(skb);
1754 goto err;
1755 }
1756
1757 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
1758 GFP_KERNEL);
1759err:
1760 if (err < 0)
1761 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
1762 return err;
1763}
1764
1765static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb,
1766 struct netlink_callback *cb)
1767{
1768 const struct nft_set *set;
1769 unsigned int idx = 0, s_idx = cb->args[0];
1770
1771 if (cb->args[1])
1772 return skb->len;
1773
1774 list_for_each_entry(set, &ctx->table->sets, list) {
1775 if (idx < s_idx)
1776 goto cont;
1777 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
1778 NLM_F_MULTI) < 0) {
1779 cb->args[0] = idx;
1780 goto done;
1781 }
1782cont:
1783 idx++;
1784 }
1785 cb->args[1] = 1;
1786done:
1787 return skb->len;
1788}
1789
1790static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb,
1791 struct netlink_callback *cb)
1792{
1793 const struct nft_set *set;
1794 unsigned int idx = 0, s_idx = cb->args[0];
1795 struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
1796
1797 if (cb->args[1])
1798 return skb->len;
1799
1800 list_for_each_entry(table, &ctx->afi->tables, list) {
1801 if (cur_table && cur_table != table)
1802 continue;
1803
1804 ctx->table = table;
1805 list_for_each_entry(set, &ctx->table->sets, list) {
1806 if (idx < s_idx)
1807 goto cont;
1808 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
1809 NLM_F_MULTI) < 0) {
1810 cb->args[0] = idx;
1811 cb->args[2] = (unsigned long) table;
1812 goto done;
1813 }
1814cont:
1815 idx++;
1816 }
1817 }
1818 cb->args[1] = 1;
1819done:
1820 return skb->len;
1821}
1822
1823static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
1824{
1825 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
1826 struct nlattr *nla[NFTA_SET_MAX + 1];
1827 struct nft_ctx ctx;
1828 int err, ret;
1829
1830 err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_MAX,
1831 nft_set_policy);
1832 if (err < 0)
1833 return err;
1834
1835 err = nft_ctx_init_from_setattr(&ctx, cb->skb, cb->nlh, (void *)nla);
1836 if (err < 0)
1837 return err;
1838
1839 if (ctx.table == NULL)
1840 ret = nf_tables_dump_sets_all(&ctx, skb, cb);
1841 else
1842 ret = nf_tables_dump_sets_table(&ctx, skb, cb);
1843
1844 return ret;
1845}
1846
1847static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
1848 const struct nlmsghdr *nlh,
1849 const struct nlattr * const nla[])
1850{
1851 const struct nft_set *set;
1852 struct nft_ctx ctx;
1853 struct sk_buff *skb2;
1854 int err;
1855
1856 /* Verify existance before starting dump */
1857 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
1858 if (err < 0)
1859 return err;
1860
1861 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1862 struct netlink_dump_control c = {
1863 .dump = nf_tables_dump_sets,
1864 };
1865 return netlink_dump_start(nlsk, skb, nlh, &c);
1866 }
1867
1868 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
1869 if (IS_ERR(set))
1870 return PTR_ERR(set);
1871
1872 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1873 if (skb2 == NULL)
1874 return -ENOMEM;
1875
1876 err = nf_tables_fill_set(skb2, &ctx, set, NFT_MSG_NEWSET, 0);
1877 if (err < 0)
1878 goto err;
1879
1880 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
1881
1882err:
1883 kfree_skb(skb2);
1884 return err;
1885}
1886
1887static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
1888 const struct nlmsghdr *nlh,
1889 const struct nlattr * const nla[])
1890{
1891 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1892 const struct nft_set_ops *ops;
1893 const struct nft_af_info *afi;
1894 struct nft_table *table;
1895 struct nft_set *set;
1896 struct nft_ctx ctx;
1897 char name[IFNAMSIZ];
1898 unsigned int size;
1899 bool create;
1900 u32 ktype, klen, dlen, dtype, flags;
1901 int err;
1902
1903 if (nla[NFTA_SET_TABLE] == NULL ||
1904 nla[NFTA_SET_NAME] == NULL ||
1905 nla[NFTA_SET_KEY_LEN] == NULL)
1906 return -EINVAL;
1907
1908 ktype = NFT_DATA_VALUE;
1909 if (nla[NFTA_SET_KEY_TYPE] != NULL) {
1910 ktype = ntohl(nla_get_be32(nla[NFTA_SET_KEY_TYPE]));
1911 if ((ktype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK)
1912 return -EINVAL;
1913 }
1914
1915 klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
1916 if (klen == 0 || klen > FIELD_SIZEOF(struct nft_data, data))
1917 return -EINVAL;
1918
1919 flags = 0;
1920 if (nla[NFTA_SET_FLAGS] != NULL) {
1921 flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
1922 if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
1923 NFT_SET_INTERVAL | NFT_SET_MAP))
1924 return -EINVAL;
1925 }
1926
1927 dtype = 0;
1928 dlen = 0;
1929 if (nla[NFTA_SET_DATA_TYPE] != NULL) {
1930 if (!(flags & NFT_SET_MAP))
1931 return -EINVAL;
1932
1933 dtype = ntohl(nla_get_be32(nla[NFTA_SET_DATA_TYPE]));
1934 if ((dtype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK &&
1935 dtype != NFT_DATA_VERDICT)
1936 return -EINVAL;
1937
1938 if (dtype != NFT_DATA_VERDICT) {
1939 if (nla[NFTA_SET_DATA_LEN] == NULL)
1940 return -EINVAL;
1941 dlen = ntohl(nla_get_be32(nla[NFTA_SET_DATA_LEN]));
1942 if (dlen == 0 ||
1943 dlen > FIELD_SIZEOF(struct nft_data, data))
1944 return -EINVAL;
1945 } else
1946 dlen = sizeof(struct nft_data);
1947 } else if (flags & NFT_SET_MAP)
1948 return -EINVAL;
1949
1950 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
1951
1952 afi = nf_tables_afinfo_lookup(nfmsg->nfgen_family, create);
1953 if (IS_ERR(afi))
1954 return PTR_ERR(afi);
1955
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02001956 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02001957 if (IS_ERR(table))
1958 return PTR_ERR(table);
1959
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02001960 nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02001961
1962 set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME]);
1963 if (IS_ERR(set)) {
1964 if (PTR_ERR(set) != -ENOENT)
1965 return PTR_ERR(set);
1966 set = NULL;
1967 }
1968
1969 if (set != NULL) {
1970 if (nlh->nlmsg_flags & NLM_F_EXCL)
1971 return -EEXIST;
1972 if (nlh->nlmsg_flags & NLM_F_REPLACE)
1973 return -EOPNOTSUPP;
1974 return 0;
1975 }
1976
1977 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
1978 return -ENOENT;
1979
1980 ops = nft_select_set_ops(nla);
1981 if (IS_ERR(ops))
1982 return PTR_ERR(ops);
1983
1984 size = 0;
1985 if (ops->privsize != NULL)
1986 size = ops->privsize(nla);
1987
1988 err = -ENOMEM;
1989 set = kzalloc(sizeof(*set) + size, GFP_KERNEL);
1990 if (set == NULL)
1991 goto err1;
1992
1993 nla_strlcpy(name, nla[NFTA_SET_NAME], sizeof(set->name));
1994 err = nf_tables_set_alloc_name(&ctx, set, name);
1995 if (err < 0)
1996 goto err2;
1997
1998 INIT_LIST_HEAD(&set->bindings);
1999 set->ops = ops;
2000 set->ktype = ktype;
2001 set->klen = klen;
2002 set->dtype = dtype;
2003 set->dlen = dlen;
2004 set->flags = flags;
2005
2006 err = ops->init(set, nla);
2007 if (err < 0)
2008 goto err2;
2009
2010 list_add_tail(&set->list, &table->sets);
2011 nf_tables_set_notify(&ctx, set, NFT_MSG_NEWSET);
2012 return 0;
2013
2014err2:
2015 kfree(set);
2016err1:
2017 module_put(ops->owner);
2018 return err;
2019}
2020
2021static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
2022{
2023 list_del(&set->list);
2024 if (!(set->flags & NFT_SET_ANONYMOUS))
2025 nf_tables_set_notify(ctx, set, NFT_MSG_DELSET);
2026
2027 set->ops->destroy(set);
2028 module_put(set->ops->owner);
2029 kfree(set);
2030}
2031
2032static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
2033 const struct nlmsghdr *nlh,
2034 const struct nlattr * const nla[])
2035{
2036 struct nft_set *set;
2037 struct nft_ctx ctx;
2038 int err;
2039
2040 if (nla[NFTA_SET_TABLE] == NULL)
2041 return -EINVAL;
2042
2043 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
2044 if (err < 0)
2045 return err;
2046
2047 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
2048 if (IS_ERR(set))
2049 return PTR_ERR(set);
2050 if (!list_empty(&set->bindings))
2051 return -EBUSY;
2052
2053 nf_tables_set_destroy(&ctx, set);
2054 return 0;
2055}
2056
2057static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
2058 const struct nft_set *set,
2059 const struct nft_set_iter *iter,
2060 const struct nft_set_elem *elem)
2061{
2062 enum nft_registers dreg;
2063
2064 dreg = nft_type_to_reg(set->dtype);
2065 return nft_validate_data_load(ctx, dreg, &elem->data, set->dtype);
2066}
2067
2068int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
2069 struct nft_set_binding *binding)
2070{
2071 struct nft_set_binding *i;
2072 struct nft_set_iter iter;
2073
2074 if (!list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
2075 return -EBUSY;
2076
2077 if (set->flags & NFT_SET_MAP) {
2078 /* If the set is already bound to the same chain all
2079 * jumps are already validated for that chain.
2080 */
2081 list_for_each_entry(i, &set->bindings, list) {
2082 if (i->chain == binding->chain)
2083 goto bind;
2084 }
2085
2086 iter.skip = 0;
2087 iter.count = 0;
2088 iter.err = 0;
2089 iter.fn = nf_tables_bind_check_setelem;
2090
2091 set->ops->walk(ctx, set, &iter);
2092 if (iter.err < 0) {
2093 /* Destroy anonymous sets if binding fails */
2094 if (set->flags & NFT_SET_ANONYMOUS)
2095 nf_tables_set_destroy(ctx, set);
2096
2097 return iter.err;
2098 }
2099 }
2100bind:
2101 binding->chain = ctx->chain;
2102 list_add_tail(&binding->list, &set->bindings);
2103 return 0;
2104}
2105
2106void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
2107 struct nft_set_binding *binding)
2108{
2109 list_del(&binding->list);
2110
2111 if (list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
2112 nf_tables_set_destroy(ctx, set);
2113}
2114
2115/*
2116 * Set elements
2117 */
2118
2119static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
2120 [NFTA_SET_ELEM_KEY] = { .type = NLA_NESTED },
2121 [NFTA_SET_ELEM_DATA] = { .type = NLA_NESTED },
2122 [NFTA_SET_ELEM_FLAGS] = { .type = NLA_U32 },
2123};
2124
2125static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
2126 [NFTA_SET_ELEM_LIST_TABLE] = { .type = NLA_STRING },
2127 [NFTA_SET_ELEM_LIST_SET] = { .type = NLA_STRING },
2128 [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NLA_NESTED },
2129};
2130
2131static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx,
2132 const struct sk_buff *skb,
2133 const struct nlmsghdr *nlh,
2134 const struct nlattr * const nla[])
2135{
2136 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
2137 const struct nft_af_info *afi;
2138 const struct nft_table *table;
2139
2140 afi = nf_tables_afinfo_lookup(nfmsg->nfgen_family, false);
2141 if (IS_ERR(afi))
2142 return PTR_ERR(afi);
2143
Pablo Neira Ayuso93707612013-10-10 23:21:26 +02002144 table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE]);
Patrick McHardy20a69342013-10-11 12:06:22 +02002145 if (IS_ERR(table))
2146 return PTR_ERR(table);
2147
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002148 nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
Patrick McHardy20a69342013-10-11 12:06:22 +02002149 return 0;
2150}
2151
2152static int nf_tables_fill_setelem(struct sk_buff *skb,
2153 const struct nft_set *set,
2154 const struct nft_set_elem *elem)
2155{
2156 unsigned char *b = skb_tail_pointer(skb);
2157 struct nlattr *nest;
2158
2159 nest = nla_nest_start(skb, NFTA_LIST_ELEM);
2160 if (nest == NULL)
2161 goto nla_put_failure;
2162
2163 if (nft_data_dump(skb, NFTA_SET_ELEM_KEY, &elem->key, NFT_DATA_VALUE,
2164 set->klen) < 0)
2165 goto nla_put_failure;
2166
2167 if (set->flags & NFT_SET_MAP &&
2168 !(elem->flags & NFT_SET_ELEM_INTERVAL_END) &&
2169 nft_data_dump(skb, NFTA_SET_ELEM_DATA, &elem->data,
2170 set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE,
2171 set->dlen) < 0)
2172 goto nla_put_failure;
2173
2174 if (elem->flags != 0)
2175 if (nla_put_be32(skb, NFTA_SET_ELEM_FLAGS, htonl(elem->flags)))
2176 goto nla_put_failure;
2177
2178 nla_nest_end(skb, nest);
2179 return 0;
2180
2181nla_put_failure:
2182 nlmsg_trim(skb, b);
2183 return -EMSGSIZE;
2184}
2185
2186struct nft_set_dump_args {
2187 const struct netlink_callback *cb;
2188 struct nft_set_iter iter;
2189 struct sk_buff *skb;
2190};
2191
2192static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
2193 const struct nft_set *set,
2194 const struct nft_set_iter *iter,
2195 const struct nft_set_elem *elem)
2196{
2197 struct nft_set_dump_args *args;
2198
2199 args = container_of(iter, struct nft_set_dump_args, iter);
2200 return nf_tables_fill_setelem(args->skb, set, elem);
2201}
2202
2203static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
2204{
2205 const struct nft_set *set;
2206 struct nft_set_dump_args args;
2207 struct nft_ctx ctx;
2208 struct nlattr *nla[NFTA_SET_ELEM_LIST_MAX + 1];
2209 struct nfgenmsg *nfmsg;
2210 struct nlmsghdr *nlh;
2211 struct nlattr *nest;
2212 u32 portid, seq;
2213 int event, err;
2214
2215 nfmsg = nlmsg_data(cb->nlh);
2216 err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_ELEM_LIST_MAX,
2217 nft_set_elem_list_policy);
2218 if (err < 0)
2219 return err;
2220
2221 err = nft_ctx_init_from_elemattr(&ctx, cb->skb, cb->nlh, (void *)nla);
2222 if (err < 0)
2223 return err;
2224
2225 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2226 if (IS_ERR(set))
2227 return PTR_ERR(set);
2228
2229 event = NFT_MSG_NEWSETELEM;
2230 event |= NFNL_SUBSYS_NFTABLES << 8;
2231 portid = NETLINK_CB(cb->skb).portid;
2232 seq = cb->nlh->nlmsg_seq;
2233
2234 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
2235 NLM_F_MULTI);
2236 if (nlh == NULL)
2237 goto nla_put_failure;
2238
2239 nfmsg = nlmsg_data(nlh);
2240 nfmsg->nfgen_family = NFPROTO_UNSPEC;
2241 nfmsg->version = NFNETLINK_V0;
2242 nfmsg->res_id = 0;
2243
2244 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, ctx.table->name))
2245 goto nla_put_failure;
2246 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_SET, set->name))
2247 goto nla_put_failure;
2248
2249 nest = nla_nest_start(skb, NFTA_SET_ELEM_LIST_ELEMENTS);
2250 if (nest == NULL)
2251 goto nla_put_failure;
2252
2253 args.cb = cb;
2254 args.skb = skb;
2255 args.iter.skip = cb->args[0];
2256 args.iter.count = 0;
2257 args.iter.err = 0;
2258 args.iter.fn = nf_tables_dump_setelem;
2259 set->ops->walk(&ctx, set, &args.iter);
2260
2261 nla_nest_end(skb, nest);
2262 nlmsg_end(skb, nlh);
2263
2264 if (args.iter.err && args.iter.err != -EMSGSIZE)
2265 return args.iter.err;
2266 if (args.iter.count == cb->args[0])
2267 return 0;
2268
2269 cb->args[0] = args.iter.count;
2270 return skb->len;
2271
2272nla_put_failure:
2273 return -ENOSPC;
2274}
2275
2276static int nf_tables_getsetelem(struct sock *nlsk, struct sk_buff *skb,
2277 const struct nlmsghdr *nlh,
2278 const struct nlattr * const nla[])
2279{
2280 const struct nft_set *set;
2281 struct nft_ctx ctx;
2282 int err;
2283
2284 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2285 if (err < 0)
2286 return err;
2287
2288 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2289 if (IS_ERR(set))
2290 return PTR_ERR(set);
2291
2292 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2293 struct netlink_dump_control c = {
2294 .dump = nf_tables_dump_set,
2295 };
2296 return netlink_dump_start(nlsk, skb, nlh, &c);
2297 }
2298 return -EOPNOTSUPP;
2299}
2300
2301static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set,
2302 const struct nlattr *attr)
2303{
2304 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
2305 struct nft_data_desc d1, d2;
2306 struct nft_set_elem elem;
2307 struct nft_set_binding *binding;
2308 enum nft_registers dreg;
2309 int err;
2310
2311 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
2312 nft_set_elem_policy);
2313 if (err < 0)
2314 return err;
2315
2316 if (nla[NFTA_SET_ELEM_KEY] == NULL)
2317 return -EINVAL;
2318
2319 elem.flags = 0;
2320 if (nla[NFTA_SET_ELEM_FLAGS] != NULL) {
2321 elem.flags = ntohl(nla_get_be32(nla[NFTA_SET_ELEM_FLAGS]));
2322 if (elem.flags & ~NFT_SET_ELEM_INTERVAL_END)
2323 return -EINVAL;
2324 }
2325
2326 if (set->flags & NFT_SET_MAP) {
2327 if (nla[NFTA_SET_ELEM_DATA] == NULL &&
2328 !(elem.flags & NFT_SET_ELEM_INTERVAL_END))
2329 return -EINVAL;
2330 } else {
2331 if (nla[NFTA_SET_ELEM_DATA] != NULL)
2332 return -EINVAL;
2333 }
2334
2335 err = nft_data_init(ctx, &elem.key, &d1, nla[NFTA_SET_ELEM_KEY]);
2336 if (err < 0)
2337 goto err1;
2338 err = -EINVAL;
2339 if (d1.type != NFT_DATA_VALUE || d1.len != set->klen)
2340 goto err2;
2341
2342 err = -EEXIST;
2343 if (set->ops->get(set, &elem) == 0)
2344 goto err2;
2345
2346 if (nla[NFTA_SET_ELEM_DATA] != NULL) {
2347 err = nft_data_init(ctx, &elem.data, &d2, nla[NFTA_SET_ELEM_DATA]);
2348 if (err < 0)
2349 goto err2;
2350
2351 err = -EINVAL;
2352 if (set->dtype != NFT_DATA_VERDICT && d2.len != set->dlen)
2353 goto err3;
2354
2355 dreg = nft_type_to_reg(set->dtype);
2356 list_for_each_entry(binding, &set->bindings, list) {
2357 struct nft_ctx bind_ctx = {
2358 .afi = ctx->afi,
2359 .table = ctx->table,
2360 .chain = binding->chain,
2361 };
2362
2363 err = nft_validate_data_load(&bind_ctx, dreg,
2364 &elem.data, d2.type);
2365 if (err < 0)
2366 goto err3;
2367 }
2368 }
2369
2370 err = set->ops->insert(set, &elem);
2371 if (err < 0)
2372 goto err3;
2373
2374 return 0;
2375
2376err3:
2377 if (nla[NFTA_SET_ELEM_DATA] != NULL)
2378 nft_data_uninit(&elem.data, d2.type);
2379err2:
2380 nft_data_uninit(&elem.key, d1.type);
2381err1:
2382 return err;
2383}
2384
2385static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
2386 const struct nlmsghdr *nlh,
2387 const struct nlattr * const nla[])
2388{
2389 const struct nlattr *attr;
2390 struct nft_set *set;
2391 struct nft_ctx ctx;
2392 int rem, err;
2393
2394 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2395 if (err < 0)
2396 return err;
2397
2398 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2399 if (IS_ERR(set))
2400 return PTR_ERR(set);
2401 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
2402 return -EBUSY;
2403
2404 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
2405 err = nft_add_set_elem(&ctx, set, attr);
2406 if (err < 0)
2407 return err;
2408 }
2409 return 0;
2410}
2411
2412static int nft_del_setelem(const struct nft_ctx *ctx, struct nft_set *set,
2413 const struct nlattr *attr)
2414{
2415 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
2416 struct nft_data_desc desc;
2417 struct nft_set_elem elem;
2418 int err;
2419
2420 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
2421 nft_set_elem_policy);
2422 if (err < 0)
2423 goto err1;
2424
2425 err = -EINVAL;
2426 if (nla[NFTA_SET_ELEM_KEY] == NULL)
2427 goto err1;
2428
2429 err = nft_data_init(ctx, &elem.key, &desc, nla[NFTA_SET_ELEM_KEY]);
2430 if (err < 0)
2431 goto err1;
2432
2433 err = -EINVAL;
2434 if (desc.type != NFT_DATA_VALUE || desc.len != set->klen)
2435 goto err2;
2436
2437 err = set->ops->get(set, &elem);
2438 if (err < 0)
2439 goto err2;
2440
2441 set->ops->remove(set, &elem);
2442
2443 nft_data_uninit(&elem.key, NFT_DATA_VALUE);
2444 if (set->flags & NFT_SET_MAP)
2445 nft_data_uninit(&elem.data, set->dtype);
2446
2447err2:
2448 nft_data_uninit(&elem.key, desc.type);
2449err1:
2450 return err;
2451}
2452
2453static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
2454 const struct nlmsghdr *nlh,
2455 const struct nlattr * const nla[])
2456{
2457 const struct nlattr *attr;
2458 struct nft_set *set;
2459 struct nft_ctx ctx;
2460 int rem, err;
2461
2462 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2463 if (err < 0)
2464 return err;
2465
2466 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2467 if (IS_ERR(set))
2468 return PTR_ERR(set);
2469 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
2470 return -EBUSY;
2471
2472 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
2473 err = nft_del_setelem(&ctx, set, attr);
2474 if (err < 0)
2475 return err;
2476 }
2477 return 0;
2478}
2479
Patrick McHardy96518512013-10-14 11:00:02 +02002480static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
2481 [NFT_MSG_NEWTABLE] = {
2482 .call = nf_tables_newtable,
2483 .attr_count = NFTA_TABLE_MAX,
2484 .policy = nft_table_policy,
2485 },
2486 [NFT_MSG_GETTABLE] = {
2487 .call = nf_tables_gettable,
2488 .attr_count = NFTA_TABLE_MAX,
2489 .policy = nft_table_policy,
2490 },
2491 [NFT_MSG_DELTABLE] = {
2492 .call = nf_tables_deltable,
2493 .attr_count = NFTA_TABLE_MAX,
2494 .policy = nft_table_policy,
2495 },
2496 [NFT_MSG_NEWCHAIN] = {
2497 .call = nf_tables_newchain,
2498 .attr_count = NFTA_CHAIN_MAX,
2499 .policy = nft_chain_policy,
2500 },
2501 [NFT_MSG_GETCHAIN] = {
2502 .call = nf_tables_getchain,
2503 .attr_count = NFTA_CHAIN_MAX,
2504 .policy = nft_chain_policy,
2505 },
2506 [NFT_MSG_DELCHAIN] = {
2507 .call = nf_tables_delchain,
2508 .attr_count = NFTA_CHAIN_MAX,
2509 .policy = nft_chain_policy,
2510 },
2511 [NFT_MSG_NEWRULE] = {
2512 .call = nf_tables_newrule,
2513 .attr_count = NFTA_RULE_MAX,
2514 .policy = nft_rule_policy,
2515 },
2516 [NFT_MSG_GETRULE] = {
2517 .call = nf_tables_getrule,
2518 .attr_count = NFTA_RULE_MAX,
2519 .policy = nft_rule_policy,
2520 },
2521 [NFT_MSG_DELRULE] = {
2522 .call = nf_tables_delrule,
2523 .attr_count = NFTA_RULE_MAX,
2524 .policy = nft_rule_policy,
2525 },
Patrick McHardy20a69342013-10-11 12:06:22 +02002526 [NFT_MSG_NEWSET] = {
2527 .call = nf_tables_newset,
2528 .attr_count = NFTA_SET_MAX,
2529 .policy = nft_set_policy,
2530 },
2531 [NFT_MSG_GETSET] = {
2532 .call = nf_tables_getset,
2533 .attr_count = NFTA_SET_MAX,
2534 .policy = nft_set_policy,
2535 },
2536 [NFT_MSG_DELSET] = {
2537 .call = nf_tables_delset,
2538 .attr_count = NFTA_SET_MAX,
2539 .policy = nft_set_policy,
2540 },
2541 [NFT_MSG_NEWSETELEM] = {
2542 .call = nf_tables_newsetelem,
2543 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2544 .policy = nft_set_elem_list_policy,
2545 },
2546 [NFT_MSG_GETSETELEM] = {
2547 .call = nf_tables_getsetelem,
2548 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2549 .policy = nft_set_elem_list_policy,
2550 },
2551 [NFT_MSG_DELSETELEM] = {
2552 .call = nf_tables_delsetelem,
2553 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2554 .policy = nft_set_elem_list_policy,
2555 },
Patrick McHardy96518512013-10-14 11:00:02 +02002556};
2557
2558static const struct nfnetlink_subsystem nf_tables_subsys = {
2559 .name = "nf_tables",
2560 .subsys_id = NFNL_SUBSYS_NFTABLES,
2561 .cb_count = NFT_MSG_MAX,
2562 .cb = nf_tables_cb,
2563};
2564
Patrick McHardy20a69342013-10-11 12:06:22 +02002565/*
2566 * Loop detection - walk through the ruleset beginning at the destination chain
2567 * of a new jump until either the source chain is reached (loop) or all
2568 * reachable chains have been traversed.
2569 *
2570 * The loop check is performed whenever a new jump verdict is added to an
2571 * expression or verdict map or a verdict map is bound to a new chain.
2572 */
2573
2574static int nf_tables_check_loops(const struct nft_ctx *ctx,
2575 const struct nft_chain *chain);
2576
2577static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
2578 const struct nft_set *set,
2579 const struct nft_set_iter *iter,
2580 const struct nft_set_elem *elem)
2581{
2582 switch (elem->data.verdict) {
2583 case NFT_JUMP:
2584 case NFT_GOTO:
2585 return nf_tables_check_loops(ctx, elem->data.chain);
2586 default:
2587 return 0;
2588 }
2589}
2590
2591static int nf_tables_check_loops(const struct nft_ctx *ctx,
2592 const struct nft_chain *chain)
2593{
2594 const struct nft_rule *rule;
2595 const struct nft_expr *expr, *last;
Patrick McHardy20a69342013-10-11 12:06:22 +02002596 const struct nft_set *set;
2597 struct nft_set_binding *binding;
2598 struct nft_set_iter iter;
Patrick McHardy20a69342013-10-11 12:06:22 +02002599
2600 if (ctx->chain == chain)
2601 return -ELOOP;
2602
2603 list_for_each_entry(rule, &chain->rules, list) {
2604 nft_rule_for_each_expr(expr, last, rule) {
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002605 const struct nft_data *data = NULL;
2606 int err;
2607
2608 if (!expr->ops->validate)
Patrick McHardy20a69342013-10-11 12:06:22 +02002609 continue;
2610
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002611 err = expr->ops->validate(ctx, expr, &data);
2612 if (err < 0)
2613 return err;
2614
Patrick McHardy20a69342013-10-11 12:06:22 +02002615 if (data == NULL)
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +02002616 continue;
Patrick McHardy20a69342013-10-11 12:06:22 +02002617
2618 switch (data->verdict) {
2619 case NFT_JUMP:
2620 case NFT_GOTO:
2621 err = nf_tables_check_loops(ctx, data->chain);
2622 if (err < 0)
2623 return err;
2624 default:
2625 break;
2626 }
2627 }
2628 }
2629
2630 list_for_each_entry(set, &ctx->table->sets, list) {
2631 if (!(set->flags & NFT_SET_MAP) ||
2632 set->dtype != NFT_DATA_VERDICT)
2633 continue;
2634
2635 list_for_each_entry(binding, &set->bindings, list) {
2636 if (binding->chain != chain)
2637 continue;
2638
2639 iter.skip = 0;
2640 iter.count = 0;
2641 iter.err = 0;
2642 iter.fn = nf_tables_loop_check_setelem;
2643
2644 set->ops->walk(ctx, set, &iter);
2645 if (iter.err < 0)
2646 return iter.err;
2647 }
2648 }
2649
2650 return 0;
2651}
2652
Patrick McHardy96518512013-10-14 11:00:02 +02002653/**
2654 * nft_validate_input_register - validate an expressions' input register
2655 *
2656 * @reg: the register number
2657 *
2658 * Validate that the input register is one of the general purpose
2659 * registers.
2660 */
2661int nft_validate_input_register(enum nft_registers reg)
2662{
2663 if (reg <= NFT_REG_VERDICT)
2664 return -EINVAL;
2665 if (reg > NFT_REG_MAX)
2666 return -ERANGE;
2667 return 0;
2668}
2669EXPORT_SYMBOL_GPL(nft_validate_input_register);
2670
2671/**
2672 * nft_validate_output_register - validate an expressions' output register
2673 *
2674 * @reg: the register number
2675 *
2676 * Validate that the output register is one of the general purpose
2677 * registers or the verdict register.
2678 */
2679int nft_validate_output_register(enum nft_registers reg)
2680{
2681 if (reg < NFT_REG_VERDICT)
2682 return -EINVAL;
2683 if (reg > NFT_REG_MAX)
2684 return -ERANGE;
2685 return 0;
2686}
2687EXPORT_SYMBOL_GPL(nft_validate_output_register);
2688
2689/**
2690 * nft_validate_data_load - validate an expressions' data load
2691 *
2692 * @ctx: context of the expression performing the load
2693 * @reg: the destination register number
2694 * @data: the data to load
2695 * @type: the data type
2696 *
2697 * Validate that a data load uses the appropriate data type for
2698 * the destination register. A value of NULL for the data means
2699 * that its runtime gathered data, which is always of type
2700 * NFT_DATA_VALUE.
2701 */
2702int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
2703 const struct nft_data *data,
2704 enum nft_data_types type)
2705{
Patrick McHardy20a69342013-10-11 12:06:22 +02002706 int err;
2707
Patrick McHardy96518512013-10-14 11:00:02 +02002708 switch (reg) {
2709 case NFT_REG_VERDICT:
2710 if (data == NULL || type != NFT_DATA_VERDICT)
2711 return -EINVAL;
Patrick McHardy20a69342013-10-11 12:06:22 +02002712
2713 if (data->verdict == NFT_GOTO || data->verdict == NFT_JUMP) {
2714 err = nf_tables_check_loops(ctx, data->chain);
2715 if (err < 0)
2716 return err;
2717
2718 if (ctx->chain->level + 1 > data->chain->level) {
2719 if (ctx->chain->level + 1 == NFT_JUMP_STACK_SIZE)
2720 return -EMLINK;
2721 data->chain->level = ctx->chain->level + 1;
2722 }
2723 }
2724
Patrick McHardy96518512013-10-14 11:00:02 +02002725 return 0;
2726 default:
2727 if (data != NULL && type != NFT_DATA_VALUE)
2728 return -EINVAL;
2729 return 0;
2730 }
2731}
2732EXPORT_SYMBOL_GPL(nft_validate_data_load);
2733
2734static const struct nla_policy nft_verdict_policy[NFTA_VERDICT_MAX + 1] = {
2735 [NFTA_VERDICT_CODE] = { .type = NLA_U32 },
2736 [NFTA_VERDICT_CHAIN] = { .type = NLA_STRING,
2737 .len = NFT_CHAIN_MAXNAMELEN - 1 },
2738};
2739
2740static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
2741 struct nft_data_desc *desc, const struct nlattr *nla)
2742{
2743 struct nlattr *tb[NFTA_VERDICT_MAX + 1];
2744 struct nft_chain *chain;
2745 int err;
2746
2747 err = nla_parse_nested(tb, NFTA_VERDICT_MAX, nla, nft_verdict_policy);
2748 if (err < 0)
2749 return err;
2750
2751 if (!tb[NFTA_VERDICT_CODE])
2752 return -EINVAL;
2753 data->verdict = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE]));
2754
2755 switch (data->verdict) {
2756 case NF_ACCEPT:
2757 case NF_DROP:
2758 case NF_QUEUE:
2759 case NFT_CONTINUE:
2760 case NFT_BREAK:
2761 case NFT_RETURN:
2762 desc->len = sizeof(data->verdict);
2763 break;
2764 case NFT_JUMP:
2765 case NFT_GOTO:
2766 if (!tb[NFTA_VERDICT_CHAIN])
2767 return -EINVAL;
2768 chain = nf_tables_chain_lookup(ctx->table,
2769 tb[NFTA_VERDICT_CHAIN]);
2770 if (IS_ERR(chain))
2771 return PTR_ERR(chain);
2772 if (chain->flags & NFT_BASE_CHAIN)
2773 return -EOPNOTSUPP;
2774
Patrick McHardy96518512013-10-14 11:00:02 +02002775 chain->use++;
2776 data->chain = chain;
2777 desc->len = sizeof(data);
2778 break;
2779 default:
2780 return -EINVAL;
2781 }
2782
2783 desc->type = NFT_DATA_VERDICT;
2784 return 0;
2785}
2786
2787static void nft_verdict_uninit(const struct nft_data *data)
2788{
2789 switch (data->verdict) {
2790 case NFT_JUMP:
2791 case NFT_GOTO:
2792 data->chain->use--;
2793 break;
2794 }
2795}
2796
2797static int nft_verdict_dump(struct sk_buff *skb, const struct nft_data *data)
2798{
2799 struct nlattr *nest;
2800
2801 nest = nla_nest_start(skb, NFTA_DATA_VERDICT);
2802 if (!nest)
2803 goto nla_put_failure;
2804
2805 if (nla_put_be32(skb, NFTA_VERDICT_CODE, htonl(data->verdict)))
2806 goto nla_put_failure;
2807
2808 switch (data->verdict) {
2809 case NFT_JUMP:
2810 case NFT_GOTO:
2811 if (nla_put_string(skb, NFTA_VERDICT_CHAIN, data->chain->name))
2812 goto nla_put_failure;
2813 }
2814 nla_nest_end(skb, nest);
2815 return 0;
2816
2817nla_put_failure:
2818 return -1;
2819}
2820
2821static int nft_value_init(const struct nft_ctx *ctx, struct nft_data *data,
2822 struct nft_data_desc *desc, const struct nlattr *nla)
2823{
2824 unsigned int len;
2825
2826 len = nla_len(nla);
2827 if (len == 0)
2828 return -EINVAL;
2829 if (len > sizeof(data->data))
2830 return -EOVERFLOW;
2831
2832 nla_memcpy(data->data, nla, sizeof(data->data));
2833 desc->type = NFT_DATA_VALUE;
2834 desc->len = len;
2835 return 0;
2836}
2837
2838static int nft_value_dump(struct sk_buff *skb, const struct nft_data *data,
2839 unsigned int len)
2840{
2841 return nla_put(skb, NFTA_DATA_VALUE, len, data->data);
2842}
2843
2844static const struct nla_policy nft_data_policy[NFTA_DATA_MAX + 1] = {
2845 [NFTA_DATA_VALUE] = { .type = NLA_BINARY,
2846 .len = FIELD_SIZEOF(struct nft_data, data) },
2847 [NFTA_DATA_VERDICT] = { .type = NLA_NESTED },
2848};
2849
2850/**
2851 * nft_data_init - parse nf_tables data netlink attributes
2852 *
2853 * @ctx: context of the expression using the data
2854 * @data: destination struct nft_data
2855 * @desc: data description
2856 * @nla: netlink attribute containing data
2857 *
2858 * Parse the netlink data attributes and initialize a struct nft_data.
2859 * The type and length of data are returned in the data description.
2860 *
2861 * The caller can indicate that it only wants to accept data of type
2862 * NFT_DATA_VALUE by passing NULL for the ctx argument.
2863 */
2864int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data,
2865 struct nft_data_desc *desc, const struct nlattr *nla)
2866{
2867 struct nlattr *tb[NFTA_DATA_MAX + 1];
2868 int err;
2869
2870 err = nla_parse_nested(tb, NFTA_DATA_MAX, nla, nft_data_policy);
2871 if (err < 0)
2872 return err;
2873
2874 if (tb[NFTA_DATA_VALUE])
2875 return nft_value_init(ctx, data, desc, tb[NFTA_DATA_VALUE]);
2876 if (tb[NFTA_DATA_VERDICT] && ctx != NULL)
2877 return nft_verdict_init(ctx, data, desc, tb[NFTA_DATA_VERDICT]);
2878 return -EINVAL;
2879}
2880EXPORT_SYMBOL_GPL(nft_data_init);
2881
2882/**
2883 * nft_data_uninit - release a nft_data item
2884 *
2885 * @data: struct nft_data to release
2886 * @type: type of data
2887 *
2888 * Release a nft_data item. NFT_DATA_VALUE types can be silently discarded,
2889 * all others need to be released by calling this function.
2890 */
2891void nft_data_uninit(const struct nft_data *data, enum nft_data_types type)
2892{
2893 switch (type) {
2894 case NFT_DATA_VALUE:
2895 return;
2896 case NFT_DATA_VERDICT:
2897 return nft_verdict_uninit(data);
2898 default:
2899 WARN_ON(1);
2900 }
2901}
2902EXPORT_SYMBOL_GPL(nft_data_uninit);
2903
2904int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
2905 enum nft_data_types type, unsigned int len)
2906{
2907 struct nlattr *nest;
2908 int err;
2909
2910 nest = nla_nest_start(skb, attr);
2911 if (nest == NULL)
2912 return -1;
2913
2914 switch (type) {
2915 case NFT_DATA_VALUE:
2916 err = nft_value_dump(skb, data, len);
2917 break;
2918 case NFT_DATA_VERDICT:
2919 err = nft_verdict_dump(skb, data);
2920 break;
2921 default:
2922 err = -EINVAL;
2923 WARN_ON(1);
2924 }
2925
2926 nla_nest_end(skb, nest);
2927 return err;
2928}
2929EXPORT_SYMBOL_GPL(nft_data_dump);
2930
2931static int __init nf_tables_module_init(void)
2932{
2933 int err;
2934
2935 info = kmalloc(sizeof(struct nft_expr_info) * NFT_RULE_MAXEXPRS,
2936 GFP_KERNEL);
2937 if (info == NULL) {
2938 err = -ENOMEM;
2939 goto err1;
2940 }
2941
2942 err = nf_tables_core_module_init();
2943 if (err < 0)
2944 goto err2;
2945
2946 err = nfnetlink_subsys_register(&nf_tables_subsys);
2947 if (err < 0)
2948 goto err3;
2949
2950 pr_info("nf_tables: (c) 2007-2009 Patrick McHardy <kaber@trash.net>\n");
2951 return 0;
2952err3:
2953 nf_tables_core_module_exit();
2954err2:
2955 kfree(info);
2956err1:
2957 return err;
2958}
2959
2960static void __exit nf_tables_module_exit(void)
2961{
2962 nfnetlink_subsys_unregister(&nf_tables_subsys);
2963 nf_tables_core_module_exit();
2964 kfree(info);
2965}
2966
2967module_init(nf_tables_module_init);
2968module_exit(nf_tables_module_exit);
2969
2970MODULE_LICENSE("GPL");
2971MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
2972MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFTABLES);