2 Copyright 2015-2018 Jo-Philipp Wich <jo@mein.io>
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
32 #include <netinet/ether.h>
33 #include <arpa/inet.h>
34 #include <netlink/msg.h>
35 #include <netlink/attr.h>
36 #include <netlink/socket.h>
37 #include <linux/rtnetlink.h>
39 #define LUCI_IP "luci.ip"
40 #define LUCI_IP_CIDR "luci.ip.cidr"
42 #define RTA_INT(x) (*(int *)RTA_DATA(x))
43 #define RTA_U32(x) (*(uint32_t *)RTA_DATA(x))
46 ((f) == AF_INET ? 32 : \
47 ((f) == AF_INET6 ? 128 : \
48 ((f) == AF_PACKET ? 48 : 0)))
51 ((f) == AF_INET ? 4 : \
52 ((f) == AF_INET6 ? 16 : \
53 ((f) == AF_PACKET ? 6 : 0)))
56 static struct nl_sock
*sock
= NULL
;
62 struct ether_addr mac
;
83 struct ether_addr mac
;
93 struct dump_filter
*filter
;
97 static int _cidr_new(lua_State
*L
, int index
, int family
, bool mask
);
99 static cidr_t
*L_checkcidr (lua_State
*L
, int index
, cidr_t
*p
)
101 if (lua_type(L
, index
) == LUA_TUSERDATA
)
102 return luaL_checkudata(L
, index
, LUCI_IP_CIDR
);
104 if (_cidr_new(L
, index
, p
? p
->family
: 0, false))
105 return lua_touserdata(L
, -1);
107 luaL_error(L
, "Invalid operand");
111 static bool parse_mac(const char *mac
, struct ether_addr
*ea
)
117 for (i
= 0; i
< 6; i
++)
121 if (sep
== 0 && (mac
[0] == ':' || mac
[0] == '-'))
124 if (sep
== 0 || mac
[0] != sep
)
130 n
= strtoul(mac
, &e
, 16);
136 ea
->ether_addr_octet
[i
] = n
;
145 static bool parse_mask(int family
, const char *mask
, int16_t *bits
)
151 struct ether_addr mac
;
155 if (family
== AF_INET
&& inet_pton(AF_INET
, mask
, &m
.v4
))
157 for (*bits
= 0, m
.v4
.s_addr
= ntohl(m
.v4
.s_addr
);
158 *bits
< AF_BITS(AF_INET
) && (m
.v4
.s_addr
<< *bits
) & 0x80000000;
161 else if ((family
== AF_INET6
&& inet_pton(AF_INET6
, mask
, &m
.v6
)) ||
162 (family
== AF_PACKET
&& parse_mac(mask
, &m
.mac
)))
165 *bits
< AF_BITS(family
) && (m
.u8
[*bits
/ 8] << (*bits
% 8)) & 128;
170 *bits
= strtoul(mask
, &e
, 10);
172 if (e
== mask
|| *e
!= 0 || *bits
> AF_BITS(family
))
179 static bool parse_cidr(const char *dest
, cidr_t
*pp
)
181 char *p
, *s
, buf
[INET6_ADDRSTRLEN
* 2 + 2];
183 strncpy(buf
, dest
, sizeof(buf
) - 1);
185 p
= strchr(buf
, '/');
190 s
= strchr(buf
, '%');
195 if (inet_pton(AF_INET
, buf
, &pp
->addr
.v4
))
196 pp
->family
= AF_INET
;
197 else if (inet_pton(AF_INET6
, buf
, &pp
->addr
.v6
))
198 pp
->family
= AF_INET6
;
199 else if (parse_mac(buf
, &pp
->addr
.mac
))
200 pp
->family
= AF_PACKET
;
206 if (pp
->family
!= AF_INET6
)
209 if (!(pp
->addr
.v6
.s6_addr
[0] == 0xFE &&
210 pp
->addr
.v6
.s6_addr
[1] >= 0x80 &&
211 pp
->addr
.v6
.s6_addr
[2] <= 0xBF))
214 pp
->scope
= if_nametoindex(s
);
225 if (!parse_mask(pp
->family
, p
, &pp
->bits
))
230 pp
->bits
= AF_BITS(pp
->family
);
236 static int format_cidr(lua_State
*L
, cidr_t
*p
)
238 char *s
, buf
[INET6_ADDRSTRLEN
+ 1 + IF_NAMESIZE
+ 4];
240 if (p
->family
== AF_PACKET
)
242 snprintf(buf
, sizeof(buf
), "%02X:%02X:%02X:%02X:%02X:%02X",
243 p
->addr
.mac
.ether_addr_octet
[0],
244 p
->addr
.mac
.ether_addr_octet
[1],
245 p
->addr
.mac
.ether_addr_octet
[2],
246 p
->addr
.mac
.ether_addr_octet
[3],
247 p
->addr
.mac
.ether_addr_octet
[4],
248 p
->addr
.mac
.ether_addr_octet
[5]);
250 if (p
->bits
< AF_BITS(AF_PACKET
))
251 lua_pushfstring(L
, "%s/%d", buf
, p
->bits
);
253 lua_pushstring(L
, buf
);
257 inet_ntop(p
->family
, &p
->addr
.v6
, buf
, sizeof(buf
));
259 s
= buf
+ strlen(buf
);
261 if (p
->scope
!= 0 && if_indextoname(p
->scope
, s
+ 1) != NULL
) {
266 if (p
->bits
< AF_BITS(p
->family
))
267 s
+= sprintf(s
, "/%d", p
->bits
);
269 lua_pushstring(L
, buf
);
275 static int L_getint(lua_State
*L
, int index
, const char *name
)
279 lua_getfield(L
, index
, name
);
281 if (lua_type(L
, -1) == LUA_TNUMBER
)
282 rv
= lua_tonumber(L
, -1);
289 static const char * L_getstr(lua_State
*L
, int index
, const char *name
)
291 const char *rv
= NULL
;
293 lua_getfield(L
, index
, name
);
295 if (lua_type(L
, -1) == LUA_TSTRING
)
296 rv
= lua_tostring(L
, -1);
303 static void L_setint(struct lua_State
*L
, const char *name
, uint32_t n
)
305 lua_pushinteger(L
, n
);
306 lua_setfield(L
, -2, name
);
309 static void L_setbool(struct lua_State
*L
, const char *name
, bool val
)
311 lua_pushboolean(L
, val
);
312 lua_setfield(L
, -2, name
);
315 static void L_setaddr(struct lua_State
*L
, const char *name
,
316 int family
, void *addr
, int bits
)
323 p
= lua_newuserdata(L
, sizeof(*p
));
328 if (family
== AF_INET
)
331 p
->bits
= (bits
< 0) ? AF_BITS(AF_INET
) : bits
;
332 p
->addr
.v4
= *(struct in_addr
*)addr
;
335 else if (family
== AF_INET6
)
337 p
->family
= AF_INET6
;
338 p
->bits
= (bits
< 0) ? AF_BITS(AF_INET6
) : bits
;
339 p
->addr
.v6
= *(struct in6_addr
*)addr
;
344 p
->family
= AF_PACKET
;
345 p
->bits
= (bits
< 0) ? AF_BITS(AF_PACKET
) : bits
;
346 p
->addr
.mac
= *(struct ether_addr
*)addr
;
350 luaL_getmetatable(L
, LUCI_IP_CIDR
);
351 lua_setmetatable(L
, -2);
352 lua_setfield(L
, -2, name
);
355 static void L_setstr(struct lua_State
*L
, const char *name
, const char *val
)
357 lua_pushstring(L
, val
);
358 lua_setfield(L
, -2, name
);
361 static void L_setdev(struct lua_State
*L
, const char *name
,
366 if (if_indextoname(RTA_INT(attr
), buf
))
367 L_setstr(L
, name
, buf
);
370 static int L_checkbits(lua_State
*L
, int index
, cidr_t
*p
)
375 if (lua_gettop(L
) < index
|| lua_isnil(L
, index
))
379 else if (lua_type(L
, index
) == LUA_TNUMBER
)
381 bits
= lua_tointeger(L
, index
);
383 if (bits
< 0 || bits
> AF_BITS(p
->family
))
384 return luaL_error(L
, "Invalid prefix size");
386 else if (lua_type(L
, index
) == LUA_TSTRING
)
388 if (!parse_mask(p
->family
, lua_tostring(L
, index
), &s16
))
389 return luaL_error(L
, "Invalid netmask format");
395 return luaL_error(L
, "Invalid data type");
401 static int _cidr_new(lua_State
*L
, int index
, int family
, bool mask
)
405 cidr_t cidr
= { }, *cidrp
;
407 if (lua_type(L
, index
) == LUA_TNUMBER
)
409 n
= htonl(lua_tointeger(L
, index
));
411 if (family
== AF_INET6
)
413 cidr
.family
= AF_INET6
;
414 cidr
.addr
.v6
.s6_addr
[12] = n
;
415 cidr
.addr
.v6
.s6_addr
[13] = (n
>> 8);
416 cidr
.addr
.v6
.s6_addr
[14] = (n
>> 16);
417 cidr
.addr
.v6
.s6_addr
[15] = (n
>> 24);
419 else if (family
== AF_INET
)
421 cidr
.family
= AF_INET
;
422 cidr
.addr
.v4
.s_addr
= n
;
426 cidr
.family
= AF_PACKET
;
427 cidr
.addr
.mac
.ether_addr_octet
[2] = n
;
428 cidr
.addr
.mac
.ether_addr_octet
[3] = (n
>> 8);
429 cidr
.addr
.mac
.ether_addr_octet
[4] = (n
>> 16);
430 cidr
.addr
.mac
.ether_addr_octet
[5] = (n
>> 24);
433 cidr
.bits
= AF_BITS(cidr
.family
);
437 addr
= luaL_checkstring(L
, index
);
439 if (!parse_cidr(addr
, &cidr
))
442 if (family
&& cidr
.family
!= family
)
446 cidr
.bits
= L_checkbits(L
, index
+ 1, &cidr
);
449 if (!(cidrp
= lua_newuserdata(L
, sizeof(*cidrp
))))
453 luaL_getmetatable(L
, LUCI_IP_CIDR
);
454 lua_setmetatable(L
, -2);
458 static int cidr_new(lua_State
*L
)
460 return _cidr_new(L
, 1, 0, true);
463 static int cidr_ipv4(lua_State
*L
)
465 return _cidr_new(L
, 1, AF_INET
, true);
468 static int cidr_ipv6(lua_State
*L
)
470 return _cidr_new(L
, 1, AF_INET6
, true);
473 static int cidr_mac(lua_State
*L
)
475 return _cidr_new(L
, 1, AF_PACKET
, true);
478 static int cidr_check(lua_State
*L
, int family
)
480 cidr_t cidr
= { }, *cidrp
;
483 if (lua_type(L
, 1) == LUA_TSTRING
)
485 addr
= lua_tostring(L
, 1);
487 if (addr
&& parse_cidr(addr
, &cidr
) && cidr
.family
== family
)
488 return format_cidr(L
, &cidr
);
492 cidrp
= lua_touserdata(L
, 1);
497 if (!lua_getmetatable(L
, 1))
500 lua_getfield(L
, LUA_REGISTRYINDEX
, LUCI_IP_CIDR
);
502 if (!lua_rawequal(L
, -1, -2))
507 if (cidrp
!= NULL
&& cidrp
->family
== family
)
508 return format_cidr(L
, cidrp
);
514 static int cidr_checkip4(lua_State
*L
)
516 return cidr_check(L
, AF_INET
);
519 static int cidr_checkip6(lua_State
*L
)
521 return cidr_check(L
, AF_INET6
);
524 static int cidr_checkmac(lua_State
*L
)
526 return cidr_check(L
, AF_PACKET
);
529 static int cidr_is4(lua_State
*L
)
531 cidr_t
*p
= L_checkcidr(L
, 1, NULL
);
533 lua_pushboolean(L
, p
->family
== AF_INET
);
537 static int cidr_is4rfc1918(lua_State
*L
)
539 cidr_t
*p
= L_checkcidr(L
, 1, NULL
);
540 uint32_t a
= htonl(p
->addr
.v4
.s_addr
);
542 lua_pushboolean(L
, (p
->family
== AF_INET
&&
543 ((a
>= 0x0A000000 && a
<= 0x0AFFFFFF) ||
544 (a
>= 0xAC100000 && a
<= 0xAC1FFFFF) ||
545 (a
>= 0xC0A80000 && a
<= 0xC0A8FFFF))));
550 static int cidr_is4linklocal(lua_State
*L
)
552 cidr_t
*p
= L_checkcidr(L
, 1, NULL
);
553 uint32_t a
= htonl(p
->addr
.v4
.s_addr
);
555 lua_pushboolean(L
, (p
->family
== AF_INET
&&
562 static bool _is_mapped4(cidr_t
*p
)
564 return (p
->family
== AF_INET6
&&
565 p
->addr
.v6
.s6_addr
[0] == 0 &&
566 p
->addr
.v6
.s6_addr
[1] == 0 &&
567 p
->addr
.v6
.s6_addr
[2] == 0 &&
568 p
->addr
.v6
.s6_addr
[3] == 0 &&
569 p
->addr
.v6
.s6_addr
[4] == 0 &&
570 p
->addr
.v6
.s6_addr
[5] == 0 &&
571 p
->addr
.v6
.s6_addr
[6] == 0 &&
572 p
->addr
.v6
.s6_addr
[7] == 0 &&
573 p
->addr
.v6
.s6_addr
[8] == 0 &&
574 p
->addr
.v6
.s6_addr
[9] == 0 &&
575 p
->addr
.v6
.s6_addr
[10] == 0xFF &&
576 p
->addr
.v6
.s6_addr
[11] == 0xFF);
579 static int cidr_is6mapped4(lua_State
*L
)
581 cidr_t
*p
= L_checkcidr(L
, 1, NULL
);
583 lua_pushboolean(L
, _is_mapped4(p
));
587 static int cidr_is6(lua_State
*L
)
589 cidr_t
*p
= L_checkcidr(L
, 1, NULL
);
591 lua_pushboolean(L
, p
->family
== AF_INET6
);
595 static int cidr_is6linklocal(lua_State
*L
)
597 cidr_t
*p
= L_checkcidr(L
, 1, NULL
);
599 lua_pushboolean(L
, (p
->family
== AF_INET6
&&
600 p
->addr
.v6
.s6_addr
[0] == 0xFE &&
601 p
->addr
.v6
.s6_addr
[1] >= 0x80 &&
602 p
->addr
.v6
.s6_addr
[1] <= 0xBF));
607 static int cidr_ismac(lua_State
*L
)
609 cidr_t
*p
= L_checkcidr(L
, 1, NULL
);
611 lua_pushboolean(L
, p
->family
== AF_PACKET
);
615 static int cidr_ismacmcast(lua_State
*L
)
617 cidr_t
*p
= L_checkcidr(L
, 1, NULL
);
619 lua_pushboolean(L
, (p
->family
== AF_PACKET
&&
620 (p
->addr
.mac
.ether_addr_octet
[0] & 0x1)));
625 static int cidr_ismaclocal(lua_State
*L
)
627 cidr_t
*p
= L_checkcidr(L
, 1, NULL
);
629 lua_pushboolean(L
, (p
->family
== AF_PACKET
&&
630 (p
->addr
.mac
.ether_addr_octet
[0] & 0x2)));
635 static int _cidr_cmp(lua_State
*L
)
637 cidr_t
*a
= L_checkcidr(L
, 1, NULL
);
638 cidr_t
*b
= L_checkcidr(L
, 2, NULL
);
640 if (a
->family
!= b
->family
)
641 return (a
->family
- b
->family
);
643 return memcmp(&a
->addr
.v6
, &b
->addr
.v6
, AF_BYTES(a
->family
));
646 static int cidr_lower(lua_State
*L
)
648 lua_pushboolean(L
, _cidr_cmp(L
) < 0);
652 static int cidr_higher(lua_State
*L
)
654 lua_pushboolean(L
, _cidr_cmp(L
) > 0);
658 static int cidr_equal(lua_State
*L
)
660 lua_pushboolean(L
, _cidr_cmp(L
) == 0);
664 static int cidr_lower_equal(lua_State
*L
)
666 lua_pushboolean(L
, _cidr_cmp(L
) <= 0);
670 static int cidr_prefix(lua_State
*L
)
672 cidr_t
*p
= L_checkcidr(L
, 1, NULL
);
673 int bits
= L_checkbits(L
, 2, p
);
676 lua_pushinteger(L
, p
->bits
);
680 static void _apply_mask(cidr_t
*p
, int bits
, bool inv
)
686 memset(&p
->addr
.u8
, inv
* 0xFF, AF_BYTES(p
->family
));
688 else if (p
->family
== AF_INET
&& bits
<= AF_BITS(AF_INET
))
691 p
->addr
.v4
.s_addr
|= ntohl((1 << (AF_BITS(AF_INET
) - bits
)) - 1);
693 p
->addr
.v4
.s_addr
&= ntohl(~((1 << (AF_BITS(AF_INET
) - bits
)) - 1));
695 else if (bits
<= AF_BITS(p
->family
))
697 for (i
= 0; i
< AF_BYTES(p
->family
); i
++)
699 b
= (bits
> 8) ? 8 : bits
;
701 p
->addr
.u8
[i
] |= ~((uint8_t)(0xFF << (8 - b
)));
703 p
->addr
.u8
[i
] &= (uint8_t)(0xFF << (8 - b
));
709 static int cidr_network(lua_State
*L
)
711 cidr_t
*p1
= L_checkcidr(L
, 1, NULL
), *p2
;
712 int bits
= L_checkbits(L
, 2, p1
);
714 if (!(p2
= lua_newuserdata(L
, sizeof(*p2
))))
718 p2
->bits
= AF_BITS(p1
->family
);
719 _apply_mask(p2
, bits
, false);
721 luaL_getmetatable(L
, LUCI_IP_CIDR
);
722 lua_setmetatable(L
, -2);
726 static int cidr_host(lua_State
*L
)
728 cidr_t
*p1
= L_checkcidr(L
, 1, NULL
);
729 cidr_t
*p2
= lua_newuserdata(L
, sizeof(*p2
));
735 p2
->bits
= AF_BITS(p1
->family
);
737 luaL_getmetatable(L
, LUCI_IP_CIDR
);
738 lua_setmetatable(L
, -2);
742 static int cidr_mask(lua_State
*L
)
744 cidr_t
*p1
= L_checkcidr(L
, 1, NULL
), *p2
;
745 int bits
= L_checkbits(L
, 2, p1
);
747 if (!(p2
= lua_newuserdata(L
, sizeof(*p2
))))
750 p2
->bits
= AF_BITS(p1
->family
);
751 p2
->family
= p1
->family
;
753 memset(&p2
->addr
.v6
.s6_addr
, 0xFF, sizeof(p2
->addr
.v6
.s6_addr
));
754 _apply_mask(p2
, bits
, false);
756 luaL_getmetatable(L
, LUCI_IP_CIDR
);
757 lua_setmetatable(L
, -2);
761 static int cidr_broadcast(lua_State
*L
)
763 cidr_t
*p1
= L_checkcidr(L
, 1, NULL
);
765 int bits
= L_checkbits(L
, 2, p1
);
767 if (p1
->family
!= AF_INET
)
770 if (!(p2
= lua_newuserdata(L
, sizeof(*p2
))))
774 p2
->bits
= AF_BITS(AF_INET
);
775 _apply_mask(p2
, bits
, true);
777 luaL_getmetatable(L
, LUCI_IP_CIDR
);
778 lua_setmetatable(L
, -2);
782 static int cidr_mapped4(lua_State
*L
)
784 cidr_t
*p1
= L_checkcidr(L
, 1, NULL
);
787 if (!_is_mapped4(p1
))
790 if (!(p2
= lua_newuserdata(L
, sizeof(*p2
))))
793 p2
->family
= AF_INET
;
794 p2
->bits
= (p1
->bits
> AF_BITS(AF_INET
)) ? AF_BITS(AF_INET
) : p1
->bits
;
795 memcpy(&p2
->addr
.v4
, p1
->addr
.v6
.s6_addr
+ 12, sizeof(p2
->addr
.v4
));
797 luaL_getmetatable(L
, LUCI_IP_CIDR
);
798 lua_setmetatable(L
, -2);
802 static int cidr_unscoped(lua_State
*L
)
804 cidr_t
*p1
= L_checkcidr(L
, 1, NULL
);
807 if (p1
->family
!= AF_INET6
)
810 if (!(p2
= lua_newuserdata(L
, sizeof(*p2
))))
816 luaL_getmetatable(L
, LUCI_IP_CIDR
);
817 lua_setmetatable(L
, -2);
821 static int cidr_tolinklocal(lua_State
*L
)
823 cidr_t
*p1
= L_checkcidr(L
, 1, NULL
);
827 if (p1
->family
!= AF_PACKET
)
830 if (!(p2
= lua_newuserdata(L
, sizeof(*p2
))))
833 p2
->family
= AF_INET6
;
834 p2
->bits
= AF_BITS(AF_INET6
);
835 p2
->addr
.u8
[0] = 0xFE;
836 p2
->addr
.u8
[1] = 0x80;
837 p2
->addr
.u8
[8] = p1
->addr
.u8
[0] ^ 0x02;
838 p2
->addr
.u8
[9] = p1
->addr
.u8
[1];
839 p2
->addr
.u8
[10] = p1
->addr
.u8
[2];
840 p2
->addr
.u8
[11] = 0xFF;
841 p2
->addr
.u8
[12] = 0xFE;
842 p2
->addr
.u8
[13] = p1
->addr
.u8
[3];
843 p2
->addr
.u8
[14] = p1
->addr
.u8
[4];
844 p2
->addr
.u8
[15] = p1
->addr
.u8
[5];
846 luaL_getmetatable(L
, LUCI_IP_CIDR
);
847 lua_setmetatable(L
, -2);
851 static int cidr_tomac(lua_State
*L
)
853 cidr_t
*p1
= L_checkcidr(L
, 1, NULL
);
857 if (p1
->family
!= AF_INET6
||
858 p1
->addr
.u8
[0] != 0xFE ||
859 p1
->addr
.u8
[1] != 0x80 ||
860 p1
->addr
.u8
[2] != 0x00 ||
861 p1
->addr
.u8
[3] != 0x00 ||
862 p1
->addr
.u8
[4] != 0x00 ||
863 p1
->addr
.u8
[5] != 0x00 ||
864 p1
->addr
.u8
[6] != 0x00 ||
865 p1
->addr
.u8
[7] != 0x00 ||
866 p1
->addr
.u8
[11] != 0xFF ||
867 p1
->addr
.u8
[12] != 0xFE)
870 if (!(p2
= lua_newuserdata(L
, sizeof(*p2
))))
873 p2
->family
= AF_PACKET
;
874 p2
->bits
= AF_BITS(AF_PACKET
);
875 p2
->addr
.u8
[0] = p1
->addr
.u8
[8] ^ 0x02;
876 p2
->addr
.u8
[1] = p1
->addr
.u8
[9];
877 p2
->addr
.u8
[2] = p1
->addr
.u8
[10];
878 p2
->addr
.u8
[3] = p1
->addr
.u8
[13];
879 p2
->addr
.u8
[4] = p1
->addr
.u8
[14];
880 p2
->addr
.u8
[5] = p1
->addr
.u8
[15];
882 luaL_getmetatable(L
, LUCI_IP_CIDR
);
883 lua_setmetatable(L
, -2);
887 static int cidr_contains(lua_State
*L
)
889 cidr_t
*p1
= L_checkcidr(L
, 1, NULL
);
890 cidr_t
*p2
= L_checkcidr(L
, 2, NULL
);
891 cidr_t a
= *p1
, b
= *p2
;
894 if (p1
->family
== p2
->family
&& p1
->bits
<= p2
->bits
)
896 _apply_mask(&a
, p1
->bits
, false);
897 _apply_mask(&b
, p1
->bits
, false);
899 rv
= !memcmp(&a
.addr
.v6
, &b
.addr
.v6
, AF_BYTES(a
.family
));
902 lua_pushboolean(L
, rv
);
907 (a)->addr.u8[AF_BYTES((a)->family) - (i) - 1]
909 static int _cidr_add_sub(lua_State
*L
, bool add
)
911 cidr_t
*p1
= L_checkcidr(L
, 1, NULL
);
912 cidr_t
*p2
= L_checkcidr(L
, 2, p1
);
914 bool inplace
= lua_isboolean(L
, 3) ? lua_toboolean(L
, 3) : false;
919 if (p1
->family
== p2
->family
)
921 if (p1
->family
== AF_INET
)
923 a
= ntohl(p1
->addr
.v4
.s_addr
);
924 b
= ntohl(p2
->addr
.v4
.s_addr
);
926 /* would over/underflow */
927 if ((add
&& (UINT_MAX
- a
) < b
) || (!add
&& a
< b
))
929 r
.addr
.v4
.s_addr
= add
* 0xFFFFFFFF;
934 r
.addr
.v4
.s_addr
= add
? htonl(a
+ b
) : htonl(a
- b
);
939 for (i
= 0, carry
= 0; i
< AF_BYTES(p1
->family
); i
++)
943 BYTE(&r
, i
) = BYTE(p1
, i
) + BYTE(p2
, i
) + carry
;
944 carry
= (BYTE(p1
, i
) + BYTE(p2
, i
) + carry
) / 256;
948 BYTE(&r
, i
) = (BYTE(p1
, i
) - BYTE(p2
, i
) - carry
);
949 carry
= (BYTE(p1
, i
) < (BYTE(p2
, i
) + carry
));
953 /* would over/underflow */
956 memset(&r
.addr
.u8
, add
* 0xFF, AF_BYTES(r
.family
));
969 lua_pushboolean(L
, ok
);
973 if (!(p1
= lua_newuserdata(L
, sizeof(*p1
))))
978 luaL_getmetatable(L
, LUCI_IP_CIDR
);
979 lua_setmetatable(L
, -2);
983 static int cidr_add(lua_State
*L
)
985 return _cidr_add_sub(L
, true);
988 static int cidr_sub(lua_State
*L
)
990 return _cidr_add_sub(L
, false);
993 static int cidr_minhost(lua_State
*L
)
995 cidr_t
*p
= L_checkcidr(L
, 1, NULL
);
997 uint8_t i
, rest
, carry
;
999 _apply_mask(&r
, r
.bits
, false);
1001 if (r
.family
== AF_INET
&& r
.bits
< AF_BITS(AF_INET
))
1003 r
.bits
= AF_BITS(AF_INET
);
1004 r
.addr
.v4
.s_addr
= htonl(ntohl(r
.addr
.v4
.s_addr
) + 1);
1006 else if (r
.bits
< AF_BITS(r
.family
))
1008 r
.bits
= AF_BITS(r
.family
);
1010 for (i
= 0, carry
= 1; i
< AF_BYTES(r
.family
); i
++)
1012 rest
= (BYTE(&r
, i
) + carry
) > 255;
1013 BYTE(&r
, i
) += carry
;
1018 if (!(p
= lua_newuserdata(L
, sizeof(*p
))))
1023 luaL_getmetatable(L
, LUCI_IP_CIDR
);
1024 lua_setmetatable(L
, -2);
1028 static int cidr_maxhost(lua_State
*L
)
1030 cidr_t
*p
= L_checkcidr(L
, 1, NULL
);
1033 _apply_mask(&r
, r
.bits
, true);
1035 if (r
.family
== AF_INET
&& r
.bits
< AF_BITS(AF_INET
))
1037 r
.bits
= AF_BITS(AF_INET
);
1038 r
.addr
.v4
.s_addr
= htonl(ntohl(r
.addr
.v4
.s_addr
) - 1);
1042 r
.bits
= AF_BITS(r
.family
);
1045 if (!(p
= lua_newuserdata(L
, sizeof(*p
))))
1050 luaL_getmetatable(L
, LUCI_IP_CIDR
);
1051 lua_setmetatable(L
, -2);
1055 static int cidr_gc (lua_State
*L
)
1060 static int cidr_tostring (lua_State
*L
)
1062 cidr_t
*p
= L_checkcidr(L
, 1, NULL
);
1063 return format_cidr(L
, p
);
1070 static bool diff_prefix(int family
, void *addr
, int bits
, bool exact
, cidr_t
*p
)
1072 uint8_t i
, b
, r
, *a
;
1078 if (!addr
|| p
->family
!= family
|| p
->bits
> bits
)
1081 if (family
== AF_INET
)
1083 m
= p
->bits
? htonl(~((1 << (AF_BITS(AF_INET
) - p
->bits
)) - 1)) : 0;
1085 if ((((struct in_addr
*)addr
)->s_addr
& m
) != (p
->addr
.v4
.s_addr
& m
))
1090 for (i
= 0, a
= addr
, r
= p
->bits
; i
< AF_BYTES(p
->family
); i
++)
1092 b
= r
? (0xFF << (8 - ((r
> 8) ? 8 : r
))) : 0;
1094 if ((a
[i
] & b
) != (p
->addr
.u8
[i
] & b
))
1097 r
-= ((r
> 8) ? 8 : r
);
1101 return (exact
&& p
->bits
!= bits
);
1104 static int cb_dump_route(struct nl_msg
*msg
, void *arg
)
1106 struct dump_state
*s
= arg
;
1107 struct dump_filter
*f
= s
->filter
;
1108 struct nlmsghdr
*hdr
= nlmsg_hdr(msg
);
1109 struct rtmsg
*rt
= NLMSG_DATA(hdr
);
1110 struct nlattr
*tb
[RTA_MAX
+1];
1111 struct in6_addr
*src
, *dst
, *gw
, *from
, def
= { };
1112 int iif
, oif
, bitlen
;
1115 if (hdr
->nlmsg_type
!= RTM_NEWROUTE
||
1116 (rt
->rtm_family
!= AF_INET
&& rt
->rtm_family
!= AF_INET6
))
1119 nlmsg_parse(hdr
, sizeof(*rt
), tb
, RTA_MAX
, NULL
);
1121 iif
= tb
[RTA_IIF
] ? RTA_INT(tb
[RTA_IIF
]) : 0;
1122 oif
= tb
[RTA_OIF
] ? RTA_INT(tb
[RTA_OIF
]) : 0;
1123 table
= tb
[RTA_TABLE
] ? RTA_U32(tb
[RTA_TABLE
]) : rt
->rtm_table
;
1124 from
= tb
[RTA_SRC
] ? RTA_DATA(tb
[RTA_SRC
]) : NULL
;
1125 src
= tb
[RTA_PREFSRC
] ? RTA_DATA(tb
[RTA_PREFSRC
]) : NULL
;
1126 dst
= tb
[RTA_DST
] ? RTA_DATA(tb
[RTA_DST
]) : &def
;
1127 gw
= tb
[RTA_GATEWAY
] ? RTA_DATA(tb
[RTA_GATEWAY
]) : NULL
;
1129 bitlen
= AF_BITS(rt
->rtm_family
);
1132 if ((f
->type
&& rt
->rtm_type
!= f
->type
) ||
1133 (f
->family
&& rt
->rtm_family
!= f
->family
) ||
1134 (f
->proto
&& rt
->rtm_protocol
!= f
->proto
) ||
1135 (f
->scope
&& rt
->rtm_scope
!= f
->scope
) ||
1136 (f
->iif
&& iif
!= f
->iif
) ||
1137 (f
->oif
&& oif
!= f
->oif
) ||
1138 (f
->table
&& table
!= f
->table
) ||
1139 diff_prefix(rt
->rtm_family
, from
, rt
->rtm_src_len
,
1140 f
->from_exact
, &f
->from
) ||
1141 diff_prefix(rt
->rtm_family
, dst
, rt
->rtm_dst_len
,
1142 f
->dst_exact
, &f
->dst
) ||
1143 diff_prefix(rt
->rtm_family
, gw
, bitlen
,
1145 diff_prefix(rt
->rtm_family
, src
, bitlen
,
1151 lua_pushvalue(s
->L
, 2);
1155 L_setint(s
->L
, "type", rt
->rtm_type
);
1156 L_setint(s
->L
, "family", (rt
->rtm_family
== AF_INET
) ? 4 : 6);
1158 L_setaddr(s
->L
, "dest", rt
->rtm_family
, dst
, rt
->rtm_dst_len
);
1161 L_setaddr(s
->L
, "gw", rt
->rtm_family
, gw
, -1);
1164 L_setaddr(s
->L
, "from", rt
->rtm_family
, from
, rt
->rtm_src_len
);
1167 L_setdev(s
->L
, "iif", tb
[RTA_IIF
]);
1170 L_setdev(s
->L
, "dev", tb
[RTA_OIF
]);
1172 L_setint(s
->L
, "table", table
);
1173 L_setint(s
->L
, "proto", rt
->rtm_protocol
);
1174 L_setint(s
->L
, "scope", rt
->rtm_scope
);
1177 L_setaddr(s
->L
, "src", rt
->rtm_family
, src
, -1);
1179 if (tb
[RTA_PRIORITY
])
1180 L_setint(s
->L
, "metric", RTA_U32(tb
[RTA_PRIORITY
]));
1182 if (rt
->rtm_family
== AF_INET6
&& tb
[RTA_CACHEINFO
])
1184 struct rta_cacheinfo
*ci
= RTA_DATA(tb
[RTA_CACHEINFO
]);
1186 if (ci
->rta_expires
)
1188 if (ci
->rta_expires
)
1189 L_setint(s
->L
, "expires", ci
->rta_expires
/ hz
);
1191 if (ci
->rta_error
!= 0)
1192 L_setint(s
->L
, "error", ci
->rta_error
);
1199 lua_call(s
->L
, 1, 0);
1200 else if (hdr
->nlmsg_flags
& NLM_F_MULTI
)
1201 lua_rawseti(s
->L
, -2, s
->index
);
1204 s
->pending
= !!(hdr
->nlmsg_flags
& NLM_F_MULTI
);
1209 cb_done(struct nl_msg
*msg
, void *arg
)
1211 struct dump_state
*s
= arg
;
1217 cb_error(struct sockaddr_nl
*nla
, struct nlmsgerr
*err
, void *arg
)
1219 struct dump_state
*s
= arg
;
1224 static int _error(lua_State
*L
, int code
, const char *msg
)
1227 lua_pushnumber(L
, code
? code
: errno
);
1228 lua_pushstring(L
, msg
? msg
: strerror(errno
));
1233 static int _route_dump(lua_State
*L
, struct dump_filter
*filter
)
1235 int flags
= NLM_F_REQUEST
;
1236 struct dump_state s
= {
1240 .callback
= lua_isfunction(L
, 2),
1245 hz
= sysconf(_SC_CLK_TCK
);
1249 sock
= nl_socket_alloc();
1251 return _error(L
, -1, "Out of memory");
1253 if (nl_connect(sock
, NETLINK_ROUTE
))
1254 return _error(L
, 0, NULL
);
1258 struct nl_cb
*cb
= nl_cb_alloc(NL_CB_DEFAULT
);
1259 struct rtmsg rtm
= {
1260 .rtm_family
= filter
->family
,
1261 .rtm_dst_len
= filter
->dst
.bits
,
1262 .rtm_src_len
= filter
->src
.bits
1266 flags
|= NLM_F_DUMP
;
1268 msg
= nlmsg_alloc_simple(RTM_GETROUTE
, flags
);
1272 nlmsg_append(msg
, &rtm
, sizeof(rtm
), 0);
1275 nla_put(msg
, RTA_DST
, AF_BYTES(filter
->dst
.family
),
1276 &filter
->dst
.addr
.v6
);
1278 if (filter
->src
.family
)
1279 nla_put(msg
, RTA_SRC
, AF_BYTES(filter
->src
.family
),
1280 &filter
->src
.addr
.v6
);
1283 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, cb_dump_route
, &s
);
1284 nl_cb_set(cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, cb_done
, &s
);
1285 nl_cb_err(cb
, NL_CB_CUSTOM
, cb_error
, &s
);
1287 nl_send_auto_complete(sock
, msg
);
1289 if (!filter
->get
&& !s
.callback
)
1292 while (s
.pending
> 0)
1293 nl_recvmsgs(sock
, cb
);
1306 return (s
.index
> 0);
1309 static int route_get(lua_State
*L
)
1311 struct dump_filter filter
= { .get
= true };
1312 const char *dest
= luaL_checkstring(L
, 1);
1313 const char *from
= luaL_optstring(L
, 2, NULL
);
1315 if (!parse_cidr(dest
, &filter
.dst
))
1316 return _error(L
, -1, "Invalid destination");
1318 if (from
&& !parse_cidr(from
, &filter
.src
))
1319 return _error(L
, -1, "Invalid source");
1321 if (filter
.src
.family
!= 0 &&
1322 filter
.src
.family
!= filter
.dst
.family
)
1323 return _error(L
, -1, "Different source/destination family");
1325 filter
.family
= filter
.dst
.family
;
1327 return _route_dump(L
, &filter
);
1330 static int route_dump(lua_State
*L
)
1334 struct dump_filter filter
= { };
1336 if (lua_type(L
, 1) == LUA_TTABLE
)
1338 filter
.family
= L_getint(L
, 1, "family");
1340 if (filter
.family
== 4)
1341 filter
.family
= AF_INET
;
1342 else if (filter
.family
== 6)
1343 filter
.family
= AF_INET6
;
1347 if ((s
= L_getstr(L
, 1, "iif")) != NULL
)
1348 filter
.iif
= if_nametoindex(s
);
1350 if ((s
= L_getstr(L
, 1, "oif")) != NULL
)
1351 filter
.oif
= if_nametoindex(s
);
1353 filter
.type
= L_getint(L
, 1, "type");
1354 filter
.scope
= L_getint(L
, 1, "scope");
1355 filter
.proto
= L_getint(L
, 1, "proto");
1356 filter
.table
= L_getint(L
, 1, "table");
1358 if ((s
= L_getstr(L
, 1, "gw")) != NULL
&& parse_cidr(s
, &p
))
1361 if ((s
= L_getstr(L
, 1, "from")) != NULL
&& parse_cidr(s
, &p
))
1364 if ((s
= L_getstr(L
, 1, "src")) != NULL
&& parse_cidr(s
, &p
))
1367 if ((s
= L_getstr(L
, 1, "dest")) != NULL
&& parse_cidr(s
, &p
))
1370 if ((s
= L_getstr(L
, 1, "from_exact")) != NULL
&& parse_cidr(s
, &p
))
1371 filter
.from
= p
, filter
.from_exact
= true;
1373 if ((s
= L_getstr(L
, 1, "dest_exact")) != NULL
&& parse_cidr(s
, &p
))
1374 filter
.dst
= p
, filter
.dst_exact
= true;
1377 return _route_dump(L
, &filter
);
1381 static bool diff_macaddr(struct ether_addr
*mac1
, struct ether_addr
*mac2
)
1383 struct ether_addr empty
= { };
1385 if (!memcmp(mac2
, &empty
, sizeof(empty
)))
1388 if (!mac1
|| memcmp(mac1
, mac2
, sizeof(empty
)))
1394 static int cb_dump_neigh(struct nl_msg
*msg
, void *arg
)
1397 struct ether_addr
*mac
;
1398 struct in6_addr
*dst
;
1399 struct dump_state
*s
= arg
;
1400 struct dump_filter
*f
= s
->filter
;
1401 struct nlmsghdr
*hdr
= nlmsg_hdr(msg
);
1402 struct ndmsg
*nd
= NLMSG_DATA(hdr
);
1403 struct nlattr
*tb
[NDA_MAX
+1];
1406 if (hdr
->nlmsg_type
!= RTM_NEWNEIGH
||
1407 (nd
->ndm_family
!= AF_INET
&& nd
->ndm_family
!= AF_INET6
))
1410 nlmsg_parse(hdr
, sizeof(*nd
), tb
, NDA_MAX
, NULL
);
1412 mac
= tb
[NDA_LLADDR
] ? RTA_DATA(tb
[NDA_LLADDR
]) : NULL
;
1413 dst
= tb
[NDA_DST
] ? RTA_DATA(tb
[NDA_DST
]) : NULL
;
1415 bitlen
= AF_BITS(nd
->ndm_family
);
1417 if ((f
->family
&& nd
->ndm_family
!= f
->family
) ||
1418 (f
->iif
&& nd
->ndm_ifindex
!= f
->iif
) ||
1419 (f
->type
&& !(f
->type
& nd
->ndm_state
)) ||
1420 diff_prefix(nd
->ndm_family
, dst
, bitlen
, false, &f
->dst
) ||
1421 diff_macaddr(mac
, &f
->mac
))
1425 lua_pushvalue(s
->L
, 2);
1429 L_setint(s
->L
, "family", (nd
->ndm_family
== AF_INET
) ? 4 : 6);
1430 L_setstr(s
->L
, "dev", if_indextoname(nd
->ndm_ifindex
, buf
));
1432 L_setbool(s
->L
, "router", (nd
->ndm_flags
& NTF_ROUTER
));
1433 L_setbool(s
->L
, "proxy", (nd
->ndm_flags
& NTF_PROXY
));
1435 L_setbool(s
->L
, "incomplete", (nd
->ndm_state
& NUD_INCOMPLETE
));
1436 L_setbool(s
->L
, "reachable", (nd
->ndm_state
& NUD_REACHABLE
));
1437 L_setbool(s
->L
, "stale", (nd
->ndm_state
& NUD_STALE
));
1438 L_setbool(s
->L
, "delay", (nd
->ndm_state
& NUD_DELAY
));
1439 L_setbool(s
->L
, "probe", (nd
->ndm_state
& NUD_PROBE
));
1440 L_setbool(s
->L
, "failed", (nd
->ndm_state
& NUD_FAILED
));
1441 L_setbool(s
->L
, "noarp", (nd
->ndm_state
& NUD_NOARP
));
1442 L_setbool(s
->L
, "permanent", (nd
->ndm_state
& NUD_PERMANENT
));
1445 L_setaddr(s
->L
, "dest", nd
->ndm_family
, dst
, -1);
1448 L_setaddr(s
->L
, "mac", AF_PACKET
, mac
, -1);
1453 lua_call(s
->L
, 1, 0);
1454 else if (hdr
->nlmsg_flags
& NLM_F_MULTI
)
1455 lua_rawseti(s
->L
, -2, s
->index
);
1458 s
->pending
= !!(hdr
->nlmsg_flags
& NLM_F_MULTI
);
1462 static int neighbor_dump(lua_State
*L
)
1466 struct ether_addr
*mac
;
1467 struct dump_filter filter
= { .type
= 0xFF & ~NUD_NOARP
};
1468 struct dump_state st
= {
1469 .callback
= lua_isfunction(L
, 2),
1475 if (lua_type(L
, 1) == LUA_TTABLE
)
1477 filter
.family
= L_getint(L
, 1, "family");
1479 if (filter
.family
== 4)
1480 filter
.family
= AF_INET
;
1481 else if (filter
.family
== 6)
1482 filter
.family
= AF_INET6
;
1486 if ((s
= L_getstr(L
, 1, "dev")) != NULL
)
1487 filter
.iif
= if_nametoindex(s
);
1489 if ((s
= L_getstr(L
, 1, "dest")) != NULL
&& parse_cidr(s
, &p
))
1492 if ((s
= L_getstr(L
, 1, "mac")) != NULL
&&
1493 (mac
= ether_aton(s
)) != NULL
)
1499 sock
= nl_socket_alloc();
1501 return _error(L
, -1, "Out of memory");
1503 if (nl_connect(sock
, NETLINK_ROUTE
))
1504 return _error(L
, 0, NULL
);
1508 struct nl_cb
*cb
= nl_cb_alloc(NL_CB_DEFAULT
);
1509 struct ndmsg ndm
= {
1510 .ndm_family
= filter
.family
1513 msg
= nlmsg_alloc_simple(RTM_GETNEIGH
, NLM_F_REQUEST
| NLM_F_DUMP
);
1517 nlmsg_append(msg
, &ndm
, sizeof(ndm
), 0);
1519 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, cb_dump_neigh
, &st
);
1520 nl_cb_set(cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, cb_done
, &st
);
1521 nl_cb_err(cb
, NL_CB_CUSTOM
, cb_error
, &st
);
1523 nl_send_auto_complete(sock
, msg
);
1528 while (st
.pending
> 0)
1529 nl_recvmsgs(sock
, cb
);
1535 return (st
.callback
== 0);
1539 static int cb_dump_link(struct nl_msg
*msg
, void *arg
)
1542 struct dump_state
*s
= arg
;
1543 struct nlmsghdr
*hdr
= nlmsg_hdr(msg
);
1544 struct ifinfomsg
*ifm
= NLMSG_DATA(hdr
);
1545 struct nlattr
*tb
[IFLA_MAX
+1];
1548 if (hdr
->nlmsg_type
!= RTM_NEWLINK
)
1551 nlmsg_parse(hdr
, sizeof(*ifm
), tb
, IFLA_MAX
, NULL
);
1553 L_setbool(s
->L
, "up", (ifm
->ifi_flags
& IFF_RUNNING
));
1554 L_setint(s
->L
, "type", ifm
->ifi_type
);
1555 L_setstr(s
->L
, "name", if_indextoname(ifm
->ifi_index
, buf
));
1558 L_setint(s
->L
, "mtu", RTA_U32(tb
[IFLA_MTU
]));
1560 if (tb
[IFLA_TXQLEN
])
1561 L_setint(s
->L
, "qlen", RTA_U32(tb
[IFLA_TXQLEN
]));
1563 if (tb
[IFLA_MASTER
])
1564 L_setdev(s
->L
, "master", tb
[IFLA_MASTER
]);
1566 if (tb
[IFLA_ADDRESS
] && nla_len(tb
[IFLA_ADDRESS
]) == AF_BYTES(AF_PACKET
))
1567 L_setaddr(s
->L
, "mac", AF_PACKET
, nla_get_string(tb
[IFLA_ADDRESS
]), -1);
1573 static int link_get(lua_State
*L
)
1575 const char *dev
= luaL_checkstring(L
, 1);
1576 struct dump_state st
= {
1583 sock
= nl_socket_alloc();
1585 return _error(L
, -1, "Out of memory");
1587 if (nl_connect(sock
, NETLINK_ROUTE
))
1588 return _error(L
, 0, NULL
);
1591 struct nl_msg
*msg
= nlmsg_alloc_simple(RTM_GETLINK
, NLM_F_REQUEST
);
1592 struct nl_cb
*cb
= nl_cb_alloc(NL_CB_DEFAULT
);
1593 struct ifinfomsg ifm
= { .ifi_index
= if_nametoindex(dev
) };
1598 nlmsg_append(msg
, &ifm
, sizeof(ifm
), 0);
1600 nl_cb_set(cb
, NL_CB_VALID
, NL_CB_CUSTOM
, cb_dump_link
, &st
);
1601 nl_cb_set(cb
, NL_CB_FINISH
, NL_CB_CUSTOM
, cb_done
, &st
);
1602 nl_cb_err(cb
, NL_CB_CUSTOM
, cb_error
, &st
);
1606 nl_send_auto_complete(sock
, msg
);
1608 while (st
.pending
> 0)
1609 nl_recvmsgs(sock
, cb
);
1618 static const luaL_reg ip_methods
[] = {
1619 { "new", cidr_new
},
1620 { "IPv4", cidr_ipv4
},
1621 { "IPv6", cidr_ipv6
},
1622 { "MAC", cidr_mac
},
1624 { "checkip4", cidr_checkip4
},
1625 { "checkip6", cidr_checkip6
},
1626 { "checkmac", cidr_checkmac
},
1628 { "route", route_get
},
1629 { "routes", route_dump
},
1631 { "neighbors", neighbor_dump
},
1633 { "link", link_get
},
1638 static const luaL_reg ip_cidr_methods
[] = {
1639 { "is4", cidr_is4
},
1640 { "is4rfc1918", cidr_is4rfc1918
},
1641 { "is4linklocal", cidr_is4linklocal
},
1642 { "is6", cidr_is6
},
1643 { "is6linklocal", cidr_is6linklocal
},
1644 { "is6mapped4", cidr_is6mapped4
},
1645 { "ismac", cidr_ismac
},
1646 { "ismaclocal", cidr_ismaclocal
},
1647 { "ismacmcast", cidr_ismacmcast
},
1648 { "lower", cidr_lower
},
1649 { "higher", cidr_higher
},
1650 { "equal", cidr_equal
},
1651 { "prefix", cidr_prefix
},
1652 { "network", cidr_network
},
1653 { "host", cidr_host
},
1654 { "mask", cidr_mask
},
1655 { "broadcast", cidr_broadcast
},
1656 { "mapped4", cidr_mapped4
},
1657 { "unscoped", cidr_unscoped
},
1658 { "tomac", cidr_tomac
},
1659 { "tolinklocal", cidr_tolinklocal
},
1660 { "contains", cidr_contains
},
1661 { "add", cidr_add
},
1662 { "sub", cidr_sub
},
1663 { "minhost", cidr_minhost
},
1664 { "maxhost", cidr_maxhost
},
1665 { "string", cidr_tostring
},
1667 { "__lt", cidr_lower
},
1668 { "__le", cidr_lower_equal
},
1669 { "__eq", cidr_equal
},
1670 { "__add", cidr_add
},
1671 { "__sub", cidr_sub
},
1672 { "__gc", cidr_gc
},
1673 { "__tostring", cidr_tostring
},
1678 int luaopen_luci_ip(lua_State
*L
)
1680 luaL_register(L
, LUCI_IP
, ip_methods
);
1682 luaL_newmetatable(L
, LUCI_IP_CIDR
);
1683 luaL_register(L
, NULL
, ip_cidr_methods
);
1684 lua_pushvalue(L
, -1);
1685 lua_setfield(L
, -2, "__index");