]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
ct expr: protocol context updates and dynamic typing
authorPatrick McHardy <kaber@trash.net>
Wed, 8 Jan 2014 13:02:16 +0000 (13:02 +0000)
committerPatrick McHardy <kaber@trash.net>
Wed, 8 Jan 2014 13:02:16 +0000 (13:02 +0000)
Include the protocols defined through relational ct expressions in the
protocol context and use the protocol context to dynamically determine
the types of network and transport layer ct expression types.

Before:

$ nft filter output ct proto-dst ssh
<cmdline>:1:28-30: Error: Can't parse symbolic invalid expressions
filter output ct proto-dst ssh
                           ^^^
$ nft filter output ip protocol tcp ct proto-dst ssh
<cmdline>:1:44-46: Error: Can't parse symbolic invalid expressions
filter output ip protocol tcp ct proto-dst ssh
                                           ^^^
$ nft filter output ct protocol tcp ct proto-dst ssh
<cmdline>:1:44-46: Error: Can't parse symbolic invalid expressions
filter output ct protocol tcp ct proto-dst ssh
                                           ^^^
After:

$ nft filter output ct proto-dst ssh
<cmdline>:1:28-30: Error: Can't parse symbolic invalid expressions
filter output ct proto-dst ssh
                           ^^^
$ nft filter output ip protocol tcp ct proto-dst ssh
$ nft filter output ct protocol tcp ct proto-dst ssh

Signed-off-by: Patrick McHardy <kaber@trash.net>
include/ct.h
src/ct.c
src/evaluate.c

index 67718c849d93f942493271481dbad8c5b9650957..64366ab7c06f02223dcd4ab202f2e8ce99649266 100644 (file)
@@ -25,5 +25,6 @@ struct ct_template {
 
 extern struct expr *ct_expr_alloc(const struct location *loc,
                                  enum nft_ct_keys key);
+extern void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr);
 
 #endif /* NFTABLES_CT_H */
index e5ca593ccfc72dbce9ed3d35ec8538220d175f1d..b8f76325a3dc8f3250cf8652f1c8097717c1b2ef 100644 (file)
--- a/src/ct.c
+++ b/src/ct.c
@@ -23,6 +23,7 @@
 #include <expression.h>
 #include <datatype.h>
 #include <ct.h>
+#include <gmputil.h>
 #include <utils.h>
 
 static const struct symbol_table ct_state_tbl = {
@@ -139,11 +140,32 @@ static void ct_expr_clone(struct expr *new, const struct expr *expr)
        new->ct.key = expr->ct.key;
 }
 
+static void ct_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr)
+{
+       const struct expr *left = expr->left, *right = expr->right;
+       const struct proto_desc *base, *desc;
+
+       assert(expr->op == OP_EQ);
+
+       switch (left->ct.key) {
+       case NFT_CT_PROTOCOL:
+               base = ctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+               desc = proto_find_upper(base, mpz_get_uint32(right->value));
+
+               proto_ctx_update(ctx, PROTO_BASE_TRANSPORT_HDR,
+                                &expr->location, desc);
+               break;
+       default:
+               break;
+       }
+}
+
 static const struct expr_ops ct_expr_ops = {
        .type           = EXPR_CT,
        .name           = "ct",
        .print          = ct_expr_print,
        .clone          = ct_expr_clone,
+       .pctx_update    = ct_expr_pctx_update,
 };
 
 struct expr *ct_expr_alloc(const struct location *loc, enum nft_ct_keys key)
@@ -154,9 +176,45 @@ struct expr *ct_expr_alloc(const struct location *loc, enum nft_ct_keys key)
        expr = expr_alloc(loc, &ct_expr_ops, tmpl->dtype,
                          tmpl->byteorder, tmpl->len);
        expr->ct.key = key;
+
+       switch (key) {
+       case NFT_CT_PROTOCOL:
+               expr->flags = EXPR_F_PROTOCOL;
+               break;
+       default:
+               break;
+       }
+
        return expr;
 }
 
+void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr)
+{
+       const struct proto_desc *desc;
+
+       switch (expr->ct.key) {
+       case NFT_CT_SRC:
+       case NFT_CT_DST:
+               desc = ctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+               if (desc == &proto_ip)
+                       expr->dtype = &ipaddr_type;
+               else if (desc == &proto_ip6)
+                       expr->dtype = &ip6addr_type;
+
+               expr->len = expr->dtype->size;
+               break;
+       case NFT_CT_PROTO_SRC:
+       case NFT_CT_PROTO_DST:
+               desc = ctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc;
+               if (desc == NULL)
+                       break;
+               expr->dtype = &inet_service_type;
+               break;
+       default:
+               break;
+       }
+}
+
 static void __init ct_init(void)
 {
        datatype_register(&ct_state_type);
index 3fe9da4f8ca29e35cb66611b9414b3a47b551797..257c67edf6fddc97ad9380329bbf2bdebd10136c 100644 (file)
@@ -289,6 +289,19 @@ static int expr_evaluate_payload(struct eval_ctx *ctx, struct expr **expr)
        return expr_evaluate_primary(ctx, expr);
 }
 
+/*
+ * CT expression: update the protocol dependant types bases on the protocol
+ * context.
+ */
+static int expr_evaluate_ct(struct eval_ctx *ctx, struct expr **expr)
+{
+       struct expr *ct = *expr;
+
+       ct_expr_update_type(&ctx->pctx, ct);
+
+       return expr_evaluate_primary(ctx, expr);
+}
+
 /*
  * Prefix expression: the argument must be a constant value of integer base
  * type; the prefix length must be less than or equal to the type width.
@@ -1042,10 +1055,11 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
        case EXPR_VERDICT:
        case EXPR_EXTHDR:
        case EXPR_META:
-       case EXPR_CT:
                return expr_evaluate_primary(ctx, expr);
        case EXPR_PAYLOAD:
                return expr_evaluate_payload(ctx, expr);
+       case EXPR_CT:
+               return expr_evaluate_ct(ctx, expr);
        case EXPR_PREFIX:
                return expr_evaluate_prefix(ctx, expr);
        case EXPR_RANGE: