summaryrefslogtreecommitdiffstats
path: root/iptables/nft-arp.c
diff options
context:
space:
mode:
Diffstat (limited to 'iptables/nft-arp.c')
-rw-r--r--iptables/nft-arp.c259
1 files changed, 118 insertions, 141 deletions
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 902d1d2b..f45ad0f7 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -25,6 +25,7 @@
#include <linux/netfilter/nf_tables.h>
#include "nft-shared.h"
+#include "nft-arp.h"
#include "nft.h"
/* a few names */
@@ -160,11 +161,10 @@ static uint8_t arpt_to_ipt_flags(uint16_t invflags)
static int nft_arp_add(struct nft_rule *r, void *data)
{
- struct arpt_entry *fw = data;
+ struct arptables_command_state *cs = data;
+ struct arpt_entry *fw = &cs->fw;
uint8_t flags = arpt_to_ipt_flags(fw->arp.invflags);
- struct xt_entry_target *t;
- char *targname;
- int ret;
+ int ret = 0;
if (fw->arp.iniface[0] != '\0')
add_iniface(r, fw->arp.iniface, flags);
@@ -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.
@@ -217,20 +221,20 @@ static int nft_arp_add(struct nft_rule *r, void *data)
if (add_counters(r, fw->counters.pcnt, fw->counters.bcnt) < 0)
return -1;
- t = nft_arp_get_target(fw);
- targname = t->u.user.name;
-
- /* Standard target? */
- if (strcmp(targname, XTC_LABEL_ACCEPT) == 0)
- ret = add_verdict(r, NF_ACCEPT);
- else if (strcmp(targname, XTC_LABEL_DROP) == 0)
- ret = add_verdict(r, NF_DROP);
- else if (strcmp(targname, XTC_LABEL_RETURN) == 0)
- ret = add_verdict(r, NFT_RETURN);
- else if (xtables_find_target(targname, XTF_TRY_LOAD) != NULL)
- ret = add_target(r, t);
- else
- ret = add_jumpto(r, targname, NFT_JUMP);
+ if (cs->target != NULL) {
+ /* Standard target? */
+ if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
+ ret = add_verdict(r, NF_ACCEPT);
+ else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
+ ret = add_verdict(r, NF_DROP);
+ else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
+ ret = add_verdict(r, NFT_RETURN);
+ else
+ ret = add_target(r, cs->target->t);
+ } else if (strlen(cs->jumpto) > 0) {
+ /* No goto in arptables */
+ ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
+ }
return ret;
}
@@ -257,13 +261,14 @@ 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;
+ struct arptables_command_state *cs = data;
+ struct arpt_entry *fw = &cs->fw;
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);
@@ -272,67 +277,57 @@ static void nft_arp_parse_meta(struct nft_rule_expr *e, uint8_t key,
static void nft_arp_parse_target(struct xtables_target *target, void *data)
{
- struct arpt_entry *fw = data;
- struct xt_entry_target **t;
+ struct arptables_command_state *cs = data;
- fw->target_offset = offsetof(struct arpt_entry, elems);
- fw->next_offset = fw->target_offset + target->t->u.target_size;
-
- t = (void *) &fw->elems;
- *t = target->t;
+ cs->target = target;
}
static void nft_arp_parse_immediate(const char *jumpto, bool nft_goto,
void *data)
{
- struct xtables_target *target;
- size_t size;
-
- target = xtables_find_target(XT_STANDARD_TARGET,
- XTF_LOAD_MUST_SUCCEED);
-
- size = XT_ALIGN(sizeof(struct xt_entry_target)) + target->size;
+ struct arptables_command_state *cs = data;
- target->t = xtables_calloc(1, size);
- target->t->u.target_size = size;
- strcpy(target->t->u.user.name, jumpto);
- target->t->u.user.revision = target->revision;
+ cs->jumpto = jumpto;
+}
- nft_arp_parse_target(target, 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_rule_expr_iter *iter,
- uint32_t offset, void *data)
+static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
+ struct nft_rule_expr *e, void *data)
{
- struct arpt_entry *fw = data;
+ struct arptables_command_state *cs = data;
+ struct arpt_entry *fw = &cs->fw;
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 +337,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;
}
@@ -359,13 +365,14 @@ static void nft_arp_parse_payload(struct nft_rule_expr_iter *iter,
}
}
-void nft_rule_to_arpt_entry(struct nft_rule *r, struct arpt_entry *fw)
+void nft_rule_to_arptables_command_state(struct nft_rule *r,
+ struct arptables_command_state *cs)
{
struct nft_rule_expr_iter *iter;
struct nft_rule_expr *expr;
int family = nft_rule_attr_get_u32(r, NFT_RULE_ATTR_FAMILY);
struct nft_xt_ctx ctx = {
- .state.fw = fw,
+ .state.cs_arp = cs,
.family = family,
};
@@ -380,11 +387,15 @@ void nft_rule_to_arpt_entry(struct nft_rule *r, struct arpt_entry *fw)
nft_rule_expr_get_str(expr, NFT_RULE_EXPR_ATTR_NAME);
if (strcmp(name, "counter") == 0)
- nft_parse_counter(expr, &ctx.state.fw->counters);
+ nft_parse_counter(expr, &ctx.state.cs_arp->fw.counters);
else if (strcmp(name, "payload") == 0)
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)
@@ -394,25 +405,34 @@ void nft_rule_to_arpt_entry(struct nft_rule *r, struct arpt_entry *fw)
}
nft_rule_expr_iter_destroy(iter);
+
+ if (cs->target != NULL)
+ cs->jumpto = cs->target->name;
+ else if (cs->jumpto != NULL)
+ cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
+ else
+ cs->jumpto = "";
}
-static struct xtables_target
-*get_target(struct arpt_entry *fw, unsigned int format)
+static void nft_arp_print_header(unsigned int format, const char *chain,
+ const char *pol,
+ const struct xt_counters *counters,
+ bool basechain, uint32_t refs)
{
- const char *targname;
- struct xtables_target *target = NULL;
- const struct xt_entry_target *t;
-
- if (!fw->target_offset)
- return NULL;
-
- t = nft_arp_get_target(fw);
- targname = t->u.user.name;
- target = xtables_find_target(targname, XTF_TRY_LOAD);
- if (!(format & FMT_NOTARGET))
- printf("-j %s ", targname);
-
- return target;
+ printf("Chain %s", chain);
+ if (pol) {
+ printf(" (policy %s", pol);
+ if (!(format & FMT_NOCOUNTS)) {
+ fputc(' ', stdout);
+ xtables_print_num(counters->pcnt, (format|FMT_NOTABLE));
+ fputs("packets, ", stdout);
+ xtables_print_num(counters->bcnt, (format|FMT_NOTABLE));
+ fputs("bytes", stdout);
+ }
+ printf(")\n");
+ } else {
+ printf(" (%u references)\n", refs);
+ }
}
static void print_fw_details(struct arpt_entry *fw, unsigned int format)
@@ -560,54 +580,35 @@ static void
nft_arp_print_firewall(struct nft_rule *r, unsigned int num,
unsigned int format)
{
- struct arpt_entry fw = {};
- struct xtables_target *target = NULL;
- const struct xt_entry_target *t = NULL;
+ struct arptables_command_state cs = {};
- nft_rule_to_arpt_entry(r, &fw);
+ nft_rule_to_arptables_command_state(r, &cs);
if (format & FMT_LINENUMBERS)
printf("%u ", num);
- target = get_target(&fw, format);
- print_fw_details(&fw, format);
+ print_fw_details(&cs.fw, format);
- if (target) {
- if (target->print)
+ if (strlen(cs.jumpto) > 0) {
+ printf("-j %s\n", cs.jumpto);
+ } else if (cs.target) {
+ if (cs.target->print)
/* Print the target information. */
- target->print(&fw.arp, t, format & FMT_NUMERIC);
+ cs.target->print(&cs.fw, cs.target->t,
+ format & FMT_NUMERIC);
}
if (!(format & FMT_NOCOUNTS)) {
printf(", pcnt=");
- xtables_print_num(fw.counters.pcnt, format);
+ xtables_print_num(cs.fw.counters.pcnt, format);
printf("-- bcnt=");
- xtables_print_num(fw.counters.bcnt, format);
+ xtables_print_num(cs.fw.counters.bcnt, format);
}
if (!(format & FMT_NONEWLINE))
fputc('\n', stdout);
}
-static void nft_arp_save_firewall(const void *data,
- unsigned int format)
-{
- const struct arpt_entry *fw = data;
- struct xtables_target *target = NULL;
- const struct xt_entry_target *t = NULL;
-
- print_fw_details((struct arpt_entry *)fw, format);
-
- target = get_target((struct arpt_entry *)fw, format);
-
- if (target) {
- if (target->print)
- /* Print the target information. */
- target->print(&fw->arp, t, format & FMT_NUMERIC);
- }
- printf("\n");
-}
-
static bool nft_arp_is_same(const void *data_a,
const void *data_b)
{
@@ -637,49 +638,24 @@ static bool nft_arp_is_same(const void *data_a,
static bool nft_arp_rule_find(struct nft_family_ops *ops, struct nft_rule *r,
void *data)
{
- struct arpt_entry *fw = data;
- struct xt_entry_target *t_fw, *t_this;
- char *targname_fw, *targname_this;
- struct arpt_entry this = {};
+ const struct arptables_command_state *cs = data;
+ struct arptables_command_state this = {};
/* Delete by matching rule case */
- nft_rule_to_arpt_entry(r, &this);
+ nft_rule_to_arptables_command_state(r, &this);
- if (!ops->is_same(fw, &this))
+ if (!nft_arp_is_same(cs, &this))
return false;
- t_fw = nft_arp_get_target(fw);
- t_this = nft_arp_get_target(&this);
-
- targname_fw = t_fw->u.user.name;
- targname_this = t_this->u.user.name;
-
- if (!strcmp(targname_fw, targname_this) &&
- (!strcmp(targname_fw, "mangle") ||
- !strcmp(targname_fw, "CLASSIFY"))) {
- if (memcmp(t_fw->data, t_this->data,
- t_fw->u.user.target_size - sizeof(*t_fw)) != 0) {
- DEBUGP("Different target\n");
- return false;
- }
- return true;
- }
+ if (!compare_targets(cs->target, this.target))
+ return false;
- if (strcmp(targname_fw, targname_this) != 0) {
- DEBUGP("Different verdict\n");
+ if (strcmp(cs->jumpto, this.jumpto) != 0)
return false;
- }
return true;
}
-static void nft_arp_save_counters(const void *data)
-{
- const struct arpt_entry *fw = data;
-
- save_counters(fw->counters.pcnt, fw->counters.bcnt);
-}
-
struct nft_family_ops nft_family_ops_arp = {
.add = nft_arp_add,
.is_same = nft_arp_is_same,
@@ -687,9 +663,10 @@ struct nft_family_ops nft_family_ops_arp = {
.parse_meta = nft_arp_parse_meta,
.parse_payload = nft_arp_parse_payload,
.parse_immediate = nft_arp_parse_immediate,
+ .print_header = nft_arp_print_header,
.print_firewall = nft_arp_print_firewall,
- .save_firewall = nft_arp_save_firewall,
- .save_counters = nft_arp_save_counters,
+ .save_firewall = NULL,
+ .save_counters = NULL,
.post_parse = NULL,
.rule_find = nft_arp_rule_find,
.parse_target = nft_arp_parse_target,