X-Git-Url: http://git.archive.openwrt.org/?p=project%2Ffirewall3.git;a=blobdiff_plain;f=utils.c;h=b2fbe0223c6d7338600654c09750a7d2a5b9622a;hp=66c186580428405da587eb8c2dd01c4b49e5e7a3;hb=c03e20d7f594058ff223f30cf34de1b5e8210b8d;hpb=3a3d85b3c787271e4860ca590d716cf557c1fb7e diff --git a/utils.c b/utils.c index 66c1865..b2fbe02 100644 --- a/utils.c +++ b/utils.c @@ -16,6 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define _GNU_SOURCE #include "utils.h" #include "options.h" @@ -224,7 +225,7 @@ __fw3_command_pipe(bool silent, const char *command, ...) return false; argn = 2; - args = malloc(argn * sizeof(arg)); + args = calloc(argn, sizeof(arg)); if (!args) return false; @@ -413,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 }; @@ -513,10 +515,39 @@ write_zone_uci(struct uci_context *ctx, struct fw3_zone *z, if (!sub) continue; - ptr.value = fw3_address_to_string(sub, true); + ptr.value = fw3_address_to_string(sub, true, false); 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 (!ifa->ifa_addr || 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"; @@ -568,7 +599,7 @@ write_ipset_uci(struct uci_context *ctx, struct fw3_ipset *s, { ptr.o = NULL; ptr.option = "iprange"; - ptr.value = fw3_address_to_string(&s->iprange, false); + ptr.value = fw3_address_to_string(&s->iprange, false, false); uci_set(ctx, &ptr); } @@ -589,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; @@ -607,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); @@ -617,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); @@ -628,6 +666,9 @@ fw3_write_statefile(void *state) fsync(fileno(sf)); fclose(sf); + + if (ifaddr) + freeifaddrs(ifaddr); } } @@ -696,7 +737,7 @@ fw3_hotplug(bool add, void *zone, void *device) close(0); close(1); close(2); - chdir("/"); + if (chdir("/")) {}; clearenv(); setenv("ACTION", add ? "add" : "remove", 1); @@ -709,3 +750,148 @@ fw3_hotplug(bool add, void *zone, void *device) /* unreached */ return false; } + +int +fw3_netmask2bitlen(int family, void *mask) +{ + int bits; + struct in_addr *v4; + struct in6_addr *v6; + + if (family == FW3_FAMILY_V6) + for (bits = 0, v6 = mask; + bits < 128 && (v6->s6_addr[bits / 8] << (bits % 8)) & 128; + bits++); + else + for (bits = 0, v4 = mask; + bits < 32 && (ntohl(v4->s_addr) << bits) & 0x80000000; + bits++); + + return bits; +} + +bool +fw3_bitlen2netmask(int family, int bits, void *mask) +{ + int i; + uint8_t rem, b; + struct in_addr *v4; + struct in6_addr *v6; + + if (family == FW3_FAMILY_V6) + { + if (bits < -128 || bits > 128) + return false; + + v6 = mask; + rem = abs(bits); + + 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 < sizeof(v6->s6_addr); i++) + v6->s6_addr[i] = ~v6->s6_addr[i]; + } + else + { + if (bits < -32 || bits > 32) + return false; + + v4 = mask; + v4->s_addr = bits ? htonl(~((1 << (32 - abs(bits))) - 1)) : 0; + + if (bits < 0) + v4->s_addr = ~v4->s_addr; + } + + 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 (!ifa->ifa_addr || 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); +}