diff options
53 files changed, 1837 insertions, 794 deletions
diff --git a/applications/luci-app-adblock/po/it/adblock.po b/applications/luci-app-adblock/po/it/adblock.po index bdaa2f29ad..88adcc8922 100644 --- a/applications/luci-app-adblock/po/it/adblock.po +++ b/applications/luci-app-adblock/po/it/adblock.po @@ -275,7 +275,7 @@ msgid "" msgstr "" msgid "" -"Size of the download queue to handle downloads & list processing in parallel " +"Size of the download queue to handle downloads & list processing in parallel " "(default '4').<br />" msgstr "" diff --git a/applications/luci-app-adblock/po/ja/adblock.po b/applications/luci-app-adblock/po/ja/adblock.po index d3a0a5c82d..60c5a9a547 100644 --- a/applications/luci-app-adblock/po/ja/adblock.po +++ b/applications/luci-app-adblock/po/ja/adblock.po @@ -301,7 +301,7 @@ msgstr "" "処理エラーまたはドメイン カウントが0以下の場合、メールを送信します。<br />" msgid "" -"Size of the download queue to handle downloads & list processing in parallel " +"Size of the download queue to handle downloads & list processing in parallel " "(default '4').<br />" msgstr "" "ダウンロードの制御とリストの処理を同時並行的に行うダウンロード キューのサイズ" diff --git a/applications/luci-app-adblock/po/pt-br/adblock.po b/applications/luci-app-adblock/po/pt-br/adblock.po index f264ed6779..7eb6e3ebc8 100644 --- a/applications/luci-app-adblock/po/pt-br/adblock.po +++ b/applications/luci-app-adblock/po/pt-br/adblock.po @@ -267,7 +267,7 @@ msgid "" msgstr "" msgid "" -"Size of the download queue to handle downloads & list processing in parallel " +"Size of the download queue to handle downloads & list processing in parallel " "(default '4').<br />" msgstr "" diff --git a/applications/luci-app-adblock/po/ru/adblock.po b/applications/luci-app-adblock/po/ru/adblock.po index 0898213a4f..6e80e80b3a 100644 --- a/applications/luci-app-adblock/po/ru/adblock.po +++ b/applications/luci-app-adblock/po/ru/adblock.po @@ -303,7 +303,7 @@ msgstr "" "≤ 0.<br />" msgid "" -"Size of the download queue to handle downloads & list processing in parallel " +"Size of the download queue to handle downloads & list processing in parallel " "(default '4').<br />" msgstr "" "Значение очереди загрузки для выполнения параллельных загрузок (по умолчанию " diff --git a/applications/luci-app-adblock/po/sv/adblock.po b/applications/luci-app-adblock/po/sv/adblock.po index 5a86d2c92e..d875a69f96 100644 --- a/applications/luci-app-adblock/po/sv/adblock.po +++ b/applications/luci-app-adblock/po/sv/adblock.po @@ -256,7 +256,7 @@ msgid "" msgstr "" msgid "" -"Size of the download queue to handle downloads & list processing in parallel " +"Size of the download queue to handle downloads & list processing in parallel " "(default '4').<br />" msgstr "" diff --git a/applications/luci-app-adblock/po/templates/adblock.pot b/applications/luci-app-adblock/po/templates/adblock.pot index 285bb1dca6..5a93f8f070 100644 --- a/applications/luci-app-adblock/po/templates/adblock.pot +++ b/applications/luci-app-adblock/po/templates/adblock.pot @@ -248,7 +248,7 @@ msgid "" msgstr "" msgid "" -"Size of the download queue to handle downloads & list processing in parallel " +"Size of the download queue to handle downloads & list processing in parallel " "(default '4').<br />" msgstr "" diff --git a/applications/luci-app-adblock/po/zh-cn/adblock.po b/applications/luci-app-adblock/po/zh-cn/adblock.po index 3b8a35b049..1d7dc2b193 100644 --- a/applications/luci-app-adblock/po/zh-cn/adblock.po +++ b/applications/luci-app-adblock/po/zh-cn/adblock.po @@ -266,7 +266,7 @@ msgid "" msgstr "" msgid "" -"Size of the download queue to handle downloads & list processing in parallel " +"Size of the download queue to handle downloads & list processing in parallel " "(default '4').<br />" msgstr "" diff --git a/applications/luci-app-adblock/po/zh-tw/adblock.po b/applications/luci-app-adblock/po/zh-tw/adblock.po index 0d1536ba8a..da00842d53 100644 --- a/applications/luci-app-adblock/po/zh-tw/adblock.po +++ b/applications/luci-app-adblock/po/zh-tw/adblock.po @@ -266,7 +266,7 @@ msgid "" msgstr "" msgid "" -"Size of the download queue to handle downloads & list processing in parallel " +"Size of the download queue to handle downloads & list processing in parallel " "(default '4').<br />" msgstr "" diff --git a/applications/luci-app-attendedsysupgrade/root/etc/uci-defaults/40_luci-attendedsysupgrade b/applications/luci-app-attendedsysupgrade/root/etc/uci-defaults/40_luci-attendedsysupgrade index 832744f7d8..1b890c0cbb 100755 --- a/applications/luci-app-attendedsysupgrade/root/etc/uci-defaults/40_luci-attendedsysupgrade +++ b/applications/luci-app-attendedsysupgrade/root/etc/uci-defaults/40_luci-attendedsysupgrade @@ -2,5 +2,6 @@ rm -rf /tmp/luci-indexcache /tmp/luci-modulecache/ /etc/init.d/uhttpd restart +/etc/init.d/rpcd reload return 0 diff --git a/applications/luci-app-attendedsysupgrade/root/www/luci-static/resources/attendedsysupgrade.js b/applications/luci-app-attendedsysupgrade/root/www/luci-static/resources/attendedsysupgrade.js index c2fe81d58a..604074ad37 100644 --- a/applications/luci-app-attendedsysupgrade/root/www/luci-static/resources/attendedsysupgrade.js +++ b/applications/luci-app-attendedsysupgrade/root/www/luci-static/resources/attendedsysupgrade.js @@ -128,7 +128,7 @@ function ubus_call(command, argument, params, variable) { } } } else { - error_box("<b>Ubus call faild:</b></br>Request: " + request_json + "</br>Response: " + JSON.stringify(response)) + error_box("<b>Ubus call faild:</b><br />Request: " + request_json + "<br />Response: " + JSON.stringify(response)) } ubus_closed++; } @@ -180,7 +180,7 @@ function upgrade_check_callback(request_text) { if(request_json.upgrades != undefined) { info_output += "<h3>Package upgrades available</h3>" for (upgrade in request_json.upgrades) { - info_output += "<b>" + upgrade + "</b>: " + request_json.upgrades[upgrade][1] + " to " + request_json.upgrades[upgrade][0] + "</br>" + info_output += "<b>" + upgrade + "</b>: " + request_json.upgrades[upgrade][1] + " to " + request_json.upgrades[upgrade][0] + "<br />" } } data.packages = request_json.packages @@ -231,9 +231,9 @@ function upgrade_request_callback(request) { var filename_split = data.sysupgrade_url.split("/") data.filename = filename_split[filename_split.length - 1] - info_output = "Firmware created</br><b>" + data.filename + "</b>" + info_output = 'Firmware created: <a href="' + data.sysupgrade_url + '"><b>' + data.filename + '</b></a>' if(data.advanced_mode == 1) { - info_output += '</br><a target="_blank" href="' + data.sysupgrade_url + '.log">Build log</a>' + info_output += '<br /><a target="_blank" href="' + data.sysupgrade_url + '.log">Build log</a>' } info_box(info_output); @@ -373,12 +373,12 @@ function server_request(request_dict, path, callback) { error_box("No firmware created due to image size. Try again with less packages selected.") } else if (request.status === 422) { - error_box("Unknown package in request") - + var package_missing = response.getResponseHeader("X-Unknown-Package"); + error_box("Unknown package in request: <b>" + package_missing + "</b>") } else if (request.status === 500) { request_json = JSON.parse(request_text) - error_box_content = "<b>Internal server error</b></br>" + error_box_content = "<b>Internal server error</b><br />" error_box_content += request_json.error if(request_json.log != undefined) { data.log_url = request_json.log diff --git a/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interface.lua b/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interface.lua index 920dc6afb1..4b1a070d1b 100644 --- a/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interface.lua +++ b/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interface.lua @@ -93,7 +93,7 @@ function configCheck() local trackingNumber = uci:get("mwan3", iface, "track_ip") overview[iface]["tracking"] = 0 - if #trackingNumber > 0 then + if trackingNumber and #trackingNumber > 0 then overview[iface]["tracking"] = #trackingNumber overview[iface]["reliability"] = false local reliabilityNumber = tonumber(uci:get("mwan3", iface, "reliability")) diff --git a/applications/luci-app-mwan3/luasrc/view/mwan/overview_status_interface.htm b/applications/luci-app-mwan3/luasrc/view/mwan/overview_status_interface.htm index 6dc3d12749..86b5ac696b 100644 --- a/applications/luci-app-mwan3/luasrc/view/mwan/overview_status_interface.htm +++ b/applications/luci-app-mwan3/luasrc/view/mwan/overview_status_interface.htm @@ -15,30 +15,27 @@ XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "interface_ for ( var iface in status.interfaces) { var state = ''; - var css = ''; switch (status.interfaces[iface].status) { case 'online': state = '<%:Online (tracking active)%>'; - css = 'wanon'; break; case 'notMonitored': state = '<%:Online (tracking off)%>'; - css = 'wanon'; break; case 'offline': state = '<%:Offline%>'; - css = 'wanoff'; break; default: state = '<%:Disabled%>'; - css = 'wanoff'; break; } statusview += String.format( - '<span class="%s"><strong>%s</strong><br />%s</span>', - css, - iface, + '<div><strong>Interface: </strong>%s</div>', + iface + ); + statusview += String.format( + '<div><strong>Status: </strong>%s</div></br></br>', state ); } @@ -53,36 +50,8 @@ XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "interface_ //]]></script> <fieldset id="interface_field" class="cbi-section"> - <legend><%:MWAN Interface Live Status%></legend> - <div id="mwan_status_text"><img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /><%:Collecting data...%></div> + <legend><%:MWAN Interfaces%></legend> + <div id="mwan_status_text"> + <img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /><%:Collecting data...%> + </div> </fieldset> - -<style type="text/css"> - .container { /* container for entire page. fixes bootstrap theme's ridiculously small page width */ - max-width: 1044px; - } - #mwan_status_text { - display: table; - font-size: 14px; - margin: auto; - max-width: 1044px; - min-width: 246px; - width: 100%; - } - .wanon { - background-color: rgb(144, 240, 144); - } - .wanoff { - background-color: rgb(240, 144, 144); - } - .wanon, .wanoff { - border-radius: 60px; - box-shadow: 0px 2px 5px -3px; - float: left; - margin: 8px 3px 0px 3px; - min-height: 30px; - min-width: 235px; - padding: 5px 10px 8px 10px; - text-align: center; - } -</style> diff --git a/applications/luci-app-mwan3/luasrc/view/mwan/status_interface.htm b/applications/luci-app-mwan3/luasrc/view/mwan/status_interface.htm index 21e59a8017..cb476967f9 100644 --- a/applications/luci-app-mwan3/luasrc/view/mwan/status_interface.htm +++ b/applications/luci-app-mwan3/luasrc/view/mwan/status_interface.htm @@ -14,98 +14,7 @@ </ul> <script type="text/javascript" src="<%=resource%>/cbi.js"></script> -<script type="text/javascript">//<![CDATA[ - XHR.poll(5, '<%=luci.dispatcher.build_url("admin", "status", "mwan", "interface_status")%>', null, - function(x, status) - { - var legend = document.getElementById('diag-rc-legend'); - var statusDiv = document.getElementById('diag-rc-output'); - legend.style.display = 'none'; - if (status.interfaces) - { - var statusview = ''; - for ( var iface in status.interfaces) - { - var state = ''; - var css = ''; - switch (status.interfaces[iface].status) - { - case 'online': - state = '<%:Online (tracking active)%>'; - css = 'wanon'; - break; - case 'notMonitored': - state = '<%:Online (tracking off)%>'; - css = 'wanon'; - break; - case 'offline': - state = '<%:Offline%>'; - css = 'wanoff'; - break; - default: - state = '<%:Disabled%>'; - css = 'wanoff'; - break; - } - statusview += String.format( - '<span class="%s"><strong>%s</strong><br />%s</span>', - css, - iface, - state - ); - } - statusDiv.innerHTML = statusview; - } - else - { - statusDiv.innerHTML = '<strong><%:No MWAN interfaces found%></strong>'; - } - } - ); -//]]></script> -<div class="cbi-map"> - <h2 name="content"><%:MWAN Status - Interface%></h2> - <%if not require("luci.sys").init.enabled("mwan3") then%> - <div><strong><%:INFO: MWAN not running%></strong></div> - <%end%> - <fieldset class="cbi-section"> - <legend id="diag-rc-legend"><%:Collecting data...%></legend> - <span id="diag-rc-output"> - <img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align: middle;" /> - </span> - </fieldset> -</div> - -<style type="text/css"> - #mwan_status_text { - display: table; - font-size: 14px; - margin: auto; - max-width: 1044px; - min-width: 246px; - width: 100%; - } - .wanon { - background-color: rgb(144, 240, 144); - } - .wanoff { - background-color: rgb(240, 144, 144); - } - .wanon, .wanoff { - border-radius: 60px; - box-shadow: 0px 2px 5px -3px; - float: left; - margin: 8px 3px 0px 3px; - min-height: 30px; - min-width: 235px; - padding: 5px 10px 8px 10px; - text-align: center; - } - #mwan_statuslog_text { - padding: 20px; - text-align: left; - } -</style> +<%+mwan/overview_status_interface%> <%+footer%> diff --git a/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/main.lua b/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/main.lua index 74edaf4894..396dedd4a3 100644 --- a/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/main.lua +++ b/applications/luci-app-ocserv/luasrc/model/cbi/ocserv/main.lua @@ -86,7 +86,7 @@ pip.default = "1" local compr = s:taboption("general", Flag, "compression", translate("Enable compression"), translate("Enable compression")) -compr.default = "1" +compr.default = "0" local udp = s:taboption("general", Flag, "udp", translate("Enable UDP"), translate("Enable UDP channel support; this must be enabled unless you know what you are doing")) diff --git a/applications/luci-app-olsr/luasrc/controller/olsr.lua b/applications/luci-app-olsr/luasrc/controller/olsr.lua index 0564bd4ea7..229f3d61b3 100644 --- a/applications/luci-app-olsr/luasrc/controller/olsr.lua +++ b/applications/luci-app-olsr/luasrc/controller/olsr.lua @@ -101,41 +101,19 @@ end local function local_mac_lookup(ipaddr) - local _, ifa, dev - - ipaddr = tostring(ipaddr) - - if not ifaddr_table then - ifaddr_table = nixio.getifaddrs() - end - - -- ipaddr -> ifname - for _, ifa in ipairs(ifaddr_table) do - if ifa.addr == ipaddr then - dev = ifa.name - break - end - end - - -- ifname -> macaddr - for _, ifa in ipairs(ifaddr_table) do - if ifa.name == dev and ifa.family == "packet" then - return ifa.addr - end + local _, rt + for _, rt in ipairs(luci.ip.routes({ type = 1, src = ipaddr })) do + local link = rt.dev and luci.ip.link(rt.dev) + local mac = link and luci.ip.checkmac(link.mac) + if mac then return mac end end end local function remote_mac_lookup(ipaddr) local _, n - - if not neigh_table then - neigh_table = luci.ip.neighbors() - end - - for _, n in ipairs(neigh_table) do - if n.mac and n.dest and n.dest:equal(ipaddr) then - return n.mac - end + for _, n in ipairs(luci.ip.neighbors({ dest = ipaddr })) do + local mac = luci.ip.checkmac(n.mac) + if mac then return mac end end end @@ -201,9 +179,9 @@ function action_neigh(json) for _, val in ipairs(assoclist) do if val.network == interface and val.list then + local assocmac, assot for assocmac, assot in pairs(val.list) do - assocmac = string.lower(assocmac or "") - if rmac == assocmac then + if rmac == luci.ip.checkmac(assocmac) then signal = tonumber(assot.signal) noise = tonumber(assot.noise) snr = (noise*-1) - (signal*-1) diff --git a/applications/luci-app-splash/luasrc/controller/splash/splash.lua b/applications/luci-app-splash/luasrc/controller/splash/splash.lua index 13b8edce6d..b4fdbd53a6 100644 --- a/applications/luci-app-splash/luasrc/controller/splash/splash.lua +++ b/applications/luci-app-splash/luasrc/controller/splash/splash.lua @@ -2,6 +2,7 @@ module("luci.controller.splash.splash", package.seeall) local uci = luci.model.uci.cursor() local util = require "luci.util" +local ipc = require "luci.ip" function index() entry({"admin", "services", "splash"}, cbi("splash/splash"), _("Client-Splash"), 90) @@ -24,30 +25,35 @@ function index() end function ip_to_mac(ip) - local ipc = require "luci.ip" local i, n - - for i, n in ipairs(ipc.neighbors()) do - if n.mac and n.dest and n.dest:equal(ip) then - return n.mac - end + for i, n in ipairs(ipc.neighbors({ dest = ip })) do + local mac = ipc.checkmac(n.mac) + if mac then return mac end end end function action_dispatch() local uci = luci.model.uci.cursor_state() - local mac = ip_to_mac(luci.http.getenv("REMOTE_ADDR")) or "" + local mac = ip_to_mac(luci.http.getenv("REMOTE_ADDR")) local access = false - uci:foreach("luci_splash", "lease", function(s) - if s.mac and s.mac:lower() == mac then access = true end - end) + if mac then + uci:foreach("luci_splash", "lease", function(s) + if ipc.checkmac(s.mac) == mac then + access = true + return false + end + end) - uci:foreach("luci_splash", "whitelist", function(s) - if s.mac and s.mac:lower() == mac then access = true end - end) + uci:foreach("luci_splash", "whitelist", function(s) + if ipc.checkmac(s.mac) == mac then + access = true + return false + end + end) + end - if #mac > 0 and access then + if access then luci.http.redirect(luci.dispatcher.build_url()) else luci.http.redirect(luci.dispatcher.build_url("splash", "splash")) @@ -56,33 +62,39 @@ end function blacklist() leased_macs = { } - uci:foreach("luci_splash", "blacklist", - function(s) leased_macs[s.mac:lower()] = true + uci:foreach("luci_splash", "blacklist", function(s) + local m = ipc.checkmac(s.mac) + if m then leased_macs[m] = true end end) return leased_macs end function action_activate() local ipc = require "luci.ip" - local mac = ip_to_mac(luci.http.getenv("REMOTE_ADDR") or "127.0.0.1") or "" + local mac = ip_to_mac(luci.http.getenv("REMOTE_ADDR") or "127.0.0.1") local uci_state = require "luci.model.uci".cursor_state() local blacklisted = false if mac and luci.http.formvalue("accept") then - uci:foreach("luci_splash", "blacklist", - function(s) if s.mac and s.mac:lower() == mac then blacklisted = true end + uci:foreach("luci_splash", "blacklist", function(s) + if ipc.checkmac(s.mac) == mac then + blacklisted = true + return false + end end) + if blacklisted then luci.http.redirect(luci.dispatcher.build_url("splash" ,"blocked")) else + local id = tostring(mac):gsub(':', ''):lower() local redirect_url = uci:get("luci_splash", "general", "redirect_url") if not redirect_url then - redirect_url = uci_state:get("luci_splash_locations", mac:gsub(':', ''):lower(), "location") + redirect_url = uci_state:get("luci_splash_locations", id, "location") end if not redirect_url then redirect_url = luci.model.uci.cursor():get("freifunk", "community", "homepage") or 'http://www.freifunk.net' end - remove_redirect(mac:gsub(':', ''):lower()) - os.execute("luci-splash lease "..mac.." >/dev/null 2>&1") + remove_redirect(id) + os.execute("luci-splash lease "..tostring(mac).." >/dev/null 2>&1") luci.http.redirect(redirect_url) end else @@ -101,6 +113,7 @@ function action_status_admin() remove = { } } + local key, _ for key, _ in pairs(macs) do local policy = luci.http.formvalue("policy.%s" % key) local mac = luci.http.protocol.urldecode(key) @@ -141,17 +154,17 @@ function action_status_public() luci.template.render("admin_status/splash", { is_admin = false }) end -function remove_redirect(mac) - local mac = mac:lower() - mac = mac:gsub(":", "") +function remove_redirect(id) local uci = require "luci.model.uci".cursor_state() local redirects = uci:get_all("luci_splash_locations") --uci:load("luci_splash_locations") uci:revert("luci_splash_locations") + -- For all redirects + local k, v for k, v in pairs(redirects) do if v[".type"] == "redirect" then - if v[".name"] ~= mac then + if v[".name"] ~= id then -- Rewrite state uci:section("luci_splash_locations", "redirect", v[".name"], { location = v.location @@ -159,5 +172,6 @@ function remove_redirect(mac) end end end + uci:save("luci_splash_redirects") end diff --git a/applications/luci-app-splash/luasrc/view/admin_status/splash.htm b/applications/luci-app-splash/luasrc/view/admin_status/splash.htm index 3415c205d5..37f67776aa 100644 --- a/applications/luci-app-splash/luasrc/view/admin_status/splash.htm +++ b/applications/luci-app-splash/luasrc/view/admin_status/splash.htm @@ -6,6 +6,8 @@ <%- local utl = require "luci.util" +local sys = require "luci.sys" +local ipc = require "luci.ip" local ipt = require "luci.sys.iptparser".IptParser() local uci = require "luci.model.uci".cursor_state() local wat = require "luci.tools.webadmin" @@ -14,21 +16,15 @@ local fs = require "nixio.fs" local clients = { } local leasetime = tonumber(uci:get("luci_splash", "general", "leasetime") or 1) * 60 * 60 -local leasefile = "/tmp/dhcp.leases" - -uci:foreach("dhcp", "dnsmasq", - function(s) - if s.leasefile then leasefile = s.leasefile end - end) - uci:foreach("luci_splash_leases", "lease", function(s) - if s.start and s.mac then - clients[s.mac:lower()] = { + local m = ipc.checkmac(s.mac) + if m and s.start then + clients[m] = { start = tonumber(s.start), limit = ( tonumber(s.start) + leasetime ), - mac = s.mac:upper(), + mac = m, ipaddr = s.ipaddr, policy = "normal", packets = 0, @@ -39,11 +35,12 @@ uci:foreach("luci_splash_leases", "lease", for _, r in ipairs(ipt:find({table="nat", chain="luci_splash_leases"})) do if r.options and #r.options >= 2 and r.options[1] == "MAC" then - if not clients[r.options[2]:lower()] then - clients[r.options[2]:lower()] = { + local m = ipc.checkmac(r.options[2]) + if m and not clients[m] then + clients[m] = { start = 0, limit = 0, - mac = r.options[2]:upper(), + mac = m, policy = ( r.target == "RETURN" ) and "whitelist" or "blacklist", packets = 0, bytes = 0 @@ -60,7 +57,7 @@ for mac, client in pairs(clients) do if client.ipaddr then local rin = ipt:find({table="mangle", chain="luci_splash_mark_in", destination=client.ipaddr}) - local rout = ipt:find({table="mangle", chain="luci_splash_mark_out", options={"MAC", client.mac:upper()}}) + local rout = ipt:find({table="mangle", chain="luci_splash_mark_out", options={"MAC", client.mac}}) if rin and #rin > 0 then client.bytes_in = rin[1].bytes @@ -76,39 +73,27 @@ end uci:foreach("luci_splash", "whitelist", function(s) - if s.mac and clients[s.mac:lower()] then - clients[s.mac:lower()].policy="whitelist" + local m = ipc.checkmac(s.mac) + if m and clients[m] then + clients[m].policy="whitelist" end end) uci:foreach("luci_splash", "blacklist", function(s) - if s.mac and clients[s.mac:lower()] then - clients[s.mac:lower()].policy=(s.kicked and "kicked" or "blacklist") + local m = ipc.checkmac(s.mac) + if m and clients[m] then + clients[m].policy=(s.kicked and "kicked" or "blacklist") end end) -if fs.access(leasefile) then - for l in io.lines(leasefile) do - local time, mac, ip, name = l:match("^(%d+) (%S+) (%S+) (%S+)") - if time and mac and ip then - local c = clients[mac:lower()] - if c then - c.ip = ip - c.hostname = ( name ~= "*" ) and name or nil - end - end +sys.net.host_hints(function(mac, v4, v6, name) + local c = mac and clients[mac] + if c then + c.ip = c.ip or v4 + c.hostname = c.hostname or name end -end - -for i, n in ipairs(ipc.neighbors({ family = 4 })) do - if n.mac and n.dest then - local c = clients[n.mac] - if c and not c.ip then - c.ip = n.dest:string() - end - end -end +end) local function showmac(mac) if not is_admin then @@ -176,7 +161,7 @@ end splash.hostname, splash.ip, splash.mac, splash.timeleft, splash.trafficin, splash.trafficout); <% if is_admin then %> - s += String.format('<select name="policy.%s" style="width:200px">', splash.mac.toLowerCase()); + s += String.format('<select name="policy.%s" style="width:200px">', splash.mac); if (splash.policy == 'whitelist') { s += '<option value="whitelist" selected="selected"><%:whitelisted%></option>' } else { @@ -196,7 +181,7 @@ end s += String.format( '</select>' + '<input type="submit" class="cbi-button cbi-button-save" name="save.%s" value="<%:Save%>" />', - splash.mac.toLowerCase()); + splash.mac); <% else %> s += String.format('%s', splash.policy); <% end %> diff --git a/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua b/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua index 2a8aceec08..9f7a51a868 100644 --- a/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua +++ b/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua @@ -3,25 +3,80 @@ module("luci.statistics.rrdtool.definitions.apcups",package.seeall) -function rrdargs( graph, plugin, plugin_instance, dtype ) +function rrdargs( graph, plugin, plugin_instance ) + + local lu = require("luci.util") + local rv = { } + + -- Types and instances supported by APC UPS + -- e.g. ups_types -> { 'timeleft', 'charge', 'percent', 'voltage' } + -- e.g. ups_inst['voltage'] -> { 'input', 'battery' } + + local ups_types = graph.tree:data_types( plugin, plugin_instance ) + + local ups_inst = {} + for _, t in ipairs(ups_types) do + ups_inst[t] = graph.tree:data_instances( plugin, plugin_instance, t ) + end + + + -- Check if hash table or array is empty or nil-filled + + local function empty( t ) + for _, v in pairs(t) do + if type(v) then return false end + end + return true + end + + + -- Append graph definition but only types/instances which are + -- supported and available to the plugin and UPS. + + local function add_supported( t, defs ) + local def_inst = defs['data']['instances'] + + if type(def_inst) == "table" then + for k, v in pairs( def_inst ) do + if lu.contains( ups_types, k) then + for j = #v, 1, -1 do + if not lu.contains( ups_inst[k], v[j] ) then + table.remove( v, j ) + end + end + if #v == 0 then + def_inst[k] = nil -- can't assign v: immutable + end + else + def_inst[k] = nil -- can't assign v: immutable + end + end + if empty(def_inst) then return end + end + table.insert( t, defs ) + end + + + -- Graph definitions for APC UPS measurements MUST use only 'instances': + -- e.g. instances = { voltage = { "input", "output" } } local voltagesdc = { title = "%H: Voltages on APC UPS - Battery", vlabel = "Volts DC", - alt_autoscale = true, + alt_autoscale = true, number_format = "%5.1lfV", data = { instances = { voltage = { "battery" } }, - - options = { + options = { voltage = { title = "Battery voltage", noarea=true } } } } - - local voltages = { + add_supported( rv, voltagesdc ) + + local voltagesac = { title = "%H: Voltages on APC UPS - AC", vlabel = "Volts AC", alt_autoscale = true, @@ -30,13 +85,13 @@ function rrdargs( graph, plugin, plugin_instance, dtype ) instances = { voltage = { "input", "output" } }, - options = { voltage_output = { color = "00e000", title = "Output voltage", noarea=true, overlay=true }, voltage_input = { color = "ffb000", title = "Input voltage", noarea=true, overlay=true } } } } + add_supported( rv, voltagesac ) local percentload = { title = "%H: Load on APC UPS ", @@ -45,17 +100,15 @@ function rrdargs( graph, plugin, plugin_instance, dtype ) y_max = "100", number_format = "%5.1lf%%", data = { - sources = { - percent_load = { "value" } - }, instances = { - percent = "load" + percent = { "load" } }, options = { percent_load = { color = "00ff00", title = "Load level" } } } } + add_supported( rv, percentload ) local charge_percent = { title = "%H: Battery charge on APC UPS ", @@ -64,54 +117,59 @@ function rrdargs( graph, plugin, plugin_instance, dtype ) y_max = "100", number_format = "%5.1lf%%", data = { - types = { "charge" }, + instances = { + charge = { "" } + }, options = { charge = { color = "00ff0b", title = "Charge level" } } } } + add_supported( rv, charge_percent ) local temperature = { title = "%H: Battery temperature on APC UPS ", vlabel = "\176C", number_format = "%5.1lf\176C", data = { - types = { "temperature" }, + instances = { + temperature = { "" } + }, options = { temperature = { color = "ffb000", title = "Battery temperature" } } } } + add_supported( rv, temperature ) local timeleft = { title = "%H: Time left on APC UPS ", vlabel = "Minutes", number_format = "%.1lfm", data = { - sources = { - timeleft = { "value" } + instances = { + timeleft = { "" } }, options = { timeleft = { color = "0000ff", title = "Time left" } } } } + add_supported( rv, timeleft ) local frequency = { title = "%H: Incoming line frequency on APC UPS ", vlabel = "Hz", number_format = "%5.0lfhz", data = { - sources = { - frequency_input = { "value" } - }, instances = { - frequency = "frequency" + frequency = { "input" } }, options = { - frequency_frequency = { color = "000fff", title = "Line frequency" } + frequency_input = { color = "000fff", title = "Line frequency" } } } } + add_supported( rv, frequency ) - return { voltages, voltagesdc, percentload, charge_percent, temperature, timeleft, frequency } + return rv end diff --git a/applications/luci-app-travelmate/Makefile b/applications/luci-app-travelmate/Makefile index 6170f9d4c3..2bd25bc171 100644 --- a/applications/luci-app-travelmate/Makefile +++ b/applications/luci-app-travelmate/Makefile @@ -1,11 +1,11 @@ -# Copyright 2017 Dirk Brenken (dev@brenken.org) +# Copyright 2017-2018 Dirk Brenken (dev@brenken.org) # This is free software, licensed under the Apache License, Version 2.0 # include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI support for Travelmate -LUCI_DEPENDS:=+travelmate +luci-lib-jsonc +LUCI_DEPENDS:=+travelmate +luci-lib-jsonc +qrencode LUCI_PKGARCH:=all include ../../luci.mk diff --git a/applications/luci-app-travelmate/luasrc/controller/travelmate.lua b/applications/luci-app-travelmate/luasrc/controller/travelmate.lua index 0f7583497f..14b8d77ff6 100644 --- a/applications/luci-app-travelmate/luasrc/controller/travelmate.lua +++ b/applications/luci-app-travelmate/luasrc/controller/travelmate.lua @@ -3,7 +3,6 @@ module("luci.controller.travelmate", package.seeall) -local fs = require("nixio.fs") local util = require("luci.util") local i18n = require("luci.i18n") local templ = require("luci.template") @@ -15,7 +14,8 @@ function index() entry({"admin", "services", "travelmate"}, firstchild(), _("Travelmate"), 40).dependent = false entry({"admin", "services", "travelmate", "tab_from_cbi"}, cbi("travelmate/overview_tab", {hideresetbtn=true, hidesavebtn=true}), _("Overview"), 10).leaf = true entry({"admin", "services", "travelmate", "stations"}, template("travelmate/stations"), _("Wireless Stations"), 20).leaf = true - entry({"admin", "services", "travelmate", "logfile"}, call("logread"), _("View Logfile"), 30).leaf = true + entry({"admin", "services", "travelmate", "apqr"}, template("travelmate/ap_qr"), _("AP QR-Codes"), 30).leaf = true + entry({"admin", "services", "travelmate", "logfile"}, call("logread"), _("View Logfile"), 40).leaf = true entry({"admin", "services", "travelmate", "advanced"}, firstchild(), _("Advanced"), 100) entry({"admin", "services", "travelmate", "advanced", "configuration"}, cbi("travelmate/configuration_tab"), _("Edit Travelmate Configuration"), 110).leaf = true entry({"admin", "services", "travelmate", "advanced", "cfg_wireless"}, cbi("travelmate/cfg_wireless_tab"), _("Edit Wireless Configuration"), 120).leaf = true diff --git a/applications/luci-app-travelmate/luasrc/view/travelmate/ap_qr.htm b/applications/luci-app-travelmate/luasrc/view/travelmate/ap_qr.htm new file mode 100644 index 0000000000..13342a3e66 --- /dev/null +++ b/applications/luci-app-travelmate/luasrc/view/travelmate/ap_qr.htm @@ -0,0 +1,62 @@ +<%# +Copyright 2018 Dirk Brenken (dev@brenken.org) +This is free software, licensed under the Apache License, Version 2.0 +-%> + +<%+header%> + +<div class="cbi-map"> + <div class="cbi-map-descr"> + <%=translate("Here you'll find the QR codes from all of your configured Access Points. It allows you to connect your Android or iOS devices to your router's WiFi using the QR code shown below.")%> + </div> +<%- + local write = io.write + local uci = require("luci.model.uci").cursor() + + uci:foreach("wireless", "wifi-iface", function(s) + local device = s.device or "" + local mode = s.mode or "" + local ssid = s.ssid or "" + local enc = s.encryption or "" + local key = s.key or "" + local hidden = s.hidden or "false" + local disabled = s.disabled or "" + local wep_slots = {s.key1 or "", s.key2 or "", s.key3 or "", s.key4 or ""} + + if device and mode == "ap" and disabled ~= "1" then + if string.match(enc, '^psk') then + enc = "WPA" + elseif string.match(enc, '^wep') then + enc = "WEP" + if tonumber(key) then + key = wep_slots[tonumber(key)] + end + elseif enc == "none" then + enc = "nopass" + key = "nokey" + else + enc = "" + end + if hidden == "1" then + hidden = "true" + end + if ssid and enc and key then + local e_ssid = string.gsub(ssid,"[\"\\';:, ]",[[\\\%1]]) + local e_key = string.gsub(key,"[\"\\';:, ]",[[\\\%1]]) + local qrcode = "" + if nixio.fs.access("/usr/bin/qrencode") then + qrcode = luci.sys.exec("/usr/bin/qrencode --inline --8bit --type=SVG --output=- 'WIFI:S:\"'" .. e_ssid .. "'\";T:'" .. enc .. "';P:\"'" .. e_key .. "'\";H:'" .. hidden .. "';'") + end +-%> + <fieldset class="cbi-section"> + <legend>AP on <%=device%> with SSID "<%=ssid%>"</legend> + <h3 name="content"><%=qrcode%></h3> + </fieldset> +<%- + end + end + end) +%> +</div> + +<%+footer%> diff --git a/applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm b/applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm index a267339950..1dacb6e24b 100644 --- a/applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm +++ b/applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm @@ -12,7 +12,6 @@ This is free software, licensed under the Apache License, Version 2.0 <%+header%> <div class="cbi-map"> -<h2 name="content"><%:Wireless Stations%></h2> <div class="cbi-map-descr"> <%=translatef("Provides an overview of all configured uplinks for the travelmate interface (%s). You can edit, delete or re-order existing uplinks or scan for a new one. The currently used uplink is emphasized in blue.", trmiface)%> </div> diff --git a/applications/luci-app-travelmate/po/ja/travelmate.po b/applications/luci-app-travelmate/po/ja/travelmate.po index 56e3badabb..30f34ef309 100644 --- a/applications/luci-app-travelmate/po/ja/travelmate.po +++ b/applications/luci-app-travelmate/po/ja/travelmate.po @@ -7,11 +7,14 @@ msgstr "" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.0.5\n" +"X-Generator: Poedit 2.0.6\n" "Last-Translator: INAGAKI Hiroshi <musashino.open@gmail.com>\n" "Plural-Forms: nplurals=1; plural=0;\n" "Language: ja\n" +msgid "AP QR-Codes" +msgstr "AP QR-コード" + msgid "Actions" msgstr "操作" @@ -43,6 +46,16 @@ msgstr "BSSID" msgid "Back to overview" msgstr "概要へ戻る" +msgid "Captive Portal Detection" +msgstr "キャプティブポータル検知" + +msgid "" +"Check the internet availability, log captive portal redirections and keep " +"the uplink connection 'alive'." +msgstr "" +"インターネットの利用可否を確認し、キャプティブポータル リダイレクトを記録して" +"アップリンク接続を 'alive' として保持します。" + msgid "Cipher" msgstr "暗号化方式" @@ -135,13 +148,18 @@ msgid "Force a manual uplink rescan / reconnect in 'trigger' mode." msgstr "" "'trigger' モード時に、手動でアップリンクの再スキャンと再接続を行います。" -msgid "How long should travelmate wait for a successful wlan interface reload." +msgid "" +"Here you'll find the QR codes from all of your configured Access Points. It " +"allows you to connect your Android or iOS devices to your router's WiFi " +"using the QR code shown below." msgstr "" -"無線LAN インターフェースのリロードが成功するまでの、Travelmate の待機時間で" -"す。" +"ここには、構成済みの全アクセスポイントの QR コードを表示しています。以下の " +"QR コードを使用して、 Android または iOS デバイスをルータの WiFi に接続するこ" +"とができます。" -msgid "How many times should travelmate try to connect to an Uplink." -msgstr "Travelmate がアップリンクへの接続を試行する回数です。" +msgid "" +"How long should travelmate wait for a successful wlan uplink connection." +msgstr "Travelmate が無線アップリンクへの接続成功を待つ時間です。" msgid "Identity" msgstr "ID" @@ -171,6 +189,13 @@ msgstr "最終実行日時" msgid "Manual Rescan" msgstr "手動再スキャン" +msgid "" +"Minimum signal quality threshold as percent for conditional uplink (dis-) " +"connections." +msgstr "" +"条件付きアップリンク接続(または切断)のための、シグナル品質閾値の下限(%)で" +"す。" + msgid "Move down" msgstr "下へ" @@ -233,6 +258,9 @@ msgstr "再スキャン" msgid "Restrict travelmate to a dedicated radio, e.g. 'radio0'." msgstr "Travelmate が指定された無線に接続するよう制御します。(例: 'radio0')" +msgid "Retry limit to connect to an uplink." +msgstr "アップリンクへの接続を試行する回数です。" + msgid "Runtime Information" msgstr "実行情報" @@ -248,6 +276,9 @@ msgstr "保存" msgid "Scan" msgstr "スキャン:" +msgid "Signal Quality Threshold" +msgstr "シグナル品質閾値" + msgid "Signal strength" msgstr "信号強度" @@ -298,24 +329,20 @@ msgstr "" msgid "Timeout in seconds between retries in 'automatic' mode." msgstr "'automatic' モード時に接続を確認または再試行する間隔(秒)です。" -msgid "To disable this feature set it to '0' which means unlimited retries." -msgstr "" -"この機能を無効にして接続の再試行を無制限にする場合、 '0' を設定します。" - msgid "Travelmate" msgstr "Travelmate" msgid "Travelmate Logfile" msgstr "Travelmate ログファイル" -msgid "Travelmate Status" -msgstr "Travelmate ステータス" +msgid "Travelmate Status (Quality)" +msgstr "Travelmate ステータス(品質)" msgid "Travelmate Version" msgstr "Travelmate バージョン" -msgid "Trigger delay" -msgstr "トリガー遅延" +msgid "Trigger Delay" +msgstr "トリガ遅延" msgid "Unknown" msgstr "不明" @@ -365,20 +392,8 @@ msgstr "" "ファイアウォールの wan ゾーンに追加します。このステップは、一度だけ実行される" "必要があります。" -msgid "connected" -msgstr "接続済" - -msgid "error" -msgstr "エラー" - msgid "hidden" msgstr "(不明)" msgid "n/a" msgstr "利用不可" - -msgid "not connected" -msgstr "未接続" - -msgid "running" -msgstr "実行中" diff --git a/applications/luci-app-travelmate/po/pt-br/travelmate.po b/applications/luci-app-travelmate/po/pt-br/travelmate.po index cf17b024ec..7cb6ac0613 100644 --- a/applications/luci-app-travelmate/po/pt-br/travelmate.po +++ b/applications/luci-app-travelmate/po/pt-br/travelmate.po @@ -12,6 +12,9 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "Language: pt_BR\n" +msgid "AP QR-Codes" +msgstr "" + msgid "Actions" msgstr "" @@ -43,6 +46,14 @@ msgstr "" msgid "Back to overview" msgstr "" +msgid "Captive Portal Detection" +msgstr "" + +msgid "" +"Check the internet availability, log captive portal redirections and keep " +"the uplink connection 'alive'." +msgstr "" + msgid "Cipher" msgstr "" @@ -129,10 +140,14 @@ msgstr "" msgid "Force a manual uplink rescan / reconnect in 'trigger' mode." msgstr "" -msgid "How long should travelmate wait for a successful wlan interface reload." +msgid "" +"Here you'll find the QR codes from all of your configured Access Points. It " +"allows you to connect your Android or iOS devices to your router's WiFi " +"using the QR code shown below." msgstr "" -msgid "How many times should travelmate try to connect to an Uplink." +msgid "" +"How long should travelmate wait for a successful wlan uplink connection." msgstr "" msgid "Identity" @@ -161,6 +176,11 @@ msgstr "" msgid "Manual Rescan" msgstr "" +msgid "" +"Minimum signal quality threshold as percent for conditional uplink (dis-) " +"connections." +msgstr "" + msgid "Move down" msgstr "" @@ -219,6 +239,9 @@ msgstr "" msgid "Restrict travelmate to a dedicated radio, e.g. 'radio0'." msgstr "" +msgid "Retry limit to connect to an uplink." +msgstr "" + msgid "Runtime Information" msgstr "" @@ -234,6 +257,9 @@ msgstr "" msgid "Scan" msgstr "" +msgid "Signal Quality Threshold" +msgstr "" + msgid "Signal strength" msgstr "" @@ -274,22 +300,19 @@ msgstr "" msgid "Timeout in seconds between retries in 'automatic' mode." msgstr "" -msgid "To disable this feature set it to '0' which means unlimited retries." -msgstr "" - msgid "Travelmate" msgstr "Travelmate" msgid "Travelmate Logfile" msgstr "" -msgid "Travelmate Status" +msgid "Travelmate Status (Quality)" msgstr "" msgid "Travelmate Version" msgstr "" -msgid "Trigger delay" +msgid "Trigger Delay" msgstr "" msgid "Unknown" @@ -338,24 +361,12 @@ msgid "" "add it to the wan zone of the firewall. This step has only to be done once." msgstr "" -msgid "connected" -msgstr "" - -msgid "error" -msgstr "" - msgid "hidden" msgstr "" msgid "n/a" msgstr "" -msgid "not connected" -msgstr "" - -msgid "running" -msgstr "" - #~ msgid "" #~ "Brief advice: Create a wwan interface, configure it to use dhcp and add " #~ "it to the wan zone in firewall. Create the wifi interfaces to be used " diff --git a/applications/luci-app-travelmate/po/ru/travelmate.po b/applications/luci-app-travelmate/po/ru/travelmate.po index fe0e476471..0b04e27838 100644 --- a/applications/luci-app-travelmate/po/ru/travelmate.po +++ b/applications/luci-app-travelmate/po/ru/travelmate.po @@ -15,6 +15,9 @@ msgstr "" "Project-Info: Это технический перевод, не дословный. Главное-удобный русский " "интерфейс, все проверялось в графическом режиме, совместим с другими apps\n" +msgid "AP QR-Codes" +msgstr "" + msgid "Actions" msgstr "Действия" @@ -46,6 +49,14 @@ msgstr "BSSID" msgid "Back to overview" msgstr "Назад в меню" +msgid "Captive Portal Detection" +msgstr "" + +msgid "" +"Check the internet availability, log captive portal redirections and keep " +"the uplink connection 'alive'." +msgstr "" + msgid "Cipher" msgstr "Алгоритм шифрования" @@ -138,13 +149,15 @@ msgstr "" "Принудительно выполнить повторное сканирование/повторное подключение внешних " "сетей в режиме 'ручной'." -msgid "How long should travelmate wait for a successful wlan interface reload." +msgid "" +"Here you'll find the QR codes from all of your configured Access Points. It " +"allows you to connect your Android or iOS devices to your router's WiFi " +"using the QR code shown below." msgstr "" -"Временная задержка необходима TravelMate для полной перезагрузки wlan " -"интерфейса." -msgid "How many times should travelmate try to connect to an Uplink." -msgstr "Сколько раз TravelMate должен пытаться подключиться к сети. " +msgid "" +"How long should travelmate wait for a successful wlan uplink connection." +msgstr "" msgid "Identity" msgstr "Идентификация EAP" @@ -174,6 +187,11 @@ msgstr "Дата последнего запуска" msgid "Manual Rescan" msgstr "Поиск сети вручную" +msgid "" +"Minimum signal quality threshold as percent for conditional uplink (dis-) " +"connections." +msgstr "" + msgid "Move down" msgstr "Переместить вниз" @@ -238,6 +256,9 @@ msgstr "Пересканировать" msgid "Restrict travelmate to a dedicated radio, e.g. 'radio0'." msgstr "Выделить TravelMate-у конкретное Wi-Fi устройство, например 'radio0'." +msgid "Retry limit to connect to an uplink." +msgstr "" + msgid "Runtime Information" msgstr "Информация о состоянии" @@ -253,6 +274,9 @@ msgstr "Сохранить" msgid "Scan" msgstr "Поиск" +msgid "Signal Quality Threshold" +msgstr "" + msgid "Signal strength" msgstr "Мощность сигнала" @@ -305,25 +329,20 @@ msgstr "" "Время ожидания в секундах между повторными попытками соединения в режиме " "'автоматически'." -msgid "To disable this feature set it to '0' which means unlimited retries." -msgstr "" -"<br />Чтобы отключить эту функцию, установите значение '0', что означает " -"неограниченное количество попыток." - msgid "Travelmate" msgstr "TravelMate" msgid "Travelmate Logfile" msgstr "Системный журнал TravelMate" -msgid "Travelmate Status" -msgstr "Состояние Travelmate" +msgid "Travelmate Status (Quality)" +msgstr "" msgid "Travelmate Version" msgstr "Версия TravelMate" -msgid "Trigger delay" -msgstr "Задержка запуска" +msgid "Trigger Delay" +msgstr "" msgid "Unknown" msgstr "Неизвестно" @@ -371,20 +390,40 @@ msgid "" "add it to the wan zone of the firewall. This step has only to be done once." msgstr "добавить в wan зону межсетевого экрана. Можно сделать только один раз." -msgid "connected" -msgstr "подключен" - -msgid "error" -msgstr "ошибка" - msgid "hidden" msgstr "скрытый" msgid "n/a" msgstr "нет данных" -msgid "not connected" -msgstr "не подключено" +#~ msgid "" +#~ "How long should travelmate wait for a successful wlan interface reload." +#~ msgstr "" +#~ "Временная задержка необходима TravelMate для полной перезагрузки wlan " +#~ "интерфейса." + +#~ msgid "How many times should travelmate try to connect to an Uplink." +#~ msgstr "Сколько раз TravelMate должен пытаться подключиться к сети. " + +#~ msgid "To disable this feature set it to '0' which means unlimited retries." +#~ msgstr "" +#~ "<br />Чтобы отключить эту функцию, установите значение '0', что означает " +#~ "неограниченное количество попыток." + +#~ msgid "Travelmate Status" +#~ msgstr "Состояние Travelmate" + +#~ msgid "Trigger delay" +#~ msgstr "Задержка запуска" + +#~ msgid "connected" +#~ msgstr "подключен" + +#~ msgid "error" +#~ msgstr "ошибка" + +#~ msgid "not connected" +#~ msgstr "не подключено" -msgid "running" -msgstr "работает" +#~ msgid "running" +#~ msgstr "работает" diff --git a/applications/luci-app-travelmate/po/templates/travelmate.pot b/applications/luci-app-travelmate/po/templates/travelmate.pot index aeefa491db..e27c61a9d0 100644 --- a/applications/luci-app-travelmate/po/templates/travelmate.pot +++ b/applications/luci-app-travelmate/po/templates/travelmate.pot @@ -1,6 +1,9 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" +msgid "AP QR-Codes" +msgstr "" + msgid "Actions" msgstr "" @@ -32,6 +35,14 @@ msgstr "" msgid "Back to overview" msgstr "" +msgid "Captive Portal Detection" +msgstr "" + +msgid "" +"Check the internet availability, log captive portal redirections and keep " +"the uplink connection 'alive'." +msgstr "" + msgid "Cipher" msgstr "" @@ -118,10 +129,14 @@ msgstr "" msgid "Force a manual uplink rescan / reconnect in 'trigger' mode." msgstr "" -msgid "How long should travelmate wait for a successful wlan interface reload." +msgid "" +"Here you'll find the QR codes from all of your configured Access Points. It " +"allows you to connect your Android or iOS devices to your router's WiFi " +"using the QR code shown below." msgstr "" -msgid "How many times should travelmate try to connect to an Uplink." +msgid "" +"How long should travelmate wait for a successful wlan uplink connection." msgstr "" msgid "Identity" @@ -150,6 +165,11 @@ msgstr "" msgid "Manual Rescan" msgstr "" +msgid "" +"Minimum signal quality threshold as percent for conditional uplink (dis-) " +"connections." +msgstr "" + msgid "Move down" msgstr "" @@ -208,6 +228,9 @@ msgstr "" msgid "Restrict travelmate to a dedicated radio, e.g. 'radio0'." msgstr "" +msgid "Retry limit to connect to an uplink." +msgstr "" + msgid "Runtime Information" msgstr "" @@ -223,6 +246,9 @@ msgstr "" msgid "Scan" msgstr "" +msgid "Signal Quality Threshold" +msgstr "" + msgid "Signal strength" msgstr "" @@ -263,22 +289,19 @@ msgstr "" msgid "Timeout in seconds between retries in 'automatic' mode." msgstr "" -msgid "To disable this feature set it to '0' which means unlimited retries." -msgstr "" - msgid "Travelmate" msgstr "" msgid "Travelmate Logfile" msgstr "" -msgid "Travelmate Status" +msgid "Travelmate Status (Quality)" msgstr "" msgid "Travelmate Version" msgstr "" -msgid "Trigger delay" +msgid "Trigger Delay" msgstr "" msgid "Unknown" @@ -327,20 +350,8 @@ msgid "" "add it to the wan zone of the firewall. This step has only to be done once." msgstr "" -msgid "connected" -msgstr "" - -msgid "error" -msgstr "" - msgid "hidden" msgstr "" msgid "n/a" msgstr "" - -msgid "not connected" -msgstr "" - -msgid "running" -msgstr "" diff --git a/applications/luci-app-wol/luasrc/model/cbi/wol.lua b/applications/luci-app-wol/luasrc/model/cbi/wol.lua index ec6a1be2a8..d40dde0178 100644 --- a/applications/luci-app-wol/luasrc/model/cbi/wol.lua +++ b/applications/luci-app-wol/luasrc/model/cbi/wol.lua @@ -2,6 +2,7 @@ -- Licensed to the public under the Apache License 2.0. local sys = require "luci.sys" +local ipc = require "luci.ip" local fs = require "nixio.fs" m = SimpleForm("wol", translate("Wake on LAN"), @@ -58,7 +59,8 @@ end function host.write(self, s, val) local host = luci.http.formvalue("cbid.wol.1.mac") - if host and #host > 0 and host:match("^[a-fA-F0-9:]+$") then + local mac = ipc.checkmac(host) + if mac then local cmd local util = luci.http.formvalue("cbid.wol.1.binary") or ( has_ewk and "/usr/bin/etherwake" or "/usr/bin/wol" @@ -69,10 +71,10 @@ function host.write(self, s, val) local broadcast = luci.http.formvalue("cbid.wol.1.broadcast") cmd = "%s -D%s %s %q" %{ util, (iface ~= "" and " -i %q" % iface or ""), - (broadcast == "1" and " -b" or ""), host + (broadcast == "1" and " -b" or ""), mac } else - cmd = "%s -v %q" %{ util, host } + cmd = "%s -v %q" %{ util, mac } end local msg = "<p><strong>%s</strong><br /><br /><code>%s<br /><br />" %{ diff --git a/documentation/api/modules/luci.http.protocol.html b/documentation/api/modules/luci.http.protocol.html index 57063bbcf9..e6e93ad3d6 100644 --- a/documentation/api/modules/luci.http.protocol.html +++ b/documentation/api/modules/luci.http.protocol.html @@ -341,7 +341,7 @@ Ltn12 source function Decode a mime encoded http message body with multipart/form-data Content-Type. Stores all extracted data associated with its parameter name -in the params table within the given message object. Multiple parameter +in the params table within the given message object. Multiple parameter values are stored as tables, ordinary ones as strings. If an optional file callback function is given then it is feeded with the file contents chunk by chunk and only the extracted file name is stored @@ -556,7 +556,7 @@ The decoded string Decode an urlencoded http message body with application/x-www-urlencoded Content-Type. Stores all extracted data associated with its parameter name -in the params table within the given message object. Multiple parameter +in the params table within the given message object. Multiple parameter values are stored as tables, ordinary ones as strings. diff --git a/documentation/api/modules/luci.ip.cidr.html b/documentation/api/modules/luci.ip.cidr.html index ce8c567952..5a2b06ec67 100644 --- a/documentation/api/modules/luci.ip.cidr.html +++ b/documentation/api/modules/luci.ip.cidr.html @@ -260,6 +260,30 @@ Checks whether the CIDR instance is an IPv6 mapped IPv4 address </tr> <tr> + <td class="name" nowrap><a href="#cidr.ismac">cidr:ismac</a> ()</td> + <td class="summary"> + +Checks whether the CIDR instance is an ethernet MAC address range + </td> + </tr> + + <tr> + <td class="name" nowrap><a href="#cidr.ismaclocal">cidr:ismaclocal</a> ()</td> + <td class="summary"> + +Checks whether the CIDR instance is a locally administered (LAA) MAC address + </td> + </tr> + + <tr> + <td class="name" nowrap><a href="#cidr.ismacmcast">cidr:ismacmcast</a> ()</td> + <td class="summary"> + +Checks whether the CIDR instance is a multicast MAC address + </td> + </tr> + + <tr> <td class="name" nowrap><a href="#cidr.lower">cidr:lower</a> (addr)</td> <td class="summary"> @@ -323,6 +347,20 @@ Derive mapped IPv4 address of CIDR instance.</td> </tr> <tr> + <td class="name" nowrap><a href="#cidr.tomac">cidr:tomac</a> ()</td> + <td class="summary"> + +Derive MAC address of IPv6 link local CIDR instance.</td> + </tr> + + <tr> + <td class="name" nowrap><a href="#cidr.tolinklocal">cidr:tolinklocal</a> ()</td> + <td class="summary"> + +Derive IPv6 link local address from MAC address CIDR instance.</td> + </tr> + + <tr> <td class="name" nowrap><a href="#cidr.contains">cidr:contains</a> (addr)</td> <td class="summary"> @@ -405,6 +443,10 @@ Checks whether the CIDR instance is an IPv4 address range cidr:is6 </a> + <li><a href="#cidr.ismac"> + cidr:ismac + </a> + </ul> </dd> @@ -499,6 +541,10 @@ Checks whether the CIDR instance is an IPv6 address range cidr:is4 </a> + <li><a href="#cidr.ismac"> + cidr:ismac + </a> + </ul> </dd> @@ -566,13 +612,108 @@ end</pre> +<dt><a name="cidr.ismac"></a><strong>cidr:ismac</strong> ()</dt> +<dd> + + +Checks whether the CIDR instance is an ethernet MAC address range + + + + + + + + +<h3>Return value:</h3> +<code>true</code> if the CIDR is a MAC address range, else <code>false</code> + + + +<h3>See also:</h3> +<ul> + + <li><a href="#cidr.is4"> + cidr:is4 + </a> + + <li><a href="#cidr.is6"> + cidr:is6 + </a> + +</ul> + +</dd> + + + + +<dt><a name="cidr.ismaclocal"></a><strong>cidr:ismaclocal</strong> ()</dt> +<dd> + + +Checks whether the CIDR instance is a locally administered (LAA) MAC address + + + + + + +<h3>Usage:</h3> +<pre>local mac = luci.ip.new("02:C0:FF:EE:00:01") +if mac:ismaclocal() then + print("Is an LAA MAC address") +end</pre> + + + +<h3>Return value:</h3> +<code>true</code> if the MAC address sets the locally administered bit. + + + +</dd> + + + + +<dt><a name="cidr.ismacmcast"></a><strong>cidr:ismacmcast</strong> ()</dt> +<dd> + + +Checks whether the CIDR instance is a multicast MAC address + + + + + + +<h3>Usage:</h3> +<pre>local mac = luci.ip.new("01:00:5E:7F:00:10") +if addr:ismacmcast() then + print("Is a multicast MAC address") +end</pre> + + + +<h3>Return value:</h3> +<code>true</code> if the MAC address sets the multicast bit. + + + +</dd> + + + + <dt><a name="cidr.lower"></a><strong>cidr:lower</strong> (addr)</dt> <dd> Checks whether this CIDR instance is lower than the given argument. The comparisation follows these rules: -<ul><li>An IPv4 address is always lower than an IPv6 address</li> +<ul><li>An IPv4 address is always lower than an IPv6 address and IPv6 addresses +are considered lower than MAC addresses</li> <li>Prefix sizes are ignored</li></ul> @@ -595,7 +736,8 @@ The comparisation follows these rules: print(addr:lower(addr)) -- false print(addr:lower("10.10.10.10/24")) -- false print(addr:lower(luci.ip.new("::1"))) -- true -print(addr:lower(luci.ip.new("192.168.200.1"))) -- true</pre> +print(addr:lower(luci.ip.new("192.168.200.1"))) -- true +print(addr:lower(luci.ip.new("00:14:22:01:23:45"))) -- true</pre> @@ -629,7 +771,8 @@ print(addr:lower(luci.ip.new("192.168.200.1"))) -- true</pre> Checks whether this CIDR instance is higher than the given argument. The comparisation follows these rules: -<ul><li>An IPv4 address is always lower than an IPv6 address</li> +<ul><li>An IPv4 address is always lower than an IPv6 address and IPv6 addresses +are considered lower than MAC addresses</li> <li>Prefix sizes are ignored</li></ul> @@ -652,7 +795,8 @@ The comparisation follows these rules: print(addr:higher(addr)) -- false print(addr:higher("10.10.10.10/24")) -- true print(addr:higher(luci.ip.new("::1"))) -- false -print(addr:higher(luci.ip.new("192.168.200.1"))) -- false</pre> +print(addr:higher(luci.ip.new("192.168.200.1"))) -- false +print(addr:higher(luci.ip.new("00:14:22:01:23:45"))) -- false</pre> @@ -709,7 +853,11 @@ print(addr:equal(luci.ip.new("::1"))) -- false local addr6 = luci.ip.new("::1") print(addr6:equal("0:0:0:0:0:0:0:1/64")) -- true -print(addr6:equal(luci.ip.new("fe80::221:63ff:fe75:aa17"))) -- false</pre> +print(addr6:equal(luci.ip.new("fe80::221:63ff:fe75:aa17"))) -- false + +local mac = luci.ip.new("00:14:22:01:23:45") +print(mac:equal("0:14:22:1:23:45")) -- true +print(mac:equal(luci.ip.new("01:23:45:67:89:AB")) -- false</pre> @@ -752,8 +900,8 @@ else the current prefix size is returned. <li> mask: Either a number containing the number of bits (<code>0..32</code> - for IPv4, <code>0..128</code> for IPv6) or a string containing a valid - netmask (optional) + for IPv4, <code>0..128</code> for IPv6 or <code>0..48</code> for MAC addresses) or a string + containing a valid netmask (optional) </li> </ul> @@ -800,8 +948,8 @@ optional mask parameter. <li> mask: Either a number containing the number of bits (<code>0..32</code> - for IPv4, <code>0..128</code> for IPv6) or a string containing a valid - netmask (optional) + for IPv4, <code>0..128</code> for IPv6 or <code>0..48</code> for MAC addresses) or a string + containing a valid netmask (optional) </li> </ul> @@ -837,7 +985,7 @@ CIDR instance representing the network address Derive host address of CIDR instance. This function essentially constructs a copy of this CIDR with the prefix size -set to <code>32</code> for IPv4 and <code>128</code> for IPv6. +set to <code>32</code> for IPv4, <code>128</code> for IPv6 or <code>48</code> for MAC addresses. @@ -877,8 +1025,8 @@ prefix size can be overridden by the optional mask parameter. <li> mask: Either a number containing the number of bits (<code>0..32</code> - for IPv4, <code>0..128</code> for IPv6) or a string containing a valid - netmask (optional) + for IPv4, <code>0..128</code> for IPv6 or <code>0..48</code> for MAC addresses) or a string + containing a valid netmask (optional) </li> </ul> @@ -913,8 +1061,8 @@ Derive broadcast address of CIDR instance. Constructs a CIDR instance representing the broadcast address of this instance. The used prefix size can be overridden by the optional mask parameter. -This function has no effect on IPv6 instances, it will return nothing in this -case. +This function has no effect on IPv6 or MAC address instances, it will return +nothing in this case. @@ -922,9 +1070,8 @@ case. <ul> <li> - mask: Either a number containing the number of bits (<code>0..32</code> - for IPv4, <code>0..128</code> for IPv6) or a string containing a valid - netmask (optional) + mask: Either a number containing the number of bits (<code>0..32</code> for IPv4) or + a string containing a valid netmask (optional) </li> </ul> @@ -960,8 +1107,8 @@ Derive mapped IPv4 address of CIDR instance. Constructs a CIDR instance representing the IPv4 address of the IPv6 mapped IPv4 address in this instance. -This function has no effect on IPv4 instances or IPv6 instances which are not a -mapped address, it will return nothing in this case. +This function has no effect on IPv4 instances, MAC address instances or IPv6 +instances which are not a mapped address, it will return nothing in this case. @@ -985,6 +1132,74 @@ Return a new CIDR instance representing the IPv4 address if this +<dt><a name="cidr.tomac"></a><strong>cidr:tomac</strong> ()</dt> +<dd> + + +Derive MAC address of IPv6 link local CIDR instance. + +Constructs a CIDR instance representing the MAC address contained in the IPv6 +link local address of this instance. + +This function has no effect on IPv4 instances, MAC address instances or IPv6 +instances which are not a link local address, it will return nothing in this +case. + + + + + + +<h3>Usage:</h3> +<pre>local addr = luci.ip.new("fe80::6666:b3ff:fe47:e1b9") +print(addr:tomac()) -- "64:66:B3:47:E1:B9"</pre> + + + +<h3>Return value:</h3> +Return a new CIDR instance representing the MAC address if this + instance is an IPv6 link local address, else return nothing. + + + +</dd> + + + + +<dt><a name="cidr.tolinklocal"></a><strong>cidr:tolinklocal</strong> ()</dt> +<dd> + + +Derive IPv6 link local address from MAC address CIDR instance. + +Constructs a CIDR instance representing the IPv6 link local address of the +MAC address represented by this instance. + +This function has no effect on IPv4 instances or IPv6 instances, it will return +nothing in this case. + + + + + + +<h3>Usage:</h3> +<pre>local mac = luci.ip.new("64:66:B3:47:E1:B9") +print(mac:tolinklocal()) -- "fe80::6666:b3ff:fe47:e1b9"</pre> + + + +<h3>Return value:</h3> +Return a new CIDR instance representing the IPv6 link local address. + + + +</dd> + + + + <dt><a name="cidr.contains"></a><strong>cidr:contains</strong> (addr)</dt> <dd> @@ -1014,7 +1229,11 @@ print(range:contains("10.0.0.0/8")) -- false local range6 = luci.ip.new("fe80::/10") print(range6:contains("fe80::221:63f:fe75:aa17/64")) -- true -print(range6:contains("fd9b:6b3:c5:0:221:63f:fe75:aa17/64")) -- false</pre> +print(range6:contains("fd9b:6b3:c5:0:221:63f:fe75:aa17/64")) -- false + +local intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/24") +print(intel_macs:contains("C0:B6:F9:A3:C:11")) -- true +print(intel_macs:contains("64:66:B3:47:E1:B9")) -- false</pre> @@ -1059,30 +1278,40 @@ address space, the result is set to the highest possible address. <h3>Usage:</h3> <pre>local addr = luci.ip.new("192.168.1.1/24") -print(addr:add(250)) -- "192.168.1.251/24" -print(addr:add("0.0.99.0")) -- "192.168.100.1/24" +print(addr:add(250)) -- "192.168.1.251/24" +print(addr:add("0.0.99.0")) -- "192.168.100.1/24" -addr:add(256, true) -- true -print(addr) -- "192.168.2.1/24 +addr:add(256, true) -- true +print(addr) -- "192.168.2.1/24 -addr:add("255.0.0.0", true) -- false (overflow) -print(addr) -- "255.255.255.255/24 +addr:add("255.0.0.0", true) -- false (overflow) +print(addr) -- "255.255.255.255/24 local addr6 = luci.ip.new("fe80::221:63f:fe75:aa17/64") -print(addr6:add(256)) -- "fe80::221:63f:fe75:ab17/64" -print(addr6:add("::ffff:0")) -- "fe80::221:640:fe74:aa17/64" +print(addr6:add(256)) -- "fe80::221:63f:fe75:ab17/64" +print(addr6:add("::ffff:0")) -- "fe80::221:640:fe74:aa17/64" + +addr6:add(256, true) -- true +print(addr6) -- "fe80::221:63f:fe75:ab17/64 + +addr6:add("ffff::", true) -- false (overflow) +print(addr6) -- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64" + +local mac = luci.ip.new("00:14:22:01:23:45") +print(mac:add(256)) -- "00:14:22:01:24:45" +print(mac:add("0:0:0:0:FF:0") -- "00:14:22:02:22:45" -addr:add(256, true) -- true -print(addr) -- "fe80::221:63f:fe75:ab17/64 +mac:add(256, true) -- true +print(mac) -- "00:14:22:01:24:45" -addr:add("ffff::", true) -- false (overflow) -print(addr) -- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64"</pre> +mac:add("FF:FF:0:0:0:0", true) -- false (overflow) +print(mac) -- "FF:FF:FF:FF:FF:FF"</pre> <h3>Return value:</h3> <ul> - <li>When adding inplace: Return <code>true</code> if the addition succeeded + <li>When adding inplace: Return <code>true</code> if the addition succeded or <code>false</code> when the addition overflowed.</li> <li>When deriving new CIDR: Return new instance representing the value of this instance plus the added amount or the highest possible address if @@ -1099,7 +1328,7 @@ print(addr) -- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64"</pr <dd> -Subtract given amount from CIDR instance. If the result would under, the lowest +Subtract given amount from CIDR instance. If the result would under, the lowest possible address is returned. @@ -1142,16 +1371,26 @@ addr:sub(256, true) -- true print(addr) -- "fe80::221:63f:fe75:a917/64" addr:sub("ffff::", true) -- false (underflow) -print(addr) -- "::/64"</pre> +print(addr) -- "::/64" + +local mac = luci.ip.new("00:14:22:01:23:45") +print(mac:sub(256)) -- "00:14:22:01:22:45" +print(mac:sub("0:0:0:0:FF:0") -- "00:14:22:00:24:45" + +mac:sub(256, true) -- true +print(mac) -- "00:14:22:01:22:45" + +mac:sub("FF:FF:0:0:0:0", true) -- false (overflow) +print(mac) -- "00:00:00:00:00:00"</pre> <h3>Return value:</h3> <ul> - <li>When subtracting inplace: Return <code>true</code> if the subtraction - succeeded or <code>false</code> when the subtraction underflowed.</li> + <li>When subtracting inplace: Return <code>true</code> if the subtraction + succeeded or <code>false</code> when the subtraction underflowed.</li> <li>When deriving new CIDR: Return new instance representing the value of - this instance minus the subtracted amount or the lowest address if + this instance minus the subtracted amount or the lowest address if the subtraction underflowed.</li></ul> @@ -1177,7 +1416,10 @@ Calculate the lowest possible host address within this CIDR instance. print(addr:minhost()) -- "192.168.123.1" local addr6 = luci.ip.new("fd9b:62b3:9cc5:0:221:63ff:fe75:aa17/64") -print(addr6:minhost()) -- "fd9b:62b3:9cc5::1"</pre> +print(addr6:minhost()) -- "fd9b:62b3:9cc5::1" + +local mac = luci.ip.new("00:14:22:01:22:45/32") +print(mac:minhost()) -- "00:14:22:01:00:01"</pre> @@ -1208,7 +1450,10 @@ Calculate the highest possible host address within this CIDR instance. print(addr:maxhost()) -- "192.168.123.254" (.255 is broadcast) local addr6 = luci.ip.new("fd9b:62b3:9cc5:0:221:63ff:fe75:aa17/64") -print(addr6:maxhost()) -- "fd9b:62b3:9cc5:0:ffff:ffff:ffff:ffff"</pre> +print(addr6:maxhost()) -- "fd9b:62b3:9cc5:0:ffff:ffff:ffff:ffff" + +local mac = luci.ip.new("00:14:22:01:22:45/32") +print(mac:maxhost()) -- "00:14:22:01:FF:FF"</pre> @@ -1229,8 +1474,9 @@ Returns a new CIDR instance representing the highest host address Convert CIDR instance into string representation. -If the prefix size of instance is less than 32 for IPv4 or 128 for IPv6, the -address is returned in the form "address/prefix" otherwise just "address". +If the prefix size of instance is less than 32 for IPv4, 128 for IPv6 or 48 for +MACs, the address is returned in the form "address/prefix" otherwise just +"address". It is usually not required to call this function directly as CIDR objects define it as __tostring function in the associated metatable. diff --git a/documentation/api/modules/luci.ip.html b/documentation/api/modules/luci.ip.html index 549a55307e..1f89626faa 100644 --- a/documentation/api/modules/luci.ip.html +++ b/documentation/api/modules/luci.ip.html @@ -232,6 +232,34 @@ Construct a new IPv6 luci.ip.cidr instance.</td> </tr> <tr> + <td class="name" nowrap><a href="#MAC">MAC</a> (address, netmask)</td> + <td class="summary"> + +Construct a new MAC luci.ip.cidr instance.</td> + </tr> + + <tr> + <td class="name" nowrap><a href="#checkip4">checkip4</a> (address)</td> + <td class="summary"> + +Verify an IPv4 address.</td> + </tr> + + <tr> + <td class="name" nowrap><a href="#checkip6">checkip6</a> (address)</td> + <td class="summary"> + +Verify an IPv6 address.</td> + </tr> + + <tr> + <td class="name" nowrap><a href="#checkmac">checkmac</a> (address)</td> + <td class="summary"> + +Verify an ethernet MAC address.</td> + </tr> + + <tr> <td class="name" nowrap><a href="#route">route</a> (address)</td> <td class="summary"> @@ -334,6 +362,10 @@ address/mask range. IPv6 </a> + <li><a href="#MAC"> + MAC + </a> + </ul> </dd> @@ -389,6 +421,10 @@ A <code>luci.ip.cidr</code> object representing the given IPv4 range. IPv6 </a> + <li><a href="#MAC"> + MAC + </a> + </ul> </dd> @@ -444,6 +480,252 @@ A <code>luci.ip.cidr</code> object representing the given IPv6 range. IPv4 </a> + <li><a href="#MAC"> + MAC + </a> + +</ul> + +</dd> + + + + +<dt><a name="MAC"></a><strong>MAC</strong> (address, netmask)</dt> +<dd> + + +Construct a new MAC luci.ip.cidr instance. +Throws an error if the given string does not represent a valid ethernet MAC +address or if the given optional mask is of a different family. + + +<h3>Parameters</h3> +<ul> + + <li> + address: String containing a valid ethernet MAC address, optionally with +prefix size (CIDR notation) or mask separated by slash. + </li> + + <li> + netmask: String containing a valid MAC address mask or number +containing a prefix size between <code>0</code> and <code>48</code> bit. +Overrides mask embedded in the first argument if specified. (optional) + </li> + +</ul> + + + + +<h3>Usage:</h3> +<pre>intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/24") +intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/FF:FF:FF:0:0:0") +intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00", "FF:FF:FF:0:0:0") +intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/24", 48) -- override mask</pre> + + + +<h3>Return value:</h3> +A <code>luci.ip.cidr</code> object representing the given MAC address range. + + + +<h3>See also:</h3> +<ul> + + <li><a href="#IPv4"> + IPv4 + </a> + + <li><a href="#IPv6"> + IPv6 + </a> + +</ul> + +</dd> + + + + +<dt><a name="checkip4"></a><strong>checkip4</strong> (address)</dt> +<dd> + + +Verify an IPv4 address. + +Checks whether given argument is a preexisting luci.ip.cidr IPv4 address +instance or a string literal convertible to an IPv4 address and returns a +plain Lua string containing the canonical representation of the address. + +If the argument is not a valid address, returns nothing. This function is +intended to aid in safely verifying address literals without having to deal +with exceptions. + + +<h3>Parameters</h3> +<ul> + + <li> + address: String containing a valid IPv4 address or existing +luci.ip.cidr IPv4 instance. + </li> + +</ul> + + + + +<h3>Usage:</h3> +<pre>ipv4 = luci.ip.checkip4(luci.ip.new("127.0.0.1")) -- "127.0.0.1" +ipv4 = luci.ip.checkip4("127.0.0.1") -- "127.0.0.1" +ipv4 = luci.ip.checkip4("nonesense") -- nothing +ipv4 = luci.ip.checkip4(123) -- nothing +ipv4 = luci.ip.checkip4(nil) -- nothing +ipv4 = luci.ip.checkip4() -- nothing</pre> + + + +<h3>Return value:</h3> +A string representing the given IPv4 address. + + + +<h3>See also:</h3> +<ul> + + <li><a href="#checkip6"> + checkip6 + </a> + + <li><a href="#checkmac"> + checkmac + </a> + +</ul> + +</dd> + + + + +<dt><a name="checkip6"></a><strong>checkip6</strong> (address)</dt> +<dd> + + +Verify an IPv6 address. + +Checks whether given argument is a preexisting luci.ip.cidr IPv6 address +instance or a string literal convertible to an IPv6 address and returns a +plain Lua string containing the canonical representation of the address. + +If the argument is not a valid address, returns nothing. This function is +intended to aid in safely verifying address literals without having to deal +with exceptions. + + +<h3>Parameters</h3> +<ul> + + <li> + address: String containing a valid IPv6 address or existing +luci.ip.cidr IPv6 instance. + </li> + +</ul> + + + + +<h3>Usage:</h3> +<pre>ipv6 = luci.ip.checkip6(luci.ip.new("0:0:0:0:0:0:0:1")) -- "::1" +ipv6 = luci.ip.checkip6("0:0:0:0:0:0:0:1") -- "::1" +ipv6 = luci.ip.checkip6("nonesense") -- nothing +ipv6 = luci.ip.checkip6(123) -- nothing +ipv6 = luci.ip.checkip6(nil) -- nothing +ipv6 = luci.ip.checkip6() -- nothing</pre> + + + +<h3>Return value:</h3> +A string representing the given IPv6 address. + + + +<h3>See also:</h3> +<ul> + + <li><a href="#checkip4"> + checkip4 + </a> + + <li><a href="#checkmac"> + checkmac + </a> + +</ul> + +</dd> + + + + +<dt><a name="checkmac"></a><strong>checkmac</strong> (address)</dt> +<dd> + + +Verify an ethernet MAC address. + +Checks whether given argument is a preexisting luci.ip.cidr MAC address +instance or a string literal convertible to an ethernet MAC and returns a +plain Lua string containing the canonical representation of the address. + +If the argument is not a valid address, returns nothing. This function is +intended to aid in safely verifying address literals without having to deal +with exceptions. + + +<h3>Parameters</h3> +<ul> + + <li> + address: String containing a valid MAC address or existing luci.ip.cidr +MAC address instance. + </li> + +</ul> + + + + +<h3>Usage:</h3> +<pre>mac = luci.ip.checkmac(luci.ip.new("00-11-22-cc-dd-ee")) -- "00:11:22:CC:DD:EE" +mac = luci.ip.checkmac("00:11:22:cc:dd:ee") -- "00:11:22:CC:DD:EE" +mac = luci.ip.checkmac("nonesense") -- nothing +mac = luci.ip.checkmac(123) -- nothing +mac = luci.ip.checkmac(nil) -- nothing +mac = luci.ip.checkmac() -- nothing</pre> + + + +<h3>Return value:</h3> +A string representing the given MAC address. + + + +<h3>See also:</h3> +<ul> + + <li><a href="#checkip4"> + checkip4 + </a> + + <li><a href="#checkip6"> + checkip6 + </a> + </ul> </dd> @@ -787,7 +1069,7 @@ A neighbour entry is a table containing the following fields: </tr> <tr> <td><code>mac</code></td> - <td>String containing the associated MAC address</td> + <td>MAC address <code>luci.ip.cidr</code> instance</td> </tr> <tr> <td><code>router</code></td> @@ -905,8 +1187,8 @@ described below is returned, else an empty table. </tr> <tr> <td><code>mac</code></td> - <td>String containing the link local address of the device in - dotted hex notation</td> + <td>MAC address <code>luci.ip.cidr</code> instance representing the device ethernet + address</td> </tr> </table> diff --git a/documentation/api/modules/luci.util.html b/documentation/api/modules/luci.util.html index 847230bbbd..70d27d3312 100644 --- a/documentation/api/modules/luci.util.html +++ b/documentation/api/modules/luci.util.html @@ -629,7 +629,7 @@ Cloned table value <dd> -Count the occurrences of given substring in given string. +Count the occurrences of given substring in given string. diff --git a/documentation/api/modules/nixio.README.html b/documentation/api/modules/nixio.README.html index d8a17f78b4..99e036b828 100644 --- a/documentation/api/modules/nixio.README.html +++ b/documentation/api/modules/nixio.README.html @@ -288,7 +288,7 @@ <br />In general all functions are namend and behave like their POSIX API counterparts - where applicable - applying the following rules: <ul> - <li>Functions should be named like the underlying POSIX API function omitting + <li>Functions should be named like the underlying POSIX API function omitting prefixes or suffixes - especially when placed in an object-context ( lockf -> File:lock, fsync -> File:sync, dup2 -> dup, ...)</li> <li>If you are unclear about the behaviour of a function you should consult @@ -296,10 +296,10 @@ <li>If the name is significantly different from the POSIX-function, the underlying function(s) are stated in the documentation.</li> <li>Parameters should reflect those of the C-API, buffer length arguments and - by-reference parameters should be omitted for pratical purposes.</li> + by-reference parameters should be omitted for practical purposes.</li> <li>If a C function accepts a bitfield as parameter, it should be translated into lower case string flags representing the flags if the bitfield is the - last parameter and also omitting prefixes or suffixes. (e.g. waitpid + last parameter and also omitting prefixes or suffixes. (e.g. waitpid (pid, &s, WNOHANG | WUNTRACED) -> waitpid(pid, "nohang", "untraced"), getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) -> Socket:getopt("socket", "reuseaddr"), etc.) </li> diff --git a/documentation/api/modules/nixio.UnifiedIO.html b/documentation/api/modules/nixio.UnifiedIO.html index 1717980841..700485dbe4 100644 --- a/documentation/api/modules/nixio.UnifiedIO.html +++ b/documentation/api/modules/nixio.UnifiedIO.html @@ -326,7 +326,7 @@ <li>The blocksize given is only advisory and to be seen as an upper limit, if an underlying read returns less bytes the chunk is nevertheless returned. - <li>If the limit parameter is omitted, the iterator returns data + <li>If the limit parameter is omitted, the iterator returns data until an end-of-file, end-of-stream, connection shutdown or similar happens. <li>The iterator will not buffer so it is safe to mix with calls to read. @@ -402,7 +402,7 @@ true <li>This function uses the blocksource function of the source descriptor and the sink function of the target descriptor. - <li>If the limit parameter is omitted, data is copied + <li>If the limit parameter is omitted, data is copied until an end-of-file, end-of-stream, connection shutdown or similar happens. <li>If the descriptor is non-blocking the function may fail with EAGAIN. @@ -461,7 +461,7 @@ true blocksource function of the source descriptor and the sink function of the target descriptor as a fallback mechanism. - <li>If the limit parameter is omitted, data is copied + <li>If the limit parameter is omitted, data is copied until an end-of-file, end-of-stream, connection shutdown or similar happens. <li>If the descriptor is non-blocking the function may fail with EAGAIN. @@ -584,7 +584,7 @@ boolean you can pass "true" to the iterator which will flush the buffer and return the bufferd data. - <li>If the limit parameter is omitted, this function uses the nixio + <li>If the limit parameter is omitted, this function uses the nixio buffersize (8192B by default). <li>If the descriptor is non-blocking the iterator may fail with EAGAIN. @@ -628,7 +628,7 @@ Line-based Iterator <li>This function uses the low-level read function of the descriptor. - <li>If the length parameter is omitted, this function returns all data + <li>If the length parameter is omitted, this function returns all data that can be read before an end-of-file, end-of-stream, connection shutdown or similar happens. diff --git a/libs/luci-lib-ip/src/ip.c b/libs/luci-lib-ip/src/ip.c index b91966c536..854a0c09c2 100644 --- a/libs/luci-lib-ip/src/ip.c +++ b/libs/luci-lib-ip/src/ip.c @@ -1,5 +1,5 @@ /* -Copyright 2015 Jo-Philipp Wich <jow@openwrt.org> +Copyright 2015-2018 Jo-Philipp Wich <jo@mein.io> Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -42,6 +42,16 @@ limitations under the License. #define RTA_INT(x) (*(int *)RTA_DATA(x)) #define RTA_U32(x) (*(uint32_t *)RTA_DATA(x)) +#define AF_BITS(f) \ + ((f) == AF_INET ? 32 : \ + ((f) == AF_INET6 ? 128 : \ + ((f) == AF_PACKET ? 48 : 0))) + +#define AF_BYTES(f) \ + ((f) == AF_INET ? 4 : \ + ((f) == AF_INET6 ? 16 : \ + ((f) == AF_PACKET ? 6 : 0))) + static int hz = 0; static struct nl_sock *sock = NULL; @@ -49,11 +59,11 @@ typedef struct { union { struct in_addr v4; struct in6_addr v6; + struct ether_addr mac; + uint8_t u8[16]; } addr; - int len; - int bits; - int family; - bool exact; + uint16_t family; + int16_t bits; } cidr_t; struct dump_filter { @@ -70,6 +80,8 @@ struct dump_filter { cidr_t src; cidr_t dst; struct ether_addr mac; + bool from_exact; + bool dst_exact; }; struct dump_state { @@ -95,29 +107,68 @@ static cidr_t *L_checkcidr (lua_State *L, int index, cidr_t *p) return NULL; } -static bool parse_mask(int family, const char *mask, int *bits) +static bool parse_mac(const char *mac, struct ether_addr *ea) +{ + unsigned long int n; + char *e, sep = 0; + int i; + + for (i = 0; i < 6; i++) + { + if (i > 0) + { + if (sep == 0 && (mac[0] == ':' || mac[0] == '-')) + sep = mac[0]; + + if (sep == 0 || mac[0] != sep) + return false; + + mac++; + } + + n = strtoul(mac, &e, 16); + + if (n > 0xFF) + return false; + + mac += (e - mac); + ea->ether_addr_octet[i] = n; + } + + if (mac[0] != 0) + return false; + + return true; +} + +static bool parse_mask(int family, const char *mask, int16_t *bits) { char *e; - struct in_addr m; - struct in6_addr m6; + union { + struct in_addr v4; + struct in6_addr v6; + struct ether_addr mac; + uint8_t u8[16]; + } m; - if (family == AF_INET && inet_pton(AF_INET, mask, &m)) + if (family == AF_INET && inet_pton(AF_INET, mask, &m.v4)) { - for (*bits = 0, m.s_addr = ntohl(m.s_addr); - *bits < 32 && (m.s_addr << *bits) & 0x80000000; + for (*bits = 0, m.v4.s_addr = ntohl(m.v4.s_addr); + *bits < AF_BITS(AF_INET) && (m.v4.s_addr << *bits) & 0x80000000; ++*bits); } - else if (family == AF_INET6 && inet_pton(AF_INET6, mask, &m6)) + else if ((family == AF_INET6 && inet_pton(AF_INET6, mask, &m.v6)) || + (family == AF_PACKET && parse_mac(mask, &m.mac))) { for (*bits = 0; - *bits < 128 && (m6.s6_addr[*bits / 8] << (*bits % 8)) & 128; + *bits < AF_BITS(family) && (m.u8[*bits / 8] << (*bits % 8)) & 128; ++*bits); } else { *bits = strtoul(mask, &e, 10); - if (e == mask || *e != 0 || *bits > ((family == AF_INET) ? 32 : 128)) + if (e == mask || *e != 0 || *bits > AF_BITS(family)) return false; } @@ -127,7 +178,6 @@ static bool parse_mask(int family, const char *mask, int *bits) static bool parse_cidr(const char *dest, cidr_t *pp) { char *p, buf[INET6_ADDRSTRLEN * 2 + 2]; - uint8_t bitlen = 0; strncpy(buf, dest, sizeof(buf) - 1); @@ -137,17 +187,11 @@ static bool parse_cidr(const char *dest, cidr_t *pp) *p++ = 0; 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, buf, &pp->addr.v6)) - { - bitlen = 128; pp->family = AF_INET6; - pp->len = sizeof(struct in6_addr); - } + else if (parse_mac(buf, &pp->addr.mac)) + pp->family = AF_PACKET; else return false; @@ -158,12 +202,45 @@ static bool parse_cidr(const char *dest, cidr_t *pp) } else { - pp->bits = bitlen; + pp->bits = AF_BITS(pp->family); } return true; } +static int format_cidr(lua_State *L, cidr_t *p) +{ + char buf[INET6_ADDRSTRLEN]; + + if (p->family == AF_PACKET) + { + snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X", + p->addr.mac.ether_addr_octet[0], + p->addr.mac.ether_addr_octet[1], + p->addr.mac.ether_addr_octet[2], + p->addr.mac.ether_addr_octet[3], + p->addr.mac.ether_addr_octet[4], + p->addr.mac.ether_addr_octet[5]); + + if (p->bits < AF_BITS(AF_PACKET)) + lua_pushfstring(L, "%s/%d", buf, p->bits); + else + lua_pushstring(L, buf); + } + else + { + if (p->bits < AF_BITS(p->family)) + lua_pushfstring(L, "%s/%d", + inet_ntop(p->family, &p->addr.v6, buf, sizeof(buf)), + p->bits); + else + lua_pushstring(L, + inet_ntop(p->family, &p->addr.v6, buf, sizeof(buf))); + } + + return 1; +} + static int L_getint(lua_State *L, int index, const char *name) { int rv = 0; @@ -220,17 +297,21 @@ static void L_setaddr(struct lua_State *L, const char *name, if (family == AF_INET) { p->family = AF_INET; - p->bits = (bits < 0) ? 32 : bits; - p->len = sizeof(p->addr.v4); + p->bits = (bits < 0) ? AF_BITS(AF_INET) : bits; p->addr.v4 = *(struct in_addr *)addr; } - else + else if (family == AF_INET6) { p->family = AF_INET6; - p->bits = (bits < 0) ? 128 : bits; - p->len = sizeof(p->addr.v6); + p->bits = (bits < 0) ? AF_BITS(AF_INET6) : bits; p->addr.v6 = *(struct in6_addr *)addr; } + else + { + p->family = AF_PACKET; + p->bits = (bits < 0) ? AF_BITS(AF_PACKET) : bits; + p->addr.mac = *(struct ether_addr *)addr; + } luaL_getmetatable(L, LUCI_IP_CIDR); lua_setmetatable(L, -2); @@ -254,6 +335,7 @@ static void L_setdev(struct lua_State *L, const char *name, static int L_checkbits(lua_State *L, int index, cidr_t *p) { + int16_t s16; int bits; if (lua_gettop(L) < index || lua_isnil(L, index)) @@ -264,13 +346,15 @@ static int L_checkbits(lua_State *L, int index, cidr_t *p) { bits = lua_tointeger(L, index); - if (bits < 0 || bits > ((p->family == AF_INET) ? 32 : 128)) + if (bits < 0 || bits > AF_BITS(p->family)) return luaL_error(L, "Invalid prefix size"); } else if (lua_type(L, index) == LUA_TSTRING) { - if (!parse_mask(p->family, lua_tostring(L, index), &bits)) + if (!parse_mask(p->family, lua_tostring(L, index), &s16)) return luaL_error(L, "Invalid netmask format"); + + bits = s16; } else { @@ -293,20 +377,26 @@ static int _cidr_new(lua_State *L, int index, int family, bool mask) if (family == AF_INET6) { cidr.family = AF_INET6; - cidr.bits = 128; - cidr.len = sizeof(cidr.addr.v6); cidr.addr.v6.s6_addr[12] = n; cidr.addr.v6.s6_addr[13] = (n >> 8); cidr.addr.v6.s6_addr[14] = (n >> 16); cidr.addr.v6.s6_addr[15] = (n >> 24); } - else + else if (family == AF_INET) { cidr.family = AF_INET; - cidr.bits = 32; - cidr.len = sizeof(cidr.addr.v4); cidr.addr.v4.s_addr = n; } + else + { + cidr.family = AF_PACKET; + cidr.addr.mac.ether_addr_octet[2] = n; + cidr.addr.mac.ether_addr_octet[3] = (n >> 8); + cidr.addr.mac.ether_addr_octet[4] = (n >> 16); + cidr.addr.mac.ether_addr_octet[5] = (n >> 24); + } + + cidr.bits = AF_BITS(cidr.family); } else { @@ -346,6 +436,62 @@ static int cidr_ipv6(lua_State *L) return _cidr_new(L, 1, AF_INET6, true); } +static int cidr_mac(lua_State *L) +{ + return _cidr_new(L, 1, AF_PACKET, true); +} + +static int cidr_check(lua_State *L, int family) +{ + cidr_t cidr = { }, *cidrp; + const char *addr; + + if (lua_type(L, 1) == LUA_TSTRING) + { + addr = lua_tostring(L, 1); + + if (addr && parse_cidr(addr, &cidr) && cidr.family == family) + return format_cidr(L, &cidr); + } + else + { + cidrp = lua_touserdata(L, 1); + + if (cidrp == NULL) + return 0; + + if (!lua_getmetatable(L, 1)) + return 0; + + lua_getfield(L, LUA_REGISTRYINDEX, LUCI_IP_CIDR); + + if (!lua_rawequal(L, -1, -2)) + cidrp = NULL; + + lua_pop(L, 2); + + if (cidrp != NULL && cidrp->family == family) + return format_cidr(L, cidrp); + } + + return 0; +} + +static int cidr_checkip4(lua_State *L) +{ + return cidr_check(L, AF_INET); +} + +static int cidr_checkip6(lua_State *L) +{ + return cidr_check(L, AF_INET6); +} + +static int cidr_checkmac(lua_State *L) +{ + return cidr_check(L, AF_PACKET); +} + static int cidr_is4(lua_State *L) { cidr_t *p = L_checkcidr(L, 1, NULL); @@ -424,6 +570,34 @@ static int cidr_is6linklocal(lua_State *L) return 1; } +static int cidr_ismac(lua_State *L) +{ + cidr_t *p = L_checkcidr(L, 1, NULL); + + lua_pushboolean(L, p->family == AF_PACKET); + return 1; +} + +static int cidr_ismacmcast(lua_State *L) +{ + cidr_t *p = L_checkcidr(L, 1, NULL); + + lua_pushboolean(L, (p->family == AF_PACKET && + (p->addr.mac.ether_addr_octet[0] & 0x1))); + + return 1; +} + +static int cidr_ismaclocal(lua_State *L) +{ + cidr_t *p = L_checkcidr(L, 1, NULL); + + lua_pushboolean(L, (p->family == AF_PACKET && + (p->addr.mac.ether_addr_octet[0] & 0x2))); + + return 1; +} + static int _cidr_cmp(lua_State *L) { cidr_t *a = L_checkcidr(L, 1, NULL); @@ -432,7 +606,7 @@ static int _cidr_cmp(lua_State *L) if (a->family != b->family) return (a->family - b->family); - return memcmp(&a->addr.v6, &b->addr.v6, a->len); + return memcmp(&a->addr.v6, &b->addr.v6, AF_BYTES(a->family)); } static int cidr_lower(lua_State *L) @@ -475,24 +649,24 @@ static void _apply_mask(cidr_t *p, int bits, bool inv) if (bits <= 0) { - memset(&p->addr.v6, inv * 0xFF, p->len); + memset(&p->addr.u8, inv * 0xFF, AF_BYTES(p->family)); } - else if (p->family == AF_INET && bits <= 32) + else if (p->family == AF_INET && bits <= AF_BITS(AF_INET)) { if (inv) - p->addr.v4.s_addr |= ntohl((1 << (32 - bits)) - 1); + p->addr.v4.s_addr |= ntohl((1 << (AF_BITS(AF_INET) - bits)) - 1); else - p->addr.v4.s_addr &= ntohl(~((1 << (32 - bits)) - 1)); + p->addr.v4.s_addr &= ntohl(~((1 << (AF_BITS(AF_INET) - bits)) - 1)); } - else if (p->family == AF_INET6 && bits <= 128) + else if (bits <= AF_BITS(p->family)) { - for (i = 0; i < sizeof(p->addr.v6.s6_addr); i++) + for (i = 0; i < AF_BYTES(p->family); i++) { b = (bits > 8) ? 8 : bits; if (inv) - p->addr.v6.s6_addr[i] |= ~((uint8_t)(0xFF << (8 - b))); + p->addr.u8[i] |= ~((uint8_t)(0xFF << (8 - b))); else - p->addr.v6.s6_addr[i] &= (uint8_t)(0xFF << (8 - b)); + p->addr.u8[i] &= (uint8_t)(0xFF << (8 - b)); bits -= b; } } @@ -507,7 +681,7 @@ static int cidr_network(lua_State *L) return 0; *p2 = *p1; - p2->bits = (p1->family == AF_INET) ? 32 : 128; + p2->bits = AF_BITS(p1->family); _apply_mask(p2, bits, false); luaL_getmetatable(L, LUCI_IP_CIDR); @@ -524,7 +698,7 @@ static int cidr_host(lua_State *L) return 0; *p2 = *p1; - p2->bits = (p1->family == AF_INET) ? 32 : 128; + p2->bits = AF_BITS(p1->family); luaL_getmetatable(L, LUCI_IP_CIDR); lua_setmetatable(L, -2); @@ -539,7 +713,7 @@ static int cidr_mask(lua_State *L) if (!(p2 = lua_newuserdata(L, sizeof(*p2)))) return 0; - p2->bits = (p1->family == AF_INET) ? 32 : 128; + p2->bits = AF_BITS(p1->family); p2->family = p1->family; memset(&p2->addr.v6.s6_addr, 0xFF, sizeof(p2->addr.v6.s6_addr)); @@ -556,14 +730,14 @@ static int cidr_broadcast(lua_State *L) cidr_t *p2; int bits = L_checkbits(L, 2, p1); - if (p1->family == AF_INET6) + if (p1->family != AF_INET) return 0; if (!(p2 = lua_newuserdata(L, sizeof(*p2)))) return 0; *p2 = *p1; - p2->bits = (p1->family == AF_INET) ? 32 : 128; + p2->bits = AF_BITS(AF_INET); _apply_mask(p2, bits, true); luaL_getmetatable(L, LUCI_IP_CIDR); @@ -583,7 +757,7 @@ static int cidr_mapped4(lua_State *L) return 0; p2->family = AF_INET; - p2->bits = (p1->bits > 32) ? 32 : p1->bits; + p2->bits = (p1->bits > AF_BITS(AF_INET)) ? AF_BITS(AF_INET) : p1->bits; memcpy(&p2->addr.v4, p1->addr.v6.s6_addr + 12, sizeof(p2->addr.v4)); luaL_getmetatable(L, LUCI_IP_CIDR); @@ -591,6 +765,72 @@ static int cidr_mapped4(lua_State *L) return 1; } +static int cidr_tolinklocal(lua_State *L) +{ + cidr_t *p1 = L_checkcidr(L, 1, NULL); + cidr_t *p2; + int i; + + if (p1->family != AF_PACKET) + return 0; + + if (!(p2 = lua_newuserdata(L, sizeof(*p2)))) + return 0; + + p2->family = AF_INET6; + p2->bits = AF_BITS(AF_INET6); + p2->addr.u8[0] = 0xFE; + p2->addr.u8[1] = 0x80; + p2->addr.u8[8] = p1->addr.u8[0] ^ 0x02; + p2->addr.u8[9] = p1->addr.u8[1]; + p2->addr.u8[10] = p1->addr.u8[2]; + p2->addr.u8[11] = 0xFF; + p2->addr.u8[12] = 0xFE; + p2->addr.u8[13] = p1->addr.u8[3]; + p2->addr.u8[14] = p1->addr.u8[4]; + p2->addr.u8[15] = p1->addr.u8[5]; + + luaL_getmetatable(L, LUCI_IP_CIDR); + lua_setmetatable(L, -2); + return 1; +} + +static int cidr_tomac(lua_State *L) +{ + cidr_t *p1 = L_checkcidr(L, 1, NULL); + cidr_t *p2; + int i; + + if (p1->family != AF_INET6 || + p1->addr.u8[0] != 0xFE || + p1->addr.u8[1] != 0x80 || + p1->addr.u8[2] != 0x00 || + p1->addr.u8[3] != 0x00 || + p1->addr.u8[4] != 0x00 || + p1->addr.u8[5] != 0x00 || + p1->addr.u8[6] != 0x00 || + p1->addr.u8[7] != 0x00 || + p1->addr.u8[11] != 0xFF || + p1->addr.u8[12] != 0xFE) + return 0; + + if (!(p2 = lua_newuserdata(L, sizeof(*p2)))) + return 0; + + p2->family = AF_PACKET; + p2->bits = AF_BITS(AF_PACKET); + p2->addr.u8[0] = p1->addr.u8[8] ^ 0x02; + p2->addr.u8[1] = p1->addr.u8[9]; + p2->addr.u8[2] = p1->addr.u8[10]; + p2->addr.u8[3] = p1->addr.u8[13]; + p2->addr.u8[4] = p1->addr.u8[14]; + p2->addr.u8[5] = p1->addr.u8[15]; + + 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); @@ -603,15 +843,15 @@ static int cidr_contains(lua_State *L) _apply_mask(&a, p1->bits, false); _apply_mask(&b, p1->bits, false); - rv = !memcmp(&a.addr.v6, &b.addr.v6, a.len); + rv = !memcmp(&a.addr.v6, &b.addr.v6, AF_BYTES(a.family)); } lua_pushboolean(L, rv); return 1; } -#define S6_BYTE(a, i) \ - (a)->addr.v6.s6_addr[sizeof((a)->addr.v6.s6_addr) - (i) - 1] +#define BYTE(a, i) \ + (a)->addr.u8[AF_BYTES((a)->family) - (i) - 1] static int _cidr_add_sub(lua_State *L, bool add) { @@ -625,45 +865,45 @@ static int _cidr_add_sub(lua_State *L, bool add) if (p1->family == p2->family) { - if (p1->family == AF_INET6) + if (p1->family == AF_INET) + { + a = ntohl(p1->addr.v4.s_addr); + b = ntohl(p2->addr.v4.s_addr); + + /* would over/underflow */ + if ((add && (UINT_MAX - a) < b) || (!add && a < b)) + { + r.addr.v4.s_addr = add * 0xFFFFFFFF; + ok = false; + } + else + { + r.addr.v4.s_addr = add ? htonl(a + b) : htonl(a - b); + } + } + else { - for (i = 0, carry = 0; i < sizeof(r.addr.v6.s6_addr); i++) + for (i = 0, carry = 0; i < AF_BYTES(p1->family); i++) { if (add) { - S6_BYTE(&r, i) = S6_BYTE(p1, i) + S6_BYTE(p2, i) + carry; - carry = (S6_BYTE(p1, i) + S6_BYTE(p2, i) + carry) / 256; + BYTE(&r, i) = BYTE(p1, i) + BYTE(p2, i) + carry; + carry = (BYTE(p1, i) + BYTE(p2, i) + carry) / 256; } else { - S6_BYTE(&r, i) = (S6_BYTE(p1, i) - S6_BYTE(p2, i) - carry); - carry = (S6_BYTE(p1, i) < (S6_BYTE(p2, i) + carry)); + BYTE(&r, i) = (BYTE(p1, i) - BYTE(p2, i) - carry); + carry = (BYTE(p1, i) < (BYTE(p2, i) + carry)); } } /* would over/underflow */ if (carry) { - memset(&r.addr.v6, add * 0xFF, sizeof(r.addr.v6)); + memset(&r.addr.u8, add * 0xFF, AF_BYTES(r.family)); ok = false; } } - else - { - a = ntohl(p1->addr.v4.s_addr); - b = ntohl(p2->addr.v4.s_addr); - - /* would over/underflow */ - if ((add && (UINT_MAX - a) < b) || (!add && a < b)) - { - r.addr.v4.s_addr = add * 0xFFFFFFFF; - ok = false; - } - else - { - r.addr.v4.s_addr = add ? htonl(a + b) : htonl(a - b); - } - } } else { @@ -705,22 +945,22 @@ static int cidr_minhost(lua_State *L) _apply_mask(&r, r.bits, false); - if (r.family == AF_INET6 && r.bits < 128) + if (r.family == AF_INET && r.bits < AF_BITS(AF_INET)) + { + r.bits = AF_BITS(AF_INET); + r.addr.v4.s_addr = htonl(ntohl(r.addr.v4.s_addr) + 1); + } + else if (r.bits < AF_BITS(r.family)) { - r.bits = 128; + r.bits = AF_BITS(r.family); - for (i = 0, carry = 1; i < sizeof(r.addr.v6.s6_addr); i++) + for (i = 0, carry = 1; i < AF_BYTES(r.family); i++) { - rest = (S6_BYTE(&r, i) + carry) > 255; - S6_BYTE(&r, i) += carry; + rest = (BYTE(&r, i) + carry) > 255; + BYTE(&r, i) += carry; carry = rest; } } - else if (r.family == AF_INET && r.bits < 32) - { - r.bits = 32; - r.addr.v4.s_addr = htonl(ntohl(r.addr.v4.s_addr) + 1); - } if (!(p = lua_newuserdata(L, sizeof(*p)))) return 0; @@ -739,14 +979,14 @@ static int cidr_maxhost(lua_State *L) _apply_mask(&r, r.bits, true); - if (r.family == AF_INET && r.bits < 32) + if (r.family == AF_INET && r.bits < AF_BITS(AF_INET)) { - r.bits = 32; + r.bits = AF_BITS(AF_INET); r.addr.v4.s_addr = htonl(ntohl(r.addr.v4.s_addr) - 1); } - else if (r.family == AF_INET6) + else { - r.bits = 128; + r.bits = AF_BITS(r.family); } if (!(p = lua_newuserdata(L, sizeof(*p)))) @@ -766,31 +1006,17 @@ static int cidr_gc (lua_State *L) static int cidr_tostring (lua_State *L) { - char buf[INET6_ADDRSTRLEN]; cidr_t *p = L_checkcidr(L, 1, NULL); - - if ((p->family == AF_INET && p->bits < 32) || - (p->family == AF_INET6 && p->bits < 128)) - { - lua_pushfstring(L, "%s/%d", - inet_ntop(p->family, &p->addr.v6, buf, sizeof(buf)), - p->bits); - } - else - { - lua_pushstring(L, inet_ntop(p->family, &p->addr.v6, buf, sizeof(buf))); - } - - return 1; + return format_cidr(L, p); } /* * route functions */ -static bool diff_prefix(int family, void *addr, int bits, cidr_t *p) +static bool diff_prefix(int family, void *addr, int bits, bool exact, cidr_t *p) { - uint8_t i, b, r; + uint8_t i, b, r, *a; uint32_t m; if (!p->family) @@ -799,28 +1025,27 @@ static bool diff_prefix(int family, void *addr, int bits, cidr_t *p) if (!addr || p->family != family || p->bits > bits) return true; - if (family == AF_INET6) + if (family == AF_INET) { - for (i = 0, r = p->bits; i < sizeof(struct in6_addr); i++) + m = p->bits ? htonl(~((1 << (AF_BITS(AF_INET) - p->bits)) - 1)) : 0; + + if ((((struct in_addr *)addr)->s_addr & m) != (p->addr.v4.s_addr & m)) + return true; + } + else + { + for (i = 0, a = addr, r = p->bits; i < AF_BYTES(p->family); i++) { b = r ? (0xFF << (8 - ((r > 8) ? 8 : r))) : 0; - if ((((struct in6_addr *)addr)->s6_addr[i] & b) != - (p->addr.v6.s6_addr[i] & b)) + if ((a[i] & b) != (p->addr.u8[i] & b)) return true; r -= ((r > 8) ? 8 : r); } } - else - { - m = p->bits ? htonl(~((1 << (32 - p->bits)) - 1)) : 0; - if ((((struct in_addr *)addr)->s_addr & m) != (p->addr.v4.s_addr & m)) - return true; - } - - return (p->exact && p->bits != bits); + return (exact && p->bits != bits); } static int cb_dump_route(struct nl_msg *msg, void *arg) @@ -848,7 +1073,7 @@ static int cb_dump_route(struct nl_msg *msg, void *arg) dst = tb[RTA_DST] ? RTA_DATA(tb[RTA_DST]) : &def; gw = tb[RTA_GATEWAY] ? RTA_DATA(tb[RTA_GATEWAY]) : NULL; - bitlen = (rt->rtm_family == AF_INET6) ? 128 : 32; + bitlen = AF_BITS(rt->rtm_family); if ((f->type && rt->rtm_type != f->type) || (f->family && rt->rtm_family != f->family) || @@ -857,10 +1082,14 @@ static int cb_dump_route(struct nl_msg *msg, void *arg) (f->iif && iif != f->iif) || (f->oif && oif != f->oif) || (f->table && table != f->table) || - diff_prefix(rt->rtm_family, from, rt->rtm_src_len, &f->from) || - diff_prefix(rt->rtm_family, dst, rt->rtm_dst_len, &f->dst) || - diff_prefix(rt->rtm_family, gw, bitlen, &f->gw) || - diff_prefix(rt->rtm_family, src, bitlen, &f->src)) + diff_prefix(rt->rtm_family, from, rt->rtm_src_len, + f->from_exact, &f->from) || + diff_prefix(rt->rtm_family, dst, rt->rtm_dst_len, + f->dst_exact, &f->dst) || + diff_prefix(rt->rtm_family, gw, bitlen, + false, &f->gw) || + diff_prefix(rt->rtm_family, src, bitlen, + false, &f->src)) goto out; if (s->callback) @@ -988,7 +1217,8 @@ static int _route_dump(lua_State *L, struct dump_filter *filter) nlmsg_append(msg, &rtm, sizeof(rtm), 0); if (filter->get) - nla_put(msg, RTA_DST, filter->dst.len, &filter->dst.addr.v6); + nla_put(msg, RTA_DST, AF_BYTES(filter->dst.family), + &filter->dst.addr.v6); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_dump_route, &s); nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_done, &s); @@ -1063,10 +1293,10 @@ static int route_dump(lua_State *L) filter.dst = p; if ((s = L_getstr(L, 1, "from_exact")) != NULL && parse_cidr(s, &p)) - filter.from = p, filter.from.exact = true; + filter.from = p, filter.from_exact = true; if ((s = L_getstr(L, 1, "dest_exact")) != NULL && parse_cidr(s, &p)) - filter.dst = p, filter.dst.exact = true; + filter.dst = p, filter.dst_exact = true; } return _route_dump(L, &filter); @@ -1107,12 +1337,12 @@ static int cb_dump_neigh(struct nl_msg *msg, void *arg) mac = tb[NDA_LLADDR] ? RTA_DATA(tb[NDA_LLADDR]) : NULL; dst = tb[NDA_DST] ? RTA_DATA(tb[NDA_DST]) : NULL; - bitlen = (nd->ndm_family == AF_INET) ? 32 : 128; + bitlen = AF_BITS(nd->ndm_family); if ((f->family && nd->ndm_family != f->family) || (f->iif && nd->ndm_ifindex != f->iif) || (f->type && !(f->type & nd->ndm_state)) || - diff_prefix(nd->ndm_family, dst, bitlen, &f->dst) || + diff_prefix(nd->ndm_family, dst, bitlen, false, &f->dst) || diff_macaddr(mac, &f->mac)) goto out; @@ -1140,15 +1370,7 @@ static int cb_dump_neigh(struct nl_msg *msg, void *arg) L_setaddr(s->L, "dest", nd->ndm_family, dst, -1); if (mac) - { - snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", - mac->ether_addr_octet[0], mac->ether_addr_octet[1], - mac->ether_addr_octet[2], mac->ether_addr_octet[3], - mac->ether_addr_octet[4], mac->ether_addr_octet[5]); - - lua_pushstring(s->L, buf); - lua_setfield(s->L, -2, "mac"); - } + L_setaddr(s->L, "mac", AF_PACKET, mac, -1); s->index++; @@ -1241,7 +1463,7 @@ out: static int cb_dump_link(struct nl_msg *msg, void *arg) { - char *p, *addr, buf[48]; + char buf[48]; struct dump_state *s = arg; struct nlmsghdr *hdr = nlmsg_hdr(msg); struct ifinfomsg *ifm = NLMSG_DATA(hdr); @@ -1266,19 +1488,8 @@ static int cb_dump_link(struct nl_msg *msg, void *arg) if (tb[IFLA_MASTER]) L_setdev(s->L, "master", tb[IFLA_MASTER]); - if (tb[IFLA_ADDRESS]) - { - len = nla_len(tb[IFLA_ADDRESS]); - addr = nla_get_string(tb[IFLA_ADDRESS]); - - if ((len * 3) <= sizeof(buf)) - { - for (p = buf, i = 0; i < len; i++) - p += sprintf(p, "%s%02x", (i ? ":" : ""), (uint8_t)*addr++); - - L_setstr(s->L, "mac", buf); - } - } + if (tb[IFLA_ADDRESS] && nla_len(tb[IFLA_ADDRESS]) == AF_BYTES(AF_PACKET)) + L_setaddr(s->L, "mac", AF_PACKET, nla_get_string(tb[IFLA_ADDRESS]), -1); s->pending = 0; return NL_SKIP; @@ -1333,13 +1544,18 @@ static const luaL_reg ip_methods[] = { { "new", cidr_new }, { "IPv4", cidr_ipv4 }, { "IPv6", cidr_ipv6 }, + { "MAC", cidr_mac }, + + { "checkip4", cidr_checkip4 }, + { "checkip6", cidr_checkip6 }, + { "checkmac", cidr_checkmac }, { "route", route_get }, { "routes", route_dump }, { "neighbors", neighbor_dump }, - { "link", link_get }, + { "link", link_get }, { } }; @@ -1351,6 +1567,9 @@ static const luaL_reg ip_cidr_methods[] = { { "is6", cidr_is6 }, { "is6linklocal", cidr_is6linklocal }, { "is6mapped4", cidr_is6mapped4 }, + { "ismac", cidr_ismac }, + { "ismaclocal", cidr_ismaclocal }, + { "ismacmcast", cidr_ismacmcast }, { "lower", cidr_lower }, { "higher", cidr_higher }, { "equal", cidr_equal }, @@ -1360,7 +1579,9 @@ static const luaL_reg ip_cidr_methods[] = { { "mask", cidr_mask }, { "broadcast", cidr_broadcast }, { "mapped4", cidr_mapped4 }, - { "contains", cidr_contains }, + { "tomac", cidr_tomac }, + { "tolinklocal", cidr_tolinklocal }, + { "contains", cidr_contains }, { "add", cidr_add }, { "sub", cidr_sub }, { "minhost", cidr_minhost }, diff --git a/libs/luci-lib-ip/src/ip.luadoc b/libs/luci-lib-ip/src/ip.luadoc index e32ae72f40..b1ecae1453 100644 --- a/libs/luci-lib-ip/src/ip.luadoc +++ b/libs/luci-lib-ip/src/ip.luadoc @@ -27,6 +27,7 @@ addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17", "ffff:ffff:ffff:ffff::") addr6 = luci.ip.new("fe80::221:63ff:fe75:aa17/64", 128) -- override netmask` @see IPv4 @see IPv6 +@see MAC ]] ---[[ @@ -47,6 +48,7 @@ addr = luci.ip.IPv4("10.24.0.1/255.255.255.0") addr = luci.ip.IPv4("10.24.0.1", "255.255.255.0") -- separate netmask addr = luci.ip.IPv4("10.24.0.1/24", 16) -- override netmask` @see IPv6 +@see MAC ]] ---[[ @@ -67,12 +69,112 @@ addr6 = luci.ip.IPv6("fe80::221:63ff:fe75:aa17/ffff:ffff:ffff:ffff::") addr6 = luci.ip.IPv6("fe80::221:63ff:fe75:aa17", "ffff:ffff:ffff:ffff::") addr6 = luci.ip.IPv6("fe80::221:63ff:fe75:aa17/64", 128) -- override netmask` @see IPv4 +@see MAC ]] ---[[ -Determine the route leading to the given destination. +Construct a new MAC luci.ip.cidr instance. +Throws an error if the given string does not represent a valid ethernet MAC +address or if the given optional mask is of a different family. @class function @sort 4 +@name MAC +@param address String containing a valid ethernet MAC address, optionally with +prefix size (CIDR notation) or mask separated by slash. +@param netmask String containing a valid MAC address mask or number +containing a prefix size between `0` and `48` bit. +Overrides mask embedded in the first argument if specified. (optional) +@return A `luci.ip.cidr` object representing the given MAC address range. +@usage `intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/24") +intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/FF:FF:FF:0:0:0") +intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00", "FF:FF:FF:0:0:0") +intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/24", 48) -- override mask` +@see IPv4 +@see IPv6 +]] + +---[[ +Verify an IPv4 address. + +Checks whether given argument is a preexisting luci.ip.cidr IPv4 address +instance or a string literal convertible to an IPv4 address and returns a +plain Lua string containing the canonical representation of the address. + +If the argument is not a valid address, returns nothing. This function is +intended to aid in safely verifying address literals without having to deal +with exceptions. +@class function +@sort 5 +@name checkip4 +@param address String containing a valid IPv4 address or existing +luci.ip.cidr IPv4 instance. +@return A string representing the given IPv4 address. +@usage `ipv4 = luci.ip.checkip4(luci.ip.new("127.0.0.1")) -- "127.0.0.1" +ipv4 = luci.ip.checkip4("127.0.0.1") -- "127.0.0.1" +ipv4 = luci.ip.checkip4("nonesense") -- nothing +ipv4 = luci.ip.checkip4(123) -- nothing +ipv4 = luci.ip.checkip4(nil) -- nothing +ipv4 = luci.ip.checkip4() -- nothing` +@see checkip6 +@see checkmac +]] + +---[[ +Verify an IPv6 address. + +Checks whether given argument is a preexisting luci.ip.cidr IPv6 address +instance or a string literal convertible to an IPv6 address and returns a +plain Lua string containing the canonical representation of the address. + +If the argument is not a valid address, returns nothing. This function is +intended to aid in safely verifying address literals without having to deal +with exceptions. +@class function +@sort 6 +@name checkip6 +@param address String containing a valid IPv6 address or existing +luci.ip.cidr IPv6 instance. +@return A string representing the given IPv6 address. +@usage `ipv6 = luci.ip.checkip6(luci.ip.new("0:0:0:0:0:0:0:1")) -- "::1" +ipv6 = luci.ip.checkip6("0:0:0:0:0:0:0:1") -- "::1" +ipv6 = luci.ip.checkip6("nonesense") -- nothing +ipv6 = luci.ip.checkip6(123) -- nothing +ipv6 = luci.ip.checkip6(nil) -- nothing +ipv6 = luci.ip.checkip6() -- nothing` +@see checkip4 +@see checkmac +]] + +---[[ +Verify an ethernet MAC address. + +Checks whether given argument is a preexisting luci.ip.cidr MAC address +instance or a string literal convertible to an ethernet MAC and returns a +plain Lua string containing the canonical representation of the address. + +If the argument is not a valid address, returns nothing. This function is +intended to aid in safely verifying address literals without having to deal +with exceptions. +@class function +@sort 7 +@name checkmac +@param address String containing a valid MAC address or existing luci.ip.cidr +MAC address instance. +@return A string representing the given MAC address. +@usage `mac = luci.ip.checkmac(luci.ip.new("00-11-22-cc-dd-ee")) -- "00:11:22:CC:DD:EE" +mac = luci.ip.checkmac("00:11:22:cc:dd:ee") -- "00:11:22:CC:DD:EE" +mac = luci.ip.checkmac("nonesense") -- nothing +mac = luci.ip.checkmac(123) -- nothing +mac = luci.ip.checkmac(nil) -- nothing +mac = luci.ip.checkmac() -- nothing` +@see checkip4 +@see checkip6 +]] + +---[[ +Determine the route leading to the given destination. +@class function +@sort 8 @name route @param address A `luci.ip.cidr` instance or a string containing a valid IPv4 or IPv6 range as specified by `luci.ip.new()`. @@ -178,7 +280,7 @@ end`</li> ---[[ Fetch all routes, optionally matching the given criteria. @class function -@sort 5 +@sort 9 @name routes @param filter <p>Table containing one or more of the possible filter critera described below (optional)</p><table> @@ -258,7 +360,7 @@ end`</li> ---[[ Fetches entries from the IPv4 ARP and IPv6 neighbour kernel table @class function -@sort 6 +@sort 10 @name neighbors @param filter <p>Table containing one or more of the possible filter critera described below (optional)</p><table> @@ -306,7 +408,7 @@ A neighbour entry is a table containing the following fields: </tr> <tr> <td>`mac`</td> - <td>String containing the associated MAC address</td> + <td>MAC address `luci.ip.cidr` instance</td> </tr> <tr> <td>`router`</td> @@ -367,7 +469,7 @@ end)`</li> ---[[ Fetch basic device information @class function -@sort 7 +@sort 11 @name link @param device String containing the network device to query @return If the given interface is found, a table containing the fields @@ -403,8 +505,8 @@ described below is returned, else an empty table. </tr> <tr> <td>`mac`</td> - <td>String containing the link local address of the device in - dotted hex notation</td> + <td>MAC address `luci.ip.cidr` instance representing the device ethernet + address</td> </tr> </table> @usage <ul> @@ -430,6 +532,7 @@ Checks whether the CIDR instance is an IPv4 address range @sort 1 @name cidr.is4 @see cidr.is6 +@see cidr.ismac @return `true` if the CIDR is an IPv4 range, else `false` ]] @@ -470,6 +573,7 @@ Checks whether the CIDR instance is an IPv6 address range @sort 4 @name cidr.is6 @see cidr.is4 +@see cidr.ismac @return `true` if the CIDR is an IPv6 range, else `false` ]] @@ -502,13 +606,51 @@ end` ]] ---[[ +Checks whether the CIDR instance is an ethernet MAC address range + +@class function +@sort 7 +@name cidr.ismac +@see cidr.is4 +@see cidr.is6 +@return `true` if the CIDR is a MAC address range, else `false` +]] + +---[[ +Checks whether the CIDR instance is a locally administered (LAA) MAC address + +@class function +@sort 8 +@name cidr.ismaclocal +@return `true` if the MAC address sets the locally administered bit. +@usage `local mac = luci.ip.new("02:C0:FF:EE:00:01") +if mac:ismaclocal() then + print("Is an LAA MAC address") +end` +]] + +---[[ +Checks whether the CIDR instance is a multicast MAC address + +@class function +@sort 9 +@name cidr.ismacmcast +@return `true` if the MAC address sets the multicast bit. +@usage `local mac = luci.ip.new("01:00:5E:7F:00:10") +if addr:ismacmcast() then + print("Is a multicast MAC address") +end` +]] + +---[[ Checks whether this CIDR instance is lower than the given argument. The comparisation follows these rules: -<ul><li>An IPv4 address is always lower than an IPv6 address</li> +<ul><li>An IPv4 address is always lower than an IPv6 address and IPv6 addresses +are considered lower than MAC addresses</li> <li>Prefix sizes are ignored</li></ul> @class function -@sort 7 +@sort 10 @name cidr.lower @param addr A `luci.ip.cidr` instance or a string convertable by `luci.ip.new()` to compare against. @@ -518,7 +660,8 @@ The comparisation follows these rules: print(addr:lower(addr)) -- false print(addr:lower("10.10.10.10/24")) -- false print(addr:lower(luci.ip.new("::1"))) -- true -print(addr:lower(luci.ip.new("192.168.200.1"))) -- true` +print(addr:lower(luci.ip.new("192.168.200.1"))) -- true +print(addr:lower(luci.ip.new("00:14:22:01:23:45"))) -- true` @see cidr.higher @see cidr.equal ]] @@ -526,11 +669,12 @@ print(addr:lower(luci.ip.new("192.168.200.1"))) -- true` ---[[ Checks whether this CIDR instance is higher than the given argument. The comparisation follows these rules: -<ul><li>An IPv4 address is always lower than an IPv6 address</li> +<ul><li>An IPv4 address is always lower than an IPv6 address and IPv6 addresses +are considered lower than MAC addresses</li> <li>Prefix sizes are ignored</li></ul> @class function -@sort 8 +@sort 11 @name cidr.higher @param addr A `luci.ip.cidr` instance or a string convertable by `luci.ip.new()` to compare against. @@ -540,7 +684,8 @@ The comparisation follows these rules: print(addr:higher(addr)) -- false print(addr:higher("10.10.10.10/24")) -- true print(addr:higher(luci.ip.new("::1"))) -- false -print(addr:higher(luci.ip.new("192.168.200.1"))) -- false` +print(addr:higher(luci.ip.new("192.168.200.1"))) -- false +print(addr:higher(luci.ip.new("00:14:22:01:23:45"))) -- false` @see cidr.lower @see cidr.equal ]] @@ -549,7 +694,7 @@ print(addr:higher(luci.ip.new("192.168.200.1"))) -- false` Checks whether this CIDR instance is equal to the given argument. @class function -@sort 9 +@sort 12 @name cidr.equal @param addr A `luci.ip.cidr` instance or a string convertable by `luci.ip.new()` to compare against. @@ -562,7 +707,11 @@ print(addr:equal(luci.ip.new("::1"))) -- false local addr6 = luci.ip.new("::1") print(addr6:equal("0:0:0:0:0:0:0:1/64")) -- true -print(addr6:equal(luci.ip.new("fe80::221:63ff:fe75:aa17"))) -- false` +print(addr6:equal(luci.ip.new("fe80::221:63ff:fe75:aa17"))) -- false + +local mac = luci.ip.new("00:14:22:01:23:45") +print(mac:equal("0:14:22:1:23:45")) -- true +print(mac:equal(luci.ip.new("01:23:45:67:89:AB")) -- false` @see cidr.lower @see cidr.higher ]] @@ -573,11 +722,11 @@ If the optional mask parameter is given, the prefix size of this CIDR is altered else the current prefix size is returned. @class function -@sort 10 +@sort 13 @name cidr.prefix @param mask Either a number containing the number of bits (`0..32` - for IPv4, `0..128` for IPv6) or a string containing a valid - netmask (optional) + for IPv4, `0..128` for IPv6 or `0..48` for MAC addresses) or a string + containing a valid netmask (optional) @return Bit count of the current prefix size @usage `local range = luci.ip.new("192.168.1.1/255.255.255.0") print(range:prefix()) -- 24 @@ -597,11 +746,11 @@ with all host parts masked out. The used prefix size can be overridden by the optional mask parameter. @class function -@sort 11 +@sort 14 @name cidr.network @param mask Either a number containing the number of bits (`0..32` - for IPv4, `0..128` for IPv6) or a string containing a valid - netmask (optional) + for IPv4, `0..128` for IPv6 or `0..48` for MAC addresses) or a string + containing a valid netmask (optional) @return CIDR instance representing the network address @usage `local range = luci.ip.new("192.168.62.243/255.255.0.0") print(range:network()) -- "192.168.0.0" @@ -616,10 +765,10 @@ print(range6:network()) -- "fd9b:62b3:9cc5::"` Derive host address of CIDR instance. This function essentially constructs a copy of this CIDR with the prefix size -set to `32` for IPv4 and `128` for IPv6. +set to `32` for IPv4, `128` for IPv6 or `48` for MAC addresses. @class function -@sort 12 +@sort 15 @name cidr.host @return CIDR instance representing the host address @usage `local range = luci.ip.new("172.19.37.45/16") @@ -634,11 +783,11 @@ Constructs a CIDR instance representing the netmask of this instance. The used prefix size can be overridden by the optional mask parameter. @class function -@sort 13 +@sort 16 @name cidr.mask @param mask Either a number containing the number of bits (`0..32` - for IPv4, `0..128` for IPv6) or a string containing a valid - netmask (optional) + for IPv4, `0..128` for IPv6 or `0..48` for MAC addresses) or a string + containing a valid netmask (optional) @return CIDR instance representing the netmask @usage `local range = luci.ip.new("172.19.37.45/16") print(range:mask()) -- "255.255.0.0" @@ -652,15 +801,14 @@ Derive broadcast address of CIDR instance. Constructs a CIDR instance representing the broadcast address of this instance. The used prefix size can be overridden by the optional mask parameter. -This function has no effect on IPv6 instances, it will return nothing in this -case. +This function has no effect on IPv6 or MAC address instances, it will return +nothing in this case. @class function -@sort 14 +@sort 17 @name cidr.broadcast -@param mask Either a number containing the number of bits (`0..32` - for IPv4, `0..128` for IPv6) or a string containing a valid - netmask (optional) +@param mask Either a number containing the number of bits (`0..32` for IPv4) or + a string containing a valid netmask (optional) @return Return a new CIDR instance representing the broadcast address if this instance is an IPv4 range, else return nothing. @usage `local range = luci.ip.new("172.19.37.45/16") @@ -675,11 +823,11 @@ Derive mapped IPv4 address of CIDR instance. Constructs a CIDR instance representing the IPv4 address of the IPv6 mapped IPv4 address in this instance. -This function has no effect on IPv4 instances or IPv6 instances which are not a -mapped address, it will return nothing in this case. +This function has no effect on IPv4 instances, MAC address instances or IPv6 +instances which are not a mapped address, it will return nothing in this case. @class function -@sort 15 +@sort 18 @name cidr.mapped4 @return Return a new CIDR instance representing the IPv4 address if this instance is an IPv6 mapped IPv4 address, else return nothing. @@ -688,10 +836,46 @@ print(addr:mapped4()) -- "172.16.19.1"` ]] ---[[ +Derive MAC address of IPv6 link local CIDR instance. + +Constructs a CIDR instance representing the MAC address contained in the IPv6 +link local address of this instance. + +This function has no effect on IPv4 instances, MAC address instances or IPv6 +instances which are not a link local address, it will return nothing in this +case. + +@class function +@sort 19 +@name cidr.tomac +@return Return a new CIDR instance representing the MAC address if this + instance is an IPv6 link local address, else return nothing. +@usage `local addr = luci.ip.new("fe80::6666:b3ff:fe47:e1b9") +print(addr:tomac()) -- "64:66:B3:47:E1:B9"` +]] + +---[[ +Derive IPv6 link local address from MAC address CIDR instance. + +Constructs a CIDR instance representing the IPv6 link local address of the +MAC address represented by this instance. + +This function has no effect on IPv4 instances or IPv6 instances, it will return +nothing in this case. + +@class function +@sort 20 +@name cidr.tolinklocal +@return Return a new CIDR instance representing the IPv6 link local address. +@usage `local mac = luci.ip.new("64:66:B3:47:E1:B9") +print(mac:tolinklocal()) -- "fe80::6666:b3ff:fe47:e1b9"` +]] + +---[[ Test whether CIDR contains given range. @class function -@sort 16 +@sort 21 @name cidr.contains @param addr A `luci.ip.cidr` instance or a string convertable by `luci.ip.new()` to test. @@ -704,7 +888,11 @@ print(range:contains("10.0.0.0/8")) -- false local range6 = luci.ip.new("fe80::/10") print(range6:contains("fe80::221:63f:fe75:aa17/64")) -- true -print(range6:contains("fd9b:6b3:c5:0:221:63f:fe75:aa17/64")) -- false` +print(range6:contains("fd9b:6b3:c5:0:221:63f:fe75:aa17/64")) -- false + +local intel_macs = luci.ip.MAC("C0:B6:F9:00:00:00/24") +print(intel_macs:contains("C0:B6:F9:A3:C:11")) -- true +print(intel_macs:contains("64:66:B3:47:E1:B9")) -- false` ]] ---[[ @@ -712,7 +900,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. @class function -@sort 17 +@sort 22 @name cidr.add @param amount A numeric value between 0 and 0xFFFFFFFF, a `luci.ip.cidr` instance or a string convertable by @@ -726,32 +914,42 @@ address space, the result is set to the highest possible address. this instance plus the added amount or the highest possible address if the addition overflowed the available address space.</li></ul> @usage `local addr = luci.ip.new("192.168.1.1/24") -print(addr:add(250)) -- "192.168.1.251/24" -print(addr:add("0.0.99.0")) -- "192.168.100.1/24" +print(addr:add(250)) -- "192.168.1.251/24" +print(addr:add("0.0.99.0")) -- "192.168.100.1/24" -addr:add(256, true) -- true -print(addr) -- "192.168.2.1/24 +addr:add(256, true) -- true +print(addr) -- "192.168.2.1/24 -addr:add("255.0.0.0", true) -- false (overflow) -print(addr) -- "255.255.255.255/24 +addr:add("255.0.0.0", true) -- false (overflow) +print(addr) -- "255.255.255.255/24 local addr6 = luci.ip.new("fe80::221:63f:fe75:aa17/64") -print(addr6:add(256)) -- "fe80::221:63f:fe75:ab17/64" -print(addr6:add("::ffff:0")) -- "fe80::221:640:fe74:aa17/64" +print(addr6:add(256)) -- "fe80::221:63f:fe75:ab17/64" +print(addr6:add("::ffff:0")) -- "fe80::221:640:fe74:aa17/64" + +addr6:add(256, true) -- true +print(addr6) -- "fe80::221:63f:fe75:ab17/64 + +addr6:add("ffff::", true) -- false (overflow) +print(addr6) -- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64" -addr:add(256, true) -- true -print(addr) -- "fe80::221:63f:fe75:ab17/64 +local mac = luci.ip.new("00:14:22:01:23:45") +print(mac:add(256)) -- "00:14:22:01:24:45" +print(mac:add("0:0:0:0:FF:0") -- "00:14:22:02:22:45" -addr:add("ffff::", true) -- false (overflow) -print(addr) -- "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/64"` +mac:add(256, true) -- true +print(mac) -- "00:14:22:01:24:45" + +mac:add("FF:FF:0:0:0:0", true) -- false (overflow) +print(mac) -- "FF:FF:FF:FF:FF:FF"` ]] ---[[ -Substract given amount from CIDR instance. If the result would under, the lowest +Subtract given amount from CIDR instance. If the result would under, the lowest possible address is returned. @class function -@sort 18 +@sort 23 @name cidr.sub @param amount A numeric value between 0 and 0xFFFFFFFF, a `luci.ip.cidr` instance or a string convertable by @@ -759,11 +957,11 @@ possible address is returned. @param inplace If `true`, modify this instance instead of returning a new derived CIDR instance. @return <ul> - <li>When substracting inplace: Return `true` if the substraction - succeded or `false` when the substraction underflowed.</li> + <li>When subtracting inplace: Return `true` if the subtraction + succeeded or `false` when the subtraction underflowed.</li> <li>When deriving new CIDR: Return new instance representing the value of - this instance minus the substracted amount or the lowest address if - the substraction underflowed.</li></ul> + this instance minus the subtracted amount or the lowest address if + the subtraction underflowed.</li></ul> @usage `local addr = luci.ip.new("192.168.1.1/24") print(addr:sub(256)) -- "192.168.0.1/24" print(addr:sub("0.168.0.0")) -- "192.0.1.1/24" @@ -782,14 +980,24 @@ addr:sub(256, true) -- true print(addr) -- "fe80::221:63f:fe75:a917/64" addr:sub("ffff::", true) -- false (underflow) -print(addr) -- "::/64"` +print(addr) -- "::/64" + +local mac = luci.ip.new("00:14:22:01:23:45") +print(mac:sub(256)) -- "00:14:22:01:22:45" +print(mac:sub("0:0:0:0:FF:0") -- "00:14:22:00:24:45" + +mac:sub(256, true) -- true +print(mac) -- "00:14:22:01:22:45" + +mac:sub("FF:FF:0:0:0:0", true) -- false (overflow) +print(mac) -- "00:00:00:00:00:00"` ]] ---[[ Calculate the lowest possible host address within this CIDR instance. @class function -@sort 19 +@sort 24 @name cidr.minhost @return Returns a new CIDR instance representing the lowest host address within this range. @@ -797,14 +1005,17 @@ Calculate the lowest possible host address within this CIDR instance. print(addr:minhost()) -- "192.168.123.1" local addr6 = luci.ip.new("fd9b:62b3:9cc5:0:221:63ff:fe75:aa17/64") -print(addr6:minhost()) -- "fd9b:62b3:9cc5::1"` +print(addr6:minhost()) -- "fd9b:62b3:9cc5::1" + +local mac = luci.ip.new("00:14:22:01:22:45/32") +print(mac:minhost()) -- "00:14:22:01:00:01"` ]] ---[[ Calculate the highest possible host address within this CIDR instance. @class function -@sort 20 +@sort 25 @name cidr.maxhost @return Returns a new CIDR instance representing the highest host address within this range. @@ -812,20 +1023,24 @@ Calculate the highest possible host address within this CIDR instance. print(addr:maxhost()) -- "192.168.123.254" (.255 is broadcast) local addr6 = luci.ip.new("fd9b:62b3:9cc5:0:221:63ff:fe75:aa17/64") -print(addr6:maxhost()) -- "fd9b:62b3:9cc5:0:ffff:ffff:ffff:ffff"` +print(addr6:maxhost()) -- "fd9b:62b3:9cc5:0:ffff:ffff:ffff:ffff" + +local mac = luci.ip.new("00:14:22:01:22:45/32") +print(mac:maxhost()) -- "00:14:22:01:FF:FF"` ]] ---[[ Convert CIDR instance into string representation. -If the prefix size of instance is less than 32 for IPv4 or 128 for IPv6, the -address is returned in the form "address/prefix" otherwise just "address". +If the prefix size of instance is less than 32 for IPv4, 128 for IPv6 or 48 for +MACs, the address is returned in the form "address/prefix" otherwise just +"address". It is usually not required to call this function directly as CIDR objects define it as __tostring function in the associated metatable. @class function -@sort 21 +@sort 26 @name cidr.string @return Returns a string representing the range or address of this CIDR instance ]] diff --git a/libs/luci-lib-nixio/docsrc/README.lua b/libs/luci-lib-nixio/docsrc/README.lua index ee3e3a216c..9860cf0919 100644 --- a/libs/luci-lib-nixio/docsrc/README.lua +++ b/libs/luci-lib-nixio/docsrc/README.lua @@ -33,7 +33,7 @@ module "nixio.README" -- <br />In general all functions are namend and behave like their POSIX API -- counterparts - where applicable - applying the following rules: -- <ul> --- <li>Functions should be named like the underlying POSIX API function ommiting +-- <li>Functions should be named like the underlying POSIX API function omitting -- prefixes or suffixes - especially when placed in an object-context ( -- lockf -> File:lock, fsync -> File:sync, dup2 -> dup, ...)</li> -- <li>If you are unclear about the behaviour of a function you should consult @@ -41,10 +41,10 @@ module "nixio.README" -- <li>If the name is significantly different from the POSIX-function, the -- underlying function(s) are stated in the documentation.</li> -- <li>Parameters should reflect those of the C-API, buffer length arguments and --- by-reference parameters should be ommitted for pratical purposes.</li> +-- by-reference parameters should be omitted for practical purposes.</li> -- <li>If a C function accepts a bitfield as parameter, it should be translated -- into lower case string flags representing the flags if the bitfield is the --- last parameter and also ommiting prefixes or suffixes. (e.g. waitpid +-- last parameter and also omitting prefixes or suffixes. (e.g. waitpid -- (pid, &s, WNOHANG | WUNTRACED) -> waitpid(pid, "nohang", "untraced"), -- getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) -> -- Socket:getopt("socket", "reuseaddr"), etc.) </li> diff --git a/libs/luci-lib-nixio/docsrc/nixio.Socket.lua b/libs/luci-lib-nixio/docsrc/nixio.Socket.lua index 7123393bf4..c970534ed0 100644 --- a/libs/luci-lib-nixio/docsrc/nixio.Socket.lua +++ b/libs/luci-lib-nixio/docsrc/nixio.Socket.lua @@ -71,7 +71,7 @@ module "nixio.Socket" --- Send a message on the socket. -- This function is identical to sendto except for the missing destination --- paramters. See the sendto description for a detailed description. +-- parameters. See the sendto description for a detailed description. -- @class function -- @name Socket.send -- @param buffer Buffer holding the data to be written. @@ -167,4 +167,4 @@ module "nixio.Socket" -- "mtu" (IP, IPv6), "hdrincl" (IP), "multicast_ttl" (IP), "multicast_loop" -- (IP, IPv6), "multicast_if" (IP, IPv6), "v6only" (IPv6), "multicast_hops" -- (IPv6), "add_membership" (IP, IPv6), "drop_membership" (IP, IPv6)] --- @return Value
\ No newline at end of file +-- @return Value diff --git a/libs/luci-lib-nixio/docsrc/nixio.UnifiedIO.lua b/libs/luci-lib-nixio/docsrc/nixio.UnifiedIO.lua index 6e407ff2ca..6d1d5ea8c6 100644 --- a/libs/luci-lib-nixio/docsrc/nixio.UnifiedIO.lua +++ b/libs/luci-lib-nixio/docsrc/nixio.UnifiedIO.lua @@ -24,15 +24,15 @@ module "nixio.UnifiedIO" -- @class function -- @name UnifiedIO.readall -- @usage This function uses the low-level read function of the descriptor. --- @usage If the length parameter is ommited, this function returns all data +-- @usage If the length parameter is omitted, this function returns all data -- that can be read before an end-of-file, end-of-stream, connection shutdown -- or similar happens. -- @usage If the descriptor is non-blocking this function may fail with EAGAIN. -- @param length Bytes to read (optional) --- @return data that was successfully read if no error occured +-- @return data that was successfully read if no error occurred -- @return - reserved for error code - -- @return - reserved for error message - --- @return data that was successfully read even if an error occured +-- @return data that was successfully read even if an error occurred --- Write a block of data and wait until all data is written. -- @class function @@ -40,10 +40,10 @@ module "nixio.UnifiedIO" -- @usage This function uses the low-level write function of the descriptor. -- @usage If the descriptor is non-blocking this function may fail with EAGAIN. -- @param block Bytes to write --- @return bytes that were successfully written if no error occured +-- @return bytes that were successfully written if no error occurred -- @return - reserved for error code - -- @return - reserved for error message - --- @return bytes that were successfully written even if an error occured +-- @return bytes that were successfully written even if an error occurred --- Create a line-based iterator. -- Lines may end with either \n or \r\n, these control chars are not included @@ -56,7 +56,7 @@ module "nixio.UnifiedIO" -- to stop reading line-based and want to use the read(all) functions instead -- you can pass "true" to the iterator which will flush the buffer -- and return the bufferd data. --- @usage If the limit parameter is ommited, this function uses the nixio +-- @usage If the limit parameter is omitted, this function uses the nixio -- buffersize (8192B by default). -- @usage If the descriptor is non-blocking the iterator may fail with EAGAIN. -- @usage The iterator can be used as an LTN12 source. @@ -69,7 +69,7 @@ module "nixio.UnifiedIO" -- @usage This function uses the low-level read function of the descriptor. -- @usage The blocksize given is only advisory and to be seen as an upper limit, -- if an underlying read returns less bytes the chunk is nevertheless returned. --- @usage If the limit parameter is ommited, the iterator returns data +-- @usage If the limit parameter is omitted, the iterator returns data -- until an end-of-file, end-of-stream, connection shutdown or similar happens. -- @usage The iterator will not buffer so it is safe to mix with calls to read. -- @usage If the descriptor is non-blocking the iterator may fail with EAGAIN. @@ -94,15 +94,15 @@ module "nixio.UnifiedIO" -- @name UnifiedIO.copy -- @usage This function uses the blocksource function of the source descriptor -- and the sink function of the target descriptor. --- @usage If the limit parameter is ommited, data is copied +-- @usage If the limit parameter is omitted, data is copied -- until an end-of-file, end-of-stream, connection shutdown or similar happens. -- @usage If the descriptor is non-blocking the function may fail with EAGAIN. -- @param fdout Target Descriptor -- @param size Bytes to copy (optional) --- @return bytes that were successfully written if no error occured +-- @return bytes that were successfully written if no error occurred -- @return - reserved for error code - -- @return - reserved for error message - --- @return bytes that were successfully written even if an error occured +-- @return bytes that were successfully written even if an error occurred --- Copy data from the current descriptor to another one using kernel-space -- copying if possible. @@ -111,19 +111,19 @@ module "nixio.UnifiedIO" -- @usage This function uses the sendfile() syscall to copy the data or the -- blocksource function of the source descriptor and the sink function -- of the target descriptor as a fallback mechanism. --- @usage If the limit parameter is ommited, data is copied +-- @usage If the limit parameter is omitted, data is copied -- until an end-of-file, end-of-stream, connection shutdown or similar happens. -- @usage If the descriptor is non-blocking the function may fail with EAGAIN. -- @param fdout Target Descriptor -- @param size Bytes to copy (optional) --- @return bytes that were successfully written if no error occured +-- @return bytes that were successfully written if no error occurred -- @return - reserved for error code - -- @return - reserved for error message - --- @return bytes that were successfully written even if an error occured +-- @return bytes that were successfully written even if an error occurred --- Close the descriptor. -- @class function -- @name UnifiedIO.close -- @usage If the descriptor is a TLS-socket the underlying descriptor is -- closed without touching the TLS connection. --- @return true
\ No newline at end of file +-- @return true diff --git a/libs/luci-lib-nixio/docsrc/nixio.fs.lua b/libs/luci-lib-nixio/docsrc/nixio.fs.lua index 5bfd7a6b79..ef495f260a 100644 --- a/libs/luci-lib-nixio/docsrc/nixio.fs.lua +++ b/libs/luci-lib-nixio/docsrc/nixio.fs.lua @@ -47,7 +47,7 @@ module "nixio.fs" -- @name nixio.fs.rename -- @param src Source path -- @param dest Destination path --- @usage It is normally not possible to rename files accross filesystems. +-- @usage It is normally not possible to rename files across filesystems. -- @return true --- Remove an empty directory. @@ -262,4 +262,4 @@ module "nixio.fs" -- omit the basename even if source and destination basename are equal. -- @param src Source path -- @param dest Destination path --- @return true
\ No newline at end of file +-- @return true diff --git a/libs/luci-lib-nixio/docsrc/nixio.lua b/libs/luci-lib-nixio/docsrc/nixio.lua index 1b434d76de..1a0d69a054 100644 --- a/libs/luci-lib-nixio/docsrc/nixio.lua +++ b/libs/luci-lib-nixio/docsrc/nixio.lua @@ -118,7 +118,7 @@ module "nixio" -- @param flag1 First Flag ["append", "creat", "excl", "nonblock", "ndelay", -- "sync", "trunc", "rdonly", "wronly", "rdwr"] -- @param ... More Flags [-"-] --- @return flag to be used as second paramter to open +-- @return flag to be used as second parameter to open --- Duplicate a file descriptor. -- @class function @@ -167,7 +167,7 @@ module "nixio" --- Wait for some event on a file descriptor. -- poll() sets the revents-field of the tables provided by fds to a bitfield --- indicating the events that occured. +-- indicating the events that occurred. -- @class function -- @usage This function works in-place on the provided table and only -- writes the revents field, you can use other fields on your demand. @@ -303,7 +303,7 @@ module "nixio" --- Set or unset a environment variable. -- @class function -- @name nixio.setenv --- @usage The environment variable will be unset if value is ommited. +-- @usage The environment variable will be unset if value is omitted. -- @param variable Variable -- @param value Value (optional) -- @return true diff --git a/modules/luci-base/luasrc/cbi/datatypes.lua b/modules/luci-base/luasrc/cbi/datatypes.lua index a7e02f350a..55cdf8a74b 100644 --- a/modules/luci-base/luasrc/cbi/datatypes.lua +++ b/modules/luci-base/luasrc/cbi/datatypes.lua @@ -196,23 +196,7 @@ function portrange(val) end function macaddr(val) - if val and val:match( - "^[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+:" .. - "[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+$" - ) then - local parts = util.split( val, ":" ) - - for i = 1,6 do - parts[i] = tonumber( parts[i], 16 ) - if parts[i] < 0 or parts[i] > 255 then - return false - end - end - - return true - end - - return false + return ip.checkmac(val) and true or false end function hostname(val) diff --git a/modules/luci-base/luasrc/http/protocol.luadoc b/modules/luci-base/luasrc/http/protocol.luadoc index 67a60d9e7a..19a0a3419b 100644 --- a/modules/luci-base/luasrc/http/protocol.luadoc +++ b/modules/luci-base/luasrc/http/protocol.luadoc @@ -69,7 +69,7 @@ data line by line with the trailing \r\n stripped of. Decode a mime encoded http message body with multipart/form-data Content-Type. Stores all extracted data associated with its parameter name -in the params table withing the given message object. Multiple parameter +in the params table within the given message object. Multiple parameter values are stored as tables, ordinary ones as strings. If an optional file callback function is given then it is feeded with the file contents chunk by chunk and only the extracted file name is stored @@ -92,7 +92,7 @@ with three arguments: Decode an urlencoded http message body with application/x-www-urlencoded Content-Type. Stores all extracted data associated with its parameter name -in the params table withing the given message object. Multiple parameter +in the params table within the given message object. Multiple parameter values are stored as tables, ordinary ones as strings. @class function @name urldecode_message_body diff --git a/modules/luci-base/luasrc/model/network.lua b/modules/luci-base/luasrc/model/network.lua index 9ea8e369da..056fc67b14 100644 --- a/modules/luci-base/luasrc/model/network.lua +++ b/modules/luci-base/luasrc/model/network.lua @@ -330,7 +330,7 @@ function init(cursor) if i.family == "packet" then _interfaces[name].flags = i.flags _interfaces[name].stats = i.data - _interfaces[name].macaddr = i.addr + _interfaces[name].macaddr = ipc.checkmac(i.addr) elseif i.family == "inet" then _interfaces[name].ipaddrs[#_interfaces[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask) elseif i.family == "inet6" then @@ -543,6 +543,9 @@ end function del_network(self, n) local r = _uci:delete("network", n) if r then + _uci:delete_all("luci", "ifstate", + function(s) return (s.interface == n) end) + _uci:delete_all("network", "alias", function(s) return (s.interface == n) end) @@ -998,7 +1001,10 @@ function protocol.ip6addrs(self) if type(addrs) == "table" then for n, addr in ipairs(addrs) do - if type(addr["local-address"]) == "table" then + if type(addr["local-address"]) == "table" and + type(addr["local-address"].mask) == "number" and + type(addr["local-address"].address) == "string" + then rv[#rv+1] = "%s/%d" %{ addr["local-address"].address, addr["local-address"].mask @@ -1227,8 +1233,7 @@ function interface.name(self) end function interface.mac(self) - local mac = self:_ubus("macaddr") - return mac and mac:upper() + return ipc.checkmac(self:_ubus("macaddr")) end function interface.ipaddrs(self) diff --git a/modules/luci-base/luasrc/sys.lua b/modules/luci-base/luasrc/sys.lua index 84c747f2bd..12b20e4c38 100644 --- a/modules/luci-base/luasrc/sys.lua +++ b/modules/luci-base/luasrc/sys.lua @@ -138,17 +138,22 @@ local function _nethints(what, callback) luci.ip.neighbors(nil, function(neigh) if neigh.mac and neigh.family == 4 then - _add(what, neigh.mac:upper(), neigh.dest:string(), nil, nil) + _add(what, neigh.mac:string(), neigh.dest:string(), nil, nil) elseif neigh.mac and neigh.family == 6 then - _add(what, neigh.mac:upper(), nil, neigh.dest:string(), nil) + _add(what, neigh.mac:string(), nil, neigh.dest:string(), nil) 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) + mac, name = e:match("^([a-fA-F0-9:-]+)%s+(%S+)") + mac = luci.ip.checkmac(mac) + if mac and name then + if luci.ip.checkip4(name) then + _add(what, mac, name, nil, nil) + else + _add(what, mac, nil, nil, name) + end end end end @@ -158,8 +163,9 @@ local function _nethints(what, callback) if s.leasefile and fs.access(s.leasefile) then for e in io.lines(s.leasefile) do mac, ip, name = e:match("^%d+ (%S+) (%S+) (%S+)") + mac = luci.ip.checkmac(mac) if mac and ip then - _add(what, mac:upper(), ip, nil, name ~= "*" and name) + _add(what, mac, ip, nil, name ~= "*" and name) end end end @@ -169,7 +175,10 @@ local function _nethints(what, callback) cur:foreach("dhcp", "host", function(s) for mac in luci.util.imatch(s.mac) do - _add(what, mac:upper(), s.ip, nil, s.name) + mac = luci.ip.checkmac(mac) + if mac then + _add(what, mac, s.ip, nil, s.name) + end end end) diff --git a/modules/luci-base/luasrc/tools/status.lua b/modules/luci-base/luasrc/tools/status.lua index 95ff46df15..5012111815 100644 --- a/modules/luci-base/luasrc/tools/status.lua +++ b/modules/luci-base/luasrc/tools/status.lua @@ -4,6 +4,7 @@ module("luci.tools.status", package.seeall) local uci = require "luci.model.uci".cursor() +local ipc = require "luci.ip" local function dhcp_leases_common(family) local rv = { } @@ -31,7 +32,7 @@ local function dhcp_leases_common(family) if family == 4 and not ip:match(":") then rv[#rv+1] = { expires = (expire ~= 0) and os.difftime(expire, os.time()), - macaddr = mac, + macaddr = ipc.checkmac(mac) or "00:00:00:00:00:00", ipaddr = ip, hostname = (name ~= "*") and name } @@ -74,19 +75,9 @@ local function dhcp_leases_common(family) hostname = (name ~= "-") and name } elseif ip and iaid == "ipv4" and family == 4 then - local mac, mac1, mac2, mac3, mac4, mac5, mac6 - if duid and type(duid) == "string" then - mac1, mac2, mac3, mac4, mac5, mac6 = duid:match("^(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)$") - end - if not (mac1 and mac2 and mac3 and mac4 and mac5 and mac6) then - mac = "FF:FF:FF:FF:FF:FF" - else - mac = mac1..":"..mac2..":"..mac3..":"..mac4..":"..mac5..":"..mac6 - end rv[#rv+1] = { expires = (expire >= 0) and os.difftime(expire, os.time()), - macaddr = duid, - macaddr = mac:lower(), + macaddr = ipc.checkmac(duid:gsub("^(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)$", "%1:%2:%3:%4:%5:%6")) or "00:00:00:00:00:00", ipaddr = ip, hostname = (name ~= "-") and name } diff --git a/modules/luci-base/luasrc/util.luadoc b/modules/luci-base/luasrc/util.luadoc index 805eeb7f8e..949aeb21c0 100644 --- a/modules/luci-base/luasrc/util.luadoc +++ b/modules/luci-base/luasrc/util.luadoc @@ -109,13 +109,13 @@ Remove leading and trailing whitespace from given string value. ]] ---[[ -Count the occurences of given substring in given string. +Count the occurrences of given substring in given string. @class function @name cmatch @param str String to search in @param pattern String containing pattern to find -@return Number of found occurences +@return Number of found occurrences ]] ---[[ diff --git a/modules/luci-base/luasrc/view/cbi/firewall_zonelist.htm b/modules/luci-base/luasrc/view/cbi/firewall_zonelist.htm index 5cb31511f6..b4260707ef 100644 --- a/modules/luci-base/luasrc/view/cbi/firewall_zonelist.htm +++ b/modules/luci-base/luasrc/view/cbi/firewall_zonelist.htm @@ -24,70 +24,72 @@ end -%> -<ul style="margin:0; list-style-type:none; text-align:left"> - <% if self.allowlocal then %> - <li style="padding:0.5em"> - <input class="cbi-input-radio" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "_empty") .. attr("name", cbid) .. attr("value", "") .. ifattr(checked[""], "checked", "checked")%> />   - <label<%=attr("for", cbid .. "_empty")%>></label> - <label<%=attr("for", cbid .. "_empty")%> style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge"> - <strong><%:Device%></strong> - <% if self.allowany and self.allowlocal then %>(<%:input%>)<% end %> - </label> - </li> - <% end %> - <% if self.allowany then %> - <li style="padding:0.5em"> - <input class="cbi-input-radio" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "_any") .. attr("name", cbid) .. attr("value", "*") .. ifattr(checked["*"], "checked", "checked")%> />   - <label<%=attr("for", cbid .. "_any")%>></label> - <label<%=attr("for", cbid .. "_any")%> style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge"> - <strong><%:Any zone%></strong> - <% if self.allowany and self.allowlocal then %>(<%:forward%>)<% end %> - </label> - </li> - <% end %> - <% - for _, zone in utl.spairs(zones, function(a,b) return (zones[a]:name() < zones[b]:name()) end) do - if zone:name() ~= self.exclude then - selected = selected or (value == zone:name()) - %> - <li style="padding:0.5em"> - <input class="cbi-input-radio" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "." .. zone:name()) .. attr("name", cbid) .. attr("value", zone:name()) .. ifattr(checked[zone:name()], "checked", "checked")%> />   - <label<%=attr("for", cbid .. "." .. zone:name())%>></label> - <label<%=attr("for", cbid .. "." .. zone:name())%> style="background-color:<%=zone:get_color()%>" class="zonebadge"> - <strong><%=zone:name()%>:</strong> - <% - local zempty = true - for _, net in ipairs(zone:get_networks()) do - net = nwm:get_network(net) - if net then - zempty = false - %> - <span class="ifacebadge<% if net:name() == self.network then %> ifacebadge-active<% end %>"><%=net:name()%>: +<span> + <ul style="margin:0; list-style-type:none; text-align:left"> + <% if self.allowlocal then %> + <li style="padding:0.5em"> + <input class="cbi-input-radio" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "_empty") .. attr("name", cbid) .. attr("value", "") .. ifattr(checked[""], "checked", "checked")%> />   + <label<%=attr("for", cbid .. "_empty")%>></label> + <label<%=attr("for", cbid .. "_empty")%> style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge"> + <strong><%:Device%></strong> + <% if self.allowany and self.allowlocal then %>(<%:input%>)<% end %> + </label> + </li> + <% end %> + <% if self.allowany then %> + <li style="padding:0.5em"> + <input class="cbi-input-radio" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "_any") .. attr("name", cbid) .. attr("value", "*") .. ifattr(checked["*"], "checked", "checked")%> />   + <label<%=attr("for", cbid .. "_any")%>></label> + <label<%=attr("for", cbid .. "_any")%> style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge"> + <strong><%:Any zone%></strong> + <% if self.allowany and self.allowlocal then %>(<%:forward%>)<% end %> + </label> + </li> + <% end %> + <% + for _, zone in utl.spairs(zones, function(a,b) return (zones[a]:name() < zones[b]:name()) end) do + if zone:name() ~= self.exclude then + selected = selected or (value == zone:name()) + %> + <li style="padding:0.5em"> + <input class="cbi-input-radio" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "." .. zone:name()) .. attr("name", cbid) .. attr("value", zone:name()) .. ifattr(checked[zone:name()], "checked", "checked")%> />   + <label<%=attr("for", cbid .. "." .. zone:name())%>></label> + <label<%=attr("for", cbid .. "." .. zone:name())%> style="background-color:<%=zone:get_color()%>" class="zonebadge"> + <strong><%=zone:name()%>:</strong> <% - local nempty = true - for _, iface in ipairs(net:is_bridge() and net:get_interfaces() or { net:get_interface() }) do - nempty = false - %> - <img<%=attr("title", iface:get_i18n())%> style="width:16px; height:16px; vertical-align:middle" src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" /> - <% end %> - <% if nempty then %><em><%:(empty)%></em><% end %> - </span> - <% end end %> - <% if zempty then %><em><%:(empty)%></em><% end %> - </label> - </li> - <% end end %> + local zempty = true + for _, net in ipairs(zone:get_networks()) do + net = nwm:get_network(net) + if net then + zempty = false + %> + <span class="ifacebadge<% if net:name() == self.network then %> ifacebadge-active<% end %>"><%=net:name()%>: + <% + local nempty = true + for _, iface in ipairs(net:is_bridge() and net:get_interfaces() or { net:get_interface() }) do + nempty = false + %> + <img<%=attr("title", iface:get_i18n())%> style="width:16px; height:16px; vertical-align:middle" src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" /> + <% end %> + <% if nempty then %><em><%:(empty)%></em><% end %> + </span> + <% end end %> + <% if zempty then %><em><%:(empty)%></em><% end %> + </label> + </li> + <% end end %> - <% if self.widget ~= "checkbox" and not self.nocreate then %> - <li style="padding:0.5em"> - <input class="cbi-input-radio" data-update="click change" type="radio"<%=attr("id", cbid .. "_new") .. attr("name", cbid) .. attr("value", "-") .. ifattr(not selected, "checked", "checked")%> />   - <label<%=attr("for", cbid .. "_new")%>></label> - <div onclick="document.getElementById('<%=cbid%>_new').checked=true" class="zonebadge" style="background-color:<%=fwm.zone.get_color()%>"> - <em><%:unspecified -or- create:%> </em> - <input type="text"<%=attr("name", cbid .. ".newzone") .. ifattr(not selected, "value", luci.http.formvalue(cbid .. ".newzone") or self.default)%> onfocus="document.getElementById('<%=cbid%>_new').checked=true" /> - </div> - </li> - <% end %> -</ul> + <% if self.widget ~= "checkbox" and not self.nocreate then %> + <li style="padding:0.5em"> + <input class="cbi-input-radio" data-update="click change" type="radio"<%=attr("id", cbid .. "_new") .. attr("name", cbid) .. attr("value", "-") .. ifattr(not selected, "checked", "checked")%> />   + <label<%=attr("for", cbid .. "_new")%>></label> + <div onclick="document.getElementById('<%=cbid%>_new').checked=true" class="zonebadge" style="background-color:<%=fwm.zone.get_color()%>"> + <em><%:unspecified -or- create:%> </em> + <input type="text"<%=attr("name", cbid .. ".newzone") .. ifattr(not selected, "value", luci.http.formvalue(cbid .. ".newzone") or self.default)%> onfocus="document.getElementById('<%=cbid%>_new').checked=true" /> + </div> + </li> + <% end %> + </ul> +</span> <%+cbi/valuefooter%> diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua index 2cb2108b9f..33f6a67038 100644 --- a/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua +++ b/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua @@ -258,7 +258,6 @@ function iface_status(ifaces) type = device:type(), ifname = device:name(), macaddr = device:mac(), - macaddr = device:mac(), is_up = device:is_up(), rx_bytes = device:rx_bytes(), tx_bytes = device:tx_bytes(), diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua index 2acda0b73b..66d9942a11 100644 --- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua +++ b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/dhcp.lua @@ -2,6 +2,7 @@ -- Licensed to the public under the Apache License 2.0. local ipc = require "luci.ip" +local sys = require "luci.sys" local o require "luci.util" @@ -311,10 +312,10 @@ end hostid = s:option(Value, "hostid", translate("<abbr title=\"Internet Protocol Version 6\">IPv6</abbr>-Suffix (hex)")) -ipc.neighbors({ family = 4 }, function(n) - if n.mac and n.dest then - ip:value(n.dest:string()) - mac:value(n.mac, "%s (%s)" %{ n.mac, n.dest:string() }) +sys.net.host_hints(function(m, v4, v6, name) + if m and v4 then + ip:value(v4) + mac:value(m, "%s (%s)" %{ m, name or v4 }) end end) diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/hosts.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/hosts.lua index fafacf35c5..46945af58b 100644 --- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/hosts.lua +++ b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/hosts.lua @@ -3,6 +3,7 @@ -- Licensed to the public under the Apache License 2.0. local ipc = require "luci.ip" +local sys = require "luci.sys" m = Map("dhcp", translate("Hostnames")) @@ -19,9 +20,11 @@ ip = s:option(Value, "ip", translate("IP address")) ip.datatype = "ipaddr" ip.rmempty = true -ipc.neighbors({ }, function(n) - if n.mac and n.dest and not n.dest:is6linklocal() then - ip:value(n.dest:string(), "%s (%s)" %{ n.dest:string(), n.mac }) +sys.net.host_hints(function(mac, v4, v6, name) + v6 = v6 and ipc.IPv6(v6) + + if v4 or (v6 and not v6:is6linklocal()) then + ip:value(tostring(v4 or v6), "%s (%s)" %{ tostring(v4 or v6), name or mac }) end end) diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/ifaces.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/ifaces.lua index 4fc71cefab..8e7a3b0667 100644 --- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/ifaces.lua +++ b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/ifaces.lua @@ -16,6 +16,7 @@ local has_firewall = fs.access("/etc/config/firewall") m = Map("network", translate("Interfaces") .. " - " .. arg[1]:upper(), translate("On this page you can configure the network interfaces. You can bridge several interfaces by ticking the \"bridge interfaces\" field and enter the names of several network interfaces separated by spaces. You can also use <abbr title=\"Virtual Local Area Network\">VLAN</abbr> notation <samp>INTERFACE.VLANNR</samp> (<abbr title=\"for example\">e.g.</abbr>: <samp>eth0.1</samp>).")) m.redirect = luci.dispatcher.build_url("admin", "network", "network") m:chain("wireless") +m:chain("luci") if has_firewall then m:chain("firewall") @@ -27,18 +28,52 @@ fw.init(m.uci) local net = nw:get_network(arg[1]) +local function set_ifstate(name, option, value) + local found = false + + m.uci:foreach("luci", "ifstate", function (s) + if s.interface == name then + m.uci:set("luci", s[".name"], option, value) + found = true + return false + end + end) + + if not found then + local sid = m.uci:add("luci", "ifstate") + m.uci:set("luci", sid, "interface", name) + m.uci:set("luci", sid, option, value) + end + + m.uci:save("luci") +end + +local function get_ifstate(name, option) + local val + + m.uci:foreach("luci", "ifstate", function (s) + if s.interface == name then + val = m.uci:get("luci", s[".name"], option) + return false + end + end) + + return val +end + local function backup_ifnames(is_bridge) - if not net:is_floating() and not m:get(net:name(), "_orig_ifname") then + if not net:is_floating() and not get_ifstate(net:name(), "ifname") then local ifcs = net:get_interfaces() or { net:get_interface() } if ifcs then local _, ifn local ifns = { } for _, ifn in ipairs(ifcs) do - ifns[#ifns+1] = ifn:name() + local wif = ifn:get_wifinet() + ifns[#ifns+1] = wif and wif:id() or ifn:name() end if #ifns > 0 then - m:set(net:name(), "_orig_ifname", table.concat(ifns, " ")) - m:set(net:name(), "_orig_bridge", tostring(net:is_bridge())) + set_ifstate(net:name(), "ifname", table.concat(ifns, " ")) + set_ifstate(net:name(), "bridge", tostring(net:is_bridge())) end end end @@ -84,10 +119,10 @@ if m:formvalue("cbid.network.%s._switch" % net:name()) then elseif net:is_floating() and not proto:is_floating() then -- if we have backup data, then re-add all orphaned interfaces -- from it and restore the bridge choice - local br = (m:get(net:name(), "_orig_bridge") == "true") + local br = (get_ifstate(net:name(), "bridge") == "true") local ifn local ifns = { } - for ifn in ut.imatch(m:get(net:name(), "_orig_ifname")) do + for ifn in ut.imatch(get_ifstate(net:name(), "ifname")) do ifn = nw:get_interface(ifn) if ifn and not ifn:get_network() then proto:add_interface(ifn) @@ -114,9 +149,7 @@ if m:formvalue("cbid.network.%s._switch" % net:name()) then for k, v in pairs(m:get(net:name())) do if k:sub(1,1) ~= "." and k ~= "type" and - k ~= "ifname" and - k ~= "_orig_ifname" and - k ~= "_orig_bridge" + k ~= "ifname" then m:del(net:name(), k) end diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm b/modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm index 5f2c074939..f474c71568 100644 --- a/modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm +++ b/modules/luci-mod-admin-full/luasrc/view/admin_status/routes.htm @@ -53,7 +53,7 @@ <tr class="cbi-section-table-row cbi-rowstyle-<%=(style and 1 or 2)%>"> <td class="cbi-value-field"><%=v.dest%></td> <td class="cbi-value-field"><%=v.mac%></td> - <td class="cbi-value-field"><%=v.dev%></td> + <td class="cbi-value-field"><%=luci.tools.webadmin.iface_get_network(v.dev) or '(' .. v.dev .. ')'%></td> </tr> <% style = not style diff --git a/modules/luci-mod-admin-mini/luasrc/model/cbi/mini/dhcp.lua b/modules/luci-mod-admin-mini/luasrc/model/cbi/mini/dhcp.lua index 9a1c1fea45..bcc26cd442 100644 --- a/modules/luci-mod-admin-mini/luasrc/model/cbi/mini/dhcp.lua +++ b/modules/luci-mod-admin-mini/luasrc/model/cbi/mini/dhcp.lua @@ -3,7 +3,7 @@ -- Licensed to the public under the Apache License 2.0. local uci = require "luci.model.uci".cursor() -local ipc = require "luci.ip" +local sys = require "luci.sys" local wa = require "luci.tools.webadmin" local fs = require "nixio.fs" @@ -87,12 +87,11 @@ name = s2:option(Value, "name", translate("Hostname")) mac = s2:option(Value, "mac", translate("<abbr title=\"Media Access Control\">MAC</abbr>-Address")) ip = s2:option(Value, "ip", translate("<abbr title=\"Internet Protocol Version 4\">IPv4</abbr>-Address")) -ipc.neighbors({ family = 4 }, function(n) - if n.mac and n.dest then - ip:value(n.dest:string()) - mac:value(n.mac, "%s (%s)" %{ n.mac, n.dest:string() }) +sys.host_hints(function(m, v4, v6, name) + if m and v4 then + ip:value(v4) + mac:value(m, "%s (%s)" %{ m, name or v4 }) end end) return m - |