diff options
Diffstat (limited to 'iptables/nft-arp.c')
-rw-r--r-- | iptables/nft-arp.c | 259 |
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, |