]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
nft-arp: add arptables-translate
authorFlorian Westphal <fw@strlen.de>
Tue, 7 Nov 2023 11:15:38 +0000 (12:15 +0100)
committerPhil Sutter <phil@nwl.cc>
Tue, 7 Nov 2023 22:40:14 +0000 (23:40 +0100)
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <phil@nwl.cc>
extensions/libarpt_mangle.c
iptables/nft-arp.c
iptables/xtables-multi.h
iptables/xtables-nft-multi.c
iptables/xtables-translate.c

index a846e97ec8f27d67a11aff4e14c2ef809ebb0662..364c9ce755b97d0a22f15b9a2187672dacd3cfea 100644 (file)
@@ -170,6 +170,52 @@ static void arpmangle_save(const void *ip, const struct xt_entry_target *target)
        arpmangle_print(ip, target, 0);
 }
 
+static void print_devaddr_xlate(const char *macaddress, struct xt_xlate *xl)
+{
+       unsigned int i;
+
+       xt_xlate_add(xl, "%02x", macaddress[0]);
+       for (i = 1; i < ETH_ALEN; ++i)
+               xt_xlate_add(xl, ":%02x", macaddress[i]);
+}
+
+static int arpmangle_xlate(struct xt_xlate *xl,
+                        const struct xt_xlate_tg_params *params)
+{
+       const struct arpt_mangle *m = (const void *)params->target->data;
+
+       if (m->flags & ARPT_MANGLE_SIP)
+               xt_xlate_add(xl, "arp saddr ip set %s ",
+                            xtables_ipaddr_to_numeric(&m->u_s.src_ip));
+
+       if (m->flags & ARPT_MANGLE_SDEV) {
+               xt_xlate_add(xl, "arp %caddr ether set ", 's');
+               print_devaddr_xlate(m->src_devaddr, xl);
+       }
+
+       if (m->flags & ARPT_MANGLE_TIP)
+               xt_xlate_add(xl, "arp daddr ip set %s ",
+                            xtables_ipaddr_to_numeric(&m->u_t.tgt_ip));
+
+       if (m->flags & ARPT_MANGLE_TDEV) {
+               xt_xlate_add(xl, "arp %caddr ether set ", 'd');
+               print_devaddr_xlate(m->tgt_devaddr, xl);
+       }
+
+       switch (m->target) {
+       case NF_ACCEPT:
+               xt_xlate_add(xl, "accept");
+               break;
+       case NF_DROP:
+               xt_xlate_add(xl, "drop");
+               break;
+       default:
+               break;
+       }
+
+       return 1;
+}
+
 static struct xtables_target arpmangle_target = {
        .name           = "mangle",
        .revision       = 0,
@@ -184,6 +230,7 @@ static struct xtables_target arpmangle_target = {
        .print          = arpmangle_print,
        .save           = arpmangle_save,
        .extra_opts     = arpmangle_opts,
+       .xlate          = arpmangle_xlate,
 };
 
 void _init(void)
index b3c8dfa453d95354bf973e4eac2e01b00a2344f5..8521cc4f15c1dc3e19f9d7273700f400e450fee2 100644 (file)
@@ -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,
index 833c11a2ac9140e75c2c69ef3f2090b9505dde51..760d3e4f2b6eb69ff4a9af72e20221f2ab33eb23 100644 (file)
@@ -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 **);
index e2b7c641f85dd958763a3a277d2230edb51f33bf..48265d8e0afa6a64c26354ddaf03648c29dab45b 100644 (file)
@@ -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},
index 88e0a6b6394948da0fb9175b48405b4ff69630ab..ea9dce204dfc94575b06ac3b6566df32d3c3f2b6 100644 (file)
@@ -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",