summaryrefslogtreecommitdiff
path: root/options.c
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2014-07-18 15:43:56 +0200
committerJo-Philipp Wich <jow@openwrt.org>2014-07-19 11:48:39 +0200
commitbba31cce0521e014109fc805671d4cff7ee9dbf6 (patch)
tree2a48c471acb221c85238f53d7266ef88ee217629 /options.c
parent0aaf63b89efb27bfa370aabc7550de10335abbe3 (diff)
downloadfirewall3-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>
Diffstat (limited to 'options.c')
-rw-r--r--options.c101
1 files changed, 57 insertions, 44 deletions
diff --git a/options.c b/options.c
index 25668fc..292f5fc 100644
--- a/options.c
+++ b/options.c
@@ -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;