diff options
Diffstat (limited to 'iptables/nft-arp.c')
-rw-r--r-- | iptables/nft-arp.c | 553 |
1 files changed, 352 insertions, 201 deletions
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index b37ffbb5..5d66e271 100644 --- a/iptables/nft-arp.c +++ b/iptables/nft-arp.c @@ -18,6 +18,7 @@ #include <xtables.h> #include <libiptc/libxtc.h> +#include <arpa/inet.h> #include <net/if_arp.h> #include <netinet/if_ether.h> @@ -25,22 +26,8 @@ #include <linux/netfilter/nf_tables.h> #include "nft-shared.h" -#include "nft-arp.h" #include "nft.h" - -/* a few names */ -char *arp_opcodes[] = -{ - "Request", - "Reply", - "Request_Reverse", - "Reply_Reverse", - "DRARP_Request", - "DRARP_Reply", - "DRARP_Error", - "InARP_Request", - "ARP_NAK", -}; +#include "xshared.h" static bool need_devaddr(struct arpt_devaddr_info *info) { @@ -54,59 +41,80 @@ static bool need_devaddr(struct arpt_devaddr_info *info) return false; } -static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data) +static int nft_arp_add(struct nft_handle *h, struct nft_rule_ctx *ctx, + struct nftnl_rule *r, struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct arpt_entry *fw = &cs->arp; uint32_t op; int ret = 0; if (fw->arp.iniface[0] != '\0') { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_IN); - add_iniface(r, fw->arp.iniface, op); + add_iface(h, r, fw->arp.iniface, NFT_META_IIFNAME, op); } if (fw->arp.outiface[0] != '\0') { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_OUT); - add_outiface(r, fw->arp.outiface, op); + add_iface(h, r, fw->arp.outiface, NFT_META_OIFNAME, op); } if (fw->arp.arhrd != 0 || + fw->arp.arhrd_mask != 0xffff || fw->arp.invflags & IPT_INV_ARPHRD) { + uint8_t reg; + op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHRD); - add_payload(r, offsetof(struct arphdr, ar_hrd), 2, - NFT_PAYLOAD_NETWORK_HEADER); - add_cmp_u16(r, fw->arp.arhrd, op); + add_payload(h, r, offsetof(struct arphdr, ar_hrd), 2, + NFT_PAYLOAD_NETWORK_HEADER, ®); + if (fw->arp.arhrd_mask != 0xffff) + add_bitwise_u16(h, r, fw->arp.arhrd_mask, 0, reg, ®); + add_cmp_u16(r, fw->arp.arhrd, op, reg); } if (fw->arp.arpro != 0 || + fw->arp.arpro_mask != 0xffff || fw->arp.invflags & IPT_INV_PROTO) { + uint8_t reg; + op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_PROTO); - add_payload(r, offsetof(struct arphdr, ar_pro), 2, - NFT_PAYLOAD_NETWORK_HEADER); - add_cmp_u16(r, fw->arp.arpro, op); + add_payload(h, r, offsetof(struct arphdr, ar_pro), 2, + NFT_PAYLOAD_NETWORK_HEADER, ®); + if (fw->arp.arpro_mask != 0xffff) + add_bitwise_u16(h, r, fw->arp.arpro_mask, 0, reg, ®); + add_cmp_u16(r, fw->arp.arpro, op, reg); } if (fw->arp.arhln != 0 || + fw->arp.arhln_mask != 255 || fw->arp.invflags & IPT_INV_ARPHLN) { + uint8_t reg; + op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHLN); - add_proto(r, offsetof(struct arphdr, ar_hln), 1, - fw->arp.arhln, op); + add_payload(h, r, offsetof(struct arphdr, ar_hln), 1, + NFT_PAYLOAD_NETWORK_HEADER, ®); + if (fw->arp.arhln_mask != 255) + add_bitwise(h, r, &fw->arp.arhln_mask, 1, reg, ®); + add_cmp_u8(r, fw->arp.arhln, op, reg); } - add_proto(r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ); + add_proto(h, r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ); if (fw->arp.arpop != 0 || + fw->arp.arpop_mask != 0xffff || fw->arp.invflags & IPT_INV_ARPOP) { + uint8_t reg; + op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPOP); - add_payload(r, offsetof(struct arphdr, ar_op), 2, - NFT_PAYLOAD_NETWORK_HEADER); - add_cmp_u16(r, fw->arp.arpop, op); + add_payload(h, r, offsetof(struct arphdr, ar_op), 2, + NFT_PAYLOAD_NETWORK_HEADER, ®); + if (fw->arp.arpop_mask != 0xffff) + add_bitwise_u16(h, r, fw->arp.arpop_mask, 0, reg, ®); + add_cmp_u16(r, fw->arp.arpop, op, reg); } if (need_devaddr(&fw->arp.src_devaddr)) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCDEVADDR); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, sizeof(struct arphdr), &fw->arp.src_devaddr.addr, &fw->arp.src_devaddr.mask, @@ -118,7 +126,7 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data) fw->arp.smsk.s_addr != 0 || fw->arp.invflags & IPT_INV_SRCIP) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCIP); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, sizeof(struct arphdr) + fw->arp.arhln, &fw->arp.src.s_addr, &fw->arp.smsk.s_addr, sizeof(struct in_addr), op); @@ -127,7 +135,7 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data) if (need_devaddr(&fw->arp.tgt_devaddr)) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_TGTDEVADDR); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr), &fw->arp.tgt_devaddr.addr, &fw->arp.tgt_devaddr.mask, @@ -138,7 +146,7 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data) fw->arp.tmsk.s_addr != 0 || fw->arp.invflags & IPT_INV_DSTIP) { op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_DSTIP); - add_addr(r, NFT_PAYLOAD_NETWORK_HEADER, + add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER, sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln, &fw->arp.tgt.s_addr, &fw->arp.tmsk.s_addr, sizeof(struct in_addr), op); @@ -168,151 +176,13 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data) return ret; } -static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, - void *data) -{ - struct iptables_command_state *cs = data; - struct arpt_entry *fw = &cs->arp; - uint8_t flags = 0; - - parse_meta(e, ctx->meta.key, fw->arp.iniface, fw->arp.iniface_mask, - fw->arp.outiface, fw->arp.outiface_mask, - &flags); - - fw->arp.invflags |= flags; -} - -static void nft_arp_parse_immediate(const char *jumpto, bool nft_goto, - void *data) -{ - struct iptables_command_state *cs = data; - - cs->jumpto = jumpto; -} - -static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask) -{ - mask->s_addr = ctx->bitwise.mask[0]; -} - -static bool nft_arp_parse_devaddr(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, - struct arpt_devaddr_info *info) -{ - uint32_t hlen; - bool inv; - - nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &hlen); - - if (hlen != ETH_ALEN) - return false; - - get_cmp_data(e, info->addr, ETH_ALEN, &inv); - - if (ctx->flags & NFT_XT_CTX_BITWISE) { - memcpy(info->mask, ctx->bitwise.mask, ETH_ALEN); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { - memset(info->mask, 0xff, - min(ctx->payload.len, ETH_ALEN)); - } - - return inv; -} - -static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) -{ - struct iptables_command_state *cs = data; - struct arpt_entry *fw = &cs->arp; - struct in_addr addr; - uint16_t ar_hrd, ar_pro, ar_op; - uint8_t ar_hln; - bool inv; - - switch (ctx->payload.offset) { - case offsetof(struct arphdr, ar_hrd): - 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 |= IPT_INV_ARPHRD; - break; - case offsetof(struct arphdr, ar_pro): - 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 |= IPT_INV_PROTO; - break; - case offsetof(struct arphdr, ar_op): - 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 |= IPT_INV_ARPOP; - break; - case offsetof(struct arphdr, ar_hln): - get_cmp_data(e, &ar_hln, sizeof(ar_hln), &inv); - fw->arp.arhln = ar_hln; - fw->arp.arhln_mask = 0xff; - if (inv) - fw->arp.invflags |= IPT_INV_ARPOP; - break; - default: - if (ctx->payload.offset == sizeof(struct arphdr)) { - if (nft_arp_parse_devaddr(ctx, e, &fw->arp.src_devaddr)) - fw->arp.invflags |= IPT_INV_SRCDEVADDR; - } else 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; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - parse_mask_ipv4(ctx, &fw->arp.smsk); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { - memset(&fw->arp.smsk, 0xff, - min(ctx->payload.len, - sizeof(struct in_addr))); - } - - if (inv) - fw->arp.invflags |= IPT_INV_SRCIP; - } else if (ctx->payload.offset == sizeof(struct arphdr) + - fw->arp.arhln + - sizeof(struct in_addr)) { - if (nft_arp_parse_devaddr(ctx, e, &fw->arp.tgt_devaddr)) - fw->arp.invflags |= IPT_INV_TGTDEVADDR; - } else if (ctx->payload.offset == sizeof(struct arphdr) + - fw->arp.arhln + - sizeof(struct in_addr) + - fw->arp.arhln) { - get_cmp_data(e, &addr, sizeof(addr), &inv); - fw->arp.tgt.s_addr = addr.s_addr; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - parse_mask_ipv4(ctx, &fw->arp.tmsk); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { - memset(&fw->arp.tmsk, 0xff, - min(ctx->payload.len, - sizeof(struct in_addr))); - } - - if (inv) - fw->arp.invflags |= IPT_INV_DSTIP; - } - break; - } -} - 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, - uint32_t entries) + int refs, uint32_t entries) { printf("Chain %s", chain); - if (basechain && pol) { + if (pol) { printf(" (policy %s", pol); if (!(format & FMT_NOCOUNTS)) { fputc(' ', stdout); @@ -323,7 +193,7 @@ static void nft_arp_print_header(unsigned int format, const char *chain, } printf(")\n"); } else { - printf(" (%u references)\n", refs); + printf(" (%d references)\n", refs); } } @@ -419,7 +289,8 @@ after_devsrc: after_devdst: - if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6) { + if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6 || + fw->arp.invflags & IPT_INV_ARPHLN) { printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHLN ? "! " : ""); printf("--h-length %d", fw->arp.arhln); @@ -433,7 +304,7 @@ after_devdst: printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPOP ? "! " : ""); - if (tmp <= NUMOPCODES && !(format & FMT_NUMERIC)) + if (tmp <= ARP_NUMOPCODES && !(format & FMT_NUMERIC)) printf("--opcode %s", arp_opcodes[tmp-1]); else printf("--opcode %d", tmp); @@ -443,7 +314,8 @@ after_devdst: sep = " "; } - if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1)) { + if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1) || + fw->arp.invflags & IPT_INV_ARPHRD) { uint16_t tmp = ntohs(fw->arp.arhrd); printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHRD @@ -451,9 +323,9 @@ after_devdst: if (tmp == 1 && !(format & FMT_NUMERIC)) printf("--h-type %s", "Ethernet"); else - printf("--h-type %u", tmp); + printf("--h-type 0x%x", tmp); if (fw->arp.arhrd_mask != 65535) - printf("/%d", ntohs(fw->arp.arhrd_mask)); + printf("/0x%x", ntohs(fw->arp.arhrd_mask)); sep = " "; } @@ -467,18 +339,17 @@ after_devdst: else printf("--proto-type 0x%x", tmp); if (fw->arp.arpro_mask != 65535) - printf("/%x", ntohs(fw->arp.arpro_mask)); + printf("/0x%x", ntohs(fw->arp.arpro_mask)); sep = " "; } } static void -nft_arp_save_rule(const void *data, unsigned int format) +nft_arp_save_rule(const struct iptables_command_state *cs, unsigned int format) { - const struct iptables_command_state *cs = data; - format |= FMT_NUMERIC; + printf(" "); nft_arp_print_rule_details(cs, format); if (cs->target && cs->target->save) cs->target->save(&cs->fw, cs->target->t); @@ -509,14 +380,14 @@ nft_arp_print_rule(struct nft_handle *h, struct nftnl_rule *r, if (!(format & FMT_NONEWLINE)) fputc('\n', stdout); - nft_clear_iptables_command_state(&cs); + xtables_clear_iptables_command_state(&cs); } -static bool nft_arp_is_same(const void *data_a, - const void *data_b) +static bool nft_arp_is_same(const struct iptables_command_state *cs_a, + const struct iptables_command_state *cs_b) { - const struct arpt_entry *a = data_a; - const struct arpt_entry *b = data_b; + const struct arpt_entry *a = &cs_a->arp; + const struct arpt_entry *b = &cs_b->arp; if (a->arp.src.s_addr != b->arp.src.s_addr || a->arp.tgt.s_addr != b->arp.tgt.s_addr @@ -617,7 +488,8 @@ static void nft_arp_post_parse(int command, cs->arp.counters.pcnt = args->pcnt_cnt; cs->arp.counters.bcnt = args->bcnt_cnt; - if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) { + if (command & (CMD_REPLACE | CMD_INSERT | + CMD_DELETE | CMD_APPEND | CMD_CHECK)) { if (!(cs->options & OPT_DESTINATION)) args->dhostnetworkmask = "0.0.0.0/0"; if (!(cs->options & OPT_SOURCE)) @@ -634,7 +506,7 @@ static void nft_arp_post_parse(int command, &args->d.naddrs); if ((args->s.naddrs > 1 || args->d.naddrs > 1) && - (cs->arp.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP))) + (cs->arp.arp.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP))) xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" " source or destination IP addresses"); @@ -657,18 +529,18 @@ static void nft_arp_post_parse(int command, if (cs->arp.arp.arhln != 6) xtables_error(PARAMETER_PROBLEM, - "Only harware address length of 6 is supported currently."); + "Only hardware address length of 6 is supported currently."); } if (args->arp_opcode) { if (get16_and_mask(args->arp_opcode, &cs->arp.arp.arpop, &cs->arp.arp.arpop_mask, 10)) { int i; - for (i = 0; i < NUMOPCODES; i++) + for (i = 0; i < ARP_NUMOPCODES; i++) if (!strcasecmp(arp_opcodes[i], args->arp_opcode)) break; - if (i == NUMOPCODES) + if (i == ARP_NUMOPCODES) xtables_error(PARAMETER_PROBLEM, "Problem with specified opcode"); cs->arp.arp.arpop = htons(i+1); @@ -700,22 +572,301 @@ static void nft_arp_init_cs(struct iptables_command_state *cs) cs->arp.arp.arhln_mask = 255; cs->arp.arp.arhrd = htons(ARPHRD_ETHER); cs->arp.arp.arhrd_mask = 65535; + cs->arp.arp.arpop_mask = 65535; + cs->arp.arp.arpro_mask = 65535; +} + +static int +nft_arp_add_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose, + bool append, int rulenum) +{ + unsigned int i, j; + int ret = 1; + + for (i = 0; i < args->s.naddrs; i++) { + cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr; + cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr; + for (j = 0; j < args->d.naddrs; j++) { + cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr; + cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr; + if (append) { + ret = nft_cmd_rule_append(h, chain, table, cs, + verbose); + } else { + ret = nft_cmd_rule_insert(h, chain, table, cs, + rulenum, verbose); + } + } + } + + return ret; +} + +static int +nft_arp_delete_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose) +{ + unsigned int i, j; + int ret = 1; + + for (i = 0; i < args->s.naddrs; i++) { + cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr; + cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr; + for (j = 0; j < args->d.naddrs; j++) { + cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr; + cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr; + ret = nft_cmd_rule_delete(h, chain, table, cs, verbose); + } + } + + return ret; +} + +static int +nft_arp_check_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose) +{ + unsigned int i, j; + int ret = 1; + + for (i = 0; i < args->s.naddrs; i++) { + cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr; + cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr; + for (j = 0; j < args->d.naddrs; j++) { + cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr; + cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr; + ret = nft_cmd_rule_check(h, chain, table, cs, verbose); + } + } + + return ret; +} + +static int +nft_arp_replace_entry(struct nft_handle *h, + const char *chain, const char *table, + struct iptables_command_state *cs, + struct xtables_args *args, bool verbose, + int rulenum) +{ + cs->arp.arp.src.s_addr = args->s.addr.v4->s_addr; + cs->arp.arp.tgt.s_addr = args->d.addr.v4->s_addr; + cs->arp.arp.smsk.s_addr = args->s.mask.v4->s_addr; + cs->arp.arp.tmsk.s_addr = args->d.mask.v4->s_addr; + + return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose); +} + +static void nft_arp_xlate_mac_and_mask(const struct arpt_devaddr_info *devaddr, + const char *addr, + bool invert, + struct xt_xlate *xl) +{ + unsigned int i; + + for (i = 0; i < 6; ++i) { + if (devaddr->mask[i]) + break; + } + + if (i == 6) + return; + + xt_xlate_add(xl, "arp %s ether ", addr); + if (invert) + xt_xlate_add(xl, "!= "); + + xt_xlate_add(xl, "%02x", (uint8_t)devaddr->addr[0]); + for (i = 1; i < 6; ++i) + xt_xlate_add(xl, ":%02x", (uint8_t)devaddr->addr[i]); + + for (i = 0; i < 6; ++i) { + int j; + + if ((uint8_t)devaddr->mask[i] == 0xff) + continue; + + xt_xlate_add(xl, "/%02x", (uint8_t)devaddr->mask[0]); + + for (j = 1; j < 6; ++j) + xt_xlate_add(xl, ":%02x", (uint8_t)devaddr->mask[j]); + return; + } +} + +static void nft_arp_xlate16(uint16_t v, uint16_t m, const char *what, + bool hex, bool inverse, + struct xt_xlate *xl) +{ + const char *fmt = hex ? "0x%x " : "%d "; + + if (m) { + xt_xlate_add(xl, "arp %s ", what); + if (inverse) + xt_xlate_add(xl, " !="); + if (m != 0xffff) { + xt_xlate_add(xl, "& "); + xt_xlate_add(xl, fmt, ntohs(m));; + + } + xt_xlate_add(xl, fmt, ntohs(v)); + } +} + +static void nft_arp_xlate_ipv4_addr(const char *what, const struct in_addr *addr, + const struct in_addr *mask, + bool inv, struct xt_xlate *xl) +{ + char mbuf[INET_ADDRSTRLEN], abuf[INET_ADDRSTRLEN]; + const char *op = inv ? "!= " : ""; + int cidr; + + if (!inv && !addr->s_addr && !mask->s_addr) + return; + + inet_ntop(AF_INET, addr, abuf, sizeof(abuf)); + + cidr = xtables_ipmask_to_cidr(mask); + switch (cidr) { + case -1: + xt_xlate_add(xl, "arp %s ip & %s %s %s ", what, + inet_ntop(AF_INET, mask, mbuf, sizeof(mbuf)), + inv ? "!=" : "==", abuf); + break; + case 32: + xt_xlate_add(xl, "arp %s ip %s%s ", what, op, abuf); + break; + default: + xt_xlate_add(xl, "arp %s ip %s%s/%d ", what, op, abuf, cidr); + } +} + +static int nft_arp_xlate(const struct iptables_command_state *cs, + struct xt_xlate *xl) +{ + const struct arpt_entry *fw = &cs->arp; + int ret; + + xlate_ifname(xl, "iifname", fw->arp.iniface, + fw->arp.invflags & IPT_INV_VIA_IN); + xlate_ifname(xl, "oifname", fw->arp.outiface, + fw->arp.invflags & IPT_INV_VIA_OUT); + + if (fw->arp.arhrd || + fw->arp.arhrd_mask != 0xffff || + fw->arp.invflags & IPT_INV_ARPHRD) + nft_arp_xlate16(fw->arp.arhrd, fw->arp.arhrd_mask, + "htype", false, + fw->arp.invflags & IPT_INV_ARPHRD, xl); + + if (fw->arp.arhln_mask != 255 || fw->arp.arhln || + fw->arp.invflags & IPT_INV_ARPHLN) { + xt_xlate_add(xl, "arp hlen "); + if (fw->arp.invflags & IPT_INV_ARPHLN) + xt_xlate_add(xl, " !="); + if (fw->arp.arhln_mask != 255) + xt_xlate_add(xl, "& %d ", fw->arp.arhln_mask); + xt_xlate_add(xl, "%d ", fw->arp.arhln); + } + + /* added implicitly by arptables-nft */ + xt_xlate_add(xl, "arp plen %d", 4); + + if (fw->arp.arpop_mask != 65535 || + fw->arp.arpop != 0 || + fw->arp.invflags & IPT_INV_ARPOP) + nft_arp_xlate16(fw->arp.arpop, fw->arp.arpop_mask, + "operation", false, + fw->arp.invflags & IPT_INV_ARPOP, xl); + + if (fw->arp.arpro_mask != 65535 || + fw->arp.invflags & IPT_INV_PROTO || + fw->arp.arpro) + nft_arp_xlate16(fw->arp.arpro, fw->arp.arpro_mask, + "ptype", true, + fw->arp.invflags & IPT_INV_PROTO, xl); + + if (fw->arp.smsk.s_addr != 0L) + nft_arp_xlate_ipv4_addr("saddr", &fw->arp.src, &fw->arp.smsk, + fw->arp.invflags & IPT_INV_SRCIP, xl); + + if (fw->arp.tmsk.s_addr != 0L) + nft_arp_xlate_ipv4_addr("daddr", &fw->arp.tgt, &fw->arp.tmsk, + fw->arp.invflags & IPT_INV_DSTIP, xl); + + nft_arp_xlate_mac_and_mask(&fw->arp.src_devaddr, "saddr", + fw->arp.invflags & IPT_INV_SRCDEVADDR, xl); + nft_arp_xlate_mac_and_mask(&fw->arp.tgt_devaddr, "daddr", + fw->arp.invflags & IPT_INV_TGTDEVADDR, xl); + + ret = xlate_matches(cs, xl); + if (!ret) + return ret; + + /* Always add counters per rule, as in iptables */ + xt_xlate_add(xl, "counter"); + return xlate_action(cs, false, xl); +} + +static const char *nft_arp_option_name(int option) +{ + switch (option) { + default: return ip46t_option_name(option); + /* different name than iptables */ + case OPT_SOURCE: return "--source-ip"; + case OPT_DESTINATION: return "--destination-ip"; + /* arptables specific ones */ + case OPT_S_MAC: return "--source-mac"; + case OPT_D_MAC: return "--destination-mac"; + case OPT_H_LENGTH: return "--h-length"; + case OPT_OPCODE: return "--opcode"; + case OPT_H_TYPE: return "--h-type"; + case OPT_P_TYPE: return "--proto-type"; + } +} + +static int nft_arp_option_invert(int option) +{ + switch (option) { + case OPT_S_MAC: return IPT_INV_SRCDEVADDR; + case OPT_D_MAC: return IPT_INV_TGTDEVADDR; + case OPT_H_LENGTH: return IPT_INV_ARPHLN; + case OPT_OPCODE: return IPT_INV_ARPOP; + case OPT_H_TYPE: return IPT_INV_ARPHRD; + case OPT_P_TYPE: return IPT_INV_PROTO; + default: return ip46t_option_invert(option); + } } struct nft_family_ops nft_family_ops_arp = { .add = nft_arp_add, .is_same = nft_arp_is_same, .print_payload = NULL, - .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_rule = nft_arp_print_rule, .save_rule = nft_arp_save_rule, .save_chain = nft_arp_save_chain, - .post_parse = nft_arp_post_parse, + .rule_parse = &nft_ruleparse_ops_arp, + .cmd_parse = { + .post_parse = nft_arp_post_parse, + .option_name = nft_arp_option_name, + .option_invert = nft_arp_option_invert, + .command_default = command_default, + .print_help = xtables_printhelp, + }, .rule_to_cs = nft_rule_to_iptables_command_state, .init_cs = nft_arp_init_cs, - .clear_cs = nft_clear_iptables_command_state, - .parse_target = nft_ipv46_parse_target, + .clear_cs = xtables_clear_iptables_command_state, + .xlate = nft_arp_xlate, + .add_entry = nft_arp_add_entry, + .delete_entry = nft_arp_delete_entry, + .check_entry = nft_arp_check_entry, + .replace_entry = nft_arp_replace_entry, }; |