summaryrefslogtreecommitdiffstats
path: root/iptables/nft-arp.c
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2014-09-30 13:07:18 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2014-09-30 14:45:07 +0200
commit2c4a34c30cb4db93653dbd139e04f7df963c3a41 (patch)
tree17261327e3fb010eefe5e745e3ead71430363e9f /iptables/nft-arp.c
parent93ad9ea1b86bdaacffd8e33654abcea3d4e148b2 (diff)
iptables-compat: fix address prefix
This patch fixes: # iptables-compat -I INPUT -s 1.2.3.0/24 generates this bytecode: ip filter INPUT 20 [ payload load 4b @ network header + 12 => reg 1 ] [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ] [ cmp eq reg 1 0x00030201 ] [ counter pkts 0 bytes 0 ] and it displays: # iptables-compat-save ... -A INPUT -s 1.2.3.0/24 ip6tables-compat and arptables-compat are also fixed. This patch uses the new context structure to annotate payload, meta and bitwise, so it interprets the cmp expression based on the context. This provides a rudimentary way to delinearize the iptables-compat rule-set, but it should be enough for the built-in xtables selectors since we still use the xtables extensions. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'iptables/nft-arp.c')
-rw-r--r--iptables/nft-arp.c62
1 files changed, 43 insertions, 19 deletions
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 902d1d2b..bb4bab29 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -198,18 +198,22 @@ static int nft_arp_add(struct nft_rule *r, void *data)
add_cmp_ptr(r, NFT_CMP_EQ, fw->arp.src_devaddr.addr, fw->arp.arhln);
}
- if (fw->arp.src.s_addr != 0)
+ if (fw->arp.src.s_addr != 0) {
add_addr(r, sizeof(struct arphdr) + fw->arp.arhln,
- &fw->arp.src.s_addr, 4, flags);
+ &fw->arp.src.s_addr, &fw->arp.smsk.s_addr,
+ sizeof(struct in_addr), flags);
+ }
if (fw->arp.tgt_devaddr.addr[0] != '\0') {
add_payload(r, sizeof(struct arphdr) + fw->arp.arhln + 4, fw->arp.arhln);
add_cmp_ptr(r, NFT_CMP_EQ, fw->arp.tgt_devaddr.addr, fw->arp.arhln);
}
- if (fw->arp.tgt.s_addr != 0)
+ if (fw->arp.tgt.s_addr != 0) {
add_addr(r, sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr),
- &fw->arp.tgt.s_addr, 4, flags);
+ &fw->arp.tgt.s_addr, &fw->arp.tmsk.s_addr,
+ sizeof(struct in_addr), flags);
+ }
/* Counters need to me added before the target, otherwise they are
* increased for each rule because of the way nf_tables works.
@@ -257,13 +261,13 @@ static uint16_t ipt_to_arpt_flags(uint8_t invflags)
return result;
}
-static void nft_arp_parse_meta(struct nft_rule_expr *e, uint8_t key,
+static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nft_rule_expr *e,
void *data)
{
struct arpt_entry *fw = data;
uint8_t flags = 0;
- parse_meta(e, key, fw->arp.iniface, fw->arp.iniface_mask,
+ parse_meta(e, ctx->meta.key, fw->arp.iniface, fw->arp.iniface_mask,
fw->arp.outiface, fw->arp.outiface_mask,
&flags);
@@ -301,38 +305,43 @@ static void nft_arp_parse_immediate(const char *jumpto, bool nft_goto,
nft_arp_parse_target(target, data);
}
-static void nft_arp_parse_payload(struct nft_rule_expr_iter *iter,
- uint32_t offset, void *data)
+static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask)
+{
+ mask->s_addr = ctx->bitwise.mask[0];
+}
+
+static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
+ struct nft_rule_expr *e, void *data)
{
struct arpt_entry *fw = data;
struct in_addr addr;
unsigned short int ar_hrd, ar_pro, ar_op, ar_hln;
bool inv;
- switch (offset) {
+ switch (ctx->payload.offset) {
case offsetof(struct arphdr, ar_hrd):
- get_cmp_data(iter, &ar_hrd, sizeof(ar_hrd), &inv);
+ get_cmp_data(e, &ar_hrd, sizeof(ar_hrd), &inv);
fw->arp.arhrd = ar_hrd;
fw->arp.arhrd_mask = 0xffff;
if (inv)
fw->arp.invflags |= ARPT_INV_ARPHRD;
break;
case offsetof(struct arphdr, ar_pro):
- get_cmp_data(iter, &ar_pro, sizeof(ar_pro), &inv);
+ get_cmp_data(e, &ar_pro, sizeof(ar_pro), &inv);
fw->arp.arpro = ar_pro;
fw->arp.arpro_mask = 0xffff;
if (inv)
fw->arp.invflags |= ARPT_INV_ARPPRO;
break;
case offsetof(struct arphdr, ar_op):
- get_cmp_data(iter, &ar_op, sizeof(ar_op), &inv);
+ get_cmp_data(e, &ar_op, sizeof(ar_op), &inv);
fw->arp.arpop = ar_op;
fw->arp.arpop_mask = 0xffff;
if (inv)
fw->arp.invflags |= ARPT_INV_ARPOP;
break;
case offsetof(struct arphdr, ar_hln):
- get_cmp_data(iter, &ar_hln, sizeof(ar_op), &inv);
+ get_cmp_data(e, &ar_hln, sizeof(ar_op), &inv);
fw->arp.arhln = ar_hln;
fw->arp.arhln_mask = 0xff;
if (inv)
@@ -342,16 +351,27 @@ static void nft_arp_parse_payload(struct nft_rule_expr_iter *iter,
if (fw->arp.arhln < 0)
break;
- if (offset == sizeof(struct arphdr) + fw->arp.arhln) {
- get_cmp_data(iter, &addr, sizeof(addr), &inv);
+ if (ctx->payload.offset == sizeof(struct arphdr) +
+ fw->arp.arhln) {
+ get_cmp_data(e, &addr, sizeof(addr), &inv);
fw->arp.src.s_addr = addr.s_addr;
- fw->arp.smsk.s_addr = 0xffffffff;
+ if (ctx->flags & NFT_XT_CTX_BITWISE)
+ parse_mask_ipv4(ctx, &fw->arp.smsk);
+ else
+ fw->arp.smsk.s_addr = 0xffffffff;
+
if (inv)
fw->arp.invflags |= ARPT_INV_SRCIP;
- } else if (offset == sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr)) {
- get_cmp_data(iter, &addr, sizeof(addr), &inv);
+ } else if (ctx->payload.offset == sizeof(struct arphdr) +
+ fw->arp.arhln +
+ sizeof(struct in_addr)) {
+ get_cmp_data(e, &addr, sizeof(addr), &inv);
fw->arp.tgt.s_addr = addr.s_addr;
- fw->arp.tmsk.s_addr = 0xffffffff;
+ if (ctx->flags & NFT_XT_CTX_BITWISE)
+ parse_mask_ipv4(ctx, &fw->arp.tmsk);
+ else
+ fw->arp.tmsk.s_addr = 0xffffffff;
+
if (inv)
fw->arp.invflags |= ARPT_INV_TGTIP;
}
@@ -385,6 +405,10 @@ void nft_rule_to_arpt_entry(struct nft_rule *r, struct arpt_entry *fw)
nft_parse_payload(&ctx, expr);
else if (strcmp(name, "meta") == 0)
nft_parse_meta(&ctx, expr);
+ else if (strcmp(name, "bitwise") == 0)
+ nft_parse_bitwise(&ctx, expr);
+ else if (strcmp(name, "cmp") == 0)
+ nft_parse_cmp(&ctx, expr);
else if (strcmp(name, "immediate") == 0)
nft_parse_immediate(&ctx, expr);
else if (strcmp(name, "target") == 0)