luci-lib-ip: support scoped IPv6 addresses
Ref: https://github.com/openwrt/luci/issues/3380 Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
parent
ea6d0d2e1f
commit
f7a7f89e0c
2 changed files with 81 additions and 16 deletions
|
@ -62,6 +62,7 @@ typedef struct {
|
||||||
struct ether_addr mac;
|
struct ether_addr mac;
|
||||||
uint8_t u8[16];
|
uint8_t u8[16];
|
||||||
} addr;
|
} addr;
|
||||||
|
uint32_t scope;
|
||||||
uint16_t family;
|
uint16_t family;
|
||||||
int16_t bits;
|
int16_t bits;
|
||||||
} cidr_t;
|
} cidr_t;
|
||||||
|
@ -177,7 +178,7 @@ static bool parse_mask(int family, const char *mask, int16_t *bits)
|
||||||
|
|
||||||
static bool parse_cidr(const char *dest, cidr_t *pp)
|
static bool parse_cidr(const char *dest, cidr_t *pp)
|
||||||
{
|
{
|
||||||
char *p, buf[INET6_ADDRSTRLEN * 2 + 2];
|
char *p, *s, buf[INET6_ADDRSTRLEN * 2 + 2];
|
||||||
|
|
||||||
strncpy(buf, dest, sizeof(buf) - 1);
|
strncpy(buf, dest, sizeof(buf) - 1);
|
||||||
|
|
||||||
|
@ -186,6 +187,11 @@ static bool parse_cidr(const char *dest, cidr_t *pp)
|
||||||
if (p)
|
if (p)
|
||||||
*p++ = 0;
|
*p++ = 0;
|
||||||
|
|
||||||
|
s = strchr(buf, '%');
|
||||||
|
|
||||||
|
if (s)
|
||||||
|
*s++ = 0;
|
||||||
|
|
||||||
if (inet_pton(AF_INET, buf, &pp->addr.v4))
|
if (inet_pton(AF_INET, buf, &pp->addr.v4))
|
||||||
pp->family = AF_INET;
|
pp->family = AF_INET;
|
||||||
else if (inet_pton(AF_INET6, buf, &pp->addr.v6))
|
else if (inet_pton(AF_INET6, buf, &pp->addr.v6))
|
||||||
|
@ -195,6 +201,22 @@ static bool parse_cidr(const char *dest, cidr_t *pp)
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (s)
|
||||||
|
{
|
||||||
|
if (pp->family != AF_INET6)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!(pp->addr.v6.s6_addr[0] == 0xFE &&
|
||||||
|
pp->addr.v6.s6_addr[1] >= 0x80 &&
|
||||||
|
pp->addr.v6.s6_addr[2] <= 0xBF))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
pp->scope = if_nametoindex(s);
|
||||||
|
|
||||||
|
if (pp->scope == 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (p)
|
if (p)
|
||||||
{
|
{
|
||||||
if (!parse_mask(pp->family, p, &pp->bits))
|
if (!parse_mask(pp->family, p, &pp->bits))
|
||||||
|
@ -210,7 +232,7 @@ static bool parse_cidr(const char *dest, cidr_t *pp)
|
||||||
|
|
||||||
static int format_cidr(lua_State *L, cidr_t *p)
|
static int format_cidr(lua_State *L, cidr_t *p)
|
||||||
{
|
{
|
||||||
char buf[INET6_ADDRSTRLEN];
|
char *s, buf[INET6_ADDRSTRLEN + 1 + IF_NAMESIZE + 4];
|
||||||
|
|
||||||
if (p->family == AF_PACKET)
|
if (p->family == AF_PACKET)
|
||||||
{
|
{
|
||||||
|
@ -229,13 +251,19 @@ static int format_cidr(lua_State *L, cidr_t *p)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
inet_ntop(p->family, &p->addr.v6, buf, sizeof(buf));
|
||||||
|
|
||||||
|
s = buf + strlen(buf);
|
||||||
|
|
||||||
|
if (p->scope != 0 && if_indextoname(p->scope, s + 1) != NULL) {
|
||||||
|
*s++ = '%';
|
||||||
|
s += strlen(s);
|
||||||
|
}
|
||||||
|
|
||||||
if (p->bits < AF_BITS(p->family))
|
if (p->bits < AF_BITS(p->family))
|
||||||
lua_pushfstring(L, "%s/%d",
|
s += sprintf(s, "/%d", p->bits);
|
||||||
inet_ntop(p->family, &p->addr.v6, buf, sizeof(buf)),
|
|
||||||
p->bits);
|
lua_pushstring(L, buf);
|
||||||
else
|
|
||||||
lua_pushstring(L,
|
|
||||||
inet_ntop(p->family, &p->addr.v6, buf, sizeof(buf)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -765,6 +793,25 @@ static int cidr_mapped4(lua_State *L)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cidr_unscoped(lua_State *L)
|
||||||
|
{
|
||||||
|
cidr_t *p1 = L_checkcidr(L, 1, NULL);
|
||||||
|
cidr_t *p2;
|
||||||
|
|
||||||
|
if (p1->family != AF_INET6)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!(p2 = lua_newuserdata(L, sizeof(*p2))))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*p2 = *p1;
|
||||||
|
p2->scope = 0;
|
||||||
|
|
||||||
|
luaL_getmetatable(L, LUCI_IP_CIDR);
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int cidr_tolinklocal(lua_State *L)
|
static int cidr_tolinklocal(lua_State *L)
|
||||||
{
|
{
|
||||||
cidr_t *p1 = L_checkcidr(L, 1, NULL);
|
cidr_t *p1 = L_checkcidr(L, 1, NULL);
|
||||||
|
@ -1601,6 +1648,7 @@ static const luaL_reg ip_cidr_methods[] = {
|
||||||
{ "mask", cidr_mask },
|
{ "mask", cidr_mask },
|
||||||
{ "broadcast", cidr_broadcast },
|
{ "broadcast", cidr_broadcast },
|
||||||
{ "mapped4", cidr_mapped4 },
|
{ "mapped4", cidr_mapped4 },
|
||||||
|
{ "unscoped", cidr_unscoped },
|
||||||
{ "tomac", cidr_tomac },
|
{ "tomac", cidr_tomac },
|
||||||
{ "tolinklocal", cidr_tolinklocal },
|
{ "tolinklocal", cidr_tolinklocal },
|
||||||
{ "contains", cidr_contains },
|
{ "contains", cidr_contains },
|
||||||
|
|
|
@ -837,6 +837,23 @@ instances which are not a mapped address, it will return nothing in this case.
|
||||||
print(addr:mapped4()) -- "172.16.19.1"`
|
print(addr:mapped4()) -- "172.16.19.1"`
|
||||||
]]
|
]]
|
||||||
|
|
||||||
|
---[[
|
||||||
|
Derive unscoped IPv6 address of CIDR instance.
|
||||||
|
|
||||||
|
Construct a copy of the given IPv6 CIDR instance and drop the associated
|
||||||
|
address scope information.
|
||||||
|
|
||||||
|
This function has no effect on IPv4 instances or MAC address instances,
|
||||||
|
it will return nothing in this case.
|
||||||
|
|
||||||
|
@class function
|
||||||
|
@sort 19
|
||||||
|
@name cidr.unscoped
|
||||||
|
@return Return a new CIDR instance representing the unscoped IPv6 address.
|
||||||
|
@usage `local addr = luci.ip.new("fe80::1234%eth0")
|
||||||
|
print(addr:unscoped()) -- "fe80::1234"`
|
||||||
|
]]
|
||||||
|
|
||||||
---[[
|
---[[
|
||||||
Derive MAC address of IPv6 link local CIDR instance.
|
Derive MAC address of IPv6 link local CIDR instance.
|
||||||
|
|
||||||
|
@ -848,7 +865,7 @@ instances which are not a link local address, it will return nothing in this
|
||||||
case.
|
case.
|
||||||
|
|
||||||
@class function
|
@class function
|
||||||
@sort 19
|
@sort 20
|
||||||
@name cidr.tomac
|
@name cidr.tomac
|
||||||
@return Return a new CIDR instance representing the MAC address if this
|
@return Return a new CIDR instance representing the MAC address if this
|
||||||
instance is an IPv6 link local address, else return nothing.
|
instance is an IPv6 link local address, else return nothing.
|
||||||
|
@ -866,7 +883,7 @@ This function has no effect on IPv4 instances or IPv6 instances, it will return
|
||||||
nothing in this case.
|
nothing in this case.
|
||||||
|
|
||||||
@class function
|
@class function
|
||||||
@sort 20
|
@sort 21
|
||||||
@name cidr.tolinklocal
|
@name cidr.tolinklocal
|
||||||
@return Return a new CIDR instance representing the IPv6 link local address.
|
@return Return a new CIDR instance representing the IPv6 link local address.
|
||||||
@usage `local mac = luci.ip.new("64:66:B3:47:E1:B9")
|
@usage `local mac = luci.ip.new("64:66:B3:47:E1:B9")
|
||||||
|
@ -877,7 +894,7 @@ print(mac:tolinklocal()) -- "fe80::6666:b3ff:fe47:e1b9"`
|
||||||
Test whether CIDR contains given range.
|
Test whether CIDR contains given range.
|
||||||
|
|
||||||
@class function
|
@class function
|
||||||
@sort 21
|
@sort 22
|
||||||
@name cidr.contains
|
@name cidr.contains
|
||||||
@param addr A `luci.ip.cidr` instance or a string convertible by
|
@param addr A `luci.ip.cidr` instance or a string convertible by
|
||||||
`luci.ip.new()` to test.
|
`luci.ip.new()` to test.
|
||||||
|
@ -902,7 +919,7 @@ Add given amount to CIDR instance. If the result would overflow the maximum
|
||||||
address space, the result is set to the highest possible address.
|
address space, the result is set to the highest possible address.
|
||||||
|
|
||||||
@class function
|
@class function
|
||||||
@sort 22
|
@sort 23
|
||||||
@name cidr.add
|
@name cidr.add
|
||||||
@param amount A numeric value between 0 and 0xFFFFFFFF, a
|
@param amount A numeric value between 0 and 0xFFFFFFFF, a
|
||||||
`luci.ip.cidr` instance or a string convertible by
|
`luci.ip.cidr` instance or a string convertible by
|
||||||
|
@ -951,7 +968,7 @@ Subtract given amount from CIDR instance. If the result would under, the lowest
|
||||||
possible address is returned.
|
possible address is returned.
|
||||||
|
|
||||||
@class function
|
@class function
|
||||||
@sort 23
|
@sort 24
|
||||||
@name cidr.sub
|
@name cidr.sub
|
||||||
@param amount A numeric value between 0 and 0xFFFFFFFF, a
|
@param amount A numeric value between 0 and 0xFFFFFFFF, a
|
||||||
`luci.ip.cidr` instance or a string convertible by
|
`luci.ip.cidr` instance or a string convertible by
|
||||||
|
@ -999,7 +1016,7 @@ print(mac) -- "00:00:00:00:00:00"`
|
||||||
Calculate the lowest possible host address within this CIDR instance.
|
Calculate the lowest possible host address within this CIDR instance.
|
||||||
|
|
||||||
@class function
|
@class function
|
||||||
@sort 24
|
@sort 25
|
||||||
@name cidr.minhost
|
@name cidr.minhost
|
||||||
@return Returns a new CIDR instance representing the lowest host address
|
@return Returns a new CIDR instance representing the lowest host address
|
||||||
within this range.
|
within this range.
|
||||||
|
@ -1017,7 +1034,7 @@ print(mac:minhost()) -- "00:14:22:01:00:01"`
|
||||||
Calculate the highest possible host address within this CIDR instance.
|
Calculate the highest possible host address within this CIDR instance.
|
||||||
|
|
||||||
@class function
|
@class function
|
||||||
@sort 25
|
@sort 26
|
||||||
@name cidr.maxhost
|
@name cidr.maxhost
|
||||||
@return Returns a new CIDR instance representing the highest host address
|
@return Returns a new CIDR instance representing the highest host address
|
||||||
within this range.
|
within this range.
|
||||||
|
@ -1042,7 +1059,7 @@ It is usually not required to call this function directly as CIDR objects
|
||||||
define it as __tostring function in the associated metatable.
|
define it as __tostring function in the associated metatable.
|
||||||
|
|
||||||
@class function
|
@class function
|
||||||
@sort 26
|
@sort 27
|
||||||
@name cidr.string
|
@name cidr.string
|
||||||
@return Returns a string representing the range or address of this CIDR instance
|
@return Returns a string representing the range or address of this CIDR instance
|
||||||
]]
|
]]
|
||||||
|
|
Loading…
Reference in a new issue