diff options
Diffstat (limited to 'iptables')
-rw-r--r-- | iptables/nft-arp.c | 259 | ||||
-rw-r--r-- | iptables/nft-arp.h | 16 | ||||
-rw-r--r-- | iptables/nft-ipv4.c | 85 | ||||
-rw-r--r-- | iptables/nft-ipv6.c | 56 | ||||
-rw-r--r-- | iptables/nft-shared.c | 136 | ||||
-rw-r--r-- | iptables/nft-shared.h | 61 | ||||
-rw-r--r-- | iptables/nft.c | 357 | ||||
-rw-r--r-- | iptables/nft.h | 5 | ||||
-rw-r--r-- | iptables/xtables-arp-standalone.c | 5 | ||||
-rw-r--r-- | iptables/xtables-arp.c | 181 | ||||
-rw-r--r-- | iptables/xtables-config-parser.y | 10 | ||||
-rw-r--r-- | iptables/xtables-events.c | 37 |
12 files changed, 612 insertions, 596 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, diff --git a/iptables/nft-arp.h b/iptables/nft-arp.h new file mode 100644 index 00000000..930dae5c --- /dev/null +++ b/iptables/nft-arp.h @@ -0,0 +1,16 @@ +#ifndef _NFT_ARP_H_ +#define _NFT_ARP_H_ + +extern char *opcodes[]; +#define NUMOPCODES 9 + +struct arptables_command_state { + struct arpt_entry fw; + struct xtables_target *target; + const char *jumpto; +}; + +void nft_rule_to_arptables_command_state(struct nft_rule *r, + struct arptables_command_state *cs); + +#endif diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 70050ba5..a2c58060 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -41,14 +41,16 @@ static int nft_ipv4_add(struct nft_rule *r, void *data) add_proto(r, offsetof(struct iphdr, protocol), 1, cs->fw.ip.proto, cs->fw.ip.invflags); - if (cs->fw.ip.src.s_addr != 0) + if (cs->fw.ip.src.s_addr != 0) { add_addr(r, offsetof(struct iphdr, saddr), - &cs->fw.ip.src.s_addr, 4, cs->fw.ip.invflags); - - if (cs->fw.ip.dst.s_addr != 0) + &cs->fw.ip.src.s_addr, &cs->fw.ip.smsk.s_addr, + sizeof(struct in_addr), cs->fw.ip.invflags); + } + if (cs->fw.ip.dst.s_addr != 0) { add_addr(r, offsetof(struct iphdr, daddr), - &cs->fw.ip.dst.s_addr, 4, cs->fw.ip.invflags); - + &cs->fw.ip.dst.s_addr, &cs->fw.ip.dmsk.s_addr, + sizeof(struct in_addr), cs->fw.ip.invflags); + } if (cs->fw.ip.flags & IPT_F_FRAG) { add_payload(r, offsetof(struct iphdr, frag_off), 2); /* get the 13 bits that contain the fragment offset */ @@ -102,35 +104,15 @@ static bool nft_ipv4_is_same(const void *data_a, b->fw.ip.iniface_mask, b->fw.ip.outiface_mask); } -static void get_frag(struct nft_rule_expr_iter *iter, bool *inv) +static void get_frag(struct nft_xt_ctx *ctx, struct nft_rule_expr *e, bool *inv) { - struct nft_rule_expr *e; - const char *name; uint8_t op; - e = nft_rule_expr_iter_next(iter); - if (e == NULL) - return; - /* we assume correct mask and xor */ - name = nft_rule_expr_get_str(e, NFT_RULE_EXPR_ATTR_NAME); - if (strcmp(name, "bitwise") != 0) { - DEBUGP("skipping no bitwise after payload\n"); - return; - } - - /* Now check for cmp */ - e = nft_rule_expr_iter_next(iter); - if (e == NULL) + if (!(ctx->flags & NFT_XT_CTX_BITWISE)) return; /* we assume correct data */ - name = nft_rule_expr_get_str(e, NFT_RULE_EXPR_ATTR_NAME); - if (strcmp(name, "cmp") != 0) { - DEBUGP("skipping no cmp after payload\n"); - return; - } - op = nft_rule_expr_get_u32(e, NFT_EXPR_CMP_OP); if (op == NFT_CMP_EQ) *inv = true; @@ -164,54 +146,66 @@ static const char *mask_to_str(uint32_t mask) return mask_str; } -static void nft_ipv4_parse_meta(struct nft_rule_expr *e, uint8_t key, +static void nft_ipv4_parse_meta(struct nft_xt_ctx *ctx, struct nft_rule_expr *e, void *data) { struct iptables_command_state *cs = data; - parse_meta(e, key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask, + parse_meta(e, ctx->meta.key, cs->fw.ip.iniface, cs->fw.ip.iniface_mask, cs->fw.ip.outiface, cs->fw.ip.outiface_mask, &cs->fw.ip.invflags); } -static void nft_ipv4_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) { - struct iptables_command_state *cs = data; + mask->s_addr = ctx->bitwise.mask[0]; +} - switch(offset) { +static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, + struct nft_rule_expr *e, void *data) +{ + struct iptables_command_state *cs = data; struct in_addr addr; uint8_t proto; bool inv; + switch(ctx->payload.offset) { case offsetof(struct iphdr, saddr): - get_cmp_data(iter, &addr, sizeof(addr), &inv); + get_cmp_data(e, &addr, sizeof(addr), &inv); cs->fw.ip.src.s_addr = addr.s_addr; - cs->fw.ip.smsk.s_addr = 0xffffffff; + if (ctx->flags & NFT_XT_CTX_BITWISE) + parse_mask_ipv4(ctx, &cs->fw.ip.smsk); + else + cs->fw.ip.smsk.s_addr = 0xffffffff; + if (inv) cs->fw.ip.invflags |= IPT_INV_SRCIP; break; case offsetof(struct iphdr, daddr): - get_cmp_data(iter, &addr, sizeof(addr), &inv); + get_cmp_data(e, &addr, sizeof(addr), &inv); cs->fw.ip.dst.s_addr = addr.s_addr; - cs->fw.ip.dmsk.s_addr = 0xffffffff; + if (ctx->flags & NFT_XT_CTX_BITWISE) + parse_mask_ipv4(ctx, &cs->fw.ip.dmsk); + else + cs->fw.ip.dmsk.s_addr = 0xffffffff; + if (inv) cs->fw.ip.invflags |= IPT_INV_DSTIP; break; case offsetof(struct iphdr, protocol): - get_cmp_data(iter, &proto, sizeof(proto), &inv); + get_cmp_data(e, &proto, sizeof(proto), &inv); cs->fw.ip.proto = proto; if (inv) cs->fw.ip.invflags |= IPT_INV_PROTO; break; case offsetof(struct iphdr, frag_off): cs->fw.ip.flags |= IPT_F_FRAG; - get_frag(iter, &inv); + get_frag(ctx, e, &inv); if (inv) cs->fw.ip.invflags |= IPT_INV_FRAG; break; default: - DEBUGP("unknown payload offset %d\n", offset); + DEBUGP("unknown payload offset %d\n", ctx->payload.offset); break; } } @@ -227,6 +221,14 @@ static void nft_ipv4_parse_immediate(const char *jumpto, bool nft_goto, cs->fw.ip.flags |= IPT_F_GOTO; } +static void nft_ipv4_print_header(unsigned int format, const char *chain, + const char *pol, + const struct xt_counters *counters, + bool basechain, uint32_t refs) +{ + print_header(format, chain, pol, counters, basechain, refs); +} + static void print_ipv4_addr(const struct iptables_command_state *cs, unsigned int format) { @@ -421,6 +423,7 @@ struct nft_family_ops nft_family_ops_ipv4 = { .parse_meta = nft_ipv4_parse_meta, .parse_payload = nft_ipv4_parse_payload, .parse_immediate = nft_ipv4_parse_immediate, + .print_header = nft_ipv4_print_header, .print_firewall = nft_ipv4_print_firewall, .save_firewall = nft_ipv4_save_firewall, .save_counters = nft_ipv4_save_counters, diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 52de5b69..5489398a 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -38,14 +38,16 @@ static int nft_ipv6_add(struct nft_rule *r, void *data) add_proto(r, offsetof(struct ip6_hdr, ip6_nxt), 1, cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags); - if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.src)) + if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.src)) { add_addr(r, offsetof(struct ip6_hdr, ip6_src), - &cs->fw6.ipv6.src, 16, cs->fw6.ipv6.invflags); - - if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dst)) + &cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk, + sizeof(struct in6_addr), cs->fw6.ipv6.invflags); + } + if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dst)) { add_addr(r, offsetof(struct ip6_hdr, ip6_dst), - &cs->fw6.ipv6.dst, 16, cs->fw6.ipv6.invflags); - + &cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk, + sizeof(struct in6_addr), cs->fw6.ipv6.invflags); + } add_compat(r, cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags); for (matchp = cs->matches; matchp; matchp = matchp->next) { @@ -87,45 +89,60 @@ static bool nft_ipv6_is_same(const void *data_a, b->fw6.ipv6.outiface_mask); } -static void nft_ipv6_parse_meta(struct nft_rule_expr *e, uint8_t key, +static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, struct nft_rule_expr *e, void *data) { struct iptables_command_state *cs = data; - parse_meta(e, key, cs->fw6.ipv6.iniface, + parse_meta(e, ctx->meta.key, cs->fw6.ipv6.iniface, cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface, cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags); } -static void nft_ipv6_parse_payload(struct nft_rule_expr_iter *iter, - uint32_t offset, void *data) +static void parse_mask_ipv6(struct nft_xt_ctx *ctx, struct in6_addr *mask) +{ + memcpy(mask, ctx->bitwise.mask, sizeof(struct in6_addr)); +} + +static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, + struct nft_rule_expr *e, void *data) { struct iptables_command_state *cs = data; - switch (offset) { struct in6_addr addr; uint8_t proto; bool inv; + switch (ctx->payload.offset) { case offsetof(struct ip6_hdr, ip6_src): - get_cmp_data(iter, &addr, sizeof(addr), &inv); + get_cmp_data(e, &addr, sizeof(addr), &inv); memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr)); + if (ctx->flags & NFT_XT_CTX_BITWISE) + parse_mask_ipv6(ctx, &cs->fw6.ipv6.smsk); + else + memset(&cs->fw.ip.smsk, 0xff, sizeof(struct in6_addr)); + if (inv) cs->fw6.ipv6.invflags |= IPT_INV_SRCIP; break; case offsetof(struct ip6_hdr, ip6_dst): - get_cmp_data(iter, &addr, sizeof(addr), &inv); + get_cmp_data(e, &addr, sizeof(addr), &inv); memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr)); + if (ctx->flags & NFT_XT_CTX_BITWISE) + parse_mask_ipv6(ctx, &cs->fw6.ipv6.dmsk); + else + memset(&cs->fw.ip.dmsk, 0xff, sizeof(struct in6_addr)); + if (inv) cs->fw6.ipv6.invflags |= IPT_INV_DSTIP; break; case offsetof(struct ip6_hdr, ip6_nxt): - get_cmp_data(iter, &proto, sizeof(proto), &inv); + get_cmp_data(e, &proto, sizeof(proto), &inv); cs->fw6.ipv6.flags |= IP6T_F_PROTO; cs->fw6.ipv6.proto = proto; if (inv) cs->fw6.ipv6.invflags |= IPT_INV_PROTO; default: - DEBUGP("unknown payload offset %d\n", offset); + DEBUGP("unknown payload offset %d\n", ctx->payload.offset); break; } } @@ -141,6 +158,14 @@ static void nft_ipv6_parse_immediate(const char *jumpto, bool nft_goto, cs->fw6.ipv6.flags |= IP6T_F_GOTO; } +static void nft_ipv6_print_header(unsigned int format, const char *chain, + const char *pol, + const struct xt_counters *counters, + bool basechain, uint32_t refs) +{ + print_header(format, chain, pol, counters, basechain, refs); +} + static void print_ipv6_addr(const struct iptables_command_state *cs, unsigned int format) { @@ -343,6 +368,7 @@ struct nft_family_ops nft_family_ops_ipv6 = { .parse_meta = nft_ipv6_parse_meta, .parse_payload = nft_ipv6_parse_payload, .parse_immediate = nft_ipv6_parse_immediate, + .print_header = nft_ipv6_print_header, .print_firewall = nft_ipv6_print_firewall, .save_firewall = nft_ipv6_save_firewall, .save_counters = nft_ipv6_save_counters, diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 0a4b85a3..00310a37 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -82,6 +82,24 @@ void add_bitwise_u16(struct nft_rule *r, int mask, int xor) nft_rule_add_expr(r, expr); } +static void add_bitwise(struct nft_rule *r, uint8_t *mask, size_t len) +{ + struct nft_rule_expr *expr; + uint32_t xor[4] = { 0 }; + + expr = nft_rule_expr_alloc("bitwise"); + if (expr == NULL) + return; + + nft_rule_expr_set_u32(expr, NFT_EXPR_BITWISE_SREG, NFT_REG_1); + nft_rule_expr_set_u32(expr, NFT_EXPR_BITWISE_DREG, NFT_REG_1); + nft_rule_expr_set_u32(expr, NFT_EXPR_BITWISE_LEN, len); + nft_rule_expr_set(expr, NFT_EXPR_BITWISE_MASK, mask, len); + nft_rule_expr_set(expr, NFT_EXPR_BITWISE_XOR, &xor, len); + + nft_rule_add_expr(r, expr); +} + void add_cmp_ptr(struct nft_rule *r, uint32_t op, void *data, size_t len) { struct nft_rule_expr *expr; @@ -151,11 +169,12 @@ void add_outiface(struct nft_rule *r, char *iface, int invflags) } void add_addr(struct nft_rule *r, int offset, - void *data, size_t len, int invflags) + void *data, void *mask, size_t len, int invflags) { uint32_t op; add_payload(r, offset, len); + add_bitwise(r, mask, len); if (invflags & IPT_INV_SRCIP || invflags & IPT_INV_DSTIP) op = NFT_CMP_NEQ; @@ -284,7 +303,7 @@ static void *nft_get_data(struct nft_xt_ctx *ctx) case NFPROTO_IPV6: return ctx->state.cs; case NFPROTO_ARP: - return ctx->state.fw; + return ctx->state.cs_arp; default: /* Should not happen */ return NULL; @@ -298,8 +317,8 @@ void nft_parse_target(struct nft_xt_ctx *ctx, struct nft_rule_expr *e) const void *targinfo = nft_rule_expr_get(e, NFT_EXPR_TG_INFO, &tg_len); struct xtables_target *target; struct xt_entry_target *t; - struct nft_family_ops *ops; size_t size; + struct nft_family_ops *ops; void *data = nft_get_data(ctx); target = xtables_find_target(targname, XTF_TRY_LOAD); @@ -365,24 +384,11 @@ void print_proto(uint16_t proto, int invert) printf("-p %u ", proto); } -void get_cmp_data(struct nft_rule_expr_iter *iter, - void *data, size_t dlen, bool *inv) +void get_cmp_data(struct nft_rule_expr *e, void *data, size_t dlen, bool *inv) { - struct nft_rule_expr *e; - const char *name; uint32_t len; uint8_t op; - e = nft_rule_expr_iter_next(iter); - if (e == NULL) - return; - - name = nft_rule_expr_get_str(e, NFT_RULE_EXPR_ATTR_NAME); - if (strcmp(name, "cmp") != 0) { - DEBUGP("skipping no cmp after meta\n"); - return; - } - memcpy(data, nft_rule_expr_get(e, NFT_EXPR_CMP_DATA, &len), dlen); op = nft_rule_expr_get_u32(e, NFT_EXPR_CMP_OP); if (op == NFT_CMP_NEQ) @@ -393,33 +399,49 @@ void get_cmp_data(struct nft_rule_expr_iter *iter, void nft_parse_meta(struct nft_xt_ctx *ctx, struct nft_rule_expr *e) { - uint8_t key = nft_rule_expr_get_u32(e, NFT_EXPR_META_KEY); - struct nft_family_ops *ops = nft_family_ops_lookup(ctx->family); - const char *name; - void *data = nft_get_data(ctx); + ctx->reg = nft_rule_expr_get_u32(e, NFT_EXPR_META_DREG); + ctx->meta.key = nft_rule_expr_get_u32(e, NFT_EXPR_META_KEY); + ctx->flags |= NFT_XT_CTX_META; +} - e = nft_rule_expr_iter_next(ctx->iter); - if (e == NULL) - return; +void nft_parse_payload(struct nft_xt_ctx *ctx, struct nft_rule_expr *e) +{ + ctx->reg = nft_rule_expr_get_u32(e, NFT_EXPR_META_DREG); + ctx->payload.offset = nft_rule_expr_get_u32(e, NFT_EXPR_PAYLOAD_OFFSET); + ctx->flags |= NFT_XT_CTX_PAYLOAD; +} - name = nft_rule_expr_get_str(e, NFT_RULE_EXPR_ATTR_NAME); - if (strcmp(name, "cmp") != 0) { - DEBUGP("skipping no cmp after meta\n"); +void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nft_rule_expr *e) +{ + uint32_t reg, len; + const void *data; + + reg = nft_rule_expr_get_u32(e, NFT_EXPR_BITWISE_SREG); + if (ctx->reg && reg != ctx->reg) return; - } - ops->parse_meta(e, key, data); + data = nft_rule_expr_get(e, NFT_EXPR_BITWISE_XOR, &len); + memcpy(ctx->bitwise.xor, data, len); + data = nft_rule_expr_get(e, NFT_EXPR_BITWISE_MASK, &len); + memcpy(ctx->bitwise.mask, data, len); + ctx->flags |= NFT_XT_CTX_BITWISE; } -void nft_parse_payload(struct nft_xt_ctx *ctx, struct nft_rule_expr *e) +void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nft_rule_expr *e) { struct nft_family_ops *ops = nft_family_ops_lookup(ctx->family); - uint32_t offset; void *data = nft_get_data(ctx); + uint32_t reg; - offset = nft_rule_expr_get_u32(e, NFT_EXPR_PAYLOAD_OFFSET); + reg = nft_rule_expr_get_u32(e, NFT_EXPR_CMP_SREG); + if (ctx->reg && reg != ctx->reg) + return; - ops->parse_payload(ctx->iter, offset, data); + if (ctx->flags & NFT_XT_CTX_META) + ops->parse_meta(ctx, e, data); + /* bitwise context is interpreted from payload */ + if (ctx->flags & NFT_XT_CTX_PAYLOAD) + ops->parse_payload(ctx, e, data); } void nft_parse_counter(struct nft_rule_expr *e, struct xt_counters *counters) @@ -486,6 +508,10 @@ void nft_rule_to_iptables_command_state(struct nft_rule *r, 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, "match") == 0) @@ -506,6 +532,50 @@ void nft_rule_to_iptables_command_state(struct nft_rule *r, cs->jumpto = ""; } +void print_header(unsigned int format, const char *chain, const char *pol, + const struct xt_counters *counters, bool basechain, + uint32_t refs) +{ + printf("Chain %s", chain); + if (basechain) { + 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); + } + + if (format & FMT_LINENUMBERS) + printf(FMT("%-4s ", "%s "), "num"); + if (!(format & FMT_NOCOUNTS)) { + if (format & FMT_KILOMEGAGIGA) { + printf(FMT("%5s ","%s "), "pkts"); + printf(FMT("%5s ","%s "), "bytes"); + } else { + printf(FMT("%8s ","%s "), "pkts"); + printf(FMT("%10s ","%s "), "bytes"); + } + } + if (!(format & FMT_NOTARGET)) + printf(FMT("%-9s ","%s "), "target"); + fputs(" prot ", stdout); + if (format & FMT_OPTIONS) + fputs("opt", stdout); + if (format & FMT_VIA) { + printf(FMT(" %-6s ","%s "), "in"); + printf(FMT("%-6s ","%s "), "out"); + } + printf(FMT(" %-19s ","%s "), "source"); + printf(FMT(" %-19s "," %s "), "destination"); + printf("\n"); +} + void print_firewall_details(const struct iptables_command_state *cs, const char *targname, uint8_t flags, uint8_t invflags, uint8_t proto, diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index c4936dde..468da5c9 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -38,14 +38,33 @@ struct xtables_args; +enum { + NFT_XT_CTX_PAYLOAD = (1 << 0), + NFT_XT_CTX_META = (1 << 1), + NFT_XT_CTX_BITWISE = (1 << 2), +}; + struct nft_xt_ctx { union { struct iptables_command_state *cs; - struct arpt_entry *fw; + struct arptables_command_state *cs_arp; } state; struct nft_rule_expr_iter *iter; int family; uint32_t flags; + + uint32_t reg; + struct { + uint32_t offset; + uint32_t len; + } payload; + struct { + uint32_t key; + } meta; + struct { + uint32_t mask[4]; + uint32_t xor[4]; + } bitwise; }; struct nft_family_ops { @@ -54,11 +73,20 @@ struct nft_family_ops { const void *data_b); void (*print_payload)(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter); - void (*parse_meta)(struct nft_rule_expr *e, uint8_t key, + void (*parse_meta)(struct nft_xt_ctx *ctx, struct nft_rule_expr *e, void *data); - void (*parse_payload)(struct nft_rule_expr_iter *iter, - uint32_t offset, void *data); + void (*parse_payload)(struct nft_xt_ctx *ctx, struct nft_rule_expr *e, + void *data); + void (*parse_bitwise)(struct nft_xt_ctx *ctx, struct nft_rule_expr *e, + void *data); + void (*parse_cmp)(struct nft_xt_ctx *ctx, struct nft_rule_expr *e, + void *data); void (*parse_immediate)(const char *jumpto, bool nft_goto, void *data); + + void (*print_header)(unsigned int format, const char *chain, + const char *pol, + const struct xt_counters *counters, bool basechain, + uint32_t refs); void (*print_firewall)(struct nft_rule *r, unsigned int num, unsigned int format); void (*save_firewall)(const void *data, unsigned int format); @@ -82,7 +110,7 @@ void add_cmp_u32(struct nft_rule *r, uint32_t val, uint32_t op); void add_iniface(struct nft_rule *r, char *iface, int invflags); void add_outiface(struct nft_rule *r, char *iface, int invflags); void add_addr(struct nft_rule *r, int offset, - void *data, size_t len, int invflags); + void *data, void *mask, size_t len, int invflags); void add_proto(struct nft_rule *r, int offset, size_t len, uint8_t proto, int invflags); void add_compat(struct nft_rule *r, uint32_t proto, bool inv); @@ -98,8 +126,9 @@ void parse_meta(struct nft_rule_expr *e, uint8_t key, char *iniface, unsigned char *iniface_mask, char *outiface, unsigned char *outiface_mask, uint8_t *invflags); void print_proto(uint16_t proto, int invert); -void get_cmp_data(struct nft_rule_expr_iter *iter, - void *data, size_t dlen, bool *inv); +void get_cmp_data(struct nft_rule_expr *e, void *data, size_t dlen, bool *inv); +void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); +void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); void nft_parse_target(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); void nft_parse_meta(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); void nft_parse_payload(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); @@ -107,6 +136,9 @@ void nft_parse_counter(struct nft_rule_expr *e, struct xt_counters *counters); void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nft_rule_expr *e); void nft_rule_to_iptables_command_state(struct nft_rule *r, struct iptables_command_state *cs); +void print_header(unsigned int format, const char *chain, const char *pol, + const struct xt_counters *counters, bool basechain, + uint32_t refs); void print_firewall_details(const struct iptables_command_state *cs, const char *targname, uint8_t flags, uint8_t invflags, uint8_t proto, @@ -180,19 +212,4 @@ struct xtables_args { #define CMD_ZERO_NUM 0x2000U #define CMD_CHECK 0x4000U -/* - * ARP - */ -extern char *opcodes[]; -#define NUMOPCODES 9 - -static inline struct xt_entry_target *nft_arp_get_target(struct arpt_entry *fw) -{ - struct xt_entry_target **target; - - target = (void *) &fw->elems; - - return *target; -} - #endif diff --git a/iptables/nft.c b/iptables/nft.c index e3b07e03..6cb03a0d 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -61,10 +61,8 @@ int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh, int ret; char buf[MNL_SOCKET_BUFFER_SIZE]; - if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0) { - perror("mnl_socket_send"); + if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0) return -1; - } ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf)); while (ret > 0) { @@ -142,6 +140,18 @@ static void mnl_nft_set_sndbuffer(const struct mnl_socket *nl) nlbuffsiz = newbuffsiz; } +static void mnl_nft_batch_reset(void) +{ + struct batch_page *batch_page, *next; + + list_for_each_entry_safe(batch_page, next, &batch_page_list, head) { + list_del(&batch_page->head); + free(batch_page->batch); + free(batch_page); + batch_num_pages--; + } +} + static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nl) { static const struct sockaddr_nl snl = { @@ -154,12 +164,12 @@ static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nl) .msg_iov = iov, .msg_iovlen = batch_num_pages, }; - struct batch_page *batch_page, *next; - int i = 0; + struct batch_page *batch_page; + int i = 0, ret; mnl_nft_set_sndbuffer(nl); - list_for_each_entry_safe(batch_page, next, &batch_page_list, head) { + list_for_each_entry(batch_page, &batch_page_list, head) { iov[i].iov_base = mnl_nlmsg_batch_head(batch_page->batch); iov[i].iov_len = mnl_nlmsg_batch_size(batch_page->batch); i++; @@ -169,26 +179,14 @@ static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nl) mnl_nlmsg_batch_size(batch_page->batch), sizeof(struct nfgenmsg)); #endif - list_del(&batch_page->head); - free(batch_page->batch); - free(batch_page); - batch_num_pages--; } - return sendmsg(mnl_socket_get_fd(nl), &msg, 0); -} + ret = sendmsg(mnl_socket_get_fd(nl), &msg, 0); + mnl_nft_batch_reset(); -static int cb_err(const struct nlmsghdr *nlh, void *data) -{ - /* We can provide better error reporting than iptables-restore */ - errno = EINVAL; - return MNL_CB_ERROR; + return ret; } -static mnl_cb_t cb_ctl_array[NLMSG_MIN_TYPE] = { - [NLMSG_ERROR] = cb_err, -}; - static int mnl_nft_batch_talk(struct nft_handle *h) { int ret, fd = mnl_socket_get_fd(h->nl); @@ -201,78 +199,59 @@ static int mnl_nft_batch_talk(struct nft_handle *h) int err = 0; ret = mnl_nft_socket_sendmsg(h->nl); - if (ret == -1) { - perror("mnl_socket_sendmsg"); + if (ret == -1) return -1; - } FD_ZERO(&readfds); FD_SET(fd, &readfds); /* receive and digest all the acknowledgments from the kernel. */ ret = select(fd+1, &readfds, NULL, NULL, &tv); - if (ret == -1) { - perror("select"); + if (ret == -1) return -1; - } + while (ret > 0 && FD_ISSET(fd, &readfds)) { ret = mnl_socket_recvfrom(h->nl, rcv_buf, sizeof(rcv_buf)); - if (ret == -1) { - perror("mnl_socket_recvfrom"); + if (ret == -1) return -1; - } - ret = mnl_cb_run2(rcv_buf, ret, 0, h->portid, - NULL, NULL, cb_ctl_array, - MNL_ARRAY_SIZE(cb_ctl_array)); - /* Continue on error, make sure we get all acknoledgments */ - if (ret == -1) + ret = mnl_cb_run(rcv_buf, ret, 0, h->portid, NULL, NULL); + /* Annotate first error and continue, make sure we get all + * acknoledgments. + */ + if (!err && ret == -1) err = errno; ret = select(fd+1, &readfds, NULL, NULL, &tv); - if (ret == -1) { - perror("select"); + if (ret == -1) return -1; - } + FD_ZERO(&readfds); FD_SET(fd, &readfds); } + errno = err; return err ? -1 : 0; } -static void mnl_nft_batch_put(struct mnl_nlmsg_batch *batch, int type, - uint32_t seq) +static void mnl_nft_batch_begin(struct mnl_nlmsg_batch *batch, uint32_t seq) { - struct nlmsghdr *nlh; - struct nfgenmsg *nfg; - - nlh = mnl_nlmsg_put_header(mnl_nlmsg_batch_current(batch)); - nlh->nlmsg_type = type; - nlh->nlmsg_flags = NLM_F_REQUEST; - nlh->nlmsg_seq = seq; - - nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg)); - nfg->nfgen_family = AF_INET; - nfg->version = NFNETLINK_V0; - nfg->res_id = NFNL_SUBSYS_NFTABLES; - + nft_batch_begin(mnl_nlmsg_batch_current(batch), seq); if (!mnl_nlmsg_batch_next(batch)) mnl_nft_batch_page_add(batch); } -static void mnl_nft_batch_begin(struct mnl_nlmsg_batch *batch, uint32_t seq) -{ - mnl_nft_batch_put(batch, NFNL_MSG_BATCH_BEGIN, seq); -} - static void mnl_nft_batch_end(struct mnl_nlmsg_batch *batch, uint32_t seq) { - mnl_nft_batch_put(batch, NFNL_MSG_BATCH_END, seq); + nft_batch_end(mnl_nlmsg_batch_current(batch), seq); + if (!mnl_nlmsg_batch_next(batch)) + mnl_nft_batch_page_add(batch); } enum obj_update_type { NFT_COMPAT_TABLE_ADD, NFT_COMPAT_CHAIN_ADD, + NFT_COMPAT_CHAIN_USER_ADD, + NFT_COMPAT_CHAIN_USER_DEL, NFT_COMPAT_CHAIN_UPDATE, NFT_COMPAT_RULE_APPEND, NFT_COMPAT_RULE_INSERT, @@ -539,7 +518,7 @@ static int nft_table_builtin_add(struct nft_handle *h, return ret; } -struct nft_chain * +static struct nft_chain * nft_chain_builtin_alloc(struct builtin_table *table, struct builtin_chain *chain, int policy) { @@ -582,12 +561,13 @@ int nft_chain_add(struct nft_handle *h, struct nft_chain *c, uint16_t flags) return mnl_talk(h, nlh, NULL, NULL); } -void nft_chain_builtin_add(struct nft_handle *h, struct builtin_table *table, - struct builtin_chain *chain, int policy) +static void nft_chain_builtin_add(struct nft_handle *h, + struct builtin_table *table, + struct builtin_chain *chain) { struct nft_chain *c; - c = nft_chain_builtin_alloc(table, chain, policy); + c = nft_chain_builtin_alloc(table, chain, NF_ACCEPT); if (c == NULL) return; @@ -598,7 +578,7 @@ void nft_chain_builtin_add(struct nft_handle *h, struct builtin_table *table, } /* find if built-in table already exists */ -struct builtin_table * +static struct builtin_table * nft_table_builtin_find(struct nft_handle *h, const char *table) { int i; @@ -619,7 +599,7 @@ nft_table_builtin_find(struct nft_handle *h, const char *table) } /* find if built-in chain already exists */ -struct builtin_chain * +static struct builtin_chain * nft_chain_builtin_find(struct builtin_table *t, const char *chain) { int i; @@ -635,30 +615,28 @@ nft_chain_builtin_find(struct builtin_table *t, const char *chain) return found ? &t->chains[i] : NULL; } -static void -__nft_chain_builtin_init(struct nft_handle *h, - struct builtin_table *table, const char *chain, - int policy) +static void nft_chain_builtin_init(struct nft_handle *h, + struct builtin_table *table) { - int i, default_policy; + int i; + struct nft_chain_list *list = nft_chain_dump(h); + struct nft_chain *c; - /* Initialize all built-in chains. Exception, for e one received as - * parameter, set the default policy as requested. - */ + /* Initialize built-in chains if they don't exist yet */ for (i=0; i<NF_IP_NUMHOOKS && table->chains[i].name != NULL; i++) { - if (chain && strcmp(table->chains[i].name, chain) == 0) - default_policy = policy; - else - default_policy = NF_ACCEPT; - nft_chain_builtin_add(h, table, &table->chains[i], - default_policy); + c = nft_chain_list_find(list, table->name, + table->chains[i].name); + if (c != NULL) + continue; + + nft_chain_builtin_add(h, table, &table->chains[i]); } + + nft_chain_list_free(list); } -int -nft_chain_builtin_init(struct nft_handle *h, const char *table, - const char *chain, int policy) +static int nft_xt_builtin_init(struct nft_handle *h, const char *table) { int ret = 0; struct builtin_table *t; @@ -673,7 +651,7 @@ nft_chain_builtin_init(struct nft_handle *h, const char *table, if (errno == EEXIST) goto out; } - __nft_chain_builtin_init(h, t, chain, policy); + nft_chain_builtin_init(h, t); out: return ret; } @@ -732,15 +710,12 @@ err: int nft_init(struct nft_handle *h, struct builtin_table *t) { h->nl = mnl_socket_open(NETLINK_NETFILTER); - if (h->nl == NULL) { - perror("mnl_socket_open"); + if (h->nl == NULL) return -1; - } - if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0) { - perror("mnl_socket_bind"); + if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0) return -1; - } + h->portid = mnl_socket_get_portid(h->nl); h->tables = t; @@ -1019,7 +994,7 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table, /* If built-in chains don't exist for this table, create them */ if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) - nft_chain_builtin_init(h, table, chain, NF_ACCEPT); + nft_xt_builtin_init(h, table); nft_fn = nft_rule_append; @@ -1074,15 +1049,11 @@ static int nft_chain_list_cb(const struct nlmsghdr *nlh, void *data) struct nft_chain_list *list = data; c = nft_chain_alloc(); - if (c == NULL) { - perror("OOM"); + if (c == NULL) goto err; - } - if (nft_chain_nlmsg_parse(nlh, c) < 0) { - perror("nft_rule_nlmsg_parse"); + if (nft_chain_nlmsg_parse(nlh, c) < 0) goto out; - } nft_chain_list_add_tail(c, list); @@ -1180,15 +1151,11 @@ static int nft_rule_list_cb(const struct nlmsghdr *nlh, void *data) struct nft_rule_list *list = data; r = nft_rule_alloc(); - if (r == NULL) { - perror("OOM"); + if (r == NULL) goto err; - } - if (nft_rule_nlmsg_parse(nlh, r) < 0) { - perror("nft_rule_nlmsg_parse"); + if (nft_rule_nlmsg_parse(nlh, r) < 0) goto out; - } nft_rule_list_add_tail(r, list); @@ -1328,14 +1295,14 @@ err: int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table) { - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; struct nft_chain *c; int ret; + nft_fn = nft_chain_user_add; + /* If built-in chains don't exist for this table, create them */ if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) - nft_chain_builtin_init(h, table, NULL, NF_ACCEPT); + nft_xt_builtin_init(h, table); c = nft_chain_alloc(); if (c == NULL) @@ -1344,12 +1311,19 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl nft_chain_attr_set(c, NFT_CHAIN_ATTR_TABLE, (char *)table); nft_chain_attr_set(c, NFT_CHAIN_ATTR_NAME, (char *)chain); - nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, h->family, - NLM_F_ACK|NLM_F_EXCL, h->seq); - nft_chain_nlmsg_build_payload(nlh, c); - nft_chain_free(c); + if (h->batch_support) { + ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c); + } else { + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; - ret = mnl_talk(h, nlh, NULL, NULL); + nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, + h->family, + NLM_F_ACK|NLM_F_EXCL, h->seq); + nft_chain_nlmsg_build_payload(nlh, c); + nft_chain_free(c); + ret = mnl_talk(h, nlh, NULL, NULL); + } /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; @@ -1400,7 +1374,11 @@ int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *tabl if (chain != NULL && strcmp(chain, chain_name) != 0) goto next; - ret = __nft_chain_del(h, c); + if (h->batch_support) + ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c); + else + ret = __nft_chain_del(h, c); + if (ret < 0) break; @@ -1414,11 +1392,14 @@ next: nft_chain_list_iter_destroy(iter); err: - nft_chain_list_free(list); + if (!h->batch_support) + nft_chain_list_free(list); /* chain not found */ - if (ret < 0 && deleted_ctr == 0) + if (deleted_ctr == 0) { + ret = -1; errno = ENOENT; + } /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; @@ -1472,15 +1453,13 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain) int nft_chain_user_rename(struct nft_handle *h,const char *chain, const char *table, const char *newname) { - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; struct nft_chain *c; uint64_t handle; int ret; /* If built-in chains don't exist for this table, create them */ if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) - nft_chain_builtin_init(h, table, NULL, NF_ACCEPT); + nft_xt_builtin_init(h, table); /* Find the old chain to be renamed */ c = nft_chain_find(h, table, chain); @@ -1499,12 +1478,19 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain, nft_chain_attr_set(c, NFT_CHAIN_ATTR_NAME, (char *)newname); nft_chain_attr_set_u64(c, NFT_CHAIN_ATTR_HANDLE, handle); - nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, h->family, - NLM_F_ACK, h->seq); - nft_chain_nlmsg_build_payload(nlh, c); - nft_chain_free(c); + if (h->batch_support) { + ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c); + } else { + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; - ret = mnl_talk(h, nlh, NULL, NULL); + nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, + h->family, NLM_F_ACK, h->seq); + nft_chain_nlmsg_build_payload(nlh, c); + nft_chain_free(c); + + ret = mnl_talk(h, nlh, NULL, NULL); + } /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; @@ -1516,15 +1502,11 @@ static int nft_table_list_cb(const struct nlmsghdr *nlh, void *data) struct nft_table_list *list = data; t = nft_table_alloc(); - if (t == NULL) { - perror("OOM"); + if (t == NULL) goto err; - } - if (nft_table_nlmsg_parse(nlh, t) < 0) { - perror("nft_rule_nlmsg_parse"); + if (nft_table_nlmsg_parse(nlh, t) < 0) goto out; - } nft_table_list_add_tail(t, list); @@ -1804,7 +1786,7 @@ int nft_rule_insert(struct nft_handle *h, const char *chain, /* If built-in chains don't exist for this table, create them */ if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) - nft_chain_builtin_init(h, table, chain, NF_ACCEPT); + nft_xt_builtin_init(h, table); nft_fn = nft_rule_insert; @@ -1890,50 +1872,6 @@ int nft_rule_replace(struct nft_handle *h, const char *chain, return ret; } -static void -print_header(unsigned int format, const char *chain, const char *pol, - const struct xt_counters *counters, bool basechain, uint32_t refs) -{ - printf("Chain %s", chain); - if (basechain) { - 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); - } - - if (format & FMT_LINENUMBERS) - printf(FMT("%-4s ", "%s "), "num"); - if (!(format & FMT_NOCOUNTS)) { - if (format & FMT_KILOMEGAGIGA) { - printf(FMT("%5s ","%s "), "pkts"); - printf(FMT("%5s ","%s "), "bytes"); - } else { - printf(FMT("%8s ","%s "), "pkts"); - printf(FMT("%10s ","%s "), "bytes"); - } - } - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ","%s "), "target"); - fputs(" prot ", stdout); - if (format & FMT_OPTIONS) - fputs("opt", stdout); - if (format & FMT_VIA) { - printf(FMT(" %-6s ","%s "), "in"); - printf(FMT("%-6s ","%s "), "out"); - } - printf(FMT(" %-19s ","%s "), "source"); - printf(FMT(" %-19s "," %s "), "destination"); - printf("\n"); -} - static int __nft_rule_list(struct nft_handle *h, const char *chain, const char *table, int rulenum, unsigned int format, @@ -2001,8 +1939,14 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, bool found = false; /* If built-in chains don't exist for this table, create them */ - if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) - nft_chain_builtin_init(h, table, NULL, NF_ACCEPT); + if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0) { + nft_xt_builtin_init(h, table); + /* Force table and chain creation, otherwise first iptables -L + * lists no table/chains. + */ + if (!list_empty(&h->obj_list)) + nft_commit(h); + } ops = nft_family_ops_lookup(h->family); @@ -2045,8 +1989,8 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table, if (found) printf("\n"); - print_header(format, chain_name, policy_name[policy], - &ctrs, basechain, refs); + ops->print_header(format, chain_name, policy_name[policy], + &ctrs, basechain, refs); __nft_rule_list(h, chain_name, table, rulenum, format, ops->print_firewall); @@ -2266,6 +2210,15 @@ static int nft_action(struct nft_handle *h, int action) NLM_F_CREATE, seq++, n->chain); break; + case NFT_COMPAT_CHAIN_USER_ADD: + nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN, + NLM_F_EXCL, seq++, + n->chain); + break; + case NFT_COMPAT_CHAIN_USER_DEL: + nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN, + 0, seq++, n->chain); + break; case NFT_COMPAT_CHAIN_UPDATE: nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN, h->restore ? @@ -2314,8 +2267,6 @@ static int nft_action(struct nft_handle *h, int action) h->batch = mnl_nft_batch_page_add(h->batch); ret = mnl_nft_batch_talk(h); - if (ret < 0) - perror("mnl_nft_batch_talk:"); mnl_nlmsg_batch_reset(h->batch); @@ -2364,33 +2315,24 @@ int nft_compatible_revision(const char *name, uint8_t rev, int opt) name, rev, type); nl = mnl_socket_open(NETLINK_NETFILTER); - if (nl == NULL) { - perror("mnl_socket_open"); + if (nl == NULL) return 0; - } - if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { - perror("mnl_socket_bind"); + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) goto err; - } + portid = mnl_socket_get_portid(nl); - if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { - perror("mnl_socket_send"); + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) goto err; - } ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); - if (ret == -1) { - perror("mnl_socket_recvfrom"); + if (ret == -1) goto err; - } ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); - if (ret == -1) { - perror("mnl_cb_run"); + if (ret == -1) goto err; - } err: mnl_socket_close(nl); @@ -2410,10 +2352,12 @@ const char *nft_strerror(int err) { { nft_chain_user_del, ENOTEMPTY, "Chain is not empty" }, { nft_chain_user_del, EINVAL, "Can't delete built-in chain" }, + { nft_chain_user_del, EBUSY, "Directory not empty" }, { nft_chain_user_del, EMLINK, "Can't delete chain with references left" }, { nft_chain_user_add, EEXIST, "Chain already exists" }, { nft_rule_add, E2BIG, "Index of insertion too big" }, + { nft_rule_check, ENOENT, "Bad rule (does a matching rule exist in that chain?)" }, { nft_rule_replace, E2BIG, "Index of replacement too big" }, { nft_rule_delete_num, E2BIG, "Index of deletion too big" }, /* { TC_READ_COUNTER, E2BIG, "Index of counter too big" }, @@ -2567,8 +2511,6 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain, struct nft_chain_list *list; struct nft_chain_list_iter *iter; struct nft_chain *c; - struct nlmsghdr *nlh; - char buf[MNL_SOCKET_BUFFER_SIZE]; int ret = 0; list = nft_chain_list_get(h); @@ -2597,14 +2539,18 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain, nft_chain_attr_unset(c, NFT_CHAIN_ATTR_HANDLE); - nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, - h->family, NLM_F_ACK, h->seq); - - nft_chain_nlmsg_build_payload(nlh, c); - - ret = mnl_talk(h, nlh, NULL, NULL); - if (ret < 0) - perror("mnl_talk:nft_chain_zero_counters"); + if (h->batch_support) { + ret = batch_chain_add(h, NFT_COMPAT_CHAIN_ADD, c); + } else { + struct nlmsghdr *nlh; + char buf[MNL_SOCKET_BUFFER_SIZE]; + + nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, + h->family, NLM_F_ACK, + h->seq); + nft_chain_nlmsg_build_payload(nlh, c); + ret = mnl_talk(h, nlh, NULL, NULL); + } if (chain != NULL) break; @@ -2612,11 +2558,12 @@ next: c = nft_chain_list_iter_next(iter); } + if (!h->batch_support) + nft_chain_list_free(list); + nft_chain_list_iter_destroy(iter); err: - nft_chain_list_free(list); - /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; } diff --git a/iptables/nft.h b/iptables/nft.h index 339d7bcd..0db2ed6c 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -54,7 +54,6 @@ void nft_fini(struct nft_handle *h); struct nft_table; struct nft_chain_list; -struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const char *table); int nft_table_add(struct nft_handle *h, struct nft_table *t, uint16_t flags); int nft_for_each_table(struct nft_handle *h, int (*func)(struct nft_handle *h, const char *tablename, bool counters), bool counters); bool nft_table_find(struct nft_handle *h, const char *tablename); @@ -65,10 +64,6 @@ int nft_table_purge_chains(struct nft_handle *h, const char *table, struct nft_c */ struct nft_chain; -struct nft_chain *nft_chain_builtin_alloc(struct builtin_table *table, struct builtin_chain *chain, int policy); -void nft_chain_builtin_add(struct nft_handle *h, struct builtin_table *table, struct builtin_chain *chain, int policy); -struct builtin_chain *nft_chain_builtin_find(struct builtin_table *t, const char *chain); -int nft_chain_builtin_init(struct nft_handle *h, const char *table, const char *chain, int policy); int nft_chain_add(struct nft_handle *h, struct nft_chain *c, uint16_t flags); int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters); struct nft_chain_list *nft_chain_dump(struct nft_handle *h); diff --git a/iptables/xtables-arp-standalone.c b/iptables/xtables-arp-standalone.c index 23b6bcb4..182dd9f3 100644 --- a/iptables/xtables-arp-standalone.c +++ b/iptables/xtables-arp-standalone.c @@ -84,5 +84,10 @@ int xtables_arp_main(int argc, char *argv[]) if (ret) ret = nft_commit(&h); + nft_fini(&h); + + if (!ret) + fprintf(stderr, "arptables: %s\n", nft_strerror(errno)); + exit(!ret); } diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index 0c79a387..c92b9e75 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -49,6 +49,7 @@ #include "xshared.h" #include "nft.h" +#include "nft-arp.h" #include <linux/netfilter_arp/arp_tables.h> typedef char arpt_chainlabel[32]; @@ -808,28 +809,6 @@ list_entries(struct nft_handle *h, const char *chain, const char *table, return nft_rule_list(h, chain, table, rulenum, format); } -static struct arpt_entry * -generate_entry(const struct arpt_entry *fw, - struct arpt_entry_target *target) -{ - struct arpt_entry_target **t; - struct arpt_entry *e; - unsigned int size; - - - size = sizeof(struct arpt_entry); - - e = xtables_malloc(size); - *e = *fw; - e->target_offset = offsetof(struct arpt_entry, elems); - e->next_offset = e->target_offset + target->u.target_size; - - t = (void *) &e->elems; - *t = target; - - return e; -} - static struct xtables_target *command_jump(struct arpt_entry *fw, const char *jumpto) { @@ -869,7 +848,7 @@ static int append_entry(struct nft_handle *h, const char *chain, const char *table, - struct arpt_entry *fw, + struct arptables_command_state *cs, int rulenum, unsigned int nsaddrs, const struct in_addr saddrs[], @@ -881,14 +860,14 @@ append_entry(struct nft_handle *h, int ret = 1; for (i = 0; i < nsaddrs; i++) { - fw->arp.src.s_addr = saddrs[i].s_addr; + cs->fw.arp.src.s_addr = saddrs[i].s_addr; for (j = 0; j < ndaddrs; j++) { - fw->arp.tgt.s_addr = daddrs[j].s_addr; + cs->fw.arp.tgt.s_addr = daddrs[j].s_addr; if (append) { - ret = nft_rule_append(h, chain, table, fw, 0, + ret = nft_rule_append(h, chain, table, cs, 0, verbose); } else { - ret = nft_rule_insert(h, chain, table, fw, + ret = nft_rule_insert(h, chain, table, cs, rulenum, verbose); } } @@ -900,22 +879,22 @@ append_entry(struct nft_handle *h, static int replace_entry(const char *chain, const char *table, - struct arpt_entry *fw, + struct arptables_command_state *cs, unsigned int rulenum, const struct in_addr *saddr, const struct in_addr *daddr, bool verbose, struct nft_handle *h) { - fw->arp.src.s_addr = saddr->s_addr; - fw->arp.tgt.s_addr = daddr->s_addr; + cs->fw.arp.src.s_addr = saddr->s_addr; + cs->fw.arp.tgt.s_addr = daddr->s_addr; - return nft_rule_replace(h, chain, table, fw, rulenum, verbose); + return nft_rule_replace(h, chain, table, cs, rulenum, verbose); } static int delete_entry(const char *chain, const char *table, - struct arpt_entry *fw, + struct arptables_command_state *cs, unsigned int nsaddrs, const struct in_addr saddrs[], unsigned int ndaddrs, @@ -926,10 +905,10 @@ delete_entry(const char *chain, int ret = 1; for (i = 0; i < nsaddrs; i++) { - fw->arp.src.s_addr = saddrs[i].s_addr; + cs->fw.arp.src.s_addr = saddrs[i].s_addr; for (j = 0; j < ndaddrs; j++) { - fw->arp.tgt.s_addr = daddrs[j].s_addr; - ret = nft_rule_delete(h, chain, table, fw, verbose); + cs->fw.arp.tgt.s_addr = daddrs[j].s_addr; + ret = nft_rule_delete(h, chain, table, cs, verbose); } } @@ -938,7 +917,7 @@ delete_entry(const char *chain, int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table) { - struct arpt_entry fw, *e = NULL; + struct arptables_command_state cs; int invert = 0; unsigned int nsaddrs = 0, ndaddrs = 0; struct in_addr *saddrs = NULL, *daddrs = NULL; @@ -950,12 +929,11 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table) unsigned int rulenum = 0, options = 0, command = 0; const char *pcnt = NULL, *bcnt = NULL; int ret = 1; - struct xtables_target *target = NULL; struct xtables_target *t; - const char *jumpto = ""; + memset(&cs, 0, sizeof(cs)); + cs.jumpto = ""; - memset(&fw, 0, sizeof(fw)); opts = original_opts; global_option_offset = 0; @@ -1106,47 +1084,47 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table) break; case 's': check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_S_IP, &fw.arp.invflags, + set_option(&options, OPT_S_IP, &cs.fw.arp.invflags, invert); shostnetworkmask = argv[optind-1]; break; case 'd': check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_D_IP, &fw.arp.invflags, + set_option(&options, OPT_D_IP, &cs.fw.arp.invflags, invert); dhostnetworkmask = argv[optind-1]; break; case 2:/* src-mac */ check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_S_MAC, &fw.arp.invflags, + set_option(&options, OPT_S_MAC, &cs.fw.arp.invflags, invert); if (getmac_and_mask(argv[optind - 1], - fw.arp.src_devaddr.addr, fw.arp.src_devaddr.mask)) + cs.fw.arp.src_devaddr.addr, cs.fw.arp.src_devaddr.mask)) xtables_error(PARAMETER_PROBLEM, "Problem with specified " "source mac"); break; case 3:/* dst-mac */ check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_D_MAC, &fw.arp.invflags, + set_option(&options, OPT_D_MAC, &cs.fw.arp.invflags, invert); if (getmac_and_mask(argv[optind - 1], - fw.arp.tgt_devaddr.addr, fw.arp.tgt_devaddr.mask)) + cs.fw.arp.tgt_devaddr.addr, cs.fw.arp.tgt_devaddr.mask)) xtables_error(PARAMETER_PROBLEM, "Problem with specified " "destination mac"); break; case 'l':/* hardware length */ check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_H_LENGTH, &fw.arp.invflags, + set_option(&options, OPT_H_LENGTH, &cs.fw.arp.invflags, invert); - getlength_and_mask(argv[optind - 1], &fw.arp.arhln, - &fw.arp.arhln_mask); + getlength_and_mask(argv[optind - 1], &cs.fw.arp.arhln, + &cs.fw.arp.arhln_mask); - if (fw.arp.arhln != 6) { + if (cs.fw.arp.arhln != 6) { xtables_error(PARAMETER_PROBLEM, "Only harware address length of" " 6 is supported currently."); @@ -1158,19 +1136,20 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table) xtables_error(PARAMETER_PROBLEM, "not supported"); /* check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_P_LENGTH, &fw.arp.invflags, + set_option(&options, OPT_P_LENGTH, &cs.fw.arp.invflags, invert); - getlength_and_mask(argv[optind - 1], &fw.arp.arpln, - &fw.arp.arpln_mask); + getlength_and_mask(argv[optind - 1], &cs.fw.arp.arpln, + &cs.fw.arp.arpln_mask); break; */ case 4:/* opcode */ check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_OPCODE, &fw.arp.invflags, + set_option(&options, OPT_OPCODE, &cs.fw.arp.invflags, invert); - if (get16_and_mask(argv[optind - 1], &fw.arp.arpop, &fw.arp.arpop_mask, 10)) { + if (get16_and_mask(argv[optind - 1], &cs.fw.arp.arpop, + &cs.fw.arp.arpop_mask, 10)) { int i; for (i = 0; i < NUMOPCODES; i++) @@ -1178,63 +1157,65 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table) break; if (i == NUMOPCODES) xtables_error(PARAMETER_PROBLEM, "Problem with specified opcode"); - fw.arp.arpop = htons(i+1); + cs.fw.arp.arpop = htons(i+1); } break; case 5:/* h-type */ check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_H_TYPE, &fw.arp.invflags, + set_option(&options, OPT_H_TYPE, &cs.fw.arp.invflags, invert); - if (get16_and_mask(argv[optind - 1], &fw.arp.arhrd, &fw.arp.arhrd_mask, 16)) { + if (get16_and_mask(argv[optind - 1], &cs.fw.arp.arhrd, + &cs.fw.arp.arhrd_mask, 16)) { if (strcasecmp(argv[optind-1], "Ethernet")) xtables_error(PARAMETER_PROBLEM, "Problem with specified hardware type"); - fw.arp.arhrd = htons(1); + cs.fw.arp.arhrd = htons(1); } break; case 6:/* proto-type */ check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_P_TYPE, &fw.arp.invflags, + set_option(&options, OPT_P_TYPE, &cs.fw.arp.invflags, invert); - if (get16_and_mask(argv[optind - 1], &fw.arp.arpro, &fw.arp.arpro_mask, 0)) { + if (get16_and_mask(argv[optind - 1], &cs.fw.arp.arpro, + &cs.fw.arp.arpro_mask, 0)) { if (strcasecmp(argv[optind-1], "ipv4")) xtables_error(PARAMETER_PROBLEM, "Problem with specified protocol type"); - fw.arp.arpro = htons(0x800); + cs.fw.arp.arpro = htons(0x800); } break; case 'j': - set_option(&options, OPT_JUMP, &fw.arp.invflags, + set_option(&options, OPT_JUMP, &cs.fw.arp.invflags, invert); - jumpto = parse_target(optarg); - target = command_jump(&fw, jumpto); + cs.jumpto = parse_target(optarg); + cs.target = command_jump(&cs.fw, cs.jumpto); break; case 'i': check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_VIANAMEIN, &fw.arp.invflags, + set_option(&options, OPT_VIANAMEIN, &cs.fw.arp.invflags, invert); parse_interface(argv[optind-1], - fw.arp.iniface, - fw.arp.iniface_mask); -/* fw.nfcache |= NFC_IP_IF_IN; */ + cs.fw.arp.iniface, + cs.fw.arp.iniface_mask); +/* cs.fw.nfcache |= NFC_IP_IF_IN; */ break; case 'o': check_inverse(optarg, &invert, &optind, argc); - set_option(&options, OPT_VIANAMEOUT, &fw.arp.invflags, + set_option(&options, OPT_VIANAMEOUT, &cs.fw.arp.invflags, invert); parse_interface(argv[optind-1], - fw.arp.outiface, - fw.arp.outiface_mask); - /* fw.nfcache |= NFC_IP_IF_OUT; */ + cs.fw.arp.outiface, + cs.fw.arp.outiface_mask); + /* cs.fw.nfcache |= NFC_IP_IF_OUT; */ break; case 'v': if (!verbose) set_option(&options, OPT_VERBOSE, - &fw.arp.invflags, invert); + &cs.fw.arp.invflags, invert); verbose++; break; @@ -1257,7 +1238,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table) break; case 'n': - set_option(&options, OPT_NUMERIC, &fw.arp.invflags, + set_option(&options, OPT_NUMERIC, &cs.fw.arp.invflags, invert); break; @@ -1277,7 +1258,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table) exit(0); case '0': - set_option(&options, OPT_LINENUMBERS, &fw.arp.invflags, + set_option(&options, OPT_LINENUMBERS, &cs.fw.arp.invflags, invert); break; @@ -1287,7 +1268,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table) case 'c': - set_option(&options, OPT_COUNTERS, &fw.arp.invflags, + set_option(&options, OPT_COUNTERS, &cs.fw.arp.invflags, invert); pcnt = optarg; if (optind < argc && argv[optind][0] != '-' @@ -1298,12 +1279,12 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table) "-%c requires packet and byte counter", opt2char(OPT_COUNTERS)); - if (sscanf(pcnt, "%llu", &fw.counters.pcnt) != 1) + if (sscanf(pcnt, "%llu", &cs.fw.counters.pcnt) != 1) xtables_error(PARAMETER_PROBLEM, "-%c packet counter not numeric", opt2char(OPT_COUNTERS)); - if (sscanf(bcnt, "%llu", &fw.counters.bcnt) != 1) + if (sscanf(bcnt, "%llu", &cs.fw.counters.bcnt) != 1) xtables_error(PARAMETER_PROBLEM, "-%c byte counter not numeric", opt2char(OPT_COUNTERS)); @@ -1325,17 +1306,17 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table) exit_tryhelp(2); default: - if (target) { + if (cs.target) { xtables_option_tpcall(c, argv, - invert, target, &fw); + invert, cs.target, &cs.fw); } break; } invert = FALSE; } - if (target) - xtables_option_tfcall(target); + if (cs.target) + xtables_option_tfcall(cs.target); if (optind < argc) xtables_error(PARAMETER_PROBLEM, @@ -1355,14 +1336,14 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table) if (shostnetworkmask) parse_hostnetworkmask(shostnetworkmask, &saddrs, - &(fw.arp.smsk), &nsaddrs); + &(cs.fw.arp.smsk), &nsaddrs); if (dhostnetworkmask) parse_hostnetworkmask(dhostnetworkmask, &daddrs, - &(fw.arp.tmsk), &ndaddrs); + &(cs.fw.arp.tmsk), &ndaddrs); if ((nsaddrs > 1 || ndaddrs > 1) && - (fw.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP))) + (cs.fw.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP))) xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" " source or destination IP addresses"); @@ -1409,34 +1390,26 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table) chain); } - if (!target && strlen(jumpto) != 0) { + if (!cs.target && strlen(cs.jumpto) != 0) { size_t size; - target = xtables_find_target(XT_STANDARD_TARGET, - XTF_LOAD_MUST_SUCCEED); - size = sizeof(struct arpt_entry_target) + target->size; - target->t = xtables_calloc(1, size); - target->t->u.target_size = size; - strcpy(target->t->u.user.name, jumpto); - } - - if (!target) { - xtables_error(PARAMETER_PROBLEM, - "No target provided or" - " initalization failed"); + cs.target = xtables_find_target(XT_STANDARD_TARGET, + XTF_LOAD_MUST_SUCCEED); + size = sizeof(struct arpt_entry_target) + cs.target->size; + cs.target->t = xtables_calloc(1, size); + cs.target->t->u.target_size = size; + strcpy(cs.target->t->u.user.name, cs.jumpto); } - - e = generate_entry(&fw, target->t); } switch (command) { case CMD_APPEND: - ret = append_entry(h, chain, *table, e, 0, + ret = append_entry(h, chain, *table, &cs, 0, nsaddrs, saddrs, ndaddrs, daddrs, options&OPT_VERBOSE, true); break; case CMD_DELETE: - ret = delete_entry(chain, *table, e, + ret = delete_entry(chain, *table, &cs, nsaddrs, saddrs, ndaddrs, daddrs, options&OPT_VERBOSE, h); break; @@ -1444,11 +1417,11 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table) ret = nft_rule_delete_num(h, chain, *table, rulenum - 1, verbose); break; case CMD_REPLACE: - ret = replace_entry(chain, *table, e, rulenum - 1, + ret = replace_entry(chain, *table, &cs, rulenum - 1, saddrs, daddrs, options&OPT_VERBOSE, h); break; case CMD_INSERT: - ret = append_entry(h, chain, *table, e, rulenum - 1, + ret = append_entry(h, chain, *table, &cs, rulenum - 1, nsaddrs, saddrs, ndaddrs, daddrs, options&OPT_VERBOSE, false); break; diff --git a/iptables/xtables-config-parser.y b/iptables/xtables-config-parser.y index 2770a1b9..c8116c3e 100644 --- a/iptables/xtables-config-parser.y +++ b/iptables/xtables-config-parser.y @@ -204,10 +204,9 @@ int xtables_config_parse(char *filename, struct nft_table_list *table_list, break; case T_TABLE: table = nft_table_alloc(); - if (table == NULL) { - perror("nft_table_alloc"); + if (table == NULL) return -1; - } + nft_table_attr_set_u32(table, NFT_TABLE_ATTR_FAMILY, family); nft_table_attr_set(table, NFT_TABLE_ATTR_NAME, e->data); /* This is intentionally prepending, instead of @@ -222,10 +221,9 @@ int xtables_config_parse(char *filename, struct nft_table_list *table_list, break; case T_CHAIN: chain = nft_chain_alloc(); - if (chain == NULL) { - perror("nft_chain_alloc"); + if (chain == NULL) return -1; - } + nft_chain_attr_set(chain, NFT_CHAIN_ATTR_TABLE, (char *)nft_table_attr_get(table, NFT_TABLE_ATTR_NAME)); nft_chain_attr_set_u32(chain, NFT_CHAIN_ATTR_FAMILY, diff --git a/iptables/xtables-events.c b/iptables/xtables-events.c index 4746825e..5aa7c6f0 100644 --- a/iptables/xtables-events.c +++ b/iptables/xtables-events.c @@ -27,6 +27,7 @@ #include "iptables.h" /* for xtables_globals */ #include "xtables-multi.h" #include "nft.h" +#include "nft-arp.h" static int table_cb(const struct nlmsghdr *nlh, int type) { @@ -34,15 +35,11 @@ static int table_cb(const struct nlmsghdr *nlh, int type) char buf[4096]; t = nft_table_alloc(); - if (t == NULL) { - perror("OOM"); + if (t == NULL) goto err; - } - if (nft_table_nlmsg_parse(nlh, t) < 0) { - perror("nft_table_nlmsg_parse"); + if (nft_table_nlmsg_parse(nlh, t) < 0) goto err_free; - } nft_table_snprintf(buf, sizeof(buf), t, NFT_OUTPUT_DEFAULT, 0); /* FIXME: define syntax to represent table events */ @@ -59,21 +56,17 @@ static bool counters; static int rule_cb(const struct nlmsghdr *nlh, int type) { struct iptables_command_state cs = {}; - struct arpt_entry fw_arp = {}; + struct arptables_command_state cs_arp = {}; struct nft_rule *r; void *fw = NULL; uint8_t family; r = nft_rule_alloc(); - if (r == NULL) { - perror("OOM"); + if (r == NULL) goto err; - } - if (nft_rule_nlmsg_parse(nlh, r) < 0) { - perror("nft_rule_nlmsg_parse"); + if (nft_rule_nlmsg_parse(nlh, r) < 0) goto err_free; - } family = nft_rule_attr_get_u32(r, NFT_RULE_ATTR_FAMILY); switch (family) { @@ -85,8 +78,8 @@ static int rule_cb(const struct nlmsghdr *nlh, int type) break; case NFPROTO_ARP: printf("-0 "); - nft_rule_to_arpt_entry(r, &fw_arp); - fw = &fw_arp; + nft_rule_to_arptables_command_state(r, &cs_arp); + fw = &cs_arp; break; default: goto err_free; @@ -109,15 +102,11 @@ static int chain_cb(const struct nlmsghdr *nlh, int type) char buf[4096]; t = nft_chain_alloc(); - if (t == NULL) { - perror("OOM"); + if (t == NULL) goto err; - } - if (nft_chain_nlmsg_parse(nlh, t) < 0) { - perror("nft_chain_nlmsg_parse"); + if (nft_chain_nlmsg_parse(nlh, t) < 0) goto err_free; - } nft_chain_snprintf(buf, sizeof(buf), t, NFT_OUTPUT_DEFAULT, 0); /* FIXME: define syntax to represent chain events */ @@ -198,12 +187,12 @@ int xtables_events_main(int argc, char *argv[]) nl = mnl_socket_open(NETLINK_NETFILTER); if (nl == NULL) { - perror("mnl_socket_open"); + perror("cannot open nfnetlink socket"); exit(EXIT_FAILURE); } if (mnl_socket_bind(nl, (1 << (NFNLGRP_NFTABLES-1)), MNL_SOCKET_AUTOPID) < 0) { - perror("mnl_socket_bind"); + perror("cannot bind to nfnetlink socket"); exit(EXIT_FAILURE); } @@ -215,7 +204,7 @@ int xtables_events_main(int argc, char *argv[]) ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); } if (ret == -1) { - perror("error"); + perror("cannot receive from nfnetlink socket"); exit(EXIT_FAILURE); } mnl_socket_close(nl); |