firewall3: check the return value of fw3_parse_options()
[project/firewall3.git] / options.c
index e864db7..d88d3ba 100644 (file)
--- a/options.c
+++ b/options.c
@@ -1,7 +1,7 @@
 /*
  * firewall3 - 3rd OpenWrt UCI firewall implementation
  *
 /*
  * firewall3 - 3rd OpenWrt UCI firewall implementation
  *
- *   Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
+ *   Copyright (C) 2013-2014 Jo-Philipp Wich <jo@mein.io>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -244,8 +244,8 @@ fw3_parse_address(void *ptr, const char *val, bool is_list)
        struct fw3_address addr = { };
        struct in_addr v4;
        struct in6_addr v6;
        struct fw3_address addr = { };
        struct in_addr v4;
        struct in6_addr v6;
-       char *p, *s, *e;
-       int i, m = -1;
+       char *p = NULL, *m = NULL, *s, *e;
+       int bits = -1;
 
        if (*val == '!')
        {
 
        if (*val == '!')
        {
@@ -258,78 +258,89 @@ fw3_parse_address(void *ptr, const char *val, bool is_list)
        if (!s)
                return false;
 
        if (!s)
                return false;
 
-       if ((p = strchr(s, '/')) != NULL)
-       {
+       if ((m = strchr(s, '/')) != NULL)
+               *m++ = 0;
+       else if ((p = strchr(s, '-')) != NULL)
                *p++ = 0;
                *p++ = 0;
-               m = strtoul(p, &e, 10);
 
 
-               if ((e == p) || (*e != 0))
+       if (inet_pton(AF_INET6, s, &v6))
+       {
+               addr.family = FW3_FAMILY_V6;
+               addr.address.v6 = v6;
+
+               if (m)
                {
                {
-                       if (strchr(s, ':') || !inet_pton(AF_INET, p, &v4))
+                       if (!inet_pton(AF_INET6, m, &v6))
                        {
                        {
-                               free(s);
-                               return false;
-                       }
+                               bits = strtol(m, &e, 10);
 
 
-                       for (i = 0, m = 32; !(v4.s_addr & 1) && (i < 32); i++)
-                       {
-                               m--;
-                               v4.s_addr >>= 1;
+                               if ((*e != 0) || !fw3_bitlen2netmask(addr.family, bits, &v6))
+                                       goto fail;
                        }
                        }
-               }
-       }
-       else if ((p = strchr(s, '-')) != NULL)
-       {
-               *p++ = 0;
 
 
-               if (inet_pton(AF_INET6, p, &v6))
-               {
-                       addr.family = FW3_FAMILY_V6;
-                       addr.address2.v6 = v6;
-                       addr.range = true;
+                       addr.mask.v6 = v6;
                }
                }
-               else if (inet_pton(AF_INET, p, &v4))
+               else if (p)
                {
                {
-                       addr.family = FW3_FAMILY_V4;
-                       addr.address2.v4 = v4;
+                       if (!inet_pton(AF_INET6, p, &addr.mask.v6))
+                               goto fail;
+
                        addr.range = true;
                }
                else
                {
                        addr.range = true;
                }
                else
                {
-                       free(s);
-                       return false;
+                       memset(addr.mask.v6.s6_addr, 0xFF, 16);
                }
        }
                }
        }
-
-       if (inet_pton(AF_INET6, s, &v6))
-       {
-               addr.family = FW3_FAMILY_V6;
-               addr.address.v6 = v6;
-               addr.mask = (m >= 0) ? m : 128;
-       }
        else if (inet_pton(AF_INET, s, &v4))
        {
                addr.family = FW3_FAMILY_V4;
                addr.address.v4 = v4;
        else if (inet_pton(AF_INET, s, &v4))
        {
                addr.family = FW3_FAMILY_V4;
                addr.address.v4 = v4;
-               addr.mask = (m >= 0) ? m : 32;
+
+               if (m)
+               {
+                       if (!inet_pton(AF_INET, m, &v4))
+                       {
+                               bits = strtol(m, &e, 10);
+
+                               if ((*e != 0) || !fw3_bitlen2netmask(addr.family, bits, &v4))
+                                       goto fail;
+                       }
+
+                       addr.mask.v4 = v4;
+               }
+               else if (p)
+               {
+                       if (!inet_pton(AF_INET, p, &addr.mask.v4))
+                               goto fail;
+
+                       addr.range = true;
+               }
+               else
+               {
+                       addr.mask.v4.s_addr = 0xFFFFFFFF;
+               }
        }
        else
        {
        }
        else
        {
-               free(s);
-               return false;
+               goto fail;
        }
 
        free(s);
        addr.set = true;
        put_value(ptr, &addr, sizeof(addr), is_list);
        return true;
        }
 
        free(s);
        addr.set = true;
        put_value(ptr, &addr, sizeof(addr), is_list);
        return true;
+
+fail:
+       free(s);
+       return false;
 }
 
 bool
 fw3_parse_network(void *ptr, const char *val, bool is_list)
 {
        struct fw3_device dev = { };
 }
 
 bool
 fw3_parse_network(void *ptr, const char *val, bool is_list)
 {
        struct fw3_device dev = { };
-       struct fw3_address *addr;
+       struct fw3_address *addr, *tmp;
        LIST_HEAD(addr_list);
 
        if (!fw3_parse_address(ptr, val, is_list))
        LIST_HEAD(addr_list);
 
        if (!fw3_parse_address(ptr, val, is_list))
@@ -343,7 +354,19 @@ fw3_parse_network(void *ptr, const char *val, bool is_list)
                        addr->invert = dev.invert;
                        addr->resolved = true;
                }
                        addr->invert = dev.invert;
                        addr->resolved = true;
                }
-               list_splice_tail(&addr_list, ptr);
+
+               if (is_list)
+               {
+                       list_splice_tail(&addr_list, ptr);
+               }
+               else if (!list_empty(&addr_list))
+               {
+                       memcpy(ptr, list_first_entry(&addr_list, typeof(*addr), list),
+                              sizeof(*addr));
+
+                       list_for_each_entry_safe(addr, tmp, &addr_list, list)
+                               free(addr);
+               }
        }
 
        return true;
        }
 
        return true;
@@ -419,7 +442,7 @@ fw3_parse_port(void *ptr, const char *val, bool is_list)
 bool
 fw3_parse_family(void *ptr, const char *val, bool is_list)
 {
 bool
 fw3_parse_family(void *ptr, const char *val, bool is_list)
 {
-       if (!strcmp(val, "any"))
+       if (!strcmp(val, "any") || !strcmp(val, "*"))
                *((enum fw3_family *)ptr) = FW3_FAMILY_ANY;
        else if (!strcmp(val, "inet") || strrchr(val, '4'))
                *((enum fw3_family *)ptr) = FW3_FAMILY_V4;
                *((enum fw3_family *)ptr) = FW3_FAMILY_ANY;
        else if (!strcmp(val, "inet") || strrchr(val, '4'))
                *((enum fw3_family *)ptr) = FW3_FAMILY_V4;
@@ -520,7 +543,7 @@ fw3_parse_protocol(void *ptr, const char *val, bool is_list)
                while (isspace(*++val));
        }
 
                while (isspace(*++val));
        }
 
-       if (!strcmp(val, "all"))
+       if (!strcmp(val, "all") || !strcmp(val, "any") || !strcmp(val, "*"))
        {
                proto.any = true;
                put_value(ptr, &proto, sizeof(proto), is_list);
        {
                proto.any = true;
                put_value(ptr, &proto, sizeof(proto), is_list);
@@ -695,7 +718,7 @@ fw3_parse_weekdays(void *ptr, const char *val, bool is_list)
 
        if (*val == '!')
        {
 
        if (*val == '!')
        {
-               setbit(*(uint8_t *)ptr, 0);
+               fw3_setbit(*(uint8_t *)ptr, 0);
                while (isspace(*++val));
        }
 
                while (isspace(*++val));
        }
 
@@ -715,7 +738,7 @@ fw3_parse_weekdays(void *ptr, const char *val, bool is_list)
                        }
                }
 
                        }
                }
 
-               setbit(*(uint8_t *)ptr, w);
+               fw3_setbit(*(uint8_t *)ptr, w);
        }
 
        free(s);
        }
 
        free(s);
@@ -730,7 +753,7 @@ fw3_parse_monthdays(void *ptr, const char *val, bool is_list)
 
        if (*val == '!')
        {
 
        if (*val == '!')
        {
-               setbit(*(uint32_t *)ptr, 0);
+               fw3_setbit(*(uint32_t *)ptr, 0);
                while (isspace(*++val));
        }
 
                while (isspace(*++val));
        }
 
@@ -747,7 +770,7 @@ fw3_parse_monthdays(void *ptr, const char *val, bool is_list)
                        return false;
                }
 
                        return false;
                }
 
-               setbit(*(uint32_t *)ptr, d);
+               fw3_setbit(*(uint32_t *)ptr, d);
        }
 
        free(s);
        }
 
        free(s);
@@ -958,7 +981,7 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
 
 bool
 fw3_parse_blob_options(void *s, const struct fw3_option *opts,
 
 bool
 fw3_parse_blob_options(void *s, const struct fw3_option *opts,
-                  struct blob_attr *a)
+                       struct blob_attr *a, const char *name)
 {
        char *p, *v, buf[16];
        bool known;
 {
        char *p, *v, buf[16];
        bool known;
@@ -984,7 +1007,9 @@ fw3_parse_blob_options(void *s, const struct fw3_option *opts,
                        {
                                if (!opt->elem_size)
                                {
                        {
                                if (!opt->elem_size)
                                {
-                                       fprintf(stderr, "%s must not be a list\n", opt->name);
+                                       fprintf(stderr, "%s: '%s' must not be a list\n",
+                                               name, opt->name);
+
                                        valid = false;
                                }
                                else
                                        valid = false;
                                }
                                else
@@ -1002,7 +1027,8 @@ fw3_parse_blob_options(void *s, const struct fw3_option *opts,
 
                                                if (!opt->parse(dest, v, true))
                                                {
 
                                                if (!opt->parse(dest, v, true))
                                                {
-                                                       fprintf(stderr, "%s has invalid value '%s'\n", opt->name, v);
+                                                       fprintf(stderr, "%s: '%s' has invalid value '%s'\n",
+                                                               name, opt->name, v);
                                                        valid = false;
                                                        continue;
                                                }
                                                        valid = false;
                                                        continue;
                                                }
@@ -1025,7 +1051,8 @@ fw3_parse_blob_options(void *s, const struct fw3_option *opts,
                                {
                                        if (!opt->parse((char *)s + opt->offset, v, false))
                                        {
                                {
                                        if (!opt->parse((char *)s + opt->offset, v, false))
                                        {
-                                               fprintf(stderr, "%s has invalid value '%s'\n", opt->name, v);
+                                               fprintf(stderr, "%s: '%s' has invalid value '%s'\n",
+                                                       name, opt->name, v);
                                                valid = false;
                                        }
                                }
                                                valid = false;
                                        }
                                }
@@ -1037,7 +1064,8 @@ fw3_parse_blob_options(void *s, const struct fw3_option *opts,
                                        {
                                                if (!opt->parse(dest, p, true))
                                                {
                                        {
                                                if (!opt->parse(dest, p, true))
                                                {
-                                                       fprintf(stderr, "%s has invalid value '%s'\n", opt->name, p);
+                                                       fprintf(stderr, "%s: '%s' has invalid value '%s'\n",
+                                                               name, opt->name, p);
                                                        valid = false;
                                                        continue;
                                                }
                                                        valid = false;
                                                        continue;
                                                }
@@ -1049,8 +1077,8 @@ fw3_parse_blob_options(void *s, const struct fw3_option *opts,
                        break;
                }
 
                        break;
                }
 
-               if (!known)
-                       fprintf(stderr, "%s is unknown\n", blobmsg_name(o));
+               if (!known && strcmp(blobmsg_name(o), "type"))
+                       fprintf(stderr, "%s: '%s' is unknown\n", name, blobmsg_name(o));
        }
 
        return valid;
        }
 
        return valid;
@@ -1058,7 +1086,7 @@ fw3_parse_blob_options(void *s, const struct fw3_option *opts,
 
 
 const char *
 
 
 const char *
-fw3_address_to_string(struct fw3_address *address, bool allow_invert)
+fw3_address_to_string(struct fw3_address *address, bool allow_invert, bool as_cidr)
 {
        char *p, ip[INET6_ADDRSTRLEN];
        static char buf[INET6_ADDRSTRLEN * 2 + 2];
 {
        char *p, ip[INET6_ADDRSTRLEN];
        static char buf[INET6_ADDRSTRLEN * 2 + 2];
@@ -1076,13 +1104,21 @@ fw3_address_to_string(struct fw3_address *address, bool allow_invert)
        if (address->range)
        {
                inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
        if (address->range)
        {
                inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
-                         &address->address2.v4, ip, sizeof(ip));
+                         &address->mask.v4, ip, sizeof(ip));
 
                p += sprintf(p, "-%s", ip);
        }
 
                p += sprintf(p, "-%s", ip);
        }
+       else if (!as_cidr)
+       {
+               inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
+                         &address->mask.v4, ip, sizeof(ip));
+
+               p += sprintf(p, "/%s", ip);
+       }
        else
        {
        else
        {
-               p += sprintf(p, "/%u", address->mask);
+               p += sprintf(p, "/%u", fw3_netmask2bitlen(address->family,
+                                                         &address->mask.v6));
        }
 
        return buf;
        }
 
        return buf;