]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
ct: add support for directional keys
authorFlorian Westphal <fw@strlen.de>
Mon, 4 Jan 2016 19:53:43 +0000 (20:53 +0100)
committerFlorian Westphal <fw@strlen.de>
Mon, 4 Jan 2016 19:53:43 +0000 (20:53 +0100)
A few keys in the ct expression are directional, i.e.
we need to tell kernel if it should fetch REPLY or ORIGINAL direction.

Split ct_keys into ct_keys & ct_keys_dir, the latter are those keys
that the kernel rejects unless also given a direction.

During postprocessing we also need to invoke ct_expr_update_type,
problem is that e.g. ct saddr can be any family (ip, ipv6) so we need
to update the expected data type based on the network base.

Signed-off-by: Florian Westphal <fw@strlen.de>
include/ct.h
include/expression.h
src/ct.c
src/netlink_delinearize.c
src/netlink_linearize.c
src/parser_bison.y

index 64366ab7c06f02223dcd4ab202f2e8ce99649266..945fcc4d829d79b8a6205f5da95d4b55becb5c97 100644 (file)
@@ -24,7 +24,9 @@ struct ct_template {
 }
 
 extern struct expr *ct_expr_alloc(const struct location *loc,
-                                 enum nft_ct_keys key);
+                                 enum nft_ct_keys key, int8_t direction);
 extern void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr);
 
+extern struct error_record *ct_dir_parse(const struct location *loc,
+                                        const char *str, int8_t *dir);
 #endif /* NFTABLES_CT_H */
index 010cb954468ed61f257c1edb82f4f6ee18b6732b..eacbb2d5cd1be305a79e220847a7986f39e1b5c6 100644 (file)
@@ -273,6 +273,7 @@ struct expr {
                struct {
                        /* EXPR_CT */
                        enum nft_ct_keys        key;
+                       int8_t                  direction;
                } ct;
        };
 };
index aa801388b615e242ff8eb4c08cd2e8ab9e3f4bd3..07e7077b047c21e9b37b99d4f1b118ec9800e33c 100644 (file)
--- a/src/ct.c
+++ b/src/ct.c
@@ -207,17 +207,34 @@ static const struct ct_template ct_templates[] = {
 
 static void ct_expr_print(const struct expr *expr)
 {
+       const struct symbolic_constant *s;
+
        printf("ct %s", ct_templates[expr->ct.key].token);
+
+       if (expr->ct.direction < 0)
+               return;
+
+       for (s = ct_dir_tbl.symbols; s->identifier != NULL; s++) {
+               if (expr->ct.direction == (int) s->value) {
+                       printf(" %s", s->identifier);
+                       return;
+               }
+       }
+
+       printf(" %d", expr->ct.direction);
 }
 
 static bool ct_expr_cmp(const struct expr *e1, const struct expr *e2)
 {
-       return e1->ct.key == e2->ct.key;
+       if (e1->ct.key != e2->ct.key)
+               return false;
+
+       return e1->ct.direction == e2->ct.direction;
 }
 
 static void ct_expr_clone(struct expr *new, const struct expr *expr)
 {
-       new->ct.key = expr->ct.key;
+       new->ct = expr->ct;
 }
 
 static void ct_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr)
@@ -249,7 +266,23 @@ static const struct expr_ops ct_expr_ops = {
        .pctx_update    = ct_expr_pctx_update,
 };
 
