]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
libxt_ipvs: use guided option parser
authorJan Engelhardt <jengelh@medozas.de>
Sat, 7 May 2011 11:03:06 +0000 (13:03 +0200)
committerJan Engelhardt <jengelh@medozas.de>
Sun, 8 May 2011 22:52:53 +0000 (00:52 +0200)
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
extensions/libxt_ipvs.c

index 89303a11511fb15a29ec797474bdc42f685dfc5b..88d235f6afeb8f809c1a9ee0dcbbc7b45a859b82 100644 (file)
@@ -5,31 +5,43 @@
  *
  * Author: Hannes Eder <heder@google.com>
  */
-#include <sys/types.h>
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <getopt.h>
-#include <netdb.h>
 #include <stdbool.h>
-#include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <xtables.h>
 #include <linux/ip_vs.h>
 #include <linux/netfilter/xt_ipvs.h>
 
-static const struct option ipvs_mt_opts[] = {
-       { .name = "ipvs",     .has_arg = false, .val = '0' },
-       { .name = "vproto",   .has_arg = true,  .val = '1' },
-       { .name = "vaddr",    .has_arg = true,  .val = '2' },
-       { .name = "vport",    .has_arg = true,  .val = '3' },
-       { .name = "vdir",     .has_arg = true,  .val = '4' },
-       { .name = "vmethod",  .has_arg = true,  .val = '5' },
-       { .name = "vportctl", .has_arg = true,  .val = '6' },
-       XT_GETOPT_TABLEEND,
+enum {
+       /* For xt_ipvs: make sure this matches up with %XT_IPVS_*'s order */
+       O_IPVS = 0,
+       O_VPROTO,
+       O_VADDR,
+       O_VPORT,
+       O_VDIR,
+       O_VMETHOD,
+       O_VPORTCTL,
 };
 
+#define s struct xt_ipvs_mtinfo
+static const struct xt_option_entry ipvs_mt_opts[] = {
+       {.name = "ipvs", .id = O_IPVS, .type = XTTYPE_NONE,
+        .flags = XTOPT_INVERT},
+       {.name = "vproto", .id = O_VPROTO, .type = XTTYPE_STRING,
+        .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, l4proto)},
+       {.name = "vaddr", .id = O_VADDR, .type = XTTYPE_HOSTMASK,
+        .flags = XTOPT_INVERT},
+       {.name = "vport", .id = O_VPORT, .type = XTTYPE_PORT,
+        .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, vport)},
+       {.name = "vdir", .id = O_VDIR, .type = XTTYPE_STRING},
+       {.name = "vmethod", .id = O_VMETHOD, .type = XTTYPE_STRING,
+        .flags = XTOPT_INVERT},
+       {.name = "vportctl", .id = O_VPORTCTL, .type = XTTYPE_PORT,
+        .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, vportctl)},
+       XTOPT_TABLEEND,
+};
+#undef s
+
 static void ipvs_mt_help(void)
 {
        printf(
@@ -49,152 +61,62 @@ static void ipvs_mt_help(void)
                );
 }
 
