diff options
Diffstat (limited to 'src/netlink_linearize.c')
-rw-r--r-- | src/netlink_linearize.c | 147 |
1 files changed, 119 insertions, 28 deletions
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index c8bbcb74..77bc5149 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -9,10 +9,11 @@ * Development of this code funded by Astaro AG (http://www.astaro.com/) */ +#include <nft.h> + #include <linux/netfilter/nf_tables.h> #include <linux/netfilter/nf_log.h> -#include <string.h> #include <rule.h> #include <statement.h> #include <expression.h> @@ -178,9 +179,8 @@ static void netlink_gen_hash(struct netlink_linearize_ctx *ctx, nft_rule_add_expr(ctx, nle, &expr->location); } -static void netlink_gen_payload(struct netlink_linearize_ctx *ctx, - const struct expr *expr, - enum nft_registers dreg) +static struct nftnl_expr * +__netlink_gen_payload(const struct expr *expr, enum nft_registers dreg) { struct nftnl_expr *nle; @@ -193,6 +193,72 @@ static void netlink_gen_payload(struct netlink_linearize_ctx *ctx, nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_LEN, div_round_up(expr->len, BITS_PER_BYTE)); + return nle; +} + +static struct nftnl_expr * +__netlink_gen_meta(const struct expr *expr, enum nft_registers dreg) +{ + struct nftnl_expr *nle; + + nle = alloc_nft_expr("meta"); + netlink_put_register(nle, NFTNL_EXPR_META_DREG, dreg); + nftnl_expr_set_u32(nle, NFTNL_EXPR_META_KEY, expr->meta.key); + + return nle; +} + +static struct nftnl_expr *netlink_gen_inner_expr(const struct expr *expr, + enum nft_registers dreg) +{ + struct expr *_expr = (struct expr *)expr; + struct nftnl_expr *nle; + + switch (expr->etype) { + case EXPR_PAYLOAD: + if (expr->payload.base == NFT_PAYLOAD_INNER_HEADER + 1) + _expr->payload.base = NFT_PAYLOAD_TUN_HEADER + 1; + + nle = __netlink_gen_payload(expr, dreg); + break; + case EXPR_META: + nle = __netlink_gen_meta(expr, dreg); + break; + default: + assert(0); + break; + } + + return nle; +} + +static void netlink_gen_inner(struct netlink_linearize_ctx *ctx, + const struct expr *expr, + enum nft_registers dreg, + const struct proto_desc *desc) +{ + struct nftnl_expr *nle; + + nle = alloc_nft_expr("inner"); + nftnl_expr_set_u32(nle, NFTNL_EXPR_INNER_HDRSIZE, desc->inner.hdrsize); + nftnl_expr_set_u32(nle, NFTNL_EXPR_INNER_FLAGS, desc->inner.flags); + nftnl_expr_set_u32(nle, NFTNL_EXPR_INNER_TYPE, desc->inner.type); + nftnl_expr_set(nle, NFTNL_EXPR_INNER_EXPR, netlink_gen_inner_expr(expr, dreg), 0); + nft_rule_add_expr(ctx, nle, &expr->location); +} + +static void netlink_gen_payload(struct netlink_linearize_ctx *ctx, + const struct expr *expr, + enum nft_registers dreg) +{ + struct nftnl_expr *nle; + + if (expr->payload.inner_desc) { + netlink_gen_inner(ctx, expr, dreg, expr->payload.inner_desc); + return; + } + + nle = __netlink_gen_payload(expr, dreg); nft_rule_add_expr(ctx, nle, &expr->location); } @@ -221,9 +287,12 @@ static void netlink_gen_meta(struct netlink_linearize_ctx *ctx, { struct nftnl_expr *nle; - nle = alloc_nft_expr("meta"); - netlink_put_register(nle, NFTNL_EXPR_META_DREG, dreg); - nftnl_expr_set_u32(nle, NFTNL_EXPR_META_KEY, expr->meta.key); + if (expr->meta.inner_desc) { + netlink_gen_inner(ctx, expr, dreg, expr->meta.inner_desc); + return; + } + + nle = __netlink_gen_meta(expr, dreg); nft_rule_add_expr(ctx, nle, &expr->location); } @@ -391,7 +460,8 @@ static struct expr *netlink_gen_prefix(struct netlink_linearize_ctx *ctx, mpz_init(mask); mpz_prefixmask(mask, expr->right->len, expr->right->prefix_len); netlink_gen_raw_data(mask, expr->right->byteorder, - expr->right->len / BITS_PER_BYTE, &nld); + div_round_up(expr->right->len, BITS_PER_BYTE), + &nld); mpz_clear(mask); zero.len = nld.len; @@ -625,10 +695,10 @@ static void netlink_gen_bitwise(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) { + struct expr *binops[NFT_MAX_EXPR_RECURSION]; struct nftnl_expr *nle; struct nft_data_linearize nld; struct expr *left, *i; - struct expr *binops[16]; mpz_t mask, xor, val, tmp; unsigned int len; int n = 0; @@ -640,16 +710,18 @@ static void netlink_gen_bitwise(struct netlink_linearize_ctx *ctx, binops[n++] = left = (struct expr *) expr; while (left->etype == EXPR_BINOP && left->left != NULL && - (left->op == OP_AND || left->op == OP_OR || left->op == OP_XOR)) + (left->op == OP_AND || left->op == OP_OR || left->op == OP_XOR)) { + if (n == array_size(binops)) + BUG("NFT_MAX_EXPR_RECURSION limit reached"); binops[n++] = left = left->left; - n--; + } - netlink_gen_expr(ctx, binops[n--], dreg); + netlink_gen_expr(ctx, binops[--n], dreg); mpz_bitmask(mask, expr->len); mpz_set_ui(xor, 0); - for (; n >= 0; n--) { - i = binops[n]; + while (n > 0) { + i = binops[--n]; mpz_set(val, i->right->value); switch (i->op) { @@ -725,6 +797,8 @@ static void netlink_gen_unary(struct netlink_linearize_ctx *ctx, struct nftnl_expr *nle; int byte_size; + assert(div_round_up(expr->arg->len, BITS_PER_BYTE) != 1); + if ((expr->arg->len % 64) == 0) byte_size = 8; else if ((expr->arg->len % 32) == 0) @@ -738,7 +812,7 @@ static void netlink_gen_unary(struct netlink_linearize_ctx *ctx, netlink_put_register(nle, NFTNL_EXPR_BYTEORDER_SREG, dreg); netlink_put_register(nle, NFTNL_EXPR_BYTEORDER_DREG, dreg); nftnl_expr_set_u32(nle, NFTNL_EXPR_BYTEORDER_LEN, - expr->len / BITS_PER_BYTE); + div_round_up(expr->len, BITS_PER_BYTE)); nftnl_expr_set_u32(nle, NFTNL_EXPR_BYTEORDER_SIZE, byte_size); nftnl_expr_set_u32(nle, NFTNL_EXPR_BYTEORDER_OP, @@ -933,6 +1007,17 @@ static struct nftnl_expr *netlink_gen_quota_stmt(const struct stmt *stmt) return nle; } +static struct nftnl_expr *netlink_gen_last_stmt(const struct stmt *stmt) +{ + struct nftnl_expr *nle; + + nle = alloc_nft_expr("last"); + nftnl_expr_set_u32(nle, NFTNL_EXPR_LAST_SET, stmt->last.set); + nftnl_expr_set_u64(nle, NFTNL_EXPR_LAST_MSECS, stmt->last.used); + + return nle; +} + struct nftnl_expr *netlink_gen_stmt_stateful(const struct stmt *stmt) { switch (stmt->ops->type) { @@ -944,6 +1029,8 @@ struct nftnl_expr *netlink_gen_stmt_stateful(const struct stmt *stmt) return netlink_gen_limit_stmt(stmt); case STMT_QUOTA: return netlink_gen_quota_stmt(stmt); + case STMT_LAST: + return netlink_gen_last_stmt(stmt); default: BUG("unknown stateful statement type %s\n", stmt->ops->name); } @@ -1030,6 +1117,8 @@ static void netlink_gen_payload_stmt(struct netlink_linearize_ctx *ctx, } if ((expr->payload.base == PROTO_BASE_NETWORK_HDR && desc && payload_needs_l4csum_update_pseudohdr(expr, desc)) || + (expr->payload.base == PROTO_BASE_TRANSPORT_HDR && desc && + desc == &proto_udp) || expr->payload.base == PROTO_BASE_INNER_HDR) nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_FLAGS, NFT_PAYLOAD_L4CSUM_PSEUDOHDR); @@ -1059,12 +1148,9 @@ static void netlink_gen_log_stmt(struct netlink_linearize_ctx *ctx, struct nftnl_expr *nle; nle = alloc_nft_expr("log"); - if (stmt->log.prefix != NULL) { - char prefix[NF_LOG_PREFIXLEN] = {}; + if (stmt->log.prefix != NULL) + nftnl_expr_set_str(nle, NFTNL_EXPR_LOG_PREFIX, stmt->log.prefix); - expr_to_string(stmt->log.prefix, prefix); - nftnl_expr_set_str(nle, NFTNL_EXPR_LOG_PREFIX, prefix); - } if (stmt->log.flags & STMT_LOG_GROUP) { nftnl_expr_set_u16(nle, NFTNL_EXPR_LOG_GROUP, stmt->log.group); if (stmt->log.flags & STMT_LOG_SNAPLEN) @@ -1502,14 +1588,14 @@ static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx, int num_stmts = 0; struct stmt *this; - sreg_key = get_register(ctx, stmt->map.key); - netlink_gen_expr(ctx, stmt->map.key, sreg_key); + sreg_key = get_register(ctx, stmt->map.key->key); + netlink_gen_expr(ctx, stmt->map.key->key, sreg_key); - sreg_data = get_register(ctx, stmt->map.data); - netlink_gen_expr(ctx, stmt->map.data, sreg_data); + sreg_data = get_register(ctx, stmt->map.data->key); + netlink_gen_expr(ctx, stmt->map.data->key, sreg_data); - release_register(ctx, stmt->map.key); - release_register(ctx, stmt->map.data); + release_register(ctx, stmt->map.key->key); + release_register(ctx, stmt->map.data->key); nle = alloc_nft_expr("dynset"); netlink_put_register(nle, NFTNL_EXPR_DYNSET_SREG_KEY, sreg_key); @@ -1520,6 +1606,10 @@ static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx, nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, set->handle.set_id); nft_rule_add_expr(ctx, nle, &stmt->location); + if (stmt->map.key->timeout > 0) + nftnl_expr_set_u64(nle, NFTNL_EXPR_DYNSET_TIMEOUT, + stmt->map.key->timeout); + list_for_each_entry(this, &stmt->map.stmt_list, list) num_stmts++; @@ -1615,6 +1705,7 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx, case STMT_COUNTER: case STMT_LIMIT: case STMT_QUOTA: + case STMT_LAST: nle = netlink_gen_stmt_stateful(stmt); nft_rule_add_expr(ctx, nle, &stmt->location); break; @@ -1656,9 +1747,9 @@ void netlink_linearize_fini(struct netlink_linearize_ctx *lctx) for (i = 0; i < NFT_EXPR_LOC_HSIZE; i++) { list_for_each_entry_safe(eloc, next, &lctx->expr_loc_htable[i], hlist) - xfree(eloc); + free(eloc); } - xfree(lctx->expr_loc_htable); + free(lctx->expr_loc_htable); } void netlink_linearize_rule(struct netlink_ctx *ctx, |