summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2015-01-28 14:21:01 +0100
committerJo-Philipp Wich <jow@openwrt.org>2015-01-28 14:21:04 +0100
commite6e74b712fe6fd87cb19e89203e4ef45d7459458 (patch)
treec969bfd546f7cc784d39950d33ad0fbe2b69ac37
parent65f0135491112341fc3af8559537eab85aa47e18 (diff)
luci-lib-ip: add functions to deal with IPv6 mapped IPv6
* Add luci.ip.cidr.is6mapped4() to test whether an IPv6 CIDR is a mapped IPv4 one * Add luci.ip.cidr.mapped4() to derive IPv4 from mapped CIDR * Remove mapped IPv4 workaround from constructor as it breaks genuine addrs like ::ffff:0 Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
-rw-r--r--libs/luci-lib-ip/src/ip.c57
1 files changed, 50 insertions, 7 deletions
diff --git a/libs/luci-lib-ip/src/ip.c b/libs/luci-lib-ip/src/ip.c
index 595ac8c3a5..b91966c536 100644
--- a/libs/luci-lib-ip/src/ip.c
+++ b/libs/luci-lib-ip/src/ip.c
@@ -126,27 +126,23 @@ static bool parse_mask(int family, const char *mask, int *bits)
static bool parse_cidr(const char *dest, cidr_t *pp)
{
- char *p, *a, buf[INET6_ADDRSTRLEN * 2 + 2];
+ char *p, buf[INET6_ADDRSTRLEN * 2 + 2];
uint8_t bitlen = 0;
strncpy(buf, dest, sizeof(buf) - 1);
- a = buf;
p = strchr(buf, '/');
if (p)
*p++ = 0;
- if (!strncasecmp(buf, "::ffff:", 7))
- a += 7;
-
- if (inet_pton(AF_INET, a, &pp->addr.v4))
+ if (inet_pton(AF_INET, buf, &pp->addr.v4))
{
bitlen = 32;
pp->family = AF_INET;
pp->len = sizeof(struct in_addr);
}
- else if (inet_pton(AF_INET6, a, &pp->addr.v6))
+ else if (inet_pton(AF_INET6, buf, &pp->addr.v6))
{
bitlen = 128;
pp->family = AF_INET6;
@@ -383,6 +379,31 @@ static int cidr_is4linklocal(lua_State *L)
return 1;
}
+static bool _is_mapped4(cidr_t *p)
+{
+ return (p->family == AF_INET6 &&
+ p->addr.v6.s6_addr[0] == 0 &&
+ p->addr.v6.s6_addr[1] == 0 &&
+ p->addr.v6.s6_addr[2] == 0 &&
+ p->addr.v6.s6_addr[3] == 0 &&
+ p->addr.v6.s6_addr[4] == 0 &&
+ p->addr.v6.s6_addr[5] == 0 &&
+ p->addr.v6.s6_addr[6] == 0 &&
+ p->addr.v6.s6_addr[7] == 0 &&
+ p->addr.v6.s6_addr[8] == 0 &&
+ p->addr.v6.s6_addr[9] == 0 &&
+ p->addr.v6.s6_addr[10] == 0xFF &&
+ p->addr.v6.s6_addr[11] == 0xFF);
+}
+
+static int cidr_is6mapped4(lua_State *L)
+{
+ cidr_t *p = L_checkcidr(L, 1, NULL);
+
+ lua_pushboolean(L, _is_mapped4(p));
+ return 1;
+}
+
static int cidr_is6(lua_State *L)
{
cidr_t *p = L_checkcidr(L, 1, NULL);
@@ -550,6 +571,26 @@ static int cidr_broadcast(lua_State *L)
return 1;
}
+static int cidr_mapped4(lua_State *L)
+{
+ cidr_t *p1 = L_checkcidr(L, 1, NULL);
+ cidr_t *p2;
+
+ if (!_is_mapped4(p1))
+ return 0;
+
+ if (!(p2 = lua_newuserdata(L, sizeof(*p2))))
+ return 0;
+
+ p2->family = AF_INET;
+ p2->bits = (p1->bits > 32) ? 32 : p1->bits;
+ memcpy(&p2->addr.v4, p1->addr.v6.s6_addr + 12, sizeof(p2->addr.v4));
+
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
static int cidr_contains(lua_State *L)
{
cidr_t *p1 = L_checkcidr(L, 1, NULL);
@@ -1309,6 +1350,7 @@ static const luaL_reg ip_cidr_methods[] = {
{ "is4linklocal", cidr_is4linklocal },
{ "is6", cidr_is6 },
{ "is6linklocal", cidr_is6linklocal },
+ { "is6mapped4", cidr_is6mapped4 },
{ "lower", cidr_lower },
{ "higher", cidr_higher },
{ "equal", cidr_equal },
@@ -1317,6 +1359,7 @@ static const luaL_reg ip_cidr_methods[] = {
{ "host", cidr_host },
{ "mask", cidr_mask },
{ "broadcast", cidr_broadcast },
+ { "mapped4", cidr_mapped4 },
{ "contains", cidr_contains },
{ "add", cidr_add },
{ "sub", cidr_sub },