1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter-feeds.git synced 2025-03-09 15:40:03 +00:00

Update luci-base and luci-mod-admin-full to latest version, disable nginx default script

This commit is contained in:
Ycarus 2018-03-15 15:27:42 +01:00
parent 7ba8d8d610
commit 139393bc8f
65 changed files with 7053 additions and 5523 deletions

View file

@ -1,4 +1,5 @@
-- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
-- Copyright 2017 Dan Luedtke <mail@danrl.com>
-- Licensed to the public under the Apache License 2.0.
local fs = require "nixio.fs"
@ -131,43 +132,50 @@ function ip6prefix(val)
return ( val and val >= 0 and val <= 128 )
end
function cidr4(val)
local ip, mask = val:match("^([^/]+)/([^/]+)$")
return ip4addr(ip) and ip4prefix(mask)
end
function cidr6(val)
local ip, mask = val:match("^([^/]+)/([^/]+)$")
return ip6addr(ip) and ip6prefix(mask)
end
function ipnet4(val)
local ip, mask = val:match("^([^/]+)/([^/]+)$")
return ip4addr(ip) and ip4addr(mask)
end
function ipnet6(val)
local ip, mask = val:match("^([^/]+)/([^/]+)$")
return ip6addr(ip) and ip6addr(mask)
end
function ipmask(val)
return ipmask4(val) or ipmask6(val)
end
function ipmask4(val)
local ip, mask = val:match("^([^/]+)/([^/]+)$")
local bits = tonumber(mask)
if bits and (bits < 0 or bits > 32) then
return false
end
if not bits and mask and not ip4addr(mask) then
return false
end
return ip4addr(ip or val)
return cidr4(val) or ipnet4(val) or ip4addr(val)
end
function ipmask6(val)
local ip, mask = val:match("^([^/]+)/([^/]+)$")
local bits = tonumber(mask)
if bits and (bits < 0 or bits > 128) then
return false
end
if not bits and mask and not ip6addr(mask) then
return false
end
return ip6addr(ip or val)
return cidr6(val) or ipnet6(val) or ip6addr(val)
end
function ip6hostid(val)
if val and val:match("^[a-fA-F0-9:]+$") and (#val > 2) then
return (ip6addr("2001:db8:0:0" .. val) or ip6addr("2001:db8:0:0:" .. val))
if val == "eui64" or val == "random" then
return true
else
local addr = ip.IPv6(val)
if addr and addr:prefix() == 128 and addr:lower("::1:0:0:0:0") then
return true
end
end
return false
@ -188,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)
@ -301,7 +293,7 @@ function string(val)
return true -- Everything qualifies as valid string
end
function directory( val, seen )
function directory(val, seen)
local s = fs.stat(val)
seen = seen or { }
@ -317,7 +309,7 @@ function directory( val, seen )
return false
end
function file( val, seen )
function file(val, seen)
local s = fs.stat(val)
seen = seen or { }
@ -333,7 +325,7 @@ function file( val, seen )
return false
end
function device( val, seen )
function device(val, seen)
local s = fs.stat(val)
seen = seen or { }
@ -468,4 +460,3 @@ function dateyyyymmdd(val)
end
return false
end

View file

