firewall3: ipset: Handle reload_set properly
[project/firewall3.git] / utils.c
diff --git a/utils.c b/utils.c
index cb478bb81c7a95eb97f9650bbb6f541ec32194e0..b465878a71f2bfc4cb3f872fbf23b5d28aec4766 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -1,7 +1,7 @@
 /*
  * firewall3 - 3rd OpenWrt UCI firewall implementation
  *
- *   Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
+ *   Copyright (C) 2013 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
  */
 
 #define _GNU_SOURCE
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+
 #include "utils.h"
 #include "options.h"
 
@@ -252,6 +256,7 @@ __fw3_command_pipe(bool silent, const char *command, ...)
        switch ((pid = fork()))
        {
        case -1:
+               free(args);
                return false;
 
        case 0:
@@ -275,6 +280,7 @@ __fw3_command_pipe(bool silent, const char *command, ...)
        }
 
        pipe_fd = fdopen(pfds[1], "w");
+       free(args);
        return true;
 }
 
@@ -462,11 +468,6 @@ write_zone_uci(struct uci_context *ctx, struct fw3_zone *z,
        ptr.value  = z->masq ? "1" : "0";
        uci_set(ctx, &ptr);
 
-       ptr.o      = NULL;
-       ptr.option = "conntrack";
-       ptr.value  = z->conntrack ? "1" : "0";
-       uci_set(ctx, &ptr);
-
        ptr.o      = NULL;
        ptr.option = "mtu_fix";
        ptr.value  = z->mtu_fix ? "1" : "0";
@@ -490,18 +491,21 @@ write_zone_uci(struct uci_context *ctx, struct fw3_zone *z,
 
        fw3_foreach(dev, &z->devices)
        {
+               char *ep;
+
                if (!dev)
                        continue;
 
                p = buf;
+               ep = buf + sizeof(buf);
 
                if (dev->invert)
-                       p += sprintf(p, "!");
+                       p += snprintf(p, ep - p, "!");
 
                if (*dev->network)
-                       p += sprintf(p, "%s@%s", dev->name, dev->network);
+                       p += snprintf(p, ep - p, "%s@%s", dev->name, dev->network);
                else
-                       p += sprintf(p, "%s", dev->name);
+                       p += snprintf(p, ep - p, "%s", dev->name);
 
                ptr.value = buf;
                uci_add_list(ctx, &ptr);
@@ -581,6 +585,14 @@ write_ipset_uci(struct uci_context *ctx, struct fw3_ipset *s,
        ptr.value  = s->name;
        uci_set(ctx, &ptr);
 
+       ptr.o      = NULL;
+       ptr.option = "family";
+       if (s->family == FW3_FAMILY_V4)
+               ptr.value = "ipv4";
+       else
+               ptr.value = "ipv6";
+       uci_set(ctx, &ptr);
+
        ptr.o      = NULL;
        ptr.option = "storage";
        ptr.value  = fw3_ipset_method_names[s->method];
@@ -774,6 +786,7 @@ bool
 fw3_bitlen2netmask(int family, int bits, void *mask)
 {
        int i;
+       uint8_t rem, b;
        struct in_addr *v4;
        struct in6_addr *v6;
 
@@ -783,14 +796,17 @@ fw3_bitlen2netmask(int family, int bits, void *mask)
                        return false;
 
                v6 = mask;
-               i = abs(bits);
+               rem = abs(bits);
 
-               memset(v6->s6_addr, 0xff, i / 8);
-               memset(v6->s6_addr + (i / 8) + 1, 0, (128 - i) / 8);
-               v6->s6_addr[i / 8] = 0xff << (8 - (i & 7));
+               for (i = 0; i < sizeof(v6->s6_addr); i++)
+               {
+                       b = (rem > 8) ? 8 : rem;
+                       v6->s6_addr[i] = (uint8_t)(0xFF << (8 - b));
+                       rem -= b;
+               }
 
                if (bits < 0)
-                       for (i = 0; i < 16; i++)
+                       for (i = 0; i < sizeof(v6->s6_addr); i++)
                                v6->s6_addr[i] = ~v6->s6_addr[i];
        }
        else
@@ -799,7 +815,7 @@ fw3_bitlen2netmask(int family, int bits, void *mask)
                        return false;
 
                v4 = mask;
-               v4->s_addr = htonl(~((1 << (32 - abs(bits))) - 1));
+               v4->s_addr = bits ? htonl(~((1 << (32 - abs(bits))) - 1)) : 0;
 
                if (bits < 0)
                        v4->s_addr = ~v4->s_addr;
@@ -891,3 +907,83 @@ fw3_flush_conntrack(void *state)
 
        freeifaddrs(ifaddr);
 }
+
+bool fw3_attr_parse_name_type(struct blob_attr *entry, const char **name, const char **type)
+{
+       struct blob_attr *opt;
+       unsigned orem;
+
+       if (!type || !name)
+               return false;
+
+       *type = NULL;
+
+       blobmsg_for_each_attr(opt, entry, orem)
+               if (!strcmp(blobmsg_name(opt), "type"))
+                       *type = blobmsg_get_string(opt);
+               else if (!strcmp(blobmsg_name(opt), "name"))
+                       *name = blobmsg_get_string(opt);
+
+       return *type != NULL ? true : false;
+}
+
+const char *
+fw3_protoname(void *proto)
+{
+       static char buf[sizeof("4294967295")];
+       struct fw3_protocol *p = proto;
+       struct protoent *pe;
+
+       if (!p)
+               return "?";
+
+       pe = getprotobynumber(p->protocol);
+
+       if (!pe)
+       {
+               snprintf(buf, sizeof(buf), "%u", p->protocol);
+               return buf;
+       }
+
+       return pe->p_name;
+}
+
+bool
+fw3_check_loopback_dev(const char *name)
+{
+       struct ifreq ifr;
+       int s;
+       bool rv = false;
+
+       s = socket(AF_LOCAL, SOCK_DGRAM, 0);
+
+       if (s < 0)
+               return false;
+
+       memset(&ifr, 0, sizeof(ifr));
+       strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name) - 1);
+
+       if (ioctl(s, SIOCGIFFLAGS, &ifr) >= 0) {
+               if (ifr.ifr_flags & IFF_LOOPBACK)
+                       rv = true;
+       }
+
+       close(s);
+
+       return rv;
+}
+
+bool
+fw3_check_loopback_addr(struct fw3_address *addr)
+{
+       if (addr->family == FW3_FAMILY_V4 &&
+           (ntohl(addr->address.v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
+               return true;
+
+       if (addr->family == FW3_FAMILY_V6 && !addr->range &&
+           fw3_netmask2bitlen(FW3_FAMILY_V6, &addr->mask.v6) == 128 &&
+           IN6_IS_ADDR_LOOPBACK(&addr->address.v6))
+               return true;
+
+       return false;
+}