diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ct.c | 8 | ||||
-rw-r--r-- | src/evaluate.c | 14 | ||||
-rw-r--r-- | src/expression.c | 16 | ||||
-rw-r--r-- | src/meta.c | 13 | ||||
-rw-r--r-- | src/payload.c | 7 | ||||
-rw-r--r-- | src/proto.c | 57 |
6 files changed, 98 insertions, 17 deletions
@@ -351,9 +351,11 @@ static void ct_expr_clone(struct expr *new, const struct expr *expr) new->ct = expr->ct; } -static void ct_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr) +static void ct_expr_pctx_update(struct proto_ctx *ctx, + const struct location *loc, + const struct expr *left, + const struct expr *right) { - const struct expr *left = expr->left, *right = expr->right; const struct proto_desc *base = NULL, *desc; uint32_t nhproto; @@ -366,7 +368,7 @@ static void ct_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr) if (!desc) return; - proto_ctx_update(ctx, left->ct.base + 1, &expr->location, desc); + proto_ctx_update(ctx, left->ct.base + 1, loc, desc); } #define NFTNL_UDATA_CT_KEY 0 diff --git a/src/evaluate.c b/src/evaluate.c index e3fe7062..c8045e5d 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -710,6 +710,17 @@ static int __expr_evaluate_payload(struct eval_ctx *ctx, struct expr *expr) return 0; } + if (payload->payload.base == desc->base && + proto_ctx_is_ambiguous(&ctx->pctx, base)) { + desc = proto_ctx_find_conflict(&ctx->pctx, base, payload->payload.desc); + assert(desc); + + return expr_error(ctx->msgs, payload, + "conflicting protocols specified: %s vs. %s", + desc->name, + payload->payload.desc->name); + } + /* No conflict: Same payload protocol as context, adjust offset * if needed. */ @@ -1874,8 +1885,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr) * Update protocol context for payload and meta iiftype * equality expressions. */ - if (expr_is_singleton(right)) - relational_expr_pctx_update(&ctx->pctx, rel); + relational_expr_pctx_update(&ctx->pctx, rel); /* fall through */ case OP_NEQ: diff --git a/src/expression.c b/src/expression.c index fe529f98..87bd4d01 100644 --- a/src/expression.c +++ b/src/expression.c @@ -708,16 +708,26 @@ struct expr *relational_expr_alloc(const struct location *loc, enum ops op, void relational_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr) { - const struct expr *left = expr->left; + const struct expr *left = expr->left, *right = expr->right; const struct expr_ops *ops; + const struct expr *i; assert(expr->etype == EXPR_RELATIONAL); assert(expr->op == OP_EQ || expr->op == OP_IMPLICIT); ops = expr_ops(left); if (ops->pctx_update && - (left->flags & EXPR_F_PROTOCOL)) - ops->pctx_update(ctx, expr); + (left->flags & EXPR_F_PROTOCOL)) { + if (expr_is_singleton(right)) + ops->pctx_update(ctx, &expr->location, left, right); + else if (right->etype == EXPR_SET) { + list_for_each_entry(i, &right->expressions, list) { + if (i->etype == EXPR_SET_ELEM && + i->key->etype == EXPR_VALUE) + ops->pctx_update(ctx, &expr->location, left, i->key); + } + } + } } static void range_expr_print(const struct expr *expr, struct output_ctx *octx) @@ -753,10 +753,11 @@ static void meta_expr_clone(struct expr *new, const struct expr *expr) * Update LL protocol context based on IIFTYPE meta match in non-LL hooks. */ static void meta_expr_pctx_update(struct proto_ctx *ctx, - const struct expr *expr) + const struct location *loc, + const struct expr *left, + const struct expr *right) { const struct hook_proto_desc *h = &hook_proto_desc[ctx->family]; - const struct expr *left = expr->left, *right = expr->right; const struct proto_desc *desc; uint8_t protonum; @@ -771,7 +772,7 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx, if (desc == NULL) desc = &proto_unknown; - proto_ctx_update(ctx, PROTO_BASE_LL_HDR, &expr->location, desc); + proto_ctx_update(ctx, PROTO_BASE_LL_HDR, loc, desc); break; case NFT_META_NFPROTO: protonum = mpz_get_uint8(right->value); @@ -784,7 +785,7 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx, desc = h->desc; } - proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, &expr->location, desc); + proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, loc, desc); break; case NFT_META_L4PROTO: desc = proto_find_upper(&proto_inet_service, @@ -792,7 +793,7 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx, if (desc == NULL) desc = &proto_unknown; - proto_ctx_update(ctx, PROTO_BASE_TRANSPORT_HDR, &expr->location, desc); + proto_ctx_update(ctx, PROTO_BASE_TRANSPORT_HDR, loc, desc); break; case NFT_META_PROTOCOL: if (h->base != PROTO_BASE_LL_HDR) @@ -806,7 +807,7 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx, if (desc == NULL) desc = &proto_unknown; - proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, &expr->location, desc); + proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, loc, desc); break; default: break; diff --git a/src/payload.c b/src/payload.c index 29242537..ca422d5b 100644 --- a/src/payload.c +++ b/src/payload.c @@ -80,9 +80,10 @@ static void payload_expr_clone(struct expr *new, const struct expr *expr) * Update protocol context for relational payload expressions. */ static void payload_expr_pctx_update(struct proto_ctx *ctx, - const struct expr *expr) + const struct location *loc, + const struct expr *left, + const struct expr *right) { - const struct expr *left = expr->left, *right = expr->right; const struct proto_desc *base, *desc; unsigned int proto = 0; @@ -102,7 +103,7 @@ static void payload_expr_pctx_update(struct proto_ctx *ctx, assert(base->length > 0); ctx->protocol[base->base].offset += base->length; } - proto_ctx_update(ctx, desc->base, &expr->location, desc); + proto_ctx_update(ctx, desc->base, loc, desc); } #define NFTNL_UDATA_SET_KEY_PAYLOAD_DESC 0 diff --git a/src/proto.c b/src/proto.c index 7d001501..7de2bbf9 100644 --- a/src/proto.c +++ b/src/proto.c @@ -193,12 +193,69 @@ void proto_ctx_update(struct proto_ctx *ctx, enum proto_bases base, const struct location *loc, const struct proto_desc *desc) { + bool found = false; + unsigned int i; + + switch (base) { + case PROTO_BASE_LL_HDR: + case PROTO_BASE_NETWORK_HDR: + break; + case PROTO_BASE_TRANSPORT_HDR: + if (ctx->protocol[base].num_protos >= PROTO_CTX_NUM_PROTOS) + break; + + for (i = 0; i < ctx->protocol[base].num_protos; i++) { + if (ctx->protocol[base].protos[i].desc == desc) { + found = true; + break; + } + } + if (!found) { + i = ctx->protocol[base].num_protos++; + ctx->protocol[base].protos[i].desc = desc; + ctx->protocol[base].protos[i].location = *loc; + } + break; + default: + BUG("unknown protocol base %d", base); + } + ctx->protocol[base].location = *loc; ctx->protocol[base].desc = desc; proto_ctx_debug(ctx, base, ctx->debug_mask); } +bool proto_ctx_is_ambiguous(struct proto_ctx *ctx, enum proto_bases base) +{ + return ctx->protocol[base].num_protos > 1; +} + +const struct proto_desc *proto_ctx_find_conflict(struct proto_ctx *ctx, + enum proto_bases base, + const struct proto_desc *desc) +{ + unsigned int i; + + switch (base) { + case PROTO_BASE_LL_HDR: + case PROTO_BASE_NETWORK_HDR: + if (desc != ctx->protocol[base].desc) + return ctx->protocol[base].desc; + break; + case PROTO_BASE_TRANSPORT_HDR: + for (i = 0; i < ctx->protocol[base].num_protos; i++) { + if (desc != ctx->protocol[base].protos[i].desc) + return ctx->protocol[base].protos[i].desc; + } + break; + default: + BUG("unknown protocol base %d", base); + } + + return NULL; +} + #define HDR_TEMPLATE(__name, __dtype, __type, __member) \ PROTO_HDR_TEMPLATE(__name, __dtype, \ BYTEORDER_BIG_ENDIAN, \ |