@ -14,8 +14,6 @@ uci = require "luci.model.uci"
i18n = require "luci.i18n"
_M.fs = fs
authenticator = {}
-- Index table
local index = nil
@ -101,24 +99,6 @@ function error500(message)
return false
end
function authenticator.htmlauth(validator, accs, default, template)
local user = http.formvalue("luci_username")
local pass = http.formvalue("luci_password")
if user and validator(user, pass) then
return user
end
require("luci.i18n")
require("luci.template")
context.path = {}
http.status(403, "Forbidden")
luci.template.render(template or "sysauth", {duser=default, fuser=user})
return false
end
function httpdispatch(request, prefix)
http.context.request = request
@ -188,6 +168,53 @@ function test_post_security()
return true
end
local function session_retrieve(sid, allowed_users)
local sdat = util.ubus("session", "get", { ubus_rpc_session = sid })
if type(sdat) == "table" and
type(sdat.values) == "table" and
type(sdat.values.token) == "string" and
(not allowed_users or
util.contains(allowed_users, sdat.values.username))
then
return sid, sdat.values
end
return nil, nil
end
local function session_setup(user, pass, allowed_users)
if util.contains(allowed_users, user) then
local login = util.ubus("session", "login", {
username = user,
password = pass,
timeout = tonumber(luci.config.sauth.sessiontime)
})
local rp = context.requestpath
and table.concat(context.requestpath, "/") or ""
if type(login) == "table" and
type(login.ubus_rpc_session) == "string"
then
util.ubus("session", "set", {
ubus_rpc_session = login.ubus_rpc_session,
values = { token = sys.uniqueid(16) }
})
io.stderr:write("luci: accepted login on /%s for %s from %s\n"
%{ rp, user, http.getenv("REMOTE_ADDR") or "?" })
return session_retrieve(login.ubus_rpc_session)
end
io.stderr:write("luci: failed login on /%s for %s from %s\n"
%{ rp, user, http.getenv("REMOTE_ADDR") or "?" })
end
return nil, nil
end
function dispatch(request)
--context._disable_memtrace = require "luci.debug".trap_memtrace("l")
local ctx = context
@ -201,10 +228,19 @@ function dispatch(request)
local lang = conf.main.lang or "auto"
if lang == "auto" then
local aclang = http.getenv("HTTP_ACCEPT_LANGUAGE") or ""
for lpat in aclang:gmatch("[%w-]+") do
lpat = lpat and lpat:gsub("-", "_")
if conf.languages[lpat] then
lang = lpat
for aclang in aclang:gmatch("[%w_-]+") do
local country, culture = aclang:match("^([a-z][a-z])[_-]([a-zA-Z][a-zA-Z])$")
if country and culture then
local cc = "%s_%s" %{ country, culture:lower() }
if conf.languages[cc] then
lang = cc
break
elseif conf.languages[country] then
lang = country
break
end
elseif conf.languages[aclang] then
lang = aclang
break
end
end
@ -331,75 +367,66 @@ function dispatch(request)
"https://github.com/openwrt/luci/issues"
)
if track.sysauth then
local authen = type(track.sysauth_authenticator) == "function"
and track.sysauth_authenticator
or authenticator[track.sysauth_authenticator]
if track.sysauth and not ctx.authsession then
local authen = track.sysauth_authenticator
local _, sid, sdat, default_user, allowed_users
local def = (type(track.sysauth) == "string") and track.sysauth
local accs = def and {track.sysauth} or track.sysauth
local sess = ctx.authsession
if not sess then
sess = http.getcookie("sysauth")
sess = sess and sess:match("^[a-f0-9]*$")
if type(authen) == "string" and authen ~= "htmlauth" then
error500("Unsupported authenticator %q configured" % authen)
return
end
local sdat = (util.ubus("session", "get", { ubus_rpc_session = sess }) or { }).values
local user, token
if sdat then
user = sdat.user
token = sdat.token
if type(track.sysauth) == "table" then
default_user, allowed_users = nil, track.sysauth
else
local eu = http.getenv("HTTP_AUTH_USER")
local ep = http.getenv("HTTP_AUTH_PASS")
if eu and ep and sys.user.checkpasswd(eu, ep) then
authen = function() return eu end
end
default_user, allowed_users = track.sysauth, { track.sysauth }
end
if not util.contains(accs, user) then
if authen then
local user, sess = authen(sys.user.checkpasswd, accs, def, track.sysauth_template)
local token
if not user or not util.contains(accs, user) then
return
else
if not sess then
local sdat = util.ubus("session", "create", { timeout = tonumber(luci.config.sauth.sessiontime) })
if sdat then
token = sys.uniqueid(16)
util.ubus("session", "set", {
ubus_rpc_session = sdat.ubus_rpc_session,
values = {
user = user,
token = token,
section = sys.uniqueid(16)
}
})
sess = sdat.ubus_rpc_session
end
end
if type(authen) == "function" then
_, sid = authen(sys.user.checkpasswd, allowed_users)
else
sid = http.getcookie("sysauth")
end
if sess and token then
http.header("Set-Cookie", 'sysauth=%s; path=%s' %{ sess, build_url() })
sid, sdat = session_retrieve(sid, allowed_users)
ctx.authsession = sess
ctx.authtoken = token
ctx.authuser = user
if not (sid and sdat) and authen == "htmlauth" then
local user = http.getenv("HTTP_AUTH_USER")
local pass = http.getenv("HTTP_AUTH_PASS")
if user == nil and pass == nil then
user = http.formvalue("luci_username")
pass = http.formvalue("luci_password")
end
sid, sdat = session_setup(user, pass, allowed_users)
if not sid then
local tmpl = require "luci.template"
context.path = {}
http.redirect(build_url(unpack(ctx.requestpath)))
end
end
else
http.status(403, "Forbidden")
tmpl.render(track.sysauth_template or "sysauth", {
duser = default_user,
fuser = user
})
return
end
else
ctx.authsession = sess
ctx.authtoken = token
ctx.authuser = user
http.header("Set-Cookie", 'sysauth=%s; path=%s' %{ sid, build_url() })
http.redirect(build_url(unpack(ctx.requestpath)))
end
if not sid or not sdat then
http.status(403, "Forbidden")
return
end
ctx.authsession = sid
ctx.authtoken = sdat.token
ctx.authuser = sdat.username
end
if c and require_post_security(c.target) then

View file

@ -224,7 +224,15 @@ function write(content, src_err)
header("Cache-Control", "no-cache")
header("Expires", "0")
end
if not context.headers["x-frame-options"] then
header("X-Frame-Options", "SAMEORIGIN")
end
if not context.headers["x-xss-protection"] then
header("X-XSS-Protection", "1; mode=block")
end
if not context.headers["x-content-type-options"] then
header("X-Content-Type-Options", "nosniff")
end
context.eoh = true
coroutine.yield(3)

