From 39f15c243912a20f3014c0efba6b8dbc80caf0e9 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 7 Aug 2015 12:09:08 +0200 Subject: nft: support listing expressions that use non-byte header fields This allows to list rules that check fields that are not aligned on byte boundary. Signed-off-by: Florian Westphal --- src/payload.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 3 deletions(-) (limited to 'src/payload.c') diff --git a/src/payload.c b/src/payload.c index 880b5d0d..23afa2f2 100644 --- a/src/payload.c +++ b/src/payload.c @@ -297,12 +297,87 @@ void payload_expr_complete(struct expr *expr, const struct proto_ctx *ctx) } } +static unsigned int mask_to_offset(const struct expr *mask) +{ + return mask ? mpz_scan1(mask->value, 0) : 0; +} + +static unsigned int mask_length(const struct expr *mask) +{ + unsigned long off; + + off = mask_to_offset(mask); + + return mpz_scan0(mask->value, off + 1); +} + +/** + * payload_expr_trim - trim payload expression according to mask + * + * @expr: the payload expression + * @mask: mask to use when searching templates + * @ctx: protocol context + * + * Walk the template list and determine if a match can be found without + * using the provided mask. + * + * If the mask has to be used, trim the mask length accordingly + * and return true to let the caller know that the mask is a dependency. + */ +bool payload_expr_trim(struct expr *expr, struct expr *mask, + const struct proto_ctx *ctx) +{ + unsigned int payload_offset = expr->payload.offset + mask_to_offset(mask); + unsigned int mask_len = mask_length(mask); + const struct proto_hdr_template *tmpl; + unsigned int payload_len = expr->len; + const struct proto_desc *desc; + unsigned int i, matched_len = mask_to_offset(mask); + + assert(expr->ops->type == EXPR_PAYLOAD); + + desc = ctx->protocol[expr->payload.base].desc; + if (desc == NULL) + return false; + + assert(desc->base == expr->payload.base); + + if (ctx->protocol[expr->payload.base].offset) { + assert(payload_offset >= ctx->protocol[expr->payload.base].offset); + payload_offset -= ctx->protocol[expr->payload.base].offset; + } + + for (i = 1; i < array_size(desc->templates); i++) { + tmpl = &desc->templates[i]; + if (tmpl->offset != payload_offset) + continue; + + if (tmpl->len > payload_len) + return false; + + payload_len -= tmpl->len; + matched_len += tmpl->len; + payload_offset += tmpl->len; + if (payload_len == 0) + return false; + + if (matched_len == mask_len) { + assert(mask->len >= mask_len); + mask->len = mask_len; + return true; + } + } + + return false; +} + /** * payload_expr_expand - expand raw merged adjacent payload expressions into its * original components * * @list: list to append expanded payload expressions to * @expr: the payload expression to expand + * @mask: optional/implicit mask to use when searching templates * @ctx: protocol context * * Expand a merged adjacent payload expression into its original components @@ -312,14 +387,16 @@ void payload_expr_complete(struct expr *expr, const struct proto_ctx *ctx) * offset order. */ void payload_expr_expand(struct list_head *list, struct expr *expr, - const struct proto_ctx *ctx) + struct expr *mask, const struct proto_ctx *ctx) { - const struct proto_desc *desc; + unsigned int off = mask_to_offset(mask); const struct proto_hdr_template *tmpl; + const struct proto_desc *desc; struct expr *new; unsigned int i; assert(expr->ops->type == EXPR_PAYLOAD); + assert(!mask || mask->len != 0); desc = ctx->protocol[expr->payload.base].desc; if (desc == NULL) @@ -336,7 +413,7 @@ void payload_expr_expand(struct list_head *list, struct expr *expr, list_add_tail(&new->list, list); expr->len -= tmpl->len; expr->payload.offset += tmpl->len; - if (expr->len == 0) + if (expr->len == off) return; } else break; -- cgit v1.2.3