123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- #!/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
|