-static void ipvs_mt_parse_addr_and_mask(const char *arg,
-                                       union nf_inet_addr *address,
-                                       union nf_inet_addr *mask,
-                                       unsigned int family)
-{
-       struct in_addr *addr = NULL;
-       struct in6_addr *addr6 = NULL;
-       unsigned int naddrs = 0;
-
-       if (family == NFPROTO_IPV4) {
-               xtables_ipparse_any(arg, &addr, &mask->in, &naddrs);
-               if (naddrs > 1)
-                       xtables_error(PARAMETER_PROBLEM,
-                                     "multiple IP addresses not allowed");
-               if (naddrs == 1)
-                       memcpy(&address->in, addr, sizeof(*addr));
-       } else if (family == NFPROTO_IPV6) {
-               xtables_ip6parse_any(arg, &addr6, &mask->in6, &naddrs);
-               if (naddrs > 1)
-                       xtables_error(PARAMETER_PROBLEM,
-                                     "multiple IP addresses not allowed");
-               if (naddrs == 1)
-                       memcpy(&address->in6, addr6, sizeof(*addr6));
-       } else {
-               /* Hu? */
-               assert(false);
-       }
-}
-
-/* Function which parses command options; returns true if it ate an option */
-static int ipvs_mt_parse(int c, char **argv, int invert, unsigned int *flags,
-                        const void *entry, struct xt_entry_match **match,
-                        unsigned int family)
+static void ipvs_mt_parse(struct xt_option_call *cb)
 {
-       struct xt_ipvs_mtinfo *data = (void *)(*match)->data;
-       char *p = NULL;
-       uint8_t op = 0;
-
-       if ('0' <= c && c <= '6') {
-               static const int ops[] = {
-                       XT_IPVS_IPVS_PROPERTY,
-                       XT_IPVS_PROTO,
-                       XT_IPVS_VADDR,
-                       XT_IPVS_VPORT,
-                       XT_IPVS_DIR,
-                       XT_IPVS_METHOD,
-                       XT_IPVS_VPORTCTL
-               };
-               op = ops[c - '0'];
-       } else
-               return 0;
-
-       if (*flags & op & XT_IPVS_ONCE_MASK)
-               goto multiple_use;
-
-       switch (c) {
-       case '0': /* --ipvs */
-               /* Nothing to do here. */
-               break;
+       struct xt_ipvs_mtinfo *data = cb->data;
 
-       case '1': /* --vproto */
-               /* Canonicalize into lower case */
-               for (p = optarg; *p != '\0'; ++p)
-                       *p = tolower(*p);
-
-               data->l4proto = xtables_parse_protocol(optarg);
+       xtables_option_parse(cb);
+       switch (cb->entry->id) {
+       case O_VPROTO:
+               data->l4proto = cb->val.protocol;
                break;
-
-       case '2': /* --vaddr */
-               ipvs_mt_parse_addr_and_mask(optarg, &data->vaddr,
-                                           &data->vmask, family);
+       case O_VADDR:
+               memcpy(&data->vaddr, &cb->val.haddr, sizeof(cb->val.haddr));
+               memcpy(&data->vmask, &cb->val.hmask, sizeof(cb->val.hmask));
                break;
-
-       case '3': /* --vport */
-               data->vport = htons(xtables_parse_port(optarg, "tcp"));
-               break;
-
-       case '4': /* --vdir */
-               xtables_param_act(XTF_NO_INVERT, "ipvs", "--vdir", invert);
-               if (strcasecmp(optarg, "ORIGINAL") == 0) {
+       case O_VDIR:
+               if (strcasecmp(cb->arg, "ORIGINAL") == 0) {
                        data->bitmask |= XT_IPVS_DIR;
                        data->invert   &= ~XT_IPVS_DIR;
-               } else if (strcasecmp(optarg, "REPLY") == 0) {
+               } else if (strcasecmp(cb->arg, "REPLY") == 0) {
                        data->bitmask |= XT_IPVS_DIR;
                        data->invert  |= XT_IPVS_DIR;
                } else {
                        xtables_param_act(XTF_BAD_VALUE,
-                                         "ipvs", "--vdir", optarg);
+                                         "ipvs", "--vdir", cb->arg);
                }
                break;
-
-       case '5': /* --vmethod */
-               if (strcasecmp(optarg, "GATE") == 0)
+       case O_VMETHOD:
+               if (strcasecmp(cb->arg, "GATE") == 0)
                        data->fwd_method = IP_VS_CONN_F_DROUTE;
-               else if (strcasecmp(optarg, "IPIP") == 0)
+               else if (strcasecmp(cb->arg, "IPIP") == 0)
                        data->fwd_method = IP_VS_CONN_F_TUNNEL;
-               else if (strcasecmp(optarg, "MASQ") == 0)
+               else if (strcasecmp(cb->arg, "MASQ") == 0)
                        data->fwd_method = IP_VS_CONN_F_MASQ;
                else
                        xtables_param_act(XTF_BAD_VALUE,
-                                         "ipvs", "--vmethod", optarg);
-               break;
-
-       case '6': /* --vportctl */
-               data->vportctl = htons(xtables_parse_port(optarg, "tcp"));
+                                         "ipvs", "--vmethod", cb->arg);
                break;
        }
-
-       if (op & XT_IPVS_ONCE_MASK) {
-               if (data->invert & XT_IPVS_IPVS_PROPERTY)
-                       xtables_error(PARAMETER_PROBLEM,
-                                     "! --ipvs cannot be together with"
-                                     " other options");
-               data->bitmask |= XT_IPVS_IPVS_PROPERTY;
-       }
-
-       data->bitmask |= op;
-       if (invert)
-               data->invert |= op;
-       *flags |= op;
-       return 1;
-
-multiple_use:
-       xtables_error(PARAMETER_PROBLEM,
-                     "multiple use of the same IPVS option is not allowed");
+       data->bitmask |= 1 << cb->entry->id;
+       if (cb->invert)
+               data->invert |= 1 << cb->entry->id;
 }
 
-static int ipvs_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
-                         const void *entry, struct xt_entry_match **match)
+static void ipvs_mt_check(struct xt_fcheck_call *cb)
 {
-       return ipvs_mt_parse(c, argv, invert, flags, entry, match,
-                            NFPROTO_IPV4);
-}
-
-static int ipvs_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
-                         const void *entry, struct xt_entry_match **match)
-{
-       return ipvs_mt_parse(c, argv, invert, flags, entry, match,
-                            NFPROTO_IPV6);
-}
+       struct xt_ipvs_mtinfo *info = cb->data;
 
-static void ipvs_mt_check(unsigned int flags)
-{
-       if (flags == 0)
+       if (cb->xflags == 0)
                xtables_error(PARAMETER_PROBLEM,
                              "IPVS: At least one option is required");
+       if (info->bitmask & XT_IPVS_ONCE_MASK) {
+               if (info->invert & XT_IPVS_IPVS_PROPERTY)
+                       xtables_error(PARAMETER_PROBLEM,
+                                     "! --ipvs cannot be together with"
+                                     " other options");
+               info->bitmask |= XT_IPVS_IPVS_PROPERTY;
+       }
 }
 
 /* Shamelessly copied from libxt_conntrack.c */
@@ -332,11 +254,11 @@ static struct xtables_match ipvs_matches_reg[] = {
                .size          = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
                .userspacesize = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
                .help          = ipvs_mt_help,
-               .parse         = ipvs_mt4_parse,
-               .final_check   = ipvs_mt_check,
+               .x6_parse      = ipvs_mt_parse,
+               .x6_fcheck     = ipvs_mt_check,
                .print         = ipvs_mt4_print,
                .save          = ipvs_mt4_save,
-               .extra_opts    = ipvs_mt_opts,
+               .x6_options    = ipvs_mt_opts,
        },
        {
                .version       = XTABLES_VERSION,
@@ -346,11 +268,11 @@ static struct xtables_match ipvs_matches_reg[] = {
                .size          = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
                .userspacesize = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
                .help          = ipvs_mt_help,
-               .parse         = ipvs_mt6_parse,
-               .final_check   = ipvs_mt_check,
+               .x6_parse      = ipvs_mt_parse,
+               .x6_fcheck     = ipvs_mt_check,
                .print         = ipvs_mt6_print,
                .save          = ipvs_mt6_save,
-               .extra_opts    = ipvs_mt_opts,
+               .x6_options    = ipvs_mt_opts,
        },
 };