X-Git-Url: http://git.archive.openwrt.org/?p=project%2Ffirewall3.git;a=blobdiff_plain;f=utils.c;h=875a141cc44fa2e2efb51ca8f3da673d77a5b1d6;hp=4f309559088ee27da28fbbcf26b419ec76274948;hb=6039c7f4b0052c4da21520cdd604f04a5a67f50d;hpb=a9c694d5b6ea026a0c745e5b650993bf0f1c13dc diff --git a/utils.c b/utils.c index 4f30955..875a141 100644 --- a/utils.c +++ b/utils.c @@ -1,7 +1,7 @@ /* * firewall3 - 3rd OpenWrt UCI firewall implementation * - * Copyright (C) 2013 Jo-Philipp Wich + * Copyright (C) 2013 Jo-Philipp Wich * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -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 }; @@ -462,11 +463,6 @@ write_zone_uci(struct uci_context *ctx, struct fw3_zone *z, 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"; uci_set(ctx, &ptr); @@ -489,18 +485,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); @@ -514,10 +513,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"; @@ -569,7 +597,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); } @@ -590,6 +618,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 +637,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 +653,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 +664,9 @@ fw3_write_statefile(void *state) fsync(fileno(sf)); fclose(sf); + + if (ifaddr) + freeifaddrs(ifaddr); } } @@ -710,3 +748,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); +}