]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
extensions: libebt_arp: Use guided option parser
authorPhil Sutter <phil@nwl.cc>
Tue, 28 Nov 2023 13:16:03 +0000 (14:16 +0100)
committerPhil Sutter <phil@nwl.cc>
Wed, 10 Jan 2024 15:07:31 +0000 (16:07 +0100)
extensions/libebt_arp.c
extensions/libebt_arp.t

index 63a953d4637da9f6b5f7133c1fef239bb4d47b03..b6d691d8c0b1002718620ee6daa46d2edeebc8d7 100644 (file)
@@ -10,7 +10,6 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <getopt.h>
 #include <xtables.h>
 #include <netinet/ether.h>
 
 #include "iptables/nft.h"
 #include "iptables/nft-bridge.h"
 
-#define ARP_OPCODE '1'
-#define ARP_HTYPE  '2'
-#define ARP_PTYPE  '3'
-#define ARP_IP_S   '4'
-#define ARP_IP_D   '5'
-#define ARP_MAC_S  '6'
-#define ARP_MAC_D  '7'
-#define ARP_GRAT   '8'
+/* values must correspond with EBT_ARP_* bit positions */
+enum {
+       O_OPCODE = 0,
+       O_HTYPE,
+       O_PTYPE,
+       O_SRC_IP,
+       O_DST_IP,
+       O_SRC_MAC,
+       O_DST_MAC,
+       O_GRAT,
+};
 
-static const struct option brarp_opts[] = {
-       { "arp-opcode"    , required_argument, 0, ARP_OPCODE },
-       { "arp-op"        , required_argument, 0, ARP_OPCODE },
-       { "arp-htype"     , required_argument, 0, ARP_HTYPE  },
-       { "arp-ptype"     , required_argument, 0, ARP_PTYPE  },
-       { "arp-ip-src"    , required_argument, 0, ARP_IP_S   },
-       { "arp-ip-dst"    , required_argument, 0, ARP_IP_D   },
-       { "arp-mac-src"   , required_argument, 0, ARP_MAC_S  },
-       { "arp-mac-dst"   , required_argument, 0, ARP_MAC_D  },
-       { "arp-gratuitous",       no_argument, 0, ARP_GRAT   },
-       XT_GETOPT_TABLEEND,
+static const struct xt_option_entry brarp_opts[] = {
+#define ENTRY(n, i, t) { .name = n, .id = i, .type = t, .flags = XTOPT_INVERT }
+       ENTRY("arp-opcode",     O_OPCODE,  XTTYPE_STRING),
+       ENTRY("arp-op",         O_OPCODE,  XTTYPE_STRING),
+       ENTRY("arp-htype",      O_HTYPE,   XTTYPE_STRING),
+       ENTRY("arp-ptype",      O_PTYPE,   XTTYPE_STRING),
+       ENTRY("arp-ip-src",     O_SRC_IP,  XTTYPE_HOSTMASK),
+       ENTRY("arp-ip-dst",     O_DST_IP,  XTTYPE_HOSTMASK),
+       ENTRY("arp-mac-src",    O_SRC_MAC, XTTYPE_ETHERMACMASK),
+       ENTRY("arp-mac-dst",    O_DST_MAC, XTTYPE_ETHERMACMASK),
+       ENTRY("arp-gratuitous", O_GRAT,    XTTYPE_NONE),
+#undef ENTRY
+       XTOPT_TABLEEND
 };
 
 /* a few names */
@@ -78,137 +82,74 @@ static void brarp_print_help(void)
 " protocol type string: see "XT_PATH_ETHERTYPES"\n");
 }
 
