aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2016-09-23 09:23:33 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2016-09-25 17:16:42 -0400
commit0f3cd9b3697708c86a825ae3cedabf7be6fd3e72 (patch)
tree14b59bebf1a6dc16a961864a93febfbacc4d3715 /net
parent7a682575ad4829b4de3e672a6ad5f73a05826b82 (diff)
netfilter: nf_tables: add range expression
Inverse ranges != [a,b] are not currently possible because rules are composites of && operations, and we need to express this: data < a || data > b This patch adds a new range expression. Positive ranges can be already through two cmp expressions: cmp(sreg, data, >=) cmp(sreg, data, <=) This new range expression provides an alternative way to express this. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/Makefile3
-rw-r--r--net/netfilter/nf_tables_core.c7
-rw-r--r--net/netfilter/nft_range.c138
3 files changed, 146 insertions, 2 deletions
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 0c8581100ac6..c23c3c84416f 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -71,8 +71,9 @@ obj-$(CONFIG_NF_DUP_NETDEV) += nf_dup_netdev.o
71 71
72# nf_tables 72# nf_tables
73nf_tables-objs += nf_tables_core.o nf_tables_api.o nf_tables_trace.o 73nf_tables-objs += nf_tables_core.o nf_tables_api.o nf_tables_trace.o
74nf_tables-objs += nft_immediate.o nft_cmp.o nft_lookup.o nft_dynset.o 74nf_tables-objs += nft_immediate.o nft_cmp.o nft_range.o
75nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o 75nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o
76nf_tables-objs += nft_lookup.o nft_dynset.o
76 77
77obj-$(CONFIG_NF_TABLES) += nf_tables.o 78obj-$(CONFIG_NF_TABLES) += nf_tables.o
78obj-$(CONFIG_NF_TABLES_INET) += nf_tables_inet.o 79obj-$(CONFIG_NF_TABLES_INET) += nf_tables_inet.o
diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
index 67259cefef06..7c94ce0080d5 100644
--- a/net/netfilter/nf_tables_core.c
+++ b/net/netfilter/nf_tables_core.c
@@ -263,8 +263,13 @@ int __init nf_tables_core_module_init(void)
263 if (err < 0) 263 if (err < 0)
264 goto err7; 264 goto err7;
265 265
266 return 0; 266 err = nft_range_module_init();
267 if (err < 0)
268 goto err8;
267 269
270 return 0;
271err8:
272 nft_dynset_module_exit();
268err7: 273err7:
269 nft_payload_module_exit(); 274 nft_payload_module_exit();
270err6: 275err6:
diff --git a/net/netfilter/nft_range.c b/net/netfilter/nft_range.c
new file mode 100644
index 000000000000..c6d5358482d1
--- /dev/null
+++ b/net/netfilter/nft_range.c
@@ -0,0 +1,138 @@
1/*
2 * Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.org>
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/kernel.h>
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/netlink.h>
13#include <linux/netfilter.h>
14#include <linux/netfilter/nf_tables.h>
15#include <net/netfilter/nf_tables_core.h>
16#include <net/netfilter/nf_tables.h>
17
18struct nft_range_expr {
19 struct nft_data data_from;
20 struct nft_data data_to;
21 enum nft_registers sreg:8;
22 u8 len;
23 enum nft_range_ops op:8;
24};
25
26static void nft_range_eval(const struct nft_expr *expr,
27 struct nft_regs *regs,
28 const struct nft_pktinfo *pkt)
29{
30 const struct nft_range_expr *priv = nft_expr_priv(expr);
31 bool mismatch;
32 int d1, d2;
33
34 d1 = memcmp(&regs->data[priv->sreg], &priv->data_from, priv->len);
35 d2 = memcmp(&regs->data[priv->sreg], &priv->data_to, priv->len);
36 switch (priv->op) {
37 case NFT_RANGE_EQ:
38 mismatch = (d1 < 0 || d2 > 0);
39 break;
40 case NFT_RANGE_NEQ:
41 mismatch = (d1 >= 0 && d2 <= 0);
42 break;
43 }
44
45 if (mismatch)
46 regs->verdict.code = NFT_BREAK;
47}
48
49static const struct nla_policy nft_range_policy[NFTA_RANGE_MAX + 1] = {
50 [NFTA_RANGE_SREG] = { .type = NLA_U32 },
51 [NFTA_RANGE_OP] = { .type = NLA_U32 },
52 [NFTA_RANGE_FROM_DATA] = { .type = NLA_NESTED },
53 [NFTA_RANGE_TO_DATA] = { .type = NLA_NESTED },
54};
55
56static int nft_range_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
57 const struct nlattr * const tb[])
58{
59 struct nft_range_expr *priv = nft_expr_priv(expr);
60 struct nft_data_desc desc_from, desc_to;
61 int err;
62
63 err = nft_data_init(NULL, &priv->data_from, sizeof(priv->data_from),
64 &desc_from, tb[NFTA_RANGE_FROM_DATA]);
65 if (err < 0)
66 return err;
67
68 err = nft_data_init(NULL, &priv->data_to, sizeof(priv->data_to),
69 &desc_to, tb[NFTA_RANGE_TO_DATA]);
70 if (err < 0)
71 goto err1;
72
73 if (desc_from.len != desc_to.len) {
74 err = -EINVAL;
75 goto err2;
76 }
77
78 priv->sreg = nft_parse_register(tb[NFTA_RANGE_SREG]);
79 err = nft_validate_register_load(priv->sreg, desc_from.len);
80 if (err < 0)
81 goto err2;
82
83 priv->op = ntohl(nla_get_be32(tb[NFTA_RANGE_OP]));
84 priv->len = desc_from.len;
85 return 0;
86err2:
87 nft_data_uninit(&priv->data_to, desc_to.type);
88err1:
89 nft_data_uninit(&priv->data_from, desc_from.type);
90 return err;
91}
92
93static int nft_range_dump(struct sk_buff *skb, const struct nft_expr *expr)
94{
95 const struct nft_range_expr *priv = nft_expr_priv(expr);
96
97 if (nft_dump_register(skb, NFTA_RANGE_SREG, priv->sreg))
98 goto nla_put_failure;
99 if (nla_put_be32(skb, NFTA_RANGE_OP, htonl(priv->op)))
100 goto nla_put_failure;
101
102 if (nft_data_dump(skb, NFTA_RANGE_FROM_DATA, &priv->data_from,
103 NFT_DATA_VALUE, priv->len) < 0 ||
104 nft_data_dump(skb, NFTA_RANGE_TO_DATA, &priv->data_to,
105 NFT_DATA_VALUE, priv->len) < 0)
106 goto nla_put_failure;
107 return 0;
108
109nla_put_failure:
110 return -1;
111}
112
113static struct nft_expr_type nft_range_type;
114static const struct nft_expr_ops nft_range_ops = {
115 .type = &nft_range_type,
116 .size = NFT_EXPR_SIZE(sizeof(struct nft_range_expr)),
117 .eval = nft_range_eval,
118 .init = nft_range_init,
119 .dump = nft_range_dump,
120};
121
122static struct nft_expr_type nft_range_type __read_mostly = {
123 .name = "range",
124 .ops = &nft_range_ops,
125 .policy = nft_range_policy,
126 .maxattr = NFTA_RANGE_MAX,
127 .owner = THIS_MODULE,
128};
129
130int __init nft_range_module_init(void)
131{
132 return nft_register_expr(&nft_range_type);
133}
134
135void nft_range_module_exit(void)
136{
137 nft_unregister_expr(&nft_range_type);
138}