]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
extensions: Unify ICMP parser into libxt_icmp.h
authorPhil Sutter <phil@nwl.cc>
Wed, 12 Oct 2022 00:02:38 +0000 (02:02 +0200)
committerPhil Sutter <phil@nwl.cc>
Tue, 15 Nov 2022 15:58:16 +0000 (16:58 +0100)
Merge all four copies of the ICMP/ICMPv6/IGMP parameter parsing code.

Signed-off-by: Phil Sutter <phil@nwl.cc>
extensions/libebt_ip.c
extensions/libebt_ip6.c
extensions/libip6t_icmp6.c
extensions/libipt_icmp.c
extensions/libxt_icmp.h

index 27ae84e9470d8a94614a2dddd5885aaafc745de0..fd87dae7e2c6293ffe5f6cdb74977be989b9bfad 100644 (file)
@@ -102,82 +102,6 @@ parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
 }
 
 /* original code from ebtables: useful_functions.c */
-static char *parse_range(const char *str, unsigned int res[])
-{
-       char *next;
-
-       if (!xtables_strtoui(str, &next, &res[0], 0, 255))
-               return NULL;
-
-       res[1] = res[0];
-       if (*next == ':') {
-               str = next + 1;
-               if (!xtables_strtoui(str, &next, &res[1], 0, 255))
-                       return NULL;
-       }
-
-       return next;
-}
-
-static int ebt_parse_icmp(const struct xt_icmp_names *codes, size_t n_codes,
-                         const char *icmptype, uint8_t type[], uint8_t code[])
-{
-       unsigned int match = n_codes;
-       unsigned int i, number[2];
-
-       for (i = 0; i < n_codes; i++) {
-               if (strncasecmp(codes[i].name, icmptype, strlen(icmptype)))
-                       continue;
-               if (match != n_codes)
-                       xtables_error(PARAMETER_PROBLEM, "Ambiguous ICMP type `%s':"
-                                       " `%s' or `%s'?",
-                                       icmptype, codes[match].name,
-                                       codes[i].name);
-               match = i;
-       }
-
-       if (match < n_codes) {
-               type[0] = type[1] = codes[match].type;
-               if (code) {
-                       code[0] = codes[match].code_min;
-                       code[1] = codes[match].code_max;
-               }
-       } else {
-               char *next = parse_range(icmptype, number);
-               if (!next) {
-                       xtables_error(PARAMETER_PROBLEM, "Unknown ICMP type `%s'",
-                                                       icmptype);
-                       return -1;
-               }
-
-               type[0] = (uint8_t) number[0];
-               type[1] = (uint8_t) number[1];
-               switch (*next) {
-               case 0:
-                       if (code) {
-                               code[0] = 0;
-                               code[1] = 255;
-                       }
-                       return 0;
-               case '/':
-                       if (code) {
-                               next = parse_range(next+1, number);
-                               code[0] = (uint8_t) number[0];
-                               code[1] = (uint8_t) number[1];
-                               if (next == NULL)
-                                       return -1;
-                               if (next && *next == 0)
-                                       return 0;
-                       }
-               /* fallthrough */
-               default:
-                       xtables_error(PARAMETER_PROBLEM, "unknown character %c", *next);
-                       return -1;
-               }
-       }
-       return 0;
-}
-
 static void print_icmp_code(uint8_t *code)
 {
        if (!code)
@@ -256,15 +180,13 @@ brip_parse(int c, char **argv, int invert, unsigned int *flags,
        case IP_EBT_ICMP:
                if (invert)
                        info->invflags |= EBT_IP_ICMP;
-               ebt_parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes), optarg,
-                             info->icmp_type, info->icmp_code);
+               ebt_parse_icmp(optarg, info->icmp_type, info->icmp_code);
                info->bitmask |= EBT_IP_ICMP;
                break;
        case IP_EBT_IGMP:
                if (invert)
                        info->invflags |= EBT_IP_IGMP;
-               ebt_parse_icmp(igmp_types, ARRAY_SIZE(igmp_types), optarg,
-                              info->igmp_type, NULL);
+               ebt_parse_igmp(optarg, info->igmp_type);
                info->bitmask |= EBT_IP_IGMP;
                break;
        case IP_EBT_TOS: {
index ac20666af5ba328dd9a67fe1e13951fde566208c..18bb2720ccbec6b0c88c8d658bc58af073c981b7 100644 (file)
@@ -72,76 +72,6 @@ parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
        free(buffer);
 }
 
