diff options
| author | Jo-Philipp Wich | 2014-07-18 13:43:56 +0000 |
|---|---|---|
| committer | Jo-Philipp Wich | 2014-07-19 09:48:39 +0000 |
| commit | bba31cce0521e014109fc805671d4cff7ee9dbf6 (patch) | |
| tree | 2a48c471acb221c85238f53d7266ef88ee217629 | |
| parent | 0aaf63b89efb27bfa370aabc7550de10335abbe3 (diff) | |
| download | firewall3-bba31cce0521e014109fc805671d4cff7ee9dbf6.tar.gz | |
Use netmasks instead of prefix lengths internally
Iptables supports using non-continuous netmasks like FFFF::FFFF which would
match the first and last 16bit of an IPv6 address while ignoring the parts
in between which is useful fordeclaring rules targeting hosts on rotating
prefixes.
Instead of storing parsed netmasks as bitcount internally, use a full mask
which is passed to iptables as-is.
Also support a new shorthand notation "addr/-N" which will construct a mask
that matches the *last* N bits of an address - useful for matching the host
part only of an IPv4 address, e.g.
option dest_ip '::c23f:eff:fe7a:a094/-64'
This will convert to a netmask of "::ffff:ffff:ffff:ffff".
Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
| -rw-r--r-- | ipsets.c | 2 | ||||
| -rw-r--r-- | iptables.c | 64 | ||||
| -rw-r--r-- | options.c | 101 | ||||
| -rw-r--r-- | options.h | 5 | ||||
| -rw-r--r-- | redirects.c | 11 | ||||
| -rw-r--r-- | ubus.c | 4 | ||||
| -rw-r--r-- | utils.c | 61 | ||||
| -rw-r--r-- | utils.h | 4 |
8 files changed, 149 insertions, 103 deletions
@@ -303,7 +303,7 @@ create_ipset(struct fw3_ipset *ipset, struct fw3_state *state) if (ipset->iprange.set) { - fw3_pr(" range %s", fw3_address_to_string(&ipset->iprange, false)); + fw3_pr(" range %s", fw3_address_to_string(&ipset->iprange, false, true)); } else if (ipset->portrange.set) { @@ -606,34 +606,6 @@ fw3_ipt_rule_in_out(struct fw3_ipt_rule *r, } -static void -ip4prefix2mask(int prefix, struct in_addr *mask) -{ - if (prefix > 0) - mask->s_addr = htonl(~((1 << (32 - prefix)) - 1)); - else - mask->s_addr = 0; -} - -#ifndef DISABLE_IPV6 -static void -ip6prefix2mask(int prefix, struct in6_addr *mask) -{ - char *p = (char *)mask; - - if (prefix > 0) - { - memset(p, 0xff, prefix / 8); - memset(p + (prefix / 8) + 1, 0, (128 - prefix) / 8); - p[prefix / 8] = 0xff << (8 - (prefix & 7)); - } - else - { - memset(mask, 0, sizeof(*mask)); - } -} -#endif - void fw3_ipt_rule_src_dest(struct fw3_ipt_rule *r, struct fw3_address *src, struct fw3_address *dest) @@ -648,13 +620,13 @@ fw3_ipt_rule_src_dest(struct fw3_ipt_rule *r, if (src->range) { fw3_ipt_rule_addarg(r, src->invert, "--src-range", - fw3_address_to_string(src, false)); + fw3_address_to_string(src, false, false)); } #ifndef DISABLE_IPV6 else if (r->h->family == FW3_FAMILY_V6) { r->e6.ipv6.src = src->address.v6; - ip6prefix2mask(src->mask, &r->e6.ipv6.smsk); + r->e6.ipv6.smsk = src->mask.v6; int i; for (i = 0; i < 4; i++) @@ -667,7 +639,7 @@ fw3_ipt_rule_src_dest(struct fw3_ipt_rule *r, else { r->e.ip.src = src->address.v4; - ip4prefix2mask(src->mask, &r->e.ip.smsk); + r->e.ip.smsk = src->mask.v4; r->e.ip.src.s_addr &= r->e.ip.smsk.s_addr; @@ -681,13 +653,13 @@ fw3_ipt_rule_src_dest(struct fw3_ipt_rule *r, if (dest->range) { fw3_ipt_rule_addarg(r, dest->invert, "--dst-range", - fw3_address_to_string(dest, false)); + fw3_address_to_string(dest, false, false)); } #ifndef DISABLE_IPV6 else if (r->h->family == FW3_FAMILY_V6) { r->e6.ipv6.dst = dest->address.v6; - ip6prefix2mask(dest->mask, &r->e6.ipv6.dmsk); + r->e6.ipv6.dmsk = dest->mask.v6; int i; for (i = 0; i < 4; i++) @@ -700,7 +672,7 @@ fw3_ipt_rule_src_dest(struct fw3_ipt_rule *r, else { r->e.ip.dst = dest->address.v4; - ip4prefix2mask(dest->mask, &r->e.ip.dmsk); + r->e.ip.dmsk = dest->mask.v4; r->e.ip.dst.s_addr &= r->e.ip.dmsk.s_addr; @@ -1003,7 +975,7 @@ fw3_ipt_rule_extra(struct fw3_ipt_rule *r, const char *extra) static void rule_print6(struct ip6t_entry *e) { - char buf[INET6_ADDRSTRLEN]; + char buf1[INET6_ADDRSTRLEN], buf2[INET6_ADDRSTRLEN]; char *pname; if (e->ipv6.flags & IP6T_F_PROTO) @@ -1040,8 +1012,9 @@ rule_print6(struct ip6t_entry *e) if (e->ipv6.flags & IP6T_INV_SRCIP) printf(" !"); - printf(" -s %s/%u", inet_ntop(AF_INET6, &e->ipv6.src, buf, sizeof(buf)), - xtables_ip6mask_to_cidr(&e->ipv6.smsk)); + printf(" -s %s/%s", + inet_ntop(AF_INET6, &e->ipv6.src, buf1, sizeof(buf1)), + inet_ntop(AF_INET6, &e->ipv6.smsk, buf2, sizeof(buf2))); } if (memcmp(&e->ipv6.dst, &in6addr_any, sizeof(struct in6_addr))) @@ -1049,8 +1022,9 @@ rule_print6(struct ip6t_entry *e) if (e->ipv6.flags & IP6T_INV_DSTIP) printf(" !"); - printf(" -d %s/%u", inet_ntop(AF_INET6, &e->ipv6.dst, buf, sizeof(buf)), - xtables_ip6mask_to_cidr(&e->ipv6.dmsk)); + printf(" -d %s/%s", + inet_ntop(AF_INET6, &e->ipv6.dst, buf1, sizeof(buf1)), + inet_ntop(AF_INET6, &e->ipv6.dmsk, buf2, sizeof(buf2))); } } #endif @@ -1059,7 +1033,7 @@ static void rule_print4(struct ipt_entry *e) { struct in_addr in_zero = { 0 }; - char buf[sizeof("255.255.255.255\0")]; + char buf1[sizeof("255.255.255.255\0")], buf2[sizeof("255.255.255.255\0")]; char *pname; if (e->ip.proto) @@ -1096,8 +1070,9 @@ rule_print4(struct ipt_entry *e) if (e->ip.flags & IPT_INV_SRCIP) printf(" !"); - printf(" -s %s/%u", inet_ntop(AF_INET, &e->ip.src, buf, sizeof(buf)), - xtables_ipmask_to_cidr(&e->ip.smsk)); + printf(" -s %s/%s", + inet_ntop(AF_INET, &e->ip.src, buf1, sizeof(buf1)), + inet_ntop(AF_INET, &e->ip.smsk, buf2, sizeof(buf2))); } if (memcmp(&e->ip.dst, &in_zero, sizeof(struct in_addr))) @@ -1105,8 +1080,9 @@ rule_print4(struct ipt_entry *e) if (e->ip.flags & IPT_INV_DSTIP) printf(" !"); - printf(" -d %s/%u", inet_ntop(AF_INET, &e->ip.dst, buf, sizeof(buf)), - xtables_ipmask_to_cidr(&e->ip.dmsk)); + printf(" -d %s/%s", + inet_ntop(AF_INET, &e->ip.dst, buf1, sizeof(buf1)), + inet_ntop(AF_INET, &e->ip.dmsk, buf2, sizeof(buf2))); } } @@ -244,8 +244,8 @@ fw3_parse_address(void *ptr, const char *val, bool is_list) struct fw3_address addr = { }; struct in_addr v4; struct in6_addr v6; - char *p, *s, *e; - int i, m = -1; + char *p = NULL, *m = NULL, *s, *e; + int bits = -1; if (*val == '!') { @@ -258,71 +258,76 @@ fw3_parse_address(void *ptr, const char *val, bool is_list) if (!s) return false; - if ((p = strchr(s, '/')) != NULL) - { + if ((m = strchr(s, '/')) != NULL) + *m++ = 0; + else if ((p = strchr(s, '-')) != NULL) *p++ = 0; - m = strtoul(p, &e, 10); - if ((e == p) || (*e != 0)) - { - if (strchr(s, ':') || !inet_pton(AF_INET, p, &v4)) - { - free(s); - return false; - } - - for (i = 0, m = 32; !(v4.s_addr & 1) && (i < 32); i++) - { - m--; - v4.s_addr >>= 1; - } - } - } - else if ((p = strchr(s, '-')) != NULL) + if (inet_pton(AF_INET6, s, &v6)) { - *p++ = 0; + addr.family = FW3_FAMILY_V6; + addr.address.v6 = v6; - if (inet_pton(AF_INET6, p, &v6)) + if (m && !inet_pton(AF_INET6, m, &addr.mask.v6)) { - addr.family = FW3_FAMILY_V6; - addr.address2.v6 = v6; - addr.range = true; + bits = strtol(m, &e, 10); + + if ((*e != 0) || !fw3_bitlen2netmask(addr.family, bits, &v6)) + goto fail; + + addr.mask.v6 = v6; } - else if (inet_pton(AF_INET, p, &v4)) + else if (p) { - addr.family = FW3_FAMILY_V4; - addr.address2.v4 = v4; + if (!inet_pton(AF_INET6, p, &addr.mask.v6)) + goto fail; + addr.range = true; } else { - free(s); - return false; + memset(addr.mask.v6.s6_addr, 0xFF, 16); } } - - if (inet_pton(AF_INET6, s, &v6)) - { - addr.family = FW3_FAMILY_V6; - addr.address.v6 = v6; - addr.mask = (m >= 0) ? m : 128; - } else if (inet_pton(AF_INET, s, &v4)) { addr.family = FW3_FAMILY_V4; addr.address.v4 = v4; - addr.mask = (m >= 0) ? m : 32; + + if (m && !inet_pton(AF_INET, m, &addr.mask.v4)) + { + bits = strtol(m, &e, 10); + + if ((*e != 0) || !fw3_bitlen2netmask(addr.family, bits, &v4)) + goto fail; + + addr.mask.v4 = v4; + } + else if (p) + { + if (!inet_pton(AF_INET, p, &addr.mask.v4)) + goto fail; + + addr.range = true; + } + else + { + addr.mask.v4.s_addr = 0xFFFFFFFF; + } } else { - free(s); - return false; + goto fail; } free(s); addr.set = true; put_value(ptr, &addr, sizeof(addr), is_list); return true; + +fail: + free(s); + return false; } bool @@ -1070,7 +1075,7 @@ fw3_parse_blob_options(void *s, const struct fw3_option *opts, const char * -fw3_address_to_string(struct fw3_address *address, bool allow_invert) +fw3_address_to_string(struct fw3_address *address, bool allow_invert, bool as_cidr) { char *p, ip[INET6_ADDRSTRLEN]; static char buf[INET6_ADDRSTRLEN * 2 + 2]; @@ -1088,13 +1093,21 @@ fw3_address_to_string(struct fw3_address *address, bool allow_invert) if (address->range) { inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, - &address->address2.v4, ip, sizeof(ip)); + &address->mask.v4, ip, sizeof(ip)); p += sprintf(p, "-%s", ip); } + else if (!as_cidr) + { + inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, + &address->mask.v4, ip, sizeof(ip)); + + p += sprintf(p, "/%s", ip); + } else { - p += sprintf(p, "/%u", address->mask); + p += sprintf(p, "/%u", fw3_netmask2bitlen(address->family, + &address->mask.v6)); } return buf; @@ -175,7 +175,6 @@ struct fw3_address bool invert; bool resolved; enum fw3_family family; - int mask; union { struct in_addr v4; struct in6_addr v6; @@ -185,7 +184,7 @@ struct fw3_address struct in_addr v4; struct in6_addr v6; struct ether_addr mac; - } address2; + } mask; }; struct fw3_mac @@ -563,6 +562,6 @@ bool fw3_parse_blob_options(void *s, const struct fw3_option *opts, struct blob_attr *a); const char * fw3_address_to_string(struct fw3_address *address, - bool allow_invert); + bool allow_invert, bool as_cidr); #endif diff --git a/redirects.c b/redirects.c index 080e2c1..5dea21f 100644 --- a/redirects.c +++ b/redirects.c @@ -116,14 +116,11 @@ check_families(struct uci_element *e, struct fw3_redirect *r) 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 @@ -603,8 +600,8 @@ expand_redirect(struct fw3_ipt_handle *handle, struct fw3_state *state, 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); @@ -94,10 +94,10 @@ parse_subnet(enum fw3_family family, struct blob_attr *dict, int rem) { if (!strcmp(blobmsg_name(cur), "address")) inet_pton(family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, - blobmsg_data(cur), &addr->address.v6); + blobmsg_get_string(cur), &addr->address.v6); else if (!strcmp(blobmsg_name(cur), "mask")) - addr->mask = be32_to_cpu(*(uint32_t *)blobmsg_data(cur)); + fw3_bitlen2netmask(family, blobmsg_get_u32(cur), &addr->mask.v6); } return addr; @@ -514,7 +514,7 @@ 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); } @@ -569,7 +569,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); } @@ -710,3 +710,60 @@ 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; + struct in_addr *v4; + struct in6_addr *v6; + + if (family == FW3_FAMILY_V6) + { + if (bits < -128 || bits > 128) + return false; + + v6 = mask; + i = abs(bits); + + memset(v6->s6_addr, 0xff, i / 8); + memset(v6->s6_addr + (i / 8) + 1, 0, (128 - i) / 8); + v6->s6_addr[i / 8] = 0xff << (8 - (i & 7)); + + if (bits < 0) + for (i = 0; i < 16; i++) + v6->s6_addr[i] = ~v6->s6_addr[i]; + } + else + { + if (bits < -32 || bits > 32) + return false; + + v4 = mask; + v4->s_addr = htonl(~((1 << (32 - abs(bits))) - 1)); + + if (bits < 0) + v4->s_addr = ~v4->s_addr; + } + + return true; +} @@ -95,4 +95,8 @@ void fw3_free_list(struct list_head *head); bool fw3_hotplug(bool add, void *zone, void *device); +int fw3_netmask2bitlen(int family, void *mask); + +bool fw3_bitlen2netmask(int family, int bits, void *mask); + #endif |