aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/linux/netfilter.h11
-rw-r--r--include/net/netfilter/nf_tables.h301
-rw-r--r--include/net/netfilter/nf_tables_core.h25
-rw-r--r--include/uapi/linux/netfilter/Kbuild1
-rw-r--r--include/uapi/linux/netfilter/nf_conntrack_common.h4
-rw-r--r--include/uapi/linux/netfilter/nf_tables.h582
-rw-r--r--include/uapi/linux/netfilter/nfnetlink.h5
-rw-r--r--net/bridge/netfilter/Kconfig3
-rw-r--r--net/bridge/netfilter/Makefile2
-rw-r--r--net/bridge/netfilter/nf_tables_bridge.c37
-rw-r--r--net/ipv4/netfilter/Kconfig16
-rw-r--r--net/ipv4/netfilter/Makefile5
-rw-r--r--net/ipv4/netfilter/nf_table_nat_ipv4.c409
-rw-r--r--net/ipv4/netfilter/nf_table_route_ipv4.c97
-rw-r--r--net/ipv4/netfilter/nf_tables_ipv4.c59
-rw-r--r--net/ipv4/netfilter/nft_reject_ipv4.c117
-rw-r--r--net/ipv6/netfilter/Kconfig8
-rw-r--r--net/ipv6/netfilter/Makefile4
-rw-r--r--net/ipv6/netfilter/nf_table_route_ipv6.c93
-rw-r--r--net/ipv6/netfilter/nf_tables_ipv6.c57
-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
39 files changed, 6393 insertions, 6 deletions
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index fef7e67f7101..2077489f9887 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -53,12 +53,13 @@ struct nf_hook_ops {
53 struct list_head list; 53 struct list_head list;
54 54
55 /* User fills in from here down. */ 55 /* User fills in from here down. */
56 nf_hookfn *hook; 56 nf_hookfn *hook;
57 struct module *owner; 57 struct module *owner;
58 u_int8_t pf; 58 void *priv;
59 unsigned int hooknum; 59 u_int8_t pf;
60 unsigned int hooknum;
60 /* Hooks are ordered in ascending priority. */ 61 /* Hooks are ordered in ascending priority. */
61 int priority; 62 int priority;
62}; 63};
63 64
64struct nf_sockopt_ops { 65struct nf_sockopt_ops {
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
new file mode 100644
index 000000000000..d26dfa345f49
--- /dev/null
+++ b/include/net/netfilter/nf_tables.h
@@ -0,0 +1,301 @@
1#ifndef _NET_NF_TABLES_H
2#define _NET_NF_TABLES_H
3
4#include <linux/list.h>
5#include <linux/netfilter.h>
6#include <linux/netfilter/nf_tables.h>
7#include <net/netlink.h>
8
9struct nft_pktinfo {
10 struct sk_buff *skb;
11 const struct net_device *in;
12 const struct net_device *out;
13 u8 hooknum;
14 u8 nhoff;
15 u8 thoff;
16};
17
18struct nft_data {
19 union {
20 u32 data[4];
21 struct {
22 u32 verdict;
23 struct nft_chain *chain;
24 };
25 };
26} __attribute__((aligned(__alignof__(u64))));
27
28static inline int nft_data_cmp(const struct nft_data *d1,
29 const struct nft_data *d2,
30 unsigned int len)
31{
32 return memcmp(d1->data, d2->data, len);
33}
34
35static inline void nft_data_copy(struct nft_data *dst,
36 const struct nft_data *src)
37{
38 BUILD_BUG_ON(__alignof__(*dst) != __alignof__(u64));
39 *(u64 *)&dst->data[0] = *(u64 *)&src->data[0];
40 *(u64 *)&dst->data[2] = *(u64 *)&src->data[2];
41}
42
43static inline void nft_data_debug(const struct nft_data *data)
44{
45 pr_debug("data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n",
46 data->data[0], data->data[1],
47 data->data[2], data->data[3]);
48}
49
50/**
51 * struct nft_ctx - nf_tables rule context
52 *
53 * @afi: address family info
54 * @table: the table the chain is contained in
55 * @chain: the chain the rule is contained in
56 */
57struct nft_ctx {
58 const struct nft_af_info *afi;
59 const struct nft_table *table;
60 const struct nft_chain *chain;
61};
62
63enum nft_data_types {
64 NFT_DATA_VALUE,
65 NFT_DATA_VERDICT,
66};
67
68struct nft_data_desc {
69 enum nft_data_types type;
70 unsigned int len;
71};
72
73extern int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data,
74 struct nft_data_desc *desc, const struct nlattr *nla);
75extern void nft_data_uninit(const struct nft_data *data,
76 enum nft_data_types type);
77extern int nft_data_dump(struct sk_buff *skb, int attr,
78 const struct nft_data *data,
79 enum nft_data_types type, unsigned int len);
80
81static inline enum nft_data_types nft_dreg_to_type(enum nft_registers reg)
82{
83 return reg == NFT_REG_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE;
84}
85
86extern int nft_validate_input_register(enum nft_registers reg);
87extern int nft_validate_output_register(enum nft_registers reg);
88extern int nft_validate_data_load(const struct nft_ctx *ctx,
89 enum nft_registers reg,
90 const struct nft_data *data,
91 enum nft_data_types type);
92
93/**
94 * struct nft_expr_ops - nf_tables expression operations
95 *
96 * @eval: Expression evaluation function
97 * @init: initialization function
98 * @destroy: destruction function
99 * @dump: function to dump parameters
100 * @list: used internally
101 * @name: Identifier
102 * @owner: module reference
103 * @policy: netlink attribute policy
104 * @maxattr: highest netlink attribute number
105 * @size: full expression size, including private data size
106 */
107struct nft_expr;
108struct nft_expr_ops {
109 void (*eval)(const struct nft_expr *expr,
110 struct nft_data data[NFT_REG_MAX + 1],
111 const struct nft_pktinfo *pkt);
112 int (*init)(const struct nft_ctx *ctx,
113 const struct nft_expr *expr,
114 const struct nlattr * const tb[]);
115 void (*destroy)(const struct nft_expr *expr);
116 int (*dump)(struct sk_buff *skb,
117 const struct nft_expr *expr);
118
119 struct list_head list;
120 const char *name;
121 struct module *owner;
122 const struct nla_policy *policy;
123 unsigned int maxattr;
124 unsigned int size;
125};
126
127#define NFT_EXPR_SIZE(size) (sizeof(struct nft_expr) + \
128 ALIGN(size, __alignof__(struct nft_expr)))
129
130/**
131 * struct nft_expr - nf_tables expression
132 *
133 * @ops: expression ops
134 * @data: expression private data
135 */
136struct nft_expr {
137 const struct nft_expr_ops *ops;
138 unsigned char data[];
139};
140
141static inline void *nft_expr_priv(const struct nft_expr *expr)
142{
143 return (void *)expr->data;
144}
145
146/**
147 * struct nft_rule - nf_tables rule
148 *
149 * @list: used internally
150 * @rcu_head: used internally for rcu
151 * @handle: rule handle
152 * @dlen: length of expression data
153 * @data: expression data
154 */
155struct nft_rule {
156 struct list_head list;
157 struct rcu_head rcu_head;
158 u64 handle:48,
159 dlen:16;
160 unsigned char data[]
161 __attribute__((aligned(__alignof__(struct nft_expr))));
162};
163
164static inline struct nft_expr *nft_expr_first(const struct nft_rule *rule)
165{
166 return (struct nft_expr *)&rule->data[0];
167}
168
169static inline struct nft_expr *nft_expr_next(const struct nft_expr *expr)
170{
171 return ((void *)expr) + expr->ops->size;
172}
173
174static inline struct nft_expr *nft_expr_last(const struct nft_rule *rule)
175{
176 return (struct nft_expr *)&rule->data[rule->dlen];
177}
178
179/*
180 * The last pointer isn't really necessary, but the compiler isn't able to
181 * determine that the result of nft_expr_last() is always the same since it
182 * can't assume that the dlen value wasn't changed within calls in the loop.
183 */
184#define nft_rule_for_each_expr(expr, last, rule) \
185 for ((expr) = nft_expr_first(rule), (last) = nft_expr_last(rule); \
186 (expr) != (last); \
187 (expr) = nft_expr_next(expr))
188
189enum nft_chain_flags {
190 NFT_BASE_CHAIN = 0x1,
191 NFT_CHAIN_BUILTIN = 0x2,
192};
193
194/**
195 * struct nft_chain - nf_tables chain
196 *
197 * @rules: list of rules in the chain
198 * @list: used internally
199 * @rcu_head: used internally
200 * @handle: chain handle
201 * @flags: bitmask of enum nft_chain_flags
202 * @use: number of jump references to this chain
203 * @level: length of longest path to this chain
204 * @name: name of the chain
205 */
206struct nft_chain {
207 struct list_head rules;
208 struct list_head list;
209 struct rcu_head rcu_head;
210 u64 handle;
211 u8 flags;
212 u16 use;
213 u16 level;
214 char name[NFT_CHAIN_MAXNAMELEN];
215};
216
217/**
218 * struct nft_base_chain - nf_tables base chain
219 *
220 * @ops: netfilter hook ops
221 * @chain: the chain
222 */
223struct nft_base_chain {
224 struct nf_hook_ops ops;
225 struct nft_chain chain;
226};
227
228static inline struct nft_base_chain *nft_base_chain(const struct nft_chain *chain)
229{
230 return container_of(chain, struct nft_base_chain, chain);
231}
232
233extern unsigned int nft_do_chain(const struct nf_hook_ops *ops,
234 struct sk_buff *skb,
235 const struct net_device *in,
236 const struct net_device *out,
237 int (*okfn)(struct sk_buff *));
238
239enum nft_table_flags {
240 NFT_TABLE_BUILTIN = 0x1,
241};
242
243/**
244 * struct nft_table - nf_tables table
245 *
246 * @list: used internally
247 * @chains: chains in the table
248 * @sets: sets in the table
249 * @hgenerator: handle generator state
250 * @use: number of chain references to this table
251 * @flags: table flag (see enum nft_table_flags)
252 * @name: name of the table
253 */
254struct nft_table {
255 struct list_head list;
256 struct list_head chains;
257 struct list_head sets;
258 u64 hgenerator;
259 u32 use;
260 u16 flags;
261 char name[];
262};
263
264/**
265 * struct nft_af_info - nf_tables address family info
266 *
267 * @list: used internally
268 * @family: address family
269 * @nhooks: number of hooks in this family
270 * @owner: module owner
271 * @tables: used internally
272 * @hooks: hookfn overrides for packet validation
273 */
274struct nft_af_info {
275 struct list_head list;
276 int family;
277 unsigned int nhooks;
278 struct module *owner;
279 struct list_head tables;
280 nf_hookfn *hooks[NF_MAX_HOOKS];
281};
282
283extern int nft_register_afinfo(struct nft_af_info *);
284extern void nft_unregister_afinfo(struct nft_af_info *);
285
286extern int nft_register_table(struct nft_table *, int family);
287extern void nft_unregister_table(struct nft_table *, int family);
288
289extern int nft_register_expr(struct nft_expr_ops *);
290extern void nft_unregister_expr(struct nft_expr_ops *);
291
292#define MODULE_ALIAS_NFT_FAMILY(family) \
293 MODULE_ALIAS("nft-afinfo-" __stringify(family))
294
295#define MODULE_ALIAS_NFT_TABLE(family, name) \
296 MODULE_ALIAS("nft-table-" __stringify(family) "-" name)
297
298#define MODULE_ALIAS_NFT_EXPR(name) \
299 MODULE_ALIAS("nft-expr-" name)
300
301#endif /* _NET_NF_TABLES_H */
diff --git a/include/net/netfilter/nf_tables_core.h b/include/net/netfilter/nf_tables_core.h
new file mode 100644
index 000000000000..283396c916e0
--- /dev/null
+++ b/include/net/netfilter/nf_tables_core.h
@@ -0,0 +1,25 @@
1#ifndef _NET_NF_TABLES_CORE_H
2#define _NET_NF_TABLES_CORE_H
3
4extern int nf_tables_core_module_init(void);
5extern void nf_tables_core_module_exit(void);
6
7extern int nft_immediate_module_init(void);
8extern void nft_immediate_module_exit(void);
9
10extern int nft_cmp_module_init(void);
11extern void nft_cmp_module_exit(void);
12
13extern int nft_lookup_module_init(void);
14extern void nft_lookup_module_exit(void);
15
16extern int nft_bitwise_module_init(void);
17extern void nft_bitwise_module_exit(void);
18
19extern int nft_byteorder_module_init(void);
20extern void nft_byteorder_module_exit(void);
21
22extern int nft_payload_module_init(void);
23extern void nft_payload_module_exit(void);
24
25#endif /* _NET_NF_TABLES_CORE_H */
diff --git a/include/uapi/linux/netfilter/Kbuild b/include/uapi/linux/netfilter/Kbuild
index 174915420d3f..6ce0b7f566a7 100644
--- a/include/uapi/linux/netfilter/Kbuild
+++ b/include/uapi/linux/netfilter/Kbuild
@@ -5,6 +5,7 @@ header-y += nf_conntrack_ftp.h
5header-y += nf_conntrack_sctp.h 5header-y += nf_conntrack_sctp.h
6header-y += nf_conntrack_tcp.h 6header-y += nf_conntrack_tcp.h
7header-y += nf_conntrack_tuple_common.h 7header-y += nf_conntrack_tuple_common.h
8header-y += nf_tables.h
8header-y += nf_nat.h 9header-y += nf_nat.h
9header-y += nfnetlink.h 10header-y += nfnetlink.h
10header-y += nfnetlink_acct.h 11header-y += nfnetlink_acct.h
diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h b/include/uapi/linux/netfilter/nf_conntrack_common.h
index 8dd803818ebe..319f47128db8 100644
--- a/include/uapi/linux/netfilter/nf_conntrack_common.h
+++ b/include/uapi/linux/netfilter/nf_conntrack_common.h
@@ -25,6 +25,10 @@ enum ip_conntrack_info {
25 IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1 25 IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1
26}; 26};
27 27
28#define NF_CT_STATE_INVALID_BIT (1 << 0)
29#define NF_CT_STATE_BIT(ctinfo) (1 << ((ctinfo) % IP_CT_IS_REPLY + 1))
30#define NF_CT_STATE_UNTRACKED_BIT (1 << (IP_CT_NUMBER + 1))
31
28/* Bitset representing status of connection. */ 32/* Bitset representing status of connection. */
29enum ip_conntrack_status { 33enum ip_conntrack_status {
30 /* It's an expected connection: bit 0 set. This bit never changed */ 34 /* It's an expected connection: bit 0 set. This bit never changed */
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
new file mode 100644
index 000000000000..ec6d84a8ed1e
--- /dev/null
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -0,0 +1,582 @@
1#ifndef _LINUX_NF_TABLES_H
2#define _LINUX_NF_TABLES_H
3
4#define NFT_CHAIN_MAXNAMELEN 32
5
6enum nft_registers {
7 NFT_REG_VERDICT,
8 NFT_REG_1,
9 NFT_REG_2,
10 NFT_REG_3,
11 NFT_REG_4,
12 __NFT_REG_MAX
13};
14#define NFT_REG_MAX (__NFT_REG_MAX - 1)
15
16/**
17 * enum nft_verdicts - nf_tables internal verdicts
18 *
19 * @NFT_CONTINUE: continue evaluation of the current rule
20 * @NFT_BREAK: terminate evaluation of the current rule
21 * @NFT_JUMP: push the current chain on the jump stack and jump to a chain
22 * @NFT_GOTO: jump to a chain without pushing the current chain on the jump stack
23 * @NFT_RETURN: return to the topmost chain on the jump stack
24 *
25 * The nf_tables verdicts share their numeric space with the netfilter verdicts.
26 */
27enum nft_verdicts {
28 NFT_CONTINUE = -1,
29 NFT_BREAK = -2,
30 NFT_JUMP = -3,
31 NFT_GOTO = -4,
32 NFT_RETURN = -5,
33};
34
35/**
36 * enum nf_tables_msg_types - nf_tables netlink message types
37 *
38 * @NFT_MSG_NEWTABLE: create a new table (enum nft_table_attributes)
39 * @NFT_MSG_GETTABLE: get a table (enum nft_table_attributes)
40 * @NFT_MSG_DELTABLE: delete a table (enum nft_table_attributes)
41 * @NFT_MSG_NEWCHAIN: create a new chain (enum nft_chain_attributes)
42 * @NFT_MSG_GETCHAIN: get a chain (enum nft_chain_attributes)
43 * @NFT_MSG_DELCHAIN: delete a chain (enum nft_chain_attributes)
44 * @NFT_MSG_NEWRULE: create a new rule (enum nft_rule_attributes)
45 * @NFT_MSG_GETRULE: get a rule (enum nft_rule_attributes)
46 * @NFT_MSG_DELRULE: delete a rule (enum nft_rule_attributes)
47 */
48enum nf_tables_msg_types {
49 NFT_MSG_NEWTABLE,
50 NFT_MSG_GETTABLE,
51 NFT_MSG_DELTABLE,
52 NFT_MSG_NEWCHAIN,
53 NFT_MSG_GETCHAIN,
54 NFT_MSG_DELCHAIN,
55 NFT_MSG_NEWRULE,
56 NFT_MSG_GETRULE,
57 NFT_MSG_DELRULE,
58 NFT_MSG_MAX,
59};
60
61enum nft_list_attributes {
62 NFTA_LIST_UNPEC,
63 NFTA_LIST_ELEM,
64 __NFTA_LIST_MAX
65};
66#define NFTA_LIST_MAX (__NFTA_LIST_MAX - 1)
67
68/**
69 * enum nft_hook_attributes - nf_tables netfilter hook netlink attributes
70 *
71 * @NFTA_HOOK_HOOKNUM: netfilter hook number (NLA_U32)
72 * @NFTA_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
73 */
74enum nft_hook_attributes {
75 NFTA_HOOK_UNSPEC,
76 NFTA_HOOK_HOOKNUM,
77 NFTA_HOOK_PRIORITY,
78 __NFTA_HOOK_MAX
79};
80#define NFTA_HOOK_MAX (__NFTA_HOOK_MAX - 1)
81
82/**
83 * enum nft_table_attributes - nf_tables table netlink attributes
84 *
85 * @NFTA_TABLE_NAME: name of the table (NLA_STRING)
86 */
87enum nft_table_attributes {
88 NFTA_TABLE_UNSPEC,
89 NFTA_TABLE_NAME,
90 __NFTA_TABLE_MAX
91};
92#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
93
94/**
95 * enum nft_chain_attributes - nf_tables chain netlink attributes
96 *
97 * @NFTA_CHAIN_TABLE: name of the table containing the chain (NLA_STRING)
98 * @NFTA_CHAIN_HANDLE: numeric handle of the chain (NLA_U64)
99 * @NFTA_CHAIN_NAME: name of the chain (NLA_STRING)
100 * @NFTA_CHAIN_HOOK: hook specification for basechains (NLA_NESTED: nft_hook_attributes)
101 */
102enum nft_chain_attributes {
103 NFTA_CHAIN_UNSPEC,
104 NFTA_CHAIN_TABLE,
105 NFTA_CHAIN_HANDLE,
106 NFTA_CHAIN_NAME,
107 NFTA_CHAIN_HOOK,
108 __NFTA_CHAIN_MAX
109};
110#define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1)
111
112/**
113 * enum nft_rule_attributes - nf_tables rule netlink attributes
114 *
115 * @NFTA_RULE_TABLE: name of the table containing the rule (NLA_STRING)
116 * @NFTA_RULE_CHAIN: name of the chain containing the rule (NLA_STRING)
117 * @NFTA_RULE_HANDLE: numeric handle of the rule (NLA_U64)
118 * @NFTA_RULE_EXPRESSIONS: list of expressions (NLA_NESTED: nft_expr_attributes)
119 */
120enum nft_rule_attributes {
121 NFTA_RULE_UNSPEC,
122 NFTA_RULE_TABLE,
123 NFTA_RULE_CHAIN,
124 NFTA_RULE_HANDLE,
125 NFTA_RULE_EXPRESSIONS,
126 __NFTA_RULE_MAX
127};
128#define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1)
129
130enum nft_data_attributes {
131 NFTA_DATA_UNSPEC,
132 NFTA_DATA_VALUE,
133 NFTA_DATA_VERDICT,
134 __NFTA_DATA_MAX
135};
136#define NFTA_DATA_MAX (__NFTA_DATA_MAX - 1)
137
138/**
139 * enum nft_verdict_attributes - nf_tables verdict netlink attributes
140 *
141 * @NFTA_VERDICT_CODE: nf_tables verdict (NLA_U32: enum nft_verdicts)
142 * @NFTA_VERDICT_CHAIN: jump target chain name (NLA_STRING)
143 */
144enum nft_verdict_attributes {
145 NFTA_VERDICT_UNSPEC,
146 NFTA_VERDICT_CODE,
147 NFTA_VERDICT_CHAIN,
148 __NFTA_VERDICT_MAX
149};
150#define NFTA_VERDICT_MAX (__NFTA_VERDICT_MAX - 1)
151
152/**
153 * enum nft_expr_attributes - nf_tables expression netlink attributes
154 *
155 * @NFTA_EXPR_NAME: name of the expression type (NLA_STRING)
156 * @NFTA_EXPR_DATA: type specific data (NLA_NESTED)
157 */
158enum nft_expr_attributes {
159 NFTA_EXPR_UNSPEC,
160 NFTA_EXPR_NAME,
161 NFTA_EXPR_DATA,
162 __NFTA_EXPR_MAX
163};
164#define NFTA_EXPR_MAX (__NFTA_EXPR_MAX - 1)
165
166/**
167 * enum nft_immediate_attributes - nf_tables immediate expression netlink attributes
168 *
169 * @NFTA_IMMEDIATE_DREG: destination register to load data into (NLA_U32)
170 * @NFTA_IMMEDIATE_DATA: data to load (NLA_NESTED: nft_data_attributes)
171 */
172enum nft_immediate_attributes {
173 NFTA_IMMEDIATE_UNSPEC,
174 NFTA_IMMEDIATE_DREG,
175 NFTA_IMMEDIATE_DATA,
176 __NFTA_IMMEDIATE_MAX
177};
178#define NFTA_IMMEDIATE_MAX (__NFTA_IMMEDIATE_MAX - 1)
179
180/**
181 * enum nft_bitwise_attributes - nf_tables bitwise expression netlink attributes
182 *
183 * @NFTA_BITWISE_SREG: source register (NLA_U32: nft_registers)
184 * @NFTA_BITWISE_DREG: destination register (NLA_U32: nft_registers)
185 * @NFTA_BITWISE_LEN: length of operands (NLA_U32)
186 * @NFTA_BITWISE_MASK: mask value (NLA_NESTED: nft_data_attributes)
187 * @NFTA_BITWISE_XOR: xor value (NLA_NESTED: nft_data_attributes)
188 *
189 * The bitwise expression performs the following operation:
190 *
191 * dreg = (sreg & mask) ^ xor
192 *
193 * which allow to express all bitwise operations:
194 *
195 * mask xor
196 * NOT: 1 1
197 * OR: 0 x
198 * XOR: 1 x
199 * AND: x 0
200 */
201enum nft_bitwise_attributes {
202 NFTA_BITWISE_UNSPEC,
203 NFTA_BITWISE_SREG,
204 NFTA_BITWISE_DREG,
205 NFTA_BITWISE_LEN,
206 NFTA_BITWISE_MASK,
207 NFTA_BITWISE_XOR,
208 __NFTA_BITWISE_MAX
209};
210#define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1)
211
212/**
213 * enum nft_byteorder_ops - nf_tables byteorder operators
214 *
215 * @NFT_BYTEORDER_NTOH: network to host operator
216 * @NFT_BYTEORDER_HTON: host to network opertaor
217 */
218enum nft_byteorder_ops {
219 NFT_BYTEORDER_NTOH,
220 NFT_BYTEORDER_HTON,
221};
222
223/**
224 * enum nft_byteorder_attributes - nf_tables byteorder expression netlink attributes
225 *
226 * @NFTA_BYTEORDER_SREG: source register (NLA_U32: nft_registers)
227 * @NFTA_BYTEORDER_DREG: destination register (NLA_U32: nft_registers)
228 * @NFTA_BYTEORDER_OP: operator (NLA_U32: enum nft_byteorder_ops)
229 * @NFTA_BYTEORDER_LEN: length of the data (NLA_U32)
230 * @NFTA_BYTEORDER_SIZE: data size in bytes (NLA_U32: 2 or 4)
231 */
232enum nft_byteorder_attributes {
233 NFTA_BYTEORDER_UNSPEC,
234 NFTA_BYTEORDER_SREG,
235 NFTA_BYTEORDER_DREG,
236 NFTA_BYTEORDER_OP,
237 NFTA_BYTEORDER_LEN,
238 NFTA_BYTEORDER_SIZE,
239 __NFTA_BYTEORDER_MAX
240};
241#define NFTA_BYTEORDER_MAX (__NFTA_BYTEORDER_MAX - 1)
242
243/**
244 * enum nft_cmp_ops - nf_tables relational operator
245 *
246 * @NFT_CMP_EQ: equal
247 * @NFT_CMP_NEQ: not equal
248 * @NFT_CMP_LT: less than
249 * @NFT_CMP_LTE: less than or equal to
250 * @NFT_CMP_GT: greater than
251 * @NFT_CMP_GTE: greater than or equal to
252 */
253enum nft_cmp_ops {
254 NFT_CMP_EQ,
255 NFT_CMP_NEQ,
256 NFT_CMP_LT,
257 NFT_CMP_LTE,
258 NFT_CMP_GT,
259 NFT_CMP_GTE,
260};
261
262/**
263 * enum nft_cmp_attributes - nf_tables cmp expression netlink attributes
264 *
265 * @NFTA_CMP_SREG: source register of data to compare (NLA_U32: nft_registers)
266 * @NFTA_CMP_OP: cmp operation (NLA_U32: nft_cmp_ops)
267 * @NFTA_CMP_DATA: data to compare against (NLA_NESTED: nft_data_attributes)
268 */
269enum nft_cmp_attributes {
270 NFTA_CMP_UNSPEC,
271 NFTA_CMP_SREG,
272 NFTA_CMP_OP,
273 NFTA_CMP_DATA,
274 __NFTA_CMP_MAX
275};
276#define NFTA_CMP_MAX (__NFTA_CMP_MAX - 1)
277
278enum nft_set_elem_flags {
279 NFT_SE_INTERVAL_END = 0x1,
280};
281
282enum nft_set_elem_attributes {
283 NFTA_SE_UNSPEC,
284 NFTA_SE_KEY,
285 NFTA_SE_DATA,
286 NFTA_SE_FLAGS,
287 __NFTA_SE_MAX
288};
289#define NFTA_SE_MAX (__NFTA_SE_MAX - 1)
290
291enum nft_set_flags {
292 NFT_SET_INTERVAL = 0x1,
293 NFT_SET_MAP = 0x2,
294};
295
296enum nft_set_attributes {
297 NFTA_SET_UNSPEC,
298 NFTA_SET_FLAGS,
299 NFTA_SET_SREG,
300 NFTA_SET_DREG,
301 NFTA_SET_KLEN,
302 NFTA_SET_DLEN,
303 NFTA_SET_ELEMENTS,
304 __NFTA_SET_MAX
305};
306#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
307
308enum nft_hash_flags {
309 NFT_HASH_MAP = 0x1,
310};
311
312enum nft_hash_elem_attributes {
313 NFTA_HE_UNSPEC,
314 NFTA_HE_KEY,
315 NFTA_HE_DATA,
316 __NFTA_HE_MAX
317};
318#define NFTA_HE_MAX (__NFTA_HE_MAX - 1)
319
320enum nft_hash_attributes {
321 NFTA_HASH_UNSPEC,
322 NFTA_HASH_FLAGS,
323 NFTA_HASH_SREG,
324 NFTA_HASH_DREG,
325 NFTA_HASH_KLEN,
326 NFTA_HASH_ELEMENTS,
327 __NFTA_HASH_MAX
328};
329#define NFTA_HASH_MAX (__NFTA_HASH_MAX - 1)
330
331/**
332 * enum nft_payload_bases - nf_tables payload expression offset bases
333 *
334 * @NFT_PAYLOAD_LL_HEADER: link layer header
335 * @NFT_PAYLOAD_NETWORK_HEADER: network header
336 * @NFT_PAYLOAD_TRANSPORT_HEADER: transport header
337 */
338enum nft_payload_bases {
339 NFT_PAYLOAD_LL_HEADER,
340 NFT_PAYLOAD_NETWORK_HEADER,
341 NFT_PAYLOAD_TRANSPORT_HEADER,
342};
343
344/**
345 * enum nft_payload_attributes - nf_tables payload expression netlink attributes
346 *
347 * @NFTA_PAYLOAD_DREG: destination register to load data into (NLA_U32: nft_registers)
348 * @NFTA_PAYLOAD_BASE: payload base (NLA_U32: nft_payload_bases)
349 * @NFTA_PAYLOAD_OFFSET: payload offset relative to base (NLA_U32)
350 * @NFTA_PAYLOAD_LEN: payload length (NLA_U32)
351 */
352enum nft_payload_attributes {
353 NFTA_PAYLOAD_UNSPEC,
354 NFTA_PAYLOAD_DREG,
355 NFTA_PAYLOAD_BASE,
356 NFTA_PAYLOAD_OFFSET,
357 NFTA_PAYLOAD_LEN,
358 __NFTA_PAYLOAD_MAX
359};
360#define NFTA_PAYLOAD_MAX (__NFTA_PAYLOAD_MAX - 1)
361
362/**
363 * enum nft_exthdr_attributes - nf_tables IPv6 extension header expression netlink attributes
364 *
365 * @NFTA_EXTHDR_DREG: destination register (NLA_U32: nft_registers)
366 * @NFTA_EXTHDR_TYPE: extension header type (NLA_U8)
367 * @NFTA_EXTHDR_OFFSET: extension header offset (NLA_U32)
368 * @NFTA_EXTHDR_LEN: extension header length (NLA_U32)
369 */
370enum nft_exthdr_attributes {
371 NFTA_EXTHDR_UNSPEC,
372 NFTA_EXTHDR_DREG,
373 NFTA_EXTHDR_TYPE,
374 NFTA_EXTHDR_OFFSET,
375 NFTA_EXTHDR_LEN,
376 __NFTA_EXTHDR_MAX
377};
378#define NFTA_EXTHDR_MAX (__NFTA_EXTHDR_MAX - 1)
379
380/**
381 * enum nft_meta_keys - nf_tables meta expression keys
382 *
383 * @NFT_META_LEN: packet length (skb->len)
384 * @NFT_META_PROTOCOL: packet ethertype protocol (skb->protocol), invalid in OUTPUT
385 * @NFT_META_PRIORITY: packet priority (skb->priority)
386 * @NFT_META_MARK: packet mark (skb->mark)
387 * @NFT_META_IIF: packet input interface index (dev->ifindex)
388 * @NFT_META_OIF: packet output interface index (dev->ifindex)
389 * @NFT_META_IIFNAME: packet input interface name (dev->name)
390 * @NFT_META_OIFNAME: packet output interface name (dev->name)
391 * @NFT_META_IIFTYPE: packet input interface type (dev->type)
392 * @NFT_META_OIFTYPE: packet output interface type (dev->type)
393 * @NFT_META_SKUID: originating socket UID (fsuid)
394 * @NFT_META_SKGID: originating socket GID (fsgid)
395 * @NFT_META_NFTRACE: packet nftrace bit
396 * @NFT_META_RTCLASSID: realm value of packet's route (skb->dst->tclassid)
397 * @NFT_META_SECMARK: packet secmark (skb->secmark)
398 */
399enum nft_meta_keys {
400 NFT_META_LEN,
401 NFT_META_PROTOCOL,
402 NFT_META_PRIORITY,
403 NFT_META_MARK,
404 NFT_META_IIF,
405 NFT_META_OIF,
406 NFT_META_IIFNAME,
407 NFT_META_OIFNAME,
408 NFT_META_IIFTYPE,
409 NFT_META_OIFTYPE,
410 NFT_META_SKUID,
411 NFT_META_SKGID,
412 NFT_META_NFTRACE,
413 NFT_META_RTCLASSID,
414 NFT_META_SECMARK,
415};
416
417/**
418 * enum nft_meta_attributes - nf_tables meta expression netlink attributes
419 *
420 * @NFTA_META_DREG: destination register (NLA_U32)
421 * @NFTA_META_KEY: meta data item to load (NLA_U32: nft_meta_keys)
422 */
423enum nft_meta_attributes {
424 NFTA_META_UNSPEC,
425 NFTA_META_DREG,
426 NFTA_META_KEY,
427 __NFTA_META_MAX
428};
429#define NFTA_META_MAX (__NFTA_META_MAX - 1)
430
431/**
432 * enum nft_ct_keys - nf_tables ct expression keys
433 *
434 * @NFT_CT_STATE: conntrack state (bitmask of enum ip_conntrack_info)
435 * @NFT_CT_DIRECTION: conntrack direction (enum ip_conntrack_dir)
436 * @NFT_CT_STATUS: conntrack status (bitmask of enum ip_conntrack_status)
437 * @NFT_CT_MARK: conntrack mark value
438 * @NFT_CT_SECMARK: conntrack secmark value
439 * @NFT_CT_EXPIRATION: relative conntrack expiration time in ms
440 * @NFT_CT_HELPER: connection tracking helper assigned to conntrack
441 * @NFT_CT_L3PROTOCOL: conntrack layer 3 protocol
442 * @NFT_CT_SRC: conntrack layer 3 protocol source (IPv4/IPv6 address)
443 * @NFT_CT_DST: conntrack layer 3 protocol destination (IPv4/IPv6 address)
444 * @NFT_CT_PROTOCOL: conntrack layer 4 protocol
445 * @NFT_CT_PROTO_SRC: conntrack layer 4 protocol source
446 * @NFT_CT_PROTO_DST: conntrack layer 4 protocol destination
447 */
448enum nft_ct_keys {
449 NFT_CT_STATE,
450 NFT_CT_DIRECTION,
451 NFT_CT_STATUS,
452 NFT_CT_MARK,
453 NFT_CT_SECMARK,
454 NFT_CT_EXPIRATION,
455 NFT_CT_HELPER,
456 NFT_CT_L3PROTOCOL,
457 NFT_CT_SRC,
458 NFT_CT_DST,
459 NFT_CT_PROTOCOL,
460 NFT_CT_PROTO_SRC,
461 NFT_CT_PROTO_DST,
462};
463
464/**
465 * enum nft_ct_attributes - nf_tables ct expression netlink attributes
466 *
467 * @NFTA_CT_DREG: destination register (NLA_U32)
468 * @NFTA_CT_KEY: conntrack data item to load (NLA_U32: nft_ct_keys)
469 * @NFTA_CT_DIRECTION: direction in case of directional keys (NLA_U8)
470 */
471enum nft_ct_attributes {
472 NFTA_CT_UNSPEC,
473 NFTA_CT_DREG,
474 NFTA_CT_KEY,
475 NFTA_CT_DIRECTION,
476 __NFTA_CT_MAX
477};
478#define NFTA_CT_MAX (__NFTA_CT_MAX - 1)
479
480/**
481 * enum nft_limit_attributes - nf_tables limit expression netlink attributes
482 *
483 * @NFTA_LIMIT_RATE: refill rate (NLA_U64)
484 * @NFTA_LIMIT_UNIT: refill unit (NLA_U64)
485 */
486enum nft_limit_attributes {
487 NFTA_LIMIT_UNSPEC,
488 NFTA_LIMIT_RATE,
489 NFTA_LIMIT_UNIT,
490 __NFTA_LIMIT_MAX
491};
492#define NFTA_LIMIT_MAX (__NFTA_LIMIT_MAX - 1)
493
494/**
495 * enum nft_counter_attributes - nf_tables counter expression netlink attributes
496 *
497 * @NFTA_COUNTER_BYTES: number of bytes (NLA_U64)
498 * @NFTA_COUNTER_PACKETS: number of packets (NLA_U64)
499 */
500enum nft_counter_attributes {
501 NFTA_COUNTER_UNSPEC,
502 NFTA_COUNTER_BYTES,
503 NFTA_COUNTER_PACKETS,
504 __NFTA_COUNTER_MAX
505};
506#define NFTA_COUNTER_MAX (__NFTA_COUNTER_MAX - 1)
507
508/**
509 * enum nft_log_attributes - nf_tables log expression netlink attributes
510 *
511 * @NFTA_LOG_GROUP: netlink group to send messages to (NLA_U32)
512 * @NFTA_LOG_PREFIX: prefix to prepend to log messages (NLA_STRING)
513 * @NFTA_LOG_SNAPLEN: length of payload to include in netlink message (NLA_U32)
514 * @NFTA_LOG_QTHRESHOLD: queue threshold (NLA_U32)
515 */
516enum nft_log_attributes {
517 NFTA_LOG_UNSPEC,
518 NFTA_LOG_GROUP,
519 NFTA_LOG_PREFIX,
520 NFTA_LOG_SNAPLEN,
521 NFTA_LOG_QTHRESHOLD,
522 __NFTA_LOG_MAX
523};
524#define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1)
525
526/**
527 * enum nft_reject_types - nf_tables reject expression reject types
528 *
529 * @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable
530 * @NFT_REJECT_TCP_RST: reject using TCP RST
531 */
532enum nft_reject_types {
533 NFT_REJECT_ICMP_UNREACH,
534 NFT_REJECT_TCP_RST,
535};
536
537/**
538 * enum nft_reject_attributes - nf_tables reject expression netlink attributes
539 *
540 * @NFTA_REJECT_TYPE: packet type to use (NLA_U32: nft_reject_types)
541 * @NFTA_REJECT_ICMP_CODE: ICMP code to use (NLA_U8)
542 */
543enum nft_reject_attributes {
544 NFTA_REJECT_UNSPEC,
545 NFTA_REJECT_TYPE,
546 NFTA_REJECT_ICMP_CODE,
547 __NFTA_REJECT_MAX
548};
549#define NFTA_REJECT_MAX (__NFTA_REJECT_MAX - 1)
550
551/**
552 * enum nft_nat_types - nf_tables nat expression NAT types
553 *
554 * @NFT_NAT_SNAT: source NAT
555 * @NFT_NAT_DNAT: destination NAT
556 */
557enum nft_nat_types {
558 NFT_NAT_SNAT,
559 NFT_NAT_DNAT,
560};
561
562/**
563 * enum nft_nat_attributes - nf_tables nat expression netlink attributes
564 *
565 * @NFTA_NAT_TYPE: NAT type (NLA_U32: nft_nat_types)
566 * @NFTA_NAT_ADDR_MIN: source register of address range start (NLA_U32: nft_registers)
567 * @NFTA_NAT_ADDR_MAX: source register of address range end (NLA_U32: nft_registers)
568 * @NFTA_NAT_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
569 * @NFTA_NAT_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
570 */
571enum nft_nat_attributes {
572 NFTA_NAT_UNSPEC,
573 NFTA_NAT_TYPE,
574 NFTA_NAT_ADDR_MIN,
575 NFTA_NAT_ADDR_MAX,
576 NFTA_NAT_PROTO_MIN,
577 NFTA_NAT_PROTO_MAX,
578 __NFTA_NAT_MAX
579};
580#define NFTA_NAT_MAX (__NFTA_NAT_MAX - 1)
581
582#endif /* _LINUX_NF_TABLES_H */
diff --git a/include/uapi/linux/netfilter/nfnetlink.h b/include/uapi/linux/netfilter/nfnetlink.h
index 4a4efafad5f4..d276c3bd55b8 100644
--- a/include/uapi/linux/netfilter/nfnetlink.h
+++ b/include/uapi/linux/netfilter/nfnetlink.h
@@ -18,6 +18,8 @@ enum nfnetlink_groups {
18#define NFNLGRP_CONNTRACK_EXP_UPDATE NFNLGRP_CONNTRACK_EXP_UPDATE 18#define NFNLGRP_CONNTRACK_EXP_UPDATE NFNLGRP_CONNTRACK_EXP_UPDATE
19 NFNLGRP_CONNTRACK_EXP_DESTROY, 19 NFNLGRP_CONNTRACK_EXP_DESTROY,
20#define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY 20#define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY
21 NFNLGRP_NFTABLES,
22#define NFNLGRP_NFTABLES NFNLGRP_NFTABLES
21 __NFNLGRP_MAX, 23 __NFNLGRP_MAX,
22}; 24};
23#define NFNLGRP_MAX (__NFNLGRP_MAX - 1) 25#define NFNLGRP_MAX (__NFNLGRP_MAX - 1)
@@ -51,6 +53,7 @@ struct nfgenmsg {
51#define NFNL_SUBSYS_ACCT 7 53#define NFNL_SUBSYS_ACCT 7
52#define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8 54#define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8
53#define NFNL_SUBSYS_CTHELPER 9 55#define NFNL_SUBSYS_CTHELPER 9
54#define NFNL_SUBSYS_COUNT 10 56#define NFNL_SUBSYS_NFTABLES 10
57#define NFNL_SUBSYS_COUNT 11
55 58
56#endif /* _UAPI_NFNETLINK_H */ 59#endif /* _UAPI_NFNETLINK_H */
diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig
index a9aff9c7d027..68f8128147be 100644
--- a/net/bridge/netfilter/Kconfig
+++ b/net/bridge/netfilter/Kconfig
@@ -1,6 +1,9 @@
1# 1#
2# Bridge netfilter configuration 2# Bridge netfilter configuration
3# 3#
4#
5config NF_TABLES_BRIDGE
6 tristate "Ethernet Bridge nf_tables support"
4 7
5menuconfig BRIDGE_NF_EBTABLES 8menuconfig BRIDGE_NF_EBTABLES
6 tristate "Ethernet Bridge tables (ebtables) support" 9 tristate "Ethernet Bridge tables (ebtables) support"
diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile
index 0718699540b0..ea7629f58b3d 100644
--- a/net/bridge/netfilter/Makefile
+++ b/net/bridge/netfilter/Makefile
@@ -2,6 +2,8 @@
2# Makefile for the netfilter modules for Link Layer filtering on a bridge. 2# Makefile for the netfilter modules for Link Layer filtering on a bridge.
3# 3#
4 4
5obj-$(CONFIG_NF_TABLES_BRIDGE) += nf_tables_bridge.o
6
5obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o 7obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o
6 8
7# tables 9# tables
diff --git a/net/bridge/netfilter/nf_tables_bridge.c b/net/bridge/netfilter/nf_tables_bridge.c
new file mode 100644
index 000000000000..bc5c21c911c0
--- /dev/null
+++ b/net/bridge/netfilter/nf_tables_bridge.c
@@ -0,0 +1,37 @@
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/init.h>
12#include <linux/module.h>
13#include <linux/netfilter_bridge.h>
14#include <net/netfilter/nf_tables.h>
15
16static struct nft_af_info nft_af_bridge __read_mostly = {
17 .family = NFPROTO_BRIDGE,
18 .nhooks = NF_BR_NUMHOOKS,
19 .owner = THIS_MODULE,
20};
21
22static int __init nf_tables_bridge_init(void)
23{
24 return nft_register_afinfo(&nft_af_bridge);
25}
26
27static void __exit nf_tables_bridge_exit(void)
28{
29 nft_unregister_afinfo(&nft_af_bridge);
30}
31
32module_init(nf_tables_bridge_init);
33module_exit(nf_tables_bridge_exit);
34
35MODULE_LICENSE("GPL");
36MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
37MODULE_ALIAS_NFT_FAMILY(AF_BRIDGE);
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 1657e39b291f..eb1d56ece361 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -36,6 +36,22 @@ config NF_CONNTRACK_PROC_COMPAT
36 36
37 If unsure, say Y. 37 If unsure, say Y.
38 38
39config NF_TABLES_IPV4
40 depends on NF_TABLES
41 tristate "IPv4 nf_tables support"
42
43config NFT_REJECT_IPV4
44 depends on NF_TABLES_IPV4
45 tristate "nf_tables IPv4 reject support"
46
47config NF_TABLE_ROUTE_IPV4
48 depends on NF_TABLES_IPV4
49 tristate "IPv4 nf_tables route table support"
50
51config NF_TABLE_NAT_IPV4
52 depends on NF_TABLES_IPV4
53 tristate "IPv4 nf_tables nat table support"
54
39config IP_NF_IPTABLES 55config IP_NF_IPTABLES
40 tristate "IP tables support (required for filtering/masq/NAT)" 56 tristate "IP tables support (required for filtering/masq/NAT)"
41 default m if NETFILTER_ADVANCED=n 57 default m if NETFILTER_ADVANCED=n
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 3622b248b6dd..b2f01cd2cd65 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -27,6 +27,11 @@ obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o
27# NAT protocols (nf_nat) 27# NAT protocols (nf_nat)
28obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o 28obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o
29 29
30obj-$(CONFIG_NF_TABLES_IPV4) += nf_tables_ipv4.o
31obj-$(CONFIG_NFT_REJECT_IPV4) += nft_reject_ipv4.o
32obj-$(CONFIG_NF_TABLE_ROUTE_IPV4) += nf_table_route_ipv4.o
33obj-$(CONFIG_NF_TABLE_NAT_IPV4) += nf_table_nat_ipv4.o
34
30# generic IP tables 35# generic IP tables
31obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o 36obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
32 37
diff --git a/net/ipv4/netfilter/nf_table_nat_ipv4.c b/net/ipv4/netfilter/nf_table_nat_ipv4.c
new file mode 100644
index 000000000000..2a6f184c10bd
--- /dev/null
+++ b/net/ipv4/netfilter/nf_table_nat_ipv4.c
@@ -0,0 +1,409 @@
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/skbuff.h>
15#include <linux/ip.h>
16#include <linux/netlink.h>
17#include <linux/netfilter.h>
18#include <linux/netfilter_ipv4.h>
19#include <linux/netfilter/nfnetlink.h>
20#include <linux/netfilter/nf_tables.h>
21#include <net/netfilter/nf_conntrack.h>
22#include <net/netfilter/nf_nat.h>
23#include <net/netfilter/nf_nat_core.h>
24#include <net/netfilter/nf_tables.h>
25#include <net/netfilter/nf_nat_l3proto.h>
26#include <net/ip.h>
27
28struct nft_nat {
29 enum nft_registers sreg_addr_min:8;
30 enum nft_registers sreg_addr_max:8;
31 enum nft_registers sreg_proto_min:8;
32 enum nft_registers sreg_proto_max:8;
33 enum nf_nat_manip_type type;
34};
35
36static void nft_nat_eval(const struct nft_expr *expr,
37 struct nft_data data[NFT_REG_MAX + 1],
38 const struct nft_pktinfo *pkt)
39{
40 const struct nft_nat *priv = nft_expr_priv(expr);
41 enum ip_conntrack_info ctinfo;
42 struct nf_conn *ct = nf_ct_get(pkt->skb, &ctinfo);
43 struct nf_nat_range range;
44
45 memset(&range, 0, sizeof(range));
46 if (priv->sreg_addr_min) {
47 range.min_addr.ip = data[priv->sreg_addr_min].data[0];
48 range.max_addr.ip = data[priv->sreg_addr_max].data[0];
49 range.flags |= NF_NAT_RANGE_MAP_IPS;
50 }
51
52 if (priv->sreg_proto_min) {
53 range.min_proto.all = data[priv->sreg_proto_min].data[0];
54 range.max_proto.all = data[priv->sreg_proto_max].data[0];
55 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
56 }
57
58 data[NFT_REG_VERDICT].verdict =
59 nf_nat_setup_info(ct, &range, priv->type);
60}
61
62static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
63 [NFTA_NAT_ADDR_MIN] = { .type = NLA_U32 },
64 [NFTA_NAT_ADDR_MAX] = { .type = NLA_U32 },
65 [NFTA_NAT_PROTO_MIN] = { .type = NLA_U32 },
66 [NFTA_NAT_PROTO_MAX] = { .type = NLA_U32 },
67 [NFTA_NAT_TYPE] = { .type = NLA_U32 },
68};
69
70static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
71 const struct nlattr * const tb[])
72{
73 struct nft_nat *priv = nft_expr_priv(expr);
74 int err;
75
76 if (tb[NFTA_NAT_TYPE] == NULL)
77 return -EINVAL;
78
79 switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) {
80 case NFT_NAT_SNAT:
81 priv->type = NF_NAT_MANIP_SRC;
82 break;
83 case NFT_NAT_DNAT:
84 priv->type = NF_NAT_MANIP_DST;
85 break;
86 default:
87 return -EINVAL;
88 }
89
90 if (tb[NFTA_NAT_ADDR_MIN]) {
91 priv->sreg_addr_min = ntohl(nla_get_be32(tb[NFTA_NAT_ADDR_MIN]));
92 err = nft_validate_input_register(priv->sreg_addr_min);
93 if (err < 0)
94 return err;
95 }
96
97 if (tb[NFTA_NAT_ADDR_MAX]) {
98 priv->sreg_addr_max = ntohl(nla_get_be32(tb[NFTA_NAT_ADDR_MAX]));
99 err = nft_validate_input_register(priv->sreg_addr_max);
100 if (err < 0)
101 return err;
102 } else
103 priv->sreg_addr_max = priv->sreg_addr_min;
104
105 if (tb[NFTA_NAT_PROTO_MIN]) {
106 priv->sreg_proto_min = ntohl(nla_get_be32(tb[NFTA_NAT_PROTO_MIN]));
107 err = nft_validate_input_register(priv->sreg_proto_min);
108 if (err < 0)
109 return err;
110 }
111
112 if (tb[NFTA_NAT_PROTO_MAX]) {
113 priv->sreg_proto_max = ntohl(nla_get_be32(tb[NFTA_NAT_PROTO_MAX]));
114 err = nft_validate_input_register(priv->sreg_proto_max);
115 if (err < 0)
116 return err;
117 } else
118 priv->sreg_proto_max = priv->sreg_proto_min;
119
120 return 0;
121}
122
123static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
124{
125 const struct nft_nat *priv = nft_expr_priv(expr);
126
127 switch (priv->type) {
128 case NF_NAT_MANIP_SRC:
129 if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_SNAT)))
130 goto nla_put_failure;
131 break;
132 case NF_NAT_MANIP_DST:
133 if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_DNAT)))
134 goto nla_put_failure;
135 break;
136 }
137
138 if (nla_put_be32(skb, NFTA_NAT_ADDR_MIN, htonl(priv->sreg_addr_min)))
139 goto nla_put_failure;
140 if (nla_put_be32(skb, NFTA_NAT_ADDR_MAX, htonl(priv->sreg_addr_max)))
141 goto nla_put_failure;
142 if (nla_put_be32(skb, NFTA_NAT_PROTO_MIN, htonl(priv->sreg_proto_min)))
143 goto nla_put_failure;
144 if (nla_put_be32(skb, NFTA_NAT_PROTO_MAX, htonl(priv->sreg_proto_max)))
145 goto nla_put_failure;
146 return 0;
147
148nla_put_failure:
149 return -1;
150}
151
152static struct nft_expr_ops nft_nat_ops __read_mostly = {
153 .name = "nat",
154 .size = NFT_EXPR_SIZE(sizeof(struct nft_nat)),
155 .owner = THIS_MODULE,
156 .eval = nft_nat_eval,
157 .init = nft_nat_init,
158 .dump = nft_nat_dump,
159 .policy = nft_nat_policy,
160 .maxattr = NFTA_NAT_MAX,
161};
162
163/*
164 * NAT table
165 */
166
167static unsigned int nf_nat_fn(const struct nf_hook_ops *ops,
168 struct sk_buff *skb,
169 const struct net_device *in,
170 const struct net_device *out,
171 int (*okfn)(struct sk_buff *))
172{
173 enum ip_conntrack_info ctinfo;
174 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
175 struct nf_conn_nat *nat;
176 enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
177 unsigned int ret;
178
179 if (ct == NULL || nf_ct_is_untracked(ct))
180 return NF_ACCEPT;
181
182 NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)));
183
184 nat = nfct_nat(ct);
185 if (nat == NULL) {
186 /* Conntrack module was loaded late, can't add extension. */
187 if (nf_ct_is_confirmed(ct))
188 return NF_ACCEPT;
189 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
190 if (nat == NULL)
191 return NF_ACCEPT;
192 }
193
194 switch (ctinfo) {
195 case IP_CT_RELATED:
196 case IP_CT_RELATED + IP_CT_IS_REPLY:
197 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
198 if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo,
199 ops->hooknum))
200 return NF_DROP;
201 else
202 return NF_ACCEPT;
203 }
204 /* Fall through */
205 case IP_CT_NEW:
206 if (nf_nat_initialized(ct, maniptype))
207 break;
208
209 ret = nft_do_chain(ops, skb, in, out, okfn);
210 if (ret != NF_ACCEPT)
211 return ret;
212 if (!nf_nat_initialized(ct, maniptype)) {
213 ret = nf_nat_alloc_null_binding(ct, ops->hooknum);
214 if (ret != NF_ACCEPT)
215 return ret;
216 }
217 default:
218 break;
219 }
220
221 return nf_nat_packet(ct, ctinfo, ops->hooknum, skb);
222}
223
224static unsigned int nf_nat_prerouting(const struct nf_hook_ops *ops,
225 struct sk_buff *skb,
226 const struct net_device *in,
227 const struct net_device *out,
228 int (*okfn)(struct sk_buff *))
229{
230 __be32 daddr = ip_hdr(skb)->daddr;
231 unsigned int ret;
232
233 ret = nf_nat_fn(ops, skb, in, out, okfn);
234 if (ret != NF_DROP && ret != NF_STOLEN &&
235 ip_hdr(skb)->daddr != daddr) {
236 skb_dst_drop(skb);
237 }
238 return ret;
239}
240
241static unsigned int nf_nat_postrouting(const struct nf_hook_ops *ops,
242 struct sk_buff *skb,
243 const struct net_device *in,
244 const struct net_device *out,
245 int (*okfn)(struct sk_buff *))
246{
247 enum ip_conntrack_info ctinfo __maybe_unused;
248 const struct nf_conn *ct __maybe_unused;
249 unsigned int ret;
250
251 ret = nf_nat_fn(ops, skb, in, out, okfn);
252#ifdef CONFIG_XFRM
253 if (ret != NF_DROP && ret != NF_STOLEN &&
254 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
255 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
256
257 if (ct->tuplehash[dir].tuple.src.u3.ip !=
258 ct->tuplehash[!dir].tuple.dst.u3.ip ||
259 ct->tuplehash[dir].tuple.src.u.all !=
260 ct->tuplehash[!dir].tuple.dst.u.all)
261 return nf_xfrm_me_harder(skb, AF_INET) == 0 ?
262 ret : NF_DROP;
263 }
264#endif
265 return ret;
266}
267
268static unsigned int nf_nat_output(const struct nf_hook_ops *ops,
269 struct sk_buff *skb,
270 const struct net_device *in,
271 const struct net_device *out,
272 int (*okfn)(struct sk_buff *))
273{
274 enum ip_conntrack_info ctinfo;
275 const struct nf_conn *ct;
276 unsigned int ret;
277
278 ret = nf_nat_fn(ops, skb, in, out, okfn);
279 if (ret != NF_DROP && ret != NF_STOLEN &&
280 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
281 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
282
283 if (ct->tuplehash[dir].tuple.dst.u3.ip !=
284 ct->tuplehash[!dir].tuple.src.u3.ip) {
285 if (ip_route_me_harder(skb, RTN_UNSPEC))
286 ret = NF_DROP;
287 }
288#ifdef CONFIG_XFRM
289 else if (ct->tuplehash[dir].tuple.dst.u.all !=
290 ct->tuplehash[!dir].tuple.src.u.all)
291 if (nf_xfrm_me_harder(skb, AF_INET))
292 ret = NF_DROP;
293#endif
294 }
295 return ret;
296}
297
298static struct nft_base_chain nf_chain_nat_prerouting __read_mostly = {
299 .chain = {
300 .name = "PREROUTING",
301 .rules = LIST_HEAD_INIT(nf_chain_nat_prerouting.chain.rules),
302 .flags = NFT_BASE_CHAIN | NFT_CHAIN_BUILTIN,
303 },
304 .ops = {
305 .hook = nf_nat_prerouting,
306 .owner = THIS_MODULE,
307 .pf = NFPROTO_IPV4,
308 .hooknum = NF_INET_PRE_ROUTING,
309 .priority = NF_IP_PRI_NAT_DST,
310 .priv = &nf_chain_nat_prerouting.chain,
311 },
312};
313
314static struct nft_base_chain nf_chain_nat_postrouting __read_mostly = {
315 .chain = {
316 .name = "POSTROUTING",
317 .rules = LIST_HEAD_INIT(nf_chain_nat_postrouting.chain.rules),
318 .flags = NFT_BASE_CHAIN | NFT_CHAIN_BUILTIN,
319 },
320 .ops = {
321 .hook = nf_nat_postrouting,
322 .owner = THIS_MODULE,
323 .pf = NFPROTO_IPV4,
324 .hooknum = NF_INET_POST_ROUTING,
325 .priority = NF_IP_PRI_NAT_SRC,
326 .priv = &nf_chain_nat_postrouting.chain,
327 },
328};
329
330static struct nft_base_chain nf_chain_nat_output __read_mostly = {
331 .chain = {
332 .name = "OUTPUT",
333 .rules = LIST_HEAD_INIT(nf_chain_nat_output.chain.rules),
334 .flags = NFT_BASE_CHAIN | NFT_CHAIN_BUILTIN,
335 },
336 .ops = {
337 .hook = nf_nat_output,
338 .owner = THIS_MODULE,
339 .pf = NFPROTO_IPV4,
340 .hooknum = NF_INET_LOCAL_OUT,
341 .priority = NF_IP_PRI_NAT_DST,
342 .priv = &nf_chain_nat_output.chain,
343 },
344};
345
346static struct nft_base_chain nf_chain_nat_input __read_mostly = {
347 .chain = {
348 .name = "INPUT",
349 .rules = LIST_HEAD_INIT(nf_chain_nat_input.chain.rules),
350 .flags = NFT_BASE_CHAIN | NFT_CHAIN_BUILTIN,
351 },
352 .ops = {
353 .hook = nf_nat_fn,
354 .owner = THIS_MODULE,
355 .pf = NFPROTO_IPV4,
356 .hooknum = NF_INET_LOCAL_IN,
357 .priority = NF_IP_PRI_NAT_SRC,
358 .priv = &nf_chain_nat_input.chain,
359 },
360};
361
362
363static struct nft_table nf_table_nat_ipv4 __read_mostly = {
364 .name = "nat",
365 .chains = LIST_HEAD_INIT(nf_table_nat_ipv4.chains),
366};
367
368static int __init nf_table_nat_init(void)
369{
370 int err;
371
372 list_add_tail(&nf_chain_nat_prerouting.chain.list,
373 &nf_table_nat_ipv4.chains);
374 list_add_tail(&nf_chain_nat_postrouting.chain.list,
375 &nf_table_nat_ipv4.chains);
376 list_add_tail(&nf_chain_nat_output.chain.list,
377 &nf_table_nat_ipv4.chains);
378 list_add_tail(&nf_chain_nat_input.chain.list,
379 &nf_table_nat_ipv4.chains);
380
381 err = nft_register_table(&nf_table_nat_ipv4, NFPROTO_IPV4);
382 if (err < 0)
383 goto err1;
384
385 err = nft_register_expr(&nft_nat_ops);
386 if (err < 0)
387 goto err2;
388
389 return 0;
390
391err2:
392 nft_unregister_table(&nf_table_nat_ipv4, NFPROTO_IPV4);
393err1:
394 return err;
395}
396
397static void __exit nf_table_nat_exit(void)
398{
399 nft_unregister_expr(&nft_nat_ops);
400 nft_unregister_table(&nf_table_nat_ipv4, AF_INET);
401}
402
403module_init(nf_table_nat_init);
404module_exit(nf_table_nat_exit);
405
406MODULE_LICENSE("GPL");
407MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
408MODULE_ALIAS_NFT_TABLE(AF_INET, "nat");
409MODULE_ALIAS_NFT_EXPR("nat");
diff --git a/net/ipv4/netfilter/nf_table_route_ipv4.c b/net/ipv4/netfilter/nf_table_route_ipv4.c
new file mode 100644
index 000000000000..4f257a1ed661
--- /dev/null
+++ b/net/ipv4/netfilter/nf_table_route_ipv4.c
@@ -0,0 +1,97 @@
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
9#include <linux/module.h>
10#include <linux/init.h>
11#include <linux/list.h>
12#include <linux/skbuff.h>
13#include <linux/netlink.h>
14#include <linux/netfilter.h>
15#include <linux/netfilter_ipv4.h>
16#include <linux/netfilter/nfnetlink.h>
17#include <linux/netfilter/nf_tables.h>
18#include <net/netfilter/nf_tables.h>
19#include <net/route.h>
20#include <net/ip.h>
21
22static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops,
23 struct sk_buff *skb,
24 const struct net_device *in,
25 const struct net_device *out,
26 int (*okfn)(struct sk_buff *))
27{
28 unsigned int ret;
29 u32 mark;
30 __be32 saddr, daddr;
31 u_int8_t tos;
32 const struct iphdr *iph;
33
34 /* root is playing with raw sockets. */
35 if (skb->len < sizeof(struct iphdr) ||
36 ip_hdrlen(skb) < sizeof(struct iphdr))
37 return NF_ACCEPT;
38
39 mark = skb->mark;
40 iph = ip_hdr(skb);
41 saddr = iph->saddr;
42 daddr = iph->daddr;
43 tos = iph->tos;
44
45 ret = nft_do_chain(ops, skb, in, out, okfn);
46 if (ret != NF_DROP && ret != NF_QUEUE) {
47 iph = ip_hdr(skb);
48
49 if (iph->saddr != saddr ||
50 iph->daddr != daddr ||
51 skb->mark != mark ||
52 iph->tos != tos)
53 if (ip_route_me_harder(skb, RTN_UNSPEC))
54 ret = NF_DROP;
55 }
56 return ret;
57}
58
59static struct nft_base_chain nf_chain_route_output __read_mostly = {
60 .chain = {
61 .name = "OUTPUT",
62 .rules = LIST_HEAD_INIT(nf_chain_route_output.chain.rules),
63 .flags = NFT_BASE_CHAIN | NFT_CHAIN_BUILTIN,
64 },
65 .ops = {
66 .hook = nf_route_table_hook,
67 .owner = THIS_MODULE,
68 .pf = NFPROTO_IPV4,
69 .hooknum = NF_INET_LOCAL_OUT,
70 .priority = NF_IP_PRI_MANGLE,
71 .priv = &nf_chain_route_output.chain,
72 },
73};
74
75static struct nft_table nf_table_route_ipv4 __read_mostly = {
76 .name = "route",
77 .chains = LIST_HEAD_INIT(nf_table_route_ipv4.chains),
78};
79
80static int __init nf_table_route_init(void)
81{
82 list_add_tail(&nf_chain_route_output.chain.list,
83 &nf_table_route_ipv4.chains);
84 return nft_register_table(&nf_table_route_ipv4, NFPROTO_IPV4);
85}
86
87static void __exit nf_table_route_exit(void)
88{
89 nft_unregister_table(&nf_table_route_ipv4, NFPROTO_IPV4);
90}
91
92module_init(nf_table_route_init);
93module_exit(nf_table_route_exit);
94
95MODULE_LICENSE("GPL");
96MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
97MODULE_ALIAS_NFT_TABLE(AF_INET, "route");
diff --git a/net/ipv4/netfilter/nf_tables_ipv4.c b/net/ipv4/netfilter/nf_tables_ipv4.c
new file mode 100644
index 000000000000..63d0a3bf53d3
--- /dev/null
+++ b/net/ipv4/netfilter/nf_tables_ipv4.c
@@ -0,0 +1,59 @@
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/init.h>
12#include <linux/module.h>
13#include <linux/ip.h>
14#include <linux/netfilter_ipv4.h>
15#include <net/netfilter/nf_tables.h>
16#include <net/ip.h>
17
18static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops,
19 struct sk_buff *skb,
20 const struct net_device *in,
21 const struct net_device *out,
22 int (*okfn)(struct sk_buff *))
23{
24 if (unlikely(skb->len < sizeof(struct iphdr) ||
25 ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) {
26 if (net_ratelimit())
27 pr_info("nf_tables_ipv4: ignoring short SOCK_RAW "
28 "packet\n");
29 return NF_ACCEPT;
30 }
31
32 return nft_do_chain(ops, skb, in, out, okfn);
33}
34
35static struct nft_af_info nft_af_ipv4 __read_mostly = {
36 .family = NFPROTO_IPV4,
37 .nhooks = NF_INET_NUMHOOKS,
38 .owner = THIS_MODULE,
39 .hooks = {
40 [NF_INET_LOCAL_OUT] = nft_ipv4_output,
41 },
42};
43
44static int __init nf_tables_ipv4_init(void)
45{
46 return nft_register_afinfo(&nft_af_ipv4);
47}
48
49static void __exit nf_tables_ipv4_exit(void)
50{
51 nft_unregister_afinfo(&nft_af_ipv4);
52}
53
54module_init(nf_tables_ipv4_init);
55module_exit(nf_tables_ipv4_exit);
56
57MODULE_LICENSE("GPL");
58MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
59MODULE_ALIAS_NFT_FAMILY(AF_INET);
diff --git a/net/ipv4/netfilter/nft_reject_ipv4.c b/net/ipv4/netfilter/nft_reject_ipv4.c
new file mode 100644
index 000000000000..b4ee8d3bb1e4
--- /dev/null
+++ b/net/ipv4/netfilter/nft_reject_ipv4.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/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/icmp.h>
19
20struct nft_reject {
21 enum nft_reject_types type:8;
22 u8 icmp_code;
23};
24
25static void nft_reject_eval(const struct nft_expr *expr,
26 struct nft_data data[NFT_REG_MAX + 1],
27 const struct nft_pktinfo *pkt)
28{
29 struct nft_reject *priv = nft_expr_priv(expr);
30
31 switch (priv->type) {
32 case NFT_REJECT_ICMP_UNREACH:
33 icmp_send(pkt->skb, ICMP_DEST_UNREACH, priv->icmp_code, 0);
34 break;
35 case NFT_REJECT_TCP_RST:
36 break;
37 }
38
39 data[NFT_REG_VERDICT].verdict = NF_DROP;
40}
41
42static const struct nla_policy nft_reject_policy[NFTA_REJECT_MAX + 1] = {
43 [NFTA_REJECT_TYPE] = { .type = NLA_U32 },
44 [NFTA_REJECT_ICMP_CODE] = { .type = NLA_U8 },
45};
46
47static int nft_reject_init(const struct nft_ctx *ctx,
48 const struct nft_expr *expr,
49 const struct nlattr * const tb[])
50{
51 struct nft_reject *priv = nft_expr_priv(expr);
52
53 if (tb[NFTA_REJECT_TYPE] == NULL)
54 return -EINVAL;
55
56 priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE]));
57 switch (priv->type) {
58 case NFT_REJECT_ICMP_UNREACH:
59 if (tb[NFTA_REJECT_ICMP_CODE] == NULL)
60 return -EINVAL;
61 priv->icmp_code = nla_get_u8(tb[NFTA_REJECT_ICMP_CODE]);
62 case NFT_REJECT_TCP_RST:
63 break;
64 default:
65 return -EINVAL;
66 }
67
68 return 0;
69}
70
71static int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr)
72{
73 const struct nft_reject *priv = nft_expr_priv(expr);
74
75 if (nla_put_be32(skb, NFTA_REJECT_TYPE, priv->type))
76 goto nla_put_failure;
77
78 switch (priv->type) {
79 case NFT_REJECT_ICMP_UNREACH:
80 if (nla_put_u8(skb, NFTA_REJECT_ICMP_CODE, priv->icmp_code))
81 goto nla_put_failure;
82 break;
83 }
84
85 return 0;
86
87nla_put_failure:
88 return -1;
89}
90
91static struct nft_expr_ops reject_ops __read_mostly = {
92 .name = "reject",
93 .size = NFT_EXPR_SIZE(sizeof(struct nft_reject)),
94 .owner = THIS_MODULE,
95 .eval = nft_reject_eval,
96 .init = nft_reject_init,
97 .dump = nft_reject_dump,
98 .policy = nft_reject_policy,
99 .maxattr = NFTA_REJECT_MAX,
100};
101
102static int __init nft_reject_module_init(void)
103{
104 return nft_register_expr(&reject_ops);
105}
106
107static void __exit nft_reject_module_exit(void)
108{
109 nft_unregister_expr(&reject_ops);
110}
111
112module_init(nft_reject_module_init);
113module_exit(nft_reject_module_exit);
114
115MODULE_LICENSE("GPL");
116MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
117MODULE_ALIAS_NFT_EXPR("reject");
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index a7f842b29b67..5677e38eeca3 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -25,6 +25,14 @@ config NF_CONNTRACK_IPV6
25 25
26 To compile it as a module, choose M here. If unsure, say N. 26 To compile it as a module, choose M here. If unsure, say N.
27 27
28config NF_TABLES_IPV6
29 depends on NF_TABLES
30 tristate "IPv6 nf_tables support"
31
32config NF_TABLE_ROUTE_IPV6
33 depends on NF_TABLES_IPV6
34 tristate "IPv6 nf_tables route table support"
35
28config IP6_NF_IPTABLES 36config IP6_NF_IPTABLES
29 tristate "IP6 tables support (required for filtering)" 37 tristate "IP6 tables support (required for filtering)"
30 depends on INET && IPV6 38 depends on INET && IPV6
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index 2b53738f798c..956af4492d10 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -23,6 +23,10 @@ obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o
23nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o 23nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o
24obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o 24obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o
25 25
26# nf_tables
27obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o
28obj-$(CONFIG_NF_TABLE_ROUTE_IPV6) += nf_table_route_ipv6.o
29
26# matches 30# matches
27obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o 31obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
28obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o 32obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
diff --git a/net/ipv6/netfilter/nf_table_route_ipv6.c b/net/ipv6/netfilter/nf_table_route_ipv6.c
new file mode 100644
index 000000000000..48ac65c7b398
--- /dev/null
+++ b/net/ipv6/netfilter/nf_table_route_ipv6.c
@@ -0,0 +1,93 @@
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/skbuff.h>
15#include <linux/netlink.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter_ipv6.h>
18#include <linux/netfilter/nfnetlink.h>
19#include <linux/netfilter/nf_tables.h>
20#include <net/netfilter/nf_tables.h>
21#include <net/route.h>
22
23static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops,
24 struct sk_buff *skb,
25 const struct net_device *in,
26 const struct net_device *out,
27 int (*okfn)(struct sk_buff *))
28{
29 unsigned int ret;
30 struct in6_addr saddr, daddr;
31 u_int8_t hop_limit;
32 u32 mark, flowlabel;
33
34 /* save source/dest address, mark, hoplimit, flowlabel, priority */
35 memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr));
36 memcpy(&daddr, &ipv6_hdr(skb)->daddr, sizeof(daddr));
37 mark = skb->mark;
38 hop_limit = ipv6_hdr(skb)->hop_limit;
39
40 /* flowlabel and prio (includes version, which shouldn't change either */
41 flowlabel = *((u32 *)ipv6_hdr(skb));
42
43 ret = nft_do_chain(ops, skb, in, out, okfn);
44 if (ret != NF_DROP && ret != NF_QUEUE &&
45 (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) ||
46 memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) ||
47 skb->mark != mark ||
48 ipv6_hdr(skb)->hop_limit != hop_limit ||
49 flowlabel != *((u_int32_t *)ipv6_hdr(skb))))
50 return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP;
51
52 return ret;
53}
54
55static struct nft_base_chain nf_chain_route_output __read_mostly = {
56 .chain = {
57 .name = "OUTPUT",
58 .rules = LIST_HEAD_INIT(nf_chain_route_output.chain.rules),
59 .flags = NFT_BASE_CHAIN | NFT_CHAIN_BUILTIN,
60 },
61 .ops = {
62 .hook = nf_route_table_hook,
63 .owner = THIS_MODULE,
64 .pf = NFPROTO_IPV6,
65 .hooknum = NF_INET_LOCAL_OUT,
66 .priority = NF_IP6_PRI_MANGLE,
67 .priv = &nf_chain_route_output.chain,
68 },
69};
70
71static struct nft_table nf_table_route_ipv6 __read_mostly = {
72 .name = "route",
73 .chains = LIST_HEAD_INIT(nf_table_route_ipv6.chains),
74};
75
76static int __init nf_table_route_init(void)
77{
78 list_add_tail(&nf_chain_route_output.chain.list,
79 &nf_table_route_ipv6.chains);
80 return nft_register_table(&nf_table_route_ipv6, NFPROTO_IPV6);
81}
82
83static void __exit nf_table_route_exit(void)
84{
85 nft_unregister_table(&nf_table_route_ipv6, NFPROTO_IPV6);
86}
87
88module_init(nf_table_route_init);
89module_exit(nf_table_route_exit);
90
91MODULE_LICENSE("GPL");
92MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
93MODULE_ALIAS_NFT_TABLE(AF_INET6, "route");
diff --git a/net/ipv6/netfilter/nf_tables_ipv6.c b/net/ipv6/netfilter/nf_tables_ipv6.c
new file mode 100644
index 000000000000..e0717cea4913
--- /dev/null
+++ b/net/ipv6/netfilter/nf_tables_ipv6.c
@@ -0,0 +1,57 @@
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/init.h>
12#include <linux/module.h>
13#include <linux/ipv6.h>
14#include <linux/netfilter_ipv6.h>
15#include <net/netfilter/nf_tables.h>
16
17static unsigned int nft_ipv6_output(const struct nf_hook_ops *ops,
18 struct sk_buff *skb,
19 const struct net_device *in,
20 const struct net_device *out,
21 int (*okfn)(struct sk_buff *))
22{
23 if (unlikely(skb->len < sizeof(struct ipv6hdr))) {
24 if (net_ratelimit())
25 pr_info("nf_tables_ipv6: ignoring short SOCK_RAW "
26 "packet\n");
27 return NF_ACCEPT;
28 }
29
30 return nft_do_chain(ops, skb, in, out, okfn);
31}
32
33static struct nft_af_info nft_af_ipv6 __read_mostly = {
34 .family = NFPROTO_IPV6,
35 .nhooks = NF_INET_NUMHOOKS,
36 .owner = THIS_MODULE,
37 .hooks = {
38 [NF_INET_LOCAL_OUT] = nft_ipv6_output,
39 },
40};
41
42static int __init nf_tables_ipv6_init(void)
43{
44 return nft_register_afinfo(&nft_af_ipv6);
45}
46
47static void __exit nf_tables_ipv6_exit(void)
48{
49 nft_unregister_afinfo(&nft_af_ipv6);
50}
51
52module_init(nf_tables_ipv6_init);
53module_exit(nf_tables_ipv6_exit);
54
55MODULE_LICENSE("GPL");
56MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
57MODULE_ALIAS_NFT_FAMILY(AF_INET6);
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");