-static char *parse_range(const char *str, unsigned int res[])
-{
-       char *next;
-
-       if (!xtables_strtoui(str, &next, &res[0], 0, 255))
-               return NULL;
-
-       res[1] = res[0];
-       if (*next == ':') {
-               str = next + 1;
-               if (!xtables_strtoui(str, &next, &res[1], 0, 255))
-                       return NULL;
-       }
-
-       return next;
-}
-
-static int
-parse_icmpv6(const char *icmpv6type, uint8_t type[], uint8_t code[])
-{
-       static const unsigned int limit = ARRAY_SIZE(icmpv6_codes);
-       unsigned int match = limit;
-       unsigned int i, number[2];
-
-       for (i = 0; i < limit; i++) {
-               if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type)))
-                       continue;
-               if (match != limit)
-                       xtables_error(PARAMETER_PROBLEM, "Ambiguous ICMPv6 type `%s':"
-                                       " `%s' or `%s'?",
-                                       icmpv6type, icmpv6_codes[match].name,
-                                       icmpv6_codes[i].name);
-               match = i;
-       }
-
-       if (match < limit) {
-               type[0] = type[1] = icmpv6_codes[match].type;
-               code[0] = icmpv6_codes[match].code_min;
-               code[1] = icmpv6_codes[match].code_max;
-       } else {
-               char *next = parse_range(icmpv6type, number);
-               if (!next) {
-                       xtables_error(PARAMETER_PROBLEM, "Unknown ICMPv6 type `%s'",
-                                                       icmpv6type);
-                       return -1;
-               }
-               type[0] = (uint8_t) number[0];
-               type[1] = (uint8_t) number[1];
-               switch (*next) {
-               case 0:
-                       code[0] = 0;
-                       code[1] = 255;
-                       return 0;
-               case '/':
-                       next = parse_range(next+1, number);
-                       code[0] = (uint8_t) number[0];
-                       code[1] = (uint8_t) number[1];
-                       if (next == NULL)
-                               return -1;
-                       if (next && *next == 0)
-                               return 0;
-               /* fallthrough */
-               default:
-                       xtables_error(PARAMETER_PROBLEM, "unknown character %c", *next);
-                       return -1;
-               }
-       }
-       return 0;
-}
-
 static void print_port_range(uint16_t *ports)
 {
        if (ports[0] == ports[1])
@@ -266,8 +196,7 @@ brip6_parse(int c, char **argv, int invert, unsigned int *flags,
        case IP_ICMP6:
                if (invert)
                        info->invflags |= EBT_IP6_ICMP6;
-               if (parse_icmpv6(optarg, info->icmpv6_type, info->icmpv6_code))
-                       return 0;
+               ebt_parse_icmpv6(optarg, info->icmpv6_type, info->icmpv6_code);
                info->bitmask |= EBT_IP6_ICMP6;
                break;
        case IP_TCLASS:
index 44f71095281663128f666352a8d542e3ac5e3a5d..439291eaaaca522f3711e48bb1f338e4bdec9e97 100644 (file)
@@ -28,59 +28,6 @@ static const struct xt_option_entry icmp6_opts[] = {
        XTOPT_TABLEEND,
 };
 
-static void
-parse_icmpv6(const char *icmpv6type, uint8_t *type, uint8_t code[])
-{
-       static const unsigned int limit = ARRAY_SIZE(icmpv6_codes);
-       unsigned int match = limit;
-       unsigned int i;
-
-       for (i = 0; i < limit; i++) {
-               if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type))
-                   == 0) {
-                       if (match != limit)
-                               xtables_error(PARAMETER_PROBLEM,
-                                          "Ambiguous ICMPv6 type `%s':"
-                                          " `%s' or `%s'?",
-                                          icmpv6type,
-                                          icmpv6_codes[match].name,
-                                          icmpv6_codes[i].name);
-                       match = i;
-               }
-       }
-
-       if (match != limit) {
-               *type = icmpv6_codes[match].type;
-               code[0] = icmpv6_codes[match].code_min;
-               code[1] = icmpv6_codes[match].code_max;
-       } else {
-               char *slash;
-               char buffer[strlen(icmpv6type) + 1];
-               unsigned int number;
-
-               strcpy(buffer, icmpv6type);
-               slash = strchr(buffer, '/');
-
-               if (slash)
-                       *slash = '\0';
-
-               if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX))
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "Invalid ICMPv6 type `%s'\n", buffer);
-               *type = number;
-               if (slash) {
-                       if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX))
-                               xtables_error(PARAMETER_PROBLEM,
-                                          "Invalid ICMPv6 code `%s'\n",
-                                          slash+1);
-                       code[0] = code[1] = number;
-               } else {
-                       code[0] = 0;
-                       code[1] = 0xFF;
-               }
-       }
-}
-
 static void icmp6_init(struct xt_entry_match *m)
 {
        struct ip6t_icmp *icmpv6info = (struct ip6t_icmp *)m->data;
@@ -93,7 +40,7 @@ static void icmp6_parse(struct xt_option_call *cb)
        struct ip6t_icmp *icmpv6info = cb->data;
 
        xtables_option_parse(cb);
-       parse_icmpv6(cb->arg, &icmpv6info->type, icmpv6info->code);
+       ipt_parse_icmpv6(cb->arg, &icmpv6info->type, icmpv6info->code);
        if (cb->invert)
                icmpv6info->invflags |= IP6T_ICMP_INV;
 }
