aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2013-10-14 05:00:02 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2013-10-14 11:15:48 -0400
commit96518518cc417bb0a8c80b9fb736202e28acdf96 (patch)
tree2ac4f939a88f0a8047403d0e07b5167369236f82 /net/netfilter
parentf59cb0453cd885736daa11ae2445982c5ab2fc83 (diff)
netfilter: add nftables
This patch adds nftables which is the intended successor of iptables. This packet filtering framework reuses the existing netfilter hooks, the connection tracking system, the NAT subsystem, the transparent proxying engine, the logging infrastructure and the userspace packet queueing facilities. In a nutshell, nftables provides a pseudo-state machine with 4 general purpose registers of 128 bits and 1 specific purpose register to store verdicts. This pseudo-machine comes with an extensible instruction set, a.k.a. "expressions" in the nftables jargon. The expressions included in this patch provide the basic functionality, they are: * bitwise: to perform bitwise operations. * byteorder: to change from host/network endianess. * cmp: to compare data with the content of the registers. * counter: to enable counters on rules. * ct: to store conntrack keys into register. * exthdr: to match IPv6 extension headers. * immediate: to load data into registers. * limit: to limit matching based on packet rate. * log: to log packets. * meta: to match metainformation that usually comes with the skbuff. * nat: to perform Network Address Translation. * payload: to fetch data from the packet payload and store it into registers. * reject (IPv4 only): to explicitly close connection, eg. TCP RST. Using this instruction-set, the userspace utility 'nft' can transform the rules expressed in human-readable text representation (using a new syntax, inspired by tcpdump) to nftables bytecode. nftables also inherits the table, chain and rule objects from iptables, but in a more configurable way, and it also includes the original datatype-agnostic set infrastructure with mapping support. This set infrastructure is enhanced in the follow up patch (netfilter: nf_tables: add netlink set API). This patch includes the following components: * the netlink API: net/netfilter/nf_tables_api.c and include/uapi/netfilter/nf_tables.h * the packet filter core: net/netfilter/nf_tables_core.c * the expressions (described above): net/netfilter/nft_*.c * the filter tables: arp, IPv4, IPv6 and bridge: net/ipv4/netfilter/nf_tables_ipv4.c net/ipv6/netfilter/nf_tables_ipv6.c net/ipv4/netfilter/nf_tables_arp.c net/bridge/netfilter/nf_tables_bridge.c * the NAT table (IPv4 only): net/ipv4/netfilter/nf_table_nat_ipv4.c * the route table (similar to mangle): net/ipv4/netfilter/nf_table_route_ipv4.c net/ipv6/netfilter/nf_table_route_ipv6.c * internal definitions under: include/net/netfilter/nf_tables.h include/net/netfilter/nf_tables_core.h * It also includes an skeleton expression: net/netfilter/nft_expr_template.c and the preliminary implementation of the meta target net/netfilter/nft_meta_target.c It also includes a change in struct nf_hook_ops to add a new pointer to store private data to the hook, that is used to store the rule list per chain. This patch is based on the patch from Patrick McHardy, plus merged accumulated cleanups, fixes and small enhancements to the nftables code that has been done since 2009, which are: From Patrick McHardy: * nf_tables: adjust netlink handler function signatures * nf_tables: only retry table lookup after successful table module load * nf_tables: fix event notification echo and avoid unnecessary messages * nft_ct: add l3proto support * nf_tables: pass expression context to nft_validate_data_load() * nf_tables: remove redundant definition * nft_ct: fix maxattr initialization * nf_tables: fix invalid event type in nf_tables_getrule() * nf_tables: simplify nft_data_init() usage * nf_tables: build in more core modules * nf_tables: fix double lookup expression unregistation * nf_tables: move expression initialization to nf_tables_core.c * nf_tables: build in payload module * nf_tables: use NFPROTO constants * nf_tables: rename pid variables to portid * nf_tables: save 48 bits per rule * nf_tables: introduce chain rename * nf_tables: check for duplicate names on chain rename * nf_tables: remove ability to specify handles for new rules * nf_tables: return error for rule change request * nf_tables: return error for NLM_F_REPLACE without rule handle * nf_tables: include NLM_F_APPEND/NLM_F_REPLACE flags in rule notification * nf_tables: fix NLM_F_MULTI usage in netlink notifications * nf_tables: include NLM_F_APPEND in rule dumps From Pablo Neira Ayuso: * nf_tables: fix stack overflow in nf_tables_newrule * nf_tables: nft_ct: fix compilation warning * nf_tables: nft_ct: fix crash with invalid packets * nft_log: group and qthreshold are 2^16 * nf_tables: nft_meta: fix socket uid,gid handling * nft_counter: allow to restore counters * nf_tables: fix module autoload * nf_tables: allow to remove all rules placed in one chain * nf_tables: use 64-bits rule handle instead of 16-bits * nf_tables: fix chain after rule deletion * nf_tables: improve deletion performance * nf_tables: add missing code in route chain type * nf_tables: rise maximum number of expressions from 12 to 128 * nf_tables: don't delete table if in use * nf_tables: fix basechain release From Tomasz Bursztyka: * nf_tables: Add support for changing users chain's name * nf_tables: Change chain's name to be fixed sized * nf_tables: Add support for replacing a rule by another one * nf_tables: Update uapi nftables netlink header documentation From Florian Westphal: * nft_log: group is u16, snaplen u32 From Phil Oester: * nf_tables: operational limit match Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/Kconfig37
-rw-r--r--net/netfilter/Makefile16
-rw-r--r--net/netfilter/nf_tables_api.c1760
-rw-r--r--net/netfilter/nf_tables_core.c152
-rw-r--r--net/netfilter/nft_bitwise.c140
-rw-r--r--net/netfilter/nft_byteorder.c167
-rw-r--r--net/netfilter/nft_cmp.c146
-rw-r--r--net/netfilter/nft_counter.c107
-rw-r--r--net/netfilter/nft_ct.c252
-rw-r--r--net/netfilter/nft_expr_template.c88
-rw-r--r--net/netfilter/nft_exthdr.c127
-rw-r--r--net/netfilter/nft_hash.c348
-rw-r--r--net/netfilter/nft_immediate.c113
-rw-r--r--net/netfilter/nft_limit.c113
-rw-r--r--net/netfilter/nft_log.c140
-rw-r--r--net/netfilter/nft_meta.c222
-rw-r--r--net/netfilter/nft_meta_target.c117
-rw-r--r--net/netfilter/nft_payload.c137
-rw-r--r--net/netfilter/nft_set.c381
19 files changed, 4563 insertions, 0 deletions
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 6e839b6dff2b..c271e1af93b5 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -413,6 +413,43 @@ config NETFILTER_SYNPROXY
413 413
414endif # NF_CONNTRACK 414endif # NF_CONNTRACK
415 415
416config NF_TABLES
417 depends on NETFILTER_NETLINK
418 tristate "Netfilter nf_tables support"
419
420config NFT_EXTHDR
421 depends on NF_TABLES
422 tristate "Netfilter nf_tables IPv6 exthdr module"
423
424config NFT_META
425 depends on NF_TABLES
426 tristate "Netfilter nf_tables meta module"
427
428config NFT_CT
429 depends on NF_TABLES
430 depends on NF_CONNTRACK
431 tristate "Netfilter nf_tables conntrack module"
432
433config NFT_SET
434 depends on NF_TABLES
435 tristate "Netfilter nf_tables set module"
436
437config NFT_HASH
438 depends on NF_TABLES
439 tristate "Netfilter nf_tables hash module"
440
441config NFT_COUNTER
442 depends on NF_TABLES
443 tristate "Netfilter nf_tables counter module"
444
445config NFT_LOG
446 depends on NF_TABLES
447 tristate "Netfilter nf_tables log module"
448
449config NFT_LIMIT
450 depends on NF_TABLES
451 tristate "Netfilter nf_tables limit module"
452
416config NETFILTER_XTABLES 453config NETFILTER_XTABLES
417 tristate "Netfilter Xtables support (required for ip_tables)" 454 tristate "Netfilter Xtables support (required for ip_tables)"
418 default m if NETFILTER_ADVANCED=n 455 default m if NETFILTER_ADVANCED=n
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index c3a0a12907f6..1ca3f3932826 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -64,6 +64,22 @@ obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o
64# SYNPROXY 64# SYNPROXY
65obj-$(CONFIG_NETFILTER_SYNPROXY) += nf_synproxy_core.o 65obj-$(CONFIG_NETFILTER_SYNPROXY) += nf_synproxy_core.o
66 66
67# nf_tables
68nf_tables-objs += nf_tables_core.o nf_tables_api.o
69nf_tables-objs += nft_immediate.o nft_cmp.o nft_lookup.o
70nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o
71
72obj-$(CONFIG_NF_TABLES) += nf_tables.o
73obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o
74obj-$(CONFIG_NFT_META) += nft_meta.o
75obj-$(CONFIG_NFT_CT) += nft_ct.o
76obj-$(CONFIG_NFT_LIMIT) += nft_limit.o
77#nf_tables-objs += nft_meta_target.o
78obj-$(CONFIG_NFT_SET) += nft_set.o
79obj-$(CONFIG_NFT_HASH) += nft_hash.o
80obj-$(CONFIG_NFT_COUNTER) += nft_counter.o
81obj-$(CONFIG_NFT_LOG) += nft_log.o
82
67# generic X tables 83# generic X tables
68obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o 84obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
69 85
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
new file mode 100644
index 000000000000..7d59c89c6c75
--- /dev/null
+++ b/net/netfilter/nf_tables_api.c
@@ -0,0 +1,1760 @@
1/*
2 * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net>
3 *
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,
107 const struct nlattr *nla,
108 bool autoload)
109{
110 struct nft_table *table;
111
112 if (nla == NULL)
113 return ERR_PTR(-EINVAL);
114
115 table = nft_table_lookup(afi, nla);
116 if (table != NULL)
117 return table;
118
119#ifdef CONFIG_MODULES
120 if (autoload) {
121 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
122 request_module("nft-table-%u-%*.s", afi->family,
123 nla_len(nla)-1, (const char *)nla_data(nla));
124 nfnl_lock(NFNL_SUBSYS_NFTABLES);
125 if (nft_table_lookup(afi, nla))
126 return ERR_PTR(-EAGAIN);
127 }
128#endif
129 return ERR_PTR(-ENOENT);
130}
131
132static inline u64 nf_tables_alloc_handle(struct nft_table *table)
133{
134 return ++table->hgenerator;
135}
136
137static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
138 [NFTA_TABLE_NAME] = { .type = NLA_STRING },
139};
140
141static int nf_tables_fill_table_info(struct sk_buff *skb, u32 portid, u32 seq,
142 int event, u32 flags, int family,
143 const struct nft_table *table)
144{
145 struct nlmsghdr *nlh;
146 struct nfgenmsg *nfmsg;
147
148 event |= NFNL_SUBSYS_NFTABLES << 8;
149 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
150 if (nlh == NULL)
151 goto nla_put_failure;
152
153 nfmsg = nlmsg_data(nlh);
154 nfmsg->nfgen_family = family;
155 nfmsg->version = NFNETLINK_V0;
156 nfmsg->res_id = 0;
157
158 if (nla_put_string(skb, NFTA_TABLE_NAME, table->name))
159 goto nla_put_failure;
160
161 return nlmsg_end(skb, nlh);
162
163nla_put_failure:
164 nlmsg_trim(skb, nlh);
165 return -1;
166}
167
168static int nf_tables_table_notify(const struct sk_buff *oskb,
169 const struct nlmsghdr *nlh,
170 const struct nft_table *table,
171 int event, int family)
172{
173 struct sk_buff *skb;
174 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
175 u32 seq = nlh ? nlh->nlmsg_seq : 0;
176 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
177 bool report;
178 int err;
179
180 report = nlh ? nlmsg_report(nlh) : false;
181 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
182 return 0;
183
184 err = -ENOBUFS;
185 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
186 if (skb == NULL)
187 goto err;
188
189 err = nf_tables_fill_table_info(skb, portid, seq, event, 0,
190 family, table);
191 if (err < 0) {
192 kfree_skb(skb);
193 goto err;
194 }
195
196 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
197 GFP_KERNEL);
198err:
199 if (err < 0)
200 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
201 return err;
202}
203
204static int nf_tables_dump_tables(struct sk_buff *skb,
205 struct netlink_callback *cb)
206{
207 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
208 const struct nft_af_info *afi;
209 const struct nft_table *table;
210 unsigned int idx = 0, s_idx = cb->args[0];
211 int family = nfmsg->nfgen_family;
212
213 list_for_each_entry(afi, &nf_tables_afinfo, list) {
214 if (family != NFPROTO_UNSPEC && family != afi->family)
215 continue;
216
217 list_for_each_entry(table, &afi->tables, list) {
218 if (idx < s_idx)
219 goto cont;
220 if (idx > s_idx)
221 memset(&cb->args[1], 0,
222 sizeof(cb->args) - sizeof(cb->args[0]));
223 if (nf_tables_fill_table_info(skb,
224 NETLINK_CB(cb->skb).portid,
225 cb->nlh->nlmsg_seq,
226 NFT_MSG_NEWTABLE,
227 NLM_F_MULTI,
228 afi->family, table) < 0)
229 goto done;
230cont:
231 idx++;
232 }
233 }
234done:
235 cb->args[0] = idx;
236 return skb->len;
237}
238
239static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb,
240 const struct nlmsghdr *nlh,
241 const struct nlattr * const nla[])
242{
243 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
244 const struct nft_af_info *afi;
245 const struct nft_table *table;
246 struct sk_buff *skb2;
247 int family = nfmsg->nfgen_family;
248 int err;
249
250 if (nlh->nlmsg_flags & NLM_F_DUMP) {
251 struct netlink_dump_control c = {
252 .dump = nf_tables_dump_tables,
253 };
254 return netlink_dump_start(nlsk, skb, nlh, &c);
255 }
256
257 afi = nf_tables_afinfo_lookup(family, false);
258 if (IS_ERR(afi))
259 return PTR_ERR(afi);
260
261 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME], false);
262 if (IS_ERR(table))
263 return PTR_ERR(table);
264
265 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
266 if (!skb2)
267 return -ENOMEM;
268
269 err = nf_tables_fill_table_info(skb2, NETLINK_CB(skb).portid,
270 nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0,
271 family, table);
272 if (err < 0)
273 goto err;
274
275 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
276
277err:
278 kfree_skb(skb2);
279 return err;
280}
281
282static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
283 const struct nlmsghdr *nlh,
284 const struct nlattr * const nla[])
285{
286 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
287 const struct nlattr *name;
288 struct nft_af_info *afi;
289 struct nft_table *table;
290 int family = nfmsg->nfgen_family;
291
292 afi = nf_tables_afinfo_lookup(family, true);
293 if (IS_ERR(afi))
294 return PTR_ERR(afi);
295
296 name = nla[NFTA_TABLE_NAME];
297 table = nf_tables_table_lookup(afi, name, false);
298 if (IS_ERR(table)) {
299 if (PTR_ERR(table) != -ENOENT)
300 return PTR_ERR(table);
301 table = NULL;
302 }
303
304 if (table != NULL) {
305 if (nlh->nlmsg_flags & NLM_F_EXCL)
306 return -EEXIST;
307 if (nlh->nlmsg_flags & NLM_F_REPLACE)
308 return -EOPNOTSUPP;
309 return 0;
310 }
311
312 table = kzalloc(sizeof(*table) + nla_len(name), GFP_KERNEL);
313 if (table == NULL)
314 return -ENOMEM;
315
316 nla_strlcpy(table->name, name, nla_len(name));
317 INIT_LIST_HEAD(&table->chains);
318
319 list_add_tail(&table->list, &afi->tables);
320 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
321 return 0;
322}
323
324static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
325 const struct nlmsghdr *nlh,
326 const struct nlattr * const nla[])
327{
328 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
329 struct nft_af_info *afi;
330 struct nft_table *table;
331 int family = nfmsg->nfgen_family;
332
333 afi = nf_tables_afinfo_lookup(family, false);
334 if (IS_ERR(afi))
335 return PTR_ERR(afi);
336
337 table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME], false);
338 if (IS_ERR(table))
339 return PTR_ERR(table);
340
341 if (table->flags & NFT_TABLE_BUILTIN)
342 return -EOPNOTSUPP;
343
344 if (table->use)
345 return -EBUSY;
346
347 list_del(&table->list);
348 nf_tables_table_notify(skb, nlh, table, NFT_MSG_DELTABLE, family);
349 kfree(table);
350 return 0;
351}
352
353static struct nft_table *__nf_tables_table_lookup(const struct nft_af_info *afi,
354 const char *name)
355{
356 struct nft_table *table;
357
358 list_for_each_entry(table, &afi->tables, list) {
359 if (!strcmp(name, table->name))
360 return table;
361 }
362
363 return ERR_PTR(-ENOENT);
364}
365
366static int nf_tables_chain_notify(const struct sk_buff *oskb,
367 const struct nlmsghdr *nlh,
368 const struct nft_table *table,
369 const struct nft_chain *chain,
370 int event, int family);
371
372/**
373 * nft_register_table - register a built-in table
374 *
375 * @table: the table to register
376 * @family: protocol family to register table with
377 *
378 * Register a built-in table for use with nf_tables. Returns zero on
379 * success or a negative errno code otherwise.
380 */
381int nft_register_table(struct nft_table *table, int family)
382{
383 struct nft_af_info *afi;
384 struct nft_table *t;
385 struct nft_chain *chain;
386 int err;
387
388 nfnl_lock(NFNL_SUBSYS_NFTABLES);
389again:
390 afi = nf_tables_afinfo_lookup(family, true);
391 if (IS_ERR(afi)) {
392 err = PTR_ERR(afi);
393 if (err == -EAGAIN)
394 goto again;
395 goto err;
396 }
397
398 t = __nf_tables_table_lookup(afi, table->name);
399 if (IS_ERR(t)) {
400 err = PTR_ERR(t);
401 if (err != -ENOENT)
402 goto err;
403 t = NULL;
404 }
405
406 if (t != NULL) {
407 err = -EEXIST;
408 goto err;
409 }
410
411 table->flags |= NFT_TABLE_BUILTIN;
412 list_add_tail(&table->list, &afi->tables);
413 nf_tables_table_notify(NULL, NULL, table, NFT_MSG_NEWTABLE, family);
414 list_for_each_entry(chain, &table->chains, list)
415 nf_tables_chain_notify(NULL, NULL, table, chain,
416 NFT_MSG_NEWCHAIN, family);
417 err = 0;
418err:
419 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
420 return err;
421}
422EXPORT_SYMBOL_GPL(nft_register_table);
423
424/**
425 * nft_unregister_table - unregister a built-in table
426 *
427 * @table: the table to unregister
428 * @family: protocol family to unregister table with
429 *
430 * Unregister a built-in table for use with nf_tables.
431 */
432void nft_unregister_table(struct nft_table *table, int family)
433{
434 struct nft_chain *chain;
435
436 nfnl_lock(NFNL_SUBSYS_NFTABLES);
437 list_del(&table->list);
438 list_for_each_entry(chain, &table->chains, list)
439 nf_tables_chain_notify(NULL, NULL, table, chain,
440 NFT_MSG_DELCHAIN, family);
441 nf_tables_table_notify(NULL, NULL, table, NFT_MSG_DELTABLE, family);
442 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
443}
444EXPORT_SYMBOL_GPL(nft_unregister_table);
445
446/*
447 * Chains
448 */
449
450static struct nft_chain *
451nf_tables_chain_lookup_byhandle(const struct nft_table *table, u64 handle)
452{
453 struct nft_chain *chain;
454
455 list_for_each_entry(chain, &table->chains, list) {
456 if (chain->handle == handle)
457 return chain;
458 }
459
460 return ERR_PTR(-ENOENT);
461}
462
463static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table,
464 const struct nlattr *nla)
465{
466 struct nft_chain *chain;
467
468 if (nla == NULL)
469 return ERR_PTR(-EINVAL);
470
471 list_for_each_entry(chain, &table->chains, list) {
472 if (!nla_strcmp(nla, chain->name))
473 return chain;
474 }
475
476 return ERR_PTR(-ENOENT);
477}
478
479static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
480 [NFTA_CHAIN_TABLE] = { .type = NLA_STRING },
481 [NFTA_CHAIN_HANDLE] = { .type = NLA_U64 },
482 [NFTA_CHAIN_NAME] = { .type = NLA_STRING,
483 .len = NFT_CHAIN_MAXNAMELEN - 1 },
484 [NFTA_CHAIN_HOOK] = { .type = NLA_NESTED },
485};
486
487static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = {
488 [NFTA_HOOK_HOOKNUM] = { .type = NLA_U32 },
489 [NFTA_HOOK_PRIORITY] = { .type = NLA_U32 },
490};
491
492static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq,
493 int event, u32 flags, int family,
494 const struct nft_table *table,
495 const struct nft_chain *chain)
496{
497 struct nlmsghdr *nlh;
498 struct nfgenmsg *nfmsg;
499
500 event |= NFNL_SUBSYS_NFTABLES << 8;
501 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
502 if (nlh == NULL)
503 goto nla_put_failure;
504
505 nfmsg = nlmsg_data(nlh);
506 nfmsg->nfgen_family = family;
507 nfmsg->version = NFNETLINK_V0;
508 nfmsg->res_id = 0;
509
510 if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name))
511 goto nla_put_failure;
512 if (nla_put_be64(skb, NFTA_CHAIN_HANDLE, cpu_to_be64(chain->handle)))
513 goto nla_put_failure;
514 if (nla_put_string(skb, NFTA_CHAIN_NAME, chain->name))
515 goto nla_put_failure;
516
517 if (chain->flags & NFT_BASE_CHAIN) {
518 const struct nf_hook_ops *ops = &nft_base_chain(chain)->ops;
519 struct nlattr *nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
520 if (nest == NULL)
521 goto nla_put_failure;
522 if (nla_put_be32(skb, NFTA_HOOK_HOOKNUM, htonl(ops->hooknum)))
523 goto nla_put_failure;
524 if (nla_put_be32(skb, NFTA_HOOK_PRIORITY, htonl(ops->priority)))
525 goto nla_put_failure;
526 nla_nest_end(skb, nest);
527 }
528
529 return nlmsg_end(skb, nlh);
530
531nla_put_failure:
532 nlmsg_trim(skb, nlh);
533 return -1;
534}
535
536static int nf_tables_chain_notify(const struct sk_buff *oskb,
537 const struct nlmsghdr *nlh,
538 const struct nft_table *table,
539 const struct nft_chain *chain,
540 int event, int family)
541{
542 struct sk_buff *skb;
543 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
544 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
545 u32 seq = nlh ? nlh->nlmsg_seq : 0;
546 bool report;
547 int err;
548
549 report = nlh ? nlmsg_report(nlh) : false;
550 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
551 return 0;
552
553 err = -ENOBUFS;
554 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
555 if (skb == NULL)
556 goto err;
557
558 err = nf_tables_fill_chain_info(skb, portid, seq, event, 0, family,
559 table, chain);
560 if (err < 0) {
561 kfree_skb(skb);
562 goto err;
563 }
564
565 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
566 GFP_KERNEL);
567err:
568 if (err < 0)
569 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
570 return err;
571}
572
573static int nf_tables_dump_chains(struct sk_buff *skb,
574 struct netlink_callback *cb)
575{
576 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
577 const struct nft_af_info *afi;
578 const struct nft_table *table;
579 const struct nft_chain *chain;
580 unsigned int idx = 0, s_idx = cb->args[0];
581 int family = nfmsg->nfgen_family;
582
583 list_for_each_entry(afi, &nf_tables_afinfo, list) {
584 if (family != NFPROTO_UNSPEC && family != afi->family)
585 continue;
586
587 list_for_each_entry(table, &afi->tables, list) {
588 list_for_each_entry(chain, &table->chains, list) {
589 if (idx < s_idx)
590 goto cont;
591 if (idx > s_idx)
592 memset(&cb->args[1], 0,
593 sizeof(cb->args) - sizeof(cb->args[0]));
594 if (nf_tables_fill_chain_info(skb, NETLINK_CB(cb->skb).portid,
595 cb->nlh->nlmsg_seq,
596 NFT_MSG_NEWCHAIN,
597 NLM_F_MULTI,
598 afi->family, table, chain) < 0)
599 goto done;
600cont:
601 idx++;
602 }
603 }
604 }
605done:
606 cb->args[0] = idx;
607 return skb->len;
608}
609
610
611static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb,
612 const struct nlmsghdr *nlh,
613 const struct nlattr * const nla[])
614{
615 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
616 const struct nft_af_info *afi;
617 const struct nft_table *table;
618 const struct nft_chain *chain;
619 struct sk_buff *skb2;
620 int family = nfmsg->nfgen_family;
621 int err;
622
623 if (nlh->nlmsg_flags & NLM_F_DUMP) {
624 struct netlink_dump_control c = {
625 .dump = nf_tables_dump_chains,
626 };
627 return netlink_dump_start(nlsk, skb, nlh, &c);
628 }
629
630 afi = nf_tables_afinfo_lookup(family, false);
631 if (IS_ERR(afi))
632 return PTR_ERR(afi);
633
634 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE], false);
635 if (IS_ERR(table))
636 return PTR_ERR(table);
637
638 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
639 if (IS_ERR(chain))
640 return PTR_ERR(chain);
641
642 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
643 if (!skb2)
644 return -ENOMEM;
645
646 err = nf_tables_fill_chain_info(skb2, NETLINK_CB(skb).portid,
647 nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0,
648 family, table, chain);
649 if (err < 0)
650 goto err;
651
652 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
653
654err:
655 kfree_skb(skb2);
656 return err;
657}
658
659static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
660 const struct nlmsghdr *nlh,
661 const struct nlattr * const nla[])
662{
663 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
664 const struct nlattr * uninitialized_var(name);
665 const struct nft_af_info *afi;
666 struct nft_table *table;
667 struct nft_chain *chain;
668 struct nft_base_chain *basechain;
669 struct nlattr *ha[NFTA_HOOK_MAX + 1];
670 int family = nfmsg->nfgen_family;
671 u64 handle = 0;
672 int err;
673 bool create;
674
675 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
676
677 afi = nf_tables_afinfo_lookup(family, true);
678 if (IS_ERR(afi))
679 return PTR_ERR(afi);
680
681 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE], create);
682 if (IS_ERR(table))
683 return PTR_ERR(table);
684
685 if (table->use == UINT_MAX)
686 return -EOVERFLOW;
687
688 chain = NULL;
689 name = nla[NFTA_CHAIN_NAME];
690
691 if (nla[NFTA_CHAIN_HANDLE]) {
692 handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
693 chain = nf_tables_chain_lookup_byhandle(table, handle);
694 if (IS_ERR(chain))
695 return PTR_ERR(chain);
696 } else {
697 chain = nf_tables_chain_lookup(table, name);
698 if (IS_ERR(chain)) {
699 if (PTR_ERR(chain) != -ENOENT)
700 return PTR_ERR(chain);
701 chain = NULL;
702 }
703 }
704
705 if (chain != NULL) {
706 if (nlh->nlmsg_flags & NLM_F_EXCL)
707 return -EEXIST;
708 if (nlh->nlmsg_flags & NLM_F_REPLACE)
709 return -EOPNOTSUPP;
710
711 if (nla[NFTA_CHAIN_HANDLE] && name &&
712 !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME])))
713 return -EEXIST;
714
715 if (nla[NFTA_CHAIN_HANDLE] && name)
716 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
717
718 goto notify;
719 }
720
721 if (nla[NFTA_CHAIN_HOOK]) {
722 struct nf_hook_ops *ops;
723
724 err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK],
725 nft_hook_policy);
726 if (err < 0)
727 return err;
728 if (ha[NFTA_HOOK_HOOKNUM] == NULL ||
729 ha[NFTA_HOOK_PRIORITY] == NULL)
730 return -EINVAL;
731 if (ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM])) >= afi->nhooks)
732 return -EINVAL;
733
734 basechain = kzalloc(sizeof(*basechain), GFP_KERNEL);
735 if (basechain == NULL)
736 return -ENOMEM;
737 chain = &basechain->chain;
738
739 ops = &basechain->ops;
740 ops->pf = family;
741 ops->owner = afi->owner;
742 ops->hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
743 ops->priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
744 ops->priv = chain;
745 ops->hook = nft_do_chain;
746 if (afi->hooks[ops->hooknum])
747 ops->hook = afi->hooks[ops->hooknum];
748
749 chain->flags |= NFT_BASE_CHAIN;
750 } else {
751 chain = kzalloc(sizeof(*chain), GFP_KERNEL);
752 if (chain == NULL)
753 return -ENOMEM;
754 }
755
756 INIT_LIST_HEAD(&chain->rules);
757 chain->handle = nf_tables_alloc_handle(table);
758 nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
759
760 list_add_tail(&chain->list, &table->chains);
761 table->use++;
762notify:
763 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_NEWCHAIN,
764 family);
765 return 0;
766}
767
768static void nf_tables_rcu_chain_destroy(struct rcu_head *head)
769{
770 struct nft_chain *chain = container_of(head, struct nft_chain, rcu_head);
771
772 BUG_ON(chain->use > 0);
773
774 if (chain->flags & NFT_BASE_CHAIN)
775 kfree(nft_base_chain(chain));
776 else
777 kfree(chain);
778}
779
780static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
781 const struct nlmsghdr *nlh,
782 const struct nlattr * const nla[])
783{
784 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
785 const struct nft_af_info *afi;
786 struct nft_table *table;
787 struct nft_chain *chain;
788 int family = nfmsg->nfgen_family;
789
790 afi = nf_tables_afinfo_lookup(family, false);
791 if (IS_ERR(afi))
792 return PTR_ERR(afi);
793
794 table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE], false);
795 if (IS_ERR(table))
796 return PTR_ERR(table);
797
798 chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
799 if (IS_ERR(chain))
800 return PTR_ERR(chain);
801
802 if (chain->flags & NFT_CHAIN_BUILTIN)
803 return -EOPNOTSUPP;
804
805 if (!list_empty(&chain->rules))
806 return -EBUSY;
807
808 list_del(&chain->list);
809 table->use--;
810
811 if (chain->flags & NFT_BASE_CHAIN)
812 nf_unregister_hook(&nft_base_chain(chain)->ops);
813
814 nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN,
815 family);
816
817 /* Make sure all rule references are gone before this is released */
818 call_rcu(&chain->rcu_head, nf_tables_rcu_chain_destroy);
819 return 0;
820}
821
822static void nft_ctx_init(struct nft_ctx *ctx,
823 const struct nft_af_info *afi,
824 const struct nft_table *table,
825 const struct nft_chain *chain)
826{
827 ctx->afi = afi;
828 ctx->table = table;
829 ctx->chain = chain;
830}
831
832/*
833 * Expressions
834 */
835
836/**
837 * nft_register_expr - register nf_tables expr operations
838 * @ops: expr operations
839 *
840 * Registers the expr operations for use with nf_tables. Returns zero on
841 * success or a negative errno code otherwise.
842 */
843int nft_register_expr(struct nft_expr_ops *ops)
844{
845 nfnl_lock(NFNL_SUBSYS_NFTABLES);
846 list_add_tail(&ops->list, &nf_tables_expressions);
847 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
848 return 0;
849}
850EXPORT_SYMBOL_GPL(nft_register_expr);
851
852/**
853 * nft_unregister_expr - unregister nf_tables expr operations
854 * @ops: expr operations
855 *
856 * Unregisters the expr operations for use with nf_tables.
857 */
858void nft_unregister_expr(struct nft_expr_ops *ops)
859{
860 nfnl_lock(NFNL_SUBSYS_NFTABLES);
861 list_del(&ops->list);
862 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
863}
864EXPORT_SYMBOL_GPL(nft_unregister_expr);
865
866static const struct nft_expr_ops *__nft_expr_ops_get(struct nlattr *nla)
867{
868 const struct nft_expr_ops *ops;
869
870 list_for_each_entry(ops, &nf_tables_expressions, list) {
871 if (!nla_strcmp(nla, ops->name))
872 return ops;
873 }
874 return NULL;
875}
876
877static const struct nft_expr_ops *nft_expr_ops_get(struct nlattr *nla)
878{
879 const struct nft_expr_ops *ops;
880
881 if (nla == NULL)
882 return ERR_PTR(-EINVAL);
883
884 ops = __nft_expr_ops_get(nla);
885 if (ops != NULL && try_module_get(ops->owner))
886 return ops;
887
888#ifdef CONFIG_MODULES
889 if (ops == NULL) {
890 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
891 request_module("nft-expr-%.*s",
892 nla_len(nla), (char *)nla_data(nla));
893 nfnl_lock(NFNL_SUBSYS_NFTABLES);
894 if (__nft_expr_ops_get(nla))
895 return ERR_PTR(-EAGAIN);
896 }
897#endif
898 return ERR_PTR(-ENOENT);
899}
900
901static const struct nla_policy nft_expr_policy[NFTA_EXPR_MAX + 1] = {
902 [NFTA_EXPR_NAME] = { .type = NLA_STRING },
903 [NFTA_EXPR_DATA] = { .type = NLA_NESTED },
904};
905
906static int nf_tables_fill_expr_info(struct sk_buff *skb,
907 const struct nft_expr *expr)
908{
909 if (nla_put_string(skb, NFTA_EXPR_NAME, expr->ops->name))
910 goto nla_put_failure;
911
912 if (expr->ops->dump) {
913 struct nlattr *data = nla_nest_start(skb, NFTA_EXPR_DATA);
914 if (data == NULL)
915 goto nla_put_failure;
916 if (expr->ops->dump(skb, expr) < 0)
917 goto nla_put_failure;
918 nla_nest_end(skb, data);
919 }
920
921 return skb->len;
922
923nla_put_failure:
924 return -1;
925};
926
927struct nft_expr_info {
928 const struct nft_expr_ops *ops;
929 struct nlattr *tb[NFTA_EXPR_MAX + 1];
930};
931
932static int nf_tables_expr_parse(const struct nlattr *nla,
933 struct nft_expr_info *info)
934{
935 const struct nft_expr_ops *ops;
936 int err;
937
938 err = nla_parse_nested(info->tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
939 if (err < 0)
940 return err;
941
942 ops = nft_expr_ops_get(info->tb[NFTA_EXPR_NAME]);
943 if (IS_ERR(ops))
944 return PTR_ERR(ops);
945 info->ops = ops;
946 return 0;
947}
948
949static int nf_tables_newexpr(const struct nft_ctx *ctx,
950 struct nft_expr_info *info,
951 struct nft_expr *expr)
952{
953 const struct nft_expr_ops *ops = info->ops;
954 int err;
955
956 expr->ops = ops;
957 if (ops->init) {
958 struct nlattr *ma[ops->maxattr + 1];
959
960 if (info->tb[NFTA_EXPR_DATA]) {
961 err = nla_parse_nested(ma, ops->maxattr,
962 info->tb[NFTA_EXPR_DATA],
963 ops->policy);
964 if (err < 0)
965 goto err1;
966 } else
967 memset(ma, 0, sizeof(ma[0]) * (ops->maxattr + 1));
968
969 err = ops->init(ctx, expr, (const struct nlattr **)ma);
970 if (err < 0)
971 goto err1;
972 }
973
974 info->ops = NULL;
975 return 0;
976
977err1:
978 expr->ops = NULL;
979 return err;
980}
981
982static void nf_tables_expr_destroy(struct nft_expr *expr)
983{
984 if (expr->ops->destroy)
985 expr->ops->destroy(expr);
986 module_put(expr->ops->owner);
987}
988
989/*
990 * Rules
991 */
992
993static struct nft_rule *__nf_tables_rule_lookup(const struct nft_chain *chain,
994 u64 handle)
995{
996 struct nft_rule *rule;
997
998 // FIXME: this sucks
999 list_for_each_entry(rule, &chain->rules, list) {
1000 if (handle == rule->handle)
1001 return rule;
1002 }
1003
1004 return ERR_PTR(-ENOENT);
1005}
1006
1007static struct nft_rule *nf_tables_rule_lookup(const struct nft_chain *chain,
1008 const struct nlattr *nla)
1009{
1010 if (nla == NULL)
1011 return ERR_PTR(-EINVAL);
1012
1013 return __nf_tables_rule_lookup(chain, be64_to_cpu(nla_get_be64(nla)));
1014}
1015
1016static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
1017 [NFTA_RULE_TABLE] = { .type = NLA_STRING },
1018 [NFTA_RULE_CHAIN] = { .type = NLA_STRING,
1019 .len = NFT_CHAIN_MAXNAMELEN - 1 },
1020 [NFTA_RULE_HANDLE] = { .type = NLA_U64 },
1021 [NFTA_RULE_EXPRESSIONS] = { .type = NLA_NESTED },
1022};
1023
1024static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
1025 int event, u32 flags, int family,
1026 const struct nft_table *table,
1027 const struct nft_chain *chain,
1028 const struct nft_rule *rule)
1029{
1030 struct nlmsghdr *nlh;
1031 struct nfgenmsg *nfmsg;
1032 const struct nft_expr *expr, *next;
1033 struct nlattr *list;
1034
1035 event |= NFNL_SUBSYS_NFTABLES << 8;
1036 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
1037 flags);
1038 if (nlh == NULL)
1039 goto nla_put_failure;
1040
1041 nfmsg = nlmsg_data(nlh);
1042 nfmsg->nfgen_family = family;
1043 nfmsg->version = NFNETLINK_V0;
1044 nfmsg->res_id = 0;
1045
1046 if (nla_put_string(skb, NFTA_RULE_TABLE, table->name))
1047 goto nla_put_failure;
1048 if (nla_put_string(skb, NFTA_RULE_CHAIN, chain->name))
1049 goto nla_put_failure;
1050 if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
1051 goto nla_put_failure;
1052
1053 list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
1054 if (list == NULL)
1055 goto nla_put_failure;
1056 nft_rule_for_each_expr(expr, next, rule) {
1057 struct nlattr *elem = nla_nest_start(skb, NFTA_LIST_ELEM);
1058 if (elem == NULL)
1059 goto nla_put_failure;
1060 if (nf_tables_fill_expr_info(skb, expr) < 0)
1061 goto nla_put_failure;
1062 nla_nest_end(skb, elem);
1063 }
1064 nla_nest_end(skb, list);
1065
1066 return nlmsg_end(skb, nlh);
1067
1068nla_put_failure:
1069 nlmsg_trim(skb, nlh);
1070 return -1;
1071}
1072
1073static int nf_tables_rule_notify(const struct sk_buff *oskb,
1074 const struct nlmsghdr *nlh,
1075 const struct nft_table *table,
1076 const struct nft_chain *chain,
1077 const struct nft_rule *rule,
1078 int event, u32 flags, int family)
1079{
1080 struct sk_buff *skb;
1081 u32 portid = NETLINK_CB(oskb).portid;
1082 struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
1083 u32 seq = nlh->nlmsg_seq;
1084 bool report;
1085 int err;
1086
1087 report = nlmsg_report(nlh);
1088 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
1089 return 0;
1090
1091 err = -ENOBUFS;
1092 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1093 if (skb == NULL)
1094 goto err;
1095
1096 err = nf_tables_fill_rule_info(skb, portid, seq, event, flags,
1097 family, table, chain, rule);
1098 if (err < 0) {
1099 kfree_skb(skb);
1100 goto err;
1101 }
1102
1103 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
1104 GFP_KERNEL);
1105err:
1106 if (err < 0)
1107 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
1108 return err;
1109}
1110
1111static int nf_tables_dump_rules(struct sk_buff *skb,
1112 struct netlink_callback *cb)
1113{
1114 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
1115 const struct nft_af_info *afi;
1116 const struct nft_table *table;
1117 const struct nft_chain *chain;
1118 const struct nft_rule *rule;
1119 unsigned int idx = 0, s_idx = cb->args[0];
1120 int family = nfmsg->nfgen_family;
1121
1122 list_for_each_entry(afi, &nf_tables_afinfo, list) {
1123 if (family != NFPROTO_UNSPEC && family != afi->family)
1124 continue;
1125
1126 list_for_each_entry(table, &afi->tables, list) {
1127 list_for_each_entry(chain, &table->chains, list) {
1128 list_for_each_entry(rule, &chain->rules, list) {
1129 if (idx < s_idx)
1130 goto cont;
1131 if (idx > s_idx)
1132 memset(&cb->args[1], 0,
1133 sizeof(cb->args) - sizeof(cb->args[0]));
1134 if (nf_tables_fill_rule_info(skb, NETLINK_CB(cb->skb).portid,
1135 cb->nlh->nlmsg_seq,
1136 NFT_MSG_NEWRULE,
1137 NLM_F_MULTI | NLM_F_APPEND,
1138 afi->family, table, chain, rule) < 0)
1139 goto done;
1140cont:
1141 idx++;
1142 }
1143 }
1144 }
1145 }
1146done:
1147 cb->args[0] = idx;
1148 return skb->len;
1149}
1150
1151static int nf_tables_getrule(struct sock *nlsk, struct sk_buff *skb,
1152 const struct nlmsghdr *nlh,
1153 const struct nlattr * const nla[])
1154{
1155 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1156 const struct nft_af_info *afi;
1157 const struct nft_table *table;
1158 const struct nft_chain *chain;
1159 const struct nft_rule *rule;
1160 struct sk_buff *skb2;
1161 int family = nfmsg->nfgen_family;
1162 int err;
1163
1164 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1165 struct netlink_dump_control c = {
1166 .dump = nf_tables_dump_rules,
1167 };
1168 return netlink_dump_start(nlsk, skb, nlh, &c);
1169 }
1170
1171 afi = nf_tables_afinfo_lookup(family, false);
1172 if (IS_ERR(afi))
1173 return PTR_ERR(afi);
1174
1175 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE], false);
1176 if (IS_ERR(table))
1177 return PTR_ERR(table);
1178
1179 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1180 if (IS_ERR(chain))
1181 return PTR_ERR(chain);
1182
1183 rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
1184 if (IS_ERR(rule))
1185 return PTR_ERR(rule);
1186
1187 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1188 if (!skb2)
1189 return -ENOMEM;
1190
1191 err = nf_tables_fill_rule_info(skb2, NETLINK_CB(skb).portid,
1192 nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
1193 family, table, chain, rule);
1194 if (err < 0)
1195 goto err;
1196
1197 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
1198
1199err:
1200 kfree_skb(skb2);
1201 return err;
1202}
1203
1204static void nf_tables_rcu_rule_destroy(struct rcu_head *head)
1205{
1206 struct nft_rule *rule = container_of(head, struct nft_rule, rcu_head);
1207 struct nft_expr *expr;
1208
1209 /*
1210 * Careful: some expressions might not be initialized in case this
1211 * is called on error from nf_tables_newrule().
1212 */
1213 expr = nft_expr_first(rule);
1214 while (expr->ops && expr != nft_expr_last(rule)) {
1215 nf_tables_expr_destroy(expr);
1216 expr = nft_expr_next(expr);
1217 }
1218 kfree(rule);
1219}
1220
1221static void nf_tables_rule_destroy(struct nft_rule *rule)
1222{
1223 call_rcu(&rule->rcu_head, nf_tables_rcu_rule_destroy);
1224}
1225
1226#define NFT_RULE_MAXEXPRS 128
1227
1228static struct nft_expr_info *info;
1229
1230static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
1231 const struct nlmsghdr *nlh,
1232 const struct nlattr * const nla[])
1233{
1234 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1235 const struct nft_af_info *afi;
1236 struct nft_table *table;
1237 struct nft_chain *chain;
1238 struct nft_rule *rule, *old_rule = NULL;
1239 struct nft_expr *expr;
1240 struct nft_ctx ctx;
1241 struct nlattr *tmp;
1242 unsigned int size, i, n;
1243 int err, rem;
1244 bool create;
1245 u64 handle;
1246
1247 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
1248
1249 afi = nf_tables_afinfo_lookup(nfmsg->nfgen_family, create);
1250 if (IS_ERR(afi))
1251 return PTR_ERR(afi);
1252
1253 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE], create);
1254 if (IS_ERR(table))
1255 return PTR_ERR(table);
1256
1257 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1258 if (IS_ERR(chain))
1259 return PTR_ERR(chain);
1260
1261 if (nla[NFTA_RULE_HANDLE]) {
1262 handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
1263 rule = __nf_tables_rule_lookup(chain, handle);
1264 if (IS_ERR(rule))
1265 return PTR_ERR(rule);
1266
1267 if (nlh->nlmsg_flags & NLM_F_EXCL)
1268 return -EEXIST;
1269 if (nlh->nlmsg_flags & NLM_F_REPLACE)
1270 old_rule = rule;
1271 else
1272 return -EOPNOTSUPP;
1273 } else {
1274 if (!create || nlh->nlmsg_flags & NLM_F_REPLACE)
1275 return -EINVAL;
1276 handle = nf_tables_alloc_handle(table);
1277 }
1278
1279 n = 0;
1280 size = 0;
1281 if (nla[NFTA_RULE_EXPRESSIONS]) {
1282 nla_for_each_nested(tmp, nla[NFTA_RULE_EXPRESSIONS], rem) {
1283 err = -EINVAL;
1284 if (nla_type(tmp) != NFTA_LIST_ELEM)
1285 goto err1;
1286 if (n == NFT_RULE_MAXEXPRS)
1287 goto err1;
1288 err = nf_tables_expr_parse(tmp, &info[n]);
1289 if (err < 0)
1290 goto err1;
1291 size += info[n].ops->size;
1292 n++;
1293 }
1294 }
1295
1296 err = -ENOMEM;
1297 rule = kzalloc(sizeof(*rule) + size, GFP_KERNEL);
1298 if (rule == NULL)
1299 goto err1;
1300
1301 rule->handle = handle;
1302 rule->dlen = size;
1303
1304 nft_ctx_init(&ctx, afi, table, chain);
1305 expr = nft_expr_first(rule);
1306 for (i = 0; i < n; i++) {
1307 err = nf_tables_newexpr(&ctx, &info[i], expr);
1308 if (err < 0)
1309 goto err2;
1310 expr = nft_expr_next(expr);
1311 }
1312
1313 /* Register hook when first rule is inserted into a base chain */
1314 if (list_empty(&chain->rules) && chain->flags & NFT_BASE_CHAIN) {
1315 err = nf_register_hook(&nft_base_chain(chain)->ops);
1316 if (err < 0)
1317 goto err2;
1318 }
1319
1320 if (nlh->nlmsg_flags & NLM_F_REPLACE) {
1321 list_replace_rcu(&old_rule->list, &rule->list);
1322 nf_tables_rule_destroy(old_rule);
1323 } else if (nlh->nlmsg_flags & NLM_F_APPEND)
1324 list_add_tail_rcu(&rule->list, &chain->rules);
1325 else
1326 list_add_rcu(&rule->list, &chain->rules);
1327
1328 nf_tables_rule_notify(skb, nlh, table, chain, rule, NFT_MSG_NEWRULE,
1329 nlh->nlmsg_flags & (NLM_F_APPEND | NLM_F_REPLACE),
1330 nfmsg->nfgen_family);
1331 return 0;
1332
1333err2:
1334 nf_tables_rule_destroy(rule);
1335err1:
1336 for (i = 0; i < n; i++) {
1337 if (info[i].ops != NULL)
1338 module_put(info[i].ops->owner);
1339 }
1340 return err;
1341}
1342
1343static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
1344 const struct nlmsghdr *nlh,
1345 const struct nlattr * const nla[])
1346{
1347 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1348 const struct nft_af_info *afi;
1349 const struct nft_table *table;
1350 struct nft_chain *chain;
1351 struct nft_rule *rule, *tmp;
1352 int family = nfmsg->nfgen_family;
1353
1354 afi = nf_tables_afinfo_lookup(family, false);
1355 if (IS_ERR(afi))
1356 return PTR_ERR(afi);
1357
1358 table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE], false);
1359 if (IS_ERR(table))
1360 return PTR_ERR(table);
1361
1362 chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
1363 if (IS_ERR(chain))
1364 return PTR_ERR(chain);
1365
1366 if (nla[NFTA_RULE_HANDLE]) {
1367 rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
1368 if (IS_ERR(rule))
1369 return PTR_ERR(rule);
1370
1371 /* List removal must be visible before destroying expressions */
1372 list_del_rcu(&rule->list);
1373
1374 nf_tables_rule_notify(skb, nlh, table, chain, rule,
1375 NFT_MSG_DELRULE, 0, family);
1376 nf_tables_rule_destroy(rule);
1377 } else {
1378 /* Remove all rules in this chain */
1379 list_for_each_entry_safe(rule, tmp, &chain->rules, list) {
1380 list_del_rcu(&rule->list);
1381
1382 nf_tables_rule_notify(skb, nlh, table, chain, rule,
1383 NFT_MSG_DELRULE, 0, family);
1384 nf_tables_rule_destroy(rule);
1385 }
1386 }
1387
1388 /* Unregister hook when last rule from base chain is deleted */
1389 if (list_empty(&chain->rules) && chain->flags & NFT_BASE_CHAIN)
1390 nf_unregister_hook(&nft_base_chain(chain)->ops);
1391
1392 return 0;
1393}
1394
1395static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
1396 [NFT_MSG_NEWTABLE] = {
1397 .call = nf_tables_newtable,
1398 .attr_count = NFTA_TABLE_MAX,
1399 .policy = nft_table_policy,
1400 },
1401 [NFT_MSG_GETTABLE] = {
1402 .call = nf_tables_gettable,
1403 .attr_count = NFTA_TABLE_MAX,
1404 .policy = nft_table_policy,
1405 },
1406 [NFT_MSG_DELTABLE] = {
1407 .call = nf_tables_deltable,
1408 .attr_count = NFTA_TABLE_MAX,
1409 .policy = nft_table_policy,
1410 },
1411 [NFT_MSG_NEWCHAIN] = {
1412 .call = nf_tables_newchain,
1413 .attr_count = NFTA_CHAIN_MAX,
1414 .policy = nft_chain_policy,
1415 },
1416 [NFT_MSG_GETCHAIN] = {
1417 .call = nf_tables_getchain,
1418 .attr_count = NFTA_CHAIN_MAX,
1419 .policy = nft_chain_policy,
1420 },
1421 [NFT_MSG_DELCHAIN] = {
1422 .call = nf_tables_delchain,
1423 .attr_count = NFTA_CHAIN_MAX,
1424 .policy = nft_chain_policy,
1425 },
1426 [NFT_MSG_NEWRULE] = {
1427 .call = nf_tables_newrule,
1428 .attr_count = NFTA_RULE_MAX,
1429 .policy = nft_rule_policy,
1430 },
1431 [NFT_MSG_GETRULE] = {
1432 .call = nf_tables_getrule,
1433 .attr_count = NFTA_RULE_MAX,
1434 .policy = nft_rule_policy,
1435 },
1436 [NFT_MSG_DELRULE] = {
1437 .call = nf_tables_delrule,
1438 .attr_count = NFTA_RULE_MAX,
1439 .policy = nft_rule_policy,
1440 },
1441};
1442
1443static const struct nfnetlink_subsystem nf_tables_subsys = {
1444 .name = "nf_tables",
1445 .subsys_id = NFNL_SUBSYS_NFTABLES,
1446 .cb_count = NFT_MSG_MAX,
1447 .cb = nf_tables_cb,
1448};
1449
1450/**
1451 * nft_validate_input_register - validate an expressions' input register
1452 *
1453 * @reg: the register number
1454 *
1455 * Validate that the input register is one of the general purpose
1456 * registers.
1457 */
1458int nft_validate_input_register(enum nft_registers reg)
1459{
1460 if (reg <= NFT_REG_VERDICT)
1461 return -EINVAL;
1462 if (reg > NFT_REG_MAX)
1463 return -ERANGE;
1464 return 0;
1465}
1466EXPORT_SYMBOL_GPL(nft_validate_input_register);
1467
1468/**
1469 * nft_validate_output_register - validate an expressions' output register
1470 *
1471 * @reg: the register number
1472 *
1473 * Validate that the output register is one of the general purpose
1474 * registers or the verdict register.
1475 */
1476int nft_validate_output_register(enum nft_registers reg)
1477{
1478 if (reg < NFT_REG_VERDICT)
1479 return -EINVAL;
1480 if (reg > NFT_REG_MAX)
1481 return -ERANGE;
1482 return 0;
1483}
1484EXPORT_SYMBOL_GPL(nft_validate_output_register);
1485
1486/**
1487 * nft_validate_data_load - validate an expressions' data load
1488 *
1489 * @ctx: context of the expression performing the load
1490 * @reg: the destination register number
1491 * @data: the data to load
1492 * @type: the data type
1493 *
1494 * Validate that a data load uses the appropriate data type for
1495 * the destination register. A value of NULL for the data means
1496 * that its runtime gathered data, which is always of type
1497 * NFT_DATA_VALUE.
1498 */
1499int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
1500 const struct nft_data *data,
1501 enum nft_data_types type)
1502{
1503 switch (reg) {
1504 case NFT_REG_VERDICT:
1505 if (data == NULL || type != NFT_DATA_VERDICT)
1506 return -EINVAL;
1507 // FIXME: do loop detection
1508 return 0;
1509 default:
1510 if (data != NULL && type != NFT_DATA_VALUE)
1511 return -EINVAL;
1512 return 0;
1513 }
1514}
1515EXPORT_SYMBOL_GPL(nft_validate_data_load);
1516
1517static const struct nla_policy nft_verdict_policy[NFTA_VERDICT_MAX + 1] = {
1518 [NFTA_VERDICT_CODE] = { .type = NLA_U32 },
1519 [NFTA_VERDICT_CHAIN] = { .type = NLA_STRING,
1520 .len = NFT_CHAIN_MAXNAMELEN - 1 },
1521};
1522
1523static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
1524 struct nft_data_desc *desc, const struct nlattr *nla)
1525{
1526 struct nlattr *tb[NFTA_VERDICT_MAX + 1];
1527 struct nft_chain *chain;
1528 int err;
1529
1530 err = nla_parse_nested(tb, NFTA_VERDICT_MAX, nla, nft_verdict_policy);
1531 if (err < 0)
1532 return err;
1533
1534 if (!tb[NFTA_VERDICT_CODE])
1535 return -EINVAL;
1536 data->verdict = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE]));
1537
1538 switch (data->verdict) {
1539 case NF_ACCEPT:
1540 case NF_DROP:
1541 case NF_QUEUE:
1542 case NFT_CONTINUE:
1543 case NFT_BREAK:
1544 case NFT_RETURN:
1545 desc->len = sizeof(data->verdict);
1546 break;
1547 case NFT_JUMP:
1548 case NFT_GOTO:
1549 if (!tb[NFTA_VERDICT_CHAIN])
1550 return -EINVAL;
1551 chain = nf_tables_chain_lookup(ctx->table,
1552 tb[NFTA_VERDICT_CHAIN]);
1553 if (IS_ERR(chain))
1554 return PTR_ERR(chain);
1555 if (chain->flags & NFT_BASE_CHAIN)
1556 return -EOPNOTSUPP;
1557
1558 if (ctx->chain->level + 1 > chain->level) {
1559 if (ctx->chain->level + 1 == 16)
1560 return -EMLINK;
1561 chain->level = ctx->chain->level + 1;
1562 }
1563 chain->use++;
1564 data->chain = chain;
1565 desc->len = sizeof(data);
1566 break;
1567 default:
1568 return -EINVAL;
1569 }
1570
1571 desc->type = NFT_DATA_VERDICT;
1572 return 0;
1573}
1574
1575static void nft_verdict_uninit(const struct nft_data *data)
1576{
1577 switch (data->verdict) {
1578 case NFT_JUMP:
1579 case NFT_GOTO:
1580 data->chain->use--;
1581 break;
1582 }
1583}
1584
1585static int nft_verdict_dump(struct sk_buff *skb, const struct nft_data *data)
1586{
1587 struct nlattr *nest;
1588
1589 nest = nla_nest_start(skb, NFTA_DATA_VERDICT);
1590 if (!nest)
1591 goto nla_put_failure;
1592
1593 if (nla_put_be32(skb, NFTA_VERDICT_CODE, htonl(data->verdict)))
1594 goto nla_put_failure;
1595
1596 switch (data->verdict) {
1597 case NFT_JUMP:
1598 case NFT_GOTO:
1599 if (nla_put_string(skb, NFTA_VERDICT_CHAIN, data->chain->name))
1600 goto nla_put_failure;
1601 }
1602 nla_nest_end(skb, nest);
1603 return 0;
1604
1605nla_put_failure:
1606 return -1;
1607}
1608
1609static int nft_value_init(const struct nft_ctx *ctx, struct nft_data *data,
1610 struct nft_data_desc *desc, const struct nlattr *nla)
1611{
1612 unsigned int len;
1613
1614 len = nla_len(nla);
1615 if (len == 0)
1616 return -EINVAL;
1617 if (len > sizeof(data->data))
1618 return -EOVERFLOW;
1619
1620 nla_memcpy(data->data, nla, sizeof(data->data));
1621 desc->type = NFT_DATA_VALUE;
1622 desc->len = len;
1623 return 0;
1624}
1625
1626static int nft_value_dump(struct sk_buff *skb, const struct nft_data *data,
1627 unsigned int len)
1628{
1629 return nla_put(skb, NFTA_DATA_VALUE, len, data->data);
1630}
1631
1632static const struct nla_policy nft_data_policy[NFTA_DATA_MAX + 1] = {
1633 [NFTA_DATA_VALUE] = { .type = NLA_BINARY,
1634 .len = FIELD_SIZEOF(struct nft_data, data) },
1635 [NFTA_DATA_VERDICT] = { .type = NLA_NESTED },
1636};
1637
1638/**
1639 * nft_data_init - parse nf_tables data netlink attributes
1640 *
1641 * @ctx: context of the expression using the data
1642 * @data: destination struct nft_data
1643 * @desc: data description
1644 * @nla: netlink attribute containing data
1645 *
1646 * Parse the netlink data attributes and initialize a struct nft_data.
1647 * The type and length of data are returned in the data description.
1648 *
1649 * The caller can indicate that it only wants to accept data of type
1650 * NFT_DATA_VALUE by passing NULL for the ctx argument.
1651 */
1652int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data,
1653 struct nft_data_desc *desc, const struct nlattr *nla)
1654{
1655 struct nlattr *tb[NFTA_DATA_MAX + 1];
1656 int err;
1657
1658 err = nla_parse_nested(tb, NFTA_DATA_MAX, nla, nft_data_policy);
1659 if (err < 0)
1660 return err;
1661
1662 if (tb[NFTA_DATA_VALUE])
1663 return nft_value_init(ctx, data, desc, tb[NFTA_DATA_VALUE]);
1664 if (tb[NFTA_DATA_VERDICT] && ctx != NULL)
1665 return nft_verdict_init(ctx, data, desc, tb[NFTA_DATA_VERDICT]);
1666 return -EINVAL;
1667}
1668EXPORT_SYMBOL_GPL(nft_data_init);
1669
1670/**
1671 * nft_data_uninit - release a nft_data item
1672 *
1673 * @data: struct nft_data to release
1674 * @type: type of data
1675 *
1676 * Release a nft_data item. NFT_DATA_VALUE types can be silently discarded,
1677 * all others need to be released by calling this function.
1678 */
1679void nft_data_uninit(const struct nft_data *data, enum nft_data_types type)
1680{
1681 switch (type) {
1682 case NFT_DATA_VALUE:
1683 return;
1684 case NFT_DATA_VERDICT:
1685 return nft_verdict_uninit(data);
1686 default:
1687 WARN_ON(1);
1688 }
1689}
1690EXPORT_SYMBOL_GPL(nft_data_uninit);
1691
1692int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
1693 enum nft_data_types type, unsigned int len)
1694{
1695 struct nlattr *nest;
1696 int err;
1697
1698 nest = nla_nest_start(skb, attr);
1699 if (nest == NULL)
1700 return -1;
1701
1702 switch (type) {
1703 case NFT_DATA_VALUE:
1704 err = nft_value_dump(skb, data, len);
1705 break;
1706 case NFT_DATA_VERDICT:
1707 err = nft_verdict_dump(skb, data);
1708 break;
1709 default:
1710 err = -EINVAL;
1711 WARN_ON(1);
1712 }
1713
1714 nla_nest_end(skb, nest);
1715 return err;
1716}
1717EXPORT_SYMBOL_GPL(nft_data_dump);
1718
1719static int __init nf_tables_module_init(void)
1720{
1721 int err;
1722
1723 info = kmalloc(sizeof(struct nft_expr_info) * NFT_RULE_MAXEXPRS,
1724 GFP_KERNEL);
1725 if (info == NULL) {
1726 err = -ENOMEM;
1727 goto err1;
1728 }
1729
1730 err = nf_tables_core_module_init();
1731 if (err < 0)
1732 goto err2;
1733
1734 err = nfnetlink_subsys_register(&nf_tables_subsys);
1735 if (err < 0)
1736 goto err3;
1737
1738 pr_info("nf_tables: (c) 2007-2009 Patrick McHardy <kaber@trash.net>\n");
1739 return 0;
1740err3:
1741 nf_tables_core_module_exit();
1742err2:
1743 kfree(info);
1744err1:
1745 return err;
1746}
1747
1748static void __exit nf_tables_module_exit(void)
1749{
1750 nfnetlink_subsys_unregister(&nf_tables_subsys);
1751 nf_tables_core_module_exit();
1752 kfree(info);
1753}
1754
1755module_init(nf_tables_module_init);
1756module_exit(nf_tables_module_exit);
1757
1758MODULE_LICENSE("GPL");
1759MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
1760MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFTABLES);
diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
new file mode 100644
index 000000000000..bc7fb85d4002
--- /dev/null
+++ b/net/netfilter/nf_tables_core.c
@@ -0,0 +1,152 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/rculist.h>
15#include <linux/skbuff.h>
16#include <linux/netlink.h>
17#include <linux/netfilter.h>
18#include <linux/netfilter/nfnetlink.h>
19#include <linux/netfilter/nf_tables.h>
20#include <net/netfilter/nf_tables_core.h>
21#include <net/netfilter/nf_tables.h>
22
23#define NFT_JUMP_STACK_SIZE 16
24
25unsigned int nft_do_chain(const struct nf_hook_ops *ops,
26 struct sk_buff *skb,
27 const struct net_device *in,
28 const struct net_device *out,
29 int (*okfn)(struct sk_buff *))
30{
31 const struct nft_chain *chain = ops->priv;
32 const struct nft_rule *rule;
33 const struct nft_expr *expr, *last;
34 struct nft_data data[NFT_REG_MAX + 1];
35 const struct nft_pktinfo pkt = {
36 .skb = skb,
37 .in = in,
38 .out = out,
39 .hooknum = ops->hooknum,
40 };
41 unsigned int stackptr = 0;
42 struct {
43 const struct nft_chain *chain;
44 const struct nft_rule *rule;
45 } jumpstack[NFT_JUMP_STACK_SIZE];
46
47do_chain:
48 rule = list_entry(&chain->rules, struct nft_rule, list);
49next_rule:
50 data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
51 list_for_each_entry_continue_rcu(rule, &chain->rules, list) {
52 nft_rule_for_each_expr(expr, last, rule) {
53 expr->ops->eval(expr, data, &pkt);
54 if (data[NFT_REG_VERDICT].verdict != NFT_CONTINUE)
55 break;
56 }
57
58 switch (data[NFT_REG_VERDICT].verdict) {
59 case NFT_BREAK:
60 data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
61 /* fall through */
62 case NFT_CONTINUE:
63 continue;
64 }
65 break;
66 }
67
68 switch (data[NFT_REG_VERDICT].verdict) {
69 case NF_ACCEPT:
70 case NF_DROP:
71 case NF_QUEUE:
72 return data[NFT_REG_VERDICT].verdict;
73 case NFT_JUMP:
74 BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE);
75 jumpstack[stackptr].chain = chain;
76 jumpstack[stackptr].rule = rule;
77 stackptr++;
78 /* fall through */
79 case NFT_GOTO:
80 chain = data[NFT_REG_VERDICT].chain;
81 goto do_chain;
82 case NFT_RETURN:
83 case NFT_CONTINUE:
84 break;
85 default:
86 WARN_ON(1);
87 }
88
89 if (stackptr > 0) {
90 stackptr--;
91 chain = jumpstack[stackptr].chain;
92 rule = jumpstack[stackptr].rule;
93 goto next_rule;
94 }
95
96 return NF_ACCEPT;
97}
98EXPORT_SYMBOL_GPL(nft_do_chain);
99
100int __init nf_tables_core_module_init(void)
101{
102 int err;
103
104 err = nft_immediate_module_init();
105 if (err < 0)
106 goto err1;
107
108 err = nft_cmp_module_init();
109 if (err < 0)
110 goto err2;
111
112 err = nft_lookup_module_init();
113 if (err < 0)
114 goto err3;
115
116 err = nft_bitwise_module_init();
117 if (err < 0)
118 goto err4;
119
120 err = nft_byteorder_module_init();
121 if (err < 0)
122 goto err5;
123
124 err = nft_payload_module_init();
125 if (err < 0)
126 goto err6;
127
128 return 0;
129
130err6:
131 nft_byteorder_module_exit();
132err5:
133 nft_bitwise_module_exit();
134err4:
135 nft_lookup_module_exit();
136err3:
137 nft_cmp_module_exit();
138err2:
139 nft_immediate_module_exit();
140err1:
141 return err;
142}
143
144void nf_tables_core_module_exit(void)
145{
146 nft_payload_module_exit();
147 nft_byteorder_module_exit();
148 nft_bitwise_module_exit();
149 nft_lookup_module_exit();
150 nft_cmp_module_exit();
151 nft_immediate_module_exit();
152}
diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c
new file mode 100644
index 000000000000..0f7501506367
--- /dev/null
+++ b/net/netfilter/nft_bitwise.c
@@ -0,0 +1,140 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables_core.h>
18#include <net/netfilter/nf_tables.h>
19
20struct nft_bitwise {
21 enum nft_registers sreg:8;
22 enum nft_registers dreg:8;
23 u8 len;
24 struct nft_data mask;
25 struct nft_data xor;
26};
27
28static void nft_bitwise_eval(const struct nft_expr *expr,
29 struct nft_data data[NFT_REG_MAX + 1],
30 const struct nft_pktinfo *pkt)
31{
32 const struct nft_bitwise *priv = nft_expr_priv(expr);
33 const struct nft_data *src = &data[priv->sreg];
34 struct nft_data *dst = &data[priv->dreg];
35 unsigned int i;
36
37 for (i = 0; i < DIV_ROUND_UP(priv->len, 4); i++) {
38 dst->data[i] = (src->data[i] & priv->mask.data[i]) ^
39 priv->xor.data[i];
40 }
41}
42
43static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = {
44 [NFTA_BITWISE_SREG] = { .type = NLA_U32 },
45 [NFTA_BITWISE_DREG] = { .type = NLA_U32 },
46 [NFTA_BITWISE_LEN] = { .type = NLA_U32 },
47 [NFTA_BITWISE_MASK] = { .type = NLA_NESTED },
48 [NFTA_BITWISE_XOR] = { .type = NLA_NESTED },
49};
50
51static int nft_bitwise_init(const struct nft_ctx *ctx,
52 const struct nft_expr *expr,
53 const struct nlattr * const tb[])
54{
55 struct nft_bitwise *priv = nft_expr_priv(expr);
56 struct nft_data_desc d1, d2;
57 int err;
58
59 if (tb[NFTA_BITWISE_SREG] == NULL ||
60 tb[NFTA_BITWISE_DREG] == NULL ||
61 tb[NFTA_BITWISE_LEN] == NULL ||
62 tb[NFTA_BITWISE_MASK] == NULL ||
63 tb[NFTA_BITWISE_XOR] == NULL)
64 return -EINVAL;
65
66 priv->sreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_SREG]));
67 err = nft_validate_input_register(priv->sreg);
68 if (err < 0)
69 return err;
70
71 priv->dreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_DREG]));
72 err = nft_validate_output_register(priv->dreg);
73 if (err < 0)
74 return err;
75 err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
76 if (err < 0)
77 return err;
78
79 priv->len = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN]));
80
81 err = nft_data_init(NULL, &priv->mask, &d1, tb[NFTA_BITWISE_MASK]);
82 if (err < 0)
83 return err;
84 if (d1.len != priv->len)
85 return -EINVAL;
86
87 err = nft_data_init(NULL, &priv->xor, &d2, tb[NFTA_BITWISE_XOR]);
88 if (err < 0)
89 return err;
90 if (d2.len != priv->len)
91 return -EINVAL;
92
93 return 0;
94}
95
96static int nft_bitwise_dump(struct sk_buff *skb, const struct nft_expr *expr)
97{
98 const struct nft_bitwise *priv = nft_expr_priv(expr);
99
100 if (nla_put_be32(skb, NFTA_BITWISE_SREG, htonl(priv->sreg)))
101 goto nla_put_failure;
102 if (nla_put_be32(skb, NFTA_BITWISE_DREG, htonl(priv->dreg)))
103 goto nla_put_failure;
104 if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(priv->len)))
105 goto nla_put_failure;
106
107 if (nft_data_dump(skb, NFTA_BITWISE_MASK, &priv->mask,
108 NFT_DATA_VALUE, priv->len) < 0)
109 goto nla_put_failure;
110
111 if (nft_data_dump(skb, NFTA_BITWISE_XOR, &priv->xor,
112 NFT_DATA_VALUE, priv->len) < 0)
113 goto nla_put_failure;
114
115 return 0;
116
117nla_put_failure:
118 return -1;
119}
120
121static struct nft_expr_ops nft_bitwise_ops __read_mostly = {
122 .name = "bitwise",
123 .size = NFT_EXPR_SIZE(sizeof(struct nft_bitwise)),
124 .owner = THIS_MODULE,
125 .eval = nft_bitwise_eval,
126 .init = nft_bitwise_init,
127 .dump = nft_bitwise_dump,
128 .policy = nft_bitwise_policy,
129 .maxattr = NFTA_BITWISE_MAX,
130};
131
132int __init nft_bitwise_module_init(void)
133{
134 return nft_register_expr(&nft_bitwise_ops);
135}
136
137void nft_bitwise_module_exit(void)
138{
139 nft_unregister_expr(&nft_bitwise_ops);
140}
diff --git a/net/netfilter/nft_byteorder.c b/net/netfilter/nft_byteorder.c
new file mode 100644
index 000000000000..8b0657a4d17b
--- /dev/null
+++ b/net/netfilter/nft_byteorder.c
@@ -0,0 +1,167 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables_core.h>
18#include <net/netfilter/nf_tables.h>
19
20struct nft_byteorder {
21 enum nft_registers sreg:8;
22 enum nft_registers dreg:8;
23 enum nft_byteorder_ops op:8;
24 u8 len;
25 u8 size;
26};
27
28static void nft_byteorder_eval(const struct nft_expr *expr,
29 struct nft_data data[NFT_REG_MAX + 1],
30 const struct nft_pktinfo *pkt)
31{
32 const struct nft_byteorder *priv = nft_expr_priv(expr);
33 struct nft_data *src = &data[priv->sreg], *dst = &data[priv->dreg];
34 union { u32 u32; u16 u16; } *s, *d;
35 unsigned int i;
36
37 s = (void *)src->data;
38 d = (void *)dst->data;
39
40 switch (priv->size) {
41 case 4:
42 switch (priv->op) {
43 case NFT_BYTEORDER_NTOH:
44 for (i = 0; i < priv->len / 4; i++)
45 d[i].u32 = ntohl((__force __be32)s[i].u32);
46 break;
47 case NFT_BYTEORDER_HTON:
48 for (i = 0; i < priv->len / 4; i++)
49 d[i].u32 = (__force __u32)htonl(s[i].u32);
50 break;
51 }
52 break;
53 case 2:
54 switch (priv->op) {
55 case NFT_BYTEORDER_NTOH:
56 for (i = 0; i < priv->len / 2; i++)
57 d[i].u16 = ntohs((__force __be16)s[i].u16);
58 break;
59 case NFT_BYTEORDER_HTON:
60 for (i = 0; i < priv->len / 2; i++)
61 d[i].u16 = (__force __u16)htons(s[i].u16);
62 break;
63 }
64 break;
65 }
66}
67
68static const struct nla_policy nft_byteorder_policy[NFTA_BYTEORDER_MAX + 1] = {
69 [NFTA_BYTEORDER_SREG] = { .type = NLA_U32 },
70 [NFTA_BYTEORDER_DREG] = { .type = NLA_U32 },
71 [NFTA_BYTEORDER_OP] = { .type = NLA_U32 },
72 [NFTA_BYTEORDER_LEN] = { .type = NLA_U32 },
73 [NFTA_BYTEORDER_SIZE] = { .type = NLA_U32 },
74};
75
76static int nft_byteorder_init(const struct nft_ctx *ctx,
77 const struct nft_expr *expr,
78 const struct nlattr * const tb[])
79{
80 struct nft_byteorder *priv = nft_expr_priv(expr);
81 int err;
82
83 if (tb[NFTA_BYTEORDER_SREG] == NULL ||
84 tb[NFTA_BYTEORDER_DREG] == NULL ||
85 tb[NFTA_BYTEORDER_LEN] == NULL ||
86 tb[NFTA_BYTEORDER_SIZE] == NULL ||
87 tb[NFTA_BYTEORDER_OP] == NULL)
88 return -EINVAL;
89
90 priv->sreg = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SREG]));
91 err = nft_validate_input_register(priv->sreg);
92 if (err < 0)
93 return err;
94
95 priv->dreg = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_DREG]));
96 err = nft_validate_output_register(priv->dreg);
97 if (err < 0)
98 return err;
99 err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
100 if (err < 0)
101 return err;
102
103 priv->op = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_OP]));
104 switch (priv->op) {
105 case NFT_BYTEORDER_NTOH:
106 case NFT_BYTEORDER_HTON:
107 break;
108 default:
109 return -EINVAL;
110 }
111
112 priv->len = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_LEN]));
113 if (priv->len == 0 || priv->len > FIELD_SIZEOF(struct nft_data, data))
114 return -EINVAL;
115
116 priv->size = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SIZE]));
117 switch (priv->size) {
118 case 2:
119 case 4:
120 break;
121 default:
122 return -EINVAL;
123 }
124
125 return 0;
126}
127
128static int nft_byteorder_dump(struct sk_buff *skb, const struct nft_expr *expr)
129{
130 const struct nft_byteorder *priv = nft_expr_priv(expr);
131
132 if (nla_put_be32(skb, NFTA_BYTEORDER_SREG, htonl(priv->sreg)))
133 goto nla_put_failure;
134 if (nla_put_be32(skb, NFTA_BYTEORDER_DREG, htonl(priv->dreg)))
135 goto nla_put_failure;
136 if (nla_put_be32(skb, NFTA_BYTEORDER_OP, htonl(priv->op)))
137 goto nla_put_failure;
138 if (nla_put_be32(skb, NFTA_BYTEORDER_LEN, htonl(priv->len)))
139 goto nla_put_failure;
140 if (nla_put_be32(skb, NFTA_BYTEORDER_SIZE, htonl(priv->size)))
141 goto nla_put_failure;
142 return 0;
143
144nla_put_failure:
145 return -1;
146}
147
148static struct nft_expr_ops nft_byteorder_ops __read_mostly = {
149 .name = "byteorder",
150 .size = NFT_EXPR_SIZE(sizeof(struct nft_byteorder)),
151 .owner = THIS_MODULE,
152 .eval = nft_byteorder_eval,
153 .init = nft_byteorder_init,
154 .dump = nft_byteorder_dump,
155 .policy = nft_byteorder_policy,
156 .maxattr = NFTA_BYTEORDER_MAX,
157};
158
159int __init nft_byteorder_module_init(void)
160{
161 return nft_register_expr(&nft_byteorder_ops);
162}
163
164void nft_byteorder_module_exit(void)
165{
166 nft_unregister_expr(&nft_byteorder_ops);
167}
diff --git a/net/netfilter/nft_cmp.c b/net/netfilter/nft_cmp.c
new file mode 100644
index 000000000000..e734d670120a
--- /dev/null
+++ b/net/netfilter/nft_cmp.c
@@ -0,0 +1,146 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables_core.h>
18#include <net/netfilter/nf_tables.h>
19
20struct nft_cmp_expr {
21 struct nft_data data;
22 enum nft_registers sreg:8;
23 u8 len;
24 enum nft_cmp_ops op:8;
25};
26
27static void nft_cmp_eval(const struct nft_expr *expr,
28 struct nft_data data[NFT_REG_MAX + 1],
29 const struct nft_pktinfo *pkt)
30{
31 const struct nft_cmp_expr *priv = nft_expr_priv(expr);
32 int d;
33
34 d = nft_data_cmp(&data[priv->sreg], &priv->data, priv->len);
35 switch (priv->op) {
36 case NFT_CMP_EQ:
37 if (d != 0)
38 goto mismatch;
39 break;
40 case NFT_CMP_NEQ:
41 if (d == 0)
42 goto mismatch;
43 break;
44 case NFT_CMP_LT:
45 if (d == 0)
46 goto mismatch;
47 case NFT_CMP_LTE:
48 if (d > 0)
49 goto mismatch;
50 break;
51 case NFT_CMP_GT:
52 if (d == 0)
53 goto mismatch;
54 case NFT_CMP_GTE:
55 if (d < 0)
56 goto mismatch;
57 break;
58 }
59 return;
60
61mismatch:
62 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
63}
64
65static const struct nla_policy nft_cmp_policy[NFTA_CMP_MAX + 1] = {
66 [NFTA_CMP_SREG] = { .type = NLA_U32 },
67 [NFTA_CMP_OP] = { .type = NLA_U32 },
68 [NFTA_CMP_DATA] = { .type = NLA_NESTED },
69};
70
71static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
72 const struct nlattr * const tb[])
73{
74 struct nft_cmp_expr *priv = nft_expr_priv(expr);
75 struct nft_data_desc desc;
76 int err;
77
78 if (tb[NFTA_CMP_SREG] == NULL ||
79 tb[NFTA_CMP_OP] == NULL ||
80 tb[NFTA_CMP_DATA] == NULL)
81 return -EINVAL;
82
83 priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
84 err = nft_validate_input_register(priv->sreg);
85 if (err < 0)
86 return err;
87
88 priv->op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
89 switch (priv->op) {
90 case NFT_CMP_EQ:
91 case NFT_CMP_NEQ:
92 case NFT_CMP_LT:
93 case NFT_CMP_LTE:
94 case NFT_CMP_GT:
95 case NFT_CMP_GTE:
96 break;
97 default:
98 return -EINVAL;
99 }
100
101 err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_CMP_DATA]);
102 if (err < 0)
103 return err;
104
105 priv->len = desc.len;
106 return 0;
107}
108
109static int nft_cmp_dump(struct sk_buff *skb, const struct nft_expr *expr)
110{
111 const struct nft_cmp_expr *priv = nft_expr_priv(expr);
112
113 if (nla_put_be32(skb, NFTA_CMP_SREG, htonl(priv->sreg)))
114 goto nla_put_failure;
115 if (nla_put_be32(skb, NFTA_CMP_OP, htonl(priv->op)))
116 goto nla_put_failure;
117
118 if (nft_data_dump(skb, NFTA_CMP_DATA, &priv->data,
119 NFT_DATA_VALUE, priv->len) < 0)
120 goto nla_put_failure;
121 return 0;
122
123nla_put_failure:
124 return -1;
125}
126
127static struct nft_expr_ops nft_cmp_ops __read_mostly = {
128 .name = "cmp",
129 .size = NFT_EXPR_SIZE(sizeof(struct nft_cmp_expr)),
130 .owner = THIS_MODULE,
131 .eval = nft_cmp_eval,
132 .init = nft_cmp_init,
133 .dump = nft_cmp_dump,
134 .policy = nft_cmp_policy,
135 .maxattr = NFTA_CMP_MAX,
136};
137
138int __init nft_cmp_module_init(void)
139{
140 return nft_register_expr(&nft_cmp_ops);
141}
142
143void nft_cmp_module_exit(void)
144{
145 nft_unregister_expr(&nft_cmp_ops);
146}
diff --git a/net/netfilter/nft_counter.c b/net/netfilter/nft_counter.c
new file mode 100644
index 000000000000..33c5d36819bb
--- /dev/null
+++ b/net/netfilter/nft_counter.c
@@ -0,0 +1,107 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/seqlock.h>
15#include <linux/netlink.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter/nf_tables.h>
18#include <net/netfilter/nf_tables.h>
19
20struct nft_counter {
21 seqlock_t lock;
22 u64 bytes;
23 u64 packets;
24};
25
26static void nft_counter_eval(const struct nft_expr *expr,
27 struct nft_data data[NFT_REG_MAX + 1],
28 const struct nft_pktinfo *pkt)
29{
30 struct nft_counter *priv = nft_expr_priv(expr);
31
32 write_seqlock_bh(&priv->lock);
33 priv->bytes += pkt->skb->len;
34 priv->packets++;
35 write_sequnlock_bh(&priv->lock);
36}
37
38static int nft_counter_dump(struct sk_buff *skb, const struct nft_expr *expr)
39{
40 struct nft_counter *priv = nft_expr_priv(expr);
41 unsigned int seq;
42 u64 bytes;
43 u64 packets;
44
45 do {
46 seq = read_seqbegin(&priv->lock);
47 bytes = priv->bytes;
48 packets = priv->packets;
49 } while (read_seqretry(&priv->lock, seq));
50
51 if (nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(bytes)))
52 goto nla_put_failure;
53 if (nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(packets)))
54 goto nla_put_failure;
55 return 0;
56
57nla_put_failure:
58 return -1;
59}
60
61static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = {
62 [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 },
63 [NFTA_COUNTER_BYTES] = { .type = NLA_U64 },
64};
65
66static int nft_counter_init(const struct nft_ctx *ctx,
67 const struct nft_expr *expr,
68 const struct nlattr * const tb[])
69{
70 struct nft_counter *priv = nft_expr_priv(expr);
71
72 if (tb[NFTA_COUNTER_PACKETS])
73 priv->packets = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS]));
74 if (tb[NFTA_COUNTER_BYTES])
75 priv->bytes = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES]));
76
77 seqlock_init(&priv->lock);
78 return 0;
79}
80
81static struct nft_expr_ops nft_counter_ops __read_mostly = {
82 .name = "counter",
83 .size = NFT_EXPR_SIZE(sizeof(struct nft_counter)),
84 .policy = nft_counter_policy,
85 .maxattr = NFTA_COUNTER_MAX,
86 .owner = THIS_MODULE,
87 .eval = nft_counter_eval,
88 .init = nft_counter_init,
89 .dump = nft_counter_dump,
90};
91
92static int __init nft_counter_module_init(void)
93{
94 return nft_register_expr(&nft_counter_ops);
95}
96
97static void __exit nft_counter_module_exit(void)
98{
99 nft_unregister_expr(&nft_counter_ops);
100}
101
102module_init(nft_counter_module_init);
103module_exit(nft_counter_module_exit);
104
105MODULE_LICENSE("GPL");
106MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
107MODULE_ALIAS_NFT_EXPR("counter");
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
new file mode 100644
index 000000000000..a1756d678226
--- /dev/null
+++ b/net/netfilter/nft_ct.c
@@ -0,0 +1,252 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables.h>
18#include <net/netfilter/nf_conntrack.h>
19#include <net/netfilter/nf_conntrack_tuple.h>
20#include <net/netfilter/nf_conntrack_helper.h>
21
22struct nft_ct {
23 enum nft_ct_keys key:8;
24 enum ip_conntrack_dir dir:8;
25 enum nft_registers dreg:8;
26 uint8_t family;
27};
28
29static void nft_ct_eval(const struct nft_expr *expr,
30 struct nft_data data[NFT_REG_MAX + 1],
31 const struct nft_pktinfo *pkt)
32{
33 const struct nft_ct *priv = nft_expr_priv(expr);
34 struct nft_data *dest = &data[priv->dreg];
35 enum ip_conntrack_info ctinfo;
36 const struct nf_conn *ct;
37 const struct nf_conn_help *help;
38 const struct nf_conntrack_tuple *tuple;
39 const struct nf_conntrack_helper *helper;
40 long diff;
41 unsigned int state;
42
43 ct = nf_ct_get(pkt->skb, &ctinfo);
44
45 switch (priv->key) {
46 case NFT_CT_STATE:
47 if (ct == NULL)
48 state = NF_CT_STATE_INVALID_BIT;
49 else if (nf_ct_is_untracked(ct))
50 state = NF_CT_STATE_UNTRACKED_BIT;
51 else
52 state = NF_CT_STATE_BIT(ctinfo);
53 dest->data[0] = state;
54 return;
55 }
56
57 if (ct == NULL)
58 goto err;
59
60 switch (priv->key) {
61 case NFT_CT_DIRECTION:
62 dest->data[0] = CTINFO2DIR(ctinfo);
63 return;
64 case NFT_CT_STATUS:
65 dest->data[0] = ct->status;
66 return;
67#ifdef CONFIG_NF_CONNTRACK_MARK
68 case NFT_CT_MARK:
69 dest->data[0] = ct->mark;
70 return;
71#endif
72#ifdef CONFIG_NF_CONNTRACK_SECMARK
73 case NFT_CT_SECMARK:
74 dest->data[0] = ct->secmark;
75 return;
76#endif
77 case NFT_CT_EXPIRATION:
78 diff = (long)jiffies - (long)ct->timeout.expires;
79 if (diff < 0)
80 diff = 0;
81 dest->data[0] = jiffies_to_msecs(diff);
82 return;
83 case NFT_CT_HELPER:
84 if (ct->master == NULL)
85 goto err;
86 help = nfct_help(ct->master);
87 if (help == NULL)
88 goto err;
89 helper = rcu_dereference(help->helper);
90 if (helper == NULL)
91 goto err;
92 if (strlen(helper->name) >= sizeof(dest->data))
93 goto err;
94 strncpy((char *)dest->data, helper->name, sizeof(dest->data));
95 return;
96 }
97
98 tuple = &ct->tuplehash[priv->dir].tuple;
99 switch (priv->key) {
100 case NFT_CT_L3PROTOCOL:
101 dest->data[0] = nf_ct_l3num(ct);
102 return;
103 case NFT_CT_SRC:
104 memcpy(dest->data, tuple->src.u3.all,
105 nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
106 return;
107 case NFT_CT_DST:
108 memcpy(dest->data, tuple->dst.u3.all,
109 nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
110 return;
111 case NFT_CT_PROTOCOL:
112 dest->data[0] = nf_ct_protonum(ct);
113 return;
114 case NFT_CT_PROTO_SRC:
115 dest->data[0] = (__force __u16)tuple->src.u.all;
116 return;
117 case NFT_CT_PROTO_DST:
118 dest->data[0] = (__force __u16)tuple->dst.u.all;
119 return;
120 }
121 return;
122err:
123 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
124}
125
126static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = {
127 [NFTA_CT_DREG] = { .type = NLA_U32 },
128 [NFTA_CT_KEY] = { .type = NLA_U32 },
129 [NFTA_CT_DIRECTION] = { .type = NLA_U8 },
130};
131
132static int nft_ct_init(const struct nft_ctx *ctx,
133 const struct nft_expr *expr,
134 const struct nlattr * const tb[])
135{
136 struct nft_ct *priv = nft_expr_priv(expr);
137 int err;
138
139 if (tb[NFTA_CT_DREG] == NULL ||
140 tb[NFTA_CT_KEY] == NULL)
141 return -EINVAL;
142
143 priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
144 if (tb[NFTA_CT_DIRECTION] != NULL) {
145 priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
146 switch (priv->dir) {
147 case IP_CT_DIR_ORIGINAL:
148 case IP_CT_DIR_REPLY:
149 break;
150 default:
151 return -EINVAL;
152 }
153 }
154
155 switch (priv->key) {
156 case NFT_CT_STATE:
157 case NFT_CT_DIRECTION:
158 case NFT_CT_STATUS:
159#ifdef CONFIG_NF_CONNTRACK_MARK
160 case NFT_CT_MARK:
161#endif
162#ifdef CONFIG_NF_CONNTRACK_SECMARK
163 case NFT_CT_SECMARK:
164#endif
165 case NFT_CT_EXPIRATION:
166 case NFT_CT_HELPER:
167 if (tb[NFTA_CT_DIRECTION] != NULL)
168 return -EINVAL;
169 break;
170 case NFT_CT_PROTOCOL:
171 case NFT_CT_SRC:
172 case NFT_CT_DST:
173 case NFT_CT_PROTO_SRC:
174 case NFT_CT_PROTO_DST:
175 if (tb[NFTA_CT_DIRECTION] == NULL)
176 return -EINVAL;
177 break;
178 default:
179 return -EOPNOTSUPP;
180 }
181
182 err = nf_ct_l3proto_try_module_get(ctx->afi->family);
183 if (err < 0)
184 return err;
185 priv->family = ctx->afi->family;
186
187 priv->dreg = ntohl(nla_get_be32(tb[NFTA_CT_DREG]));
188 err = nft_validate_output_register(priv->dreg);
189 if (err < 0)
190 goto err1;
191
192 err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
193 if (err < 0)
194 goto err1;
195 return 0;
196
197err1:
198 nf_ct_l3proto_module_put(ctx->afi->family);
199 return err;
200}
201
202static void nft_ct_destroy(const struct nft_expr *expr)
203{
204 struct nft_ct *priv = nft_expr_priv(expr);
205
206 nf_ct_l3proto_module_put(priv->family);
207}
208
209static int nft_ct_dump(struct sk_buff *skb, const struct nft_expr *expr)
210{
211 const struct nft_ct *priv = nft_expr_priv(expr);
212
213 if (nla_put_be32(skb, NFTA_CT_DREG, htonl(priv->dreg)))
214 goto nla_put_failure;
215 if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
216 goto nla_put_failure;
217 if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
218 goto nla_put_failure;
219 return 0;
220
221nla_put_failure:
222 return -1;
223}
224
225static struct nft_expr_ops nft_ct_ops __read_mostly = {
226 .name = "ct",
227 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
228 .owner = THIS_MODULE,
229 .eval = nft_ct_eval,
230 .init = nft_ct_init,
231 .destroy = nft_ct_destroy,
232 .dump = nft_ct_dump,
233 .policy = nft_ct_policy,
234 .maxattr = NFTA_CT_MAX,
235};
236
237static int __init nft_ct_module_init(void)
238{
239 return nft_register_expr(&nft_ct_ops);
240}
241
242static void __exit nft_ct_module_exit(void)
243{
244 nft_unregister_expr(&nft_ct_ops);
245}
246
247module_init(nft_ct_module_init);
248module_exit(nft_ct_module_exit);
249
250MODULE_LICENSE("GPL");
251MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
252MODULE_ALIAS_NFT_EXPR("ct");
diff --git a/net/netfilter/nft_expr_template.c b/net/netfilter/nft_expr_template.c
new file mode 100644
index 000000000000..9fc8eb308193
--- /dev/null
+++ b/net/netfilter/nft_expr_template.c
@@ -0,0 +1,88 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/kernel.h>
12#include <linux/init.h>
13#include <linux/netlink.h>
14#include <linux/netfilter.h>
15#include <linux/netfilter/nf_tables.h>
16#include <net/netfilter/nf_tables.h>
17
18struct nft_template {
19
20};
21
22static void nft_template_eval(const struct nft_expr *expr,
23 struct nft_data data[NFT_REG_MAX + 1],
24 const struct nft_pktinfo *pkt)
25{
26 struct nft_template *priv = nft_expr_priv(expr);
27
28}
29
30static const struct nla_policy nft_template_policy[NFTA_TEMPLATE_MAX + 1] = {
31 [NFTA_TEMPLATE_ATTR] = { .type = NLA_U32 },
32};
33
34static int nft_template_init(const struct nft_ctx *ctx,
35 const struct nft_expr *expr,
36 const struct nlattr *tb[])
37{
38 struct nft_template *priv = nft_expr_priv(expr);
39
40 return 0;
41}
42
43static void nft_template_destroy(const struct nft_ctx *ctx,
44 const struct nft_expr *expr)
45{
46 struct nft_template *priv = nft_expr_priv(expr);
47
48}
49
50static int nft_template_dump(struct sk_buff *skb, const struct nft_expr *expr)
51{
52 const struct nft_template *priv = nft_expr_priv(expr);
53
54 NLA_PUT_BE32(skb, NFTA_TEMPLATE_ATTR, priv->field);
55 return 0;
56
57nla_put_failure:
58 return -1;
59}
60
61static struct nft_expr_ops template_ops __read_mostly = {
62 .name = "template",
63 .size = NFT_EXPR_SIZE(sizeof(struct nft_template)),
64 .owner = THIS_MODULE,
65 .eval = nft_template_eval,
66 .init = nft_template_init,
67 .destroy = nft_template_destroy,
68 .dump = nft_template_dump,
69 .policy = nft_template_policy,
70 .maxattr = NFTA_TEMPLATE_MAX,
71};
72
73static int __init nft_template_module_init(void)
74{
75 return nft_register_expr(&template_ops);
76}
77
78static void __exit nft_template_module_exit(void)
79{
80 nft_unregister_expr(&template_ops);
81}
82
83module_init(nft_template_module_init);
84module_exit(nft_template_module_exit);
85
86MODULE_LICENSE("GPL");
87MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
88MODULE_ALIAS_NFT_EXPR("template");
diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c
new file mode 100644
index 000000000000..21c6a6b7b662
--- /dev/null
+++ b/net/netfilter/nft_exthdr.c
@@ -0,0 +1,127 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables.h>
18// FIXME:
19#include <net/ipv6.h>
20
21struct nft_exthdr {
22 u8 type;
23 u8 offset;
24 u8 len;
25 enum nft_registers dreg:8;
26};
27
28static void nft_exthdr_eval(const struct nft_expr *expr,
29 struct nft_data data[NFT_REG_MAX + 1],
30 const struct nft_pktinfo *pkt)
31{
32 struct nft_exthdr *priv = nft_expr_priv(expr);
33 struct nft_data *dest = &data[priv->dreg];
34 unsigned int offset;
35 int err;
36
37 err = ipv6_find_hdr(pkt->skb, &offset, priv->type, NULL, NULL);
38 if (err < 0)
39 goto err;
40 offset += priv->offset;
41
42 if (skb_copy_bits(pkt->skb, offset, dest->data, priv->len) < 0)
43 goto err;
44 return;
45err:
46 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
47}
48
49static const struct nla_policy nft_exthdr_policy[NFTA_EXTHDR_MAX + 1] = {
50 [NFTA_EXTHDR_DREG] = { .type = NLA_U32 },
51 [NFTA_EXTHDR_TYPE] = { .type = NLA_U8 },
52 [NFTA_EXTHDR_OFFSET] = { .type = NLA_U32 },
53 [NFTA_EXTHDR_LEN] = { .type = NLA_U32 },
54};
55
56static int nft_exthdr_init(const struct nft_ctx *ctx,
57 const struct nft_expr *expr,
58 const struct nlattr * const tb[])
59{
60 struct nft_exthdr *priv = nft_expr_priv(expr);
61 int err;
62
63 if (tb[NFTA_EXTHDR_DREG] == NULL ||
64 tb[NFTA_EXTHDR_TYPE] == NULL ||
65 tb[NFTA_EXTHDR_OFFSET] == NULL ||
66 tb[NFTA_EXTHDR_LEN] == NULL)
67 return -EINVAL;
68
69 priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]);
70 priv->offset = ntohl(nla_get_be32(tb[NFTA_EXTHDR_OFFSET]));
71 priv->len = ntohl(nla_get_be32(tb[NFTA_EXTHDR_LEN]));
72 if (priv->len == 0 ||
73 priv->len > FIELD_SIZEOF(struct nft_data, data))
74 return -EINVAL;
75
76 priv->dreg = ntohl(nla_get_be32(tb[NFTA_EXTHDR_DREG]));
77 err = nft_validate_output_register(priv->dreg);
78 if (err < 0)
79 return err;
80 return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
81}
82
83static int nft_exthdr_dump(struct sk_buff *skb, const struct nft_expr *expr)
84{
85 const struct nft_exthdr *priv = nft_expr_priv(expr);
86
87 if (nla_put_be32(skb, NFTA_EXTHDR_DREG, htonl(priv->dreg)))
88 goto nla_put_failure;
89 if (nla_put_u8(skb, NFTA_EXTHDR_TYPE, priv->type))
90 goto nla_put_failure;
91 if (nla_put_be32(skb, NFTA_EXTHDR_OFFSET, htonl(priv->offset)))
92 goto nla_put_failure;
93 if (nla_put_be32(skb, NFTA_EXTHDR_LEN, htonl(priv->len)))
94 goto nla_put_failure;
95 return 0;
96
97nla_put_failure:
98 return -1;
99}
100
101static struct nft_expr_ops exthdr_ops __read_mostly = {
102 .name = "exthdr",
103 .size = NFT_EXPR_SIZE(sizeof(struct nft_exthdr)),
104 .owner = THIS_MODULE,
105 .eval = nft_exthdr_eval,
106 .init = nft_exthdr_init,
107 .dump = nft_exthdr_dump,
108 .policy = nft_exthdr_policy,
109 .maxattr = NFTA_EXTHDR_MAX,
110};
111
112static int __init nft_exthdr_module_init(void)
113{
114 return nft_register_expr(&exthdr_ops);
115}
116
117static void __exit nft_exthdr_module_exit(void)
118{
119 nft_unregister_expr(&exthdr_ops);
120}
121
122module_init(nft_exthdr_module_init);
123module_exit(nft_exthdr_module_exit);
124
125MODULE_LICENSE("GPL");
126MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
127MODULE_ALIAS_NFT_EXPR("exthdr");
diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c
new file mode 100644
index 000000000000..67cc502881f1
--- /dev/null
+++ b/net/netfilter/nft_hash.c
@@ -0,0 +1,348 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/list.h>
15#include <linux/jhash.h>
16#include <linux/netlink.h>
17#include <linux/netfilter.h>
18#include <linux/netfilter/nf_tables.h>
19#include <net/netfilter/nf_tables.h>
20
21struct nft_hash {
22 struct hlist_head *hash;
23 unsigned int hsize;
24 enum nft_registers sreg:8;
25 enum nft_registers dreg:8;
26 u8 klen;
27 u8 dlen;
28 u16 flags;
29};
30
31struct nft_hash_elem {
32 struct hlist_node hnode;
33 struct nft_data key;
34 struct nft_data data[];
35};
36
37static u32 nft_hash_rnd __read_mostly;
38static bool nft_hash_rnd_initted __read_mostly;
39
40static unsigned int nft_hash_data(const struct nft_data *data,
41 unsigned int hsize, unsigned int len)
42{
43 unsigned int h;
44
45 // FIXME: can we reasonably guarantee the upper bits are fixed?
46 h = jhash2(data->data, len >> 2, nft_hash_rnd);
47 return ((u64)h * hsize) >> 32;
48}
49
50static void nft_hash_eval(const struct nft_expr *expr,
51 struct nft_data data[NFT_REG_MAX + 1],
52 const struct nft_pktinfo *pkt)
53{
54 const struct nft_hash *priv = nft_expr_priv(expr);
55 const struct nft_hash_elem *elem;
56 const struct nft_data *key = &data[priv->sreg];
57 unsigned int h;
58
59 h = nft_hash_data(key, priv->hsize, priv->klen);
60 hlist_for_each_entry(elem, &priv->hash[h], hnode) {
61 if (nft_data_cmp(&elem->key, key, priv->klen))
62 continue;
63 if (priv->flags & NFT_HASH_MAP)
64 nft_data_copy(&data[priv->dreg], elem->data);
65 return;
66 }
67 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
68}
69
70static void nft_hash_elem_destroy(const struct nft_expr *expr,
71 struct nft_hash_elem *elem)
72{
73 const struct nft_hash *priv = nft_expr_priv(expr);
74
75 nft_data_uninit(&elem->key, NFT_DATA_VALUE);
76 if (priv->flags & NFT_HASH_MAP)
77 nft_data_uninit(elem->data, nft_dreg_to_type(priv->dreg));
78 kfree(elem);
79}
80
81static const struct nla_policy nft_he_policy[NFTA_HE_MAX + 1] = {
82 [NFTA_HE_KEY] = { .type = NLA_NESTED },
83 [NFTA_HE_DATA] = { .type = NLA_NESTED },
84};
85
86static int nft_hash_elem_init(const struct nft_ctx *ctx,
87 const struct nft_expr *expr,
88 const struct nlattr *nla,
89 struct nft_hash_elem **new)
90{
91 struct nft_hash *priv = nft_expr_priv(expr);
92 struct nlattr *tb[NFTA_HE_MAX + 1];
93 struct nft_hash_elem *elem;
94 struct nft_data_desc d1, d2;
95 unsigned int size;
96 int err;
97
98 err = nla_parse_nested(tb, NFTA_HE_MAX, nla, nft_he_policy);
99 if (err < 0)
100 return err;
101
102 if (tb[NFTA_HE_KEY] == NULL)
103 return -EINVAL;
104 size = sizeof(*elem);
105
106 if (priv->flags & NFT_HASH_MAP) {
107 if (tb[NFTA_HE_DATA] == NULL)
108 return -EINVAL;
109 size += sizeof(elem->data[0]);
110 } else {
111 if (tb[NFTA_HE_DATA] != NULL)
112 return -EINVAL;
113 }
114
115 elem = kzalloc(size, GFP_KERNEL);
116 if (elem == NULL)
117 return -ENOMEM;
118
119 err = nft_data_init(ctx, &elem->key, &d1, tb[NFTA_HE_KEY]);
120 if (err < 0)
121 goto err1;
122 err = -EINVAL;
123 if (d1.type != NFT_DATA_VALUE || d1.len != priv->klen)
124 goto err2;
125
126 if (tb[NFTA_HE_DATA] != NULL) {
127 err = nft_data_init(ctx, elem->data, &d2, tb[NFTA_HE_DATA]);
128 if (err < 0)
129 goto err2;
130 err = nft_validate_data_load(ctx, priv->dreg, elem->data, d2.type);
131 if (err < 0)
132 goto err3;
133 }
134
135 *new = elem;
136 return 0;
137
138err3:
139 nft_data_uninit(elem->data, d2.type);
140err2:
141 nft_data_uninit(&elem->key, d1.type);
142err1:
143 kfree(elem);
144 return err;
145}
146
147static int nft_hash_elem_dump(struct sk_buff *skb, const struct nft_expr *expr,
148 const struct nft_hash_elem *elem)
149
150{
151 const struct nft_hash *priv = nft_expr_priv(expr);
152 struct nlattr *nest;
153
154 nest = nla_nest_start(skb, NFTA_LIST_ELEM);
155 if (nest == NULL)
156 goto nla_put_failure;
157
158 if (nft_data_dump(skb, NFTA_HE_KEY, &elem->key,
159 NFT_DATA_VALUE, priv->klen) < 0)
160 goto nla_put_failure;
161
162 if (priv->flags & NFT_HASH_MAP) {
163 if (nft_data_dump(skb, NFTA_HE_DATA, elem->data,
164 NFT_DATA_VALUE, priv->dlen) < 0)
165 goto nla_put_failure;
166 }
167
168 nla_nest_end(skb, nest);
169 return 0;
170
171nla_put_failure:
172 return -1;
173}
174
175static void nft_hash_destroy(const struct nft_ctx *ctx,
176 const struct nft_expr *expr)
177{
178 const struct nft_hash *priv = nft_expr_priv(expr);
179 const struct hlist_node *next;
180 struct nft_hash_elem *elem;
181 unsigned int i;
182
183 for (i = 0; i < priv->hsize; i++) {
184 hlist_for_each_entry_safe(elem, next, &priv->hash[i], hnode) {
185 hlist_del(&elem->hnode);
186 nft_hash_elem_destroy(expr, elem);
187 }
188 }
189 kfree(priv->hash);
190}
191
192static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = {
193 [NFTA_HASH_FLAGS] = { .type = NLA_U32 },
194 [NFTA_HASH_SREG] = { .type = NLA_U32 },
195 [NFTA_HASH_DREG] = { .type = NLA_U32 },
196 [NFTA_HASH_KLEN] = { .type = NLA_U32 },
197 [NFTA_HASH_ELEMENTS] = { .type = NLA_NESTED },
198};
199
200static int nft_hash_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
201 const struct nlattr * const tb[])
202{
203 struct nft_hash *priv = nft_expr_priv(expr);
204 struct nft_hash_elem *elem, *uninitialized_var(new);
205 const struct nlattr *nla;
206 unsigned int cnt, i;
207 unsigned int h;
208 int err, rem;
209
210 if (unlikely(!nft_hash_rnd_initted)) {
211 get_random_bytes(&nft_hash_rnd, 4);
212 nft_hash_rnd_initted = true;
213 }
214
215 if (tb[NFTA_HASH_SREG] == NULL ||
216 tb[NFTA_HASH_KLEN] == NULL ||
217 tb[NFTA_HASH_ELEMENTS] == NULL)
218 return -EINVAL;
219
220 if (tb[NFTA_HASH_FLAGS] != NULL) {
221 priv->flags = ntohl(nla_get_be32(tb[NFTA_HASH_FLAGS]));
222 if (priv->flags & ~NFT_HASH_MAP)
223 return -EINVAL;
224 }
225
226 priv->sreg = ntohl(nla_get_be32(tb[NFTA_HASH_SREG]));
227 err = nft_validate_input_register(priv->sreg);
228 if (err < 0)
229 return err;
230
231 if (tb[NFTA_HASH_DREG] != NULL) {
232 if (!(priv->flags & NFT_HASH_MAP))
233 return -EINVAL;
234 priv->dreg = ntohl(nla_get_be32(tb[NFTA_HASH_DREG]));
235 err = nft_validate_output_register(priv->dreg);
236 if (err < 0)
237 return err;
238 }
239
240 priv->klen = ntohl(nla_get_be32(tb[NFTA_HASH_KLEN]));
241 if (priv->klen == 0)
242 return -EINVAL;
243
244 cnt = 0;
245 nla_for_each_nested(nla, tb[NFTA_HASH_ELEMENTS], rem) {
246 if (nla_type(nla) != NFTA_LIST_ELEM)
247 return -EINVAL;
248 cnt++;
249 }
250
251 /* Aim for a load factor of 0.75 */
252 cnt = cnt * 4 / 3;
253
254 priv->hash = kcalloc(cnt, sizeof(struct hlist_head), GFP_KERNEL);
255 if (priv->hash == NULL)
256 return -ENOMEM;
257 priv->hsize = cnt;
258
259 for (i = 0; i < cnt; i++)
260 INIT_HLIST_HEAD(&priv->hash[i]);
261
262 err = -ENOMEM;
263 nla_for_each_nested(nla, tb[NFTA_HASH_ELEMENTS], rem) {
264 err = nft_hash_elem_init(ctx, expr, nla, &new);
265 if (err < 0)
266 goto err1;
267
268 h = nft_hash_data(&new->key, priv->hsize, priv->klen);
269 hlist_for_each_entry(elem, &priv->hash[h], hnode) {
270 if (nft_data_cmp(&elem->key, &new->key, priv->klen))
271 continue;
272 nft_hash_elem_destroy(expr, new);
273 err = -EEXIST;
274 goto err1;
275 }
276 hlist_add_head(&new->hnode, &priv->hash[h]);
277 }
278 return 0;
279
280err1:
281 nft_hash_destroy(ctx, expr);
282 return err;
283}
284
285static int nft_hash_dump(struct sk_buff *skb, const struct nft_expr *expr)
286{
287 const struct nft_hash *priv = nft_expr_priv(expr);
288 const struct nft_hash_elem *elem;
289 struct nlattr *list;
290 unsigned int i;
291
292 if (priv->flags)
293 if (nla_put_be32(skb, NFTA_HASH_FLAGS, htonl(priv->flags)))
294 goto nla_put_failure;
295 if (nla_put_be32(skb, NFTA_HASH_SREG, htonl(priv->sreg)))
296 goto nla_put_failure;
297 if (priv->flags & NFT_HASH_MAP)
298 if (nla_put_be32(skb, NFTA_HASH_DREG, htonl(priv->dreg)))
299 goto nla_put_failure;
300 if (nla_put_be32(skb, NFTA_HASH_KLEN, htonl(priv->klen)))
301 goto nla_put_failure;
302
303 list = nla_nest_start(skb, NFTA_HASH_ELEMENTS);
304 if (list == NULL)
305 goto nla_put_failure;
306
307 for (i = 0; i < priv->hsize; i++) {
308 hlist_for_each_entry(elem, &priv->hash[i], hnode) {
309 if (nft_hash_elem_dump(skb, expr, elem) < 0)
310 goto nla_put_failure;
311 }
312 }
313
314 nla_nest_end(skb, list);
315 return 0;
316
317nla_put_failure:
318 return -1;
319}
320
321static struct nft_expr_ops nft_hash_ops __read_mostly = {
322 .name = "hash",
323 .size = NFT_EXPR_SIZE(sizeof(struct nft_hash)),
324 .owner = THIS_MODULE,
325 .eval = nft_hash_eval,
326 .init = nft_hash_init,
327 .destroy = nft_hash_destroy,
328 .dump = nft_hash_dump,
329 .policy = nft_hash_policy,
330 .maxattr = NFTA_HASH_MAX,
331};
332
333static int __init nft_hash_module_init(void)
334{
335 return nft_register_expr(&nft_hash_ops);
336}
337
338static void __exit nft_hash_module_exit(void)
339{
340 nft_unregister_expr(&nft_hash_ops);
341}
342
343module_init(nft_hash_module_init);
344module_exit(nft_hash_module_exit);
345
346MODULE_LICENSE("GPL");
347MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
348MODULE_ALIAS_NFT_EXPR("hash");
diff --git a/net/netfilter/nft_immediate.c b/net/netfilter/nft_immediate.c
new file mode 100644
index 000000000000..3bf42c3cc49a
--- /dev/null
+++ b/net/netfilter/nft_immediate.c
@@ -0,0 +1,113 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables_core.h>
18#include <net/netfilter/nf_tables.h>
19
20struct nft_immediate_expr {
21 struct nft_data data;
22 enum nft_registers dreg:8;
23 u8 dlen;
24};
25
26static void nft_immediate_eval(const struct nft_expr *expr,
27 struct nft_data data[NFT_REG_MAX + 1],
28 const struct nft_pktinfo *pkt)
29{
30 const struct nft_immediate_expr *priv = nft_expr_priv(expr);
31
32 nft_data_copy(&data[priv->dreg], &priv->data);
33}
34
35static const struct nla_policy nft_immediate_policy[NFTA_IMMEDIATE_MAX + 1] = {
36 [NFTA_IMMEDIATE_DREG] = { .type = NLA_U32 },
37 [NFTA_IMMEDIATE_DATA] = { .type = NLA_NESTED },
38};
39
40static int nft_immediate_init(const struct nft_ctx *ctx,
41 const struct nft_expr *expr,
42 const struct nlattr * const tb[])
43{
44 struct nft_immediate_expr *priv = nft_expr_priv(expr);
45 struct nft_data_desc desc;
46 int err;
47
48 if (tb[NFTA_IMMEDIATE_DREG] == NULL ||
49 tb[NFTA_IMMEDIATE_DATA] == NULL)
50 return -EINVAL;
51
52 priv->dreg = ntohl(nla_get_be32(tb[NFTA_IMMEDIATE_DREG]));
53 err = nft_validate_output_register(priv->dreg);
54 if (err < 0)
55 return err;
56
57 err = nft_data_init(ctx, &priv->data, &desc, tb[NFTA_IMMEDIATE_DATA]);
58 if (err < 0)
59 return err;
60 priv->dlen = desc.len;
61
62 err = nft_validate_data_load(ctx, priv->dreg, &priv->data, desc.type);
63 if (err < 0)
64 goto err1;
65
66 return 0;
67
68err1:
69 nft_data_uninit(&priv->data, desc.type);
70 return err;
71}
72
73static void nft_immediate_destroy(const struct nft_expr *expr)
74{
75 const struct nft_immediate_expr *priv = nft_expr_priv(expr);
76 return nft_data_uninit(&priv->data, nft_dreg_to_type(priv->dreg));
77}
78
79static int nft_immediate_dump(struct sk_buff *skb, const struct nft_expr *expr)
80{
81 const struct nft_immediate_expr *priv = nft_expr_priv(expr);
82
83 if (nla_put_be32(skb, NFTA_IMMEDIATE_DREG, htonl(priv->dreg)))
84 goto nla_put_failure;
85
86 return nft_data_dump(skb, NFTA_IMMEDIATE_DATA, &priv->data,
87 nft_dreg_to_type(priv->dreg), priv->dlen);
88
89nla_put_failure:
90 return -1;
91}
92
93static struct nft_expr_ops nft_imm_ops __read_mostly = {
94 .name = "immediate",
95 .size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)),
96 .owner = THIS_MODULE,
97 .eval = nft_immediate_eval,
98 .init = nft_immediate_init,
99 .destroy = nft_immediate_destroy,
100 .dump = nft_immediate_dump,
101 .policy = nft_immediate_policy,
102 .maxattr = NFTA_IMMEDIATE_MAX,
103};
104
105int __init nft_immediate_module_init(void)
106{
107 return nft_register_expr(&nft_imm_ops);
108}
109
110void nft_immediate_module_exit(void)
111{
112 nft_unregister_expr(&nft_imm_ops);
113}
diff --git a/net/netfilter/nft_limit.c b/net/netfilter/nft_limit.c
new file mode 100644
index 000000000000..e0e3fc8aebc3
--- /dev/null
+++ b/net/netfilter/nft_limit.c
@@ -0,0 +1,113 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/spinlock.h>
15#include <linux/netlink.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter/nf_tables.h>
18#include <net/netfilter/nf_tables.h>
19
20static DEFINE_SPINLOCK(limit_lock);
21
22struct nft_limit {
23 u64 tokens;
24 u64 rate;
25 u64 unit;
26 unsigned long stamp;
27};
28
29static void nft_limit_eval(const struct nft_expr *expr,
30 struct nft_data data[NFT_REG_MAX + 1],
31 const struct nft_pktinfo *pkt)
32{
33 struct nft_limit *priv = nft_expr_priv(expr);
34
35 spin_lock_bh(&limit_lock);
36 if (time_after_eq(jiffies, priv->stamp)) {
37 priv->tokens = priv->rate;
38 priv->stamp = jiffies + priv->unit * HZ;
39 }
40
41 if (priv->tokens >= 1) {
42 priv->tokens--;
43 spin_unlock_bh(&limit_lock);
44 return;
45 }
46 spin_unlock_bh(&limit_lock);
47
48 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
49}
50
51static const struct nla_policy nft_limit_policy[NFTA_LIMIT_MAX + 1] = {
52 [NFTA_LIMIT_RATE] = { .type = NLA_U64 },
53 [NFTA_LIMIT_UNIT] = { .type = NLA_U64 },
54};
55
56static int nft_limit_init(const struct nft_ctx *ctx,
57 const struct nft_expr *expr,
58 const struct nlattr * const tb[])
59{
60 struct nft_limit *priv = nft_expr_priv(expr);
61
62 if (tb[NFTA_LIMIT_RATE] == NULL ||
63 tb[NFTA_LIMIT_UNIT] == NULL)
64 return -EINVAL;
65
66 priv->rate = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_RATE]));
67 priv->unit = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_UNIT]));
68 priv->stamp = jiffies + priv->unit * HZ;
69 priv->tokens = priv->rate;
70 return 0;
71}
72
73static int nft_limit_dump(struct sk_buff *skb, const struct nft_expr *expr)
74{
75 const struct nft_limit *priv = nft_expr_priv(expr);
76
77 if (nla_put_be64(skb, NFTA_LIMIT_RATE, cpu_to_be64(priv->rate)))
78 goto nla_put_failure;
79 if (nla_put_be64(skb, NFTA_LIMIT_UNIT, cpu_to_be64(priv->unit)))
80 goto nla_put_failure;
81 return 0;
82
83nla_put_failure:
84 return -1;
85}
86
87static struct nft_expr_ops nft_limit_ops __read_mostly = {
88 .name = "limit",
89 .size = NFT_EXPR_SIZE(sizeof(struct nft_limit)),
90 .owner = THIS_MODULE,
91 .eval = nft_limit_eval,
92 .init = nft_limit_init,
93 .dump = nft_limit_dump,
94 .policy = nft_limit_policy,
95 .maxattr = NFTA_LIMIT_MAX,
96};
97
98static int __init nft_limit_module_init(void)
99{
100 return nft_register_expr(&nft_limit_ops);
101}
102
103static void __exit nft_limit_module_exit(void)
104{
105 nft_unregister_expr(&nft_limit_ops);
106}
107
108module_init(nft_limit_module_init);
109module_exit(nft_limit_module_exit);
110
111MODULE_LICENSE("GPL");
112MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
113MODULE_ALIAS_NFT_EXPR("limit");
diff --git a/net/netfilter/nft_log.c b/net/netfilter/nft_log.c
new file mode 100644
index 000000000000..da495c3b1e7e
--- /dev/null
+++ b/net/netfilter/nft_log.c
@@ -0,0 +1,140 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables.h>
18#include <net/netfilter/nf_log.h>
19#include <linux/netdevice.h>
20
21static const char *nft_log_null_prefix = "";
22
23struct nft_log {
24 struct nf_loginfo loginfo;
25 char *prefix;
26 int family;
27};
28
29static void nft_log_eval(const struct nft_expr *expr,
30 struct nft_data data[NFT_REG_MAX + 1],
31 const struct nft_pktinfo *pkt)
32{
33 const struct nft_log *priv = nft_expr_priv(expr);
34 struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
35
36 nf_log_packet(net, priv->family, pkt->hooknum, pkt->skb, pkt->in,
37 pkt->out, &priv->loginfo, "%s", priv->prefix);
38}
39
40static const struct nla_policy nft_log_policy[NFTA_LOG_MAX + 1] = {
41 [NFTA_LOG_GROUP] = { .type = NLA_U16 },
42 [NFTA_LOG_PREFIX] = { .type = NLA_STRING },
43 [NFTA_LOG_SNAPLEN] = { .type = NLA_U32 },
44 [NFTA_LOG_QTHRESHOLD] = { .type = NLA_U16 },
45};
46
47static int nft_log_init(const struct nft_ctx *ctx,
48 const struct nft_expr *expr,
49 const struct nlattr * const tb[])
50{
51 struct nft_log *priv = nft_expr_priv(expr);
52 struct nf_loginfo *li = &priv->loginfo;
53 const struct nlattr *nla;
54
55 priv->family = ctx->afi->family;
56
57 nla = tb[NFTA_LOG_PREFIX];
58 if (nla != NULL) {
59 priv->prefix = kmalloc(nla_len(nla) + 1, GFP_KERNEL);
60 if (priv->prefix == NULL)
61 return -ENOMEM;
62 nla_strlcpy(priv->prefix, nla, nla_len(nla) + 1);
63 } else
64 priv->prefix = (char *)nft_log_null_prefix;
65
66 li->type = NF_LOG_TYPE_ULOG;
67 if (tb[NFTA_LOG_GROUP] != NULL)
68 li->u.ulog.group = ntohs(nla_get_be16(tb[NFTA_LOG_GROUP]));
69
70 if (tb[NFTA_LOG_SNAPLEN] != NULL)
71 li->u.ulog.copy_len = ntohl(nla_get_be32(tb[NFTA_LOG_SNAPLEN]));
72 if (tb[NFTA_LOG_QTHRESHOLD] != NULL) {
73 li->u.ulog.qthreshold =
74 ntohs(nla_get_be16(tb[NFTA_LOG_QTHRESHOLD]));
75 }
76
77 return 0;
78}
79
80static void nft_log_destroy(const struct nft_expr *expr)
81{
82 struct nft_log *priv = nft_expr_priv(expr);
83
84 if (priv->prefix != nft_log_null_prefix)
85 kfree(priv->prefix);
86}
87
88static int nft_log_dump(struct sk_buff *skb, const struct nft_expr *expr)
89{
90 const struct nft_log *priv = nft_expr_priv(expr);
91 const struct nf_loginfo *li = &priv->loginfo;
92
93 if (priv->prefix != nft_log_null_prefix)
94 if (nla_put_string(skb, NFTA_LOG_PREFIX, priv->prefix))
95 goto nla_put_failure;
96 if (li->u.ulog.group)
97 if (nla_put_be16(skb, NFTA_LOG_GROUP, htons(li->u.ulog.group)))
98 goto nla_put_failure;
99 if (li->u.ulog.copy_len)
100 if (nla_put_be32(skb, NFTA_LOG_SNAPLEN,
101 htonl(li->u.ulog.copy_len)))
102 goto nla_put_failure;
103 if (li->u.ulog.qthreshold)
104 if (nla_put_be16(skb, NFTA_LOG_QTHRESHOLD,
105 htons(li->u.ulog.qthreshold)))
106 goto nla_put_failure;
107 return 0;
108
109nla_put_failure:
110 return -1;
111}
112
113static struct nft_expr_ops nft_log_ops __read_mostly = {
114 .name = "log",
115 .size = NFT_EXPR_SIZE(sizeof(struct nft_log)),
116 .owner = THIS_MODULE,
117 .eval = nft_log_eval,
118 .init = nft_log_init,
119 .destroy = nft_log_destroy,
120 .dump = nft_log_dump,
121 .policy = nft_log_policy,
122 .maxattr = NFTA_LOG_MAX,
123};
124
125static int __init nft_log_module_init(void)
126{
127 return nft_register_expr(&nft_log_ops);
128}
129
130static void __exit nft_log_module_exit(void)
131{
132 nft_unregister_expr(&nft_log_ops);
133}
134
135module_init(nft_log_module_init);
136module_exit(nft_log_module_exit);
137
138MODULE_LICENSE("GPL");
139MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
140MODULE_ALIAS_NFT_EXPR("log");
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
new file mode 100644
index 000000000000..96735aa2f039
--- /dev/null
+++ b/net/netfilter/nft_meta.c
@@ -0,0 +1,222 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/dst.h>
18#include <net/sock.h>
19#include <net/tcp_states.h> /* for TCP_TIME_WAIT */
20#include <net/netfilter/nf_tables.h>
21
22struct nft_meta {
23 enum nft_meta_keys key:8;
24 enum nft_registers dreg:8;
25};
26
27static void nft_meta_eval(const struct nft_expr *expr,
28 struct nft_data data[NFT_REG_MAX + 1],
29 const struct nft_pktinfo *pkt)
30{
31 const struct nft_meta *priv = nft_expr_priv(expr);
32 const struct sk_buff *skb = pkt->skb;
33 const struct net_device *in = pkt->in, *out = pkt->out;
34 struct nft_data *dest = &data[priv->dreg];
35
36 switch (priv->key) {
37 case NFT_META_LEN:
38 dest->data[0] = skb->len;
39 break;
40 case NFT_META_PROTOCOL:
41 *(__be16 *)dest->data = skb->protocol;
42 break;
43 case NFT_META_PRIORITY:
44 dest->data[0] = skb->priority;
45 break;
46 case NFT_META_MARK:
47 dest->data[0] = skb->mark;
48 break;
49 case NFT_META_IIF:
50 if (in == NULL)
51 goto err;
52 dest->data[0] = in->ifindex;
53 break;
54 case NFT_META_OIF:
55 if (out == NULL)
56 goto err;
57 dest->data[0] = out->ifindex;
58 break;
59 case NFT_META_IIFNAME:
60 if (in == NULL)
61 goto err;
62 strncpy((char *)dest->data, in->name, sizeof(dest->data));
63 break;
64 case NFT_META_OIFNAME:
65 if (out == NULL)
66 goto err;
67 strncpy((char *)dest->data, out->name, sizeof(dest->data));
68 break;
69 case NFT_META_IIFTYPE:
70 if (in == NULL)
71 goto err;
72 *(u16 *)dest->data = in->type;
73 break;
74 case NFT_META_OIFTYPE:
75 if (out == NULL)
76 goto err;
77 *(u16 *)dest->data = out->type;
78 break;
79 case NFT_META_SKUID:
80 if (skb->sk == NULL || skb->sk->sk_state == TCP_TIME_WAIT)
81 goto err;
82
83 read_lock_bh(&skb->sk->sk_callback_lock);
84 if (skb->sk->sk_socket == NULL ||
85 skb->sk->sk_socket->file == NULL) {
86 read_unlock_bh(&skb->sk->sk_callback_lock);
87 goto err;
88 }
89
90 dest->data[0] =
91 from_kuid_munged(&init_user_ns,
92 skb->sk->sk_socket->file->f_cred->fsuid);
93 read_unlock_bh(&skb->sk->sk_callback_lock);
94 break;
95 case NFT_META_SKGID:
96 if (skb->sk == NULL || skb->sk->sk_state == TCP_TIME_WAIT)
97 goto err;
98
99 read_lock_bh(&skb->sk->sk_callback_lock);
100 if (skb->sk->sk_socket == NULL ||
101 skb->sk->sk_socket->file == NULL) {
102 read_unlock_bh(&skb->sk->sk_callback_lock);
103 goto err;
104 }
105 dest->data[0] =
106 from_kgid_munged(&init_user_ns,
107 skb->sk->sk_socket->file->f_cred->fsgid);
108 read_unlock_bh(&skb->sk->sk_callback_lock);
109 break;
110#ifdef CONFIG_NET_CLS_ROUTE
111 case NFT_META_RTCLASSID: {
112 const struct dst_entry *dst = skb_dst(skb);
113
114 if (dst == NULL)
115 goto err;
116 dest->data[0] = dst->tclassid;
117 break;
118 }
119#endif
120#ifdef CONFIG_NETWORK_SECMARK
121 case NFT_META_SECMARK:
122 dest->data[0] = skb->secmark;
123 break;
124#endif
125 default:
126 WARN_ON(1);
127 goto err;
128 }
129 return;
130
131err:
132 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
133}
134
135static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = {
136 [NFTA_META_DREG] = { .type = NLA_U32 },
137 [NFTA_META_KEY] = { .type = NLA_U32 },
138};
139
140static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
141 const struct nlattr * const tb[])
142{
143 struct nft_meta *priv = nft_expr_priv(expr);
144 int err;
145
146 if (tb[NFTA_META_DREG] == NULL ||
147 tb[NFTA_META_KEY] == NULL)
148 return -EINVAL;
149
150 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
151 switch (priv->key) {
152 case NFT_META_LEN:
153 case NFT_META_PROTOCOL:
154 case NFT_META_PRIORITY:
155 case NFT_META_MARK:
156 case NFT_META_IIF:
157 case NFT_META_OIF:
158 case NFT_META_IIFNAME:
159 case NFT_META_OIFNAME:
160 case NFT_META_IIFTYPE:
161 case NFT_META_OIFTYPE:
162 case NFT_META_SKUID:
163 case NFT_META_SKGID:
164#ifdef CONFIG_NET_CLS_ROUTE
165 case NFT_META_RTCLASSID:
166#endif
167#ifdef CONFIG_NETWORK_SECMARK
168 case NFT_META_SECMARK:
169#endif
170 break;
171 default:
172 return -EOPNOTSUPP;
173 }
174
175 priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG]));
176 err = nft_validate_output_register(priv->dreg);
177 if (err < 0)
178 return err;
179 return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
180}
181
182static int nft_meta_dump(struct sk_buff *skb, const struct nft_expr *expr)
183{
184 const struct nft_meta *priv = nft_expr_priv(expr);
185
186 if (nla_put_be32(skb, NFTA_META_DREG, htonl(priv->dreg)))
187 goto nla_put_failure;
188 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
189 goto nla_put_failure;
190 return 0;
191
192nla_put_failure:
193 return -1;
194}
195
196static struct nft_expr_ops nft_meta_ops __read_mostly = {
197 .name = "meta",
198 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
199 .owner = THIS_MODULE,
200 .eval = nft_meta_eval,
201 .init = nft_meta_init,
202 .dump = nft_meta_dump,
203 .policy = nft_meta_policy,
204 .maxattr = NFTA_META_MAX,
205};
206
207static int __init nft_meta_module_init(void)
208{
209 return nft_register_expr(&nft_meta_ops);
210}
211
212static void __exit nft_meta_module_exit(void)
213{
214 nft_unregister_expr(&nft_meta_ops);
215}
216
217module_init(nft_meta_module_init);
218module_exit(nft_meta_module_exit);
219
220MODULE_LICENSE("GPL");
221MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
222MODULE_ALIAS_NFT_EXPR("meta");
diff --git a/net/netfilter/nft_meta_target.c b/net/netfilter/nft_meta_target.c
new file mode 100644
index 000000000000..71177df75ffb
--- /dev/null
+++ b/net/netfilter/nft_meta_target.c
@@ -0,0 +1,117 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/kernel.h>
12#include <linux/init.h>
13#include <linux/list.h>
14#include <linux/rbtree.h>
15#include <linux/netlink.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter/nf_tables.h>
18#include <net/netfilter/nf_tables.h>
19
20struct nft_meta {
21 enum nft_meta_keys key;
22};
23
24static void nft_meta_eval(const struct nft_expr *expr,
25 struct nft_data *nfres,
26 struct nft_data *data,
27 const struct nft_pktinfo *pkt)
28{
29 const struct nft_meta *meta = nft_expr_priv(expr);
30 struct sk_buff *skb = pkt->skb;
31 u32 val = data->data[0];
32
33 switch (meta->key) {
34 case NFT_META_MARK:
35 skb->mark = val;
36 break;
37 case NFT_META_PRIORITY:
38 skb->priority = val;
39 break;
40 case NFT_META_NFTRACE:
41 skb->nf_trace = val;
42 break;
43#ifdef CONFIG_NETWORK_SECMARK
44 case NFT_META_SECMARK:
45 skb->secmark = val;
46 break;
47#endif
48 default:
49 WARN_ON(1);
50 }
51}
52
53static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = {
54 [NFTA_META_KEY] = { .type = NLA_U32 },
55};
56
57static int nft_meta_init(const struct nft_expr *expr, struct nlattr *tb[])
58{
59 struct nft_meta *meta = nft_expr_priv(expr);
60
61 if (tb[NFTA_META_KEY] == NULL)
62 return -EINVAL;
63
64 meta->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
65 switch (meta->key) {
66 case NFT_META_MARK:
67 case NFT_META_PRIORITY:
68 case NFT_META_NFTRACE:
69#ifdef CONFIG_NETWORK_SECMARK
70 case NFT_META_SECMARK:
71#endif
72 break;
73 default:
74 return -EINVAL;
75 }
76
77 return 0;
78}
79
80static int nft_meta_dump(struct sk_buff *skb, const struct nft_expr *expr)
81{
82 struct nft_meta *meta = nft_expr_priv(expr);
83
84 NLA_PUT_BE32(skb, NFTA_META_KEY, htonl(meta->key));
85 return 0;
86
87nla_put_failure:
88 return -1;
89}
90
91static struct nft_expr_ops meta_target __read_mostly = {
92 .name = "meta",
93 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
94 .owner = THIS_MODULE,
95 .eval = nft_meta_eval,
96 .init = nft_meta_init,
97 .dump = nft_meta_dump,
98 .policy = nft_meta_policy,
99 .maxattr = NFTA_META_MAX,
100};
101
102static int __init nft_meta_target_init(void)
103{
104 return nft_register_expr(&meta_target);
105}
106
107static void __exit nft_meta_target_exit(void)
108{
109 nft_unregister_expr(&meta_target);
110}
111
112module_init(nft_meta_target_init);
113module_exit(nft_meta_target_exit);
114
115MODULE_LICENSE("GPL");
116MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
117MODULE_ALIAS_NFT_EXPR("meta");
diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
new file mode 100644
index 000000000000..329f134b3f89
--- /dev/null
+++ b/net/netfilter/nft_payload.c
@@ -0,0 +1,137 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
17#include <net/netfilter/nf_tables_core.h>
18#include <net/netfilter/nf_tables.h>
19
20struct nft_payload {
21 enum nft_payload_bases base:8;
22 u8 offset;
23 u8 len;
24 enum nft_registers dreg:8;
25};
26
27static void nft_payload_eval(const struct nft_expr *expr,
28 struct nft_data data[NFT_REG_MAX + 1],
29 const struct nft_pktinfo *pkt)
30{
31 const struct nft_payload *priv = nft_expr_priv(expr);
32 const struct sk_buff *skb = pkt->skb;
33 struct nft_data *dest = &data[priv->dreg];
34 int offset;
35
36 switch (priv->base) {
37 case NFT_PAYLOAD_LL_HEADER:
38 if (!skb_mac_header_was_set(skb))
39 goto err;
40 offset = skb_mac_header(skb) - skb->data;
41 break;
42 case NFT_PAYLOAD_NETWORK_HEADER:
43 offset = skb_network_offset(skb);
44 break;
45 case NFT_PAYLOAD_TRANSPORT_HEADER:
46 offset = skb_transport_offset(skb);
47 break;
48 default:
49 BUG();
50 }
51 offset += priv->offset;
52
53 if (skb_copy_bits(skb, offset, dest->data, priv->len) < 0)
54 goto err;
55 return;
56err:
57 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
58}
59
60static const struct nla_policy nft_payload_policy[NFTA_PAYLOAD_MAX + 1] = {
61 [NFTA_PAYLOAD_DREG] = { .type = NLA_U32 },
62 [NFTA_PAYLOAD_BASE] = { .type = NLA_U32 },
63 [NFTA_PAYLOAD_OFFSET] = { .type = NLA_U32 },
64 [NFTA_PAYLOAD_LEN] = { .type = NLA_U32 },
65};
66
67static int nft_payload_init(const struct nft_ctx *ctx,
68 const struct nft_expr *expr,
69 const struct nlattr * const tb[])
70{
71 struct nft_payload *priv = nft_expr_priv(expr);
72 int err;
73
74 if (tb[NFTA_PAYLOAD_DREG] == NULL ||
75 tb[NFTA_PAYLOAD_BASE] == NULL ||
76 tb[NFTA_PAYLOAD_OFFSET] == NULL ||
77 tb[NFTA_PAYLOAD_LEN] == NULL)
78 return -EINVAL;
79
80 priv->base = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE]));
81 switch (priv->base) {
82 case NFT_PAYLOAD_LL_HEADER:
83 case NFT_PAYLOAD_NETWORK_HEADER:
84 case NFT_PAYLOAD_TRANSPORT_HEADER:
85 break;
86 default:
87 return -EOPNOTSUPP;
88 }
89
90 priv->offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
91 priv->len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
92 if (priv->len == 0 ||
93 priv->len > FIELD_SIZEOF(struct nft_data, data))
94 return -EINVAL;
95
96 priv->dreg = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_DREG]));
97 err = nft_validate_output_register(priv->dreg);
98 if (err < 0)
99 return err;
100 return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
101}
102
103static int nft_payload_dump(struct sk_buff *skb, const struct nft_expr *expr)
104{
105 const struct nft_payload *priv = nft_expr_priv(expr);
106
107 if (nla_put_be32(skb, NFTA_PAYLOAD_DREG, htonl(priv->dreg)) ||
108 nla_put_be32(skb, NFTA_PAYLOAD_BASE, htonl(priv->base)) ||
109 nla_put_be32(skb, NFTA_PAYLOAD_OFFSET, htonl(priv->offset)) ||
110 nla_put_be32(skb, NFTA_PAYLOAD_LEN, htonl(priv->len)))
111 goto nla_put_failure;
112 return 0;
113
114nla_put_failure:
115 return -1;
116}
117
118static struct nft_expr_ops nft_payload_ops __read_mostly = {
119 .name = "payload",
120 .size = NFT_EXPR_SIZE(sizeof(struct nft_payload)),
121 .owner = THIS_MODULE,
122 .eval = nft_payload_eval,
123 .init = nft_payload_init,
124 .dump = nft_payload_dump,
125 .policy = nft_payload_policy,
126 .maxattr = NFTA_PAYLOAD_MAX,
127};
128
129int __init nft_payload_module_init(void)
130{
131 return nft_register_expr(&nft_payload_ops);
132}
133
134void nft_payload_module_exit(void)
135{
136 nft_unregister_expr(&nft_payload_ops);
137}
diff --git a/net/netfilter/nft_set.c b/net/netfilter/nft_set.c
new file mode 100644
index 000000000000..7b7c8354c327
--- /dev/null
+++ b/net/netfilter/nft_set.c
@@ -0,0 +1,381 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
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/kernel.h>
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/list.h>
15#include <linux/rbtree.h>
16#include <linux/netlink.h>
17#include <linux/netfilter.h>
18#include <linux/netfilter/nf_tables.h>
19#include <net/netfilter/nf_tables.h>
20
21struct nft_set {
22 struct rb_root root;
23 enum nft_registers sreg:8;
24 enum nft_registers dreg:8;
25 u8 klen;
26 u8 dlen;
27 u16 flags;
28};
29
30struct nft_set_elem {
31 struct rb_node node;
32 enum nft_set_elem_flags flags;
33 struct nft_data key;
34 struct nft_data data[];
35};
36
37static void nft_set_eval(const struct nft_expr *expr,
38 struct nft_data data[NFT_REG_MAX + 1],
39 const struct nft_pktinfo *pkt)
40{
41 const struct nft_set *priv = nft_expr_priv(expr);
42 const struct rb_node *parent = priv->root.rb_node;
43 const struct nft_set_elem *elem, *interval = NULL;
44 const struct nft_data *key = &data[priv->sreg];
45 int d;
46
47 while (parent != NULL) {
48 elem = rb_entry(parent, struct nft_set_elem, node);
49
50 d = nft_data_cmp(&elem->key, key, priv->klen);
51 if (d < 0) {
52 parent = parent->rb_left;
53 interval = elem;
54 } else if (d > 0)
55 parent = parent->rb_right;
56 else {
57found:
58 if (elem->flags & NFT_SE_INTERVAL_END)
59 goto out;
60 if (priv->flags & NFT_SET_MAP)
61 nft_data_copy(&data[priv->dreg], elem->data);
62 return;
63 }
64 }
65
66 if (priv->flags & NFT_SET_INTERVAL && interval != NULL) {
67 elem = interval;
68 goto found;
69 }
70out:
71 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
72}
73
74static void nft_set_elem_destroy(const struct nft_expr *expr,
75 struct nft_set_elem *elem)
76{
77 const struct nft_set *priv = nft_expr_priv(expr);
78
79 nft_data_uninit(&elem->key, NFT_DATA_VALUE);
80 if (priv->flags & NFT_SET_MAP)
81 nft_data_uninit(elem->data, nft_dreg_to_type(priv->dreg));
82 kfree(elem);
83}
84
85static const struct nla_policy nft_se_policy[NFTA_SE_MAX + 1] = {
86 [NFTA_SE_KEY] = { .type = NLA_NESTED },
87 [NFTA_SE_DATA] = { .type = NLA_NESTED },
88 [NFTA_SE_FLAGS] = { .type = NLA_U32 },
89};
90
91static int nft_set_elem_init(const struct nft_ctx *ctx,
92 const struct nft_expr *expr,
93 const struct nlattr *nla,
94 struct nft_set_elem **new)
95{
96 struct nft_set *priv = nft_expr_priv(expr);
97 struct nlattr *tb[NFTA_SE_MAX + 1];
98 struct nft_set_elem *elem;
99 struct nft_data_desc d1, d2;
100 enum nft_set_elem_flags flags = 0;
101 unsigned int size;
102 int err;
103
104 err = nla_parse_nested(tb, NFTA_SE_MAX, nla, nft_se_policy);
105 if (err < 0)
106 return err;
107
108 if (tb[NFTA_SE_KEY] == NULL)
109 return -EINVAL;
110
111 if (tb[NFTA_SE_FLAGS] != NULL) {
112 flags = ntohl(nla_get_be32(tb[NFTA_SE_FLAGS]));
113 if (flags & ~NFT_SE_INTERVAL_END)
114 return -EINVAL;
115 }
116
117 size = sizeof(*elem);
118 if (priv->flags & NFT_SET_MAP) {
119 if (tb[NFTA_SE_DATA] == NULL && !(flags & NFT_SE_INTERVAL_END))
120 return -EINVAL;
121 size += sizeof(elem->data[0]);
122 } else {
123 if (tb[NFTA_SE_DATA] != NULL)
124 return -EINVAL;
125 }
126
127 elem = kzalloc(size, GFP_KERNEL);
128 if (elem == NULL)
129 return -ENOMEM;
130 elem->flags = flags;
131
132 err = nft_data_init(ctx, &elem->key, &d1, tb[NFTA_SE_KEY]);
133 if (err < 0)
134 goto err1;
135 err = -EINVAL;
136 if (d1.type != NFT_DATA_VALUE || d1.len != priv->klen)
137 goto err2;
138
139 if (tb[NFTA_SE_DATA] != NULL) {
140 err = nft_data_init(ctx, elem->data, &d2, tb[NFTA_SE_DATA]);
141 if (err < 0)
142 goto err2;
143 err = -EINVAL;
144 if (priv->dreg != NFT_REG_VERDICT && d2.len != priv->dlen)
145 goto err2;
146 err = nft_validate_data_load(ctx, priv->dreg, elem->data, d2.type);
147 if (err < 0)
148 goto err3;
149 }
150
151 *new = elem;
152 return 0;
153
154err3:
155 nft_data_uninit(elem->data, d2.type);
156err2:
157 nft_data_uninit(&elem->key, d1.type);
158err1:
159 kfree(elem);
160 return err;
161}
162
163static int nft_set_elem_dump(struct sk_buff *skb, const struct nft_expr *expr,
164 const struct nft_set_elem *elem)
165
166{
167 const struct nft_set *priv = nft_expr_priv(expr);
168 struct nlattr *nest;
169
170 nest = nla_nest_start(skb, NFTA_LIST_ELEM);
171 if (nest == NULL)
172 goto nla_put_failure;
173
174 if (nft_data_dump(skb, NFTA_SE_KEY, &elem->key,
175 NFT_DATA_VALUE, priv->klen) < 0)
176 goto nla_put_failure;
177
178 if (priv->flags & NFT_SET_MAP && !(elem->flags & NFT_SE_INTERVAL_END)) {
179 if (nft_data_dump(skb, NFTA_SE_DATA, elem->data,
180 nft_dreg_to_type(priv->dreg), priv->dlen) < 0)
181 goto nla_put_failure;
182 }
183
184 if (elem->flags){
185 if (nla_put_be32(skb, NFTA_SE_FLAGS, htonl(elem->flags)))
186 goto nla_put_failure;
187 }
188
189 nla_nest_end(skb, nest);
190 return 0;
191
192nla_put_failure:
193 return -1;
194}
195
196static void nft_set_destroy(const struct nft_expr *expr)
197{
198 struct nft_set *priv = nft_expr_priv(expr);
199 struct nft_set_elem *elem;
200 struct rb_node *node;
201
202 while ((node = priv->root.rb_node) != NULL) {
203 rb_erase(node, &priv->root);
204 elem = rb_entry(node, struct nft_set_elem, node);
205 nft_set_elem_destroy(expr, elem);
206 }
207}
208
209static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
210 [NFTA_SET_FLAGS] = { .type = NLA_U32 },
211 [NFTA_SET_SREG] = { .type = NLA_U32 },
212 [NFTA_SET_DREG] = { .type = NLA_U32 },
213 [NFTA_SET_KLEN] = { .type = NLA_U32 },
214 [NFTA_SET_DLEN] = { .type = NLA_U32 },
215 [NFTA_SET_ELEMENTS] = { .type = NLA_NESTED },
216};
217
218static int nft_set_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
219 const struct nlattr * const tb[])
220{
221 struct nft_set *priv = nft_expr_priv(expr);
222 struct nft_set_elem *elem, *uninitialized_var(new);
223 struct rb_node *parent, **p;
224 const struct nlattr *nla;
225 int err, rem, d;
226
227 if (tb[NFTA_SET_SREG] == NULL ||
228 tb[NFTA_SET_KLEN] == NULL ||
229 tb[NFTA_SET_ELEMENTS] == NULL)
230 return -EINVAL;
231
232 priv->root = RB_ROOT;
233
234 if (tb[NFTA_SET_FLAGS] != NULL) {
235 priv->flags = ntohl(nla_get_be32(tb[NFTA_SET_FLAGS]));
236 if (priv->flags & ~(NFT_SET_INTERVAL | NFT_SET_MAP))
237 return -EINVAL;
238 }
239
240 priv->sreg = ntohl(nla_get_be32(tb[NFTA_SET_SREG]));
241 err = nft_validate_input_register(priv->sreg);
242 if (err < 0)
243 return err;
244
245 if (tb[NFTA_SET_DREG] != NULL) {
246 if (!(priv->flags & NFT_SET_MAP))
247 return -EINVAL;
248 if (tb[NFTA_SET_DLEN] == NULL)
249 return -EINVAL;
250
251 priv->dreg = ntohl(nla_get_be32(tb[NFTA_SET_DREG]));
252 err = nft_validate_output_register(priv->dreg);
253 if (err < 0)
254 return err;
255
256 if (priv->dreg == NFT_REG_VERDICT)
257 priv->dlen = FIELD_SIZEOF(struct nft_data, data);
258 else {
259 priv->dlen = ntohl(nla_get_be32(tb[NFTA_SET_DLEN]));
260 if (priv->dlen == 0 ||
261 priv->dlen > FIELD_SIZEOF(struct nft_data, data))
262 return -EINVAL;
263 }
264 } else {
265 if (priv->flags & NFT_SET_MAP)
266 return -EINVAL;
267 if (tb[NFTA_SET_DLEN] != NULL)
268 return -EINVAL;
269 }
270
271 priv->klen = ntohl(nla_get_be32(tb[NFTA_SET_KLEN]));
272 if (priv->klen == 0 ||
273 priv->klen > FIELD_SIZEOF(struct nft_data, data))
274 return -EINVAL;
275
276 nla_for_each_nested(nla, tb[NFTA_SET_ELEMENTS], rem) {
277 err = -EINVAL;
278 if (nla_type(nla) != NFTA_LIST_ELEM)
279 goto err1;
280
281 err = nft_set_elem_init(ctx, expr, nla, &new);
282 if (err < 0)
283 goto err1;
284
285 parent = NULL;
286 p = &priv->root.rb_node;
287 while (*p != NULL) {
288 parent = *p;
289 elem = rb_entry(parent, struct nft_set_elem, node);
290 d = nft_data_cmp(&elem->key, &new->key, priv->klen);
291 if (d < 0)
292 p = &parent->rb_left;
293 else if (d > 0)
294 p = &parent->rb_right;
295 else {
296 err = -EEXIST;
297 goto err2;
298 }
299 }
300 rb_link_node(&new->node, parent, p);
301 rb_insert_color(&new->node, &priv->root);
302 }
303
304 return 0;
305
306err2:
307 nft_set_elem_destroy(expr, new);
308err1:
309 nft_set_destroy(expr);
310 return err;
311}
312
313static int nft_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
314{
315 struct nft_set *priv = nft_expr_priv(expr);
316 const struct nft_set_elem *elem;
317 struct rb_node *node;
318 struct nlattr *list;
319
320 if (priv->flags) {
321 if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(priv->flags)))
322 goto nla_put_failure;
323 }
324
325 if (nla_put_be32(skb, NFTA_SET_SREG, htonl(priv->sreg)))
326 goto nla_put_failure;
327 if (nla_put_be32(skb, NFTA_SET_KLEN, htonl(priv->klen)))
328 goto nla_put_failure;
329
330 if (priv->flags & NFT_SET_MAP) {
331 if (nla_put_be32(skb, NFTA_SET_DREG, htonl(priv->dreg)))
332 goto nla_put_failure;
333 if (nla_put_be32(skb, NFTA_SET_DLEN, htonl(priv->dlen)))
334 goto nla_put_failure;
335 }
336
337 list = nla_nest_start(skb, NFTA_SET_ELEMENTS);
338 if (list == NULL)
339 goto nla_put_failure;
340
341 for (node = rb_first(&priv->root); node; node = rb_next(node)) {
342 elem = rb_entry(node, struct nft_set_elem, node);
343 if (nft_set_elem_dump(skb, expr, elem) < 0)
344 goto nla_put_failure;
345 }
346
347 nla_nest_end(skb, list);
348 return 0;
349
350nla_put_failure:
351 return -1;
352}
353
354static struct nft_expr_ops nft_set_ops __read_mostly = {
355 .name = "set",
356 .size = NFT_EXPR_SIZE(sizeof(struct nft_set)),
357 .owner = THIS_MODULE,
358 .eval = nft_set_eval,
359 .init = nft_set_init,
360 .destroy = nft_set_destroy,
361 .dump = nft_set_dump,
362 .policy = nft_set_policy,
363 .maxattr = NFTA_SET_MAX,
364};
365
366static int __init nft_set_module_init(void)
367{
368 return nft_register_expr(&nft_set_ops);
369}
370
371static void __exit nft_set_module_exit(void)
372{
373 nft_unregister_expr(&nft_set_ops);
374}
375
376module_init(nft_set_module_init);
377module_exit(nft_set_module_exit);
378
379MODULE_LICENSE("GPL");
380MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
381MODULE_ALIAS_NFT_EXPR("set");