View file

@ -264,7 +264,7 @@ function header_source( sock )
end
-- 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
@ -433,7 +433,7 @@ function mimedecode_message_body( src, msg, filecb )
end
-- 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.
function urldecode_message_body( src, msg )

View file

@ -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

View file

@ -498,11 +498,13 @@ function forwarding.dest(self)
end
function forwarding.src_zone(self)
return zone(self:src())
local z = zone(self:src())
return z.sid and z
end
function forwarding.dest_zone(self)
return zone(self:dest())
local z = zone(self:dest())
return z.sid and z
end

View file

@ -6,14 +6,12 @@ local type, next, pairs, ipairs, loadfile, table, select
local tonumber, tostring, math = tonumber, tostring, math
local require = require
local pcall, require, setmetatable = pcall, require, setmetatable
local nxo = require "nixio"
local nfs = require "nixio.fs"
local ipc = require "luci.ip"
local sys = require "luci.sys"
local utl = require "luci.util"
local dsp = require "luci.dispatcher"
local uci = require "luci.model.uci"
local lng = require "luci.i18n"
local jsc = require "luci.jsonc"
@ -108,6 +106,58 @@ function _set(c, s, o, v)
end
end
local function _wifi_state()
if not next(_ubuswificache) then
_ubuswificache = utl.ubus("network.wireless", "status", {}) or {}
end
return _ubuswificache
end
local function _wifi_state_by_sid(sid)
local t1, n1 = _uci:get("wireless", sid)
if t1 == "wifi-iface" and n1 ~= nil then
local radioname, radiostate
for radioname, radiostate in pairs(_wifi_state()) do
if type(radiostate) == "table" and
type(radiostate.interfaces) == "table"
then
local netidx, netstate
for netidx, netstate in ipairs(radiostate.interfaces) do
if type(netstate) == "table" and
type(netstate.section) == "string"
then
local t2, n2 = _uci:get("wireless", netstate.section)
if t1 == t2 and n1 == n2 then
return radioname, radiostate, netstate
end
end
end
end
end
end
end
local function _wifi_state_by_ifname(ifname)
if type(ifname) == "string" then
local radioname, radiostate
for radioname, radiostate in pairs(_wifi_state()) do
if type(radiostate) == "table" and
type(radiostate.interfaces) == "table"
then
local netidx, netstate
for netidx, netstate in ipairs(radiostate.interfaces) do
if type(netstate) == "table" and
type(netstate.ifname) == "string" and
netstate.ifname == ifname
then
return radioname, radiostate, netstate
end
end
end
end
end
end
function _wifi_iface(x)
local _, p
for _, p in ipairs(IFACE_PATTERNS_WIRELESS) do
@ -118,59 +168,111 @@ function _wifi_iface(x)
return false
end
function _wifi_state(key, val, field)
local radio, radiostate, ifc, ifcstate
local function _wifi_iwinfo_by_ifname(ifname, force_phy_only)
local stat, iwinfo = pcall(require, "iwinfo")
local iwtype = stat and type(ifname) == "string" and iwinfo.type(ifname)
local is_nonphy_op = {
bitrate = true,
quality = true,
quality_max = true,
mode = true,
ssid = true,
bssid = true,
assoclist = true,
encryption = true
}
if not next(_ubuswificache) then
_ubuswificache = utl.ubus("network.wireless", "status", {}) or {}
if iwtype then
-- if we got a type but no real netdev, we're referring to a phy
local phy_only = force_phy_only or (ipc.link(ifname).type ~= 1)
-- workaround extended section format
for radio, radiostate in pairs(_ubuswificache) do
for ifc, ifcstate in pairs(radiostate.interfaces) do
if ifcstate.section and ifcstate.section:sub(1, 1) == '@' then
local s = _uci:get_all('wireless.%s' % ifcstate.section)
if s then
ifcstate.section = s['.name']
end
return setmetatable({}, {
__index = function(t, k)
if k == "ifname" then
return ifname
elseif phy_only and is_nonphy_op[k] then
return nil
elseif iwinfo[iwtype][k] then
return iwinfo[iwtype][k](ifname)
end
end
end
})
end
end
for radio, radiostate in pairs(_ubuswificache) do
for ifc, ifcstate in pairs(radiostate.interfaces) do
if ifcstate[key] == val then
return ifcstate[field]
end
local function _wifi_sid_by_netid(netid)
if type(netid) == "string" then
local radioname, netidx = netid:match("^(%w+)%.network(%d+)$")
if radioname and netidx then
local i, n = 0, nil
netidx = tonumber(netidx)
_uci:foreach("wireless", "wifi-iface",
function(s)
if s.device == radioname then
i = i + 1
if i == netidx then
n = s[".name"]
return false
end
end
end)
return n
end
end
end
function _wifi_lookup(ifn)
-- got a radio#.network# pseudo iface, locate the corresponding section
local radio, ifnidx = ifn:match("^(%w+)%.network(%d+)$")
if radio and ifnidx then
local sid = nil
local num = 0
ifnidx = tonumber(ifnidx)
_uci:foreach("wireless", "wifi-iface",
function(s)
if s.device == radio then
num = num + 1
if num == ifnidx then
sid = s['.name']
return false
end
end
end)
function _wifi_sid_by_ifname(ifn)
local sid = _wifi_sid_by_netid(ifn)
if sid then
return sid
-- looks like wifi, try to locate the section via ubus state
elseif _wifi_iface(ifn) then
return _wifi_state("ifname", ifn, "section")
end
local _, _, netstate = _wifi_state_by_ifname(ifn)
if netstate and type(netstate.section) == "string" then
return netstate.section
end
end
local function _wifi_netid_by_sid(sid)
local t, n = _uci:get("wireless", sid)
if t == "wifi-iface" and n ~= nil then
local radioname = _uci:get("wireless", n, "device")
if type(radioname) == "string" then
local i, netid = 0, nil
_uci:foreach("wireless", "wifi-iface",
function(s)
if s.device == radioname then
i = i + 1
if s[".name"] == n then
netid = "%s.network%d" %{ radioname, i }
return false
end
end
end)
return netid, radioname
end
end
end
local function _wifi_netid_by_netname(name)
local netid = nil
_uci:foreach("wireless", "wifi-iface",
function(s)
local net
for net in utl.imatch(s.network) do
if net == name then
netid = _wifi_netid_by_sid(s[".name"])
return false
end
end
end)
return netid
end
function _iface_virtual(x)
@ -228,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
@ -441,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)
@ -524,20 +629,8 @@ function get_interface(self, i)
if _interfaces[i] or _wifi_iface(i) then
return interface(i)
else
local ifc
local num = { }
_uci:foreach("wireless", "wifi-iface",
function(s)
if s.device then
num[s.device] = num[s.device] and num[s.device] + 1 or 1
if s['.name'] == i then
ifc = interface(
"%s.network%d" %{s.device, num[s.device] })
return false
end
end
end)
return ifc
local netid = _wifi_netid_by_netname(i)
return netid and interface(netid)
end
end
@ -644,7 +737,7 @@ function get_wifidevs(self)
end
function get_wifinet(self, net)
local wnet = _wifi_lookup(net)
local wnet = _wifi_sid_by_ifname(net)
if wnet then
return wifinet(wnet)
end
@ -660,7 +753,7 @@ function add_wifinet(self, net, options)
end
function del_wifinet(self, net)
local wnet = _wifi_lookup(net)
local wnet = _wifi_sid_by_ifname(net)
if wnet then
_uci:delete("wireless", wnet)
return true
@ -784,22 +877,7 @@ function protocol.ifname(self)
ifname = self:_ubus("device")
end
if not ifname then
local num = { }
_uci:foreach("wireless", "wifi-iface",
function(s)
if s.device then
num[s.device] = num[s.device]
and num[s.device] + 1 or 1
local net
for net in utl.imatch(s.network) do
if net == self.sid then
ifname = "%s.network%d" %{ s.device, num[s.device] }
return false
end
end
end
end)
ifname = _wifi_netid_by_netname(self.sid)
end
return ifname
end
@ -923,7 +1001,15 @@ function protocol.ip6addrs(self)
if type(addrs) == "table" then
for n, addr in ipairs(addrs) do
rv[#rv+1] = "%s1/%d" %{ addr.address, addr.mask }
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
}
end
end
end
@ -981,24 +1067,17 @@ function protocol.is_empty(self)
if self:is_floating() then
return false
else
local rv = true
local empty = true
if (self:_get("ifname") or ""):match("%S+") then
rv = false
empty = false
end
_uci:foreach("wireless", "wifi-iface",
function(s)
local n
for n in utl.imatch(s.network) do
if n == self.sid then
rv = false
return false
end
end
end)
if empty and _wifi_netid_by_netname(self.sid) then
empty = false
end
return rv
return empty
end
end
@ -1006,7 +1085,7 @@ function protocol.add_interface(self, ifname)
ifname = _M:ifnameof(ifname)
if ifname and not self:is_floating() then
-- if its a wifi interface, change its network option
local wif = _wifi_lookup(ifname)
local wif = _wifi_sid_by_ifname(ifname)
if wif then
_append("wireless", wif, "network", self.sid)
@ -1021,7 +1100,7 @@ function protocol.del_interface(self, ifname)
ifname = _M:ifnameof(ifname)
if ifname and not self:is_floating() then
-- if its a wireless interface, clear its network option
local wif = _wifi_lookup(ifname)
local wif = _wifi_sid_by_ifname(ifname)
if wif then _filter("wireless", wif, "network", self.sid) end
-- remove the interface
@ -1043,21 +1122,7 @@ function protocol.get_interface(self)
ifn = ifn:match("^[^:/]+")
return ifn and interface(ifn, self)
end
ifn = nil
_uci:foreach("wireless", "wifi-iface",
function(s)
if s.device then
num[s.device] = num[s.device] and num[s.device] + 1 or 1
local net
for net in utl.imatch(s.network) do
if net == self.sid then
ifn = "%s.network%d" %{ s.device, num[s.device] }
return false
end
end
end
end)
ifn = _wifi_netid_by_netname(self.sid)
return ifn and interface(ifn, self)
end
end
@ -1077,18 +1142,17 @@ function protocol.get_interfaces(self)
ifaces[#ifaces+1] = nfs[ifn]
end
local num = { }
local wfs = { }
_uci:foreach("wireless", "wifi-iface",
function(s)
if s.device then
num[s.device] = num[s.device] and num[s.device] + 1 or 1
local net
for net in utl.imatch(s.network) do
if net == self.sid then
ifn = "%s.network%d" %{ s.device, num[s.device] }
wfs[ifn] = interface(ifn, self)
ifn = _wifi_netid_by_sid(s[".name"])
if ifn then
wfs[ifn] = interface(ifn, self)
end
end
end
end
@ -1119,7 +1183,7 @@ function protocol.contains_interface(self, ifname)
end
end
local wif = _wifi_lookup(ifname)
local wif = _wifi_sid_by_ifname(ifname)
if wif then
local n
for n in utl.imatch(_uci:get("wireless", wif, "network")) do
@ -1134,17 +1198,18 @@ function protocol.contains_interface(self, ifname)
end
function protocol.adminlink(self)
return dsp.build_url("admin", "network", "network", self.sid)
local stat, dsp = pcall(require, "luci.dispatcher")
return stat and dsp.build_url("admin", "network", "network", self.sid)
end
interface = utl.class()
function interface.__init__(self, ifname, network)
local wif = _wifi_lookup(ifname)
local wif = _wifi_sid_by_ifname(ifname)
if wif then
self.wif = wifinet(wif)
self.ifname = _wifi_state("section", wif, "ifname")
self.ifname = self.wif:ifname()
end
self.ifname = self.ifname or ifname
@ -1168,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)
@ -1332,9 +1396,14 @@ end
wifidev = utl.class()
function wifidev.__init__(self, dev)
self.sid = dev
self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
function wifidev.__init__(self, name)
local t, n = _uci:get("wireless", name)
if t == "wifi-device" and n ~= nil then
self.sid = n
self.iwinfo = _wifi_iwinfo_by_ifname(self.sid, true)
end
self.sid = self.sid or name
self.iwinfo = self.iwinfo or { ifname = self.sid }
end
function wifidev.get(self, opt)
@ -1362,8 +1431,6 @@ function wifidev.get_i18n(self)
local t = "Generic"
if self.iwinfo.type == "wl" then
t = "Broadcom"
elseif self.iwinfo.type == "madwifi" then
t = "Atheros"
end
local m = ""
@ -1389,7 +1456,7 @@ function wifidev.get_wifinet(self, net)
if _uci:get("wireless", net) == "wifi-iface" then
return wifinet(net)
else
local wnet = _wifi_lookup(net)
local wnet = _wifi_sid_by_ifname(net)
if wnet then
return wifinet(wnet)
end
@ -1423,7 +1490,7 @@ function wifidev.del_wifinet(self, net)
if utl.instanceof(net, wifinet) then
net = net.sid
elseif _uci:get("wireless", net) ~= "wifi-iface" then
net = _wifi_lookup(net)
net = _wifi_sid_by_ifname(net)
end
if net and _uci:get("wireless", net, "device") == self.sid then
@ -1437,49 +1504,50 @@ end
wifinet = utl.class()
function wifinet.__init__(self, net, data)
self.sid = net
local n = 0
local num = { }
local netid, sid
_uci:foreach("wireless", "wifi-iface",
function(s)
n = n + 1
if s.device then
num[s.device] = num[s.device] and num[s.device] + 1 or 1
if s['.name'] == self.sid then
sid = "@wifi-iface[%d]" % n
netid = "%s.network%d" %{ s.device, num[s.device] }
return false
end
end
end)
function wifinet.__init__(self, name, data)
local sid, netid, radioname, radiostate, netstate
-- lookup state by radio#.network# notation
sid = _wifi_sid_by_netid(name)
if sid then
local _, k, r, i
for k, r in pairs(_ubuswificache) do
if type(r) == "table" and
type(r.interfaces) == "table"
then
for _, i in ipairs(r.interfaces) do
if type(i) == "table" and i.section == sid then
self._ubusdata = {
radio = k,
dev = r,
net = i
}
end
netid = name
radioname, radiostate, netstate = _wifi_state_by_sid(sid)
else
-- lookup state by ifname (e.g. wlan0)
radioname, radiostate, netstate = _wifi_state_by_ifname(name)
if radioname and radiostate and netstate then
sid = netstate.section
netid = _wifi_netid_by_sid(sid)
else
-- lookup state by uci section id (e.g. cfg053579)
radioname, radiostate, netstate = _wifi_state_by_sid(name)
if radioname and radiostate and netstate then
sid = name
netid = _wifi_netid_by_sid(sid)
else
-- no state available, try to resolve from uci
netid, radioname = _wifi_netid_by_sid(name)
if netid and radioname then
sid = name
end
end
end
end
local dev = _wifi_state("section", self.sid, "ifname") or netid
local iwinfo =
(netstate and _wifi_iwinfo_by_ifname(netstate.ifname)) or
(radioname and _wifi_iwinfo_by_ifname(radioname)) or
{ ifname = (netid or sid or name) }
self.netid = netid
self.wdev = dev
self.iwinfo = dev and sys.wifi.getiwinfo(dev) or { }
self.sid = sid or name
self.wdev = iwinfo.ifname
self.iwinfo = iwinfo
self.netid = netid
self._ubusdata = {
radio = radioname,
dev = radiostate,
net = netstate
}
end
function wifinet.ubus(self, ...)
@ -1666,7 +1734,8 @@ function wifinet.get_i18n(self)
end
function wifinet.adminlink(self)
return dsp.build_url("admin", "network", "wireless", self.netid)
local stat, dsp = pcall(require, "luci.dispatcher")
return dsp and dsp.build_url("admin", "network", "wireless", self.netid)
end
function wifinet.get_network(self)

View file

@ -7,6 +7,7 @@ local table = require "table"
local nixio = require "nixio"
local fs = require "nixio.fs"
local uci = require "luci.model.uci"
local ntm = require "luci.model.network"
local luci = {}
luci.util = require "luci.util"
@ -117,45 +118,12 @@ end
net = {}
-- The following fields are defined for arp entry objects:
-- { "IP address", "HW address", "HW type", "Flags", "Mask", "Device" }
function net.arptable(callback)
local arp = (not callback) and {} or nil
local e, r, v
if fs.access("/proc/net/arp") then
for e in io.lines("/proc/net/arp") do
local r = { }, v
for v in e:gmatch("%S+") do
r[#r+1] = v
end
if r[1] ~= "IP" then
local x = {
["IP address"] = r[1],
["HW type"] = r[2],
["Flags"] = r[3],
["HW address"] = r[4],
["Mask"] = r[5],
["Device"] = r[6]
}
if callback then
callback(x)
else
arp = arp or { }
arp[#arp+1] = x
end
end
end
end
return arp
end
local function _nethints(what, callback)
local _, k, e, mac, ip, name
local cur = uci.cursor()
local ifn = { }
local hosts = { }
local lookup = { }
local function _add(i, ...)
local k = select(i, ...)
@ -178,9 +146,14 @@ local function _nethints(what, callback)
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
@ -190,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
@ -201,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)
@ -224,8 +201,20 @@ local function _nethints(what, callback)
end
end
for _, e in pairs(hosts) do
lookup[#lookup+1] = (what > 1) and e[what] or (e[2] or e[3])
end
if #lookup > 0 then
lookup = luci.util.ubus("network.rrdns", "lookup", {
addrs = lookup,
timeout = 250,
limit = 1000
}) or { }
end
for _, e in luci.util.kspairs(hosts) do
callback(e[1], e[2], e[3], e[4])
callback(e[1], e[2], e[3], lookup[e[2]] or lookup[e[3]] or e[4])
end
end
@ -234,17 +223,17 @@ end
function net.mac_hints(callback)
if callback then
_nethints(1, function(mac, v4, v6, name)
name = name or nixio.getnameinfo(v4 or v6, nil, 100) or v4
name = name or v4
if name and name ~= mac then
callback(mac, name or nixio.getnameinfo(v4 or v6, nil, 100) or v4)
callback(mac, name or v4)
end
end)
else
local rv = { }
_nethints(1, function(mac, v4, v6, name)
name = name or nixio.getnameinfo(v4 or v6, nil, 100) or v4
name = name or v4
if name and name ~= mac then
rv[#rv+1] = { mac, name or nixio.getnameinfo(v4 or v6, nil, 100) or v4 }
rv[#rv+1] = { mac, name or v4 }
end
end)
return rv
@ -256,7 +245,7 @@ end
function net.ipv4_hints(callback)
if callback then
_nethints(2, function(mac, v4, v6, name)
name = name or nixio.getnameinfo(v4, nil, 100) or mac
name = name or mac
if name and name ~= v4 then
callback(v4, name)
end
@ -264,7 +253,7 @@ function net.ipv4_hints(callback)
else
local rv = { }
_nethints(2, function(mac, v4, v6, name)
name = name or nixio.getnameinfo(v4, nil, 100) or mac
name = name or mac
if name and name ~= v4 then
rv[#rv+1] = { v4, name }
end
@ -278,7 +267,7 @@ end
function net.ipv6_hints(callback)
if callback then
_nethints(3, function(mac, v4, v6, name)
name = name or nixio.getnameinfo(v6, nil, 100) or mac
name = name or mac
if name and name ~= v6 then
callback(v6, name)
end
@ -286,7 +275,7 @@ function net.ipv6_hints(callback)
else
local rv = { }
_nethints(3, function(mac, v4, v6, name)
name = name or nixio.getnameinfo(v6, nil, 100) or mac
name = name or mac
if name and name ~= v6 then
rv[#rv+1] = { v6, name }
end
@ -369,8 +358,10 @@ end
function net.devices()
local devs = {}
local seen = {}
for k, v in ipairs(nixio.getifaddrs()) do
if v.family == "packet" then
if v.name and not seen[v.name] then
seen[v.name] = true
devs[#devs+1] = v.name
end
end
@ -378,145 +369,6 @@ function net.devices()
end
function net.deviceinfo()
local devs = {}
for k, v in ipairs(nixio.getifaddrs()) do
if v.family == "packet" then
local d = v.data
d[1] = d.rx_bytes
d[2] = d.rx_packets
d[3] = d.rx_errors
d[4] = d.rx_dropped
d[5] = 0
d[6] = 0
d[7] = 0
d[8] = d.multicast
d[9] = d.tx_bytes
d[10] = d.tx_packets
d[11] = d.tx_errors
d[12] = d.tx_dropped
d[13] = 0
d[14] = d.collisions
d[15] = 0
d[16] = 0
devs[v.name] = d
end
end
return devs
end
-- The following fields are defined for route entry tables:
-- { "dest", "gateway", "metric", "refcount", "usecount", "irtt",
-- "flags", "device" }
function net.routes(callback)
local routes = { }
for line in io.lines("/proc/net/route") do
local dev, dst_ip, gateway, flags, refcnt, usecnt, metric,
dst_mask, mtu, win, irtt = line:match(
"([^%s]+)\t([A-F0-9]+)\t([A-F0-9]+)\t([A-F0-9]+)\t" ..
"(%d+)\t(%d+)\t(%d+)\t([A-F0-9]+)\t(%d+)\t(%d+)\t(%d+)"
)
if dev then
gateway = luci.ip.Hex( gateway, 32, luci.ip.FAMILY_INET4 )
dst_mask = luci.ip.Hex( dst_mask, 32, luci.ip.FAMILY_INET4 )
dst_ip = luci.ip.Hex(
dst_ip, dst_mask:prefix(dst_mask), luci.ip.FAMILY_INET4
)
local rt = {
dest = dst_ip,
gateway = gateway,
metric = tonumber(metric),
refcount = tonumber(refcnt),
usecount = tonumber(usecnt),
mtu = tonumber(mtu),
window = tonumber(window),
irtt = tonumber(irtt),
flags = tonumber(flags, 16),
device = dev
}
if callback then
callback(rt)
else
routes[#routes+1] = rt
end
end
end
return routes
end
-- The following fields are defined for route entry tables:
-- { "source", "dest", "nexthop", "metric", "refcount", "usecount",
-- "flags", "device" }
function net.routes6(callback)
if fs.access("/proc/net/ipv6_route", "r") then
local routes = { }
for line in io.lines("/proc/net/ipv6_route") do
local dst_ip, dst_prefix, src_ip, src_prefix, nexthop,
metric, refcnt, usecnt, flags, dev = line:match(
"([a-f0-9]+) ([a-f0-9]+) " ..
"([a-f0-9]+) ([a-f0-9]+) " ..
"([a-f0-9]+) ([a-f0-9]+) " ..
"([a-f0-9]+) ([a-f0-9]+) " ..
"([a-f0-9]+) +([^%s]+)"
)
if dst_ip and dst_prefix and
src_ip and src_prefix and
nexthop and metric and
refcnt and usecnt and
flags and dev
then
src_ip = luci.ip.Hex(
src_ip, tonumber(src_prefix, 16), luci.ip.FAMILY_INET6, false
)
dst_ip = luci.ip.Hex(
dst_ip, tonumber(dst_prefix, 16), luci.ip.FAMILY_INET6, false
)
nexthop = luci.ip.Hex( nexthop, 128, luci.ip.FAMILY_INET6, false )
local rt = {
source = src_ip,
dest = dst_ip,
nexthop = nexthop,
metric = tonumber(metric, 16),
refcount = tonumber(refcnt, 16),
usecount = tonumber(usecnt, 16),
flags = tonumber(flags, 16),
device = dev,
-- lua number is too small for storing the metric
-- add a metric_raw field with the original content
metric_raw = metric
}
if callback then
callback(rt)
else
routes[#routes+1] = rt
end
end
end
return routes
end
end
function net.pingtest(host)
return os.execute("ping -c1 '"..host:gsub("'", '').."' >/dev/null 2>&1")
end
process = {}
function process.info(key)
@ -609,37 +461,19 @@ end
wifi = {}
function wifi.getiwinfo(ifname)
local stat, iwinfo = pcall(require, "iwinfo")
ntm.init()
if ifname then
local d, n = ifname:match("^(%w+)%.network(%d+)")
local wstate = luci.util.ubus("network.wireless", "status") or { }
d = d or ifname
n = n and tonumber(n) or 1
if type(wstate[d]) == "table" and
type(wstate[d].interfaces) == "table" and
type(wstate[d].interfaces[n]) == "table" and
type(wstate[d].interfaces[n].ifname) == "string"
then
ifname = wstate[d].interfaces[n].ifname
else
ifname = d
end
local t = stat and iwinfo.type(ifname)
local x = t and iwinfo[t] or { }
return setmetatable({}, {
__index = function(t, k)
if k == "ifname" then
return ifname
elseif x[k] then
return x[k](ifname)
end
end
})
local wnet = ntm:get_wifinet(ifname)
if wnet and wnet.iwinfo then
return wnet.iwinfo
end
local wdev = ntm:get_wifidev(ifname)
if wdev and wdev.iwinfo then
return wdev.iwinfo
end
return { ifname = ifname }
end

View file

@ -51,7 +51,7 @@ TZ = {
{ 'Africa/Nouakchott', 'GMT0' },
{ 'Africa/Ouagadougou', 'GMT0' },
{ 'Africa/Porto-Novo', 'WAT-1' },
{ 'Africa/Sao Tome', 'GMT0' },
{ 'Africa/Sao Tome', 'WAT-1' },
{ 'Africa/Tripoli', 'EET-2' },
{ 'Africa/Tunis', 'CET-1' },
{ 'Africa/Windhoek', 'CAT-2' },
@ -85,7 +85,7 @@ TZ = {
{ 'America/Bogota', '<-05>5' },
{ 'America/Boise', 'MST7MDT,M3.2.0,M11.1.0' },
{ 'America/Cambridge Bay', 'MST7MDT,M3.2.0,M11.1.0' },
{ 'America/Campo Grande', '<-04>4<-03>,M10.3.0/0,M2.3.0/0' },
{ 'America/Campo Grande', '<-04>4<-03>,M11.1.0/0,M2.3.0/0' },
{ 'America/Cancun', 'EST5' },
{ 'America/Caracas', '<-04>4' },
{ 'America/Cayenne', '<-03>3' },
@ -94,7 +94,7 @@ TZ = {
{ 'America/Chihuahua', 'MST7MDT,M4.1.0,M10.5.0' },
{ 'America/Costa Rica', 'CST6' },
{ 'America/Creston', 'MST7' },
{ 'America/Cuiaba', '<-04>4<-03>,M10.3.0/0,M2.3.0/0' },
{ 'America/Cuiaba', '<-04>4<-03>,M11.1.0/0,M2.3.0/0' },
{ 'America/Curacao', 'AST4' },
{ 'America/Danmarkshavn', 'GMT0' },
{ 'America/Dawson', 'PST8PDT,M3.2.0,M11.1.0' },
@ -181,7 +181,7 @@ TZ = {
{ 'America/Santarem', '<-03>3' },
{ 'America/Santiago', '<-04>4<-03>,M8.2.6/24,M5.2.6/24' },
{ 'America/Santo Domingo', 'AST4' },
{ 'America/Sao Paulo', '<-03>3<-02>,M10.3.0/0,M2.3.0/0' },
{ 'America/Sao Paulo', '<-03>3<-02>,M11.1.0/0,M2.3.0/0' },
{ 'America/Scoresbysund', '<-01>1<+00>,M3.5.0/0,M10.5.0/1' },
{ 'America/Sitka', 'AKST9AKDT,M3.2.0,M11.1.0' },
{ 'America/St Barthelemy', 'AST4' },

View file

@ -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
}

View file

@ -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
]]
---[[

View file

@ -43,11 +43,12 @@
&#160;&#8658;&#160;
<% for _, fwd in ipairs(zone:get_forwardings_by("src")) do
fz = fwd:dest_zone()
empty = false %>
if fz then
empty = false %>
<label class="zonebadge" style="background-color:<%=fz:get_color()%>">
<strong><%=fz:name()%></strong>
</label>&#160;
<% end %>
<% end end %>
<% if empty then %>
<label class="zonebadge zonebadge-empty">
<strong><%=zone:forward():upper()%></strong>

View file

@ -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")%> /> &#160;
<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")%> /> &#160;
<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")%> /> &#160;
<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")%> /> &#160;
<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")%> /> &#160;
<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")%> /> &#160;
<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")%> /> &#160;
<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:%>&#160;</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")%> /> &#160;
<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:%>&#160;</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%>