Implement luci.upnp ubus app. Convert lua page to js client side implementation. Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
155 lines
No EOL
3.6 KiB
Lua
Executable file
155 lines
No EOL
3.6 KiB
Lua
Executable file
#!/usr/bin/env lua
|
|
|
|
local json = require "luci.jsonc"
|
|
local UCI = require "luci.model.uci"
|
|
local fs = require "nixio.fs"
|
|
local sys = require "luci.sys"
|
|
|
|
local methods = {
|
|
get_status = {
|
|
call = function()
|
|
local uci = UCI.cursor()
|
|
local lease_file = uci:get("upnpd", "config", "upnp_lease_file")
|
|
|
|
local ipv4_hints = sys.net.ipv4_hints()
|
|
local rule = { }
|
|
|
|
local ipt = io.popen("iptables --line-numbers -t nat -xnvL MINIUPNPD 2>/dev/null")
|
|
if ipt then
|
|
local upnpf = lease_file and io.open(lease_file, "r")
|
|
while true do
|
|
local ln = ipt:read("*l")
|
|
if not ln then
|
|
break
|
|
elseif ln:match("^%d+") then
|
|
local num, proto, extport, intaddr, intport =
|
|
ln:match("^(%d+).-([a-z]+).-dpt:(%d+) to:(%S-):(%d+)")
|
|
local descr = ""
|
|
|
|
if num and proto and extport and intaddr and intport then
|
|
extport = tonumber(extport)
|
|
intport = tonumber(intport)
|
|
|
|
if upnpf then
|
|
local uln = upnpf:read("*l")
|
|
if uln then descr = uln:match(string.format("^%s:%d:%s:%d:%%d*:(.*)$", proto:upper(), extport, intaddr, intport)) end
|
|
if not descr then descr = "" end
|
|
end
|
|
|
|
local host_hint, _, e
|
|
|
|
for _,e in pairs(ipv4_hints) do
|
|
if e[1] == intaddr then
|
|
host_hint = e[2]
|
|
break
|
|
end
|
|
end
|
|
|
|
rule[#rule+1] = {
|
|
num = num,
|
|
proto = proto:upper(),
|
|
extport = extport,
|
|
intaddr = intaddr,
|
|
host_hint = host_hint,
|
|
intport = intport,
|
|
descr = descr
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
if upnpf then upnpf:close() end
|
|
ipt:close()
|
|
end
|
|
|
|
return { rules = rule }
|
|
end
|
|
},
|
|
delete_rule = {
|
|
args = { token = "token" },
|
|
call = function(args)
|
|
local util = require "luci.util"
|
|
local idx = args and tonumber(args.token)
|
|
local res = {}
|
|
|
|
if idx and idx > 0 then
|
|
local uci = UCI.cursor()
|
|
|
|
sys.call("iptables -t filter -D MINIUPNPD %d 2>/dev/null" % idx)
|
|
sys.call("iptables -t nat -D MINIUPNPD %d 2>/dev/null" % idx)
|
|
|
|
local lease_file = uci:get("upnpd", "config", "upnp_lease_file")
|
|
if lease_file and fs.access(lease_file) then
|
|
sys.call("sed -i -e '%dd' %s" %{ idx, util.shellquote(lease_file) })
|
|
end
|
|
|
|
uci.unload()
|
|
|
|
return { result = "OK" }
|
|
end
|
|
|
|
return { result = "Bad request" }
|
|
end
|
|
}
|
|
}
|
|
|
|
local function parseInput()
|
|
local parse = json.new()
|
|
local done, err
|
|
|
|
while true do
|
|
local chunk = io.read(4096)
|
|
if not chunk then
|
|
break
|
|
elseif not done and not err then
|
|
done, err = parse:parse(chunk)
|
|
end
|
|
end
|
|
|
|
if not done then
|
|
print(json.stringify({ error = err or "Incomplete input" }))
|
|
os.exit(1)
|
|
end
|
|
|
|
return parse:get()
|
|
end
|
|
|
|
local function validateArgs(func, uargs)
|
|
local method = methods[func]
|
|
if not method then
|
|
print(json.stringify({ error = "Method not found" }))
|
|
os.exit(1)
|
|
end
|
|
|
|
if type(uargs) ~= "table" then
|
|
print(json.stringify({ error = "Invalid arguments" }))
|
|
os.exit(1)
|
|
end
|
|
|
|
uargs.ubus_rpc_session = nil
|
|
|
|
local k, v
|
|
local margs = method.args or {}
|
|
for k, v in pairs(uargs) do
|
|
if margs[k] == nil or
|
|
(v ~= nil and type(v) ~= type(margs[k]))
|
|
then
|
|
print(json.stringify({ error = "Invalid arguments" }))
|
|
os.exit(1)
|
|
end
|
|
end
|
|
|
|
return method
|
|
end
|
|
|
|
if arg[1] == "list" then
|
|
local _, method, rv = nil, nil, {}
|
|
for _, method in pairs(methods) do rv[_] = method.args or {} end
|
|
print((json.stringify(rv):gsub(":%[%]", ":{}")))
|
|
elseif arg[1] == "call" then
|
|
local args = parseInput()
|
|
local method = validateArgs(arg[2], args)
|
|
local result, code = method.call(args)
|
|
print((json.stringify(result):gsub("^%[%]$", "{}")))
|
|
os.exit(code or 0)
|
|
end |