aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/uapi/linux/netfilter/nf_tables.h2
-rw-r--r--net/netfilter/nft_ct.c164
2 files changed, 136 insertions, 30 deletions
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 448593c07120..83c985a6170b 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -609,12 +609,14 @@ enum nft_ct_keys {
609 * @NFTA_CT_DREG: destination register (NLA_U32) 609 * @NFTA_CT_DREG: destination register (NLA_U32)
610 * @NFTA_CT_KEY: conntrack data item to load (NLA_U32: nft_ct_keys) 610 * @NFTA_CT_KEY: conntrack data item to load (NLA_U32: nft_ct_keys)
611 * @NFTA_CT_DIRECTION: direction in case of directional keys (NLA_U8) 611 * @NFTA_CT_DIRECTION: direction in case of directional keys (NLA_U8)
612 * @NFTA_CT_SREG: source register (NLA_U32)
612 */ 613 */
613enum nft_ct_attributes { 614enum nft_ct_attributes {
614 NFTA_CT_UNSPEC, 615 NFTA_CT_UNSPEC,
615 NFTA_CT_DREG, 616 NFTA_CT_DREG,
616 NFTA_CT_KEY, 617 NFTA_CT_KEY,
617 NFTA_CT_DIRECTION, 618 NFTA_CT_DIRECTION,
619 NFTA_CT_SREG,
618 __NFTA_CT_MAX 620 __NFTA_CT_MAX
619}; 621};
620#define NFTA_CT_MAX (__NFTA_CT_MAX - 1) 622#define NFTA_CT_MAX (__NFTA_CT_MAX - 1)
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
index 3727a321c9a7..c7c12858e113 100644
--- a/net/netfilter/nft_ct.c
+++ b/net/netfilter/nft_ct.c
@@ -18,17 +18,21 @@
18#include <net/netfilter/nf_conntrack.h> 18#include <net/netfilter/nf_conntrack.h>
19#include <net/netfilter/nf_conntrack_tuple.h> 19#include <net/netfilter/nf_conntrack_tuple.h>
20#include <net/netfilter/nf_conntrack_helper.h> 20#include <net/netfilter/nf_conntrack_helper.h>
21#include <net/netfilter/nf_conntrack_ecache.h>
21 22
22struct nft_ct { 23struct nft_ct {
23 enum nft_ct_keys key:8; 24 enum nft_ct_keys key:8;
24 enum ip_conntrack_dir dir:8; 25 enum ip_conntrack_dir dir:8;
25 enum nft_registers dreg:8; 26 union{
27 enum nft_registers dreg:8;
28 enum nft_registers sreg:8;
29 };
26 uint8_t family; 30 uint8_t family;
27}; 31};
28 32
29static void nft_ct_eval(const struct nft_expr *expr, 33static void nft_ct_get_eval(const struct nft_expr *expr,
30 struct nft_data data[NFT_REG_MAX + 1], 34 struct nft_data data[NFT_REG_MAX + 1],
31 const struct nft_pktinfo *pkt) 35 const struct nft_pktinfo *pkt)
32{ 36{
33 const struct nft_ct *priv = nft_expr_priv(expr); 37 const struct nft_ct *priv = nft_expr_priv(expr);
34 struct nft_data *dest = &data[priv->dreg]; 38 struct nft_data *dest = &data[priv->dreg];
@@ -123,10 +127,37 @@ err:
123 data[NFT_REG_VERDICT].verdict = NFT_BREAK; 127 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
124} 128}
125 129
130static void nft_ct_set_eval(const struct nft_expr *expr,
131 struct nft_data data[NFT_REG_MAX + 1],
132 const struct nft_pktinfo *pkt)
133{
134 const struct nft_ct *priv = nft_expr_priv(expr);
135 struct sk_buff *skb = pkt->skb;
136 u32 value = data[priv->sreg].data[0];
137 enum ip_conntrack_info ctinfo;
138 struct nf_conn *ct;
139
140 ct = nf_ct_get(skb, &ctinfo);
141 if (ct == NULL)
142 return;
143
144 switch (priv->key) {
145#ifdef CONFIG_NF_CONNTRACK_MARK
146 case NFT_CT_MARK:
147 if (ct->mark != value) {
148 ct->mark = value;
149 nf_conntrack_event_cache(IPCT_MARK, ct);
150 }
151 break;
152#endif
153 }
154}
155
126static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = { 156static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = {
127 [NFTA_CT_DREG] = { .type = NLA_U32 }, 157 [NFTA_CT_DREG] = { .type = NLA_U32 },
128 [NFTA_CT_KEY] = { .type = NLA_U32 }, 158 [NFTA_CT_KEY] = { .type = NLA_U32 },
129 [NFTA_CT_DIRECTION] = { .type = NLA_U8 }, 159 [NFTA_CT_DIRECTION] = { .type = NLA_U8 },
160 [NFTA_CT_SREG] = { .type = NLA_U32 },
130}; 161};
131 162
132static int nft_ct_l3proto_try_module_get(uint8_t family) 163static int nft_ct_l3proto_try_module_get(uint8_t family)
@@ -162,18 +193,11 @@ static void nft_ct_l3proto_module_put(uint8_t family)
162 nf_ct_l3proto_module_put(family); 193 nf_ct_l3proto_module_put(family);
163} 194}
164 195
165static int nft_ct_init(const struct nft_ctx *ctx, 196static int nft_ct_init_validate_get(const struct nft_expr *expr,
166 const struct nft_expr *expr, 197 const struct nlattr * const tb[])
167 const struct nlattr * const tb[])
168{ 198{
169 struct nft_ct *priv = nft_expr_priv(expr); 199 struct nft_ct *priv = nft_expr_priv(expr);
170 int err;
171 200
172 if (tb[NFTA_CT_DREG] == NULL ||
173 tb[NFTA_CT_KEY] == NULL)
174 return -EINVAL;
175
176 priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
177 if (tb[NFTA_CT_DIRECTION] != NULL) { 201 if (tb[NFTA_CT_DIRECTION] != NULL) {
178 priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]); 202 priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
179 switch (priv->dir) { 203 switch (priv->dir) {
@@ -212,24 +236,62 @@ static int nft_ct_init(const struct nft_ctx *ctx,
212 return -EOPNOTSUPP; 236 return -EOPNOTSUPP;
213 } 237 }
214 238
239 return 0;
240}
241
242static int nft_ct_init_validate_set(uint32_t key)
243{
244 switch (key) {
245 case NFT_CT_MARK:
246 break;
247 default:
248 return -EOPNOTSUPP;
249 }
250
251 return 0;
252}
253
254static int nft_ct_init(const struct nft_ctx *ctx,
255 const struct nft_expr *expr,
256 const struct nlattr * const tb[])
257{
258 struct nft_ct *priv = nft_expr_priv(expr);
259 int err;
260
261 priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
262
263 if (tb[NFTA_CT_DREG]) {
264 err = nft_ct_init_validate_get(expr, tb);
265 if (err < 0)
266 return err;
267
268 priv->dreg = ntohl(nla_get_be32(tb[NFTA_CT_DREG]));
269 err = nft_validate_output_register(priv->dreg);
270 if (err < 0)
271 return err;
272
273 err = nft_validate_data_load(ctx, priv->dreg, NULL,
274 NFT_DATA_VALUE);
275 if (err < 0)
276 return err;
277 } else {
278 err = nft_ct_init_validate_set(priv->key);
279 if (err < 0)
280 return err;
281
282 priv->sreg = ntohl(nla_get_be32(tb[NFTA_CT_SREG]));
283 err = nft_validate_input_register(priv->sreg);
284 if (err < 0)
285 return err;
286 }
287
215 err = nft_ct_l3proto_try_module_get(ctx->afi->family); 288 err = nft_ct_l3proto_try_module_get(ctx->afi->family);
216 if (err < 0) 289 if (err < 0)
217 return err; 290 return err;
218 priv->family = ctx->afi->family;
219 291
220 priv->dreg = ntohl(nla_get_be32(tb[NFTA_CT_DREG])); 292 priv->family = ctx->afi->family;
221 err = nft_validate_output_register(priv->dreg);
222 if (err < 0)
223 goto err1;
224 293
225 err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
226 if (err < 0)
227 goto err1;
228 return 0; 294 return 0;
229
230err1:
231 nft_ct_l3proto_module_put(ctx->afi->family);
232 return err;
233} 295}
234 296
235static void nft_ct_destroy(const struct nft_expr *expr) 297static void nft_ct_destroy(const struct nft_expr *expr)
@@ -239,7 +301,7 @@ static void nft_ct_destroy(const struct nft_expr *expr)
239 nft_ct_l3proto_module_put(priv->family); 301 nft_ct_l3proto_module_put(priv->family);
240} 302}
241 303
242static int nft_ct_dump(struct sk_buff *skb, const struct nft_expr *expr) 304static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
243{ 305{
244 const struct nft_ct *priv = nft_expr_priv(expr); 306 const struct nft_ct *priv = nft_expr_priv(expr);
245 307
@@ -255,19 +317,61 @@ nla_put_failure:
255 return -1; 317 return -1;
256} 318}
257 319
320static int nft_ct_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
321{
322 const struct nft_ct *priv = nft_expr_priv(expr);
323
324 if (nla_put_be32(skb, NFTA_CT_SREG, htonl(priv->sreg)))
325 goto nla_put_failure;
326 if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
327 goto nla_put_failure;
328 return 0;
329
330nla_put_failure:
331 return -1;
332}
333
258static struct nft_expr_type nft_ct_type; 334static struct nft_expr_type nft_ct_type;
259static const struct nft_expr_ops nft_ct_ops = { 335static const struct nft_expr_ops nft_ct_get_ops = {
260 .type = &nft_ct_type, 336 .type = &nft_ct_type,
261 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)), 337 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
262 .eval = nft_ct_eval, 338 .eval = nft_ct_get_eval,
263 .init = nft_ct_init, 339 .init = nft_ct_init,
264 .destroy = nft_ct_destroy, 340 .destroy = nft_ct_destroy,
265 .dump = nft_ct_dump, 341 .dump = nft_ct_get_dump,
266}; 342};
267 343
344static const struct nft_expr_ops nft_ct_set_ops = {
345 .type = &nft_ct_type,
346 .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
347 .eval = nft_ct_set_eval,
348 .init = nft_ct_init,
349 .destroy = nft_ct_destroy,
350 .dump = nft_ct_set_dump,
351};
352
353static const struct nft_expr_ops *
354nft_ct_select_ops(const struct nft_ctx *ctx,
355 const struct nlattr * const tb[])
356{
357 if (tb[NFTA_CT_KEY] == NULL)
358 return ERR_PTR(-EINVAL);
359
360 if (tb[NFTA_CT_DREG] && tb[NFTA_CT_SREG])
361 return ERR_PTR(-EINVAL);
362
363 if (tb[NFTA_CT_DREG])
364 return &nft_ct_get_ops;
365
366 if (tb[NFTA_CT_SREG])
367 return &nft_ct_set_ops;
368
369 return ERR_PTR(-EINVAL);
370}
371
268static struct nft_expr_type nft_ct_type __read_mostly = { 372static struct nft_expr_type nft_ct_type __read_mostly = {
269 .name = "ct", 373 .name = "ct",
270 .ops = &nft_ct_ops, 374 .select_ops = &nft_ct_select_ops,
271 .policy = nft_ct_policy, 375 .policy = nft_ct_policy,
272 .maxattr = NFTA_CT_MAX, 376 .maxattr = NFTA_CT_MAX,
273 .owner = THIS_MODULE, 377 .owner = THIS_MODULE,