Reapply SNAT/MASQUERADE rules on firewall reloads
[project/firewall3.git] / options.c
index a2a0465..4c42be0 100644 (file)
--- a/options.c
+++ b/options.c
@@ -1,7 +1,7 @@
 /*
  * firewall3 - 3rd OpenWrt UCI firewall implementation
  *
- *   Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
+ *   Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -78,6 +78,7 @@ const char *fw3_flag_names[__FW3_FLAG_MAX] = {
        "MARK",
        "DNAT",
        "SNAT",
+       "MASQUERADE",
 
        "ACCEPT",
        "REJECT",
@@ -142,9 +143,10 @@ fw3_parse_bool(void *ptr, const char *val, bool is_list)
 bool
 fw3_parse_int(void *ptr, const char *val, bool is_list)
 {
-       int n = strtol(val, NULL, 0);
+       char *e;
+       int n = strtol(val, &e, 0);
 
-       if (errno == ERANGE || errno == EINVAL)
+       if (e == val || *e)
                return false;
 
        *((int *)ptr) = n;
@@ -163,7 +165,7 @@ bool
 fw3_parse_target(void *ptr, const char *val, bool is_list)
 {
        return parse_enum(ptr, val, &fw3_flag_names[FW3_FLAG_ACCEPT],
-                         FW3_FLAG_ACCEPT, FW3_FLAG_SNAT);
+                         FW3_FLAG_ACCEPT, FW3_FLAG_MASQUERADE);
 }
 
 bool
@@ -342,12 +344,13 @@ fw3_parse_network(void *ptr, const char *val, bool is_list)
                        list_for_each_entry(addr, addr_list, list)
                        {
                                addr->invert = dev.invert;
+                               addr->resolved = true;
 
                                if (!put_value(ptr, addr, sizeof(*addr), is_list))
                                        break;
                        }
 
-                       fw3_ubus_address_free(addr_list);
+                       fw3_free_list(addr_list);
                }
        }
 
@@ -517,6 +520,7 @@ fw3_parse_protocol(void *ptr, const char *val, bool is_list)
 {
        struct fw3_protocol proto = { };
        struct protoent *ent;
+       char *e;
 
        if (*val == '!')
        {
@@ -555,9 +559,9 @@ fw3_parse_protocol(void *ptr, const char *val, bool is_list)
                return true;
        }
 
-       proto.protocol = strtoul(val, NULL, 10);
+       proto.protocol = strtoul(val, &e, 10);
 
-       if (errno == ERANGE || errno == EINVAL)
+       if ((e == val) || (*e != 0))
                return false;
 
        put_value(ptr, &proto, sizeof(proto), is_list);
@@ -576,20 +580,22 @@ fw3_parse_ipset_datatype(void *ptr, const char *val, bool is_list)
 {
        struct fw3_ipset_datatype type = { };
 
+       type.dir = "src";
+
        if (!strncmp(val, "dest_", 5))
        {
                val += 5;
-               type.dest = true;
+               type.dir = "dst";
        }
        else if (!strncmp(val, "dst_", 4))
        {
                val += 4;
-               type.dest = true;
+               type.dir = "dst";
        }
        else if (!strncmp(val, "src_", 4))
        {
                val += 4;
-               type.dest = false;
+               type.dir = "src";
        }
 
        if (parse_enum(&type.type, val, &fw3_ipset_type_names[FW3_IPSET_TYPE_IP],
@@ -808,8 +814,48 @@ fw3_parse_mark(void *ptr, const char *val, bool is_list)
        return true;
 }
 
+bool
+fw3_parse_setmatch(void *ptr, const char *val, bool is_list)
+{
+       struct fw3_setmatch *m = ptr;
+       char *p, *s;
+       int i;
+
+       if (*val == '!')
+       {
+               m->invert = true;
+               while (isspace(*++val));
+       }
+
+       if (!(s = strdup(val)))
+               return false;
 
-void
+       if (!(p = strtok(s, " \t")))
+       {
+               free(s);
+               return false;
+       }
+
+       strncpy(m->name, p, sizeof(m->name));
+
+       for (i = 0, p = strtok(NULL, " \t,");
+            i < 3 && p != NULL;
+            i++, p = strtok(NULL, " \t,"))
+       {
+               if (!strncmp(p, "dest", 4) || !strncmp(p, "dst", 3))
+                       m->dir[i] = "dst";
+               else if (!strncmp(p, "src", 3))
+                       m->dir[i] = "src";
+       }
+
+       free(s);
+
+       m->set = true;
+       return true;
+}
+
+
+bool
 fw3_parse_options(void *s, const struct fw3_option *opts,
                   struct uci_section *section)
 {
@@ -819,6 +865,7 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
        struct uci_option *o;
        const struct fw3_option *opt;
        struct list_head *dest;
+       bool valid = true;
 
        uci_foreach_element(&section->options, e)
        {
@@ -838,6 +885,7 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
                                if (!opt->elem_size)
                                {
                                        warn_elem(e, "must not be a list");
+                                       valid = false;
                                }
                                else
                                {
@@ -851,6 +899,7 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
                                                if (!opt->parse(dest, l->name, true))
                                                {
                                                        warn_elem(e, "has invalid value '%s'", l->name);
+                                                       valid = false;
                                                        continue;
                                                }
                                        }
@@ -866,7 +915,10 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
                                if (!opt->elem_size)
                                {
                                        if (!opt->parse((char *)s + opt->offset, o->v.string, false))
+                                       {
                                                warn_elem(e, "has invalid value '%s'", o->v.string);
+                                               valid = false;
+                                       }
                                }
                                else
                                {
@@ -877,6 +929,7 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
                                                if (!opt->parse(dest, p, true))
                                                {
                                                        warn_elem(e, "has invalid value '%s'", p);
+                                                       valid = false;
                                                        continue;
                                                }
                                        }
@@ -890,6 +943,8 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
                if (!known)
                        warn_elem(e, "is unknown");
        }
+
+       return valid;
 }