diff options
author | Florian Westphal <fw@strlen.de> | 2023-11-07 12:15:38 +0100 |
---|---|---|
committer | Phil Sutter <phil@nwl.cc> | 2023-11-07 23:40:14 +0100 |
commit | 5b7324e0675e332ae186e1bd6978aa320f628086 (patch) | |
tree | e258f128ccfe5637759cbce7031b6c491f8492f1 /iptables | |
parent | ab2d5f8c7bbeea49d9dddaaf3d2fac8c7fdeae56 (diff) |
nft-arp: add arptables-translate
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <phil@nwl.cc>
Diffstat (limited to 'iptables')
-rw-r--r-- | iptables/nft-arp.c | 153 | ||||
-rw-r--r-- | iptables/xtables-multi.h | 1 | ||||
-rw-r--r-- | iptables/xtables-nft-multi.c | 1 | ||||
-rw-r--r-- | iptables/xtables-translate.c | 35 |
4 files changed, 189 insertions, 1 deletions
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c index b3c8dfa4..8521cc4f 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> @@ -663,6 +664,157 @@ nft_arp_replace_entry(struct nft_handle *h, 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); +} + struct nft_family_ops nft_family_ops_arp = { .add = nft_arp_add, .is_same = nft_arp_is_same, @@ -678,6 +830,7 @@ struct nft_family_ops nft_family_ops_arp = { .rule_to_cs = nft_rule_to_iptables_command_state, .init_cs = nft_arp_init_cs, .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, diff --git a/iptables/xtables-multi.h b/iptables/xtables-multi.h index 833c11a2..760d3e4f 100644 --- a/iptables/xtables-multi.h +++ b/iptables/xtables-multi.h @@ -9,6 +9,7 @@ extern int xtables_ip4_restore_main(int, char **); extern int xtables_ip6_main(int, char **); extern int xtables_ip6_save_main(int, char **); extern int xtables_ip6_restore_main(int, char **); +extern int xtables_arp_xlate_main(int, char **); extern int xtables_ip4_xlate_main(int, char **); extern int xtables_ip6_xlate_main(int, char **); extern int xtables_eb_xlate_main(int, char **); diff --git a/iptables/xtables-nft-multi.c b/iptables/xtables-nft-multi.c index e2b7c641..48265d8e 100644 --- a/iptables/xtables-nft-multi.c +++ b/iptables/xtables-nft-multi.c @@ -30,6 +30,7 @@ static const struct subcommand multi_subcommands[] = { {"ip6tables-translate", xtables_ip6_xlate_main}, {"iptables-restore-translate", xtables_ip4_xlate_restore_main}, {"ip6tables-restore-translate", xtables_ip6_xlate_restore_main}, + {"arptables-translate", xtables_arp_xlate_main}, {"arptables", xtables_arp_main}, {"arptables-nft", xtables_arp_main}, {"arptables-restore", xtables_arp_restore_main}, diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index 88e0a6b6..ea9dce20 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -140,6 +140,7 @@ bool xlate_find_match(const struct iptables_command_state *cs, const char *p_nam } const char *family2str[] = { + [NFPROTO_ARP] = "arp", [NFPROTO_IPV4] = "ip", [NFPROTO_IPV6] = "ip6", }; @@ -196,6 +197,15 @@ static int xlate(struct nft_handle *h, struct xt_cmd_parse *p, for (i = 0; i < args->s.naddrs; i++) { switch (h->family) { + case NFPROTO_ARP: + 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 = cb(h, p, cs, append); + } + break; case AF_INET: cs->fw.ip.src.s_addr = args->s.addr.v4[i].s_addr; cs->fw.ip.smsk.s_addr = args->s.mask.v4[i].s_addr; @@ -475,7 +485,24 @@ static int xtables_xlate_main_common(struct nft_handle *h, xtables_globals.program_name = progname; xtables_globals.compat_rev = dummy_compat_rev; - ret = xtables_init_all(&xtables_globals, family); + + switch (family) { + case NFPROTO_IPV4: + ret = xtables_init_all(&xtables_globals, family); + break; + case NFPROTO_IPV6: + ret = xtables_init_all(&xtables_globals, family); + break; + case NFPROTO_ARP: + arptables_globals.program_name = progname; + arptables_globals.compat_rev = dummy_compat_rev; + ret = xtables_init_all(&arptables_globals, family); + break; + default: + ret = -1; + break; + } + if (ret < 0) { fprintf(stderr, "%s/%s Failed to initialize xtables\n", xtables_globals.program_name, @@ -590,6 +617,12 @@ static int xtables_restore_xlate_main(int family, const char *progname, exit(0); } +int xtables_arp_xlate_main(int argc, char *argv[]) +{ + return xtables_xlate_main(NFPROTO_ARP, "arptables-translate", + argc, argv); +} + int xtables_ip4_xlate_main(int argc, char *argv[]) { return xtables_xlate_main(NFPROTO_IPV4, "iptables-translate", |