luci.util = require "luci.util"
luci.ip = require "luci.ip"
-local tonumber, ipairs, pairs, pcall, type, next, setmetatable, require =
- tonumber, ipairs, pairs, pcall, type, next, setmetatable, require
+local tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select =
+ tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select
--- LuCI Linux and POSIX system utilities.
return _parse_delimited_table(io.lines("/proc/net/arp"), "%s%s+", callback)
end
+local function _nethints(what, callback)
+ local _, k, e, mac, ip, name
+ local ifn = { }
+ local hosts = { }
+
+ local function _add(i, ...)
+ local k = select(i, ...)
+ if k then
+ if not hosts[k] then hosts[k] = { } end
+ hosts[k][1] = select(1, ...) or hosts[k][1]
+ hosts[k][2] = select(2, ...) or hosts[k][2]
+ hosts[k][3] = select(3, ...) or hosts[k][3]
+ hosts[k][4] = select(4, ...) or hosts[k][4]
+ end
+ end
+
+ if fs.access("/proc/net/arp") then
+ for e in io.lines("/proc/net/arp") do
+ ip, mac = e:match("^([%d%.]+)%s+%S+%s+%S+%s+([a-fA-F0-9:]+)%s+")
+ if ip and mac then
+ _add(what, mac:upper(), ip, nil, nil)
+ end
+ end
+ end
+
+ if fs.access("/etc/ethers") then
+ for e in io.lines("/etc/ethers") do
+ mac, ip = e:match("^([a-f0-9]%S+) (%S+)")
+ if mac and ip then
+ _add(what, mac:upper(), ip, nil, nil)
+ end
+ end
+ end
+
+ if fs.access("/var/dhcp.leases") then
+ for e in io.lines("/var/dhcp.leases") do
+ mac, ip, name = e:match("^%d+ (%S+) (%S+) (%S+)")
+ if mac and ip then
+ _add(what, mac:upper(), ip, nil, name ~= "*" and name)
+ end
+ end
+ end
+
+ for _, e in ipairs(nixio.getifaddrs()) do
+ if e.name ~= "lo" then
+ ifn[e.name] = ifn[e.name] or { }
+ if e.family == "packet" and e.addr and #e.addr == 17 then
+ ifn[e.name][1] = e.addr:upper()
+ elseif e.family == "inet" then
+ ifn[e.name][2] = e.addr
+ elseif e.family == "inet6" then
+ ifn[e.name][3] = e.addr
+ end
+ end
+ end
+
+ for _, e in pairs(ifn) do
+ if e[what] and (e[2] or e[3]) then
+ _add(what, e[1], e[2], e[3], e[4])
+ end
+ end
+
+ for _, e in luci.util.kspairs(hosts) do
+ callback(e[1], e[2], e[3], e[4])
+ end
+end
+
+--- Returns a two-dimensional table of mac address hints.
+-- @return Table of table containing known hosts from various sources.
+-- Each entry contains the values in the following order:
+-- [ "mac", "name" ]
+function net.mac_hints(callback)
+ if callback then
+ _nethints(1, function(mac, v4, v6, name)
+ name = name or nixio.getnameinfo(v4 or v6) or v4
+ if name and name ~= mac then
+ callback(mac, name or nixio.getnameinfo(v4 or v6) or v4)
+ end
+ end)
+ else
+ local rv = { }
+ _nethints(1, function(mac, v4, v6, name)
+ name = name or nixio.getnameinfo(v4 or v6) or v4
+ if name and name ~= mac then
+ rv[#rv+1] = { mac, name or nixio.getnameinfo(v4 or v6) or v4 }
+ end
+ end)
+ return rv
+ end
+end
+
+--- Returns a two-dimensional table of IPv4 address hints.
+-- @return Table of table containing known hosts from various sources.
+-- Each entry contains the values in the following order:
+-- [ "ip", "name" ]
+function net.ipv4_hints(callback)
+ if callback then
+ _nethints(2, function(mac, v4, v6, name)
+ name = name or nixio.getnameinfo(v4) or mac
+ if name and name ~= v4 then
+ callback(v4, name)
+ end
+ end)
+ else
+ local rv = { }
+ _nethints(2, function(mac, v4, v6, name)
+ name = name or nixio.getnameinfo(v4) or mac
+ if name and name ~= v4 then
+ rv[#rv+1] = { v4, name }
+ end
+ end)
+ return rv
+ end
+end
+
+--- Returns a two-dimensional table of IPv6 address hints.
+-- @return Table of table containing known hosts from various sources.
+-- Each entry contains the values in the following order:
+-- [ "ip", "name" ]
+function net.ipv6_hints(callback)
+ if callback then
+ _nethints(3, function(mac, v4, v6, name)
+ name = name or nixio.getnameinfo(v6) or mac
+ if name and name ~= v6 then
+ callback(v6, name)
+ end
+ end)
+ else
+ local rv = { }
+ _nethints(3, function(mac, v4, v6, name)
+ name = name or nixio.getnameinfo(v6) or mac
+ if name and name ~= v6 then
+ rv[#rv+1] = { v6, name }
+ end
+ end)
+ return rv
+ end
+end
+
--- Returns conntrack information
-- @return Table with the currently tracked IP connections
function net.conntrack(callback)
"([a-f0-9]+) +([^%s]+)"
)
- src_ip = luci.ip.Hex(
- src_ip, tonumber(src_prefix, 16), luci.ip.FAMILY_INET6, false
- )
-
- dst_ip = luci.ip.Hex(
- dst_ip, tonumber(dst_prefix, 16), luci.ip.FAMILY_INET6, false
- )
-
- nexthop = luci.ip.Hex( nexthop, 128, luci.ip.FAMILY_INET6, false )
-
- local rt = {
- source = src_ip,
- dest = dst_ip,
- nexthop = nexthop,
- metric = tonumber(metric, 16),
- refcount = tonumber(refcnt, 16),
- usecount = tonumber(usecnt, 16),
- flags = tonumber(flags, 16),
- device = dev,
-
- -- lua number is too small for storing the metric
- -- add a metric_raw field with the original content
- metric_raw = metric
- }
+ if dst_ip and dst_prefix and
+ src_ip and src_prefix and
+ nexthop and metric and
+ refcnt and usecnt and
+ flags and dev
+ then
+ src_ip = luci.ip.Hex(
+ src_ip, tonumber(src_prefix, 16), luci.ip.FAMILY_INET6, false
+ )
+
+ dst_ip = luci.ip.Hex(
+ dst_ip, tonumber(dst_prefix, 16), luci.ip.FAMILY_INET6, false
+ )
+
+ nexthop = luci.ip.Hex( nexthop, 128, luci.ip.FAMILY_INET6, false )
+
+ local rt = {
+ source = src_ip,
+ dest = dst_ip,
+ nexthop = nexthop,
+ metric = tonumber(metric, 16),
+ refcount = tonumber(refcnt, 16),
+ usecount = tonumber(usecnt, 16),
+ flags = tonumber(flags, 16),
+ device = dev,
+
+ -- lua number is too small for storing the metric
+ -- add a metric_raw field with the original content
+ metric_raw = metric
+ }
- if callback then
- callback(rt)
- else
- routes[#routes+1] = rt
+ if callback then
+ callback(rt)
+ else
+ routes[#routes+1] = rt
+ end
end
end
--- Retrieve the current user password hash.
-- @param username String containing the username to retrieve the password for
-- @return String containing the hash or nil if no password is set.
+-- @return Password database entry
function user.getpasswd(username)
local pwe = nixio.getsp and nixio.getsp(username) or nixio.getpw(username)
local pwh = pwe and (pwe.pwdp or pwe.passwd)
if not pwh or #pwh < 1 or pwh == "!" or pwh == "x" then
- return nil
+ return nil, pwe
else
- return pwh
+ return pwh, pwe
end
end
-- @param pass String containing the password to compare
-- @return Boolean indicating wheather the passwords are equal
function user.checkpasswd(username, pass)
- local pwh = user.getpasswd(username)
- if pwh and nixio.crypt(pass, pwh) ~= pwh then
- return false
- else
- return true
+ local pwh, pwe = user.getpasswd(username)
+ if pwe then
+ return (pwh == nil or nixio.crypt(pass, pwh) == pwh)
end
+ return false
end
--- Change the password of given user.
end
end
---- Get iwconfig output for all wireless devices.
--- @return Table of tables containing the iwconfing output for each wifi device
-function wifi.getiwconfig()
- local cnt = luci.util.exec("PATH=/sbin:/usr/sbin iwconfig 2>/dev/null")
- local iwc = {}
-
- for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n\n")) do
- local k = l:match("^(.-) ")
- l = l:gsub("^(.-) +", "", 1)
- if k then
- local entry, flags = _parse_mixed_record(l)
- if entry then
- entry.flags = flags
- end
- iwc[k] = entry
- end
- end
-
- return iwc
-end
-
---- Get iwlist scan output from all wireless devices.
--- @return Table of tables contaiing all scan results
-function wifi.iwscan(iface)
- local siface = iface or ""
- local cnt = luci.util.exec("iwlist "..siface.." scan 2>/dev/null")
- local iws = {}
-
- for i, l in pairs(luci.util.split(luci.util.trim(cnt), "\n\n")) do
- local k = l:match("^(.-) ")
- l = l:gsub("^[^\n]+", "", 1)
- l = luci.util.trim(l)
- if k then
- iws[k] = {}
- for j, c in pairs(luci.util.split(l, "\n Cell")) do
- c = c:gsub("^(.-)- ", "", 1)
- c = luci.util.split(c, "\n", 7)
- c = table.concat(c, "\n", 1)
- local entry, flags = _parse_mixed_record(c)
- if entry then
- entry.flags = flags
- end
- table.insert(iws[k], entry)
- end
- end
- end
-
- return iface and (iws[iface] or {}) or iws
-end
-
--- Get available channels from given wireless iface.
-- @param iface Wireless interface (optional)
-- @return Table of available channels
-- @return Numeric index value
function init.index(name)
if fs.access(init.dir..name) then
- return call("env -i sh -c 'source %s%s; exit $START' >/dev/null"
+ return call("env -i sh -c 'source %s%s enabled; exit ${START:-255}' >/dev/null"
%{ init.dir, name })
end
end