diff options
author | Jo-Philipp Wich <jow@openwrt.org> | 2014-08-06 19:00:18 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jow@openwrt.org> | 2014-08-11 11:34:19 +0200 |
commit | 2807cc26b8e46eef5f23c06534a853dd48183331 (patch) | |
tree | a5676af6d0bd293e1f3bd01442b4cb43121d54bd | |
parent | 91953d6a6e90df988f442f53097bd208784a295d (diff) | |
download | firewall3-2807cc26b8e46eef5f23c06534a853dd48183331.tar.gz |
Selectively flush conntrack
Record active IP addresses in firewall state file and trigger
conntrack flush for changed IP addresses on firewall reload.
Additionally trigger a complete flush on the first firewall
start in order to clear out streams which might have bypassed
the masquerading rules.
Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
-rw-r--r-- | main.c | 14 | ||||
-rw-r--r-- | options.h | 2 | ||||
-rw-r--r-- | utils.c | 130 | ||||
-rw-r--r-- | utils.h | 4 | ||||
-rw-r--r-- | zones.c | 4 |
5 files changed, 142 insertions, 12 deletions
@@ -167,8 +167,6 @@ family_set(struct fw3_state *state, enum fw3_family family, bool set) static int stop(bool complete) { - FILE *ct; - int rv = 1; enum fw3_family family; enum fw3_table table; @@ -224,13 +222,8 @@ stop(bool complete) if (run_state) fw3_destroy_ipsets(run_state); - if (complete && (ct = fopen("/proc/net/nf_conntrack", "w")) != NULL) - { - info(" * Flushing conntrack table ..."); - - fwrite("f\n", 2, 1, ct); - fclose(ct); - } + if (complete) + fw3_flush_conntrack(NULL); if (!rv && run_state) fw3_write_statefile(run_state); @@ -304,6 +297,7 @@ start(void) if (!rv) { + fw3_flush_conntrack(run_state); fw3_set_defaults(cfg_state); if (!print_family) @@ -395,6 +389,8 @@ start: if (!rv) { + fw3_flush_conntrack(run_state); + fw3_set_defaults(cfg_state); fw3_run_includes(cfg_state, true); fw3_hotplug_zones(cfg_state, true); @@ -314,6 +314,8 @@ struct fw3_zone bool custom_chains; uint32_t flags[2]; + + struct list_head old_addrs; }; struct fw3_rule @@ -414,13 +414,14 @@ write_defaults_uci(struct uci_context *ctx, struct fw3_defaults *d, static void write_zone_uci(struct uci_context *ctx, struct fw3_zone *z, - struct uci_package *dest) + struct uci_package *dest, struct ifaddrs *ifaddr) { struct fw3_device *dev; struct fw3_address *sub; + struct ifaddrs *ifa; enum fw3_family fam = FW3_FAMILY_ANY; - char *p, buf[34]; + char *p, buf[INET6_ADDRSTRLEN]; struct uci_ptr ptr = { .p = dest }; @@ -518,6 +519,35 @@ write_zone_uci(struct uci_context *ctx, struct fw3_zone *z, uci_add_list(ctx, &ptr); } + ptr.o = NULL; + ptr.option = "__addrs"; + + fw3_foreach(dev, &z->devices) + { + if (!dev) + continue; + + for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) + { + if (strcmp(dev->name, ifa->ifa_name)) + continue; + + if (ifa->ifa_addr->sa_family == AF_INET) + inet_ntop(AF_INET, + &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr, + buf, sizeof(buf)); + else if (ifa->ifa_addr->sa_family == AF_INET6) + inet_ntop(AF_INET6, + &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr, + buf, sizeof(buf)); + else + continue; + + ptr.value = buf; + uci_add_list(ctx, &ptr); + } + } + sprintf(buf, "0x%x", z->flags[0]); ptr.o = NULL; ptr.option = "__flags_v4"; @@ -590,6 +620,7 @@ fw3_write_statefile(void *state) struct fw3_state *s = state; struct fw3_zone *z; struct fw3_ipset *i; + struct ifaddrs *ifaddr; struct uci_package *p; @@ -608,6 +639,12 @@ fw3_write_statefile(void *state) return; } + if (getifaddrs(&ifaddr)) + { + warn("Cannot get interface addresses: %s", strerror(errno)); + ifaddr = NULL; + } + if ((p = uci_lookup_package(s->uci, "fw3_state")) != NULL) uci_unload(s->uci, p); @@ -618,7 +655,7 @@ fw3_write_statefile(void *state) write_defaults_uci(s->uci, &s->defaults, p); list_for_each_entry(z, &s->zones, list) - write_zone_uci(s->uci, z, p); + write_zone_uci(s->uci, z, p, ifaddr); list_for_each_entry(i, &s->ipsets, list) write_ipset_uci(s->uci, i, p); @@ -629,6 +666,9 @@ fw3_write_statefile(void *state) fsync(fileno(sf)); fclose(sf); + + if (ifaddr) + freeifaddrs(ifaddr); } } @@ -767,3 +807,87 @@ fw3_bitlen2netmask(int family, int bits, void *mask) return true; } + +void +fw3_flush_conntrack(void *state) +{ + bool found; + struct fw3_state *s = state; + struct fw3_address *addr; + struct fw3_device *dev; + struct fw3_zone *zone; + struct ifaddrs *ifaddr, *ifa; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + char buf[INET6_ADDRSTRLEN]; + FILE *ct; + + if (!state) + { + if ((ct = fopen("/proc/net/nf_conntrack", "w")) != NULL) + { + info(" * Flushing conntrack table ..."); + + fwrite("f\n", 1, 2, ct); + fclose(ct); + } + + return; + } + + if (getifaddrs(&ifaddr)) + { + warn("Cannot get interface addresses: %s", strerror(errno)); + return; + } + + if ((ct = fopen("/proc/net/nf_conntrack", "w")) != NULL) + { + list_for_each_entry(zone, &s->zones, list) + list_for_each_entry(addr, &zone->old_addrs, list) + { + found = false; + + list_for_each_entry(dev, &zone->devices, list) + { + for (ifa = ifaddr; ifa && !found; ifa = ifa->ifa_next) + { + if (strcmp(dev->name, ifa->ifa_name)) + continue; + + sin = (struct sockaddr_in *)ifa->ifa_addr; + sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; + + if (addr->family == FW3_FAMILY_V4 && + sin->sin_family == AF_INET) + { + found = !memcmp(&addr->address.v4, &sin->sin_addr, + sizeof(sin->sin_addr)); + } + else if (addr->family == FW3_FAMILY_V6 && + sin6->sin6_family == AF_INET6) + { + found = !memcmp(&addr->address.v6, &sin6->sin6_addr, + sizeof(sin6->sin6_addr)); + } + } + + if (found) + break; + } + + if (!found) + { + inet_ntop(addr->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, + &addr->address.v4, buf, sizeof(buf)); + + info(" * Flushing conntrack: %s", buf); + fprintf(ct, "%s\n", buf); + } + } + + fclose(ct); + } + + freeifaddrs(ifaddr); +} @@ -28,6 +28,8 @@ #include <sys/stat.h> #include <sys/wait.h> #include <sys/file.h> +#include <sys/types.h> +#include <ifaddrs.h> #include <libubox/list.h> #include <uci.h> @@ -99,4 +101,6 @@ int fw3_netmask2bitlen(int family, void *mask); bool fw3_bitlen2netmask(int family, int bits, void *mask); +void fw3_flush_conntrack(void *zone); + #endif @@ -83,6 +83,8 @@ const struct fw3_option fw3_zone_opts[] = { FW3_OPT("__flags_v4", int, zone, flags[0]), FW3_OPT("__flags_v6", int, zone, flags[1]), + FW3_LIST("__addrs", address, zone, old_addrs), + { } }; @@ -138,6 +140,8 @@ fw3_alloc_zone(void) INIT_LIST_HEAD(&zone->masq_src); INIT_LIST_HEAD(&zone->masq_dest); + INIT_LIST_HEAD(&zone->old_addrs); + zone->enabled = true; zone->custom_chains = true; zone->log_limit.rate = 10; |