index f0e838874286bd17ac71313645bcbc080beaa43e..b0318aebc2c5745866c75f52c32795f699c13a7f 100644 (file)
@@ -35,59 +35,6 @@ static const struct xt_option_entry icmp_opts[] = {
        XTOPT_TABLEEND,
 };
 
-static void 
-parse_icmp(const char *icmptype, uint8_t *type, uint8_t code[])
-{
-       static const unsigned int limit = ARRAY_SIZE(icmp_codes);
-       unsigned int match = limit;
-       unsigned int i;
-
-       for (i = 0; i < limit; i++) {
-               if (strncasecmp(icmp_codes[i].name, icmptype, strlen(icmptype))
-                   == 0) {
-                       if (match != limit)
-                               xtables_error(PARAMETER_PROBLEM,
-                                          "Ambiguous ICMP type `%s':"
-                                          " `%s' or `%s'?",
-                                          icmptype,
-                                          icmp_codes[match].name,
-                                          icmp_codes[i].name);
-                       match = i;
-               }
-       }
-
-       if (match != limit) {
-               *type = icmp_codes[match].type;
-               code[0] = icmp_codes[match].code_min;
-               code[1] = icmp_codes[match].code_max;
-       } else {
-               char *slash;
-               char buffer[strlen(icmptype) + 1];
-               unsigned int number;
-
-               strcpy(buffer, icmptype);
-               slash = strchr(buffer, '/');
-
-               if (slash)
-                       *slash = '\0';
-
-               if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX))
-                       xtables_error(PARAMETER_PROBLEM,
-                                  "Invalid ICMP type `%s'\n", buffer);
-               *type = number;
-               if (slash) {
-                       if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX))
-                               xtables_error(PARAMETER_PROBLEM,
-                                          "Invalid ICMP code `%s'\n",
-                                          slash+1);
-                       code[0] = code[1] = number;
-               } else {
-                       code[0] = 0;
-                       code[1] = 0xFF;
-               }
-       }
-}
-
 static void icmp_init(struct xt_entry_match *m)
 {
        struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data;
@@ -101,7 +48,7 @@ static void icmp_parse(struct xt_option_call *cb)
        struct ipt_icmp *icmpinfo = cb->data;
 
        xtables_option_parse(cb);
-       parse_icmp(cb->arg, &icmpinfo->type, icmpinfo->code);
+       ipt_parse_icmp(cb->arg, &icmpinfo->type, icmpinfo->code);
        if (cb->invert)
                icmpinfo->invflags |= IPT_ICMP_INV;
 }
index d6d9f9b6ffc98f4f4aaac43cb93e2f0ef963ed9f..a763e50c1de323d6c5ba520bb4fdadfb511fbe14 100644 (file)
@@ -102,6 +102,132 @@ static const struct xt_icmp_names {
        { "membership-report-v3", 0x22 },
 };
 
