iptables: fix regression with unintended free in need_protomatch
[project/firewall3.git] / redirects.c
index b928287deebb0f8407aa5ecbc4dab75bdda05c66..9a827b65a892cb9d8794ecdc3bd0a3189a903c0f 100644 (file)
@@ -155,7 +155,7 @@ resolve_dest(struct uci_element *e, struct fw3_redirect *redir,
                        if (!compare_addr(addr, &redir->ip_redir))
                                continue;
 
-                       strncpy(redir->dest.name, zone->name, sizeof(redir->dest.name) - 1);
+                       snprintf(redir->dest.name, sizeof(redir->dest.name), "%s", zone->name);
                        redir->dest.set = true;
                        redir->_dest = zone;
 
@@ -458,14 +458,14 @@ append_chain_nat(struct fw3_ipt_rule *r, struct fw3_redirect *redir)
 static void
 set_redirect(struct fw3_ipt_rule *r, struct fw3_port *port)
 {
-       char buf[sizeof("65535-65535\0")];
+       char buf[sizeof("65535-65535")];
 
        fw3_ipt_rule_target(r, "REDIRECT");
 
        if (port && port->set)
        {
                if (port->port_min == port->port_max)
-                       sprintf(buf, "%u", port->port_min);
+                       snprintf(buf, sizeof(buf), "%u", port->port_min);
                else
                        snprintf(buf, sizeof(buf), "%u-%u", port->port_min, port->port_max);
 
@@ -477,22 +477,30 @@ static void
 set_snat_dnat(struct fw3_ipt_rule *r, enum fw3_flag target,
               struct fw3_address *addr, struct fw3_port *port)
 {
-       char buf[sizeof("255.255.255.255:65535-65535\0")];
-
-       buf[0] = '\0';
+       char buf[sizeof("255.255.255.255:65535-65535")] = {};
+       char ip[INET_ADDRSTRLEN], *p = buf;
+       size_t rem = sizeof(buf);
+       int len;
 
        if (addr && addr->set)
        {
-               inet_ntop(AF_INET, &addr->address.v4, buf, sizeof(buf));
+               inet_ntop(AF_INET, &addr->address.v4, ip, sizeof(ip));
+
+               len = snprintf(p, rem, "%s", ip);
+
+               if (len < 0 || len >= rem)
+                       return;
+
+               rem -= len;
+               p += len;
        }
 
        if (port && port->set)
        {
                if (port->port_min == port->port_max)
-                       sprintf(buf + strlen(buf), ":%u", port->port_min);
+                       snprintf(p, rem, ":%u", port->port_min);
                else
-                       sprintf(buf + strlen(buf), ":%u-%u",
-                               port->port_min, port->port_max);
+                       snprintf(p, rem, ":%u-%u", port->port_min, port->port_max);
        }
 
        if (target == FW3_FLAG_DNAT)
@@ -708,9 +716,8 @@ expand_redirect(struct fw3_ipt_handle *handle, struct fw3_state *state,
                return;
 
        ext_addrs = fw3_resolve_zone_addresses(redir->_src, &redir->ip_dest);
-
        if (!ext_addrs)
-               goto out;
+               return;
 
        list_for_each_entry(ext_addr, ext_addrs, list)
        {
@@ -733,6 +740,9 @@ expand_redirect(struct fw3_ipt_handle *handle, struct fw3_state *state,
                                continue;
 
                        int_addrs = fw3_resolve_zone_addresses(zone, NULL);
+                       if (!int_addrs)
+                               continue;
+
                        list_for_each_entry(int_addr, int_addrs, list)
                        {
                                if (!fw3_is_family(int_addr, handle->family))
@@ -755,12 +765,12 @@ expand_redirect(struct fw3_ipt_handle *handle, struct fw3_state *state,
                                                         &ref_addr, int_addr, ext_addr, reflection_zone);
                                }
                        }
+
+                       fw3_free_list(int_addrs);
                }
        }
 
-out:
        fw3_free_list(ext_addrs);
-       fw3_free_list(int_addrs);
 }
 
 void