diff options
Diffstat (limited to 'src/meta.c')
-rw-r--r-- | src/meta.c | 70 |
1 files changed, 70 insertions, 0 deletions
@@ -301,6 +301,10 @@ static const struct meta_template meta_templates[] = { 4 * 8, BYTEORDER_HOST_ENDIAN), [NFT_META_PROTOCOL] = META_TEMPLATE("protocol", ðertype_type, 2 * 8, BYTEORDER_BIG_ENDIAN), + [NFT_META_NFPROTO] = META_TEMPLATE("nfproto", &nfproto_type, + 1 * 8, BYTEORDER_HOST_ENDIAN), + [NFT_META_L4PROTO] = META_TEMPLATE("l4proto", &inet_protocol_type, + 1 * 8, BYTEORDER_HOST_ENDIAN), [NFT_META_PRIORITY] = META_TEMPLATE("priority", &tchandle_type, 4 * 8, BYTEORDER_HOST_ENDIAN), [NFT_META_MARK] = META_TEMPLATE("mark", &mark_type, @@ -341,11 +345,60 @@ static void meta_expr_clone(struct expr *new, const struct expr *expr) new->meta.key = expr->meta.key; } +/** + * meta_expr_pctx_update - update protocol context based on meta match + * + * @ctx: protocol context + * @expr: relational meta expression + * + * 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 hook_proto_desc *h = &hook_proto_desc[ctx->family]; + const struct expr *left = expr->left, *right = expr->right; + const struct proto_desc *desc; + + assert(expr->op == OP_EQ); + + switch (left->meta.key) { + case NFT_META_IIFTYPE: + if (h->base < PROTO_BASE_NETWORK_HDR) + return; + + desc = proto_dev_desc(mpz_get_uint16(right->value)); + if (desc == NULL) + desc = &proto_unknown; + + proto_ctx_update(ctx, PROTO_BASE_LL_HDR, &expr->location, desc); + break; + case NFT_META_NFPROTO: + desc = proto_find_upper(h->desc, mpz_get_uint8(right->value)); + if (desc == NULL) + desc = &proto_unknown; + + proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, &expr->location, desc); + break; + case NFT_META_L4PROTO: + desc = proto_find_upper(&proto_inet_service, + mpz_get_uint8(right->value)); + if (desc == NULL) + desc = &proto_unknown; + + proto_ctx_update(ctx, PROTO_BASE_TRANSPORT_HDR, &expr->location, desc); + break; + default: + break; + } +} + static const struct expr_ops meta_expr_ops = { .type = EXPR_META, .name = "meta", .print = meta_expr_print, .clone = meta_expr_clone, + .pctx_update = meta_expr_pctx_update, }; struct expr *meta_expr_alloc(const struct location *loc, enum nft_meta_keys key) @@ -356,6 +409,23 @@ struct expr *meta_expr_alloc(const struct location *loc, enum nft_meta_keys key) expr = expr_alloc(loc, &meta_expr_ops, tmpl->dtype, tmpl->byteorder, tmpl->len); expr->meta.key = key; + + switch (key) { + case NFT_META_IIFTYPE: + expr->flags |= EXPR_F_PROTOCOL; + break; + case NFT_META_NFPROTO: + expr->flags |= EXPR_F_PROTOCOL; + expr->meta.base = PROTO_BASE_LL_HDR; + break; + case NFT_META_L4PROTO: + expr->flags |= EXPR_F_PROTOCOL; + expr->meta.base = PROTO_BASE_NETWORK_HDR; + break; + default: + break; + } + return expr; } |