-#define OPT_OPCODE 0x01
-#define OPT_HTYPE  0x02
-#define OPT_PTYPE  0x04
-#define OPT_IP_S   0x08
-#define OPT_IP_D   0x10
-#define OPT_MAC_S  0x20
-#define OPT_MAC_D  0x40
-#define OPT_GRAT   0x80
-
-static int
-brarp_parse(int c, char **argv, int invert, unsigned int *flags,
-           const void *entry, struct xt_entry_match **match)
+static void brarp_parse(struct xt_option_call *cb)
 {
-       struct ebt_arp_info *arpinfo = (struct ebt_arp_info *)(*match)->data;
-       struct in_addr *ipaddr, ipmask;
+       struct ebt_arp_info *arpinfo = cb->data;
+       struct xt_ethertypeent *ent;
        long int i;
        char *end;
-       unsigned char *maddr;
-       unsigned char *mmask;
-       unsigned int ipnr;
 
-       switch (c) {
-       case ARP_OPCODE:
-               EBT_CHECK_OPTION(flags, OPT_OPCODE);
-               if (invert)
-                       arpinfo->invflags |= EBT_ARP_OPCODE;
-               i = strtol(optarg, &end, 10);
+
+       xtables_option_parse(cb);
+
+       arpinfo->bitmask |= 1 << cb->entry->id;
+       if (cb->invert)
+               arpinfo->invflags |= 1 << cb->entry->id;
+
+       switch (cb->entry->id) {
+       case O_OPCODE:
+               i = strtol(cb->arg, &end, 10);
                if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
                        for (i = 0; i < ARRAY_SIZE(opcodes); i++)
-                               if (!strcasecmp(opcodes[i], optarg))
+                               if (!strcasecmp(opcodes[i], cb->arg))
                                        break;
                        if (i == ARRAY_SIZE(opcodes))
-                               xtables_error(PARAMETER_PROBLEM, "Problem with specified ARP opcode");
+                               xtables_error(PARAMETER_PROBLEM,
+                                             "Problem with specified ARP opcode");
                        i++;
                }
                arpinfo->opcode = htons(i);
-               arpinfo->bitmask |= EBT_ARP_OPCODE;
                break;
-
-       case ARP_HTYPE:
-               EBT_CHECK_OPTION(flags, OPT_HTYPE);
-               if (invert)
-                       arpinfo->invflags |= EBT_ARP_HTYPE;
-               i = strtol(optarg, &end, 10);
+       case O_HTYPE:
+               i = strtol(cb->arg, &end, 10);
                if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
-                       if (!strcasecmp("Ethernet", argv[optind - 1]))
+                       if (!strcasecmp("Ethernet", cb->arg))
                                i = 1;
                        else
-                               xtables_error(PARAMETER_PROBLEM, "Problem with specified ARP hardware type");
+                               xtables_error(PARAMETER_PROBLEM,
+                                             "Problem with specified ARP hardware type");
                }
                arpinfo->htype = htons(i);
-               arpinfo->bitmask |= EBT_ARP_HTYPE;
                break;
-       case ARP_PTYPE: {
-               uint16_t proto;
-
-               EBT_CHECK_OPTION(flags, OPT_PTYPE);
-               if (invert)
-                       arpinfo->invflags |= EBT_ARP_PTYPE;
-
-               i = strtol(optarg, &end, 16);
-               if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
-                       struct xt_ethertypeent *ent;
-
-                       ent = xtables_getethertypebyname(argv[optind - 1]);
-                       if (!ent)
-                               xtables_error(PARAMETER_PROBLEM, "Problem with specified ARP "
-                                                                "protocol type");
-                       proto = ent->e_ethertype;
-
-               } else
-                       proto = i;
-               arpinfo->ptype = htons(proto);
-               arpinfo->bitmask |= EBT_ARP_PTYPE;
-               break;
-       }
-
-       case ARP_IP_S:
-       case ARP_IP_D:
-               xtables_ipparse_any(optarg, &ipaddr, &ipmask, &ipnr);
-               if (c == ARP_IP_S) {
-                       EBT_CHECK_OPTION(flags, OPT_IP_S);
-                       arpinfo->saddr = ipaddr->s_addr;
-                       arpinfo->smsk = ipmask.s_addr;
-                       arpinfo->bitmask |= EBT_ARP_SRC_IP;
-               } else {
-                       EBT_CHECK_OPTION(flags, OPT_IP_D);
-                       arpinfo->daddr = ipaddr->s_addr;
-                       arpinfo->dmsk = ipmask.s_addr;
-                       arpinfo->bitmask |= EBT_ARP_DST_IP;
-               }
-               free(ipaddr);
-               if (invert) {
-                       if (c == ARP_IP_S)
-                               arpinfo->invflags |= EBT_ARP_SRC_IP;
-                       else
-                               arpinfo->invflags |= EBT_ARP_DST_IP;
+       case O_PTYPE:
+               i = strtol(cb->arg, &end, 16);
+               if (i >= 0 && i < (0x1 << 16) && *end == '\0') {
+                       arpinfo->ptype = htons(i);
+                       break;
                }
+               ent = xtables_getethertypebyname(cb->arg);
+               if (!ent)
+                       xtables_error(PARAMETER_PROBLEM,
+                                     "Problem with specified ARP protocol type");
+               arpinfo->ptype = htons(ent->e_ethertype);
                break;
-       case ARP_MAC_S:
-       case ARP_MAC_D:
-               if (c == ARP_MAC_S) {
-                       EBT_CHECK_OPTION(flags, OPT_MAC_S);
-                       maddr = arpinfo->smaddr;
-                       mmask = arpinfo->smmsk;
-                       arpinfo->bitmask |= EBT_ARP_SRC_MAC;
-               } else {
-                       EBT_CHECK_OPTION(flags, OPT_MAC_D);
-                       maddr = arpinfo->dmaddr;
-                       mmask = arpinfo->dmmsk;
-                       arpinfo->bitmask |= EBT_ARP_DST_MAC;
-               }
-               if (invert) {
-                       if (c == ARP_MAC_S)
-                               arpinfo->invflags |= EBT_ARP_SRC_MAC;
-                       else
-                               arpinfo->invflags |= EBT_ARP_DST_MAC;
-               }
-               if (xtables_parse_mac_and_mask(optarg, maddr, mmask))
-                       xtables_error(PARAMETER_PROBLEM, "Problem with ARP MAC address argument");
+       case O_SRC_IP:
+               arpinfo->saddr = cb->val.haddr.ip & cb->val.hmask.ip;
+               arpinfo->smsk = cb->val.hmask.ip;
+               break;
+       case O_DST_IP:
+               arpinfo->daddr = cb->val.haddr.ip & cb->val.hmask.ip;
+               arpinfo->dmsk = cb->val.hmask.ip;
+               break;
+       case O_SRC_MAC:
+               memcpy(arpinfo->smaddr, cb->val.ethermac, ETH_ALEN);
+               memcpy(arpinfo->smmsk, cb->val.ethermacmask, ETH_ALEN);
                break;
-       case ARP_GRAT:
-               EBT_CHECK_OPTION(flags, OPT_GRAT);
-               arpinfo->bitmask |= EBT_ARP_GRAT;
-               if (invert)
-                       arpinfo->invflags |= EBT_ARP_GRAT;
+       case O_DST_MAC:
+               memcpy(arpinfo->dmaddr, cb->val.ethermac, ETH_ALEN);
+               memcpy(arpinfo->dmmsk, cb->val.ethermacmask, ETH_ALEN);
                break;
-       default:
-               return 0;
        }
