From 2b29ea5f3c3ed693fc0579016569a36cb3796703 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 29 Sep 2017 13:54:21 +0200 Subject: src: ct: add eval part to inject dependencies for ct saddr/daddr nft has enough context to determine if a dependeny is needed. add rule ip filter ct original ip6 saddr allows nft to generate an error due to conflicting bases (ip vs ip6). add rule inet filter ct original ip6 saddr allows nft to inject an ipv6 dependency expression. add rule inet filter ct original saddr will print an error and will suggest to add ip/ip6 keyword. Delinerize and print support will be added in followup patches. Signed-off-by: Florian Westphal --- src/evaluate.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 6 deletions(-) (limited to 'src/evaluate.c') diff --git a/src/evaluate.c b/src/evaluate.c index c796c3c3..8735bb76 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -696,27 +696,85 @@ static int expr_evaluate_rt(struct eval_ctx *ctx, struct expr **expr) return expr_evaluate_primary(ctx, expr); } +static int ct_gen_nh_dependency(struct eval_ctx *ctx, struct expr *ct) +{ + const struct proto_desc *base, *base_now; + struct expr *left, *right, *dep; + struct stmt *nstmt = NULL; + + base_now = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; + + switch (ct->ct.nfproto) { + case NFPROTO_IPV4: + base = &proto_ip; + break; + case NFPROTO_IPV6: + base = &proto_ip6; + break; + default: + base = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; + if (base == &proto_ip) + ct->ct.nfproto = NFPROTO_IPV4; + else if (base == &proto_ip) + ct->ct.nfproto = NFPROTO_IPV6; + + if (base) + break; + + return expr_error(ctx->msgs, ct, + "cannot determine ip protocol version, use \"ip %1$caddr\" or \"ip6 %1$caddr\" instead", + ct->ct.key == NFT_CT_SRC ? 's' : 'd'); + } + + /* no additional dependency needed? */ + if (base == base_now) + return 0; + + if (base_now && base_now != base) + return expr_error(ctx->msgs, ct, + "conflicting dependencies: %s vs. %s\n", + base->name, + ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc->name); + switch (ctx->pctx.family) { + case NFPROTO_IPV4: + case NFPROTO_IPV6: + return 0; + } + + left = ct_expr_alloc(&ct->location, NFT_CT_L3PROTOCOL, ct->ct.direction, ct->ct.nfproto); + + right = constant_expr_alloc(&ct->location, left->dtype, + left->dtype->byteorder, left->len, + constant_data_ptr(ct->ct.nfproto, left->len)); + dep = relational_expr_alloc(&ct->location, OP_EQ, left, right); + + left->ops->pctx_update(&ctx->pctx, dep); + + nstmt = expr_stmt_alloc(&dep->location, dep); + + list_add_tail(&nstmt->list, &ctx->stmt->list); + return 0; +} + /* * CT expression: update the protocol dependant types bases on the protocol * context. */ static int expr_evaluate_ct(struct eval_ctx *ctx, struct expr **expr) { - const struct proto_desc *base; struct expr *ct = *expr; - ct_expr_update_type(&ctx->pctx, ct); - - base = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; switch (ct->ct.key) { case NFT_CT_SRC: case NFT_CT_DST: - if (base != &proto_ip && base != &proto_ip6) - return expr_error_base(ctx->msgs, ct); + ct_gen_nh_dependency(ctx, ct); + break; default: break; } + ct_expr_update_type(&ctx->pctx, ct); + return expr_evaluate_primary(ctx, expr); } -- cgit v1.2.3 From d53f6caace0759c0e79fe6e7b647bd6f20201e28 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 29 Sep 2017 13:54:21 +0200 Subject: src: rt: add keyword distinction for nexthop vs nexthop6 the rt expression currently always sets NFT_RT_NEXTHOP4 and then uses the network base to determine if its really supposed to be NEXTHOP6. For inet, this will fail because the network base is not known, so this currently enforces need for "meta nfproto" to dermine the type. Allow following syntax instead: rt ip nexthop rt ip6 nexthop There is no need for a dependency anymore, as rt expression checks the hook protocol, ie. NEXTHOP4 will break if the hook pf is not NFPROTO_IPV4. Cc: Anders K. Pedersen Signed-off-by: Florian Westphal --- src/evaluate.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'src/evaluate.c') diff --git a/src/evaluate.c b/src/evaluate.c index 8735bb76..ca9180b7 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -662,32 +662,28 @@ static int expr_evaluate_payload(struct eval_ctx *ctx, struct expr **exprp) return 0; } -static int expr_error_base(struct list_head *msgs, const struct expr *e) -{ - return expr_error(msgs, e, - "meta nfproto ipv4 or ipv6 must be specified " - "before %s expression", e->ops->name); -} - /* * RT expression: validate protocol dependencies. */ static int expr_evaluate_rt(struct eval_ctx *ctx, struct expr **expr) { - const struct proto_desc *base; + static const char emsg[] = "cannot determine ip protocol version, use \"ip nexthop\" or \"ip6 nexthop\" instead"; struct expr *rt = *expr; rt_expr_update_type(&ctx->pctx, rt); - base = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; switch (rt->rt.key) { case NFT_RT_NEXTHOP4: - if (base != &proto_ip) - return expr_error_base(ctx->msgs, rt); + if (rt->dtype != &ipaddr_type) + return expr_error(ctx->msgs, rt, "%s", emsg); + if (ctx->pctx.family == NFPROTO_IPV6) + return expr_error(ctx->msgs, rt, "%s nexthop will not match", "ip"); break; case NFT_RT_NEXTHOP6: - if (base != &proto_ip6) - return expr_error_base(ctx->msgs, rt); + if (rt->dtype != &ip6addr_type) + return expr_error(ctx->msgs, rt, "%s", emsg); + if (ctx->pctx.family == NFPROTO_IPV4) + return expr_error(ctx->msgs, rt, "%s nexthop will not match", "ip6"); break; default: break; -- cgit v1.2.3