diff options
Diffstat (limited to 'src/netlink_delinearize.c')
-rw-r--r-- | src/netlink_delinearize.c | 115 |
1 files changed, 93 insertions, 22 deletions
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 09f5932a..3584de78 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -232,11 +232,11 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx, nld.value = nftnl_expr_get(nle, NFTNL_EXPR_CMP_DATA, &nld.len); right = netlink_alloc_value(loc, &nld); - if (left->len != right->len) { - if (left->len > right->len) - return netlink_error(ctx, loc, - "Relational expression size " - "mismatch"); + if (left->len > right->len && + left->dtype != &string_type) { + return netlink_error(ctx, loc, + "Relational expression size mismatch"); + } else if (left->len < right->len) { left = netlink_parse_concat_expr(ctx, loc, sreg, right->len); if (left == NULL) return; @@ -1088,7 +1088,7 @@ static void meta_match_postprocess(struct rule_pp_ctx *ctx, } /* Convert a bitmask to a prefix length */ -static unsigned int expr_mask_to_prefix(struct expr *expr) +static unsigned int expr_mask_to_prefix(const struct expr *expr) { unsigned long n; @@ -1214,6 +1214,91 @@ static void relational_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *e } } +static struct expr *string_wildcard_expr_alloc(struct location *loc, + const struct expr *mask, + const struct expr *expr) +{ + unsigned int len = div_round_up(expr->len, BITS_PER_BYTE); + char data[len + 2]; + int pos; + + mpz_export_data(data, expr->value, BYTEORDER_HOST_ENDIAN, len); + pos = div_round_up(expr_mask_to_prefix(mask), BITS_PER_BYTE); + data[pos] = '*'; + data[pos + 1] = '\0'; + + return constant_expr_alloc(loc, &string_type, BYTEORDER_HOST_ENDIAN, + expr->len + BITS_PER_BYTE, data); +} + +static void escaped_string_wildcard_expr_alloc(struct expr **exprp, + unsigned int len) +{ + struct expr *expr = *exprp, *tmp; + char data[len + 3]; + int pos; + + mpz_export_data(data, expr->value, BYTEORDER_HOST_ENDIAN, len); + pos = div_round_up(len, BITS_PER_BYTE); + data[pos - 1] = '\\'; + data[pos] = '*'; + + tmp = constant_expr_alloc(&expr->location, &string_type, + BYTEORDER_HOST_ENDIAN, + expr->len + BITS_PER_BYTE, data); + expr_free(expr); + *exprp = tmp; +} + +/* This calculates the string length and checks if it is nul-terminated, this + * function is quite a hack :) + */ +static bool __expr_postprocess_string(struct expr **exprp) +{ + struct expr *expr = *exprp; + unsigned int len = expr->len; + bool nulterminated = false; + mpz_t tmp; + + mpz_init(tmp); + while (len >= BITS_PER_BYTE) { + mpz_bitmask(tmp, BITS_PER_BYTE); + mpz_lshift_ui(tmp, len - BITS_PER_BYTE); + mpz_and(tmp, tmp, expr->value); + if (mpz_cmp_ui(tmp, 0)) + break; + else + nulterminated = true; + len -= BITS_PER_BYTE; + } + + mpz_rshift_ui(tmp, len - BITS_PER_BYTE); + + if (nulterminated && + mpz_cmp_ui(tmp, '*') == 0) + escaped_string_wildcard_expr_alloc(exprp, len); + + mpz_clear(tmp); + expr->len = len; + + return nulterminated; +} + +static struct expr *expr_postprocess_string(struct expr *expr) +{ + struct expr *mask; + + assert(expr->dtype->type == TYPE_STRING); + if (__expr_postprocess_string(&expr)) + return expr; + + mask = constant_expr_alloc(&expr->location, &integer_type, + BYTEORDER_HOST_ENDIAN, + expr->len + BITS_PER_BYTE, NULL); + mpz_init_bitmask(mask->value, expr->len); + return string_wildcard_expr_alloc(&expr->location, mask, expr); +} + static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) { struct expr *expr = *exprp, *i; @@ -1299,22 +1384,8 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) if (expr->byteorder == BYTEORDER_HOST_ENDIAN) mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE); - // Quite a hack :) - if (expr->dtype->type == TYPE_STRING) { - unsigned int len = expr->len; - mpz_t tmp; - mpz_init(tmp); - while (len >= BITS_PER_BYTE) { - mpz_bitmask(tmp, BITS_PER_BYTE); - mpz_lshift_ui(tmp, len - BITS_PER_BYTE); - mpz_and(tmp, tmp, expr->value); - if (mpz_cmp_ui(tmp, 0)) - break; - len -= BITS_PER_BYTE; - } - mpz_clear(tmp); - expr->len = len; - } + if (expr->dtype->type == TYPE_STRING) + *exprp = expr_postprocess_string(expr); if (expr->dtype->basetype != NULL && expr->dtype->basetype->type == TYPE_BITMASK) |