-struct expr *ct_expr_alloc(const struct location *loc, enum nft_ct_keys key)
+struct error_record *ct_dir_parse(const struct location *loc, const char *str,
+                                 int8_t *direction)
+{
+       const struct symbolic_constant *s;
+
+       for (s = ct_dir_tbl.symbols; s->identifier != NULL; s++) {
+               if (!strcmp(str, s->identifier)) {
+                       *direction = s->value;
+                       return NULL;
+               }
+       }
+
+       return error(loc, "Could not parse direction %s", str);
+}
+
+struct expr *ct_expr_alloc(const struct location *loc, enum nft_ct_keys key,
+                          int8_t direction)
 {
        const struct ct_template *tmpl = &ct_templates[key];
        struct expr *expr;
@@ -257,6 +290,7 @@ 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;
+       expr->ct.direction = direction;
 
        switch (key) {
        case NFT_CT_PROTOCOL:
index f68fca09484cef86609228915576df29cd4943e9..769321aa12381d93df3394b9e1db5908ec6905bd 100644 (file)
@@ -536,12 +536,16 @@ static void netlink_parse_ct_expr(struct netlink_parse_ctx *ctx,
                                  const struct location *loc,
                                  const struct nftnl_expr *nle)
 {
+       struct expr *expr = NULL;
        enum nft_registers dreg;
+       int8_t dir = -1;
        uint32_t key;
-       struct expr *expr;
+
+       if (nftnl_expr_is_set(nle, NFTNL_EXPR_CT_DIR))
+               dir = nftnl_expr_get_u8(nle, NFTNL_EXPR_CT_DIR);
 
        key  = nftnl_expr_get_u32(nle, NFTNL_EXPR_CT_KEY);
-       expr = ct_expr_alloc(loc, key);
+       expr = ct_expr_alloc(loc, key, dir);
 
        dreg = netlink_parse_register(nle, NFTNL_EXPR_CT_DREG);
        netlink_set_register(ctx, dreg, expr);
@@ -1117,6 +1121,12 @@ static void meta_match_postprocess(struct rule_pp_ctx *ctx,
        }
 }
 
+static void ct_match_postprocess(struct rule_pp_ctx *ctx,
+                                const struct expr *expr)
+{
+       return meta_match_postprocess(ctx, expr);
+}
+
 /* Convert a bitmask to a prefix length */
 static unsigned int expr_mask_to_prefix(const struct expr *expr)
 {
@@ -1394,6 +1404,9 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
                expr_postprocess(ctx, &expr->right);
 
                switch (expr->left->ops->type) {
+               case EXPR_CT:
+                       ct_match_postprocess(ctx, expr);
+                       break;
                case EXPR_META:
                        meta_match_postprocess(ctx, expr);
                        break;
@@ -1431,9 +1444,11 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
        case EXPR_SET_REF:
        case EXPR_EXTHDR:
        case EXPR_META:
-       case EXPR_CT:
        case EXPR_VERDICT:
                break;
+       case EXPR_CT:
+               ct_expr_update_type(&ctx->pctx, expr);
+               break;
        default:
                BUG("unknown expression type %s\n", expr->ops->name);
        }
index 131c3f951b6ee7b0385faca9d96ed6c71071dea9..48f5f0273cc2a0cdda002bde7e9020deb5aec85e 100644 (file)
@@ -209,6 +209,10 @@ static void netlink_gen_ct(struct netlink_linearize_ctx *ctx,
        nle = alloc_nft_expr("ct");
        netlink_put_register(nle, NFTNL_EXPR_CT_DREG, dreg);
        nftnl_expr_set_u32(nle, NFTNL_EXPR_CT_KEY, expr->ct.key);
+       if (expr->ct.direction >= 0)
+               nftnl_expr_set_u8(nle, NFTNL_EXPR_CT_DIR,
+                                 expr->ct.direction);
+
        nftnl_rule_add_expr(ctx->nlr, nle);
 }
 
index af51e4dd840f6ee66b98a0df4ad053d51c76f963..fcd4813e1dcf18ff199abe7c7f44bea0b74e4e78 100644 (file)
@@ -567,7 +567,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 
 %type <expr>                   ct_expr
 %destructor { expr_free($$); } ct_expr
-%type <val>                    ct_key
+%type <val>                    ct_key          ct_key_dir
 
 %type <val>                    export_format
 %type <string>                 monitor_event
@@ -2264,9 +2264,22 @@ meta_stmt                :       META    meta_key        SET     expr
                        }
                        ;
 
-ct_expr                        :       CT      ct_key
+ct_expr                        :       CT      ct_key
                        {
-                               $$ = ct_expr_alloc(&@$, $2);
+                               $$ = ct_expr_alloc(&@$, $2, -1);
+                       }
+                       |       CT      ct_key_dir      STRING
+                       {
+                               struct error_record *erec;
+                               int8_t direction;
+
+                               erec = ct_dir_parse(&@$, $3, &direction);
+                               if (erec != NULL) {
+                                       erec_queue(erec, state->msgs);
+                                       YYERROR;
+                               }
+
+                               $$ = ct_expr_alloc(&@$, $2, direction);
                        }
                        ;
 
@@ -2276,13 +2289,14 @@ ct_key                  :       STATE           { $$ = NFT_CT_STATE; }
                        |       MARK            { $$ = NFT_CT_MARK; }
                        |       EXPIRATION      { $$ = NFT_CT_EXPIRATION; }
                        |       HELPER          { $$ = NFT_CT_HELPER; }
-                       |       L3PROTOCOL      { $$ = NFT_CT_L3PROTOCOL; }
-                       |       SADDR           { $$ = NFT_CT_SRC; }
+                       |       LABEL           { $$ = NFT_CT_LABELS; }
+                       ;
+ct_key_dir             :       SADDR           { $$ = NFT_CT_SRC; }
                        |       DADDR           { $$ = NFT_CT_DST; }
+                       |       L3PROTOCOL      { $$ = NFT_CT_L3PROTOCOL; }
                        |       PROTOCOL        { $$ = NFT_CT_PROTOCOL; }
                        |       PROTO_SRC       { $$ = NFT_CT_PROTO_SRC; }
                        |       PROTO_DST       { $$ = NFT_CT_PROTO_DST; }
-                       |       LABEL           { $$ = NFT_CT_LABELS; }
                        ;
 
 ct_stmt                        :       CT      ct_key          SET     expr