immortalwrt/package/lienol/luci-app-passwall/luasrc/controller/passwall.lua

371 lines
15 KiB
Lua
Raw Normal View History

2019-12-21 19:32:02 +08:00
-- Copyright 2018-2020 Lienol <lawlienol@gmail.com>
2019-08-03 00:02:17 +08:00
module("luci.controller.passwall", package.seeall)
local appname = "passwall"
local ucic = luci.model.uci.cursor()
2019-08-03 00:02:17 +08:00
local http = require "luci.http"
local kcptun = require "luci.model.cbi.passwall.api.kcptun"
local brook = require "luci.model.cbi.passwall.api.brook"
local v2ray = require "luci.model.cbi.passwall.api.v2ray"
local trojan_go = require "luci.model.cbi.passwall.api.trojan_go"
2019-08-03 00:02:17 +08:00
function index()
if not nixio.fs.access("/etc/config/passwall") then return end
entry({"admin", "vpn"}, firstchild(), "VPN", 45).dependent = false
entry({"admin", "vpn", "passwall", "reset_config"}, call("reset_config")).leaf = true
entry({"admin", "vpn", "passwall", "show"}, call("show_menu")).leaf = true
entry({"admin", "vpn", "passwall", "hide"}, call("hide_menu")).leaf = true
if nixio.fs.access("/etc/config/passwall") and
nixio.fs.access("/etc/config/passwall_show") then
entry({"admin", "vpn", "passwall"}, alias("admin", "vpn", "passwall", "settings"), _("Pass Wall"), 1).dependent = true
end
entry({"admin", "vpn", "passwall", "settings"}, cbi("passwall/global"), _("Basic Settings"), 1).dependent = true
entry({"admin", "vpn", "passwall", "node_list"}, cbi("passwall/node_list"), _("Node List"), 2).dependent = true
entry({"admin", "vpn", "passwall", "auto_switch"}, cbi("passwall/auto_switch"), _("Auto Switch"), 3).leaf = true
entry({"admin", "vpn", "passwall", "other"}, cbi("passwall/other", {autoapply = true}), _("Other Settings"), 93).leaf = true
if nixio.fs.access("/usr/sbin/haproxy") then
entry({"admin", "vpn", "passwall", "haproxy"}, cbi("passwall/haproxy"), _("Load Balancing"), 94).leaf = true
end
entry({"admin", "vpn", "passwall", "node_subscribe"}, cbi("passwall/node_subscribe"), _("Node Subscribe"), 95).dependent = true
entry({"admin", "vpn", "passwall", "rule"}, cbi("passwall/rule"), _("Rule Update"), 96).leaf = true
entry({"admin", "vpn", "passwall", "node_config"}, cbi("passwall/node_config")).leaf = true
entry({"admin", "vpn", "passwall", "shunt_rules"}, cbi("passwall/shunt_rules")).leaf = true
entry({"admin", "vpn", "passwall", "acl"}, cbi("passwall/acl"), _("Access control"), 97).leaf = true
entry({"admin", "vpn", "passwall", "log"}, form("passwall/log"), _("Watch Logs"), 999).leaf = true
entry({"admin", "vpn", "passwall", "server"}, cbi("passwall/server/index"), _("Server-Side"), 99).leaf = true
entry({"admin", "vpn", "passwall", "server_user"}, cbi("passwall/server/user")).leaf = true
entry({"admin", "vpn", "passwall", "server_user_status"}, call("server_user_status")).leaf = true
entry({"admin", "vpn", "passwall", "server_get_log"}, call("server_get_log")).leaf = true
entry({"admin", "vpn", "passwall", "server_clear_log"}, call("server_clear_log")).leaf = true
entry({"admin", "vpn", "passwall", "link_append_temp"}, call("link_append_temp")).leaf = true
entry({"admin", "vpn", "passwall", "link_load_temp"}, call("link_load_temp")).leaf = true
entry({"admin", "vpn", "passwall", "link_clear_temp"}, call("link_clear_temp")).leaf = true
entry({"admin", "vpn", "passwall", "link_add_node"}, call("link_add_node")).leaf = true
entry({"admin", "vpn", "passwall", "get_log"}, call("get_log")).leaf = true
entry({"admin", "vpn", "passwall", "clear_log"}, call("clear_log")).leaf = true
entry({"admin", "vpn", "passwall", "status"}, call("status")).leaf = true
entry({"admin", "vpn", "passwall", "socks_status"}, call("socks_status")).leaf = true
entry({"admin", "vpn", "passwall", "connect_status"}, call("connect_status")).leaf = true
entry({"admin", "vpn", "passwall", "check_port"}, call("check_port")).leaf = true
entry({"admin", "vpn", "passwall", "ping_node"}, call("ping_node")).leaf = true
entry({"admin", "vpn", "passwall", "set_node"}, call("set_node")).leaf = true
entry({"admin", "vpn", "passwall", "copy_node"}, call("copy_node")).leaf = true
entry({"admin", "vpn", "passwall", "clear_all_nodes"}, call("clear_all_nodes")).leaf = true
entry({"admin", "vpn", "passwall", "delete_select_nodes"}, call("delete_select_nodes")).leaf = true
entry({"admin", "vpn", "passwall", "update_rules"}, call("update_rules")).leaf = true
entry({"admin", "vpn", "passwall", "luci_check"}, call("luci_check")).leaf = true
entry({"admin", "vpn", "passwall", "luci_update"}, call("luci_update")).leaf = true
entry({"admin", "vpn", "passwall", "kcptun_check"}, call("kcptun_check")).leaf = true
entry({"admin", "vpn", "passwall", "kcptun_update"}, call("kcptun_update")).leaf = true
entry({"admin", "vpn", "passwall", "brook_check"}, call("brook_check")).leaf = true
entry({"admin", "vpn", "passwall", "brook_update"}, call("brook_update")).leaf = true
entry({"admin", "vpn", "passwall", "v2ray_check"}, call("v2ray_check")).leaf = true
entry({"admin", "vpn", "passwall", "v2ray_update"}, call("v2ray_update")).leaf = true
entry({"admin", "vpn", "passwall", "trojan_go_check"}, call("trojan_go_check")).leaf = true
entry({"admin", "vpn", "passwall", "trojan_go_update"}, call("trojan_go_update")).leaf = true
2019-08-03 00:02:17 +08:00
end
local function http_write_json(content)
http.prepare_content("application/json")
http.write_json(content or {code = 1})
2019-08-03 00:02:17 +08:00
end
function reset_config()
luci.sys.call('[ -f "/usr/share/passwall/config.default" ] && cp -f /usr/share/passwall/config.default /etc/config/passwall && /etc/init.d/passwall reload')
luci.http.redirect(luci.dispatcher.build_url("admin", "vpn", "passwall"))
end
2019-08-03 00:02:17 +08:00
function show_menu()
luci.sys.call("touch /etc/config/passwall_show")
luci.http.redirect(luci.dispatcher.build_url("admin", "vpn", "passwall"))
2019-08-03 00:02:17 +08:00
end
function hide_menu()
luci.sys.call("rm -rf /etc/config/passwall_show")
luci.http.redirect(luci.dispatcher.build_url("admin", "status", "overview"))
2019-08-03 00:02:17 +08:00
end
function link_append_temp()
local link = luci.http.formvalue("link")
local lfile = "/tmp/links.conf"
local ret, ldata="empty", {}
luci.sys.call('touch ' .. lfile .. ' && echo \'' .. link .. '\' >> ' .. lfile)
ret = luci.sys.exec([[awk -F'://' 'BEGIN{ all=0 } /.{2,9}:\/\/.{4,}$/ {gsub(/:\/\/.*$/,""); arr[$0]++; all++ } END { for(typ in arr) { printf("%s: %d, ", typ, arr[typ]) }; printf("\ntotal: %d", all) }' ]] .. lfile)
luci.http.prepare_content("application/json")
luci.http.write_json({counter = ret})
end
function link_load_temp()
local lfile = "/tmp/links.conf"
local ret, ldata="empty", {}
ldata[#ldata+1] = nixio.fs.readfile(lfile) or "_nofile_"
if ldata[1] == "" then
ldata[1] = "_nodata_"
else
ret = luci.sys.exec([[awk -F'://' 'BEGIN{ all=0 } /.{2,9}:\/\/.{4,}$/ {gsub(/:\/\/.*$/,""); arr[$0]++; all++ } END { for(typ in arr) { printf("%s: %d, ", typ, arr[typ]) }; printf("\ntotal: %d", all) }' ]] .. lfile)
end
luci.http.prepare_content("application/json")
luci.http.write_json({counter = ret, data = ldata})
end
function link_clear_temp()
local lfile = "/tmp/links.conf"
luci.sys.call('cat /dev/null > ' .. lfile)
end
2019-11-30 19:16:05 +08:00
function link_add_node()
local lfile = "/tmp/links.conf"
local link = luci.http.formvalue("link")
luci.sys.call('echo \'' .. link .. '\' >> ' .. lfile)
luci.sys.call("lua /usr/share/passwall/subscribe.lua add log")
2019-08-03 00:02:17 +08:00
end
function get_log()
-- luci.sys.exec("[ -f /var/log/passwall.log ] && sed '1!G;h;$!d' /var/log/passwall.log > /var/log/passwall_show.log")
luci.http.write(luci.sys.exec("[ -f '/var/log/passwall.log' ] && cat /var/log/passwall.log"))
2019-08-03 00:02:17 +08:00
end
function clear_log()
luci.sys.call("echo '' > /var/log/passwall.log")
end
2019-08-03 00:02:17 +08:00
2019-11-30 19:16:05 +08:00
function status()
-- local dns_mode = ucic:get(appname, "@global[0]", "dns_mode")
local e = {}
e.dns_mode_status = luci.sys.call("netstat -apn | grep 7913 >/dev/null") == 0
e.haproxy_status = luci.sys.call(string.format("ps -w | grep -v grep | grep '%s/bin/' | grep haproxy >/dev/null", appname)) == 0
local tcp_node_num = ucic:get(appname, "@global_other[0]", "tcp_node_num") or 1
for i = 1, tcp_node_num, 1 do
e["kcptun_tcp_node%s_status" % i] = luci.sys.call(string.format("ps -w | grep -v grep | grep '%s/bin/kcptun' | grep -i 'tcp_%s' >/dev/null", appname, i)) == 0
e["tcp_node%s_status" % i] = luci.sys.call(string.format("ps -w | grep -v -E 'grep|kcptun' | grep '%s/bin/' | grep -i 'TCP_%s' >/dev/null", appname, i)) == 0
end
local udp_node_num = ucic:get(appname, "@global_other[0]", "udp_node_num") or 1
for i = 1, udp_node_num, 1 do
if (ucic:get(appname, "@global[0]", "udp_node" .. i) or "nil") == "tcp" then
e["udp_node%s_status" % i] = e["tcp_node%s_status" % i]
else
e["udp_node%s_status" % i] = luci.sys.call(string.format("ps -w | grep -v grep | grep '%s/bin/' | grep -i 'UDP_%s' >/dev/null", appname, i)) == 0
end
end
luci.http.prepare_content("application/json")
luci.http.write_json(e)
end
2019-11-16 08:31:55 +08:00
function socks_status()
local e = {}
local index = luci.http.formvalue("index")
local id = luci.http.formvalue("id")
e.index = index
e.status = luci.sys.call(string.format("ps -w | grep -v grep | grep '%s/bin/' | grep 'SOCKS_%s' > /dev/null", appname, id)) == 0
luci.http.prepare_content("application/json")
luci.http.write_json(e)
2019-08-03 00:02:17 +08:00
end
function connect_status()
local e = {}
e.use_time = ""
local url = luci.http.formvalue("url")
local result = luci.sys.exec('curl --connect-timeout 5 -o /dev/null -I -skL -w "%{http_code}:%{time_starttransfer}" ' .. url)
local code = tonumber(luci.sys.exec("echo -n '" .. result .. "' | awk -F ':' '{print $1}'") or "0")
if code ~= 0 then
local use_time = luci.sys.exec("echo -n '" .. result .. "' | awk -F ':' '{print $2}'")
e.use_time = string.format("%.2f", use_time * 1000)
e.ping_type = "curl"
end
luci.http.prepare_content("application/json")
luci.http.write_json(e)
2019-08-03 00:02:17 +08:00
end
function ping_node()
local index = luci.http.formvalue("index")
local address = luci.http.formvalue("address")
local port = luci.http.formvalue("port")
local e = {}
e.index = index
if (ucic:get(appname, "@global_other[0]", "use_tcping") or 1) == "1" and luci.sys.exec("echo -n $(command -v tcping)") ~= "" then
e.ping = luci.sys.exec(string.format("echo -n $(tcping -q -c 1 -i 1 -t 2 -p %s %s 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}') 2>/dev/null", port, address))
end
if e.ping == nil or tonumber(e.ping) == 0 then
e.ping = luci.sys.exec("echo -n $(ping -c 1 -W 1 %q 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}') 2>/dev/null" % address)
end
luci.http.prepare_content("application/json")
luci.http.write_json(e)
2019-08-03 00:02:17 +08:00
end
2019-11-30 19:16:05 +08:00
function set_node()
local protocol = luci.http.formvalue("protocol")
local number = luci.http.formvalue("number")
local section = luci.http.formvalue("section")
ucic:set(appname, "@global[0]", protocol .. "_node" .. number, section)
ucic:commit(appname)
luci.sys.call("/etc/init.d/passwall restart > /dev/null 2>&1 &")
luci.http.redirect(luci.dispatcher.build_url("admin", "vpn", "passwall", "log"))
2019-08-03 00:02:17 +08:00
end
2019-11-30 19:16:05 +08:00
function copy_node()
local e = {}
local section = luci.http.formvalue("section")
luci.http.prepare_content("application/json")
luci.http.write_json(e)
2019-08-03 00:02:17 +08:00
end
function clear_all_nodes()
ucic:foreach(appname, "nodes", function(node)
ucic:delete(appname, node['.name'])
end)
local function clear(type)
local node_num = ucic:get(appname, "@global_other[0]", type .. "_node_num") or 1
for i = 1, node_num, 1 do
local node = ucic:get(appname, "@global[0]", type .. "_node" .. i)
if node then
ucic:set(appname, '@global[0]', type .. "_node" .. i, "nil")
end
end
end
clear("tcp")
clear("udp")
ucic:commit(appname)
luci.sys.call("/etc/init.d/" .. appname .. " restart")
end
function delete_select_nodes()
local ids = luci.http.formvalue("ids")
string.gsub(ids, '[^' .. "," .. ']+', function(w)
ucic:delete(appname, w)
end)
ucic:commit(appname)
luci.sys.call("/etc/init.d/" .. appname .. " restart")
end
2019-08-03 00:02:17 +08:00
function check_port()
local node_name = ""
local retstring = "<br />"
-- retstring = retstring .. "<font color='red'>暂时不支持UDP检测</font><br />"
retstring = retstring .. "<font color='green'>检测端口可用性</font><br />"
ucic:foreach("passwall", "nodes", function(s)
local ret = ""
local tcp_socket
if (s.use_kcp and s.use_kcp == "1" and s.kcp_port) or
(s.v2ray_transport and s.v2ray_transport == "mkcp" and s.port) then
else
local type = s.type
if type and type ~= "V2ray_balancing" and type ~= "V2ray_shunt" and
s.address and s.port and s.remarks then
node_name = "%s[%s] %s:%s" % {s.type, s.remarks, s.address, s.port}
tcp_socket = nixio.socket("inet", "stream")
tcp_socket:setopt("socket", "rcvtimeo", 3)
tcp_socket:setopt("socket", "sndtimeo", 3)
ret = tcp_socket:connect(s.address, s.port)
if tostring(ret) == "true" then
retstring = retstring .. "<font color='green'>" .. node_name .. " OK.</font><br />"
else
retstring = retstring .. "<font color='red'>" .. node_name .. " Error.</font><br />"
end
ret = ""
end
end
if tcp_socket then tcp_socket:close() end
end)
luci.http.prepare_content("application/json")
luci.http.write_json({ret = retstring})
2019-08-03 00:02:17 +08:00
end
function update_rules()
local update = luci.http.formvalue("update")
luci.sys.call("lua /usr/share/passwall/rule_update.lua log '" .. update .. "' > /dev/null 2>&1 &")
2019-08-03 00:02:17 +08:00
end
function server_user_status()
local e = {}
e.index = luci.http.formvalue("index")
e.status = luci.sys.call(string.format("ps -w | grep -v 'grep' | grep '%s/bin/' | grep -i '%s' >/dev/null", appname .. "_server", luci.http.formvalue("id"))) == 0
http_write_json(e)
end
function server_get_log()
luci.http.write(luci.sys.exec("[ -f '/var/log/passwall_server.log' ] && cat /var/log/passwall_server.log"))
end
function server_clear_log()
luci.sys.call("echo '' > /var/log/passwall_server.log")
end
2019-08-03 00:02:17 +08:00
function kcptun_check()
local json = kcptun.to_check("")
http_write_json(json)
2019-08-03 00:02:17 +08:00
end
function kcptun_update()
local json = nil
local task = http.formvalue("task")
if task == "extract" then
json = kcptun.to_extract(http.formvalue("file"), http.formvalue("subfix"))
elseif task == "move" then
json = kcptun.to_move(http.formvalue("file"))
else
json = kcptun.to_download(http.formvalue("url"))
end
http_write_json(json)
2019-08-03 00:02:17 +08:00
end
function brook_check()
local json = brook.to_check("")
http_write_json(json)
2019-08-03 00:02:17 +08:00
end
function brook_update()
local json = nil
local task = http.formvalue("task")
if task == "move" then
json = brook.to_move(http.formvalue("file"))
else
json = brook.to_download(http.formvalue("url"))
end
http_write_json(json)
2019-08-03 00:02:17 +08:00
end
function v2ray_check()
local json = v2ray.to_check("")
http_write_json(json)
2019-08-03 00:02:17 +08:00
end
function v2ray_update()
local json = nil
local task = http.formvalue("task")
if task == "extract" then
json = v2ray.to_extract(http.formvalue("file"), http.formvalue("subfix"))
elseif task == "move" then
json = v2ray.to_move(http.formvalue("file"))
else
json = v2ray.to_download(http.formvalue("url"))
end
http_write_json(json)
end
function trojan_go_check()
local json = trojan_go.to_check("")
http_write_json(json)
end
function trojan_go_update()
local json = nil
local task = http.formvalue("task")
if task == "extract" then
json = trojan_go.to_extract(http.formvalue("file"), http.formvalue("subfix"))
elseif task == "move" then
json = trojan_go.to_move(http.formvalue("file"))
else
json = trojan_go.to_download(http.formvalue("url"))
end
http_write_json(json)
2019-08-03 00:02:17 +08:00
end