1 --- LuCI IP calculation and netlink access library.
5 Construct a new luci.ip.cidr instance and autodetect the address family.
6 Throws an error if the given strings do not represent a valid address or
7 if the given optional netmask is of a different family.
11 @param address String containing a valid IPv4 or IPv6 address, optionally
12 with prefix size (CIDR notation) or netmask separated by slash.
13 @param netmask String containing a valid IPv4 or IPv6 netmask or number
14 containing a prefix size in bits (`0..32` for IPv4,
15 `0..128` for IPv6). Overrides mask embedded in the first argument
16 if specified. (optional)
17 @return A `luci.ip.cidr` object representing the given
19 @usage `addr = luci.ip.new("10.24.0.1/24")
20 addr = luci.ip.new("10.24.0.1/255.255.255.0")
21 addr = luci.ip.new("10.24.0.1", "255.255.255.0") -- separate netmask
22 addr = luci.ip.new("10.24.0.1/24", 16) -- override netmask
24 addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17/64")
25 addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17/ffff:ffff:ffff:ffff::")
26 addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17", "ffff:ffff:ffff:ffff::")
27 addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17/64", 128) -- override netmask`
33 Construct a new IPv4 luci.ip.cidr instance.
34 Throws an error if the given string does not represent a valid IPv4 address or
35 if the given optional netmask is of a different family.
39 @param address String containing a valid IPv4, optionally with prefix size
40 (CIDR notation) or netmask separated by slash.
41 @param netmask String containing a valid IPv4 netmask or number
42 containing a prefix size between `0` and `32` bit.
43 Overrides mask embedded in the first argument if specified. (optional)
44 @return A `luci.ip.cidr` object representing the given IPv4 range.
45 @usage `addr = luci.ip.IPv4("10.24.0.1/24")
46 addr = luci.ip.IPv4("10.24.0.1/255.255.255.0")
47 addr = luci.ip.IPv4("10.24.0.1", "255.255.255.0") -- separate netmask
48 addr = luci.ip.IPv4("10.24.0.1/24", 16) -- override netmask`
53 Construct a new IPv6 luci.ip.cidr instance.
54 Throws an error if the given string does not represent a valid IPv6 address or
55 if the given optional netmask is of a different family.
59 @param address String containing a valid IPv6, optionally with prefix size
60 (CIDR notation) or netmask separated by slash.
61 @param netmask String containing a valid IPv4 netmask or number
62 containing a prefix size between `0` and `128` bit.
63 Overrides mask embedded in the first argument if specified. (optional)
64 @return A `luci.ip.cidr` object representing the given IPv6 range.
65 @usage `addr6 = luci.ip.IPv6("fe80::221:63ff:fe75:aa17/64")
66 addr6 = luci.ip.IPv6("fe80::221:63ff:fe75:aa17/ffff:ffff:ffff:ffff::")
67 addr6 = luci.ip.IPv6("fe80::221:63ff:fe75:aa17", "ffff:ffff:ffff:ffff::")
68 addr6 = luci.ip.IPv6("fe80::221:63ff:fe75:aa17/64", 128) -- override netmask`
73 Determine the route leading to the given destination.
77 @param address A `luci.ip.cidr` instance or a string containing
78 a valid IPv4 or IPv6 range as specified by `luci.ip.new()`.
79 @return <p>Table containing the fields described below.</p>
80 <table id="routetable">
81 <tr><th>Field</th><th>Description</th></tr>
83 <p>Route type with one of the following numeric values:</p>
87 <td>`RTN_UNICAST` - Gateway or direct route</td>
91 <td>`RTN_LOCAL` - Accept locally</td>
96 Accept locally as broadcast send as broadcast</td>
101 Accept locally as broadcast but send as unicast</td>
105 <td>`RTN_MULTICAST` - Multicast route</td>
111 <td>Number containing the route family, `4` for IPv4 or
116 <td>Destination `luci.ip.cidr` instance</td>
120 <td>Gateway `luci.ip.cidr` instance (optional)</td>
124 <td>Source address `luci.ip.cidr` instance (optional)</td>
128 <td>Preferred source `luci.ip.cidr` instance (optional)</td>
132 <td>String containing the name of the outgoing interface</td>
136 <td>String containing the name of the incoming interface (optional)</td>
140 <td>Number of the associated routing table (`0..65535`)</td>
144 <td>Number of the associated routing protocol</td>
148 <td>Number describing the scope of the route, most commonly
149 `0` for global or `253` for on-link</td>
153 <td>Number describing the route metric (optional)</td>
157 <td>Number of seconds the prefix is valid (IPv6 only, optional)</td>
161 <td>Route destination error code (optional)</td>
165 <li>Find default gateway by getting route to Google's public NS server
166 `rt = luci.ip.route("8.8.8.8")
168 print("gateway is", rt.gw)
170 <li>Determine IPv6 upstream interface `rt = luci.ip.route("2001::/7")
172 print("ipv6 upstream device is", rt.dev)
179 Fetch all routes, optionally matching the given criteria.
183 @param filter <p>Table containing one or more of the possible filter
184 critera described below (optional)</p><table>
185 <tr><th>Field</th><th>Description</th></tr>
186 <tr><td>`family`</td><td>
187 Number describing the address family to return - `4` selects
188 IPv4 routes, `6` IPv6 ones. Any other value selects both.
190 <tr><td>`iif`</td><td>
191 String containing the incoming route interface to match.
193 <tr><td>`oif`</td><td>
194 String containing the outgoing route interface to match.
196 <tr><td>`type`</td><td>
197 Numeric type to match, e.g. `1` for unicast.
199 <tr><td>`scope`</td><td>
200 Numeric scope to match, e.g. `253` for onlink.
202 <tr><td>`proto`</td><td>
203 Numeric protocol to match, e.g. `2` for boot.
205 <tr><td>`table`</td><td>
206 Numeric routing table to match (`0..65535`).
208 <tr><td>`gw`</td><td>
209 String containing the gateway address to match. Can be in any notation
210 specified by `luci.ip.new()`. Prefix matching is performed when
211 comparing the routes, e.g. "192.168.1.0/24" would select routes with gateway
212 addresses `192.168.1.1 .. 192.168.1.255`.
214 <tr><td>`dest`</td><td>
215 String containing the destination to match. Prefix matching is performed.
217 <tr><td>`from`</td><td>
218 String containing the source address to match. Prefix matching is performed.
220 <tr><td>`src`</td><td>
221 String containing the preferred source address to match.
222 Prefix matching is performed.
224 <tr><td>`dest_exact`</td><td>
225 String containing the destination to match. Exact matching is performed,
226 e.g. `dest = "0.0.0.0/0"` would match <em>any</em> IPv4 route
227 while `dest_exact = "0.0.0.0/0"` will <em>only</em> match the
230 <tr><td>`from_exact`</td><td>
231 String containing the source address to match. Exact matching is performed.
234 @param callback <p>Callback function to invoke for each found route
235 instead of returning one table of route objects (optional)</p>
236 @return If no callback function is provided, a table of routes
237 <a href="#routetable">as specified by `luci.ip.route()`</a>
238 is returned. If a callback function is given, it is invoked for each route
239 and nothing is returned.
242 <li>Find all IPv4 default routes:
243 `luci.ip.routes({ dest_exact = "0.0.0.0/0" }, function(rt)
244 print(rt.type, rt.gw, rt.dev)
246 <li>Find all global IPv6 prefixes on the current system:
247 `luci.ip.routes({ from = "2001::/7" }, function(rt)
250 <li>Fetch all IPv4 routes:
251 `routes = luci.ip.routes({ family = 4 })
252 for _, rt in ipairs(routes) do
253 print(rt.dest, rt.gw, rt.dev)
259 Fetches entries from the IPv4 ARP and IPv6 neighbour kernel table
263 @param filter <p>Table containing one or more of the possible filter
264 critera described below (optional)</p><table>
265 <tr><th>Field</th><th>Description</th></tr>
266 <tr><td>`family`</td><td>
267 Number describing the address family to return - `4` selects
268 IPv4 ARP, `6` select IPv6 neighbour entries. Any other value
271 <tr><td>`dev`</td><td>
272 String containing the associated interface to match.
274 <tr><td>`dest`</td><td>
275 String containing the associated address to match. Can be in any notation
276 specified by `luci.ip.new()`. Prefix matching is performed when
277 comparing the addresses, e.g. "192.168.1.0/24" would select ARP entries
278 for `192.168.1.1 .. 192.168.1.255`.
280 <tr><td>`mac`</td><td>
281 String containing MAC address to match.
284 @param callback <p>Callback function to invoke for each found neighbour
285 entry instead of returning one table of neighbour entries (optional)</p>
286 @return If no callback function is provided, a table of neighbour entries
287 is returned. If a callback function is given, it is invoked for each entry
288 and nothing is returned.
290 A neighbour entry is a table containing the following fields:
293 <tr><th>Field</th><th>Description</th></tr>
296 <td>Number containing the neighbour entry family, `4` for IPv4
297 ARP or `6` for IPv6 NDP</td>
301 <td>String containing the associated device of the neighbour entry</td>
305 <td>IP address `luci.ip.cidr` instance</td>
309 <td>String containing the associated MAC address</td>
313 <td>Boolean "true" if the neighbour entry is a router (IPv6, optional)</td>
317 <td>Boolean "true" if this is a proxy entry (optional)</td>
320 <td>`incomplete`</td>
321 <td>Boolean "true" if the entry is in incomplete state (optional)</td>
325 <td>Boolean "true" if the entry is in reachable state (optional)</td>
329 <td>Boolean "true" if the entry is stale (optional)</td>
333 <td>Boolean "true" if the entry is delayed (optional)</td>
337 <td>Boolean "true" if the entry is in probe state (optional)</td>
341 <td>Boolean "true" if the entry is in failed state (optional)</td>
345 <td>Boolean "true" if the entry is not caused by NDP or
350 <td>Boolean "true" if the entry was statically configured from
351 userspace (optional)</td>
355 <li>Find all ARP neighbours in the LAN:
356 `luci.ip.neighbors({ dest = "192.168.0.0/16" }, function(n)
359 <li>Find all active IPv6 addresses of host with given MAC:
360 `luci.ip.neighbors({ family = 6, mac = "00:21:63:75:aa:17" },
368 Fetch basic device information
372 @param device String containing the network device to query
373 @return If the given interface is found, a table containing the fields
374 described below is returned, else an empty table.
377 <tr><th>Field</th><th>Description</th></tr>
380 <td>Boolean indicating whether the device is in IFF_RUNNING state</td>
384 <td>Numeric value indicating the type of the device, e.g. `1`
389 <td>String containing the name of the device</td>
393 <td>If queried device is a bridge port, string containing the name of
394 parent bridge device (optional)</td>
398 <td>Number containing the current MTU of the device</td>
402 <td>Number containing the TX queue length of the device</td>
406 <td>String containing the link local address of the device in
407 dotted hex notation</td>
411 <li>Test whether device br-lan exists:
412 `print(luci.ip.link("br-lan").name ~= nil)
414 <li>Query MAC address of eth0:
415 `print(luci.ip.link("eth0").mac)
422 -- Represents an IPv4 or IPv6 address range.
424 module "luci.ip.cidr"
427 Checks whether the CIDR instance is an IPv4 address range
433 @return `true` if the CIDR is an IPv4 range, else `false`
437 Checks whether the CIDR instance is within the private RFC1918 address space
441 @name cidr.is4rfc1918
442 @return `true` if the entire range of this CIDR lies within one of
443 the ranges `10.0.0.0-10.255.255.255`,
444 `172.16.0.0-172.31.0.0` or
445 `192.168.0.0-192.168.255.255`, else `false`.
446 @usage `local addr = luci.ip.new("192.168.45.2/24")
447 if addr:is4rfc1918() then
448 print("Is a private address")
453 Checks whether the CIDR instance is an IPv4 link local (Zeroconf) address
457 @name cidr.is4linklocal
458 @return `true` if the entire range of this CIDR lies within the range
459 the range `169.254.0.0-169.254.255.255`, else `false`.
460 @usage `local addr = luci.ip.new("169.254.34.125")
461 if addr:is4linklocal() then
462 print("Is a zeroconf address")
467 Checks whether the CIDR instance is an IPv6 address range
473 @return `true` if the CIDR is an IPv6 range, else `false`
477 Checks whether the CIDR instance is an IPv6 link local address
481 @name cidr.is6linklocal
482 @return `true` if the entire range of this CIDR lies within the range
483 the `fe80::/10` range, else `false`.
484 @usage `local addr = luci.ip.new("fe92:53a:3216:af01:221:63ff:fe75:aa17/64")
485 if addr:is6linklocal() then
486 print("Is a linklocal address")
491 Checks whether the CIDR instance is an IPv6 mapped IPv4 address
495 @name cidr.is6mapped4
496 @return `true` if the address is an IPv6 mapped IPv4 address in the
497 form `::ffff:1.2.3.4`.
498 @usage `local addr = luci.ip.new("::ffff:192.168.1.1")
499 if addr:is6mapped4() then
500 print("Is a mapped IPv4 address")
505 Checks whether this CIDR instance is lower than the given argument.
506 The comparisation follows these rules:
507 <ul><li>An IPv4 address is always lower than an IPv6 address</li>
508 <li>Prefix sizes are ignored</li></ul>
513 @param addr A `luci.ip.cidr` instance or a string convertable by
514 `luci.ip.new()` to compare against.
515 @return `true` if this CIDR is lower than the given address,
517 @usage `local addr = luci.ip.new("192.168.1.1")
518 print(addr:lower(addr)) -- false
519 print(addr:lower("10.10.10.10/24")) -- false
520 print(addr:lower(luci.ip.new("::1"))) -- true
521 print(addr:lower(luci.ip.new("192.168.200.1"))) -- true`
527 Checks whether this CIDR instance is higher than the given argument.
528 The comparisation follows these rules:
529 <ul><li>An IPv4 address is always lower than an IPv6 address</li>
530 <li>Prefix sizes are ignored</li></ul>
535 @param addr A `luci.ip.cidr` instance or a string convertable by
536 `luci.ip.new()` to compare against.
537 @return `true` if this CIDR is higher than the given address,
539 @usage `local addr = luci.ip.new("192.168.1.1")
540 print(addr:higher(addr)) -- false
541 print(addr:higher("10.10.10.10/24")) -- true
542 print(addr:higher(luci.ip.new("::1"))) -- false
543 print(addr:higher(luci.ip.new("192.168.200.1"))) -- false`
549 Checks whether this CIDR instance is equal to the given argument.
554 @param addr A `luci.ip.cidr` instance or a string convertable by
555 `luci.ip.new()` to compare against.
556 @return `true` if this CIDR is equal to the given address,
558 @usage `local addr = luci.ip.new("192.168.1.1")
559 print(addr:equal(addr)) -- true
560 print(addr:equal("192.168.1.1")) -- true
561 print(addr:equal(luci.ip.new("::1"))) -- false
563 local addr6 = luci.ip.new("::1")
564 print(addr6:equal("0:0:0:0:0:0:0:1/64")) -- true
565 print(addr6:equal(luci.ip.new("fe80::221:63ff:fe75:aa17"))) -- false`
571 Get or set prefix size of CIDR instance.
572 If the optional mask parameter is given, the prefix size of this CIDR is altered
573 else the current prefix size is returned.
578 @param mask Either a number containing the number of bits (`0..32`
579 for IPv4, `0..128` for IPv6) or a string containing a valid
581 @return Bit count of the current prefix size
582 @usage `local range = luci.ip.new("192.168.1.1/255.255.255.0")
583 print(range:prefix()) -- 24
586 print(range:prefix()) -- 16
588 range:prefix("255.255.255.255")
589 print(range:prefix()) -- 32`
593 Derive network address of CIDR instance.
595 Returns a new CIDR instance representing the network address of this instance
596 with all host parts masked out. The used prefix size can be overridden by the
597 optional mask parameter.
602 @param mask Either a number containing the number of bits (`0..32`
603 for IPv4, `0..128` for IPv6) or a string containing a valid
605 @return CIDR instance representing the network address
606 @usage `local range = luci.ip.new("192.168.62.243/255.255.0.0")
607 print(range:network()) -- "192.168.0.0"
608 print(range:network(24)) -- "192.168.62.0"
609 print(range:network("255.255.255.0")) -- "192.168.62.0"
611 local range6 = luci.ip.new("fd9b:62b3:9cc5:0:221:63ff:fe75:aa17/64")
612 print(range6:network()) -- "fd9b:62b3:9cc5::"`
616 Derive host address of CIDR instance.
618 This function essentially constructs a copy of this CIDR with the prefix size
619 set to `32` for IPv4 and `128` for IPv6.
624 @return CIDR instance representing the host address
625 @usage `local range = luci.ip.new("172.19.37.45/16")
626 print(range) -- "172.19.37.45/16"
627 print(range:host()) -- "172.19.37.45"`
631 Derive netmask of CIDR instance.
633 Constructs a CIDR instance representing the netmask of this instance. The used
634 prefix size can be overridden by the optional mask parameter.
639 @param mask Either a number containing the number of bits (`0..32`
640 for IPv4, `0..128` for IPv6) or a string containing a valid
642 @return CIDR instance representing the netmask
643 @usage `local range = luci.ip.new("172.19.37.45/16")
644 print(range:mask()) -- "255.255.0.0"
645 print(range:mask(24)) -- "255.255.255.0"
646 print(range:mask("255.0.0.0")) -- "255.0.0.0"`
650 Derive broadcast address of CIDR instance.
652 Constructs a CIDR instance representing the broadcast address of this instance.
653 The used prefix size can be overridden by the optional mask parameter.
655 This function has no effect on IPv6 instances, it will return nothing in this
661 @param mask Either a number containing the number of bits (`0..32`
662 for IPv4, `0..128` for IPv6) or a string containing a valid
664 @return Return a new CIDR instance representing the broadcast address if this
665 instance is an IPv4 range, else return nothing.
666 @usage `local range = luci.ip.new("172.19.37.45/16")
667 print(range:broadcast()) -- "172.19.255.255"
668 print(range:broadcast(24)) -- "172.19.37.255"
669 print(range:broadcast("255.0.0.0")) -- "172.255.255.255"`
673 Derive mapped IPv4 address of CIDR instance.
675 Constructs a CIDR instance representing the IPv4 address of the IPv6 mapped
676 IPv4 address in this instance.
678 This function has no effect on IPv4 instances or IPv6 instances which are not a
679 mapped address, it will return nothing in this case.
684 @return Return a new CIDR instance representing the IPv4 address if this
685 instance is an IPv6 mapped IPv4 address, else return nothing.
686 @usage `local addr = luci.ip.new("::ffff:172.16.19.1")
687 print(addr:mapped4()) -- "172.16.19.1"`
691 Test whether CIDR contains given range.
696 @param addr A `luci.ip.cidr` instance or a string convertable by
697 `luci.ip.new()` to test.
698 @return `true` if this instance fully contains the given address else
700 @usage `local range = luci.ip.new("10.24.0.0/255.255.0.0")
701 print(range:contains("10.24.5.1")) -- true
702 print(range:contains("::1")) -- false
703 print(range:contains("10.0.0.0/8")) -- false
705 local range6 = luci.ip.new("fe80::/10")
706 print(range6:contains("fe80::221:63f:fe75:aa17/64")) -- true
707 print(range6:contains("fd9b:6b3:c5:0:221:63f:fe75:aa17/64")) -- false`
711 Add given amount to CIDR instance. If the result would overflow the maximum
712 address space, the result is set to the highest possible address.
717 @param amount A numeric value between 0 and 0xFFFFFFFF, a
718 `luci.ip.cidr` instance or a string convertable by
720 @param inplace If `true`, modify this instance instead of returning
721 a new derived CIDR instance.
723 <li>When adding inplace: Return `true` if the addition succeded
724 or `false` when the addition overflowed.</li>
725 <li>When deriving new CIDR: Return new instance representing the value of
726 this instance plus the added amount or the highest possible address if
727 the addition overflowed the available address space.</li></ul>
728 @usage `local addr = luci.ip.new("192.168.1.1/24")
729 print(addr:add(250)) -- "192.168.1.251/24"
730 print(addr:add("0.0.99.0")) -- "192.168.100.1/24"
732 addr:add(256, true) -- true
733 print(addr) -- "192.168.2.1/24
735 addr:add("255.0.0.0", true) -- false (overflow)
736 print(addr) -- "255.255.255.255/24
738 local addr6 = luci.ip.new("fe80::221:63f:fe75:aa17/64")
739 print(addr6:add(256)) -- "fe80::221:63f:fe75:ab17/64"
740 print(addr6:add("::ffff:0")) -- "fe80::221:640:fe74:aa17/64"
742 addr:add(256, true) -- true
743 print(addr) -- "fe80::221:63f:fe75:ab17/64
745 addr:add("ffff::", true) -- false (overflow)
746 print(addr) -- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64"`
750 Substract given amount from CIDR instance. If the result would under, the lowest
751 possible address is returned.
756 @param amount A numeric value between 0 and 0xFFFFFFFF, a
757 `luci.ip.cidr` instance or a string convertable by
759 @param inplace If `true`, modify this instance instead of returning
760 a new derived CIDR instance.
762 <li>When substracting inplace: Return `true` if the substraction
763 succeded or `false` when the substraction underflowed.</li>
764 <li>When deriving new CIDR: Return new instance representing the value of
765 this instance minus the substracted amount or the lowest address if
766 the substraction underflowed.</li></ul>
767 @usage `local addr = luci.ip.new("192.168.1.1/24")
768 print(addr:sub(256)) -- "192.168.0.1/24"
769 print(addr:sub("0.168.0.0")) -- "192.0.1.1/24"
771 addr:sub(256, true) -- true
772 print(addr) -- "192.168.0.1/24
774 addr:sub("255.0.0.0", true) -- false (underflow)
775 print(addr) -- "0.0.0.0/24
777 local addr6 = luci.ip.new("fe80::221:63f:fe75:aa17/64")
778 print(addr6:sub(256)) -- "fe80::221:63f:fe75:a917/64"
779 print(addr6:sub("::ffff:0")) -- "fe80::221:63e:fe76:aa17/64"
781 addr:sub(256, true) -- true
782 print(addr) -- "fe80::221:63f:fe75:a917/64"
784 addr:sub("ffff::", true) -- false (underflow)
785 print(addr) -- "::/64"`
789 Calculate the lowest possible host address within this CIDR instance.
794 @return Returns a new CIDR instance representing the lowest host address
796 @usage `local addr = luci.ip.new("192.168.123.56/24")
797 print(addr:minhost()) -- "192.168.123.1"
799 local addr6 = luci.ip.new("fd9b:62b3:9cc5:0:221:63ff:fe75:aa17/64")
800 print(addr6:minhost()) -- "fd9b:62b3:9cc5::1"`
804 Calculate the highest possible host address within this CIDR instance.
809 @return Returns a new CIDR instance representing the highest host address
811 @usage `local addr = luci.ip.new("192.168.123.56/24")
812 print(addr:maxhost()) -- "192.168.123.254" (.255 is broadcast)
814 local addr6 = luci.ip.new("fd9b:62b3:9cc5:0:221:63ff:fe75:aa17/64")
815 print(addr6:maxhost()) -- "fd9b:62b3:9cc5:0:ffff:ffff:ffff:ffff"`
819 Convert CIDR instance into string representation.
821 If the prefix size of instance is less than 32 for IPv4 or 128 for IPv6, the
822 address is returned in the form "address/prefix" otherwise just "address".
824 It is usually not required to call this function directly as CIDR objects
825 define it as __tostring function in the associated metatable.
830 @return Returns a string representing the range or address of this CIDR instance