-       return 1;
 }
 
 static void brarp_print(const void *ip, const struct xt_entry_match *match, int numeric)
@@ -279,9 +220,9 @@ static struct xtables_match brarp_match = {
        .size           = XT_ALIGN(sizeof(struct ebt_arp_info)),
        .userspacesize  = XT_ALIGN(sizeof(struct ebt_arp_info)),
        .help           = brarp_print_help,
-       .parse          = brarp_parse,
+       .x6_parse       = brarp_parse,
        .print          = brarp_print,
-       .extra_opts     = brarp_opts,
+       .x6_options     = brarp_opts,
 };
 
 void _init(void)
index 96fbce906107c76527864cda52d4d465072e3601..c8e874e83c513d1ee8645cb98d70d50231707a21 100644 (file)
@@ -1,7 +1,11 @@
 :INPUT,FORWARD,OUTPUT
 -p ARP --arp-op Request;=;OK
+-p ARP --arp-op ! Request;=;OK
+-p ARP --arp-htype Ethernet;-p ARP --arp-htype 1;OK
+-p ARP --arp-htype 1;=;OK
 -p ARP --arp-htype ! 1;=;OK
 -p ARP --arp-ptype 0x2;=;OK
+-p ARP --arp-ptype ! 0x2;=;OK
 -p ARP --arp-ip-src 1.2.3.4;=;OK
 -p ARP ! --arp-ip-dst 1.2.3.4;-p ARP --arp-ip-dst ! 1.2.3.4 -j CONTINUE;OK
 -p ARP --arp-ip-src ! 0.0.0.0;=;OK
@@ -10,6 +14,9 @@
 -p ARP --arp-ip-src ! 1.2.3.4/255.255.255.0;-p ARP --arp-ip-src ! 1.2.3.0/24;OK
 -p ARP --arp-ip-src ! 1.2.3.4/255.0.255.255;-p ARP --arp-ip-src ! 1.0.3.4/255.0.255.255;OK
 -p ARP --arp-mac-src 00:de:ad:be:ef:00;=;OK
+-p ARP --arp-mac-src ! 00:de:ad:be:ef:00;=;OK
 -p ARP --arp-mac-dst de:ad:be:ef:00:00/ff:ff:ff:ff:00:00;=;OK
+-p ARP --arp-mac-dst ! de:ad:be:ef:00:00/ff:ff:ff:ff:00:00;=;OK
 -p ARP --arp-gratuitous;=;OK
+-p ARP ! --arp-gratuitous;=;OK
 --arp-htype 1;=;FAIL