summaryrefslogtreecommitdiffstats
path: root/src/netlink_delinearize.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/netlink_delinearize.c')
-rw-r--r--src/netlink_delinearize.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 79efda12..f41223a8 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -979,6 +979,38 @@ static void netlink_parse_reject(struct netlink_parse_ctx *ctx,
ctx->stmt = stmt;
}
+static bool is_nat_addr_map(const struct expr *addr, uint8_t family)
+{
+ const struct expr *mappings, *data;
+ const struct set *set;
+
+ if (!addr ||
+ expr_ops(addr)->type != EXPR_MAP)
+ return false;
+
+ mappings = addr->right;
+ if (expr_ops(mappings)->type != EXPR_SET_REF)
+ return false;
+
+ set = mappings->set;
+ data = set->data;
+
+ if (!(data->flags & EXPR_F_INTERVAL))
+ return false;
+
+ /* if we're dealing with an address:address map,
+ * the length will be bit_sizeof(addr) + 32 (one register).
+ */
+ switch (family) {
+ case NFPROTO_IPV4:
+ return data->len == 32 + 32;
+ case NFPROTO_IPV6:
+ return data->len == 128 + 128;
+ }
+
+ return false;
+}
+
static bool is_nat_proto_map(const struct expr *addr, uint8_t family)
{
const struct expr *mappings, *data;
@@ -1046,6 +1078,13 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
stmt->nat.addr = addr;
}
+ if (is_nat_addr_map(addr, family)) {
+ stmt->nat.family = family;
+ stmt->nat.type_flags |= STMT_NAT_F_INTERVAL;
+ ctx->stmt = stmt;
+ return;
+ }
+
reg2 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX);
if (reg2 && reg2 != reg1) {
addr = netlink_get_register(ctx, loc, reg2);