+static inline char *parse_range(const char *str, unsigned int res[])
+{
+       char *next;
+
+       if (!xtables_strtoui(str, &next, &res[0], 0, 255))
+               return NULL;
+
+       res[1] = res[0];
+       if (*next == ':') {
+               str = next + 1;
+               if (!xtables_strtoui(str, &next, &res[1], 0, 255))
+                       return NULL;
+       }
+
+       return next;
+}
+
+static void
+__parse_icmp(const struct xt_icmp_names codes[], size_t n_codes,
+            const char *codes_name, const char *fmtstring,
+            uint8_t type[], uint8_t code[])
+{
+       unsigned int match = n_codes;
+       unsigned int i, number[2];
+
+       for (i = 0; i < n_codes; i++) {
+               if (strncasecmp(codes[i].name, fmtstring, strlen(fmtstring)))
+                       continue;
+               if (match != n_codes)
+                       xtables_error(PARAMETER_PROBLEM,
+                                     "Ambiguous %s type `%s': `%s' or `%s'?",
+                                     codes_name, fmtstring, codes[match].name,
+                                     codes[i].name);
+               match = i;
+       }
+
+       if (match < n_codes) {
+               type[0] = type[1] = codes[match].type;
+               if (code) {
+                       code[0] = codes[match].code_min;
+                       code[1] = codes[match].code_max;
+               }
+       } else {
+               char *next = parse_range(fmtstring, number);
+               if (!next)
+                       xtables_error(PARAMETER_PROBLEM, "Unknown %s type `%s'",
+                                     codes_name, fmtstring);
+               type[0] = (uint8_t) number[0];
+               type[1] = (uint8_t) number[1];
+               switch (*next) {
+               case 0:
+                       if (code) {
+                               code[0] = 0;
+                               code[1] = 255;
+                       }
+                       return;
+               case '/':
+                       if (!code)
+                               break;
+
+                       next = parse_range(next + 1, number);
+                       if (!next)
+                               xtables_error(PARAMETER_PROBLEM,
+                                             "Unknown %s code `%s'",
+                                             codes_name, fmtstring);
+                       code[0] = (uint8_t) number[0];
+                       code[1] = (uint8_t) number[1];
+                       if (!*next)
+                               break;
+               /* fallthrough */
+               default:
+                       xtables_error(PARAMETER_PROBLEM,
+                                     "unknown character %c", *next);
+               }
+       }
+}
+
+static inline void
+__ipt_parse_icmp(const struct xt_icmp_names *codes, size_t n_codes,
+                const char *codes_name, const char *fmtstr,
+                uint8_t *type, uint8_t code[])
+{
+       uint8_t types[2];
+
+       __parse_icmp(codes, n_codes, codes_name, fmtstr, types, code);
+       if (types[1] != types[0])
+               xtables_error(PARAMETER_PROBLEM,
+                             "%s type range not supported", codes_name);
+       *type = types[0];
+}
+
+static inline void
+ipt_parse_icmp(const char *str, uint8_t *type, uint8_t code[])
+{
+       __ipt_parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes),
+                        "ICMP", str, type, code);
+}
+
+static inline void
+ipt_parse_icmpv6(const char *str, uint8_t *type, uint8_t code[])
+{
+       __ipt_parse_icmp(icmpv6_codes, ARRAY_SIZE(icmpv6_codes),
+                        "ICMPv6", str, type, code);
+}
+
+static inline void
+ebt_parse_icmp(const char *str, uint8_t type[], uint8_t code[])
+{
+       __parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes),
+                    "ICMP", str, type, code);
+}
+
+static inline void
+ebt_parse_icmpv6(const char *str, uint8_t type[], uint8_t code[])
+{
+       __parse_icmp(icmpv6_codes, ARRAY_SIZE(icmpv6_codes),
+                    "ICMPv6", str, type, code);
+}
+
+static inline void
+ebt_parse_igmp(const char *str, uint8_t type[])
+{
+       __parse_icmp(igmp_types, ARRAY_SIZE(igmp_types),
+                    "IGMP", str, type, NULL);
+}
+
 static void xt_print_icmp_types(const struct xt_icmp_names *_icmp_codes,
                                unsigned int n_codes)
 {