/*
* 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
static bool
compare_addr(struct fw3_address *a, struct fw3_address *b)
{
- uint32_t mask;
-
if (a->family != FW3_FAMILY_V4 || b->family != FW3_FAMILY_V4)
return false;
- mask = htonl(~((1 << (32 - a->mask)) - 1));
-
- return ((a->address.v4.s_addr & mask) == (b->address.v4.s_addr & mask));
+ return ((a->address.v4.s_addr & a->mask.v4.s_addr) ==
+ (b->address.v4.s_addr & a->mask.v4.s_addr));
}
static bool
list_for_each_entry(zone, &state->zones, list)
{
- addrs = fw3_resolve_zone_addresses(zone);
+ addrs = fw3_resolve_zone_addresses(zone, NULL);
if (!addrs)
continue;
{
struct fw3_zone *zone;
struct fw3_device *net;
- struct fw3_address *addr;
- struct list_head *addrs;
+ struct fw3_address *addr, *tmp;
if (redir->target != FW3_FLAG_DNAT)
return false;
{
list_for_each_entry(net, &zone->networks, list)
{
- addrs = fw3_ubus_address(net->name);
-
- if (!addrs)
- continue;
+ LIST_HEAD(addrs);
- list_for_each_entry(addr, addrs, list)
+ fw3_ubus_address(&addrs, net->name);
+ list_for_each_entry_safe(addr, tmp, &addrs, list)
{
- if (!compare_addr(&redir->ip_redir, addr))
- continue;
+ if (!redir->local && compare_addr(&redir->ip_redir, addr)) {
+ warn_elem(e, "refers to a destination address on this router, "
+ "assuming port redirection");
- warn_elem(e, "refers to a destination address on this router, "
- "assuming port redirection");
+ redir->local = true;
+ }
- redir->local = true;
- break;
+ list_del(&addr->list);
+ free(addr);
}
- fw3_free_list(addrs);
-
if (redir->local)
return true;
}
if (strcmp(s->type, "redirect"))
continue;
- redir = malloc(sizeof(*redir));
-
+ redir = calloc(1, sizeof(*redir));
if (!redir)
continue;
- memset(redir, 0, sizeof(*redir));
-
INIT_LIST_HEAD(&redir->proto);
INIT_LIST_HEAD(&redir->mac_src);
warn_elem(e, "has no target specified, defaulting to DNAT");
redir->target = FW3_FLAG_DNAT;
}
- else if (redir->target < FW3_FLAG_DNAT)
+ else if (redir->target < FW3_FLAG_DNAT || redir->target > FW3_FLAG_SNAT)
{
warn_elem(e, "has invalid target specified, defaulting to DNAT");
redir->target = FW3_FLAG_DNAT;
}
static void
+set_redirect(struct fw3_ipt_rule *r, struct fw3_port *port)
+{
+ char buf[sizeof("65535-65535\0")];
+
+ fw3_ipt_rule_target(r, "REDIRECT");
+
+ if (port && port->set)
+ {
+ if (port->port_min == port->port_max)
+ sprintf(buf, "%u", port->port_min);
+ else
+ sprintf(buf, "%u-%u", port->port_min, port->port_max);
+
+ fw3_ipt_rule_addarg(r, false, "--to-ports", buf);
+ }
+}
+
+static void
set_snat_dnat(struct fw3_ipt_rule *r, enum fw3_flag target,
struct fw3_address *addr, struct fw3_port *port)
{
static void
set_target_nat(struct fw3_ipt_rule *r, struct fw3_redirect *redir)
{
- if (redir->target == FW3_FLAG_DNAT)
+ if (redir->local)
+ set_redirect(r, &redir->port_redir);
+ else if (redir->target == FW3_FLAG_DNAT)
set_snat_dnat(r, redir->target, &redir->ip_redir, &redir->port_redir);
else
set_snat_dnat(r, redir->target, &redir->ip_dest, &redir->port_dest);
print_redirect(handle, state, redir, num, proto, mac);
/* reflection rules */
- if (redir->target != FW3_FLAG_DNAT || !redir->reflection)
+ if (redir->target != FW3_FLAG_DNAT || !redir->reflection || redir->local)
return;
if (!redir->_dest || !redir->_src->masq)
return;
- ext_addrs = fw3_resolve_zone_addresses(redir->_src);
- int_addrs = fw3_resolve_zone_addresses(redir->_dest);
+ ext_addrs = fw3_resolve_zone_addresses(redir->_src, &redir->ip_dest);
+ int_addrs = fw3_resolve_zone_addresses(redir->_dest, NULL);
if (!ext_addrs || !int_addrs)
goto out;
else
ref_addr = *ext_addr;
- ref_addr.mask = 32;
- ext_addr->mask = 32;
+ ref_addr.mask.v4.s_addr = 0xFFFFFFFF;
+ ext_addr->mask.v4.s_addr = 0xFFFFFFFF;
print_reflection(handle, state, redir, num, proto,
&ref_addr, int_addr, ext_addr);