From 7ad9e1f8ad4ba637be841d0573bdfdcf397f0815 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 4 Jan 2016 20:53:43 +0100 Subject: ct: add support for directional keys 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 --- include/ct.h | 4 +++- include/expression.h | 1 + src/ct.c | 40 +++++++++++++++++++++++++++++++++++++--- src/netlink_delinearize.c | 21 ++++++++++++++++++--- src/netlink_linearize.c | 4 ++++ src/parser_bison.y | 26 ++++++++++++++++++++------ 6 files changed, 83 insertions(+), 13 deletions(-) diff --git a/include/ct.h b/include/ct.h index 64366ab7..945fcc4d 100644 --- a/include/ct.h +++ b/include/ct.h @@ -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 */ diff --git a/include/expression.h b/include/expression.h index 010cb954..eacbb2d5 100644 --- a/include/expression.h +++ b/include/expression.h @@ -273,6 +273,7 @@ struct expr { struct { /* EXPR_CT */ enum nft_ct_keys key; + int8_t direction; } ct; }; }; diff --git a/src/ct.c b/src/ct.c index aa801388..07e7077b 100644 --- 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: diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index f68fca09..769321aa 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -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); } diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index 131c3f95..48f5f027 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -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); } diff --git a/src/parser_bison.y b/src/parser_bison.y index af51e4dd..fcd4813e 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -567,7 +567,7 @@ static void location_update(struct location *loc, struct location *rhs, int n) %type ct_expr %destructor { expr_free($$); } ct_expr -%type ct_key +%type ct_key ct_key_dir %type export_format %type 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 -- cgit v1.2.3