options: treat time strings as UTC times
[project/firewall3.git] / options.c
index f41153c..087aa63 100644 (file)
--- a/options.c
+++ b/options.c
@@ -1,7 +1,7 @@
 /*
  * 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
@@ -75,6 +75,7 @@ const char *fw3_flag_names[__FW3_FLAG_MAX] = {
        "REJECT",
        "DROP",
        "NOTRACK",
+       "HELPER",
        "MARK",
        "DNAT",
        "SNAT",
@@ -342,19 +343,31 @@ fw3_parse_network(void *ptr, const char *val, bool is_list)
        struct fw3_device dev = { };
        struct fw3_address *addr, *tmp;
        LIST_HEAD(addr_list);
+       int n_addrs;
 
        if (!fw3_parse_address(ptr, val, is_list))
        {
                if (!fw3_parse_device(&dev, val, false))
                        return false;
 
-               fw3_ubus_address(&addr_list, dev.name);
+               n_addrs = fw3_ubus_address(&addr_list, dev.name);
+
                list_for_each_entry(addr, &addr_list, list)
                {
                        addr->invert = dev.invert;
                        addr->resolved = true;
                }
 
+               /* add an empty address member with .set = false, .resolved = true
+                * to signal resolving failure to callers */
+               if (n_addrs == 0)
+               {
+                       tmp = fw3_alloc(sizeof(*tmp));
+                       tmp->resolved = true;
+
+                       list_add_tail(&tmp->list, &addr_list);
+               }
+
                if (is_list)
                {
                        list_splice_tail(&addr_list, ptr);
@@ -628,6 +641,7 @@ fw3_parse_date(void *ptr, const char *val, bool is_list)
 {
        unsigned int year = 1970, mon = 1, day = 1, hour = 0, min = 0, sec = 0;
        struct tm tm = { 0 };
+       time_t ts;
        char *p;
 
        year = strtoul(val, &p, 10);
@@ -672,9 +686,11 @@ ret:
        tm.tm_min  = min;
        tm.tm_sec  = sec;
 
-       if (mktime(&tm) >= 0)
+       ts = mktime(&tm) - timezone;
+
+       if (ts >= 0)
        {
-               *((struct tm *)ptr) = tm;
+               gmtime_r(&ts, (struct tm *)ptr);
                return true;
        }
 
@@ -718,7 +734,7 @@ fw3_parse_weekdays(void *ptr, const char *val, bool is_list)
 
        if (*val == '!')
        {
-               setbit(*(uint8_t *)ptr, 0);
+               fw3_setbit(*(uint8_t *)ptr, 0);
                while (isspace(*++val));
        }
 
@@ -738,7 +754,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);
@@ -753,7 +769,7 @@ fw3_parse_monthdays(void *ptr, const char *val, bool is_list)
 
        if (*val == '!')
        {
-               setbit(*(uint32_t *)ptr, 0);
+               fw3_setbit(*(uint32_t *)ptr, 0);
                while (isspace(*++val));
        }
 
@@ -770,7 +786,7 @@ fw3_parse_monthdays(void *ptr, const char *val, bool is_list)
                        return false;
                }
 
-               setbit(*(uint32_t *)ptr, d);
+               fw3_setbit(*(uint32_t *)ptr, d);
        }
 
        free(s);
@@ -885,13 +901,46 @@ fw3_parse_direction(void *ptr, const char *val, bool is_list)
        return valid;
 }
 
+bool
+fw3_parse_cthelper(void *ptr, const char *val, bool is_list)
+{
+       struct fw3_cthelpermatch m = { };
+
+       if (*val == '!')
+       {
+               m.invert = true;
+               while (isspace(*++val));
+       }
+
+       if (*val)
+       {
+               m.set = true;
+               strncpy(m.name, val, sizeof(m.name) - 1);
+               put_value(ptr, &m, sizeof(m), is_list);
+               return true;
+       }
+
+       return false;
+}
+
+bool
+fw3_parse_setentry(void *ptr, const char *val, bool is_list)
+{
+       struct fw3_setentry e = { };
+
+       e.value = val;
+       put_value(ptr, &e, sizeof(e), is_list);
+
+       return true;
+}
+
 
 bool
 fw3_parse_options(void *s, const struct fw3_option *opts,
                   struct uci_section *section)
 {
        char *p, *v;
-       bool known;
+       bool known, inv;
        struct uci_element *e, *l;
        struct uci_option *o;
        const struct fw3_option *opt;
@@ -953,10 +1002,30 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
                                }
                                else
                                {
+                                       inv = false;
                                        dest = (struct list_head *)((char *)s + opt->offset);
 
                                        for (p = strtok(v, " \t"); p != NULL; p = strtok(NULL, " \t"))
                                        {
+                                               /* If we encounter a sole "!" token, assume that it
+                                                * is meant to be part of the next token, so silently
+                                                * skip it and remember the state... */
+                                               if (!strcmp(p, "!"))
+                                               {
+                                                       inv = true;
+                                                       continue;
+                                               }
+
+                                               /* The previous token was a sole "!", rewind pointer
+                                                * back by one byte to precede the value with an
+                                                * exclamation mark which effectively turns
+                                                * ("!", "foo") into ("!foo") */
+                                               if (inv)
+                                               {
+                                                       *--p = '!';
+                                                       inv = false;
+                                               }
+
                                                if (!opt->parse(dest, p, true))
                                                {
                                                        warn_elem(e, "has invalid value '%s'", p);
@@ -964,6 +1033,14 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
                                                        continue;
                                                }
                                        }
+
+                                       /* The last token was a sole "!" without any subsequent
+                                        * text, so pass it to the option parser as-is. */
+                                       if (inv && !opt->parse(dest, "!", true))
+                                       {
+                                               warn_elem(e, "has invalid value '%s'", p);
+                                               valid = false;
+                                       }
                                }
                        }
 
@@ -981,7 +1058,7 @@ fw3_parse_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;
@@ -1007,7 +1084,9 @@ fw3_parse_blob_options(void *s, const struct fw3_option *opts,
                        {
                                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
@@ -1025,7 +1104,8 @@ fw3_parse_blob_options(void *s, const struct fw3_option *opts,
 
                                                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;
                                                }
@@ -1048,7 +1128,8 @@ fw3_parse_blob_options(void *s, const struct fw3_option *opts,
                                {
                                        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;
                                        }
                                }
@@ -1060,7 +1141,8 @@ fw3_parse_blob_options(void *s, const struct fw3_option *opts,
                                        {
                                                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;
                                                }
@@ -1072,8 +1154,8 @@ fw3_parse_blob_options(void *s, const struct fw3_option *opts,
                        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;