luci-app-passwall: sync with upstream source

This commit is contained in:
CN_SZTL 2020-07-05 20:19:28 +08:00
parent c653aaa165
commit c5644ccb0b
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
56 changed files with 14268 additions and 9882 deletions

View File

@ -6,9 +6,9 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
PKG_VERSION:=3.6
PKG_RELEASE:=40
PKG_DATE:=20200411
PKG_VERSION:=3.9
PKG_RELEASE:=4
PKG_DATE:=20200705
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
@ -22,20 +22,16 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_ipt2socks
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks
bool "Include Shadowsocks Redir (ss-redir)"
bool "Include Shadowsocks"
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR
bool "Include ShadowsocksR Redir (ssr-redir)"
bool "Include ShadowsocksR"
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_socks
bool "Include Shadowsocks Socks (ss-local)"
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_socks
bool "Include ShadowsocksR Socks (ssr-local)"
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Server
bool "Include ShadowsocksR Server"
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_V2ray
bool "Include V2ray"
@ -86,12 +82,13 @@ define Package/$(PKG_NAME)
TITLE:=LuCI support for PassWall
PKGARCH:=all
DEPENDS:=+libmbedtls +iptables-mod-tproxy +ip +ipset +coreutils +coreutils-base64 +coreutils-nohup +luci-lib-jsonc \
+wget +resolveip +unzip +dnsmasq-full +tcping +libuci-lua \
+curl +ca-certificates +resolveip +unzip +dnsmasq-full +tcping +libuci-lua \
+PACKAGE_$(PKG_NAME)_INCLUDE_ipt2socks:ipt2socks \
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks:shadowsocks-libev-ss-redir \
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks:shadowsocks-libev-ss-local \
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR:shadowsocksr-libev-alt \
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_socks:shadowsocks-libev-ss-local \
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_socks:shadowsocksr-libev-ssr-local \
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR:shadowsocksr-libev-ssr-local \
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Server:shadowsocksr-libev-server \
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:v2ray \
+PACKAGE_$(PKG_NAME)_INCLUDE_Trojan:trojan \
+PACKAGE_$(PKG_NAME)_INCLUDE_Trojan:ipt2socks \
@ -116,6 +113,7 @@ endef
define Package/$(PKG_NAME)/conffiles
/etc/config/passwall
/etc/config/passwall_server
/usr/share/passwall/rules/blacklist_host
/usr/share/passwall/rules/blacklist_ip
/usr/share/passwall/rules/whitelist_host
@ -125,16 +123,21 @@ endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) ./root/etc/config/passwall $(1)/etc/config/passwall
$(INSTALL_CONF) ./root/etc/config/passwall_show $(1)/etc/config/passwall_show
$(INSTALL_CONF) ./root/etc/config/passwall_server $(1)/etc/config/passwall_server
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./root/etc/init.d/passwall $(1)/etc/init.d/passwall
$(INSTALL_BIN) ./root/etc/init.d/passwall_server $(1)/etc/init.d/passwall_server
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_CONF) ./root/etc/uci-defaults/* $(1)/etc/uci-defaults
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./root/etc/init.d/passwall $(1)/etc/init.d/passwall
$(INSTALL_DIR) $(1)/usr/share/passwall
cp -pR ./root/usr/share/passwall/* $(1)/usr/share/passwall
$(INSTALL_CONF) ./root/etc/config/passwall $(1)/usr/share/passwall/config.default
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
cp -pR ./root/usr/share/rpcd/acl.d/* $(1)/usr/share/rpcd/acl.d
$(INSTALL_DIR) $(1)/usr/lib/lua/luci
cp -pR ./luasrc/* $(1)/usr/lib/lua/luci/
@ -146,6 +149,8 @@ endef
define Package/$(PKG_NAME)/postinst
#!/bin/sh
chmod a+x $${IPKG_INSTROOT}/usr/share/passwall/* >/dev/null 2>&1
chmod a+x $${IPKG_INSTROOT}/usr/lib/lua/luci/model/cbi/passwall/server/api/app.lua >/dev/null 2>&1
touch $${IPKG_INSTROOT}/etc/config/passwall_show >/dev/null 2>&1
exit 0
endef

View File

@ -1,8 +1,8 @@
-- Copyright 2018-2020 Lienol <lawlienol@gmail.com>
module("luci.controller.passwall", package.seeall)
local appname = "passwall"
local ucic = luci.model.uci.cursor()
local http = require "luci.http"
local passwall = require "luci.model.cbi.passwall.api.passwall"
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"
@ -10,75 +10,53 @@ local v2ray = require "luci.model.cbi.passwall.api.v2ray"
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", "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
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
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
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", "acl"}, cbi("passwall/acl"),
_("Access control"), 97).leaf = true
entry({"admin", "vpn", "passwall", "log"}, form("passwall/log"),
_("Watch Logs"), 99).leaf = true
entry({"admin", "vpn", "passwall", "node_config"},
cbi("passwall/node_config")).leaf = true
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", "link_add_node"}, call("link_add_node")).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_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", "clear_log"}, call("clear_log")).leaf = true
entry({"admin", "vpn", "passwall", "status"}, call("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", "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", "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
end
local function http_write_json(content)
@ -87,8 +65,7 @@ local function http_write_json(content)
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.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
@ -104,83 +81,63 @@ end
function link_add_node()
local link = luci.http.formvalue("link")
luci.sys.call('rm -f /tmp/links.conf && echo "' .. link ..
'" >> /tmp/links.conf')
luci.sys.call('rm -f /tmp/links.conf && echo "' .. link .. '" >> /tmp/links.conf')
luci.sys.call("lua /usr/share/passwall/subscribe.lua add log")
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"))
luci.http.write(luci.sys.exec("[ -f '/var/log/passwall.log' ] && cat /var/log/passwall.log"))
end
function clear_log() luci.sys.call("echo '' > /var/log/passwall.log") end
function clear_log()
luci.sys.call("echo '' > /var/log/passwall.log")
end
function status()
-- local dns_mode = luci.sys.exec("echo -n $(uci -q get " .. appname .. ".@global[0].dns_mode)")
-- 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 = luci.sys.exec(
"echo -n $(uci -q get %s.@global_other[0].tcp_node_num)" %
appname)
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/' | grep 'kcptun_tcp_%s' >/dev/null",
appname, i)) == 0
e["tcp_node%s_status" % i] = luci.sys.call(
string.format(
"ps -w | grep -v grep | grep -v kcptun | grep '%s/bin/' | grep -i -E 'TCP_%s' >/dev/null",
appname, i)) == 0
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 = luci.sys.exec(
"echo -n $(uci -q get %s.@global_other[0].udp_node_num)" %
appname)
local udp_node_num = ucic:get(appname, "@global_other[0]", "udp_node_num") or 1
for i = 1, udp_node_num, 1 do
e["udp_node%s_status" % i] = luci.sys.call(
string.format(
"ps -w | grep -v grep | grep '%s/bin/' | grep -i -E 'UDP_%s' >/dev/null",
appname, i)) == 0
end
local socks_node_num = luci.sys.exec(
"echo -n $(uci -q get %s.@global_other[0].socks_node_num)" %
appname)
for i = 1, socks_node_num, 1 do
e["kcptun_socks_node%s_status" % i] =
luci.sys.call(string.format(
"ps -w | grep -v grep | grep '%s/bin/' | grep 'kcptun_socks_%s' >/dev/null",
appname, i)) == 0
e["socks_node%s_status" % i] = luci.sys.call(
string.format(
"ps -w | grep -v grep | grep -v kcptun | grep '%s/bin/' | grep -i 'SOCKS_%s' >/dev/null",
appname, i, i)) == 0
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
function connect_status()
local os = require "os"
function socks_status()
local e = {}
local start_time = os.time()
if luci.http.formvalue("type") == "google" then
e.status = luci.sys.call(
"echo $(/usr/share/passwall/test.sh test_url 'www.google.com/generate_204') | grep 200 >/dev/null") ==
0
else
e.status = luci.sys.call(
"echo $(/usr/share/passwall/test.sh test_url 'www.baidu.com') | grep 200 >/dev/null") ==
0
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)
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_total}" ' .. 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
local use_time = os.difftime(os.time(), start_time)
e.use_time = use_time
luci.http.prepare_content("application/json")
luci.http.write_json(e)
end
@ -191,12 +148,11 @@ function ping_node()
local port = luci.http.formvalue("port")
local e = {}
e.index = index
if luci.sys.exec("echo -n $(uci -q get %s.@global_other[0].use_tcping)" % appname) == "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 -p %s %s 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print$2}') 2>/dev/null", port, address))
luci.sys.call(string.format("ps -w | grep 'tcping -q -c 1 -i 1 -p %s %s' | grep -v grep | awk '{print $1}' | xargs kill -9 2>/dev/null", port, address))
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 1 -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)
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)
@ -206,11 +162,10 @@ function set_node()
local protocol = luci.http.formvalue("protocol")
local number = luci.http.formvalue("number")
local section = luci.http.formvalue("section")
luci.sys.call("uci set passwall.@global[0]." .. protocol .. "_node" ..
number .. "=" .. section ..
" && uci commit passwall && /etc/init.d/passwall restart > /dev/null 2>&1 &")
luci.http.redirect(luci.dispatcher.build_url("admin", "vpn", "passwall",
"log"))
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"))
end
function copy_node()
@ -220,17 +175,44 @@ function copy_node()
luci.http.write_json(e)
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
function check_port()
local s
local node_name = ""
local uci = luci.model.uci.cursor()
local retstring = "<br />"
-- retstring = retstring .. "<font color='red'>暂时不支持UDP检测</font><br />"
retstring = retstring ..
"<font color='green'>检测端口可用性</font><br />"
uci:foreach("passwall", "nodes", function(s)
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
@ -246,13 +228,9 @@ function check_port()
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 />"
retstring = retstring .. "<font color='green'>" .. node_name .. " OK.</font><br />"
else
retstring =
retstring .. "<font color='red'>" .. node_name ..
" Error.</font><br />"
retstring = retstring .. "<font color='red'>" .. node_name .. " Error.</font><br />"
end
ret = ""
end
@ -265,19 +243,22 @@ 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 &")
luci.sys.call("lua /usr/share/passwall/rule_update.lua log '" .. update .. "' > /dev/null 2>&1 &")
end
function luci_check()
local json = passwall.to_check("")
http_write_json(json)
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 luci_update()
local json = passwall.update_luci(http.formvalue("url"),
http.formvalue("save"))
http_write_json(json)
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
function kcptun_check()

View File

@ -1,11 +1,8 @@
local sys = require "luci.sys"
local webadmin = require "luci.tools.webadmin"
local uci = require"luci.model.uci".cursor()
local fs = require "nixio.fs"
local api = require "luci.model.cbi.passwall.api.api"
local appname = "passwall"
m = Map("passwall")
m = Map(appname)
-- [[ Rule List Settings ]]--
s = m:section(TypedSection, "global_rules")
@ -15,7 +12,7 @@ s.anonymous = true
s:tab("w_hosts", translate("Whitelist Hosts"), "<font color='red'>" ..
translate("Join the white list of domain names will not go agent.") ..
"</font>")
local w_host_file = "/usr/share/passwall/rules/whitelist_host"
local w_host_file = string.format("/usr/share/%s/rules/whitelist_host", appname)
o = s:taboption("w_hosts", TextValue, "whitelist_host")
o.rows = 8
o.wrap = "off"
@ -30,7 +27,7 @@ o.remove = function(self, section, value) fs.writefile(w_host_file, "") end
s:tab("w_ip", translate("Whitelist IP"), "<font color='red'>" .. translate(
"These had been joined ip addresses will not use proxy.Please input the ip address or ip address segment,every line can input only one ip address.For example,192.168.0.0/24 or 223.5.5.5.") ..
"</font>")
local w_ip_file = "/usr/share/passwall/rules/whitelist_ip"
local w_ip_file = string.format("/usr/share/%s/rules/whitelist_ip", appname)
o = s:taboption("w_ip", TextValue, "whitelist_ip")
o.rows = 8
o.wrap = "off"
@ -46,7 +43,7 @@ s:tab("b_hosts", translate("Blacklist Hosts"),
"<font color='red'>" .. translate(
"These had been joined websites will use proxy.Please input the domain names of websites,every line can input only one website domain.For example,google.com.") ..
"</font>")
local b_host_file = "/usr/share/passwall/rules/blacklist_host"
local b_host_file = string.format("/usr/share/%s/rules/blacklist_host", appname)
o = s:taboption("b_hosts", TextValue, "blacklist_host")
o.rows = 8
o.wrap = "off"
@ -61,7 +58,7 @@ o.remove = function(self, section, value) fs.writefile(b_host_file, "") end
s:tab("b_ip", translate("Blacklist IP"), "<font color='red'>" .. translate(
"These had been joined ip addresses will use proxy.Please input the ip address or ip address segment,every line can input only one ip address.For example,35.24.0.0/24 or 8.8.4.4.") ..
"</font>")
local b_ip_file = "/usr/share/passwall/rules/blacklist_ip"
local b_ip_file = string.format("/usr/share/%s/rules/blacklist_ip", appname)
o = s:taboption("b_ip", TextValue, "blacklist_ip")
o.rows = 8
o.wrap = "off"
@ -111,14 +108,14 @@ o.rmempty = true
sys.net.mac_hints(function(e, t) o:value(e, "%s (%s)" % {e, t}) end)
---- TCP Node
local tcp_node_num = api.uci_get_type("global_other", "tcp_node_num", 1)
local tcp_node_num = m:get("@global_other[0]", "tcp_node_num") or 1
if tonumber(tcp_node_num) > 1 then
o = s:option(ListValue, "tcp_node", translate("TCP Node"))
for i = 1, tcp_node_num, 1 do o:value(i, "TCP_" .. i) end
end
---- UDP Node
local udp_node_num = api.uci_get_type("global_other", "udp_node_num", 1)
local udp_node_num = m:get("@global_other[0]", "udp_node_num") or 1
if tonumber(udp_node_num) > 1 then
o = s:option(ListValue, "udp_node", translate("UDP Node"))
for i = 1, udp_node_num, 1 do o:value(i, "UDP_" .. i) end

View File

@ -6,16 +6,21 @@ local util = require "luci.util"
local i18n = require "luci.i18n"
appname = "passwall"
curl = "/usr/bin/curl"
curl_args = {"-skL", "--connect-timeout 3", "--retry 3", "-m 60"}
wget = "/usr/bin/wget"
wget_args = {"--no-check-certificate", "--quiet", "--timeout=100", "--tries=3"}
command_timeout = 300
LEDE_BOARD = nil
DISTRIB_TARGET = nil
function gen_uuid()
local uuid = string.gsub(sys.exec("echo -n $(cat /proc/sys/kernel/random/uuid)"), "-", "")
return uuid
end
function uci_get_type(type, config, default)
local value = uci:get_first(appname, type, config, default) or sys.exec(
"echo -n `uci -q get " .. appname .. ".@" .. type ..
"[0]." .. config .. "`")
local value = uci:get_first(appname, type, config, default) or sys.exec("echo -n `uci -q get " .. appname .. ".@" .. type .."[0]." .. config .. "`")
if (value == nil or value == "") and (default and default ~= "") then
value = default
end
@ -23,15 +28,46 @@ function uci_get_type(type, config, default)
end
function uci_get_type_id(id, config, default)
local value = uci:get(appname, id, config, default) or
sys.exec("echo -n `uci -q get " .. appname .. "." .. id ..
"." .. config .. "`")
local value = uci:get(appname, id, config, default) or sys.exec("echo -n `uci -q get " .. appname .. "." .. id .. "." .. config .. "`")
if (value == nil or value == "") and (default and default ~= "") then
value = default
end
return value
end
function get_v2ray_path()
local path = uci_get_type("global_app", "v2ray_file")
return path .. "/v2ray"
end
function get_v2ray_version()
local path = get_v2ray_path()
local version = sys.exec("[ -f '" .. path .. "' ] && " .. path .. " -version | awk '{print $2}' | sed -n 1P")
return version
end
function get_kcptun_path()
local path = uci_get_type("global_app", "kcptun_client_file")
return path
end
function get_kcptun_version()
local path = get_kcptun_path()
local version = sys.exec("[ -f '" .. path .. "' ] && " .. path .. " -v | awk '{print $3}'")
return version
end
function get_brook_path()
local path = uci_get_type("global_app", "brook_file")
return path
end
function get_brook_version()
local path = get_brook_path()
local version = sys.exec("[ -f '" .. path .. "' ] && " .. path .. " -v | awk '{print $3}'")
return version
end
function _unpack(t, i)
i = i or 1
if t[i] ~= nil then return t[i], _unpack(t, i + 1) end
@ -169,16 +205,7 @@ end
function get_api_json(url)
local jsonc = require "luci.jsonc"
local output = {}
-- exec(wget, { "-O-", url, _unpack(wget_args) },
-- function(chunk) output[#output + 1] = chunk end)
-- local json_content = util.trim(table.concat(output))
local json_content = luci.sys.exec(wget ..
" --no-check-certificate --timeout=10 -t 1 -O- " ..
url)
local json_content = luci.sys.exec(curl .. " " .. _unpack(curl_args) .. " " .. url)
if json_content == "" then return {} end
return jsonc.parse(json_content) or {}
end

View File

@ -103,8 +103,7 @@ function to_download(url)
local tmp_file = util.trim(util.exec("mktemp -u -t brook_download.XXXXXX"))
local result = api.exec(api.wget, {"-O", tmp_file, url, api._unpack(api.wget_args)},
nil, api.command_timeout) == 0
local result = api.exec(api.curl, {api._unpack(api.curl_args), "-o", tmp_file, url}, nil, api.command_timeout) == 0
if not result then
api.exec("/bin/rm", {"-f", tmp_file})

View File

@ -0,0 +1,34 @@
local ucursor = require "luci.model.uci".cursor()
local jsonc = require "luci.jsonc"
local node_section = arg[1]
local local_port = arg[2]
local server_host = arg[3]
local server_port = arg[4]
local node = ucursor:get_all("passwall", node_section)
local config = {
server = server_host or node.address,
server_port = server_port or tonumber(node.port),
local_address = "0.0.0.0",
local_port = tonumber(local_port),
password = node.password,
timeout = tonumber(node.timeout),
fast_open = (node.tcp_fast_open and node.tcp_fast_open == "true") and true or false,
reuse_port = true
}
if node.type == "SS" then
config.method = node.ss_encrypt_method
if node.ss_plugin and node.ss_plugin ~= "none" then
config.plugin = node.ss_plugin
config.plugin_opts = node.ss_plugin_opts or nil
end
elseif node.type == "SSR" then
config.method = node.ssr_encrypt_method
config.protocol = node.protocol
config.protocol_param = node.protocol_param
config.obfs = node.obfs
config.obfs_param = node.obfs_param
end
print(jsonc.stringify(config, 1))

View File

@ -1,24 +1,51 @@
local ucursor = require"luci.model.uci".cursor()
local sys = require "luci.sys"
local json = require "luci.jsonc"
local appname = "passwall"
local node_section = arg[1]
local proto = arg[2]
local redir_port = arg[3]
local socks_proxy_port = arg[4]
local node = ucursor:get_all("passwall", node_section)
local node = ucursor:get_all(appname, node_section)
local inbounds = {}
local outbounds = {}
local network = proto
local routing = nil
local function gen_outbound(node)
local function gen_outbound(node, tag)
local result = nil
if node then
local node_id = node[".name"]
if tag == nil then
tag = node_id
end
if node.type ~= "V2ray" then
if node.type == "Socks" then
node.v2ray_protocol = "socks"
node.v2ray_transport = "tcp"
else
local node_type = (proto and proto ~= "nil") and proto or "socks"
local new_port = sys.exec(string.format("echo -n $(/usr/share/%s/app.sh get_new_port auto tcp)", appname))
node.port = new_port
sys.call(string.format("/usr/share/%s/app.sh run_socks %s %s %s %s %s",
appname,
node_id,
"127.0.0.1",
new_port,
string.format("/var/etc/%s/v2_%s_%s.json", appname, node_type, node_id),
"4")
)
node.v2ray_protocol = "socks"
node.v2ray_transport = "tcp"
node.address = "127.0.0.1"
end
end
result = {
tag = node[".name"],
tag = tag,
protocol = node.v2ray_protocol or "vmess",
mux = {
enabled = (node.v2ray_mux == "1") and true or false,
concurrency = (node.v2ray_mux_concurrency) and
tonumber(node.v2ray_mux_concurrency) or 8
concurrency = (node.v2ray_mux_concurrency) and tonumber(node.v2ray_mux_concurrency) or 8
},
-- 底层传输配置
streamSettings = (node.v2ray_protocol == "vmess") and {
@ -26,10 +53,10 @@ local function gen_outbound(node)
security = node.v2ray_stream_security,
tlsSettings = (node.v2ray_stream_security == "tls") and {
serverName = node.tls_serverName,
allowInsecure = (node.tls_allowInsecure == "1") and true or
false
allowInsecure = (node.tls_allowInsecure == "1") and true or false
} or nil,
tcpSettings = (node.v2ray_transport == "tcp") and {
tcpSettings = (node.v2ray_transport == "tcp" and
node.v2ray_protocol ~= "socks") and {
header = {
type = node.v2ray_tcp_guise,
request = {
@ -45,8 +72,7 @@ local function gen_outbound(node)
tti = tonumber(node.v2ray_mkcp_tti),
uplinkCapacity = tonumber(node.v2ray_mkcp_uplinkCapacity),
downlinkCapacity = tonumber(node.v2ray_mkcp_downlinkCapacity),
congestion = (node.v2ray_mkcp_congestion == "1") and true or
false,
congestion = (node.v2ray_mkcp_congestion == "1") and true or false,
readBufferSize = tonumber(node.v2ray_mkcp_readBufferSize),
writeBufferSize = tonumber(node.v2ray_mkcp_writeBufferSize),
header = {type = node.v2ray_mkcp_guise}
@ -82,19 +108,12 @@ local function gen_outbound(node)
}
}
} or nil,
servers = (node.v2ray_protocol == "http" or node.v2ray_protocol == "socks" or node.v2ray_protocol == "shadowsocks") and {
servers = (node.v2ray_protocol == "socks") and {
{
address = node.address,
port = tonumber(node.port),
method = node.v2ray_ss_encrypt_method,
password = node.password or "",
ota = (node.v2ray_ss_ota == '1') and true or false,
users = (node.username and node.password) and {
{
user = node.username or "",
pass = node.password or ""
}
} or nil
users = (node.username and node.password) and
{{user = node.username, pass = node.password}} or nil
}
} or nil
}
@ -139,12 +158,83 @@ if redir_port ~= "nil" then
end
end
local outbound = gen_outbound(node)
if outbound then table.insert(outbounds, outbound) end
if node.v2ray_protocol == "_shunt" then
local rules = {}
ucursor:foreach(appname, "shunt_rules", function(e)
local _node_id = node[e[".name"]] or nil
if _node_id and _node_id ~= "nil" then
local _node = ucursor:get_all(appname, _node_id)
local _outbound = gen_outbound(_node, e[".name"])
if _outbound then
table.insert(outbounds, _outbound)
if e.domain_list then
local _domain = {}
string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w)
table.insert(_domain, w)
end)
table.insert(rules, {
type = "field",
outboundTag = e[".name"],
domain = _domain
})
end
if e.ip_list then
local _ip = {}
string.gsub(e.ip_list, '[^' .. "\r\n" .. ']+', function(w)
table.insert(_ip, w)
end)
table.insert(rules, {
type = "field",
outboundTag = e[".name"],
ip = _ip
})
end
end
end
end)
local default_node_id = node.default_node or nil
if default_node_id and default_node_id ~= "nil" then
local default_node = ucursor:get_all(appname, default_node_id)
local default_outbound = gen_outbound(default_node, "default")
if default_outbound then
table.insert(outbounds, default_outbound)
local rule = {
type = "field",
outboundTag = "default",
network = network
}
table.insert(rules, rule)
end
end
routing = {domainStrategy = "IPOnDemand", rules = rules}
elseif node.v2ray_protocol == "_balancing" then
if node.v2ray_balancing_node then
local nodes = node.v2ray_balancing_node
local length = #nodes
for i = 1, length do
local node = ucursor:get_all(appname, nodes[i])
local outbound = gen_outbound(node)
if outbound then table.insert(outbounds, outbound) end
end
routing = {
domainStrategy = "IPOnDemand",
balancers = {{tag = "balancer", selector = nodes}},
rules = {
{type = "field", network = "tcp,udp", balancerTag = "balancer"}
}
}
end
else
local outbound = gen_outbound(node)
if outbound then table.insert(outbounds, outbound) end
end
-- 额外传出连接
table.insert(outbounds,
{protocol = "freedom", tag = "direct", settings = {keep = ""}})
table.insert(outbounds, {protocol = "freedom", tag = "direct", settings = {keep = ""}})
local v2ray = {
log = {

View File

@ -1,193 +0,0 @@
local ucursor = require"luci.model.uci".cursor()
local sys = require "luci.sys"
local json = require "luci.jsonc"
local node_section = arg[1]
local proto = arg[2]
local redir_port = arg[3]
local socks_proxy_port = arg[4]
local node = ucursor:get_all("passwall", node_section)
local inbounds = {}
local outbounds = {}
local network = proto
local routing = nil
local function gen_outbound(node)
local result = nil
if node then
local node_id = node[".name"]
if node.type ~= "V2ray" then
if node.type == "Socks5" then
node.v2ray_protocol = "socks"
node.v2ray_transport = "tcp"
else
local node_type = (proto and proto ~= "nil") and proto or
"socks"
local new_port = sys.exec(
"echo -n $(/usr/share/passwall/app.sh get_new_port auto tcp)")
node.port = new_port
sys.call(string.format(
"/usr/share/passwall/app.sh gen_start_config %s %s %s %s %s %s",
node_id, new_port, "SOCKS",
"/var/etc/passwall/v2_balancing_" .. node_type .. "_" ..
node_id .. ".json", "4", "127.0.0.1"))
node.v2ray_protocol = "socks"
node.v2ray_transport = "tcp"
node.address = "127.0.0.1"
end
end
result = {
tag = node_id,
protocol = node.v2ray_protocol or "vmess",
mux = {
enabled = (node.v2ray_mux == "1") and true or false,
concurrency = (node.v2ray_mux_concurrency) and
tonumber(node.v2ray_mux_concurrency) or 8
},
-- 底层传输配置
streamSettings = (node.v2ray_protocol == "vmess") and {
network = node.v2ray_transport,
security = node.v2ray_stream_security,
tlsSettings = (node.v2ray_stream_security == "tls") and {
serverName = node.tls_serverName,
allowInsecure = (node.tls_allowInsecure == "1") and true or
false
} or nil,
tcpSettings = (node.v2ray_transport == "tcp" and
node.v2ray_protocol ~= "socks") and {
header = {
type = node.v2ray_tcp_guise,
request = {
path = node.v2ray_tcp_guise_http_path or {"/"},
headers = {
Host = node.v2ray_tcp_guise_http_host or {}
}
} or {}
}
} or nil,
kcpSettings = (node.v2ray_transport == "mkcp") and {
mtu = tonumber(node.v2ray_mkcp_mtu),
tti = tonumber(node.v2ray_mkcp_tti),
uplinkCapacity = tonumber(node.v2ray_mkcp_uplinkCapacity),
downlinkCapacity = tonumber(node.v2ray_mkcp_downlinkCapacity),
congestion = (node.v2ray_mkcp_congestion == "1") and true or
false,
readBufferSize = tonumber(node.v2ray_mkcp_readBufferSize),
writeBufferSize = tonumber(node.v2ray_mkcp_writeBufferSize),
header = {type = node.v2ray_mkcp_guise}
} or nil,
wsSettings = (node.v2ray_transport == "ws") and {
path = node.v2ray_ws_path or "",
headers = (node.v2ray_ws_host ~= nil) and
{Host = node.v2ray_ws_host} or nil
} or nil,
httpSettings = (node.v2ray_transport == "h2") and
{path = node.v2ray_h2_path, host = node.v2ray_h2_host} or
nil,
dsSettings = (node.v2ray_transport == "ds") and
{path = node.v2ray_ds_path} or nil,
quicSettings = (node.v2ray_transport == "quic") and {
security = node.v2ray_quic_security,
key = node.v2ray_quic_key,
header = {type = node.v2ray_quic_guise}
} or nil
} or nil,
settings = {
vnext = (node.v2ray_protocol == "vmess") and {
{
address = node.address,
port = tonumber(node.port),
users = {
{
id = node.v2ray_VMess_id,
alterId = tonumber(node.v2ray_VMess_alterId),
level = tonumber(node.v2ray_VMess_level),
security = node.v2ray_security
}
}
}
} or nil,
servers = (node.v2ray_protocol == "socks") and {
{
address = node.address,
port = tonumber(node.port),
users = (node.username and node.password) and
{{user = node.username, pass = node.password}} or
nil
}
} or nil
}
}
end
return result
end
if socks_proxy_port ~= "nil" then
table.insert(inbounds, {
listen = "0.0.0.0",
port = socks_proxy_port,
protocol = "socks",
settings = {auth = "noauth", udp = true, ip = "127.0.0.1"}
})
network = "tcp,udp"
end
if redir_port ~= "nil" then
table.insert(inbounds, {
port = redir_port,
protocol = "dokodemo-door",
settings = {network = proto, followRedirect = true},
sniffing = {enabled = true, destOverride = {"http", "tls"}}
})
if proto == "tcp" and node.v2ray_tcp_socks == "1" then
table.insert(inbounds, {
listen = "0.0.0.0",
port = tonumber(node.v2ray_tcp_socks_port),
protocol = "socks",
settings = {
auth = node.v2ray_tcp_socks_auth,
accounts = (node.v2ray_tcp_socks_auth == "password") and {
{
user = node.v2ray_tcp_socks_auth_username,
pass = node.v2ray_tcp_socks_auth_password
}
} or nil,
udp = true
}
})
end
end
if node.v2ray_balancing_node then
local nodes = node.v2ray_balancing_node
local length = #nodes
for i = 1, length do
local node = ucursor:get_all("passwall", nodes[i])
local outbound = gen_outbound(node)
if outbound then table.insert(outbounds, outbound) end
end
routing = {
domainStrategy = "IPOnDemand",
balancers = {{tag = "balancer", selector = nodes}},
rules = {
{type = "field", network = "tcp,udp", balancerTag = "balancer"}
}
}
end
-- 额外传出连接
table.insert(outbounds,
{protocol = "freedom", tag = "direct", settings = {keep = ""}})
local v2ray = {
log = {
-- error = "/var/log/v2ray.log",
loglevel = "warning"
},
-- 传入连接
inbounds = inbounds,
-- 传出连接
outbounds = outbounds,
-- 路由
routing = routing
}
print(json.stringify(v2ray, 1))

View File

@ -1,222 +0,0 @@
local ucursor = require"luci.model.uci".cursor()
local sys = require "luci.sys"
local json = require "luci.jsonc"
local node_section = arg[1]
local proto = arg[2]
local redir_port = arg[3]
local socks_proxy_port = arg[4]
local node = ucursor:get_all("passwall", node_section)
local inbounds = {}
local outbounds = {}
local network = proto
local routing = nil
local function gen_outbound(node, tag)
local result = nil
if node then
local node_id = node[".name"]
if node.type ~= "V2ray" then
if node.type == "Socks5" then
node.v2ray_protocol = "socks"
node.v2ray_transport = "tcp"
else
local node_type = (proto and proto ~= "nil") and proto or "socks"
local new_port = sys.exec("echo -n $(/usr/share/passwall/app.sh get_new_port auto tcp)")
node.port = new_port
sys.call(string.format("/usr/share/passwall/app.sh gen_start_config %s %s %s %s %s %s",
node_id, new_port, "SOCKS",
"/var/etc/passwall/v2_shunt_" .. node_type .. "_" .. node_id .. ".json", "4", "127.0.0.1"))
node.v2ray_protocol = "socks"
node.v2ray_transport = "tcp"
node.address = "127.0.0.1"
end
end
result = {
tag = tag,
protocol = node.v2ray_protocol or "vmess",
mux = {
enabled = (node.v2ray_mux == "1") and true or false,
concurrency = (node.v2ray_mux_concurrency) and tonumber(node.v2ray_mux_concurrency) or 8
},
-- 底层传输配置
streamSettings = (node.v2ray_protocol == "vmess") and {
network = node.v2ray_transport,
security = node.v2ray_stream_security,
tlsSettings = (node.v2ray_stream_security == "tls") and {
serverName = node.tls_serverName,
allowInsecure = (node.tls_allowInsecure == "1") and true or false
} or nil,
tcpSettings = (node.v2ray_transport == "tcp" and
node.v2ray_protocol ~= "socks") and {
header = {
type = node.v2ray_tcp_guise,
request = {
path = node.v2ray_tcp_guise_http_path or {"/"},
headers = {
Host = node.v2ray_tcp_guise_http_host or {}
}
} or {}
}
} or nil,
kcpSettings = (node.v2ray_transport == "mkcp") and {
mtu = tonumber(node.v2ray_mkcp_mtu),
tti = tonumber(node.v2ray_mkcp_tti),
uplinkCapacity = tonumber(node.v2ray_mkcp_uplinkCapacity),
downlinkCapacity = tonumber(node.v2ray_mkcp_downlinkCapacity),
congestion = (node.v2ray_mkcp_congestion == "1") and true or false,
readBufferSize = tonumber(node.v2ray_mkcp_readBufferSize),
writeBufferSize = tonumber(node.v2ray_mkcp_writeBufferSize),
header = {type = node.v2ray_mkcp_guise}
} or nil,
wsSettings = (node.v2ray_transport == "ws") and {
path = node.v2ray_ws_path or "",
headers = (node.v2ray_ws_host ~= nil) and
{Host = node.v2ray_ws_host} or nil
} or nil,
httpSettings = (node.v2ray_transport == "h2") and
{path = node.v2ray_h2_path, host = node.v2ray_h2_host} or
nil,
dsSettings = (node.v2ray_transport == "ds") and
{path = node.v2ray_ds_path} or nil,
quicSettings = (node.v2ray_transport == "quic") and {
security = node.v2ray_quic_security,
key = node.v2ray_quic_key,
header = {type = node.v2ray_quic_guise}
} or nil
} or nil,
settings = {
vnext = (node.v2ray_protocol == "vmess") and {
{
address = node.address,
port = tonumber(node.port),
users = {
{
id = node.v2ray_VMess_id,
alterId = tonumber(node.v2ray_VMess_alterId),
level = tonumber(node.v2ray_VMess_level),
security = node.v2ray_security
}
}
}
} or nil,
servers = (node.v2ray_protocol == "socks") and {
{
address = node.address,
port = tonumber(node.port),
users = (node.username and node.password) and
{{user = node.username, pass = node.password}} or nil
}
} or nil
}
}
end
return result
end
if socks_proxy_port ~= "nil" then
table.insert(inbounds, {
listen = "0.0.0.0",
port = socks_proxy_port,
protocol = "socks",
settings = {auth = "noauth", udp = true, ip = "127.0.0.1"}
})
network = "tcp,udp"
end
if redir_port ~= "nil" then
table.insert(inbounds, {
port = redir_port,
protocol = "dokodemo-door",
settings = {network = proto, followRedirect = true},
sniffing = {enabled = true, destOverride = {"http", "tls"}}
})
if proto == "tcp" and node.v2ray_tcp_socks == "1" then
table.insert(inbounds, {
listen = "0.0.0.0",
port = tonumber(node.v2ray_tcp_socks_port),
protocol = "socks",
settings = {
auth = node.v2ray_tcp_socks_auth,
accounts = (node.v2ray_tcp_socks_auth == "password") and {
{
user = node.v2ray_tcp_socks_auth_username,
pass = node.v2ray_tcp_socks_auth_password
}
} or nil,
udp = true
}
})
end
end
local rules = {}
local youtube_node_id = node.youtube_node or nil
if youtube_node_id and youtube_node_id ~= "nil" then
local youtube_node = ucursor:get_all("passwall", youtube_node_id)
local youtube_outbound = gen_outbound(youtube_node, "youtube")
if youtube_outbound then
table.insert(outbounds, youtube_outbound)
local rule = {
type = "field",
domain = {
"youtube", "youtube.com", "youtu.be", "googlevideo.com",
"ytimg.com", "gvt2.com"
},
outboundTag = "youtube"
}
table.insert(rules, rule)
end
end
local netflix_node_id = node.netflix_node or nil
if netflix_node_id and netflix_node_id ~= "nil" then
local netflix_node = ucursor:get_all("passwall", netflix_node_id)
local netflix_outbound = gen_outbound(netflix_node, "netflix")
if netflix_outbound then
table.insert(outbounds, netflix_outbound)
local rule = {
type = "field",
domain = {
"netflix", "netflix.com", "nflxso.net", "nflxext.com",
"nflximg.com", "nflximg.net", "nflxvideo.net", "fast.com"
},
outboundTag = "netflix"
}
table.insert(rules, rule)
end
end
local default_node_id = node.default_node or nil
if default_node_id and default_node_id ~= "nil" then
local default_node = ucursor:get_all("passwall", default_node_id)
local default_outbound = gen_outbound(default_node, "default")
if default_outbound then
table.insert(outbounds, default_outbound)
local rule = {
type = "field",
outboundTag = "default",
network = network
}
table.insert(rules, rule)
end
end
routing = {domainStrategy = "IPOnDemand", rules = rules}
-- 额外传出连接
table.insert(outbounds, {protocol = "freedom", tag = "direct", settings = {keep = ""}})
local v2ray = {
log = {
-- error = "/var/log/v2ray.log",
loglevel = "warning"
},
-- 传入连接
inbounds = inbounds,
-- 传出连接
outbounds = outbounds,
-- 路由
routing = routing
}
print(json.stringify(v2ray, 1))

View File

@ -99,9 +99,7 @@ function to_download(url)
local tmp_file = util.trim(util.exec("mktemp -u -t kcptun_download.XXXXXX"))
local result = api.exec(api.wget,
{"-O", tmp_file, url, api._unpack(api.wget_args)},
nil, api.command_timeout) == 0
local result = api.exec(api.curl, {api._unpack(api.curl_args), "-o", tmp_file, url}, nil, api.command_timeout) == 0
if not result then
api.exec("/bin/rm", {"-f", tmp_file})

View File

@ -1,110 +0,0 @@
module("luci.model.cbi.passwall.api.passwall", package.seeall)
local fs = require "nixio.fs"
local sys = require "luci.sys"
local util = require "luci.util"
local i18n = require "luci.i18n"
local api = require "luci.model.cbi.passwall.api.api"
local luci_api =
"https://api.github.com/repos/lienol/openwrt-package/releases/latest"
function get_luci_version()
local ipkg = require "luci.model.ipkg"
local package_name = "luci-app-passwall"
local package_info = ipkg.info(package_name) or {}
if next(package_info) ~= nil then
return package_info[package_name]["Version"]
end
return ""
end
function to_check()
local json = api.get_api_json(luci_api)
if json.tag_name == nil then
return {
code = 1,
error = i18n.translate("Get remote version info failed.")
}
end
local remote_version = json.tag_name:match("[^v]+")
local needs_update = api.compare_versions(get_luci_version(client_file),
"<", remote_version)
local html_url, download_url
if needs_update then
html_url = json.html_url
for _, v in ipairs(json.assets) do
local n = v.name
if n then
if n:match("luci%-app%-passwall") then
download_url = v.browser_download_url
end
end
end
end
if needs_update and not download_url then
return {
code = 1,
now_version = get_luci_version(),
version = remote_version,
html_url = html_url,
error = i18n.translate(
"New version found, but failed to get new version download url.")
}
end
return {
code = 0,
update = needs_update,
now_version = get_luci_version(),
version = remote_version,
url = {html = html_url, download = download_url}
}
end
function update_luci(url, save)
if not url or url == "" then
return {code = 1, error = i18n.translate("Download url is required.")}
end
sys.call("/bin/rm -f /tmp/luci_passwall.*.ipk")
local tmp_file =
util.trim(util.exec("mktemp -u -t luci_passwall.XXXXXX")) .. ".ipk"
local result = api.exec(api.wget,
{"-O", tmp_file, url, api._unpack(api.wget_args)},
nil, api.command_timeout) == 0
if not result then
api.exec("/bin/rm", {"-f", tmp_file})
return {
code = 1,
error = i18n.translatef("File download failed or timed out: %s", url)
}
end
api.exec("/bin/opkg", {"remove", "luci-app-passwall"})
local opkg_args = {"--force-downgrade", "--force-reinstall"}
if save ~= "true" then opkg_args[#opkg_args + 1] = "--force-maintainer" end
result =
api.exec("/bin/opkg", {"install", tmp_file, api._unpack(opkg_args)}) ==
0
if not result then
api.exec("/bin/rm", {"-f", tmp_file})
return {code = 1, error = i18n.translate("Package update failed.")}
end
api.exec("/bin/rm", {"-f", tmp_file})
api.exec("/bin/rm", {"-rf", "/tmp/luci-indexcache", "/tmp/luci-modulecache"})
return {code = 0}
end

View File

@ -95,9 +95,7 @@ function to_download(url)
local tmp_file = util.trim(util.exec("mktemp -u -t v2ray_download.XXXXXX"))
local result = api.exec(api.wget,
{"-O", tmp_file, url, api._unpack(api.wget_args)},
nil, api.command_timeout) == 0
local result = api.exec(api.curl, {api._unpack(api.curl_args), "-o", tmp_file, url}, nil, api.command_timeout) == 0
if not result then
api.exec("/bin/rm", {"-f", tmp_file})

View File

@ -1,20 +1,22 @@
local uci = require"luci.model.uci".cursor()
local api = require "luci.model.cbi.passwall.api.api"
local appname = "passwall"
local n = {}
local nodes_table = {}
uci:foreach(appname, "nodes", function(e)
if e.type and e.remarks and e.address and e.port then
if (e.type == "V2ray_balancing" or e.type == "V2ray_shunt") or (e.address:match("[\u4e00-\u9fa5]") and e.address:find("%.") and e.address:sub(#e.address) ~= ".") then
n[e[".name"]] = "%s[%s] %s:%s" % {e.type, e.remarks, e.address, e.port}
if e.type and e.remarks then
local remarks = ""
if e.type == "V2ray" and (e.v2ray_protocol == "_balancing" or e.v2ray_protocol == "_shunt") then
remarks = "%s[%s] " % {translatef(e.type .. e.v2ray_protocol), e.remarks}
else
remarks = "%s[%s] %s:%s" % {e.type, e.remarks, e.address, e.port}
end
nodes_table[#nodes_table + 1] = {
id = e[".name"],
remarks = remarks
}
end
end)
local key_table = {}
for key, _ in pairs(n) do table.insert(key_table, key) end
table.sort(key_table)
m = Map(appname)
-- [[ Auto Switch Settings ]]--
@ -32,15 +34,14 @@ o = s:option(Value, "testing_time", translate("How often is a diagnosis made"),
o.default = "3"
---- TCP Node
-- local tcp_node_num = tonumber(api.uci_get_type("global_other", "tcp_node_num", 1))
-- local tcp_node_num = tonumber(m:get("@global_other[0]", "tcp_node_num") or 1)
-- 暂时只支持TCP1
local tcp_node_num = 1
for i = 1, tcp_node_num, 1 do
o = s:option(DynamicList, "tcp_node" .. i,
"TCP " .. i .. " " .. translate("List of backup nodes"),
translate(
"List of backup nodes, the first of which must be the primary node and the others the standby node."))
for _, key in pairs(key_table) do o:value(key, n[key]) end
o = s:option(DynamicList, "tcp_node" .. i, "TCP " .. i .. " " .. translate("List of backup nodes"), translate("List of backup nodes, the first of which must be the primary node and the others the standby node."))
for k, v in pairs(nodes_table) do
o:value(v.id, v.remarks)
end
end
return m

View File

@ -1,9 +1,7 @@
local o = require "luci.dispatcher"
local fs = require "nixio.fs"
local sys = require "luci.sys"
local ipkg = require("luci.model.ipkg")
local uci = require"luci.model.uci".cursor()
local api = require "luci.model.cbi.passwall.api.api"
local appname = "passwall"
local function is_installed(e) return ipkg.installed(e) end
@ -14,36 +12,32 @@ local function is_finded(e)
false
end
local n = {}
local nodes_table = {}
uci:foreach(appname, "nodes", function(e)
local type = e.type
if type == nil then type = "" end
local address = e.address
if address == nil then address = "" end
-- if (type == "V2ray_balancing" or type == "V2ray_shunt") or (address:match("[\u4e00-\u9fa5]") and address:find("%.") and address:sub(#address) ~= ".") then
if type and address and e.remarks then
if e.use_kcp and e.use_kcp == "1" then
n[e[".name"]] = "%s+%s[%s] %s" %
{translate(type), "Kcptun", e.remarks, address}
if e.type and e.remarks then
local remarks = ""
if e.type == "V2ray" and (e.v2ray_protocol == "_balancing" or e.v2ray_protocol == "_shunt") then
remarks = "%s[%s] " % {translatef(e.type .. e.v2ray_protocol), e.remarks}
else
n[e[".name"]] = "%s[%s] %s" %
{translate(type), e.remarks, address}
if e.use_kcp and e.use_kcp == "1" then
remarks = "%s+%s[%s] %s" % {e.type, "Kcptun", e.remarks, address}
else
remarks = "%s[%s] %s:%s" % {e.type, e.remarks, e.address, e.port}
end
end
nodes_table[#nodes_table + 1] = {
id = e[".name"],
remarks = remarks
}
end
-- end
end)
local key_table = {}
for key, _ in pairs(n) do table.insert(key_table, key) end
table.sort(key_table)
m = Map(appname)
local status_use_big_icon = api.uci_get_type("global_other",
"status_use_big_icon", 1)
local status_use_big_icon = m:get("@global_other[0]", "status_use_big_icon") or 1
if status_use_big_icon and tonumber(status_use_big_icon) == 1 then
m:append(Template("passwall/global/status"))
m:append(Template(appname .. "/global/status"))
else
m:append(Template("passwall/global/status2"))
m:append(Template(appname .. "/global/status2"))
end
-- [[ Global Settings ]]--
@ -57,8 +51,7 @@ o = s:option(Flag, "enabled", translate("Main switch"))
o.rmempty = false
---- TCP Node
local tcp_node_num = tonumber(
api.uci_get_type("global_other", "tcp_node_num", 1))
local tcp_node_num = tonumber(m:get("@global_other[0]", "tcp_node_num") or 1)
for i = 1, tcp_node_num, 1 do
if i == 1 then
o = s:option(ListValue, "tcp_node" .. i, translate("TCP Node"))
@ -68,41 +61,24 @@ for i = 1, tcp_node_num, 1 do
translate("TCP Node") .. " " .. i)
end
o:value("nil", translate("Close"))
for _, key in pairs(key_table) do o:value(key, n[key]) end
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
end
---- UDP Node
local udp_node_num = tonumber(
api.uci_get_type("global_other", "udp_node_num", 1))
local udp_node_num = tonumber(m:get("@global_other[0]", "udp_node_num") or 1)
for i = 1, udp_node_num, 1 do
if i == 1 then
o = s:option(ListValue, "udp_node" .. i, translate("UDP Node"))
-- o.description = translate("For Game Mode or DNS resolution and more.") .. translate("The selected server will not use Kcptun.")
o:value("nil", translate("Close"))
o:value("tcp", translate("Same as the tcp node"))
o:value("tcp_", translate("Same as the tcp node") .. "" .. translate("New process") .. "")
else
o = s:option(ListValue, "udp_node" .. i,
translate("UDP Node") .. " " .. i)
o:value("nil", translate("Close"))
end
for _, key in pairs(key_table) do o:value(key, n[key]) end
end
---- Socks Node
local socks_node_num = tonumber(api.uci_get_type("global_other",
"socks_node_num", 1))
for i = 1, socks_node_num, 1 do
if i == 1 then
o = s:option(ListValue, "socks_node" .. i, translate("Socks Node"))
-- o.description = translate("The client can use the router's Socks proxy.")
o:value("nil", translate("Close"))
o:value("tcp", translate("Same as the tcp node"))
else
o = s:option(ListValue, "socks_node" .. i,
translate("Socks Node") .. " " .. i)
o:value("nil", translate("Close"))
end
for _, key in pairs(key_table) do o:value(key, n[key]) end
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
end
o = s:option(Value, "up_china_dns", translate("China DNS Server") .. "(UDP)")
@ -125,19 +101,20 @@ o = s:option(ListValue, "dns_mode", translate("DNS Mode"))
-- o.description = translate("if has problem, please try another mode.<br />if you use no patterns are used, DNS of wan will be used by default as upstream of dnsmasq.")
o.rmempty = false
o:reset_values()
if is_finded("chinadns-ng") then o:value("chinadns-ng", "ChinaDNS-NG") end
if is_finded("chinadns-ng") then
o:value("chinadns-ng", "ChinaDNS-NG")
end
if is_installed("pdnsd") or is_installed("pdnsd-alt") or is_finded("pdnsd") then
o:value("pdnsd", "pdnsd")
end
if is_finded("dns2socks") then
o:value("dns2socks",
"dns2socks + " .. translate("Use Socks Node Resolve DNS"))
o:value("dns2socks", "dns2socks")
end
o:value("local_7913", translate("Use local port 7913 as DNS"))
o:value("nonuse", translate("No patterns are used"))
---- Upstream trust DNS Server for ChinaDNS-NG
o = s:option(Value, "up_trust_chinadns_ng_dns",
o = s:option(ListValue, "up_trust_chinadns_ng_dns",
translate("Upstream trust DNS Server for ChinaDNS-NG") .. "(UDP)")
-- o.description = translate("You can use other resolving DNS services as trusted DNS, Example: dns2socks, dns-forwarder... 127.0.0.1#5353<br />Only use two at most, english comma separation, If you do not fill in the # and the following port, you are using port 53.")
o.default = "pdnsd"
@ -145,41 +122,46 @@ if is_installed("pdnsd") or is_installed("pdnsd-alt") or is_finded("pdnsd") then
o:value("pdnsd", "pdnsd + " .. translate("Use TCP Node Resolve DNS"))
end
if is_finded("dns2socks") then
o:value("dns2socks",
"dns2socks + " .. translate("Use Socks Node Resolve DNS"))
o:value("dns2socks", "dns2socks")
end
o:value("8.8.4.4,8.8.8.8", "8.8.4.4, 8.8.8.8 (Google DNS)")
o:value("208.67.222.222,208.67.220.220",
"208.67.222.222, 208.67.220.220 (Open DNS)")
o:value("udp", translate("Use UDP Node Resolve DNS"))
o:depends("dns_mode", "chinadns-ng")
---- Use TCP Node Resolve DNS
--[[ if is_installed("pdnsd") or is_installed("pdnsd-alt") or is_finded("pdnsd") then
o = s:option(Flag, "use_tcp_node_resolve_dns",
translate("Use TCP Node Resolve DNS"))
-- o.description = translate("If checked, DNS is resolved using the TCP node.")
o = s:option(Flag, "use_tcp_node_resolve_dns", translate("Use TCP Node Resolve DNS"))
o.description = translate("If checked, DNS is resolved using the TCP node.")
o.default = 1
o:depends("dns_mode", "pdnsd")
end
--]]
o = s:option(Value, "dns2socks_forward", translate("DNS Address"))
o = s:option(Value, "socks_server", translate("Socks Server"))
o.default = "127.0.0.1:1080"
o:depends({dns_mode = "dns2socks"})
o:depends({dns_mode = "chinadns-ng", up_trust_chinadns_ng_dns = "dns2socks"})
o = s:option(Flag, "fair_mode", translate("Fair Mode"))
o.default = "1"
o:depends({dns_mode = "chinadns-ng"})
---- DNS Forward
o = s:option(Value, "dns_forward", translate("DNS Address"))
o.default = "8.8.4.4"
o:value("8.8.4.4", "8.8.4.4 (Google DNS)")
o:value("8.8.8.8", "8.8.8.8 (Google DNS)")
o:value("208.67.222.222", "208.67.222.222 (Open DNS)")
o:value("208.67.220.220", "208.67.220.220 (Open DNS)")
o:depends("dns_mode", "dns2socks")
o:depends("up_trust_chinadns_ng_dns", "dns2socks")
o:depends({dns_mode = "chinadns-ng"})
o:depends({dns_mode = "dns2socks"})
o:depends({dns_mode = "pdnsd"})
---- DNS Forward
o = s:option(Value, "dns_forward", translate("DNS Address"))
o.default = "8.8.4.4, 8.8.8.8"
o:value("8.8.4.4, 8.8.8.8", "8.8.4.4, 8.8.8.8 (Google DNS)")
o:value("208.67.222.222", "208.67.222.222 (Open DNS)")
o:value("208.67.220.220", "208.67.220.220 (Open DNS)")
o:depends("dns_mode", "pdnsd")
o:depends("up_trust_chinadns_ng_dns", "pdnsd")
o = s:option(Flag, "dns_cache", translate("DNS Cache"))
o.default = "1"
o:depends({dns_mode = "chinadns-ng", up_trust_chinadns_ng_dns = "pdnsd"})
o:depends({dns_mode = "chinadns-ng", up_trust_chinadns_ng_dns = "dns2socks"})
o:depends({dns_mode = "dns2socks"})
o:depends({dns_mode = "pdnsd"})
---- TCP Default Proxy Mode
o = s:option(ListValue, "tcp_proxy_mode",
@ -227,12 +209,12 @@ o.default = "default"
o.rmempty = false
---- Tips
s:append(Template("passwall/global/tips"))
s:append(Template(appname .. "/global/tips"))
--[[
local apply = luci.http.formvalue("cbi.apply")
if apply then
os.execute("/etc/init.d/passwall restart")
os.execute("/etc/init.d/" .. appname .." restart")
end
--]]

View File

@ -1,30 +1,28 @@
local e = require "nixio.fs"
local e = require "luci.sys"
local net = require"luci.model.network".init()
local uci = require"luci.model.uci".cursor()
local net = require "luci.model.network".init()
local uci = require "luci.model.uci".cursor()
local appname = "passwall"
local n = {}
local nodes_table = {}
uci:foreach(appname, "nodes", function(e)
if e.type and e.remarks and e.port and e.address and e.address ~= "127.0.0.1" then
if e.address:match("[\u4e00-\u9fa5]") and e.address:find("%.") and e.address:sub(#e.address) ~= "." then
e.remark = "%s[%s] %s:%s" % {translate(e.type), e.remarks, e.address, e.port}
n[e[".name"]] = e
nodes_table[#nodes_table + 1] = {
id = e[".name"],
remarks = "%s[%s] %s:%s" % {translate(e.type), e.remarks, e.address, e.port},
obj = e
}
end
end
end)
local key_table = {}
for key, _ in pairs(n) do table.insert(key_table, key) end
table.sort(key_table)
m = Map(appname)
-- [[ Haproxy Settings ]]--
s = m:section(TypedSection, "global_haproxy", translate("Load Balancing"))
s.anonymous = true
s:append(Template("passwall/haproxy/status"))
s:append(Template(appname .. "/haproxy/status"))
---- Balancing Enable
o = s:option(Flag, "balancing_enable", translate("Enable Load Balancing"))
@ -63,9 +61,7 @@ o.rmempty = false
---- Node Address
o = s:option(Value, "lbss", translate("Node Address"))
for _, key in pairs(key_table) do
o:value(n[key].address .. ":" .. n[key].port, n[key].remark)
end
for k, v in pairs(nodes_table) do o:value(v.obj.address .. ":" .. v.obj.port, v.remarks) end
o.rmempty = false
---- Node Port

View File

@ -55,7 +55,7 @@ local v2ray_header_type_list = {
}
m = Map(appname, translate("Node Config"))
m.redirect = d.build_url("admin", "vpn", "passwall")
m.redirect = d.build_url("admin", "vpn", appname)
s = m:section(NamedSection, arg[1], "nodes", "")
s.addremove = false
@ -68,14 +68,16 @@ remarks.rmempty = false
type = s:option(ListValue, "type", translate("Type"))
if ((is_installed("redsocks2") or is_finded("redsocks2")) or
(is_installed("ipt2socks") or is_finded("ipt2socks"))) then
type:value("Socks5", translate("Socks5"))
type:value("Socks", translate("Socks"))
end
if is_finded("ss-redir") then
type:value("SS", translate("Shadowsocks"))
end
if is_finded("ssr-redir") then
type:value("SSR", translate("ShadowsocksR"))
end
if is_finded("ss-redir") then type:value("SS", translate("Shadowsocks")) end
if is_finded("ssr-redir") then type:value("SSR", translate("ShadowsocksR")) end
if is_installed("v2ray") or is_finded("v2ray") then
type:value("V2ray", translate("V2ray"))
type:value("V2ray_balancing", translate("V2ray Balancing"))
type:value("V2ray_shunt", translate("V2ray Shunt"))
end
if is_installed("brook") or is_finded("brook") then
type:value("Brook", translate("Brook"))
@ -84,14 +86,50 @@ if is_installed("trojan") or is_finded("trojan") then
type:value("Trojan", translate("Trojan"))
end
v2ray_protocol = s:option(ListValue, "v2ray_protocol",
translate("V2ray Protocol"))
v2ray_protocol = s:option(ListValue, "v2ray_protocol", translate("Protocol"))
v2ray_protocol:value("vmess", translate("Vmess"))
v2ray_protocol:value("http", translate("HTTP"))
v2ray_protocol:value("socks", translate("Socks"))
v2ray_protocol:value("shadowsocks", translate("Shadowsocks"))
v2ray_protocol:value("_balancing", translate("Balancing"))
v2ray_protocol:value("_shunt", translate("Shunt"))
v2ray_protocol:depends("type", "V2ray")
local nodes_table = {}
uci:foreach(appname, "nodes", function(e)
if e.type and e.remarks and e.port then
if e.address:match("[\u4e00-\u9fa5]") and e.address:find("%.") and e.address:sub(#e.address) ~= "." then
nodes_table[#nodes_table + 1] = {
id = e[".name"],
remarks = "%s[%s] %s:%s" % {e.type, e.remarks, e.address, e.port}
}
end
end
end)
-- 负载均衡列表
v2ray_balancing_node = s:option(DynamicList, "v2ray_balancing_node", translate("Load balancing node list"), translate("Load balancing node list, <a target='_blank' href='https://toutyrater.github.io/routing/balance2.html'>document</a>"))
for k, v in pairs(nodes_table) do v2ray_balancing_node:value(v.id, v.remarks) end
v2ray_balancing_node:depends("v2ray_protocol", "_balancing")
-- 分流
uci:foreach(appname, "shunt_rules", function(e)
o = s:option(ListValue, e[".name"], translate(e.remarks))
o:value("nil", translate("Close"))
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
o:depends("v2ray_protocol", "_shunt")
o = s:option(Flag, e[".name"] .. "_proxy", translate(e.remarks) .. translate("Preproxy"), translate("Use the default node for the transit."))
o.default = 0
o:depends("v2ray_protocol", "_shunt")
end)
default_node = s:option(ListValue, "default_node", translate("Default") .. " " .. translate("Node"))
default_node:value("nil", translate("Close"))
for k, v in pairs(nodes_table) do default_node:value(v.id, v.remarks) end
default_node:depends("v2ray_protocol", "_shunt")
-- Brook协议
brook_protocol = s:option(ListValue, "brook_protocol",
translate("Brook Protocol"))
brook_protocol:value("client", translate("Brook"))
@ -101,70 +139,28 @@ brook_protocol:depends("type", "Brook")
brook_tls = s:option(Flag, "brook_tls", translate("Use TLS"))
brook_tls:depends("brook_protocol", "wsclient")
local n = {}
uci:foreach(appname, "nodes", function(e)
if e.type and e.remarks and e.port then
if e.address:match("[\u4e00-\u9fa5]") and e.address:find("%.") and e.address:sub(#e.address) ~= "." then
n[e[".name"]] = "%s[%s] %s:%s" % {e.type, e.remarks, e.address, e.port}
end
end
end)
local key_table = {}
for key, _ in pairs(n) do table.insert(key_table, key) end
table.sort(key_table)
v2ray_balancing_node = s:option(DynamicList, "v2ray_balancing_node",
translate("Load balancing node list"),
translate(
"Load balancing node list, <a target='_blank' href='https://toutyrater.github.io/routing/balance2.html'>document</a>"))
for _, key in pairs(key_table) do v2ray_balancing_node:value(key, n[key]) end
v2ray_balancing_node:depends("type", "V2ray_balancing")
youtube_node = s:option(ListValue, "youtube_node",
"Youtube " .. translate("Node"))
youtube_node:value("nil", translate("Close"))
for _, key in pairs(key_table) do youtube_node:value(key, n[key]) end
youtube_node:depends("type", "V2ray_shunt")
youtube_proxy = s:option(Flag, "youtube_proxy", "Youtube " .. translate("Node") .. translate("Preproxy"),
"Youtube " .. translate("Node") .. translate("Use the default node for the transit."))
youtube_proxy.default = 0
youtube_proxy:depends("type", "V2ray_shunt")
netflix_node = s:option(ListValue, "netflix_node",
"Netflix " .. translate("Node"))
netflix_node:value("nil", translate("Close"))
for _, key in pairs(key_table) do netflix_node:value(key, n[key]) end
netflix_node:depends("type", "V2ray_shunt")
netflix_proxy = s:option(Flag, "netflix_proxy", "Netflix " .. translate("Node") .. translate("Preproxy"),
"Netflix " .. translate("Node") .. translate("Use the default node for the transit."))
netflix_proxy.default = 0
netflix_proxy:depends("type", "V2ray_shunt")
default_node = s:option(ListValue, "default_node",
translate("Default") .. " " .. translate("Node"))
default_node:value("nil", translate("Close"))
for _, key in pairs(key_table) do default_node:value(key, n[key]) end
default_node:depends("type", "V2ray_shunt")
address = s:option(Value, "address", translate("Address (Support Domain Name)"))
address.rmempty = false
address:depends("type", "Socks5")
address:depends("type", "Socks")
address:depends("type", "SS")
address:depends("type", "SSR")
address:depends("type", "V2ray")
address:depends({ type = "V2ray", v2ray_protocol = "vmess" })
address:depends({ type = "V2ray", v2ray_protocol = "http" })
address:depends({ type = "V2ray", v2ray_protocol = "socks" })
address:depends({ type = "V2ray", v2ray_protocol = "shadowsocks" })
address:depends("type", "Brook")
address:depends("type", "Trojan")
--[[
use_ipv6 = s:option(Flag, "use_ipv6", translate("Use IPv6"))
use_ipv6.default = 0
use_ipv6:depends("type", "Socks5")
use_ipv6:depends("type", "Socks")
use_ipv6:depends("type", "SS")
use_ipv6:depends("type", "SSR")
use_ipv6:depends("type", "V2ray")
use_ipv6:depends({ type = "V2ray", v2ray_protocol = "vmess" })
use_ipv6:depends({ type = "V2ray", v2ray_protocol = "http" })
use_ipv6:depends({ type = "V2ray", v2ray_protocol = "socks" })
use_ipv6:depends({ type = "V2ray", v2ray_protocol = "shadowsocks" })
use_ipv6:depends("type", "Brook")
use_ipv6:depends("type", "Trojan")
--]]
@ -172,21 +168,24 @@ use_ipv6:depends("type", "Trojan")
port = s:option(Value, "port", translate("Port"))
port.datatype = "port"
port.rmempty = false
port:depends("type", "Socks5")
port:depends("type", "Socks")
port:depends("type", "SS")
port:depends("type", "SSR")
port:depends("type", "V2ray")
port:depends({ type = "V2ray", v2ray_protocol = "vmess" })
port:depends({ type = "V2ray", v2ray_protocol = "http" })
port:depends({ type = "V2ray", v2ray_protocol = "socks" })
port:depends({ type = "V2ray", v2ray_protocol = "shadowsocks" })
port:depends("type", "Brook")
port:depends("type", "Trojan")
username = s:option(Value, "username", translate("Username"))
username:depends("type", "Socks5")
username:depends("type", "Socks")
username:depends("v2ray_protocol", "http")
username:depends("v2ray_protocol", "socks")
password = s:option(Value, "password", translate("Password"))
password.password = true
password:depends("type", "Socks5")
password:depends("type", "Socks")
password:depends("type", "SS")
password:depends("type", "SSR")
password:depends("type", "Brook")
@ -429,10 +428,12 @@ v2ray_quic_guise = s:option(ListValue, "v2ray_quic_guise",
for a, t in ipairs(v2ray_header_type_list) do v2ray_quic_guise:value(t) end
v2ray_quic_guise:depends("v2ray_transport", "quic")
-- [[ 其它 ]]--
-- [[ Mux ]]--
v2ray_mux = s:option(Flag, "v2ray_mux", translate("Mux"))
v2ray_mux:depends("type", "V2ray")
v2ray_mux:depends({ type = "V2ray", v2ray_protocol = "vmess" })
v2ray_mux:depends({ type = "V2ray", v2ray_protocol = "http" })
v2ray_mux:depends({ type = "V2ray", v2ray_protocol = "socks" })
v2ray_mux:depends({ type = "V2ray", v2ray_protocol = "shadowsocks" })
v2ray_mux_concurrency = s:option(Value, "v2ray_mux_concurrency",
translate("Mux Concurrency"))
@ -448,7 +449,7 @@ v2ray_tcp_socks.default = 0
v2ray_tcp_socks:depends("type", "V2ray")
v2ray_tcp_socks_port = s:option(Value, "v2ray_tcp_socks_port",
"Socks5 " .. translate("Port"),
"Socks " .. translate("Port"),
translate("Do not conflict with other ports"))
v2ray_tcp_socks_port.datatype = "port"
v2ray_tcp_socks_port.default = 1080
@ -463,11 +464,11 @@ v2ray_tcp_socks_auth:value("password", translate("User Password"))
v2ray_tcp_socks_auth:depends("v2ray_tcp_socks", "1")
v2ray_tcp_socks_auth_username = s:option(Value, "v2ray_tcp_socks_auth_username",
"Socks5 " .. translate("Username"))
"Socks " .. translate("Username"))
v2ray_tcp_socks_auth_username:depends("v2ray_tcp_socks_auth", "password")
v2ray_tcp_socks_auth_password = s:option(Value, "v2ray_tcp_socks_auth_password",
"Socks5 " .. translate("Password"))
"Socks " .. translate("Password"))
v2ray_tcp_socks_auth_password:depends("v2ray_tcp_socks_auth", "password")
--]]
@ -481,54 +482,4 @@ trojan_cert_path = s:option(Value, "trojan_cert_path",
trojan_cert_path.default = ""
trojan_cert_path:depends("trojan_verify_cert", "1")
-- v2ray_insecure = s:option(Flag, "v2ray_insecure", translate("allowInsecure"))
-- v2ray_insecure:depends("type", "V2ray")
function rmempty_restore()
address.rmempty = true
port.rmempty = true
password.rmempty = true
timeout.rmempty = true
tcp_fast_open.rmempty = true
-- v2ray_protocol.rmempty = true
v2ray_VMess_id.rmempty = true
v2ray_VMess_alterId.rmempty = true
end
type.validate = function(self, value)
rmempty_restore()
if value == "SS" then
address.rmempty = false
port.rmempty = false
password.rmempty = false
timeout.rmempty = false
tcp_fast_open.rmempty = false
elseif value == "SSR" then
address.rmempty = false
port.rmempty = false
password.rmempty = false
timeout.rmempty = false
tcp_fast_open.rmempty = false
elseif value == "V2ray" then
address.rmempty = false
port.rmempty = false
-- v2ray_protocol.rmempty = false
-- v2ray_VMess_id.rmempty = false
-- v2ray_VMess_alterId.rmempty = false
elseif value == "V2ray_balancing" then
elseif value == "Brook" then
address.rmempty = false
port.rmempty = false
password.rmempty = false
elseif value == "Trojan" then
address.rmempty = false
port.rmempty = false
password.rmempty = false
tcp_fast_open.rmempty = false
end
return value
end
v2ray_transport.validate = function(self, value) return value end
return m

View File

@ -1,8 +1,5 @@
local d = require "luci.dispatcher"
local fs = require "nixio.fs"
local sys = require "luci.sys"
local uci = require"luci.model.uci".cursor()
local api = require "luci.model.cbi.passwall.api.api"
local _api = require "luci.model.cbi.passwall.api.api"
local appname = "passwall"
m = Map(appname)
@ -34,48 +31,56 @@ o = s:option(Flag, "show_group", translate("Show Group"))
o.default = 1
-- [[ Add the node via the link ]]--
s:append(Template("passwall/node_list/link_add_node"))
s:append(Template(appname .. "/node_list/link_add_node"))
-- [[ Node List ]]--
s = m:section(TypedSection, "nodes")
-- s.description = translate("Support for more than 10,000 ping nodes and luci does not crash and not slow.")
s.anonymous = true
s.addremove = true
s.template = "cbi/tblsection"
s.extedit = d.build_url("admin", "vpn", "passwall", "node_config", "%s")
s.extedit = d.build_url("admin", "vpn", appname, "node_config", "%s")
function s.create(e, t)
local e = TypedSection.create(e, t)
luci.http
.redirect(d.build_url("admin", "vpn", "passwall", "node_config", e))
local uuid = _api.gen_uuid()
t = uuid
TypedSection.create(e, t)
luci.http.redirect(e.extedit:format(t))
end
function s.remove(t, a)
function s.remove(e, t)
s.map.proceed = true
s.map:del(a)
luci.http.redirect(d.build_url("admin", "vpn", "passwall", "node_list"))
s.map:del(t)
luci.http.redirect(d.build_url("admin", "vpn", appname, "node_list"))
end
if api.uci_get_type("global_other", "show_group", "1") == "1" then
if m:get("@global_other[0]", "show_group") == "1" then
show_group = s:option(DummyValue, "group", translate("Group"))
show_group.cfgvalue = function(t, n)
local group = api.uci_get_type_id(n, "group") or ""
local group = m:get(n, "group") or ""
return group ~= "" and group or ""
end
end
s.sortable = true
-- 简洁模式
if api.uci_get_type("global_other", "compact_display_nodes", "0") == "1" then
if m:get("@global_other[0]", "compact_display_nodes") == "1" then
if show_group then show_group.width = "25%" end
o = s:option(DummyValue, "remarks", translate("Remarks"))
o.cfgvalue = function(t, n)
local str = ""
local is_sub = api.uci_get_type_id(n, "is_sub") or ""
local group = api.uci_get_type_id(n, "group") or ""
local remarks = api.uci_get_type_id(n, "remarks") or ""
local type = api.uci_get_type_id(n, "type") or ""
local address = api.uci_get_type_id(n, "address") or ""
local port = api.uci_get_type_id(n, "port") or ""
local is_sub = m:get(n, "is_sub") or ""
local group = m:get(n, "group") or ""
local remarks = m:get(n, "remarks") or ""
local type = m:get(n, "type") or ""
if type == "V2ray" then
local protocol = m:get(n, "v2ray_protocol")
if protocol == "_balancing" then
type = type .. " 负载均衡"
elseif protocol == "_shunt" then
type = type .. " 分流"
end
end
local address = m:get(n, "address") or ""
local port = m:get(n, "port") or ""
str = str .. translate(type) .. "" .. remarks
if address ~= "" and port ~= "" then
local s = " " .. address .. ":" .. port .. ""
@ -85,7 +90,7 @@ if api.uci_get_type("global_other", "compact_display_nodes", "0") == "1" then
end
else
---- Add Mode
if api.uci_get_type("global_other", "show_add_mode", "1") == "1" then
if m:get("@global_other[0]", "show_add_mode") == "1" then
o = s:option(DummyValue, "add_mode", translate("Add Mode"))
o.cfgvalue = function(t, n)
local v = Value.cfgvalue(t, n)
@ -101,8 +106,20 @@ else
---- Type
o = s:option(DummyValue, "type", translate("Type"))
o.cfgvalue = function(t, n)
local result = ""
local v = Value.cfgvalue(t, n)
if v then return translate(v) end
if v then
result = translate(v)
if v == "V2ray" then
local protocol = m:get(n, "v2ray_protocol")
if protocol == "_balancing" then
result = result .. " 负载均衡"
elseif protocol == "_shunt" then
result = result .. " 分流"
end
end
end
return result
end
---- Remarks
@ -119,32 +136,27 @@ else
o.cfgvalue = function(t, n)
return Value.cfgvalue(t, n) or "---"
end
---- Encrypt Method
--[[ o = s:option(DummyValue, "encrypt_method", translate("Encrypt Method"))
o.width = "15%"
o.cfgvalue = function(t, n)
local str = ""
local type = api.uci_get_type_id(n, "type") or ""
if type == "SSR" then
return api.uci_get_type_id(n, "ssr_encrypt_method")
elseif type == "SS" then
return api.uci_get_type_id(n, "ss_encrypt_method")
elseif type == "V2ray" then
return api.uci_get_type_id(n, "v2ray_security")
end
return str
end--]]
end
---- Ping
o = s:option(DummyValue, "ping", translate("Latency"))
if api.uci_get_type("global_other", "auto_ping", "0") == "0" then
o.template = "passwall/node_list/ping"
if m:get("@global_other[0]", "auto_ping") == "0" then
o.template = appname .. "/node_list/ping"
else
o.template = "passwall/node_list/auto_ping"
o.template = appname .. "/node_list/auto_ping"
end
--[[
o.cfgvalue = function(t, n)
local type = m:get(n, "type") or ""
if type == "V2ray" then
local protocol = m:get(n, "v2ray_protocol","")
if protocol == "_balancing" or protocol == "_shunt" then
return "---"
end
end
end
--]]
m:append(Template("passwall/node_list/node_list"))
m:append(Template(appname .. "/node_list/node_list"))
return m

View File

@ -1,7 +1,6 @@
local e = require "nixio.fs"
local e = require "luci.sys"
local appname = "passwall"
m = Map("passwall")
m = Map(appname)
-- [[ Subscribe Settings ]]--
s = m:section(TypedSection, "global_subscribe", "")
@ -36,20 +35,16 @@ o:depends("auto_update_subscribe", 1)
o = s:option(Button, "_update", translate("Manual subscription"))
o.inputstyle = "apply"
function o.write(e, e)
luci.sys.call(
"lua /usr/share/passwall/subscribe.lua start log > /dev/null 2>&1 &")
luci.http.redirect(luci.dispatcher.build_url("admin", "vpn", "passwall",
"log"))
luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua start log > /dev/null 2>&1 &")
luci.http.redirect(luci.dispatcher.build_url("admin", "vpn", appname, "log"))
end
---- Subscribe Delete All
o = s:option(Button, "_stop", translate("Delete All Subscribe Node"))
o.inputstyle = "remove"
function o.write(e, e)
luci.sys.call(
"lua /usr/share/passwall/subscribe.lua truncate log > /dev/null 2>&1 &")
luci.http.redirect(luci.dispatcher.build_url("admin", "vpn", "passwall",
"log"))
luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua truncate log > /dev/null 2>&1 &")
luci.http.redirect(luci.dispatcher.build_url("admin", "vpn", appname, "log"))
end
filter_enabled = s:option(Flag, "filter_enabled", translate("Filter keyword switch"), translate("When checked, below options can only be take effect."))
@ -62,6 +57,10 @@ o = s:option(Flag, "filter_keyword_discarded", translate("Filter keyword discard
o.default = "1"
o.rmempty = false
o = s:option(Flag, "allowInsecure", translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, V2Ray does not check the validity of the TLS certificate provided by the remote host by default."))
o.default = "1"
o.rmempty = false
s = m:section(TypedSection, "subscribe_list", "",
"<font color='red'>" .. translate(
"Please input the subscription url first, save and submit before updating. If you subscribe to update, it is recommended to delete all subscriptions and then re-subscribe.") ..

View File

@ -1,6 +1,8 @@
local api = require "luci.model.cbi.passwall.api.api"
local _api = require "luci.model.cbi.passwall.api.api"
local uci = require"luci.model.uci".cursor()
local appname = "passwall"
m = Map("passwall")
m = Map(appname)
-- [[ Delay Settings ]]--
s = m:section(TypedSection, "global_delay", translate("Delay Settings"))
@ -73,8 +75,8 @@ o.default = "22,25,53,143,465,587,993,995,80,443"
o:value("1:65535", translate("All"))
o:value("22,25,53,143,465,587,993,995,80,443", translate("Common Use"))
o:value("80,443", translate("Only Web"))
o:value("80:", "80 " .. translate("or more"))
o:value(":443", "443 " .. translate("or less"))
o:value("80:65535", "80 " .. translate("or more"))
o:value("1:443", "443 " .. translate("or less"))
---- UDP Redir Ports
o = s:option(Value, "udp_redir_ports", translate("UDP Redir Ports"))
@ -92,15 +94,6 @@ o:value("2", "2 " .. translate("Process"))
o:value("3", "3 " .. translate("Process"))
o:value("4", "4 " .. translate("Process"))
---- Socks Proxy Port
local socks_node_num = tonumber(api.uci_get_type("global_other",
"socks_node_num", 1))
for i = 1, socks_node_num, 1 do
o = s:option(Value, "socks_proxy_port" .. i, translate("Socks Proxy Port"))
o.datatype = "port"
o.default = "108" .. i
end
--[[
---- Proxy IPv6
o = s:option(Flag, "proxy_ipv6", translate("Proxy IPv6"),
@ -152,14 +145,6 @@ o:value("1")
o:value("2")
o:value("3")
---- Socks Node Number Option
o = s:option(ListValue, "socks_node_num", "Socks" .. translate("Node Number"))
o.default = "1"
o.rmempty = false
o:value("1")
o:value("2")
o:value("3")
---- 状态使用大图标
o = s:option(Flag, "status_use_big_icon", translate("Status Use Big Icon"))
o.default = "1"
@ -176,4 +161,54 @@ o = s:option(Flag, "status_show_ip111", translate("Status Show IP111"))
o.default = "0"
o.rmempty = false
local nodes_table = {}
uci:foreach(appname, "nodes", function(e)
if e.type and e.remarks then
local remarks = ""
if e.type == "V2ray" and (e.v2ray_protocol == "_balancing" or e.v2ray_protocol == "_shunt") then
remarks = "%s[%s] " % {translatef(e.type .. e.v2ray_protocol), e.remarks}
else
if e.use_kcp and e.use_kcp == "1" then
remarks = "%s+%s[%s] %s" % {e.type, "Kcptun", e.remarks, address}
else
remarks = "%s[%s] %s:%s" % {e.type, e.remarks, e.address, e.port}
end
end
nodes_table[#nodes_table + 1] = {
id = e[".name"],
remarks = remarks
}
end
end)
-- [[ Node List ]]--
s = m:section(TypedSection, "socks", translate("Socks Config"))
s.anonymous = true
s.addremove = true
s.template = "cbi/tblsection"
function s.create(e, t)
TypedSection.create(e, _api.gen_uuid())
end
o = s:option(DummyValue, "status", translate("Status"))
o.template = appname .. "/other/socks_status"
---- Enable
o = s:option(Flag, "enabled", translate("Enable"))
o.default = 1
o.rmempty = false
o = s:option(ListValue, "node", translate("Socks Node"))
local tcp_node_num = tonumber(m:get("@global_other[0]", "tcp_node_num") or 1)
for i = 1, tcp_node_num, 1 do
o:value("tcp" .. i, translatef("Same as the tcp %s node", i))
end
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
o = s:option(Value, "port", translate("Listen Port"))
o.datatype = "port"
o.rmempty = false
m:append(Template(appname .. "/other/footer"))
return m

View File

@ -1,17 +1,36 @@
local e = require "nixio.fs"
local e = require "luci.sys"
local d = require "luci.dispatcher"
local appname = "passwall"
m = Map("passwall")
m = Map(appname)
-- [[ Rule Settings ]]--
s = m:section(TypedSection, "global_rules", translate("Rule status"))
s.anonymous = true
s:append(Template("passwall/rule/rule_version"))
s:append(Template(appname .. "/rule/rule_version"))
--[[
o = s:option(Flag, "adblock", translate("Enable adblock"))
o.rmempty = false
]]--
---- Enable custom url
o = s:option(Flag, "enable_custom_url", translate("Enable custom url"))
o.default = 0
o.rmempty = false
---- gfwlist URL
o = s:option(Value, "gfwlist_url", translate("gfwlist Update url"))
o:value("https://cdn.jsdelivr.net/gh/Loukky/gfwlist-by-loukky/gfwlist.txt", translate("Loukky/gfwlist-by-loukky"))
o:value("https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt", translate("gfwlist/gfwlist"))
o.default = "https://cdn.jsdelivr.net/gh/Loukky/gfwlist-by-loukky/gfwlist.txt"
o:depends("enable_custom_url", 1)
----chnroute URL
o = s:option(Value, "chnroute_url", translate("Chnroute Update url"))
o:value("https://ispip.clang.cn/all_cn.txt", translate("Clang.CN"))
o:value("https://ispip.clang.cn/all_cn_cidr.txt", translate("Clang.CN.CIDR"))
o.default = "https://ispip.clang.cn/all_cn.txt"
o:depends("enable_custom_url", 1)
---- Auto Update
o = s:option(Flag, "auto_update", translate("Enable auto update rules"))
o.default = 0
@ -31,16 +50,27 @@ for e = 0, 23 do o:value(e, e .. translate("oclock")) end
o.default = 0
o:depends("auto_update", 1)
s = m:section(TypedSection, "shunt_rules", "V2ray" .. translate("Shunt") .. translate("Rule"))
s.template = "cbi/tblsection"
s.anonymous = false
s.addremove = true
s.extedit = d.build_url("admin", "vpn", appname, "shunt_rules", "%s")
function s.create(e, t)
TypedSection.create(e, t)
luci.http.redirect(e.extedit:format(t))
end
o = s:option(DummyValue, "remarks", translate("Remarks"))
-- [[ App Settings ]]--
s = m:section(TypedSection, "global_app", translate("App Update"),
"<font color='red'>" ..
translate("Please confirm that your firmware supports FPU.") ..
"</font>")
s.anonymous = true
s:append(Template("passwall/rule/passwall_version"))
s:append(Template("passwall/rule/v2ray_version"))
s:append(Template("passwall/rule/kcptun_version"))
s:append(Template("passwall/rule/brook_version"))
s:append(Template(appname .. "/rule/v2ray_version"))
s:append(Template(appname .. "/rule/kcptun_version"))
s:append(Template(appname .. "/rule/brook_version"))
---- V2ray Path
o = s:option(Value, "v2ray_file", translate("V2ray Path"), translate(
@ -57,7 +87,7 @@ o.rmempty = false
--[[
o = s:option(Button, "_check_kcptun", translate("Manually update"), translate("Make sure there is enough space to install Kcptun"))
o.template = "passwall/kcptun"
o.template = appname .. "/kcptun"
o.inputstyle = "apply"
o.btnclick = "onBtnClick_kcptun(this);"
o.id = "_kcptun-check_btn"]] --

View File

@ -0,0 +1,130 @@
#!/usr/bin/lua
local action = arg[1]
local sys = require 'luci.sys'
local jsonc = require "luci.jsonc"
local ucic = require"luci.model.uci".cursor()
local _api = require "luci.model.cbi.passwall.api.api"
local CONFIG = "passwall_server"
local CONFIG_PATH = "/var/etc/" .. CONFIG
local LOG_APP_FILE = "/var/log/" .. CONFIG .. ".log"
local TMP_BIN_PATH = CONFIG_PATH .. "/bin"
local function log(...)
local f, err = io.open(LOG_APP_FILE, "a")
if f and err == nil then
local str = os.date("%Y-%m-%d %H:%M:%S: ") .. table.concat({...}, " ")
f:write(str .. "\n")
f:close()
end
end
local function cmd(cmd)
sys.call(cmd)
end
local function ln_start(s, d, command)
d = TMP_BIN_PATH .. "/" .. d
cmd(string.format('[ ! -f "%s" ] && ln -s %s %s 2>/dev/null', d, s, d))
return string.format("%s >/dev/null 2>&1 &", d .. " " ..command)
end
local function gen_include()
cmd(string.format("echo '#!/bin/sh' > /var/etc/%s.include", CONFIG))
local function extract_rules(a)
local result = "*" .. a
result = result .. "\n" .. sys.exec('iptables-save -t ' .. a .. ' | grep "PSW-SERVER" | sed -e "s/^-A \\(INPUT\\)/-I \\1 1/"')
result = result .. "COMMIT"
return result
end
local f, err = io.open("/var/etc/" .. CONFIG .. ".include", "a")
if f and err == nil then
f:write('iptables-save -c | grep -v "PSW-SERVER" | iptables-restore -c' .. "\n")
f:write('iptables-restore -n <<-EOT' .. "\n")
f:write(extract_rules("filter") .. "\n")
f:write("EOT" .. "\n")
f:close()
end
end
local function start()
local enabled = tonumber(ucic:get(CONFIG, "@global[0]", "enable") or 0)
if enabled == nil or enabled == 0 then
return
end
cmd(string.format("mkdir -p %s %s", CONFIG_PATH, TMP_BIN_PATH))
cmd(string.format("touch %s", LOG_APP_FILE))
cmd("iptables -N PSW-SERVER")
cmd("iptables -I INPUT -j PSW-SERVER")
ucic:foreach(CONFIG, "user", function(user)
local id = user[".name"]
local enable = user.enable
if enable and tonumber(enable) == 1 then
local remarks = user.remarks
local port = tonumber(user.port)
local bin
local config = {}
local config_file = CONFIG_PATH .. "/" .. id .. ".json"
local udp_forward = 1
local type = user.type or ""
if type == "SSR" then
config = require("luci.model.cbi.passwall.server.api.ssr").gen_config(user)
local udp_param = ""
udp_forward = tonumber(user.udp_forward) or 1
if udp_forward == 1 then
udp_param = "-u"
end
bin = ln_start("/usr/bin/ssr-server", "ssr-server", "-c " .. config_file .. " " .. udp_param)
elseif type == "V2ray" then
config = require("luci.model.cbi.passwall.server.api.v2ray").gen_config(user)
bin = ln_start(_api.get_v2ray_path(), "v2ray", "-config=" .. config_file)
elseif type == "Trojan" then
config = require("luci.model.cbi.passwall.server.api.trojan").gen_config(user)
bin = ln_start("/usr/sbin/trojan", "trojan", "-c " .. config_file)
elseif type == "Brook" then
local brook_protocol = user.brook_protocol
local brook_password = user.password
bin = ln_start(_api.get_brook_path(), "brook_" .. id, string.format("%s -l :%s -p %s", brook_protocol, port, brook_password))
end
if next(config) then
local f, err = io.open(config_file, "w")
if f and err == nil then
f:write(jsonc.stringify(config, 1))
f:close()
end
log(string.format("%s %s 生成配置文件并运行 - %s", remarks, port, config_file))
end
if bin then
cmd(bin)
end
local bind_local = user.bind_local or 0
if bind_local and tonumber(bind_local) ~= 1 then
cmd(string.format('iptables -A PSW-SERVER -p tcp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
if udp_forward == 1 then
cmd(string.format('iptables -A PSW-SERVER -p udp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks))
end
end
end
end)
gen_include()
end
local function stop()
cmd(string.format("ps -w | grep -v 'grep' | grep '%s/' | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &", CONFIG_PATH))
cmd("iptables -D INPUT -j PSW-SERVER 2>/dev/null")
cmd("iptables -F PSW-SERVER 2>/dev/null")
cmd("iptables -X PSW-SERVER 2>/dev/null")
cmd(string.format("rm -rf %s %s /var/etc/%s.include", CONFIG_PATH, LOG_APP_FILE, CONFIG))
end
if action then
if action == "start" then
start()
elseif action == "stop" then
stop()
end
end

View File

@ -0,0 +1,15 @@
module("luci.model.cbi.passwall.server.api.ssr", package.seeall)
function gen_config(user)
local config = {}
config.server = {"[::0]", "0.0.0.0"}
config.server_port = tonumber(user.port)
config.password = user.password
config.timeout = tonumber(user.timeout)
config.fast_open = (user.tcp_fast_open and user.tcp_fast_open == "true") and true or false
config.method = user.ssr_encrypt_method
config.protocol = user.protocol
config.protocol_param = user.protocol_param
config.obfs = user.obfs
config.obfs_param = user.obfs_param
return config
end

View File

@ -0,0 +1,36 @@
module("luci.model.cbi.passwall.server.api.trojan", package.seeall)
function gen_config(user)
local config = {
run_type = "server",
local_addr = "0.0.0.0",
local_port = tonumber(user.port),
remote_addr = (user.remote_enable == "1" and user.remote_address) and user.remote_address or nil,
remote_port = (user.remote_enable == "1" and user.remote_port) and user.remote_port or nil,
password = user.password,
log_level = 1,
ssl = {
cert = user.tls_certificateFile,
key = user.tls_keyFile,
key_password = "",
cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA",
cipher_tls13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384",
prefer_server_cipher = true,
alpn = {"http/1.1"},
reuse_session = true,
session_ticket = false,
session_timeout = 600,
plain_http_response = "",
curves = "",
dhparam = ""
},
tcp = {
prefer_ipv4 = false,
no_delay = true,
keep_alive = true,
reuse_port = false,
fast_open = (user.fast_open == "true") and true or false,
fast_open_qlen = 20
}
}
return config
end

View File

@ -0,0 +1,235 @@
module("luci.model.cbi.passwall.server.api.v2ray", package.seeall)
local ucic = require"luci.model.uci".cursor()
function gen_config(user)
local settings = nil
local routing = nil
local outbounds = {
{protocol = "freedom"}, {protocol = "blackhole", tag = "blocked"}
}
if user.v2ray_protocol == "vmess" then
if user.vmess_id then
local clients = {}
for i = 1, #user.vmess_id do
clients[i] = {
id = user.vmess_id[i],
level = tonumber(user.vmess_level),
alterId = tonumber(user.vmess_alterId)
}
end
settings = {clients = clients}
end
elseif user.v2ray_protocol == "socks" then
settings = {
auth = (user.username == nil and user.password == nil) and "noauth" or "password",
accounts = {
{
user = (user.username == nil) and "" or user.username,
pass = (user.password == nil) and "" or user.password
}
}
}
elseif user.v2ray_protocol == "http" then
settings = {
allowTransparent = false,
accounts = {
{
user = (user.username == nil) and "" or user.username,
pass = (user.password == nil) and "" or user.password
}
}
}
elseif user.v2ray_protocol == "shadowsocks" then
settings = {
method = user.v2ray_ss_encrypt_method,
password = user.password,
level = tonumber(user.vmess_level) or 1,
network = user.v2ray_ss_network or "TCP,UDP",
ota = (user.v2ray_ss_ota == '1') and true or false
}
end
if user.accept_lan == nil or user.accept_lan == "0" then
routing = {
domainStrategy = "IPOnDemand",
rules = {
{
type = "field",
ip = {"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"},
outboundTag = "blocked"
}
}
}
end
if user.transit_node and user.transit_node ~= "nil" then
local node = ucic:get_all("passwall", user.transit_node)
if node and node ~= "nil" and node.type and node.type == "V2ray" then
local transit_node = {
tag = "transit",
protocol = node.v2ray_protocol or "vmess",
mux = {
enabled = (node.v2ray_mux == "1") and true or false,
concurrency = (node.v2ray_mux_concurrency) and
tonumber(node.v2ray_mux_concurrency) or 8
},
-- 底层传输配置
streamSettings = (node.v2ray_protocol == "vmess") and {
network = node.v2ray_transport,
security = node.v2ray_stream_security,
tlsSettings = (node.v2ray_stream_security == "tls") and {
serverName = node.tls_serverName,
allowInsecure = (node.tls_allowInsecure == "1") and true or
false
} or nil,
tcpSettings = (node.v2ray_transport == "tcp") and {
header = {
type = node.v2ray_tcp_guise,
request = {
path = node.v2ray_tcp_guise_http_path or {"/"},
headers = {
Host = node.v2ray_tcp_guise_http_host or {}
}
} or {}
}
} or nil,
kcpSettings = (node.v2ray_transport == "mkcp") and {
mtu = tonumber(node.v2ray_mkcp_mtu),
tti = tonumber(node.v2ray_mkcp_tti),
uplinkCapacity = tonumber(node.v2ray_mkcp_uplinkCapacity),
downlinkCapacity = tonumber(
node.v2ray_mkcp_downlinkCapacity),
congestion = (node.v2ray_mkcp_congestion == "1") and
true or false,
readBufferSize = tonumber(node.v2ray_mkcp_readBufferSize),
writeBufferSize = tonumber(
node.v2ray_mkcp_writeBufferSize),
header = {type = node.v2ray_mkcp_guise}
} or nil,
wsSettings = (node.v2ray_transport == "ws") and {
path = node.v2ray_ws_path or "",
headers = (node.v2ray_ws_host ~= nil) and
{Host = node.v2ray_ws_host} or nil
} or nil,
httpSettings = (node.v2ray_transport == "h2") and
{path = node.v2ray_h2_path, host = node.v2ray_h2_host} or
nil,
dsSettings = (node.v2ray_transport == "ds") and
{path = node.v2ray_ds_path} or nil,
quicSettings = (node.v2ray_transport == "quic") and {
security = node.v2ray_quic_security,
key = node.v2ray_quic_key,
header = {type = node.v2ray_quic_guise}
} or nil
} or nil,
settings = {
vnext = (node.v2ray_protocol == "vmess") and {
{
address = node.address,
port = tonumber(node.port),
users = {
{
id = node.v2ray_VMess_id,
alterId = tonumber(node.v2ray_VMess_alterId),
level = tonumber(node.v2ray_VMess_level),
security = node.v2ray_security
}
}
}
} or nil,
servers = (node.v2ray_protocol == "http" or
node.v2ray_protocol == "socks" or node.v2ray_protocol == "shadowsocks") and {
{
address = node.address,
port = tonumber(node.port),
method = node.v2ray_ss_encrypt_method,
password = node.password or "",
ota = (node.v2ray_ss_ota == '1') and true or false,
users = (node.username and node.password) and
{
{
user = node.username or "",
pass = node.password or ""
}
} or nil
}
} or nil
}
}
table.insert(outbounds, 1, transit_node)
end
end
local config = {
log = {
-- error = "/var/log/v2ray.log",
loglevel = "warning"
},
-- 传入连接
inbounds = {
{
listen = (user.bind_local == "1") and "127.0.0.1" or nil,
port = tonumber(user.port),
protocol = user.v2ray_protocol,
-- 底层传输配置
settings = settings,
streamSettings = (user.v2ray_protocol == "vmess") and {
network = user.v2ray_transport,
security = (user.tls_enable == '1') and "tls" or "none",
tlsSettings = (user.tls_enable == '1') and {
-- serverName = (user.tls_serverName),
allowInsecure = false,
disableSystemRoot = false,
certificates = {
{
certificateFile = user.tls_certificateFile,
keyFile = user.tls_keyFile
}
}
} or nil,
tcpSettings = (user.v2ray_transport == "tcp") and {
header = {
type = user.v2ray_tcp_guise,
request = {
path = user.v2ray_tcp_guise_http_path or {"/"},
headers = {
Host = user.v2ray_tcp_guise_http_host or {}
}
} or {}
}
} or nil,
kcpSettings = (user.v2ray_transport == "mkcp") and {
mtu = tonumber(user.v2ray_mkcp_mtu),
tti = tonumber(user.v2ray_mkcp_tti),
uplinkCapacity = tonumber(user.v2ray_mkcp_uplinkCapacity),
downlinkCapacity = tonumber(user.v2ray_mkcp_downlinkCapacity),
congestion = (user.v2ray_mkcp_congestion == "1") and true or false,
readBufferSize = tonumber(user.v2ray_mkcp_readBufferSize),
writeBufferSize = tonumber(user.v2ray_mkcp_writeBufferSize),
header = {type = user.v2ray_mkcp_guise}
} or nil,
wsSettings = (user.v2ray_transport == "ws") and
{
headers = (user.v2ray_ws_host) and {Host = user.v2ray_ws_host} or
nil,
path = user.v2ray_ws_path
} or nil,
httpSettings = (user.v2ray_transport == "h2") and
{path = user.v2ray_h2_path, host = user.v2ray_h2_host} or nil,
dsSettings = (user.v2ray_transport == "ds") and
{path = user.v2ray_ds_path} or nil,
quicSettings = (user.v2ray_transport == "quic") and {
security = user.v2ray_quic_security,
key = user.v2ray_quic_key,
header = {type = user.v2ray_quic_guise}
} or nil
} or nil
}
},
-- 传出连接
outbounds = outbounds,
routing = routing
}
return config
end

View File

@ -0,0 +1,51 @@
local d = require "luci.dispatcher"
local _api = require "luci.model.cbi.passwall.api.api"
local e = luci.model.uci.cursor()
m = Map("passwall_server", translate("Server-Side"))
t = m:section(NamedSection, "global", "global")
t.anonymous = true
t.addremove = false
e = t:option(Flag, "enable", translate("Enable"))
e.rmempty = false
t = m:section(TypedSection, "user", translate("Users Manager"))
t.anonymous = true
t.addremove = true
t.template = "cbi/tblsection"
t.extedit = d.build_url("admin", "vpn", "passwall", "server_user", "%s")
function t.create(e, t)
local uuid = _api.gen_uuid()
t = uuid
TypedSection.create(e, t)
luci.http.redirect(e.extedit:format(t))
end
function t.remove(e, t)
e.map.proceed = true
e.map:del(t)
luci.http.redirect(d.build_url("admin", "vpn", "passwall", "server"))
end
e = t:option(Flag, "enable", translate("Enable"))
e.width = "5%"
e.rmempty = false
e = t:option(DummyValue, "status", translate("Status"))
e.template = "passwall/server/users_status"
e.value = translate("Collecting data...")
e = t:option(DummyValue, "remarks", translate("Remarks"))
e.width = "15%"
---- Type
e = t:option(DummyValue, "type", translate("Type"))
e = t:option(DummyValue, "port", translate("Port"))
m:append(Template("passwall/server/log"))
m:append(Template("passwall/server/users_list_status"))
return m

View File

@ -0,0 +1,322 @@
local d = require "luci.dispatcher"
local ipkg = require("luci.model.ipkg")
local uci = require"luci.model.uci".cursor()
local api = require "luci.model.cbi.passwall.api.api"
local function is_finded(e)
local function get_customed_path(e)
return api.uci_get_type("global_app", e .. "_file")
end
return luci.sys.exec("find /usr/*bin %s -iname %s -type f" % {get_customed_path(e), e}) ~= "" and true or false
end
local function is_installed(e) return ipkg.installed(e) end
local ssr_encrypt_method_list = {
"none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb",
"aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr",
"bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb",
"cast5-cfb", "des-cfb", "idea-cfb", "seed-cfb", "salsa20", "chacha20",
"chacha20-ietf"
}
local ssr_protocol_list = {
"origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple",
"auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5",
"auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c",
"auth_chain_d", "auth_chain_e", "auth_chain_f"
}
local ssr_obfs_list = {
"plain", "http_simple", "http_post", "random_head", "tls_simple",
"tls1.0_session_auth", "tls1.2_ticket_auth"
}
local v2ray_ss_encrypt_method_list = {
"aes-128-cfb", "aes-256-cfb", "aes-128-gcm", "aes-256-gcm", "chacha20", "chacha20-ietf", "chacha20-poly1305", "chacha20-ietf-poly1305"
}
local v2ray_header_type_list = {
"none", "srtp", "utp", "wechat-video", "dtls", "wireguard"
}
map = Map("passwall_server", translate("Server Config"))
map.redirect = d.build_url("admin", "vpn", "passwall", "server")
s = map:section(NamedSection, arg[1], "user", "")
s.addremove = false
s.dynamic = false
enable = s:option(Flag, "enable", translate("Enable"))
enable.default = "1"
enable.rmempty = false
remarks = s:option(Value, "remarks", translate("Remarks"))
remarks.default = translate("Remarks")
remarks.rmempty = false
type = s:option(ListValue, "type", translate("Type"))
if is_finded("ssr-server") then
type:value("SSR", translate("ShadowsocksR"))
end
if is_installed("v2ray") or is_finded("v2ray") then
type:value("V2ray", translate("V2ray"))
end
if is_installed("brook") or is_finded("brook") then
type:value("Brook", translate("Brook"))
end
if is_installed("trojan") or is_finded("trojan") then
type:value("Trojan", translate("Trojan"))
end
v2ray_protocol = s:option(ListValue, "v2ray_protocol", translate("Protocol"))
v2ray_protocol:value("vmess", translate("Vmess"))
v2ray_protocol:value("http", translate("HTTP"))
v2ray_protocol:value("socks", translate("Socks"))
v2ray_protocol:value("shadowsocks", translate("Shadowsocks"))
v2ray_protocol:depends("type", "V2ray")
-- Brook协议
brook_protocol = s:option(ListValue, "brook_protocol",
translate("Brook Protocol"))
brook_protocol:value("server", translate("Brook"))
brook_protocol:value("wsserver", translate("WebSocket"))
brook_protocol:depends("type", "Brook")
brook_tls = s:option(Flag, "brook_tls", translate("Use TLS"))
brook_tls:depends("brook_protocol", "wsserver")
port = s:option(Value, "port", translate("Port"))
port.datatype = "port"
port.rmempty = false
port:depends("type", "SSR")
port:depends({ type = "V2ray", v2ray_protocol = "vmess" })
port:depends({ type = "V2ray", v2ray_protocol = "http" })
port:depends({ type = "V2ray", v2ray_protocol = "socks" })
port:depends({ type = "V2ray", v2ray_protocol = "shadowsocks" })
port:depends("type", "Brook")
port:depends("type", "Trojan")
username = s:option(Value, "username", translate("Username"))
username:depends("v2ray_protocol", "http")
username:depends("v2ray_protocol", "socks")
password = s:option(Value, "password", translate("Password"))
password.password = true
password:depends("type", "SSR")
password:depends("type", "Brook")
password:depends("type", "Trojan")
password:depends({ type = "V2ray", v2ray_protocol = "http" })
password:depends({ type = "V2ray", v2ray_protocol = "socks" })
password:depends({ type = "V2ray", v2ray_protocol = "shadowsocks" })
ssr_encrypt_method = s:option(ListValue, "ssr_encrypt_method", translate("Encrypt Method"))
for a, t in ipairs(ssr_encrypt_method_list) do ssr_encrypt_method:value(t) end
ssr_encrypt_method:depends("type", "SSR")
v2ray_ss_encrypt_method = s:option(ListValue, "v2ray_ss_encrypt_method", translate("Encrypt Method"))
for a, t in ipairs(v2ray_ss_encrypt_method_list) do v2ray_ss_encrypt_method:value(t) end
v2ray_ss_encrypt_method:depends("v2ray_protocol", "shadowsocks")
v2ray_ss_network = s:option(ListValue, "v2ray_ss_network", translate("Transport"))
v2ray_ss_network.default = "tcp,udp"
v2ray_ss_network:value("tcp", "TCP")
v2ray_ss_network:value("udp", "UDP")
v2ray_ss_network:value("tcp,udp", "TCP,UDP")
v2ray_ss_network:depends("v2ray_protocol", "shadowsocks")
v2ray_ss_ota = s:option(Flag, "v2ray_ss_ota", translate("OTA"), translate("When OTA is enabled, V2Ray will reject connections that are not OTA enabled. This option is invalid when using AEAD encryption."))
v2ray_ss_ota.default = "0"
v2ray_ss_ota:depends("v2ray_protocol", "shadowsocks")
protocol = s:option(ListValue, "protocol", translate("Protocol"))
for a, t in ipairs(ssr_protocol_list) do protocol:value(t) end
protocol:depends("type", "SSR")
protocol_param = s:option(Value, "protocol_param", translate("Protocol_param"))
protocol_param:depends("type", "SSR")
obfs = s:option(ListValue, "obfs", translate("Obfs"))
for a, t in ipairs(ssr_obfs_list) do obfs:value(t) end
obfs:depends("type", "SSR")
obfs_param = s:option(Value, "obfs_param", translate("Obfs_param"))
obfs_param:depends("type", "SSR")
timeout = s:option(Value, "timeout", translate("Connection Timeout"))
timeout.datatype = "uinteger"
timeout.default = 300
timeout:depends("type", "SSR")
tcp_fast_open = s:option(ListValue, "tcp_fast_open", translate("TCP Fast Open"), translate("Need node support required"))
tcp_fast_open:value("false")
tcp_fast_open:value("true")
tcp_fast_open:depends("type", "SSR")
tcp_fast_open:depends("type", "Trojan")
udp_forward = s:option(Flag, "udp_forward", translate("UDP Forward"))
udp_forward.default = "1"
udp_forward.rmempty = false
udp_forward:depends("type", "SSR")
vmess_id = s:option(DynamicList, "vmess_id", translate("ID"))
for i = 1, 3 do
local uuid = luci.sys.exec("echo -n $(cat /proc/sys/kernel/random/uuid)")
vmess_id:value(uuid)
end
vmess_id:depends({ type = "V2ray", v2ray_protocol = "vmess" })
vmess_alterId = s:option(Value, "vmess_alterId", translate("Alter ID"))
vmess_alterId.default = 16
vmess_alterId:depends({ type = "V2ray", v2ray_protocol = "vmess" })
vmess_level = s:option(Value, "vmess_level", translate("User Level"))
vmess_level.default = 1
vmess_level:depends({ type = "V2ray", v2ray_protocol = "vmess" })
vmess_level:depends({ type = "V2ray", v2ray_protocol = "shadowsocks" })
v2ray_transport = s:option(ListValue, "v2ray_transport", translate("Transport"))
v2ray_transport:value("tcp", "TCP")
v2ray_transport:value("mkcp", "mKCP")
v2ray_transport:value("ws", "WebSocket")
v2ray_transport:value("h2", "HTTP/2")
v2ray_transport:value("ds", "DomainSocket")
v2ray_transport:value("quic", "QUIC")
v2ray_transport:depends("v2ray_protocol", "vmess")
-- [[ TCP部分 ]]--
-- TCP伪装
v2ray_tcp_guise = s:option(ListValue, "v2ray_tcp_guise", translate("Camouflage Type"))
v2ray_tcp_guise:value("none", "none")
v2ray_tcp_guise:value("http", "http")
v2ray_tcp_guise:depends("v2ray_transport", "tcp")
-- HTTP域名
v2ray_tcp_guise_http_host = s:option(DynamicList, "v2ray_tcp_guise_http_host", translate("HTTP Host"))
v2ray_tcp_guise_http_host:depends("v2ray_tcp_guise", "http")
-- HTTP路径
v2ray_tcp_guise_http_path = s:option(DynamicList, "v2ray_tcp_guise_http_path", translate("HTTP Path"))
v2ray_tcp_guise_http_path:depends("v2ray_tcp_guise", "http")
-- [[ mKCP部分 ]]--
v2ray_mkcp_guise = s:option(ListValue, "v2ray_mkcp_guise", translate("Camouflage Type"), translate('<br />none: default, no masquerade, data sent is packets with no characteristics.<br />srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).<br />utp: packets disguised as uTP will be recognized as bittorrent downloaded data.<br />wechat-video: packets disguised as WeChat video calls.<br />dtls: disguised as DTLS 1.2 packet.<br />wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)'))
for a, t in ipairs(v2ray_header_type_list) do v2ray_mkcp_guise:value(t) end
v2ray_mkcp_guise:depends("v2ray_transport", "mkcp")
v2ray_mkcp_mtu = s:option(Value, "v2ray_mkcp_mtu", translate("KCP MTU"))
v2ray_mkcp_mtu:depends("v2ray_transport", "mkcp")
v2ray_mkcp_tti = s:option(Value, "v2ray_mkcp_tti", translate("KCP TTI"))
v2ray_mkcp_tti:depends("v2ray_transport", "mkcp")
v2ray_mkcp_uplinkCapacity = s:option(Value, "v2ray_mkcp_uplinkCapacity", translate("KCP uplinkCapacity"))
v2ray_mkcp_uplinkCapacity:depends("v2ray_transport", "mkcp")
v2ray_mkcp_downlinkCapacity = s:option(Value, "v2ray_mkcp_downlinkCapacity", translate("KCP downlinkCapacity"))
v2ray_mkcp_downlinkCapacity:depends("v2ray_transport", "mkcp")
v2ray_mkcp_congestion = s:option(Flag, "v2ray_mkcp_congestion", translate("KCP Congestion"))
v2ray_mkcp_congestion:depends("v2ray_transport", "mkcp")
v2ray_mkcp_readBufferSize = s:option(Value, "v2ray_mkcp_readBufferSize", translate("KCP readBufferSize"))
v2ray_mkcp_readBufferSize:depends("v2ray_transport", "mkcp")
v2ray_mkcp_writeBufferSize = s:option(Value, "v2ray_mkcp_writeBufferSize", translate("KCP writeBufferSize"))
v2ray_mkcp_writeBufferSize:depends("v2ray_transport", "mkcp")
-- [[ WebSocket部分 ]]--
v2ray_ws_host = s:option(Value, "v2ray_ws_host", translate("WebSocket Host"))
v2ray_ws_host:depends("v2ray_transport", "ws")
v2ray_ws_host:depends("v2ray_ss_transport", "ws")
v2ray_ws_path = s:option(Value, "v2ray_ws_path", translate("WebSocket Path"))
v2ray_ws_path:depends("v2ray_transport", "ws")
v2ray_ws_path:depends("v2ray_ss_transport", "ws")
-- [[ HTTP/2部分 ]]--
v2ray_h2_host = s:option(DynamicList, "v2ray_h2_host", translate("HTTP/2 Host"))
v2ray_h2_host:depends("v2ray_transport", "h2")
v2ray_h2_host:depends("v2ray_ss_transport", "h2")
v2ray_h2_path = s:option(Value, "v2ray_h2_path", translate("HTTP/2 Path"))
v2ray_h2_path:depends("v2ray_transport", "h2")
v2ray_h2_path:depends("v2ray_ss_transport", "h2")
-- [[ DomainSocket部分 ]]--
v2ray_ds_path = s:option(Value, "v2ray_ds_path", "Path", translate("A legal file path. This file must not exist before running V2Ray."))
v2ray_ds_path:depends("v2ray_transport", "ds")
-- [[ QUIC部分 ]]--
v2ray_quic_security = s:option(ListValue, "v2ray_quic_security", translate("Encrypt Method"))
v2ray_quic_security:value("none")
v2ray_quic_security:value("aes-128-gcm")
v2ray_quic_security:value("chacha20-poly1305")
v2ray_quic_security:depends("v2ray_transport", "quic")
v2ray_quic_key = s:option(Value, "v2ray_quic_key", translate("Encrypt Method") .. translate("Key"))
v2ray_quic_key:depends("v2ray_transport", "quic")
v2ray_quic_guise = s:option(ListValue, "v2ray_quic_guise", translate("Camouflage Type"))
for a, t in ipairs(v2ray_header_type_list) do v2ray_quic_guise:value(t) end
v2ray_quic_guise:depends("v2ray_transport", "quic")
remote_enable = s:option(Flag, "remote_enable", translate("Enable Remote"),translate("You can forward to Nginx/Caddy/V2ray WebSocket and more."))
remote_enable.default = "1"
remote_enable.rmempty = false
remote_enable:depends("type", "Trojan")
remote_address = s:option(Value, "remote_address", translate("Remote Address"))
remote_address.default = "127.0.0.1"
remote_address:depends("remote_enable", 1)
remote_port = s:option(Value, "remote_port", translate("Remote Port"))
remote_port.datatype = "port"
remote_port.default = "80"
remote_port:depends("remote_enable", 1)
-- [[ TLS部分 ]] --
tls_enable = s:option(Flag, "tls_enable", "TLS/SSL")
tls_enable:depends({ type = "V2ray", v2ray_protocol = "vmess", v2ray_transport = "ws" })
tls_enable:depends({ type = "V2ray", v2ray_protocol = "vmess", v2ray_transport = "h2" })
tls_enable.default = "0"
tls_enable.rmempty = false
tls_certificateFile = s:option(Value, "tls_certificateFile", translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
tls_certificateFile:depends("tls_enable", 1)
tls_certificateFile:depends("type", "Trojan")
tls_keyFile = s:option(Value, "tls_keyFile", translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
tls_keyFile:depends("tls_enable", 1)
tls_keyFile:depends("type", "Trojan")
local nodes_table = {}
uci:foreach("passwall", "nodes", function(e)
if e.type and e.type == "V2ray" and e.remarks and e.address and e.port then
nodes_table[#nodes_table + 1] = {
id = e[".name"],
remarks = "%s[%s] %s:%s" % {e.type, e.remarks, e.address, e.port}
}
end
end)
transit_node = s:option(ListValue, "transit_node", translate("transit node"))
transit_node:value("nil", translate("Close"))
for k, v in pairs(nodes_table) do transit_node:value(v.id, v.remarks) end
transit_node.default = "nil"
transit_node:depends("type", "V2ray")
bind_local = s:option(Flag, "bind_local", translate("Bind Local"), translate("When selected, it can only be accessed locally,It is recommended to turn on when using reverse proxies."))
bind_local.default = "0"
bind_local:depends("type", "V2ray")
accept_lan = s:option(Flag, "accept_lan", translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!"))
accept_lan.default = "0"
accept_lan.rmempty = false
accept_lan:depends("type", "V2ray")
return map

View File

@ -0,0 +1,21 @@
local d = require "luci.dispatcher"
local appname = "passwall"
m = Map(appname, "V2ray" .. translate("Shunt") .. translate("Rule"))
m.redirect = d.build_url("admin", "vpn", appname)
s = m:section(NamedSection, arg[1], "shunt_rules", "")
s.addremove = false
s.dynamic = false
remarks = s:option(Value, "remarks", translate("Remarks"))
remarks.default = arg[1]
remarks.rmempty = false
domain_list = s:option(TextValue, "domain_list", translate("Domain"))
domain_list.rows = 15
ip_list = s:option(TextValue, "ip_list", "IP")
ip_list.rows = 15
return m

File diff suppressed because one or more lines are too long

View File

@ -13,7 +13,6 @@ end
local tcp_node_num = api.uci_get_type("global_other", "tcp_node_num", 1)
local udp_node_num = api.uci_get_type("global_other", "udp_node_num", 1)
local socks_node_num = api.uci_get_type("global_other", "socks_node_num", 1)
local status_show_check_port = api.uci_get_type("global_other", "status_show_check_port", 0)
local status_show_ip111 = api.uci_get_type("global_other", "status_show_ip111", 0)
@ -82,15 +81,6 @@ local status_show_ip111 = api.uci_get_type("global_other", "status_show_ip111",
</div>
</div>
<div class="cbi-value">
<label class="cbi-value-title">Socks
<%:Status%>
</label>
<div class="cbi-value-field" id="_socks_node_status">
<%:Collecting data...%>
</div>
</div>
<% if ipkg.installed("kcptun") or is_finded("kcptun*") then %>
<div class="cbi-value">
<label class="cbi-value-title">Kcptun
@ -127,7 +117,7 @@ local status_show_ip111 = api.uci_get_type("global_other", "status_show_ip111",
<%:Baidu Connection%>
</label>
<div class="cbi-value-field">
<input type="button" class="cbi-button cbi-input-apply" value="<%:Check%>" onclick="return check_connect(this,'baidu')" />
<input type="button" class="cbi-button cbi-input-apply" value="<%:Check%>" onclick="return check_connect(this, 'baidu', 'www.baidu.com')" />
<font id="_baidu_status"></font>
</div>
</div>
@ -136,10 +126,19 @@ local status_show_ip111 = api.uci_get_type("global_other", "status_show_ip111",
<%:Google Connection%>
</label>
<div class="cbi-value-field">
<input type="button" class="cbi-button cbi-input-apply" value="<%:Check%>" onclick="return check_connect(this,'google')" />
<input type="button" class="cbi-button cbi-input-apply" value="<%:Check%>" onclick="return check_connect(this, 'google', 'www.google.com/generate_204')" />
<font id="_google_status"></font>
</div>
</div>
<div class="cbi-value">
<label class="cbi-value-title">
<%:GitHub Connection%>
</label>
<div class="cbi-value-field">
<input type="button" class="cbi-button cbi-input-apply" value="<%:Check%>" onclick="return check_connect(this, 'github', 'https://github.com')" />
<font id="_github_status"></font>
</div>
</div>
<% if tonumber(status_show_check_port) == 1 then %>
<div class="cbi-value">
<label class="cbi-value-title">
@ -172,7 +171,7 @@ local status_show_ip111 = api.uci_get_type("global_other", "status_show_ip111",
var google_status = document.getElementById('_google_status');
XHR.poll(3, '<%=dsp.build_url("admin/vpn/passwall/status")%>', null,
function(x, json) {
if(x && x.status == 200) {
if (x && x.status == 200) {
var tcp_node_status = document.getElementById('_tcp_node_status');
if (tcp_node_status) {
var tcp_node_num = <%=tcp_node_num%>;
@ -236,73 +235,43 @@ local status_show_ip111 = api.uci_get_type("global_other", "status_show_ip111",
udp_node_status.innerHTML = text;
}
}
var socks_node_status = document.getElementById('_socks_node_status');
if (socks_node_status) {
var socks_node_num = <%=socks_node_num%>;
if (socks_node_num >= 1) {
var text = '';
if (socks_node_num == 1) {
if (json["socks_node1_status"])
text += '<font color="green"><%:RUNNING%> ✓</font>';
else
text += '<font color="red"><%:NOT RUNNING%> X</font>';
} else {
for(var i = 0; i < socks_node_num; i++) {
var k = i + 1;
if (json["socks_node" + k + "_status"])
text += '<font color="green" size="3"></font>';
else
text += '<font color="red" size="3"> X</font>';
}
}
socks_node_status.innerHTML = text;
}
}
if(haproxy_status)
if (haproxy_status)
haproxy_status.innerHTML = json.haproxy_status ? '<font color="green"><%:RUNNING%> ✓</font>' : '<font color="red"><%:NOT RUNNING%> X</font>';
if(dns_mode_status)
if (dns_mode_status)
dns_mode_status.innerHTML = json.dns_mode_status ? '<font color="green"><%:RUNNING%> ✓</font>' : '<font color="red"><%:NOT RUNNING%> X</font>';
}
});
function check_connect(btn, type) {
function check_connect(btn, type, url) {
btn.disabled = true;
btn.value = '<%:Check...%>';
var sendDate = (new Date()).getTime();
XHR.get('<%=dsp.build_url("admin/vpn/passwall/connect_status")%>', {
type: type
type: type,
url: url
},
function(x, rv) {
var s = document.getElementById('_' + type + '_status');
if(s) {
if(rv.status) {
if (s) {
if (rv.ping_type && rv.ping_type == "curl") {
var use_time = rv.use_time;
var speed = "";
var color="red";
if (use_time < 1) {
if (use_time < 1000) {
color = "green";
speed = "<%:Very Fast%>";
} else if (use_time < 2) {
color = "green";
speed = "<%:Fast%>";
} else if (use_time < 3) {
} else if (use_time < 2000) {
color = "#b9b90b";
speed = "<%:General%>";
} else if (use_time < 4) {
} else {
color = "red";
speed = "<%:Slow%>";
} else if (use_time >= 4) {
color = "red";
speed = "<%:Very Slow%>";
}
//s.setAttribute("color", color);
btn.setAttribute("style","background-color: " + color + " !important; border-color: " + color + " !important;");
btn.value = speed;
}
else {
btn.setAttribute("style","color: " + color + " !important");
btn.value = use_time + " ms";;
} else if (rv.status) {
btn.setAttribute("style","color: green !important");
btn.value = "<%:Working...%>";
} else {
//s.setAttribute("color", "red");
btn.setAttribute("style","background-color:red !important; border-color: red !important;");
btn.setAttribute("style","color: red !important");
btn.value = '<%:Problem detected!%> X';
}
}
@ -319,7 +288,7 @@ local status_show_ip111 = api.uci_get_type("global_other", "status_show_ip111",
XHR.get('<%=dsp.build_url("admin/vpn/passwall/check_port")%>', null,
function(x, rv) {
var s = document.getElementById('_node_status');
if(s) {
if (s) {
s.innerHTML = rv.ret;
var clear_btn = document.getElementById('clear_check_port_btn');
clear_btn.style.display = "inline-block";

View File

@ -62,16 +62,24 @@ local dsp = require "luci.dispatcher"
document.getElementById("nodes_link").focus();
}
}
function clear_all_nodes() {
if (confirm('<%:Are you sure to clear all nodes?%>') == true){
XHR.get('<%=dsp.build_url("admin/vpn/passwall/clear_all_nodes")%>', null,
function(x, data) {
if(x && x.status == 200) {
window.location.href = '<%=dsp.build_url("admin/vpn/passwall/node_list")%>';
}
else {
alert("<%:Error%>");
}
});
}
}
//]]>
</script>
<div class="cbi-value">
<label class="cbi-value-title"><%:Add Node%></label>
<div class="cbi-value-field">
<input class="cbi-button cbi-button-add" type="button" onclick="open_add_link_div()" value="<%:Add the node via the link%>" />
</div>
</div>
<div id="add_link_div">
<div class="cbi-value">
<label class="cbi-value-title"><%:SS/SSR/V2ray/Trojan Link%></label>
@ -87,3 +95,13 @@ local dsp = require "luci.dispatcher"
</div>
</div>
</div>
<div class="cbi-value">
<label class="cbi-value-title"><%:Operation%></label>
<div class="cbi-value-field">
<input class="cbi-button cbi-button-add" type="button" onclick="open_add_link_div()" value="<%:Add the node via the link%>" />
<input class="cbi-button cbi-button-remove" type="button" onclick="clear_all_nodes()" value="<%:Clear all nodes%>" />
<input class="cbi-button cbi-button-remove" type="button" onclick="delete_select_nodes()" value="<%:Delete select nodes%>" />
<input class="cbi-button" type="button" onclick="select_all(this)" value="<%:Select all%>" />
</div>
</div>

View File

@ -5,7 +5,6 @@
local tcp_node_num = api.uci_get_type("global_other", "tcp_node_num", 1)
local udp_node_num = api.uci_get_type("global_other", "udp_node_num", 1)
local socks_node_num = api.uci_get_type("global_other", "socks_node_num", 1)
local compact_display_nodes = api.uci_get_type("global_other", "compact_display_nodes", 1)
-%>
@ -20,32 +19,39 @@ table td, .table .td {
word-break: keep-all;
}
#set_node_div{
#set_node_div {
display: none;
width: 30rem;
position: fixed;
left:50%;
top:50%;
transform: translate(-50%, -50%);
padding-top: 30px;
z-index: 99;
text-align: center;
background: white;
box-shadow: darkgrey 10px 10px 30px 5px;
}
._select {
background: #dad8d8;
}
</style>
<script type="text/javascript">
//<![CDATA[
var ajax = {
post: function(url, data, fn_success, fn_timeout) {
post: function(url, data, fn_success, timeout, fn_timeout) {
var xhr = new XMLHttpRequest();
var code = ajax.encode(data);
xhr.open("POST", url, true);
xhr.timeout = 1000;
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.ontimeout = function() {
fn_timeout(xhr);
if (timeout && timeout > 1000) {
xhr.timeout = timeout;
}
if (fn_timeout) {
xhr.ontimeout = function() {
fn_timeout(xhr);
}
}
xhr.onreadystatechange = function() {
if(xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) {
@ -96,30 +102,131 @@ table td, .table .td {
document.getElementById("set_node_name").innerHTML = "";
}
function _cbi_row_top(id) {
var dom = document.getElementById("cbi-passwall-" + id);
if (dom) {
var trs = document.getElementById("cbi-passwall-nodes").getElementsByClassName("cbi-section-table-row");
if (trs && trs.length > 0) {
for (var i = 0; i < trs.length; i++) {
var up = dom.getElementsByClassName("cbi-button-up");
if (up) {
cbi_row_swap(up[0], true, 'cbi.sts.passwall.nodes');
}
}
}
}
}
function select_node_div(btn, id) {
btn.value = "<%:DeSelect%>";
btn.setAttribute("onclick", "deselect_node_div(this, '" + id + "')");
var dom = document.getElementById("cbi-passwall-" + id);
if (dom) {
dom.classList.add("_select");
dom.setAttribute("nodes_id", id);
}
}
function deselect_node_div(btn, id) {
btn.value = "<%:Select%>";
btn.setAttribute("onclick", "select_node_div(this, '" + id + "')");
var dom = document.getElementById("cbi-passwall-" + id);
if (dom) {
dom.classList.remove("_select");
dom.removeAttribute("nodes_id");
}
}
function select_all(btn) {
var doms = document.getElementById("cbi-passwall-nodes").getElementsByClassName("cbi-section-table-row");
if (doms && doms.length > 0) {
for (var i = 0 ; i < doms.length; i++) {
var id = doms[i].id.replace("cbi-passwall-", "");
var btn2 = document.getElementById("select_" + id);
select_node_div(btn2, id);
}
btn.value = "<%:DeSelect all%>";
btn.setAttribute("onclick", "deselect_all(this)");
}
}
function deselect_all(btn) {
var doms = document.getElementById("cbi-passwall-nodes").getElementsByClassName("cbi-section-table-row");
if (doms && doms.length > 0) {
for (var i = 0 ; i < doms.length; i++) {
var id = doms[i].id.replace("cbi-passwall-", "");
var btn2 = document.getElementById("select_" + id);
deselect_node_div(btn2, id);
}
btn.value = "<%:Select all%>";
btn.setAttribute("onclick", "select_all(this)");
}
}
function delete_select_nodes() {
var doms = document.getElementsByClassName("_select");
if (doms && doms.length > 0) {
var ids = [];
for (var i = 0 ; i < doms.length; i++) {
if (doms[i].getAttribute("nodes_id")) {
ids.push(doms[i].getAttribute("nodes_id"))
}
}
if (confirm('<%:Are you sure to delete select nodes?%>') == true){
XHR.get('<%=dsp.build_url("admin/vpn/passwall/delete_select_nodes")%>', {
ids: ids.join()
},
function(x, data) {
if(x && x.status == 200) {
window.location.href = '<%=dsp.build_url("admin/vpn/passwall/node_list")%>';
}
else {
alert("<%:Error%>");
}
});
}
} else {
alert("<%:You no select nodes !%>");
}
}
function set_node(protocol,number) {
if (confirm('<%:Are you sure set to%> ' + protocol.toUpperCase() + "_" + number + '<%:the server?%>')==true){
window.location.href = '<%=dsp.build_url("admin/vpn/passwall/set_node")%>?protocol=' + protocol + '&number=' + number + '&section=' + section;
}
}
function ping_node(cbi_id,dom) {
function get_address_full(id) {
<% if compact_display_nodes and tonumber(compact_display_nodes) == 1 then %>
var remarks = document.getElementById("cbid.passwall." + cbi_id + ".remarks").value;
var address = null;
var port = null;
if (remarks.lastIndexOf("") != -1 && remarks.lastIndexOf("") != -1) {
var address_full = remarks.substring(remarks.lastIndexOf("") + 1, remarks.lastIndexOf(""));
address = address_full.substring(0, address_full.lastIndexOf(":"));
port = address_full.substring(address_full.lastIndexOf(":") + 1);
var remarks = document.getElementById("cbid.passwall." + id + ".remarks").value;
var result = remarks.match("\\(.+?)\\");
if (result != null) {
var full = result[1];
var address = full.substring(0, full.lastIndexOf(":"));
var port = full.substring(full.lastIndexOf(":") + 1);
}
<% else %>
var address = document.getElementById("cbid.passwall." + cbi_id + ".address").value;
var port = document.getElementById("cbid.passwall." + cbi_id + ".port").value;
try {
var address = document.getElementById("cbid.passwall." + id + ".address").value;
var port = document.getElementById("cbid.passwall." + id + ".port").value;
}
catch(err){}
<% end %>
if ((address != null && address != "") && (port != null && port != "")) {
//判断是否含有汉字
var reg = new RegExp("[\\u4E00-\\u9FFF]+","g");
if ((address != null && address != "") && (port != null && port != "") && reg.test(address) == false && (address.indexOf(".") != -1 && address.charAt(address.address - 1) != ".")) {
return { address: address, port: port };
} else {
return null;
}
}
function ping_node(cbi_id, dom) {
var full = get_address_full(cbi_id);
if (full != null) {
XHR.get('<%=dsp.build_url("admin/vpn/passwall/ping_node")%>', {
address: address,
port: port
address: full.address,
port: full.port
},
function(x, result) {
if(x && x.status == 200) {
@ -141,102 +248,143 @@ table td, .table .td {
}
/* 自动Ping */
var nodes = [];
const auto_ping_value = document.getElementsByClassName('auto_ping_value');
var index = 0;
function auto_ping() {
if (index >= auto_ping_value.length) {
return;
}
var has_ping = auto_ping_value[index].getAttribute("has_ping");
if (has_ping == null) {
var cbi_id = auto_ping_value[index].getAttribute("cbiid");
<% if compact_display_nodes and tonumber(compact_display_nodes) == 1 then %>
var remarks = document.getElementById("cbid.passwall." + cbi_id + ".remarks").value;
var address = null;
var port = null;
if (remarks.lastIndexOf("") != -1 && remarks.lastIndexOf("") != -1) {
var address_full = remarks.substring(remarks.lastIndexOf("") + 1, remarks.lastIndexOf(""));
address = address_full.substring(0, address_full.lastIndexOf(":"));
port = address_full.substring(address_full.lastIndexOf(":") + 1);
for (var i = 0; i < auto_ping_value.length; i++) {
var cbi_id = auto_ping_value[i].getAttribute("cbiid");
var full = get_address_full(cbi_id);
if (full != null) {
var flag = false;
//当有多个相同地址和端口时合在一起
for (var j = 0; j < nodes.length; j++) {
if (nodes[j].address == full.address && nodes[j].port == full.port) {
nodes[j].indexs = nodes[j].indexs + "," + i;
flag = true;
break;
}
<% else %>
var address = document.getElementById("cbid.passwall." + cbi_id + ".address").value;
var port = document.getElementById("cbid.passwall." + cbi_id + ".port").value;
<% end %>
//判断是否含有汉字
var reg = new RegExp("[\\u4E00-\\u9FFF]+","g");
if ((address != null && address != "") && (port != null && port != "") && reg.test(address) == false && (address.indexOf(".") != -1 && address.charAt(address.address - 1) != ".")) {
ajax.post('<%=dsp.build_url("admin/vpn/passwall/ping_node")%>', {
index: index,
address: address,
port: port
},
function(x, result) {
if(x && x.status == 200) {
for(var i = 0; i < auto_ping_value.length; i++) {
var obj = auto_ping_value[i];
var obj_cbi_id = obj.getAttribute("cbiid");
<% if compact_display_nodes and tonumber(compact_display_nodes) == 1 then %>
var obj_remarks = document.getElementById("cbid.passwall." + obj_cbi_id + ".remarks").value;
var obj_address = null;
var obj_port = null;
if (obj_remarks.lastIndexOf("") != -1 && obj_remarks.lastIndexOf("") != -1) {
var obj_address_full = obj_remarks.substring(obj_remarks.lastIndexOf("") + 1, obj_remarks.lastIndexOf(""));
obj_address = obj_address_full.substring(0, obj_address_full.lastIndexOf(":"));
obj_port = obj_address_full.substring(obj_address_full.lastIndexOf(":") + 1);
}
<% else %>
var obj_address = document.getElementById("cbid.passwall." + obj_cbi_id + ".address").value;
var obj_port = document.getElementById("cbid.passwall." + obj_cbi_id + ".port").value;
<% end %>
if (address == obj_address && port == obj_port) {
auto_ping_value[i].setAttribute("has_ping", "1");
if (result.ping == null || result.ping.trim() == "") {
auto_ping_value[i].innerHTML = "<font style='color:red'><%:Timeout%></font>";
} else {
var ping = parseInt(result.ping);
if (ping < 100)
auto_ping_value[i].innerHTML = "<font style='color:green'>" + result.ping + " ms" + "</font>";
else if (ping < 200)
auto_ping_value[i].innerHTML = "<font style='color:#fb9a05'>" + result.ping + " ms" + "</font>";
else if (ping >= 200)
auto_ping_value[i].innerHTML = "<font style='color:red'>" + result.ping + " ms" + "</font>";
}
}
}
}
index++;
auto_ping();
},
function(x) {
auto_ping_value[index].innerHTML = "<font style='color:red'><%:Timeout%></font>";
index++;
auto_ping();
},
);
} else {
index++;
auto_ping();
}
}
else {
index++;
auto_ping();
if (flag)
continue;
nodes.push({
indexs: i + "",
address: full.address,
port: full.port
});
}
}
auto_ping();
const _xhr = (index) => {
return new Promise((res) => {
const dom = nodes[index];
if (!dom) res()
ajax.post('<%=dsp.build_url("admin/vpn/passwall/ping_node")%>', {
index: dom.indexs,
address: dom.address,
port: dom.port
},
function(x, result) {
if (x && x.status == 200) {
var strs = dom.indexs.split(",");
for (var i = 0; i < strs.length; i++) {
if (result.ping == null || result.ping.trim() == "") {
auto_ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
} else {
var ping = parseInt(result.ping);
if (ping < 100)
auto_ping_value[strs[i]].innerHTML = "<font style='color:green'>" + result.ping + " ms" + "</font>";
else if (ping < 200)
auto_ping_value[strs[i]].innerHTML = "<font style='color:#fb9a05'>" + result.ping + " ms" + "</font>";
else if (ping >= 200)
auto_ping_value[strs[i]].innerHTML = "<font style='color:red'>" + result.ping + " ms" + "</font>";
}
}
}
res();
},
5000,
function(x) {
var strs = dom.indexs.split(",");
for (var i = 0; i < strs.length; i++) {
auto_ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
}
res();
}
);
})
}
//添加"应用"按钮到"修改"按钮前
var edit_btn = document.getElementsByClassName("cbi-button cbi-button-edit");
let task = -1;
const thread = () => {
task = task + 1
if (nodes[task]) {
_xhr(task).then(thread);
}
}
for (let i = 0; i < 20; i++) {
thread()
}
/* 递归单请求方法
var index = 0;
function auto_ping() {
if (index >= nodes.length) {
return;
}
var indexs = nodes[index].indexs;
var address = nodes[index].address;
var port = nodes[index].port;
ajax.post('<%=dsp.build_url("admin/vpn/passwall/ping_node")%>', {
index: indexs,
address: address,
port: port
},
function(x, result) {
if (x && x.status == 200) {
var strs = indexs.split(",");
for (var i = 0; i < strs.length; i++) {
if (result.ping == null || result.ping.trim() == "") {
auto_ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
} else {
var ping = parseInt(result.ping);
if (ping < 100)
auto_ping_value[strs[i]].innerHTML = "<font style='color:green'>" + result.ping + " ms" + "</font>";
else if (ping < 200)
auto_ping_value[strs[i]].innerHTML = "<font style='color:#fb9a05'>" + result.ping + " ms" + "</font>";
else if (ping >= 200)
auto_ping_value[strs[i]].innerHTML = "<font style='color:red'>" + result.ping + " ms" + "</font>";
}
}
}
index++;
return auto_ping();
},
function(x) {
var strs = indexs.split(",");
for (var i = 0; i < strs.length; i++) {
auto_ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
}
index++;
return auto_ping();
},
);
}
auto_ping();
*/
var edit_btn = document.getElementById("cbi-passwall-nodes").getElementsByClassName("cbi-button cbi-button-edit");
for(var i = 0; i < edit_btn.length; i++) {
try {
var onclick_str = edit_btn[i].getAttribute("onclick");
var id = onclick_str.substring(onclick_str.lastIndexOf('/') + 1, onclick_str.length - 1);
var td = edit_btn[i].parentNode;
var apply = '<input class="cbi-button cbi-button-add" type="button" value="<%:Use%>" onclick="open_set_node_div(\'' + id + '\')" alt="<%:Use%>" title="<%:Use%>" />';
td.innerHTML = apply + "&nbsp;&nbsp;" + td.innerHTML;
var new_div = "";
//添加"置顶"按钮到"修改"按钮前
new_div += '<input class="cbi-button" type="button" value="<%:To Top%>" onclick="_cbi_row_top(\'' + id + '\')"/>&nbsp;&nbsp;';
//添加"选择"按钮到"修改"按钮前
new_div += '<input class="cbi-button cbi-button-add" type="button" value="<%:Select%>" id="select_' + id + '" onclick="select_node_div(this, \'' + id + '\')"/>&nbsp;&nbsp;';
//添加"应用"按钮到"修改"按钮前
new_div += '<input class="cbi-button cbi-button-apply" type="button" value="<%:Use%>" id="apply_' + id + '" onclick="open_set_node_div(\'' + id + '\')"/>&nbsp;&nbsp;';
td.innerHTML = new_div + td.innerHTML;
}
catch(err) {
console.error(err);
@ -246,26 +394,22 @@ table td, .table .td {
//]]>
</script>
<div id="set_node_div">
<div class="cbi-value"><%:You choose node is:%><span id="set_node_name"></span></div>
<div class="cbi-value">
<% if tcp_node_num and tonumber(tcp_node_num) >= 1 then %>
<% for i = 1, tcp_node_num, 1 do %>
<input class="cbi-button cbi-button-edit" type="button" onclick="set_node('tcp',<%=i%>)" value="TCP_<%=i%>" />
<div style="display: -webkit-flex; display: flex; -webkit-align-items: center; align-items: center; -webkit-justify-content: center; justify-content: center;">
<div id="set_node_div">
<div class="cbi-value"><%:You choose node is:%><span id="set_node_name"></span></div>
<div class="cbi-value">
<% if tcp_node_num and tonumber(tcp_node_num) >= 1 then %>
<% for i = 1, tcp_node_num, 1 do %>
<input class="cbi-button cbi-button-edit" type="button" onclick="set_node('tcp',<%=i%>)" value="TCP_<%=i%>" />
<% end %>
<% end %>
<% end %>
<% if udp_node_num and tonumber(udp_node_num) >= 1 then %>
<% for i = 1, udp_node_num, 1 do %>
<input class="cbi-button cbi-button-edit" type="button" onclick="set_node('udp',<%=i%>)" value="UDP_<%=i%>" />
<% if udp_node_num and tonumber(udp_node_num) >= 1 then %>
<% for i = 1, udp_node_num, 1 do %>
<input class="cbi-button cbi-button-edit" type="button" onclick="set_node('udp',<%=i%>)" value="UDP_<%=i%>" />
<% end %>
<% end %>
<% end %>
<% if socks_node_num and tonumber(socks_node_num) >= 1 then %>
<% for i = 1, socks_node_num, 1 do %>
<input class="cbi-button cbi-button-edit" type="button" onclick="set_node('socks',<%=i%>)" value="Socks_<%=i%>" />
<% end %>
<% end %>
<input class="cbi-button cbi-button-remove" type="button" onclick="close_set_node_div()" value="<%:Close%>" />
<input class="cbi-button cbi-button-remove" type="button" onclick="close_set_node_div()" value="<%:Close%>" />
</div>
</div>
</div>

View File

@ -0,0 +1,22 @@
<%
local dsp = require "luci.dispatcher"
-%>
<script type="text/javascript">
//<![CDATA[
var _status = document.getElementsByClassName('_status');
for (var i = 0; i < _status.length; i++) {
var id = _status[i].getAttribute("socks_id");
XHR.get('<%=dsp.build_url("admin/vpn/passwall/socks_status")%>', {
index: i,
id: id
},
function(x, result) {
_status[result.index].setAttribute("style","font-weight:bold;");
_status[result.index].setAttribute("color",result.status ? "green":"red");
_status[result.index].innerHTML = (result.status ? '✓' : 'X');
}
);
}
//]]>
</script>

View File

@ -0,0 +1,3 @@
<%+cbi/valueheader%>
<font class="_status" socks_id="<%=section%>"></font>
<%+cbi/valuefooter%>

View File

@ -2,8 +2,7 @@
local api = require "luci.model.cbi.passwall.api.api"
local dsp = require "luci.dispatcher"
local brook_path = api.uci_get_type("global_app", "brook_file")
local brook_version = luci.sys.exec("[ -f '" .. brook_path .. "' ] && " .. brook_path .. " -v | awk '{print $3}'")
local brook_version = api.get_brook_version()
-%>
<script type="text/javascript">

View File

@ -2,8 +2,7 @@
local api = require "luci.model.cbi.passwall.api.api"
local dsp = require "luci.dispatcher"
local kcptun_path = api.uci_get_type("global_app", "kcptun_client_file")
local kcptun_version = luci.sys.exec("[ -f '" .. kcptun_path .. "' ] && " .. kcptun_path .. " -v | awk '{print $3}'")
local kcptun_version = api.get_kcptun_version()
-%>
<script type="text/javascript">

View File

@ -1,156 +0,0 @@
<%
local api = require "luci.model.cbi.passwall.api.api"
local dsp = require "luci.dispatcher"
function get_luci_version()
local ipkg = require "luci.model.ipkg"
local package_name = "luci-app-passwall"
local package_info = ipkg.info(package_name) or {}
if next(package_info) ~= nil then
return package_info[package_name]["Version"]
end
return ""
end
local passwall_version = get_luci_version()
-%>
<script type="text/javascript">
//<![CDATA[
var passwallInfo;
var tokenStr = '<%=token%>';
var noUpdateText = '<%:It is the latest version%>';
var updateSuccessText = '<%:Update successful%>';
var clickToUpdateText = '<%:Click to update%>';
var inProgressText = '<%:Updating...%>';
var unexpectedErrorText = '<%:Unexpected error%>';
var updateInProgressNotice = '<%:Updating, are you sure to close?%>';
var downloadingText = '<%:Downloading...%>';
var decompressioningText = '<%:Unpacking...%>';
var movingText = '<%:Moving...%>';
window.onload = function() {
var passwallCheckBtn = document.getElementById('_passwall-check_btn');
var passwallDetailElm = document.getElementById('_passwall-check_btn-detail');
};
function addPageNotice_luci() {
window.onbeforeunload = function(e) {
e.returnValue = updateInProgressNotice;
return updateInProgressNotice;
};
}
function removePageNotice_luci() {
window.onbeforeunload = undefined;
}
function onUpdateSuccess_luci(btn) {
alert(updateSuccessText);
if(btn) {
btn.value = updateSuccessText;
btn.placeholder = updateSuccessText;
btn.disabled = true;
}
window.setTimeout(function() {
window.location.reload();
}, 1000);
}
function onRequestError_luci(btn, errorMessage) {
btn.disabled = false;
btn.value = btn.placeholder;
if(errorMessage) {
alert(errorMessage);
}
}
function onBtnClick_luci(btn) {
if(passwallInfo === undefined) {
checkUpdate_luci(btn);
} else {
doUpdate_luci(btn);
}
}
function checkUpdate_luci(btn) {
btn.disabled = true;
btn.value = inProgressText;
addPageNotice_luci();
var ckeckDetailElm = document.getElementById(btn.id + '-detail');
XHR.get('<%=dsp.build_url("admin/vpn/passwall/luci_check")%>', {
token: tokenStr,
arch: ''
}, function(x,json) {
removePageNotice_luci();
if(json.code) {
passwallInfo = undefined;
onRequestError_luci(btn, json.error);
} else {
if(json.update) {
passwallInfo = json;
btn.disabled = false;
btn.value = clickToUpdateText;
btn.placeholder = clickToUpdateText;
if(ckeckDetailElm) {
var urlNode = '';
if(json.version) {
urlNode = '<em style="color:red;">最新版本号:' + json.version + '</em>';
if(json.url && json.url.html) {
urlNode = '<a href="' + json.url.html + '" target="_blank">' + urlNode + '</a>';
}
}
ckeckDetailElm.innerHTML = urlNode;
}
} else {
btn.disabled = true;
btn.value = noUpdateText;
}
}
},300);
}
function doUpdate_luci(btn) {
btn.disabled = true;
btn.value = downloadingText;
addPageNotice_luci();
var updateUrl = '<%=dsp.build_url("admin/vpn/passwall/luci_update")%>';
// Download file
XHR.get(updateUrl, {
token: tokenStr,
url: passwallInfo ? passwallInfo.url.download : '',
save: true
}, function(x,json) {
removePageNotice_luci();
if(json.code) {
onRequestError_luci(btn, json.error);
} else {
onUpdateSuccess_luci(btn);
}
},300)
}
//]]>
</script>
<div class="cbi-value">
<label class="cbi-value-title">PassWall
<%:Version%>
</label>
<div class="cbi-value-field">
<div class="cbi-value-description">
<span><%=passwall_version%>】</span>
<input class="cbi-button cbi-input-apply" type="button" id="_passwall-check_btn" onclick="onBtnClick_luci(this);" value="<%:Manually update%>" />
<span id="_passwall-check_btn-detail"></span>
</div>
</div>
</div>

View File

@ -2,8 +2,7 @@
local api = require "luci.model.cbi.passwall.api.api"
local dsp = require "luci.dispatcher"
local V2ray_path = api.uci_get_type("global_app", "v2ray_file")
local V2ray_version = luci.sys.exec("[ -f '" .. V2ray_path .. "/v2ray' ] && " .. V2ray_path .. "/v2ray -version | awk '{print $2}' | sed -n 1P")
local v2ray_version = api.get_v2ray_version()
-%>
<script type="text/javascript">
@ -167,7 +166,7 @@ local V2ray_version = luci.sys.exec("[ -f '" .. V2ray_path .. "/v2ray' ] && " ..
</label>
<div class="cbi-value-field">
<div class="cbi-value-description">
<span><%=V2ray_version%>】</span>
<span><%=v2ray_version%>】</span>
<input class="cbi-button cbi-input-apply" type="button" id="_v2ray-check_btn" onclick="onBtnClick_v2ray(this);" value="<%:Manually update%>" />
<span id="_v2ray-check_btn-detail"></span>
</div>

View File

@ -0,0 +1,31 @@
<script type="text/javascript">
//<![CDATA[
function clear_log(btn) {
XHR.get('<%=url([[admin]], [[vpn]], [[passwall]], [[server_clear_log]])%>', null,
function(x, data) {
if(x && x.status == 200) {
var log_textarea = document.getElementById('log_textarea');
log_textarea.innerHTML = "";
log_textarea.scrollTop = log_textarea.scrollHeight;
}
}
);
}
XHR.poll(3, '<%=url([[admin]], [[vpn]], [[passwall]], [[server_get_log]])%>', null,
function(x, data) {
if(x && x.status == 200) {
var log_textarea = document.getElementById('log_textarea');
log_textarea.innerHTML = x.responseText;
log_textarea.scrollTop = log_textarea.scrollHeight;
}
}
);
//]]>
</script>
<fieldset class="cbi-section" id="_log_fieldset">
<legend>
<%:Logs%>
</legend>
<input class="cbi-button cbi-input-remove" type="button" onclick="clear_log()" value="<%:Clear logs%>">
<textarea id="log_textarea" class="cbi-input-textarea" style="width: 100%;margin-top: 10px;" data-update="change" rows="20" wrap="off" readonly="readonly"></textarea>
</fieldset>

View File

@ -0,0 +1,23 @@
<%
local dsp = require "luci.dispatcher"
-%>
<script type="text/javascript">
//<![CDATA[
var _users_status = document.getElementsByClassName('_users_status');
for(var i = 0; i < _users_status.length; i++) {
var id = _users_status[i].parentElement.parentElement.parentElement.id;
id = id.substr(id.lastIndexOf("-") + 1);
XHR.poll(1,'<%=url([[admin]], [[vpn]], [[passwall]], [[server_user_status]])%>', {
index: i,
id: id
},
function(x, result) {
_users_status[result.index].setAttribute("style","font-weight:bold;");
_users_status[result.index].setAttribute("color",result.status ? "green":"red");
_users_status[result.index].innerHTML = (result.status ? '✓' : 'X');
}
);
}
//]]>
</script>

View File

@ -0,0 +1,3 @@
<%+cbi/valueheader%>
<font class="_users_status" hint="<%=self:cfgvalue(section)%>">--</font>
<%+cbi/valuefooter%>

View File

@ -94,6 +94,9 @@ msgstr "百度连接"
msgid "Google Connection"
msgstr "谷歌连接"
msgid "GitHub Connection"
msgstr "GitHub连接"
msgid "Node Check"
msgstr "节点检测"
@ -103,9 +106,6 @@ msgstr "检测中..."
msgid "Clear"
msgstr "清除"
msgid "If you can use it, very stable. If not, GG !!!"
msgstr "如果你会用稳得一批。否则GG"
msgid "Main switch"
msgstr "总开关"
@ -115,12 +115,21 @@ msgstr "TCP节点"
msgid "UDP Node"
msgstr "UDP节点"
msgid "Socks Config"
msgstr "Socks配置"
msgid "Socks Node"
msgstr "Socks节点"
msgid "Same as the tcp node"
msgstr "与TCP节点相同"
msgid "Same as the tcp %s node"
msgstr "与TCP%s节点相同"
msgid "New process"
msgstr "另开进程"
msgid "For used to surf the Internet."
msgstr "用于科学上网。"
@ -148,12 +157,24 @@ msgstr "如果有问题,请尝试其他模式。<br />如果您没有使用任
msgid "Use TCP Node Resolve DNS"
msgstr "使用TCP节点解析DNS"
msgid "Use UDP Node Resolve DNS"
msgstr "使用UDP节点解析DNS"
msgid "If checked, DNS is resolved using the TCP node."
msgstr "如果勾选则使用TCP节点解析DNS解决污染。"
msgid "Socks Server"
msgstr "Socks服务器"
msgid "Fair Mode"
msgstr "公平模式"
msgid "DNS Address"
msgstr "DNS地址"
msgid "DNS Cache"
msgstr "DNS缓存"
msgid "China DNS Server"
msgstr "国内DNS服务器"
@ -256,6 +277,9 @@ msgstr "路由器自身"
msgid "Danger"
msgstr "危险"
msgid "Operation"
msgstr "操作"
msgid "Add Node"
msgstr "添加节点"
@ -268,6 +292,39 @@ msgstr "SS/SSR/V2ray/Trojan链接"
msgid "Please enter the correct link, ss:// ssr:// vmess:// trojan://"
msgstr "请输入正确的链接ss:// ssr:// vmess:// trojan://"
msgid "Clear all nodes"
msgstr "清空所有节点"
msgid "Are you sure to clear all nodes?"
msgstr "你确定要清空所有节点吗?"
msgid "Error"
msgstr "错误"
msgid "Delete select nodes"
msgstr "删除选择的节点"
msgid "To Top"
msgstr "置顶"
msgid "Select"
msgstr "选择"
msgid "DeSelect"
msgstr "反选"
msgid "Select all"
msgstr "全选"
msgid "DeSelect all"
msgstr "全不选"
msgid "Are you sure to delete select nodes?"
msgstr "你确定要删除选择的节点吗?"
msgid "You no select nodes !"
msgstr "你没有选择任何节点!"
msgid "Are you sure set to"
msgstr "你确定要设为"
@ -289,14 +346,14 @@ msgstr "添加方式"
msgid "Type"
msgstr "类型"
msgid "V2ray Balancing"
msgstr "V2ray 负载均衡"
msgid "Balancing"
msgstr "负载均衡"
msgid "V2ray_balancing"
msgstr "V2ray 负载均衡"
msgid "V2ray Shunt"
msgstr "V2ray 分流"
msgid "Shunt"
msgstr "分流"
msgid "V2ray_shunt"
msgstr "V2ray 分流"
@ -358,9 +415,6 @@ msgstr "选中后保存应用后即使用tcping替换ping检测节点"
msgid "Concise display nodes"
msgstr "简洁显示节点"
msgid "Support for more than 10,000 ping nodes and luci does not crash and not slow."
msgstr "支持超过10000个节点而LuCI却不会卡死更不会崩溃。"
msgid "Apply"
msgstr "应用"
@ -526,6 +580,15 @@ msgstr "备用"
msgid "Manually update"
msgstr "手动更新"
msgid "Enable custom url"
msgstr "启用自定义规则地址"
msgid "gfwlist Update url"
msgstr "GFWList更新URL"
msgid "Chnroute Update url"
msgstr "国内IP段(Chnroute)更新URL"
msgid "Rule status"
msgstr "规则版本"
@ -646,6 +709,9 @@ msgstr "关键字丢弃"
msgid "When checked, the keywords in the list are discarded. Otherwise, it is not discarded."
msgstr "当勾选时,将丢弃包含列表里的关键字的节点。否则,将保留列表的关键字的节点(反过来)。"
msgid "Whether unsafe connections are allowed. When checked, V2Ray does not check the validity of the TLS certificate provided by the remote host by default."
msgstr "是否允许不安全连接。当勾选时,缺省情况下客户端不会检查远端主机所提供的 TLS 证书的有效性。"
msgid "Add"
msgstr "添加"
@ -841,6 +907,60 @@ msgstr "隐藏菜单方法,地址栏输入例:"
msgid "After the hidden to the display, input example in the address bar:"
msgstr "当你隐藏后想再次显示,地址栏输入例:"
msgid "When OTA is enabled, V2Ray will reject connections that are not OTA enabled. This option is invalid when using AEAD encryption."
msgstr "开启 OTA 后V2Ray 会拒绝未启用 OTA 的连接。当使用 AEAD 加密时,该选项无效。"
msgid "transit node"
msgstr "中转到此节点"
msgid "Bind Local"
msgstr "本机监听"
msgid "When selected, it can only be accessed locally,It is recommended to turn on when using reverse proxies."
msgstr "当勾选时,只能由本机访问此端口,当开启反向代理时建议勾选此项。"
msgid "Accept LAN Access"
msgstr "接受局域网访问"
msgid "When selected, it can accessed lan , this will not be safe!"
msgstr "当勾选时,可以直接访问局域网,这将不安全!(非特殊情况不建议开启)"
msgid "Enable Remote"
msgstr "启用转发"
msgid "You can forward to Nginx/Caddy/V2ray WebSocket and more."
msgstr "您可以转发到Nginx/Caddy/V2ray WebSocket等。"
msgid "Remote Address"
msgstr "远程地址"
msgid "Remote Port"
msgstr "远程端口"
msgid "as:"
msgstr "如:"
msgid "Public key absolute path"
msgstr "公钥文件绝对路径"
msgid "Private key absolute path"
msgstr "私钥文件绝对路径"
msgid "Server-Side"
msgstr "服务器端"
msgid "Server Config"
msgstr "服务器配置"
msgid "Users Manager"
msgstr "用户管理"
msgid "Logs"
msgstr "日志"
msgid "UDP Forward"
msgstr "UDP转发"
msgid "Can't determine ARCH, or ARCH not supported."
msgstr "无法确认ARCH架构或是不支持。"

View File

@ -3,7 +3,6 @@ config global
option enabled '0'
option tcp_node1 'nil'
option udp_node1 'nil'
option socks_node1 'nil'
option dns_mode 'pdnsd'
option up_china_dns 'default'
option dns_forward '8.8.4.4'
@ -27,9 +26,6 @@ config global_forwarding
option udp_no_redir_ports '80,443'
option tcp_redir_ports '22,25,53,143,465,587,993,995,80,443'
option udp_redir_ports '1:65535'
option socks_proxy_port1 '1081'
option socks_proxy_port2 '1082'
option socks_proxy_port3 '1083'
option proxy_ipv6 '0'
config global_other
@ -37,7 +33,6 @@ config global_other
option auto_ping '1'
option tcp_node_num '1'
option udp_node_num '1'
option socks_node_num '1'
option status_use_big_icon '1'
option status_show_check_port '0'
option status_show_ip111 '0'
@ -50,10 +45,13 @@ config global_rules
option chnlist_update '1'
option chnroute_update '1'
option gfwlist_update '1'
option gfwlist_version '2020-03-10'
option chnroute_version '2020-03-10'
option chnlist_version '2020-03-10'
option gfwlist_version '2020-04-14'
option chnroute_version '2020-05-22'
option chnlist_version '2020-05-22'
option enable_custom_url '0'
option gfwlist_url 'https://cdn.jsdelivr.net/gh/Loukky/gfwlist-by-loukky/gfwlist.txt'
option chnroute_url 'https://ispip.clang.cn/all_cn.txt'
config global_app
option v2ray_file '/usr/bin/v2ray/'
option kcptun_client_file '/usr/bin/kcptun-client'
@ -64,6 +62,7 @@ config global_subscribe
option auto_update_subscribe '0'
option filter_enabled '1'
option filter_keyword_discarded '1'
option allowInsecure '1'
list filter_keyword '过期时间'
list filter_keyword '剩余流量'
list filter_keyword 'QQ群'
@ -72,3 +71,28 @@ config global_subscribe
config auto_switch
option testing_time '1'
option enable '0'
config shunt_rules 'youtube'
option remarks 'youtube'
option domain_list 'youtube
youtube.com
youtu.be
googlevideo.com
ytimg.com
gvt2.com'
config shunt_rules 'netflix'
option remarks '奈飞'
option domain_list 'netflix
netflix.com
nflxso.net
nflxext.com
nflximg.com
nflximg.net
nflxvideo.net
fast.com'
config shunt_rules 'TVB'
option remarks 'TVB'
option domain_list 'tvb.com
mytvsuper.com'

View File

@ -0,0 +1,4 @@
config global 'global'
option enable '0'

View File

@ -0,0 +1,16 @@
#!/bin/sh /etc/rc.common
START=99
start() {
/usr/lib/lua/luci/model/cbi/passwall/server/api/app.lua start
}
stop() {
/usr/lib/lua/luci/model/cbi/passwall/server/api/app.lua stop
}
restart() {
stop
start
}

View File

@ -11,9 +11,19 @@ uci -q batch <<-EOF >/dev/null
set firewall.passwall.path=/var/etc/passwall.include
set firewall.passwall.reload=1
commit firewall
delete ucitrack.@passwall_server[-1]
add ucitrack passwall_server
set ucitrack.@passwall_server[-1].init=passwall_server
commit ucitrack
delete firewall.passwall_server
set firewall.passwall_server=include
set firewall.passwall_server.type=script
set firewall.passwall_server.path=/var/etc/passwall_server.include
set firewall.passwall_server.reload=1
commit firewall
set uhttpd.main.max_requests=50
commit uhttpd
EOF
killall -q -9 kcptun haproxy shadowsocks-libev shadowsocksr-libev
/etc/init.d/haproxy disable && /etc/init.d/haproxy stop
rm -rf /tmp/luci-*cache
exit 0

View File

@ -17,10 +17,9 @@ DNSMASQ_PATH=/etc/dnsmasq.d
RESOLVFILE=/tmp/resolv.conf.d/resolv.conf.auto
DNS_PORT=7913
LUA_API_PATH=/usr/lib/lua/luci/model/cbi/$CONFIG/api
API_GEN_TROJAN=$LUA_API_PATH/gen_trojan.lua
API_GEN_SS=$LUA_API_PATH/gen_shadowsocks.lua
API_GEN_V2RAY=$LUA_API_PATH/gen_v2ray.lua
API_GEN_V2RAY_BALANCING=$LUA_API_PATH/gen_v2ray_balancing.lua
API_GEN_V2RAY_SHUNT=$LUA_API_PATH/gen_v2ray_shunt.lua
API_GEN_TROJAN=$LUA_API_PATH/gen_trojan.lua
echolog() {
local d="$(date "+%Y-%m-%d %H:%M:%S")"
@ -104,7 +103,7 @@ check_port_exists() {
get_new_port() {
port=$1
[ "$port" == "auto" ] && port=$SOCKS_REDIR_PORT3
[ "$port" == "auto" ] && port=2082
protocol=$2
result=$(check_port_exists $port $protocol)
if [ "$result" = 1 ]; then
@ -156,19 +155,11 @@ UDP_REDIR_PORT1=$(config_t_get global_forwarding udp_redir_port 1051)
UDP_REDIR_PORT2=$(expr $UDP_REDIR_PORT1 + 1)
UDP_REDIR_PORT3=$(expr $UDP_REDIR_PORT2 + 1)
SOCKS_NODE_NUM=$(config_t_get global_other socks_node_num 1)
for i in $(seq 1 $SOCKS_NODE_NUM); do
eval SOCKS_NODE$i=$(config_t_get global socks_node$i nil)
done
SOCKS_REDIR_PORT1=$(config_t_get global_forwarding socks_proxy_port1 1081)
SOCKS_REDIR_PORT2=$(config_t_get global_forwarding socks_proxy_port2 1082)
SOCKS_REDIR_PORT3=$(config_t_get global_forwarding socks_proxy_port3 1083)
[ "$UDP_NODE1" == "tcp" ] && UDP_NODE1=$TCP_NODE1
[ "$SOCKS_NODE1" == "tcp" ] && SOCKS_NODE1=$TCP_NODE1
[ "$UDP_NODE1" == "tcp_" ] && UDP_NODE1=$TCP_NODE1
[ "$UDP_NODE1" == "tcp" ] && UDP_REDIR_PORT1=$TCP_REDIR_PORT1
# Dynamic variables (Used to record)
# TCP_NODE1_IP="" UDP_NODE1_IP="" SOCKS_NODE1_IP="" TCP_NODE1_PORT="" UDP_NODE1_PORT="" SOCKS_NODE1_PORT="" TCP_NODE1_TYPE="" UDP_NODE1_TYPE="" SOCKS_NODE1_TYPE=""
# TCP_NODE1_IP="" UDP_NODE1_IP="" TCP_NODE1_PORT="" UDP_NODE1_PORT="" TCP_NODE1_TYPE="" UDP_NODE1_TYPE=""
TCP_REDIR_PORTS=$(config_t_get global_forwarding tcp_redir_ports '80,443')
UDP_REDIR_PORTS=$(config_t_get global_forwarding udp_redir_ports '1:65535')
@ -183,14 +174,26 @@ LOCALHOST_UDP_PROXY_MODE=$(config_t_get global localhost_udp_proxy_mode default)
[ "$LOCALHOST_UDP_PROXY_MODE" == "default" ] && LOCALHOST_UDP_PROXY_MODE=$UDP_PROXY_MODE
load_config() {
local auto_switch_list=$(config_t_get auto_switch tcp_node1 nil)
[ -n "$auto_switch_list" -a "$auto_switch_list" != "nil" ] && {
for tmp in $auto_switch_list; do
tmp_id=$(config_n_get $tmp address nil)
[ "$tmp_id" == "nil" ] && {
uci -q del_list $CONFIG.@auto_switch[0].tcp_node1=$tmp
uci commit $CONFIG
}
done
}
[ "$ENABLED" != 1 ] && return 1
[ "$TCP_NODE1" == "nil" -a "$UDP_NODE1" == "nil" -a "$SOCKS_NODE1" == "nil" ] && {
[ "$TCP_NODE1" == "nil" -a "$UDP_NODE1" == "nil" ] && {
echolog "没有选择节点!"
return 1
}
DNS_MODE=$(config_t_get global dns_mode pdnsd)
DNS_FORWARD=$(config_t_get global dns_forward 8.8.4.4)
DNS_CACHE=$(config_t_get global dns_cache 1)
use_tcp_node_resolve_dns=0
use_udp_node_resolve_dns=0
process=1
@ -224,191 +227,126 @@ load_config() {
return 0
}
gen_ss_ssr_config_file() {
local type local_port kcptun node configfile
type=$1
local_port=$2
kcptun=$3
node=$4
configfile=$5
local port encrypt_method
port=$(config_n_get $node port)
encrypt_method=$(config_n_get $node ss_encrypt_method)
[ "$type" == "ssr" ] && encrypt_method=$(config_n_get $node ssr_encrypt_method)
[ "$kcptun" == "1" ] && {
server_host=127.0.0.1
port=$KCPTUN_REDIR_PORT
}
cat <<-EOF >$configfile
{
"server": "$server_host",
"server_port": $port,
"local_address": "0.0.0.0",
"local_port": $local_port,
"password": "$(config_n_get $node password)",
"timeout": $(config_n_get $node timeout),
"method": "$encrypt_method",
"fast_open": $(config_n_get $node tcp_fast_open false),
"reuse_port": true,
EOF
[ "$1" == "ssr" ] && {
cat <<-EOF >>$configfile
"protocol": "$(config_n_get $node protocol)",
"protocol_param": "$(config_n_get $node protocol_param)",
"obfs": "$(config_n_get $node obfs)",
"obfs_param": "$(config_n_get $node obfs_param)"
EOF
}
echo -e "}" >>$configfile
}
gen_start_config() {
local node local_port redir_type config_file bind server_host port type
node=$1
local_port=$2
redir_type=$3
config_file=$4
bind="0.0.0.0"
[ -n "$6" ] && bind="$6"
type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
remarks=$(config_n_get $node remarks)
server_host=$(config_n_get $node address)
port=$(config_n_get $node port)
run_socks() {
local node=$1
local bind=$2
local local_port=$3
local config_file=$4
local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
local remarks=$(config_n_get $node remarks)
local server_host=$(config_n_get $node address)
local port=$(config_n_get $node port)
[ -n "$server_host" -a -n "$port" ] && {
# 判断节点服务器地址是否URL并去掉~
server_host=$(echo $server_host | sed 's/^\(https:\/\/\|http:\/\/\)//g' | awk -F '/' '{print $1}')
local server_host=$(echo $server_host | sed 's/^\(https:\/\/\|http:\/\/\)//g' | awk -F '/' '{print $1}')
# 判断节点服务器地址是否包含汉字~
local tmp=$(echo -n $server_host | awk '{print gensub(/[!-~]/,"","g",$0)}')
[ -n "$tmp" ] && {
echolog "${redir_type}_${5}节点,非法的服务器地址,无法启动!"
echolog "$remarks,非法的服务器地址,无法启动!"
return 1
}
[ "$bind" == "0.0.0.0" ] && echolog "${redir_type}_${5}节点:$remarks,节点${server_host}:${port},监听端口:$local_port"
[ "$bind" != "127.0.0.1" ] && echolog "Socks节点$remarks,地址:${server_host}:${port},监听端口:$local_port"
}
if [ "$redir_type" == "SOCKS" ]; then
eval SOCKS_NODE${5}_PORT=$port
if [ "$type" == "socks5" ]; then
echolog "Socks节点不能使用Socks代理节点"
elif [ "$type" == "v2ray" ]; then
lua $API_GEN_V2RAY $node nil nil $local_port >$config_file
ln_start_bin $(config_t_get global_app v2ray_file $(find_bin v2ray))/v2ray v2ray_socks_$5 "-config=$config_file"
elif [ "$type" == "v2ray_balancing" ]; then
lua $API_GEN_V2RAY_BALANCING $node nil nil $local_port >$config_file
ln_start_bin $(config_t_get global_app v2ray_file $(find_bin v2ray))/v2ray v2ray_socks_$5 "-config=$config_file"
elif [ "$type" == "v2ray_shunt" ]; then
lua $API_GEN_V2RAY_SHUNT $node nil nil $local_port >$config_file
ln_start_bin $(config_t_get global_app v2ray_file $(find_bin v2ray))/v2ray v2ray_socks_$5 "-config=$config_file"
elif [ "$type" == "trojan" ]; then
lua $API_GEN_TROJAN $node client $bind $local_port >$config_file
ln_start_bin $(find_bin trojan) trojan_socks_$5 "-c $config_file"
elif [ "$type" == "brook" ]; then
local protocol=$(config_n_get $node brook_protocol client)
local brook_tls=$(config_n_get $node brook_tls 0)
[ "$protocol" == "wsclient" ] && {
[ "$brook_tls" == "1" ] && server_host="wss://${server_host}" || server_host="ws://${server_host}"
}
ln_start_bin $(config_t_get global_app brook_file $(find_bin brook)) brook_socks_$5 "$protocol -l $bind:$local_port -i $$bind -s $server_host:$port -p $(config_n_get $node password)"
elif [ "$type" == "ssr" ]; then
gen_ss_ssr_config_file ssr $local_port 0 $node $config_file
ln_start_bin $(find_bin ssr-local) ssr-local_socks_$5 "-c $config_file -b $bind -u"
elif [ "$type" == "ss" ]; then
gen_ss_ssr_config_file ss $local_port 0 $node $config_file
local plugin_params=""
local plugin=$(config_n_get $node ss_plugin)
if [ "$plugin" != "none" ]; then
[ "$plugin" == "v2ray-plugin" -o "$plugin" == "obfs-local" ] && {
local plugin_opts=""
local opts=$(config_n_get $node ss_plugin_opts)
[ -n "$opts" ] && plugin_opts="--plugin-opts $opts"
plugin_params="--plugin $plugin $plugin_opts"
}
fi
ln_start_bin $(find_bin ss-local) ss-local_socks_$5 "-c $config_file -b $bind -u $plugin_params"
fi
if [ "$type" == "socks" ]; then
echolog "Socks节点不能使用Socks代理节点"
elif [ "$type" == "v2ray" ]; then
lua $API_GEN_V2RAY $node nil nil $local_port > $config_file
ln_start_bin $(config_t_get global_app v2ray_file $(find_bin v2ray))/v2ray v2ray "-config=$config_file"
elif [ "$type" == "trojan" ]; then
lua $API_GEN_TROJAN $node client $bind $local_port > $config_file
ln_start_bin $(find_bin trojan) trojan "-c $config_file"
elif [ "$type" == "brook" ]; then
local protocol=$(config_n_get $node brook_protocol client)
local brook_tls=$(config_n_get $node brook_tls 0)
[ "$protocol" == "wsclient" ] && {
[ "$brook_tls" == "1" ] && server_host="wss://${server_host}" || server_host="ws://${server_host}"
}
ln_start_bin $(config_t_get global_app brook_file $(find_bin brook)) brook_socks_$5 "$protocol -l $bind:$local_port -i $$bind -s $server_host:$port -p $(config_n_get $node password)"
elif [ "$type" == "ssr" ] || [ "$type" == "ss" ]; then
lua $API_GEN_SS $node $local_port > $config_file
ln_start_bin $(find_bin ${type}-local) ${type}-local "-c $config_file -b $bind -u"
fi
}
run_redir() {
local node=$1
local bind=$2
local local_port=$3
local config_file=$4
local redir_type=$5
local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
local remarks=$(config_n_get $node remarks)
local server_host=$(config_n_get $node address)
local port=$(config_n_get $node port)
[ -n "$server_host" -a -n "$port" ] && {
# 判断节点服务器地址是否URL并去掉~
local server_host=$(echo $server_host | sed 's/^\(https:\/\/\|http:\/\/\)//g' | awk -F '/' '{print $1}')
# 判断节点服务器地址是否包含汉字~
local tmp=$(echo -n $server_host | awk '{print gensub(/[!-~]/,"","g",$0)}')
[ -n "$tmp" ] && {
echolog "$remarks节点,非法的服务器地址,无法启动!"
return 1
}
[ "$bind" != "127.0.0.1" ] && echolog "${redir_type}_${6}节点:$remarks,节点:${server_host}:${port},监听端口:$local_port"
}
eval ${redir_type}_NODE${6}_PORT=$port
if [ "$redir_type" == "UDP" ]; then
eval UDP_NODE${5}_PORT=$port
if [ "$type" == "socks5" ]; then
if [ "$type" == "socks" ]; then
local node_address=$(config_n_get $node address)
local node_port=$(config_n_get $node port)
local server_username=$(config_n_get $node username)
local server_password=$(config_n_get $node password)
eval port=\$UDP_REDIR_PORT$5
ln_start_bin $(find_bin ipt2socks) ipt2socks_udp_$5 "-4 -U -l $port -b 0.0.0.0 -s $node_address -p $node_port -R"
eval port=\$UDP_REDIR_PORT$6
ln_start_bin $(find_bin ipt2socks) ipt2socks_udp_$6 "-U -l $port -b 0.0.0.0 -s $node_address -p $node_port -R"
elif [ "$type" == "v2ray" ]; then
lua $API_GEN_V2RAY $node udp $local_port nil >$config_file
ln_start_bin $(config_t_get global_app v2ray_file $(find_bin v2ray))/v2ray v2ray_udp_$5 "-config=$config_file"
elif [ "$type" == "v2ray_balancing" ]; then
lua $API_GEN_V2RAY_BALANCING $node udp $local_port nil >$config_file
ln_start_bin $(config_t_get global_app v2ray_file $(find_bin v2ray))/v2ray v2ray_udp_$5 "-config=$config_file"
elif [ "$type" == "v2ray_shunt" ]; then
lua $API_GEN_V2RAY_SHUNT $node udp $local_port nil >$config_file
ln_start_bin $(config_t_get global_app v2ray_file $(find_bin v2ray))/v2ray v2ray_udp_$5 "-config=$config_file"
lua $API_GEN_V2RAY $node udp $local_port nil > $config_file
ln_start_bin $(config_t_get global_app v2ray_file $(find_bin v2ray))/v2ray v2ray "-config=$config_file"
elif [ "$type" == "trojan" ]; then
SOCKS_REDIR_PORT4=$(expr $SOCKS_REDIR_PORT3 + 1)
local_port=$(get_new_port $SOCKS_REDIR_PORT4 tcp)
socks_port=$local_port
lua $API_GEN_TROJAN $node client "127.0.0.1" $socks_port >$config_file
ln_start_bin $(find_bin trojan) trojan_udp_$5 "-c $config_file"
local_port=$(get_new_port 2080 tcp)
lua $API_GEN_TROJAN $node client "127.0.0.1" $local_port > $config_file
ln_start_bin $(find_bin trojan) trojan "-c $config_file"
local node_address=$(config_n_get $node address)
local node_port=$(config_n_get $node port)
local server_username=$(config_n_get $node username)
local server_password=$(config_n_get $node password)
eval port=\$UDP_REDIR_PORT$5
ln_start_bin $(find_bin ipt2socks) ipt2socks_udp_$5 "-4 -U -l $port -b 0.0.0.0 -s 127.0.0.1 -p $socks_port -R"
eval port=\$UDP_REDIR_PORT$6
ln_start_bin $(find_bin ipt2socks) ipt2socks_udp_$6 "-U -l $port -b 0.0.0.0 -s 127.0.0.1 -p $local_port -R"
elif [ "$type" == "brook" ]; then
local protocol=$(config_n_get $node brook_protocol client)
if [ "$protocol" == "wsclient" ]; then
echolog "Brook的WebSocket不支持UDP转发"
else
ln_start_bin $(config_t_get global_app brook_file $(find_bin brook)) brook_udp_$5 "tproxy -l 0.0.0.0:$local_port -s $server_host:$port -p $(config_n_get $node password)"
ln_start_bin $(config_t_get global_app brook_file $(find_bin brook)) brook_udp_$6 "tproxy -l 0.0.0.0:$local_port -s $server_host:$port -p $(config_n_get $node password)"
fi
elif [ "$type" == "ssr" ]; then
gen_ss_ssr_config_file ssr $local_port 0 $node $config_file
ln_start_bin $(find_bin ssr-redir) ssr-redir_udp_$5 "-c $config_file -U"
elif [ "$type" == "ss" ]; then
gen_ss_ssr_config_file ss $local_port 0 $node $config_file
local plugin_params=""
local plugin=$(config_n_get $node ss_plugin)
if [ "$plugin" != "none" ]; then
[ "$plugin" == "v2ray-plugin" -o "$plugin" == "obfs-local" ] && {
local plugin_opts=""
local opts=$(config_n_get $node ss_plugin_opts)
[ -n "$opts" ] && plugin_opts="--plugin-opts $opts"
plugin_params="--plugin $plugin $plugin_opts"
}
fi
ln_start_bin $(find_bin ss-redir) ss-redir_udp_$5 "-c $config_file -U $plugin_params"
elif [ "$type" == "ssr" ] || [ "$type" == "ss" ]; then
lua $API_GEN_SS $node $local_port > $config_file
ln_start_bin $(find_bin ${type}-redir) ${type}-redir "-c $config_file -U"
fi
fi
if [ "$redir_type" == "TCP" ]; then
eval TCP_NODE${5}_PORT=$port
if [ "$type" == "socks5" ]; then
if [ "$type" == "socks" ]; then
local node_address=$(config_n_get $node address)
local node_port=$(config_n_get $node port)
local server_username=$(config_n_get $node username)
local server_password=$(config_n_get $node password)
eval port=\$TCP_REDIR_PORT$5
ln_start_bin $(find_bin ipt2socks) ipt2socks_tcp_$5 "-4 -T -l $port -b 0.0.0.0 -s $node_address -p $node_port -R"
eval port=\$TCP_REDIR_PORT$6
local extra_param="-T"
[ "$6" == 1 ] && [ "$UDP_NODE1" == "tcp" ] && extra_param=""
ln_start_bin $(find_bin ipt2socks) ipt2socks_tcp_$6 "-l $port -b 0.0.0.0 -s $node_address -p $node_port -R $extra_param"
elif [ "$type" == "v2ray" ]; then
lua $API_GEN_V2RAY $node tcp $local_port nil >$config_file
ln_start_bin $(config_t_get global_app v2ray_file $(find_bin v2ray))/v2ray v2ray_tcp_$5 "-config=$config_file"
elif [ "$type" == "v2ray_balancing" ]; then
lua $API_GEN_V2RAY_BALANCING $node tcp $local_port nil >$config_file
ln_start_bin $(config_t_get global_app v2ray_file $(find_bin v2ray))/v2ray v2ray_tcp_$5 "-config=$config_file"
elif [ "$type" == "v2ray_shunt" ]; then
lua $API_GEN_V2RAY_SHUNT $node tcp $local_port nil >$config_file
ln_start_bin $(config_t_get global_app v2ray_file $(find_bin v2ray))/v2ray v2ray_tcp_$5 "-config=$config_file"
local extra_param="tcp"
[ "$6" == 1 ] && [ "$UDP_NODE1" == "tcp" ] && extra_param="tcp,udp"
lua $API_GEN_V2RAY $node $extra_param $local_port nil > $config_file
ln_start_bin $(config_t_get global_app v2ray_file $(find_bin v2ray))/v2ray v2ray "-config=$config_file"
elif [ "$type" == "trojan" ]; then
lua $API_GEN_TROJAN $node nat "0.0.0.0" $local_port >$config_file
lua $API_GEN_TROJAN $node nat "0.0.0.0" $local_port > $config_file
[ "$6" == 1 ] && [ "$UDP_NODE1" == "tcp" ] && echolog "Trojan的NAT模式不支持UDP转发"
for k in $(seq 1 $process); do
ln_start_bin $(find_bin trojan) trojan_tcp_$5 "-c $config_file"
ln_start_bin $(find_bin trojan) trojan "-c $config_file"
done
else
local kcptun_use=$(config_n_get $node use_kcp 0)
@ -424,28 +362,19 @@ gen_start_config() {
local run_kcptun_ip=$server_host
[ -n "$kcptun_server_host" ] && run_kcptun_ip=$(get_host_ip $network_type $kcptun_server_host)
KCPTUN_REDIR_PORT=$(get_new_port $KCPTUN_REDIR_PORT tcp)
ln_start_bin $(config_t_get global_app kcptun_client_file $(find_bin kcptun-client)) kcptun_tcp_$5 "-l 0.0.0.0:$KCPTUN_REDIR_PORT -r $run_kcptun_ip:$kcptun_port $kcptun_config"
ln_start_bin $(config_t_get global_app kcptun_client_file $(find_bin kcptun-client)) kcptun_tcp_$6 "-l 0.0.0.0:$KCPTUN_REDIR_PORT -r $run_kcptun_ip:$kcptun_port $kcptun_config"
fi
fi
if [ "$type" == "ssr" ]; then
gen_ss_ssr_config_file ssr $local_port $kcptun_use $node $config_file
for k in $(seq 1 $process); do
ln_start_bin $(find_bin ssr-redir) ssr-redir_tcp_$5 "-c $config_file"
done
elif [ "$type" == "ss" ]; then
gen_ss_ssr_config_file ss $local_port $kcptun_use $node $config_file
local plugin_params=""
local plugin=$(config_n_get $node ss_plugin)
if [ "$plugin" != "none" ]; then
[ "$plugin" == "v2ray-plugin" -o "$plugin" == "obfs-local" ] && {
local plugin_opts=""
local opts=$(config_n_get $node ss_plugin_opts)
[ -n "$opts" ] && plugin_opts="--plugin-opts $opts"
plugin_params="--plugin $plugin $plugin_opts"
}
if [ "$type" == "ssr" ] || [ "$type" == "ss" ]; then
if [ "$kcptun_use" == "1" ]; then
lua $API_GEN_SS $node $local_port 127.0.0.1 $KCPTUN_REDIR_PORT > $config_file
[ "$6" == 1 ] && [ "$UDP_NODE1" == "tcp" ] && echolog "Kcptun不支持UDP转发"
else
lua $API_GEN_SS $node $local_port > $config_file
[ "$6" == 1 ] && [ "$UDP_NODE1" == "tcp" ] && extra_param="-u"
fi
for k in $(seq 1 $process); do
ln_start_bin $(find_bin ss-redir) ss-redir_tcp_$5 "-c $config_file $plugin_params"
ln_start_bin $(find_bin ${type}-redir) ${type}-redir "-c $config_file $extra_param"
done
elif [ "$type" == "brook" ]; then
local server_ip=$server_host
@ -453,17 +382,18 @@ gen_start_config() {
local brook_tls=$(config_n_get $node brook_tls 0)
if [ "$protocol" == "wsclient" ]; then
[ "$brook_tls" == "1" ] && server_ip="wss://${server_ip}" || server_ip="ws://${server_ip}"
socks_port=$(get_new_port $(expr $SOCKS_REDIR_PORT3 + 3) tcp)
ln_start_bin $(config_t_get global_app brook_file $(find_bin brook)) brook_tcp_$5 "wsclient -l 127.0.0.1:$socks_port -i 127.0.0.1 -s $server_ip:$port -p $(config_n_get $node password)"
eval port=\$TCP_REDIR_PORT$5
ln_start_bin $(find_bin ipt2socks) ipt2socks_tcp_$5 "-4 -T -l $port -b 0.0.0.0 -s 127.0.0.1 -p $socks5_port -R"
socks_port=$(get_new_port 2081 tcp)
ln_start_bin $(config_t_get global_app brook_file $(find_bin brook)) brook_tcp_$6 "wsclient -l 127.0.0.1:$socks_port -i 127.0.0.1 -s $server_ip:$port -p $(config_n_get $node password)"
eval port=\$TCP_REDIR_PORT$6
ln_start_bin $(find_bin ipt2socks) ipt2socks_tcp_$6 "-T -l $port -b 0.0.0.0 -s 127.0.0.1 -p $socks_port -R"
echolog "Brook的WebSocket不支持透明代理将使用ipt2socks转换透明代理"
[ "$6" == 1 ] && [ "$UDP_NODE1" == "tcp" ] && echolog "Brook的WebSocket不支持UDP转发"
else
[ "$kcptun_use" == "1" ] && {
server_ip=127.0.0.1
port=$KCPTUN_REDIR_PORT
}
ln_start_bin $(config_t_get global_app brook_file $(find_bin brook)) brook_tcp_$5 "tproxy -l 0.0.0.0:$local_port -s $server_ip:$port -p $(config_n_get $node password)"
ln_start_bin $(config_t_get global_app brook_file $(find_bin brook)) brook_tcp_$6 "tproxy -l 0.0.0.0:$local_port -s $server_ip:$port -p $(config_n_get $node password)"
fi
fi
fi
@ -479,7 +409,7 @@ node_switch() {
local config_file=$TMP_PATH/${1}_${i}.json
eval current_port=\$${1}_REDIR_PORT${i}
local port=$(cat $TMP_PORT_PATH/${1}_${i})
gen_start_config $node $port $1 $config_file $i
run_redir $node "0.0.0.0" $port $config_file $1 $i
echo $node > $TMP_ID_PATH/${1}_${i}
local node_net=$(echo $1 | tr 'A-Z' 'a-z')
uci set $CONFIG.@global[0].${node_net}_node${i}=$node
@ -498,7 +428,7 @@ start_redir() {
eval current_port=\$${1}_REDIR_PORT$i
local port=$(echo $(get_new_port $current_port $2))
eval ${1}_REDIR${i}=$port
gen_start_config $node $port $1 $config_file $i
run_redir $node "0.0.0.0" $port $config_file $1 $i
#eval ip=\$${1}_NODE${i}_IP
echo $node > $TMP_ID_PATH/${1}_${i}
echo $port > $TMP_PORT_PATH/${1}_${i}
@ -506,6 +436,23 @@ start_redir() {
done
}
start_socks() {
local ids=$(uci show $CONFIG | grep "=socks" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}')
for id in $ids; do
local enabled=$(config_n_get $id enabled 0)
[ "$enabled" == "0" ] && continue
local node=$(config_n_get $id node nil)
if [ "$(echo $node | grep ^tcp)" ]; then
local num=$(echo $node | sed "s/tcp//g")
eval node=\$TCP_NODE$num
fi
[ "$node" == "nil" ] && continue
local config_file=$TMP_PATH/SOCKS_${id}.json
local port=$(config_n_get $id port)
run_socks $node "0.0.0.0" $port $config_file $id
done
}
clean_log() {
logsnum=$(cat $LOG_FILE 2>/dev/null | wc -l)
[ "$logsnum" -gt 300 ] && {
@ -515,6 +462,7 @@ clean_log() {
}
start_crontab() {
touch /etc/crontabs/root
sed -i '/$CONFIG/d' /etc/crontabs/root >/dev/null 2>&1 &
auto_on=$(config_t_get global_delay auto_on 0)
if [ "$auto_on" = "1" ]; then
@ -565,6 +513,7 @@ start_crontab() {
}
stop_crontab() {
touch /etc/crontabs/root
sed -i "/$CONFIG/d" /etc/crontabs/root >/dev/null 2>&1 &
ps | grep "$APP_PATH/test.sh" | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &
/etc/init.d/cron restart
@ -580,24 +529,24 @@ start_dns() {
echolog "DNS使用本机7913端口DNS服务器解析域名..."
;;
dns2socks)
if [ -n "$SOCKS_NODE1" -a "$SOCKS_NODE1" != "nil" ]; then
DNS2SOCKS_FORWARD=$(config_t_get global dns2socks_forward 8.8.4.4)
ln_start_bin $(find_bin dns2socks) dns2socks "127.0.0.1:$SOCKS_REDIR_PORT1 $DNS2SOCKS_FORWARD 127.0.0.1:$DNS_PORT"
echolog "DNSdns2socks..."
else
echolog "DNSdns2socks模式需要使用Socks代理节点请开启"
force_stop
fi
DNS2SOCKS_SOCKS_SERVER=$(echo $(config_t_get global socks_server nil) | sed "s/#/:/g")
[ "$DNS2SOCKS_SOCKS_SERVER" != "nil" ] && {
DNS2SOCKS_FORWARD=$(echo $DNS_FORWARD | awk -F ',' '{print $1}')
[ -z "$DNS2SOCKS_FORWARD" ] && DNS2SOCKS_FORWARD="8.8.4.4"
[ "$DNS_CACHE" == "0" ] && local _cache="/d"
ln_start_bin $(find_bin dns2socks) dns2socks "$DNS2SOCKS_SOCKS_SERVER $DNS2SOCKS_FORWARD 127.0.0.1:$DNS_PORT $_cache"
echolog "DNSdns2socks($DNS2SOCKS_FORWARD)..."
}
;;
pdnsd)
if [ -z "$TCP_NODE1" -o "$TCP_NODE1" == "nil" ]; then
echolog "DNSpdnsd 模式需要启用TCP节点"
force_stop
else
gen_pdnsd_config $DNS_PORT 2048
DNS_FORWARD=$(echo $DNS_FORWARD | sed 's/,/ /g')
gen_pdnsd_config $DNS_PORT
ln_start_bin $(find_bin pdnsd) pdnsd "--daemon -c $pdnsd_dir/pdnsd.conf -d"
echolog "DNSpdnsd + 使用TCP节点解析DNS$DNS_FORWARD..."
DNS_FORWARD=$(echo $DNS_FORWARD | sed 's/,/ /g')
fi
;;
chinadns-ng)
@ -610,36 +559,43 @@ start_dns() {
[ -f "$RULES_PATH/chnlist" ] && cp -a $RULES_PATH/chnlist $TMP_PATH/chnlist
[ -f "$TMP_PATH/chnlist" ] && {
[ -f "$RULES_PATH/whitelist_host" -a -s "$RULES_PATH/whitelist_host" ] && cat $RULES_PATH/whitelist_host >> $TMP_PATH/chnlist
local chnlist_param="-m $TMP_PATH/chnlist -M -f"
local chnlist_param="-m $TMP_PATH/chnlist -M"
}
local fair_mode=$(config_t_get global fair_mode 1)
if [ "$fair_mode" == "1" ]; then
fair_mode="-f"
else
fair_mode=""
fi
up_trust_chinadns_ng_dns=$(config_t_get global up_trust_chinadns_ng_dns "pdnsd")
if [ "$up_trust_chinadns_ng_dns" == "pdnsd" ]; then
if [ -z "$TCP_NODE1" -o "$TCP_NODE1" == "nil" ]; then
echolog "DNSChinaDNS-NG + pdnsd 模式需要启用TCP节点"
force_stop
else
gen_pdnsd_config $other_port 0
DNS_FORWARD=$(echo $DNS_FORWARD | sed 's/,/ /g')
gen_pdnsd_config $other_port
ln_start_bin $(find_bin pdnsd) pdnsd "--daemon -c $pdnsd_dir/pdnsd.conf -d"
ln_start_bin $(find_bin chinadns-ng) chinadns-ng "-l $DNS_PORT -c $UP_CHINA_DNS -t 127.0.0.1#$other_port $gfwlist_param $chnlist_param"
ln_start_bin $(find_bin chinadns-ng) chinadns-ng "-l $DNS_PORT -c $UP_CHINA_DNS -t 127.0.0.1#$other_port $gfwlist_param $chnlist_param $fair_mode"
echolog "DNSChinaDNS-NG + pdnsd($DNS_FORWARD)国内DNS$UP_CHINA_DNS"
DNS_FORWARD=$(echo $DNS_FORWARD | sed 's/,/ /g')
fi
elif [ "$up_trust_chinadns_ng_dns" == "dns2socks" ]; then
if [ -n "$SOCKS_NODE1" -a "$SOCKS_NODE1" != "nil" ]; then
DNS2SOCKS_FORWARD=$(config_t_get global dns2socks_forward 8.8.4.4)
ln_start_bin $(find_bin dns2socks) dns2socks "127.0.0.1:$SOCKS_REDIR_PORT1 $DNS2SOCKS_FORWARD 127.0.0.1:$other_port"
ln_start_bin $(find_bin chinadns-ng) chinadns-ng "-l $DNS_PORT -c $UP_CHINA_DNS -t 127.0.0.1#$other_port $gfwlist_param $chnlist_param"
DNS2SOCKS_SOCKS_SERVER=$(echo $(config_t_get global socks_server nil) | sed "s/#/:/g")
[ "$DNS2SOCKS_SOCKS_SERVER" != "nil" ] && {
DNS2SOCKS_FORWARD=$(echo $DNS_FORWARD | awk -F ',' '{print $1}')
[ -z "$DNS2SOCKS_FORWARD" ] && DNS2SOCKS_FORWARD="8.8.4.4"
[ "$DNS_CACHE" == "0" ] && local _cache="/d"
ln_start_bin $(find_bin dns2socks) dns2socks "$DNS2SOCKS_SOCKS_SERVER $DNS2SOCKS_FORWARD 127.0.0.1:$other_port $_cache"
ln_start_bin $(find_bin chinadns-ng) chinadns-ng "-l $DNS_PORT -c $UP_CHINA_DNS -t 127.0.0.1#$other_port $gfwlist_param $chnlist_param $fair_mode"
echolog "DNSChinaDNS-NG + dns2socks($DNS2SOCKS_FORWARD)国内DNS$UP_CHINA_DNS"
else
echolog "DNSdns2socks模式需要使用Socks代理节点请开启"
force_stop
fi
else
}
elif [ "$up_trust_chinadns_ng_dns" == "udp" ]; then
use_udp_node_resolve_dns=1
DNS_FORWARD=$(echo $up_trust_chinadns_ng_dns | sed 's/,/ /g')
ln_start_bin $(find_bin chinadns-ng) chinadns-ng "-l $DNS_PORT -c $UP_CHINA_DNS -t $up_trust_chinadns_ng_dns $gfwlist_param $chnlist_param"
ln_start_bin $(find_bin chinadns-ng) chinadns-ng "-l $DNS_PORT -c $UP_CHINA_DNS -t $DNS_FORWARD $gfwlist_param $chnlist_param $fair_mode"
echolog "DNSChinaDNS-NG国内DNS$UP_CHINA_DNS可信DNS$up_trust_chinadns_ng_dns如果不能使用请确保UDP节点已打开并且支持UDP转发。"
DNS_FORWARD=$(echo $DNS_FORWARD | sed 's/,/ /g')
fi
;;
esac
@ -656,7 +612,7 @@ add_dnsmasq() {
[ "$DNS_MODE" != "nonuse" ] && {
[ -f "$RULES_PATH/whitelist_host" -a -s "$RULES_PATH/whitelist_host" ] && cat $RULES_PATH/whitelist_host | sed -e "/^$/d" | sort -u | awk '{if (mode == 0 && dns1 != "") print "server=/."$1"/'$UP_CHINA_DNS1'"; if (mode == 0 && dns2 != "") print "server=/."$1"/'$UP_CHINA_DNS2'"; print "ipset=/."$1"/whitelist"}' mode=$chinadns_mode dns1=$UP_CHINA_DNS1 dns2=$UP_CHINA_DNS2 > $TMP_DNSMASQ_PATH/whitelist_host.conf
uci show $CONFIG | grep "@nodes" | grep "address" | cut -d "'" -f 2 | sed 's/^\(https:\/\/\|http:\/\/\)//g' | awk -F '/' '{print $1}' | grep -v "google.c" | grep -E '.*\..*$' | grep '[a-zA-Z]$' | sort -u | awk '{if (dns1 != "") print "server=/."$1"/'$UP_CHINA_DNS1'"; if (dns2 != "") print "server=/."$1"/'$UP_CHINA_DNS2'"; print "ipset=/."$1"/vpsiplist"}' dns1=$UP_CHINA_DNS1 dns2=$UP_CHINA_DNS2 > $TMP_DNSMASQ_PATH/vpsiplist_host.conf
uci show $CONFIG | grep ".address=" | cut -d "'" -f 2 | sed 's/^\(https:\/\/\|http:\/\/\)//g' | awk -F '/' '{print $1}' | grep -v "google.c" | grep -E '.*\..*$' | grep '[a-zA-Z]$' | sort -u | awk '{if (dns1 != "") print "server=/."$1"/'$UP_CHINA_DNS1'"; if (dns2 != "") print "server=/."$1"/'$UP_CHINA_DNS2'"; print "ipset=/."$1"/vpsiplist"}' dns1=$UP_CHINA_DNS1 dns2=$UP_CHINA_DNS2 > $TMP_DNSMASQ_PATH/vpsiplist_host.conf
[ -f "$RULES_PATH/blacklist_host" -a -s "$RULES_PATH/blacklist_host" ] && cat $RULES_PATH/blacklist_host | sed -e "/^$/d" | sort -u | awk '{if (mode == 0) print "server=/."$1"/127.0.0.1#'$DNS_PORT'"; print "ipset=/."$1"/blacklist"}' mode=$chinadns_mode > $TMP_DNSMASQ_PATH/blacklist_host.conf
if [ "$chinadns_mode" == 0 ]; then
[ -f "$RULES_PATH/gfwlist.conf" -a -s "$RULES_PATH/gfwlist.conf" ] && ln -s $RULES_PATH/gfwlist.conf $TMP_DNSMASQ_PATH/gfwlist.conf
@ -703,7 +659,6 @@ add_dnsmasq() {
no-resolv
EOF
else
# 防呆
[ -z "$DEFAULT_DNS1" ] && {
local tmp=$(get_host_ip ipv4 www.baidu.com 1)
[ -z "$tmp" ] && {
@ -728,9 +683,12 @@ gen_pdnsd_config() {
mkdir -p $pdnsd_dir
touch $pdnsd_dir/pdnsd.cache
chown -R root.nogroup $pdnsd_dir
local perm_cache=2048
local _cache="on"
[ "$DNS_CACHE" == "0" ] && _cache="off" && perm_cache=0
cat > $pdnsd_dir/pdnsd.conf <<-EOF
global {
perm_cache = $2;
perm_cache = $perm_cache;
cache_dir = "$pdnsd_dir";
run_as = "root";
server_ip = 127.0.0.1;
@ -748,7 +706,7 @@ gen_pdnsd_config() {
}
EOF
cat >> $pdnsd_dir/pdnsd.conf <<-EOF
server {
label = "node";
@ -759,6 +717,7 @@ gen_pdnsd_config() {
interval = 10m;
uptest = none;
purge_cache = off;
caching = $_cache;
}
EOF
@ -918,7 +877,7 @@ boot() {
start() {
! load_config && return 1
start_haproxy
start_redir SOCKS tcp
start_socks
start_redir TCP tcp
start_redir UDP udp
start_dns
@ -935,7 +894,7 @@ stop() {
kill_all v2ray-plugin obfs-local
ps -w | grep -v "grep" | grep $CONFIG/test.sh | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &
ps -w | grep -v "grep" | grep $CONFIG/monitor.sh | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &
ps -w | grep -v "grep" | grep -E "$TMP_PATH" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &
ps -w | grep -v -E "grep|${TMP_PATH}_server" | grep -E "$TMP_PATH" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &
ps -w | grep -v "grep" | grep "sleep 1m" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &
rm -rf $TMP_DNSMASQ_PATH $TMP_PATH
stop_crontab
@ -948,8 +907,11 @@ case $1 in
get_new_port)
get_new_port $2 $3
;;
gen_start_config)
gen_start_config $2 $3 $4 $5 $6 $7
run_socks)
run_socks $2 $3 $4 $5 $6
;;
run_redir)
run_redir $2 $3 $4 $5 $6 $7
;;
node_switch)
node_switch $2 $3 $4 $5

View File

@ -1,74 +0,0 @@
config global
option enabled '0'
option tcp_node1 'nil'
option udp_node1 'nil'
option socks_node1 'nil'
option dns_mode 'pdnsd'
option up_china_dns 'default'
option dns_forward '8.8.4.4'
option use_tcp_node_resolve_dns '1'
option tcp_proxy_mode 'chnroute'
option udp_proxy_mode 'chnroute'
option localhost_tcp_proxy_mode 'gfwlist'
option localhost_udp_proxy_mode 'gfwlist'
config global_haproxy
option balancing_enable '0'
config global_delay
option auto_on '0'
option start_daemon '0'
option start_delay '1'
config global_forwarding
option process '0'
option tcp_no_redir_ports 'disable'
option udp_no_redir_ports '80,443'
option tcp_redir_ports '22,25,53,143,465,587,993,995,80,443'
option udp_redir_ports '1:65535'
option socks_proxy_port1 '1081'
option socks_proxy_port2 '1082'
option socks_proxy_port3 '1083'
option proxy_ipv6 '0'
config global_other
option use_tcping '1'
option auto_ping '1'
option tcp_node_num '1'
option udp_node_num '1'
option socks_node_num '1'
option status_use_big_icon '1'
option status_show_check_port '0'
option status_show_ip111 '0'
option compact_display_nodes '0'
option show_group '0'
option show_add_mode '0'
config global_rules
option auto_update '0'
option chnlist_update '1'
option chnroute_update '1'
option gfwlist_update '1'
option gfwlist_version '2020-03-10'
option chnroute_version '2020-03-10'
option chnlist_version '2020-03-10'
config global_app
option v2ray_file '/usr/bin/v2ray/'
option kcptun_client_file '/usr/bin/kcptun-client'
option brook_file '/usr/bin/brook'
config global_subscribe
option subscribe_proxy '0'
option auto_update_subscribe '0'
option filter_enabled '1'
option filter_keyword_discarded '1'
list filter_keyword '过期时间'
list filter_keyword '剩余流量'
list filter_keyword 'QQ群'
list filter_keyword '官网'
config auto_switch
option testing_time '1'
option enable '0'

View File

@ -137,26 +137,26 @@ load_acl() {
eval TCP_NODE_TYPE=$(echo $(config_n_get $TCP_NODE type) | tr 'A-Z' 'a-z')
local is_tproxy
[ "$TCP_NODE_TYPE" == "brook" -a "$(config_n_get $TCP_NODE brook_protocol client)" == "client" ] && ipt_tmp=$ipt_m && is_tproxy="TPROXY"
[ "$tcp_no_redir_ports" != "disable" ] && $ipt_tmp -A PSW_ACL $(comment "$remarks") $(factor $ip "-s") $(factor $mac "-m mac --mac-source") -p tcp -m multiport --dport $tcp_no_redir_ports -j RETURN
[ "$tcp_no_redir_ports" != "disable" ] && $ipt_tmp -A PSW $(comment "$remarks") $(factor $ip "-s") $(factor $mac "-m mac --mac-source") -p tcp -m multiport --dport $tcp_no_redir_ports -j RETURN
eval tcp_port=\$TCP_REDIR_PORT$tcp_node
$ipt_tmp -A PSW_ACL $(comment "$remarks") -p tcp $(factor $ip "-s") $(factor $mac "-m mac --mac-source") $(factor $tcp_redir_ports "-m multiport --dport") $(dst $IPSET_BLACKLIST) $(REDIRECT $tcp_port $is_tproxy)
$ipt_tmp -A PSW_ACL $(comment "$remarks") -p tcp $(factor $ip "-s") $(factor $mac "-m mac --mac-source") $(factor $tcp_redir_ports "-m multiport --dport") $(get_redirect_ipt $tcp_proxy_mode $tcp_port $is_tproxy)
$ipt_tmp -A PSW $(comment "$remarks") -p tcp $(factor $ip "-s") $(factor $mac "-m mac --mac-source") $(factor $tcp_redir_ports "-m multiport --dport") $(dst $IPSET_BLACKLIST) $(REDIRECT $tcp_port $is_tproxy)
$ipt_tmp -A PSW $(comment "$remarks") -p tcp $(factor $ip "-s") $(factor $mac "-m mac --mac-source") $(factor $tcp_redir_ports "-m multiport --dport") $(get_redirect_ipt $tcp_proxy_mode $tcp_port $is_tproxy)
unset is_tproxy
unset tcp_port
}
}
$ipt_tmp -A PSW_ACL $(comment "$remarks") $(factor $ip "-s") $(factor $mac "-m mac --mac-source") -p tcp -j RETURN
$ipt_tmp -A PSW $(comment "$remarks") $(factor $ip "-s") $(factor $mac "-m mac --mac-source") -p tcp -j RETURN
[ "$udp_proxy_mode" != "disable" ] && {
[ "$UDP_NODE" != "nil" ] && {
eval udp_port=\$UDP_REDIR_PORT$udp_node
[ "$udp_no_redir_ports" != "disable" ] && $ipt_m -A PSW_ACL $(comment "$remarks") $(factor $ip "-s") $(factor $mac "-m mac --mac-source") -p udp -m multiport --dport $udp_no_redir_ports -j RETURN
$ipt_m -A PSW_ACL $(comment "$remarks") -p udp $(factor $ip "-s") $(factor $mac "-m mac --mac-source") $(factor $UDP_REDIR_PORTS "-m multiport --dport") $(dst $IPSET_BLACKLIST) $(REDIRECT $udp_port TPROXY)
$ipt_m -A PSW_ACL $(comment "$remarks") -p udp $(factor $ip "-s") $(factor $mac "-m mac --mac-source") $(factor $UDP_REDIR_PORTS "-m multiport --dport") $(get_redirect_ipt $udp_proxy_mode $udp_port TPROXY)
[ "$udp_no_redir_ports" != "disable" ] && $ipt_m -A PSW $(comment "$remarks") $(factor $ip "-s") $(factor $mac "-m mac --mac-source") -p udp -m multiport --dport $udp_no_redir_ports -j RETURN
$ipt_m -A PSW $(comment "$remarks") -p udp $(factor $ip "-s") $(factor $mac "-m mac --mac-source") $(factor $UDP_REDIR_PORTS "-m multiport --dport") $(dst $IPSET_BLACKLIST) $(REDIRECT $udp_port TPROXY)
$ipt_m -A PSW $(comment "$remarks") -p udp $(factor $ip "-s") $(factor $mac "-m mac --mac-source") $(factor $UDP_REDIR_PORTS "-m multiport --dport") $(get_redirect_ipt $udp_proxy_mode $udp_port TPROXY)
unset udp_port
}
}
$ipt_m -A PSW_ACL $(comment "$remarks") $(factor $ip "-s") $(factor $mac "-m mac --mac-source") -p udp -j RETURN
$ipt_m -A PSW $(comment "$remarks") $(factor $ip "-s") $(factor $mac "-m mac --mac-source") -p udp -j RETURN
done
}
@ -166,27 +166,28 @@ load_acl() {
local TCP_NODE1_TYPE=$(echo $(config_n_get $TCP_NODE1 type) | tr 'A-Z' 'a-z')
local is_tproxy
[ "$TCP_NODE1_TYPE" == "brook" -a "$(config_n_get $TCP_NODE1 brook_protocol client)" == "client" ] && ipt_tmp=$ipt_m && is_tproxy="TPROXY"
[ "$TCP_NO_REDIR_PORTS" != "disable" ] && $ipt_tmp -A PSW_ACL $(comment "默认") -p tcp -m multiport --dport $TCP_NO_REDIR_PORTS -j RETURN
$ipt_tmp -A PSW_ACL $(comment "默认") -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport") $(dst $IPSET_BLACKLIST) $(REDIRECT $TCP_REDIR_PORT1 $is_tproxy)
$ipt_tmp -A PSW_ACL $(comment "默认") -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport") $(get_redirect_ipt $TCP_PROXY_MODE $TCP_REDIR_PORT1 $is_tproxy)
[ "$TCP_NO_REDIR_PORTS" != "disable" ] && $ipt_tmp -A PSW $(comment "默认") -p tcp -m multiport --dport $TCP_NO_REDIR_PORTS -j RETURN
$ipt_tmp -A PSW $(comment "默认") -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport") $(dst $IPSET_BLACKLIST) $(REDIRECT $TCP_REDIR_PORT1 $is_tproxy)
$ipt_tmp -A PSW $(comment "默认") -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport") $(get_redirect_ipt $TCP_PROXY_MODE $TCP_REDIR_PORT1 $is_tproxy)
}
$ipt_tmp -A PSW_ACL $(comment "默认") -p tcp -j RETURN
$ipt_tmp -A PSW $(comment "默认") -p tcp -j RETURN
echolog "TCP默认代理模式$(get_action_chain_name $TCP_PROXY_MODE)"
# 加载UDP默认代理模式
[ "$UDP_NODE1" != "nil" -a "$UDP_PROXY_MODE" != "disable" ] && {
[ "$UDP_NO_REDIR_PORTS" != "disable" ] && $ipt_m -A PSW_ACL $(comment "默认") -p udp -m multiport --dport $UDP_NO_REDIR_PORTS -j RETURN
$ipt_m -A PSW_ACL $(comment "默认") -p udp $(factor $UDP_REDIR_PORTS "-m multiport --dport") $(dst $IPSET_BLACKLIST) $(REDIRECT $UDP_REDIR_PORT1 TPROXY)
$ipt_m -A PSW_ACL $(comment "默认") -p udp $(factor $UDP_REDIR_PORTS "-m multiport --dport") $(get_redirect_ipt $UDP_PROXY_MODE $UDP_REDIR_PORT1 TPROXY)
[ "$UDP_NO_REDIR_PORTS" != "disable" ] && $ipt_m -A PSW $(comment "默认") -p udp -m multiport --dport $UDP_NO_REDIR_PORTS -j RETURN
$ipt_m -A PSW $(comment "默认") -p udp $(factor $UDP_REDIR_PORTS "-m multiport --dport") $(dst $IPSET_BLACKLIST) $(REDIRECT $UDP_REDIR_PORT1 TPROXY)
$ipt_m -A PSW $(comment "默认") -p udp $(factor $UDP_REDIR_PORTS "-m multiport --dport") $(get_redirect_ipt $UDP_PROXY_MODE $UDP_REDIR_PORT1 TPROXY)
}
$ipt_m -A PSW_ACL $(comment "默认") -p udp -j RETURN
$ipt_m -A PSW $(comment "默认") -p udp -j RETURN
echolog "UDP默认代理模式$(get_action_chain_name $UDP_PROXY_MODE)"
}
filter_vpsip() {
echolog "开始过滤所有IPV4节点到白名单"
uci show $CONFIG | grep "@nodes" | grep "address" | cut -d "'" -f 2 | grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}" | sed -e "/^$/d" | sed -e "s/^/add $IPSET_VPSIPLIST &/g" | awk '{print $0} END{print "COMMIT"}' | ipset -! -R
echolog "过滤所有IPV4节点完成"
echolog "开始过滤所有节点到白名单"
uci show $CONFIG | grep ".address=" | cut -d "'" -f 2 | grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}" | sed -e "/^$/d" | sed -e "s/^/add $IPSET_VPSIPLIST &/g" | awk '{print $0} END{print "COMMIT"}' | ipset -! -R
#uci show $CONFIG | grep ".address=" | cut -d "'" -f 2 | grep -E "([[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){0,7}::[a-f0-9]{0,4}(:[a-f0-9]{1,4}){0,7}])" | sed -e "/^$/d" | sed -e "s/^/add $IPSET_VPSIP6LIST &/g" | awk '{print $0} END{print "COMMIT"}' | ipset -! -R
echolog "过滤所有节点完成"
}
filter_node() {
@ -199,37 +200,46 @@ filter_node() {
local port=$(config_n_get $1 port)
if [ -n "$3" ] && [ "$3" == "1" ] && [ -n "$4" ]; then
if [ "$i" == "$ipt_m" ]; then
$i -I PSW_OUTPUT 2 -p $2 -d $address --dport $port $(REDIRECT 1 MARK)
else
$i -I PSW_OUTPUT 2 -p $2 -d $address --dport $port $(REDIRECT $4)
fi
is_exist=$($i -n -L PSW_OUTPUT 2>/dev/null | grep -c "$address:$port")
[ "$is_exist" == 0 ] && {
if [ "$i" == "$ipt_m" ]; then
$i -I PSW_OUTPUT 2 $(comment "$address:$port") -p $2 -d $address --dport $port $(REDIRECT 1 MARK)
else
$i -I PSW_OUTPUT 2 $(comment "$address:$port") -p $2 -d $address --dport $port $(REDIRECT $4)
fi
}
else
is_exist=$($i -n -L PSW_OUTPUT 2>/dev/null | grep -c "$address:$port")
[ "$is_exist" == 0 ] && {
local ADD_INDEX=2
local INDEX=$($i -n -L PSW_OUTPUT --line-numbers | grep "$IPSET_VPSIPLIST" | sed -n '$p' | awk '{print $1}')
[ -n "$INDEX" ] && ADD_INDEX=$INDEX
$i -I PSW_OUTPUT $ADD_INDEX -p $2 -d $address --dport $port $(comment "$address:$port") -j RETURN
$i -I PSW_OUTPUT $ADD_INDEX $(comment "$address:$port") -p $2 -d $address --dport $port -j RETURN
}
fi
}
}
local tmp_type=$(echo $(config_n_get $1 type) | tr 'A-Z' 'a-z')
if [ "$tmp_type" == "v2ray_shunt" ]; then
local v2ray_protocol=$(config_n_get $1 v2ray_protocol)
if [ "$v2ray_protocol" == "_shunt" ]; then
local default_node=$(config_n_get $1 default_node nil)
filter_rules $default_node $2
local default_node_address=$(get_host_ip ipv4 $(config_n_get $default_node address) 1)
local default_node_port=$(config_n_get $default_node port)
local youtube_node=$(config_n_get $1 youtube_node)
local youtube_proxy=$(config_n_get $1 youtube_proxy 0)
[ "$default_node" == "$youtube_node" ] && youtube_proxy=0
local netflix_node=$(config_n_get $1 netflix_node)
local netflix_proxy=$(config_n_get $1 netflix_proxy 0)
[ "$default_node" == "$netflix_node" ] && netflix_proxy=0
filter_rules $(config_n_get $1 youtube_node) $2 $youtube_proxy $3
filter_rules $(config_n_get $1 netflix_node) $2 $netflix_proxy $3
elif [ "$tmp_type" == "v2ray_balancing" ]; then
local shunt_ids=$(uci show $CONFIG | grep "=shunt_rules" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}')
for shunt_id in $shunt_ids; do
local _proxy=$(config_n_get $1 "${shunt_id}_proxy" 0)
local _node=$(config_n_get $1 "${shunt_id}" nil)
[ "$_proxy" == 1 ] && {
local _node_address=$(get_host_ip ipv4 $(config_n_get $_node address) 1)
local _node_port=$(config_n_get $_node port)
[ "$_node_address" == "$default_node_address" ] && [ "$_node_port" == "$default_node_port" ] && {
_proxy=0
}
}
filter_rules $(config_n_get $1 $shunt_id) $2 $_proxy $3
done
elif [ "$v2ray_protocol" == "_balancing" ]; then
local balancing_node=$(config_n_get $1 v2ray_balancing_node)
for node_id in $balancing_node
do
@ -282,7 +292,6 @@ add_firewall_rule() {
$ipt_n -A PSW $(dst $IPSET_LANIPLIST) -j RETURN
$ipt_n -A PSW $(dst $IPSET_VPSIPLIST) -j RETURN
$ipt_n -A PSW $(dst $IPSET_WHITELIST) -j RETURN
$ipt_n -N PSW_ACL
$ipt_n -N PSW_OUTPUT
$ipt_n -A PSW_OUTPUT $(dst $IPSET_LANIPLIST) -j RETURN
@ -293,7 +302,6 @@ add_firewall_rule() {
$ipt_m -A PSW $(dst $IPSET_LANIPLIST) -j RETURN
$ipt_m -A PSW $(dst $IPSET_VPSIPLIST) -j RETURN
$ipt_m -A PSW $(dst $IPSET_WHITELIST) -j RETURN
$ipt_m -N PSW_ACL
$ipt_m -N PSW_OUTPUT
$ipt_m -A PSW_OUTPUT $(dst $IPSET_LANIPLIST) -j RETURN
@ -302,13 +310,20 @@ add_firewall_rule() {
ip rule add fwmark 1 lookup 100
ip route add local 0.0.0.0/0 dev lo table 100
for i in $(seq 1 $SOCKS_NODE_NUM); do
eval node=\$SOCKS_NODE$i
[ "$node" != "nil" ] && {
filter_node $node tcp
filter_node $node udp
}
# 过滤Socks节点
local ids=$(uci show $CONFIG | grep "=socks" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}')
for id in $ids; do
local enabled=$(config_n_get $id enabled 0)
[ "$enabled" == "0" ] && continue
local node=$(config_n_get $id node nil)
if [ "$(echo $node | grep ^tcp)" ]; then
local num=$(echo $node | sed "s/tcp//g")
eval node=\$TCP_NODE$num
fi
[ "$node" == "nil" ] && continue
filter_node $node tcp
filter_node $node udp
done
for i in $(seq 1 $TCP_NODE_NUM); do
@ -319,42 +334,36 @@ add_firewall_rule() {
# 加载路由器自身代理 TCP
if [ "$TCP_NODE1" != "nil" ]; then
local ipt_tmp=$ipt_n
local dns_l="PSW_OUTPUT"
local dns_r=$(REDIRECT $TCP_REDIR_PORT1)
local blist_r=$(REDIRECT $TCP_REDIR_PORT1)
local p_r=$(get_redirect_ipt $LOCALHOST_TCP_PROXY_MODE $TCP_REDIR_PORT1)
TCP_NODE1_TYPE=$(echo $(config_n_get $TCP_NODE1 type) | tr 'A-Z' 'a-z')
if [ "$TCP_NODE1_TYPE" == "brook" -a "$(config_n_get $TCP_NODE1 brook_protocol client)" == "client" ]; then
[ "$use_tcp_node_resolve_dns" == 1 -a -n "$DNS_FORWARD" ] && {
for dns in $DNS_FORWARD ; do
local dns_ip=$(echo $dns | sed "s/:/#/g" | awk -F "#" '{print $1}')
ipset test $IPSET_LANIPLIST $dns_ip 2>/dev/null
[ $? == 0 ] && continue
local dns_port=$(echo $dns | sed "s/:/#/g" | awk -F "#" '{print $2}')
[ -z "$dns_port" ] && dns_port=53
$ipt_m -I PSW 2 -p tcp -d $dns_ip --dport $dns_port $(REDIRECT $TCP_REDIR_PORT1 TPROXY)
done
}
$ipt_m -A OUTPUT -p tcp -j PSW_OUTPUT
[ "$TCP_NO_REDIR_PORTS" != "disable" ] && $ipt_m -A PSW_OUTPUT -p tcp -m multiport --dport $TCP_NO_REDIR_PORTS -j RETURN
$ipt_m -A PSW_OUTPUT -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport") $(dst $IPSET_BLACKLIST) $(REDIRECT 1 MARK)
$ipt_m -A PSW_OUTPUT -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport") $(get_redirect_ipt $LOCALHOST_TCP_PROXY_MODE 1 MARK)
else
[ "$use_tcp_node_resolve_dns" == 1 -a -n "$DNS_FORWARD" ] && {
for dns in $DNS_FORWARD ; do
local dns_ip=$(echo $dns | sed "s/:/#/g" | awk -F "#" '{print $1}')
ipset test $IPSET_LANIPLIST $dns_ip 2>/dev/null
[ $? == 0 ] && continue
local dns_port=$(echo $dns | sed "s/:/#/g" | awk -F "#" '{print $2}')
[ -z "$dns_port" ] && dns_port=53
local ADD_INDEX=2
$ipt_n -I PSW_OUTPUT $ADD_INDEX -p tcp -d $dns_ip --dport $dns_port $(REDIRECT $TCP_REDIR_PORT1)
done
}
$ipt_n -A OUTPUT -p tcp -j PSW_OUTPUT
[ "$TCP_NO_REDIR_PORTS" != "disable" ] && $ipt_n -A PSW_OUTPUT -p tcp -m multiport --dport $TCP_NO_REDIR_PORTS -j RETURN
$ipt_n -A PSW_OUTPUT -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport") $(dst $IPSET_BLACKLIST) $(REDIRECT $TCP_REDIR_PORT1)
$ipt_n -A PSW_OUTPUT -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport") $(get_redirect_ipt $LOCALHOST_TCP_PROXY_MODE $TCP_REDIR_PORT1)
if [ "$TCP_NODE1_TYPE" == "brook" ] && [ "$(config_n_get $TCP_NODE1 brook_protocol client)" == "client" ]; then
ipt_tmp=$ipt_m
dns_l="PSW"
dns_r="$(REDIRECT $TCP_REDIR_PORT1 TPROXY)"
blist_r=$(REDIRECT 1 MARK)
p_r=$(get_redirect_ipt $LOCALHOST_TCP_PROXY_MODE 1 MARK)
fi
[ "$use_tcp_node_resolve_dns" == 1 -a -n "$DNS_FORWARD" ] && {
for dns in $DNS_FORWARD ; do
local dns_ip=$(echo $dns | sed "s/:/#/g" | awk -F "#" '{print $1}')
ipset test $IPSET_LANIPLIST $dns_ip 2>/dev/null
[ $? == 0 ] && continue
local dns_port=$(echo $dns | sed "s/:/#/g" | awk -F "#" '{print $2}')
[ -z "$dns_port" ] && dns_port=53
$ipt_tmp -I $dns_l 2 -p tcp -d $dns_ip --dport $dns_port $dns_r
[ "$ipt_tmp" == "$ipt_m" ] && $ipt_tmp -I PSW_OUTPUT 2 -p tcp -d $dns_ip --dport $dns_port $(REDIRECT 1 MARK)
done
}
$ipt_tmp -A OUTPUT -p tcp -j PSW_OUTPUT
[ "$TCP_NO_REDIR_PORTS" != "disable" ] && $ipt_tmp -A PSW_OUTPUT -p tcp -m multiport --dport $TCP_NO_REDIR_PORTS -j RETURN
$ipt_tmp -A PSW_OUTPUT -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport") $(dst $IPSET_BLACKLIST) $blist_r
$ipt_tmp -A PSW_OUTPUT -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport") $p_r
fi
$ipt_n -A PSW -j PSW_ACL
local PRE_INDEX=1
ADBYBY_INDEX=$($ipt_n -L PREROUTING --line-numbers | grep "ADBYBY" | sed -n '$p' | awk '{print $1}')
if [ -n "$ADBYBY_INDEX" ]; then
@ -370,7 +379,6 @@ add_firewall_rule() {
lan_ipv6=$(ip address show $lan_ifname | grep -w "inet6" | awk '{print $2}') #当前LAN IPv6段
[ -n "$lan_ipv6" ] && {
$ip6t_n -N PSW
$ip6t_n -N PSW_ACL
$ip6t_n -A PREROUTING -j PSW
[ -n "$lan_ipv6" ] && {
for ip in $lan_ipv6; do
@ -387,6 +395,7 @@ add_firewall_rule() {
for i in $(seq 1 $UDP_NODE_NUM); do
eval node=\$UDP_NODE$i
eval port=\$UDP_REDIR_PORT$i
[ "$node" == "tcp" ] && eval node=\$TCP_NODE$i && eval port=\$TCP_REDIR_PORT$i
[ "$node" != "nil" ] && filter_node $node udp $port
done
@ -411,7 +420,6 @@ add_firewall_rule() {
$ipt_m -A PSW_OUTPUT -p udp $(factor $UDP_REDIR_PORTS "-m multiport --dport") $(get_redirect_ipt $LOCALHOST_UDP_PROXY_MODE 1 MARK)
fi
$ipt_m -A PSW -j PSW_ACL
$ipt_m -A PREROUTING -j PSW
# 加载ACLS
@ -426,20 +434,17 @@ del_firewall_rule() {
$ipt_n -D PREROUTING -p tcp -j PSW 2>/dev/null
$ipt_n -D OUTPUT -p tcp -j PSW_OUTPUT 2>/dev/null
$ipt_n -F PSW 2>/dev/null && $ipt_n -X PSW 2>/dev/null
$ipt_n -F PSW_ACL 2>/dev/null && $ipt_n -X PSW_ACL 2>/dev/null
$ipt_n -F PSW_OUTPUT 2>/dev/null && $ipt_n -X PSW_OUTPUT 2>/dev/null
$ipt_m -D PREROUTING -j PSW 2>/dev/null
$ipt_m -D OUTPUT -p tcp -j PSW_OUTPUT 2>/dev/null
$ipt_m -D OUTPUT -p udp -j PSW_OUTPUT 2>/dev/null
$ipt_m -F PSW 2>/dev/null && $ipt_m -X PSW 2>/dev/null
$ipt_m -F PSW_ACL 2>/dev/null && $ipt_m -X PSW_ACL 2>/dev/null
$ipt_m -F PSW_OUTPUT 2>/dev/null && $ipt_m -X PSW_OUTPUT 2>/dev/null
$ip6t_n -D PREROUTING -j PSW 2>/dev/null
$ip6t_n -D OUTPUT -j PSW_OUTPUT 2>/dev/null
$ip6t_n -F PSW 2>/dev/null && $ip6t_n -X PSW 2>/dev/null
$ip6t_n -F PSW_ACL 2>/dev/null && $ip6t_n -X PSW_ACL 2>/dev/null
$ip6t_n -F PSW_OUTPUT 2>/dev/null && $ip6t_n -X PSW_OUTPUT 2>/dev/null
ip rule del fwmark 1 lookup 100 2>/dev/null

View File

@ -36,11 +36,6 @@ do
eval UDP_NODE$i=$(config_t_get global udp_node$i nil)
done
SOCKS_NODE_NUM=$(config_t_get global_other socks_node_num 1)
for i in $(seq 1 $SOCKS_NODE_NUM); do
eval SOCKS_NODE$i=$(config_t_get global socks_node$i nil)
done
dns_mode=$(config_t_get global dns_mode)
use_haproxy=$(config_t_get global_haproxy balancing_enable 0)
@ -51,13 +46,13 @@ do
#kcptun
use_kcp=$(config_n_get $tmp_node use_kcp 0)
if [ $use_kcp -gt 0 ]; then
icount=$(ps -w | grep -v grep | grep $RUN_BIN_PATH | grep kcptun_tcp_${i} | wc -l)
icount=$(ps -w | grep -v grep | grep "$RUN_BIN_PATH/kcptun" | grep -i "tcp_${i}" | wc -l)
if [ $icount = 0 ]; then
/etc/init.d/passwall restart
exit 0
fi
fi
icount=$(ps -w | grep -v grep | grep -v kcptun | grep $RUN_BIN_PATH | grep -i -E "TCP_${i}" | wc -l)
icount=$(ps -w | grep -v -E 'grep|kcptun' | grep "$RUN_BIN_PATH" | grep -i "TCP_${i}" | wc -l)
if [ $icount = 0 ]; then
/etc/init.d/passwall restart
exit 0
@ -69,20 +64,9 @@ do
for i in $(seq 1 $UDP_NODE_NUM); do
eval tmp_node=\$UDP_NODE$i
if [ "$tmp_node" != "nil" ]; then
[ "$tmp_node" == "default" ] && tmp_node=$TCP_NODE1
icount=$(ps -w | grep -v grep | grep $RUN_BIN_PATH | grep -i -E "UDP_${i}" | wc -l)
if [ $icount = 0 ]; then
/etc/init.d/passwall restart
exit 0
fi
fi
done
#socks
for i in $(seq 1 $SOCKS_NODE_NUM); do
eval tmp_node=\$SOCKS_NODE$i
if [ "$tmp_node" != "nil" ]; then
icount=$(ps -w | grep -v grep | grep -v kcptun | grep $RUN_BIN_PATH | grep -i "SOCKS_${i}" | wc -l)
[ "$tmp_node" == "tcp" ] && continue
[ "$tmp_node" == "tcp_" ] && tmp_node=$TCP_NODE1
icount=$(ps -w | grep -v grep | grep "$RUN_BIN_PATH" | grep -i "UDP_${i}" | wc -l)
if [ $icount = 0 ]; then
/etc/init.d/passwall restart
exit 0
@ -101,7 +85,7 @@ do
#haproxy
if [ $use_haproxy -gt 0 ]; then
icount=$(ps -w | grep -v grep | grep $RUN_BIN_PATH | grep haproxy | wc -l)
icount=$(ps -w | grep -v grep | grep "$RUN_BIN_PATH/haproxy" | wc -l)
if [ $icount = 0 ]; then
/etc/init.d/passwall restart
exit 0

View File

@ -6,6 +6,49 @@ local ucic = luci.model.uci.cursor()
local name = 'passwall'
local arg1 = arg[1]
local rule_path = "/usr/share/" .. name .. "/rules"
local url_main = 'https://cdn.jsdelivr.net/gh/hq450/fancyss/rules'
local reboot = 0
local gfwlist_update = 0
local chnroute_update = 0
local chnlist_update = 0
-- match comments/title/whitelist/ip address
local comment_pattern = "^[!\\[@]+"
local ip_pattern = "^%d+%.%d+%.%d+%.%d+"
local domain_pattern = "([%w%-%_]+%.[%w%.%-%_]+)[%/%*]*"
-- gfwlist parameter
local mydnsip = '127.0.0.1'
local mydnsport = '7913'
local ipsetname = 'gfwlist'
-- custom url
local enable_custom_url = ucic:get_first(name, 'global_rules', "enable_custom_url", 0)
local gfwlist_url = ucic:get_first(name, 'global_rules', "gfwlist_url", "https://cdn.jsdelivr.net/gh/Loukky/gfwlist-by-loukky/gfwlist.txt")
local chnroute_url = ucic:get_first(name, 'global_rules', "chnroute_url", "https://ispip.clang.cn/all_cn.txt")
local chnlist_url_1 = 'https://cdn.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/accelerated-domains.china.conf'
local chnlist_url_2 = 'https://cdn.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/apple.china.conf'
local chnlist_url_3 = 'https://cdn.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/google.china.conf'
local bc='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
-- base64decoding
local function base64_dec(data)
data = string.gsub(data, '[^'..bc..'=]', '')
return (data:gsub('.', function(x)
if (x == '=') then return '' end
local r,f='',(bc:find(x)-1)
for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
return r;
end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
if (#x ~= 8) then return '' end
local c=0
for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
return string.char(c)
end))
end
local log = function(...)
if arg1 then
local result = os.date("%Y-%m-%d %H:%M:%S: ") ..
@ -27,6 +70,7 @@ local function trim(text)
if not text or text == "" then return "" end
return (string.gsub(text, "^%s*(.-)%s*$", "%1"))
end
-- wget
local function wget(url, file)
local cmd = "/usr/bin/wget --no-check-certificate -t 3 -T 10 -O"
@ -39,12 +83,119 @@ local function wget(url, file)
return trim(stdout)
end
local rule_path = "/usr/share/" .. name .. "/rules"
local url_main = "https://raw.githubusercontent.com/hq450/fancyss/master/rules"
local reboot = 0
local gfwlist_update = 0
local chnroute_update = 0
local chnlist_update = 0
-- curl
local function curl(url, file)
local cmd = "curl -skL -w %{http_code} --retry 3 --connect-timeout 3 '" .. url .. "'"
if file then
cmd = cmd .. " -o " .. file
end
local stdout = luci.sys.exec(cmd)
if file then
return tonumber(trim(stdout))
else
return trim(stdout)
end
end
--获取gfwlist
local function fetch_gfwlist()
--请求gfwlist
local sret = curl(gfwlist_url, "/tmp/gfwlist.txt")
if sret == 200 then
--解码gfwlist
local gfwlist = io.open("/tmp/gfwlist.txt", "r")
local decode = base64_dec(gfwlist:read("*all"))
gfwlist:close()
--写回gfwlist
gfwlist = io.open("/tmp/gfwlist.txt", "w")
gfwlist:write(decode)
gfwlist:close()
end
return sret;
end
--获取chnroute
local function fetch_chnroute()
--请求chnroute
local sret = curl(chnroute_url, "/tmp/chnroute_tmp")
return sret;
end
--获取chnlist
local function fetch_chnlist()
--请求chnlist
local sret = 0
local sret1 = curl(chnlist_url_1, "/tmp/chnlist_1")
local sret2 = curl(chnlist_url_2, "/tmp/chnlist_2")
local sret3 = curl(chnlist_url_3, "/tmp/chnlist_3")
if sret1 == 200 and sret2 ==200 and sret3 == 200 then
sret=200
end
return sret;
end
--gfwlist转码至dnsmasq格式
local function generate_gfwlist()
local domains = {}
local out = io.open("/tmp/gfwlist_tmp", "w")
for line in io.lines("/tmp/gfwlist.txt") do
if not (string.find(line, comment_pattern) or string.find(line, ip_pattern)) then
local start, finish, match = string.find(line, domain_pattern)
if (start) then
domains[match] = true
end
end
end
for k,v in pairs(domains) do
out:write(string.format("server=/.%s/%s#%s\n", k,mydnsip,mydnsport))
out:write(string.format("ipset=/.%s/%s\n", k,ipsetname))
end
out:close()
end
--处理合并chnlist列表
local function generate_chnlist()
local domains = {}
local out = io.open("/tmp/cdn_tmp", "w")
for line in io.lines("/tmp/chnlist_1") do
local start, finish, match = string.find(line, domain_pattern)
if (start) then
domains[match] = true
end
end
for line in io.lines("/tmp/chnlist_2") do
local start, finish, match = string.find(line, domain_pattern)
if (start) then
domains[match] = true
end
end
for line in io.lines("/tmp/chnlist_3") do
local start, finish, match = string.find(line, domain_pattern)
if (start) then
domains[match] = true
end
end
--写入临时文件
for k,v in pairs(domains) do
out:write(string.format("%s\n", k))
end
out:close()
--删除重复条目并排序
luci.sys.call("cat /tmp/cdn_tmp | sort -u > /tmp/chnlist_tmp")
end
if arg[2] then
if arg[2]:find("gfwlist") then
gfwlist_update = 1
@ -63,83 +214,161 @@ end
if gfwlist_update == 0 and chnroute_update == 0 and chnlist_update == 0 then
os.exit(0)
end
local version = wget(url_main .. "/version1")
if version then
log("开始更新规则...")
if tonumber(enable_custom_url) == 1 then
local new_version = os.date("%Y-%m-%d")
log("已启用自定义规则地址...")
if tonumber(gfwlist_update) == 1 then
local gfwlist = luci.sys.exec("echo -n $(echo '" .. version .. "' | sed -n 1p)")
local new_version = luci.sys.exec("echo -n $(echo '" .. gfwlist .. "' | awk '{print $1}')")
local new_md5 = luci.sys.exec("echo -n $(echo '" .. gfwlist .. "' | awk '{print $3}')")
if new_version ~= "" and new_md5 ~= "" then
local old_version = ucic:get_first(name, 'global_rules', "gfwlist_version", "nil")
local old_md5 = luci.sys.exec("echo -n $(md5sum " .. rule_path .. "/gfwlist.conf | awk '{print $1}')")
if old_md5 ~= new_md5 or old_version ~= new_version then
log("开始更新gfwlist...")
wget(url_main .. "/gfwlist.conf", "/tmp/gfwlist_tmp")
local download_md5 = luci.sys.exec("echo -n $([ -f '/tmp/gfwlist_tmp' ] && md5sum /tmp/gfwlist_tmp | awk '{print $1}')")
if download_md5 == new_md5 then
luci.sys.exec("mv -f /tmp/gfwlist_tmp " .. rule_path .. "/gfwlist.conf")
ucic:set(name, ucic:get_first(name, 'global_rules'), "gfwlist_version", new_version)
reboot = 1
log("更新gfwlist成功...")
end
log("开始更新gfwlist...")
local old_md5 = luci.sys.exec("echo -n $(md5sum " .. rule_path .. "/gfwlist.conf | awk '{print $1}')")
local status = fetch_gfwlist()
if status == 200 then
generate_gfwlist()
local new_md5 = luci.sys.exec("echo -n $([ -f '/tmp/gfwlist_tmp' ] && md5sum /tmp/gfwlist_tmp | awk '{print $1}')")
if old_md5 ~= new_md5 then
luci.sys.exec("mv -f /tmp/gfwlist_tmp " .. rule_path .. "/gfwlist.conf")
ucic:set(name, ucic:get_first(name, 'global_rules'), "gfwlist_version", new_version)
reboot = 1
log("更新gfwlist成功...")
else
log("gfwlist版本一致不用更新。")
end
else
log("gfwlist文件下载失败")
end
os.remove("/tmp/gfwlist.txt")
os.remove("/tmp/gfwlist_tmp")
end
if tonumber(chnroute_update) == 1 then
local chnroute = luci.sys.exec("echo -n $(echo '" .. version .. "' | sed -n 2p)")
local new_version = luci.sys.exec("echo -n $(echo '" .. chnroute .. "' | awk '{print $1}')")
local new_md5 = luci.sys.exec("echo -n $(echo '" .. chnroute .. "' | awk '{print $3}')")
if new_version ~= "" and new_md5 ~= "" then
local old_version = ucic:get_first(name, 'global_rules', "chnroute_version", "nil")
local old_md5 = luci.sys.exec("echo -n $(md5sum " .. rule_path .. "/chnroute | awk '{print $1}')")
if old_md5 ~= new_md5 or old_version ~= new_version then
log("开始更新chnroute...")
wget(url_main .. "/chnroute.txt", "/tmp/chnroute_tmp")
local download_md5 = luci.sys.exec("echo -n $([ -f '/tmp/chnroute_tmp' ] && md5sum /tmp/chnroute_tmp | awk '{print $1}')")
if download_md5 == new_md5 then
luci.sys.exec("mv -f /tmp/chnroute_tmp " .. rule_path .. "/chnroute")
ucic:set(name, ucic:get_first(name, 'global_rules'), "chnroute_version", new_version)
reboot = 1
log("更新chnroute成功...")
end
log("开始更新chnroute...")
local old_md5 = luci.sys.exec("echo -n $(md5sum " .. rule_path .. "/chnroute | awk '{print $1}')")
local status = fetch_chnroute()
if status == 200 then
local new_md5 = luci.sys.exec("echo -n $([ -f '/tmp/chnroute_tmp' ] && md5sum /tmp/chnroute_tmp | awk '{print $1}')")
if old_md5 ~= new_md5 then
luci.sys.exec("mv -f /tmp/chnroute_tmp " .. rule_path .. "/chnroute")
ucic:set(name, ucic:get_first(name, 'global_rules'), "chnroute_version", new_version)
reboot = 1
log("更新chnroute成功...")
else
log("chnroute版本一致不用更新。")
end
else
log("chnroute文件下载失败")
end
os.remove("/tmp/chnroute_tmp")
end
if tonumber(chnlist_update) == 1 then
local chnlist = luci.sys.exec("echo -n $(echo '" .. version .. "' | sed -n 4p)")
local new_version = luci.sys.exec("echo -n $(echo '" .. chnlist .. "' | awk '{print $1}')")
local new_md5 = luci.sys.exec("echo -n $(echo '" .. chnlist .. "' | awk '{print $3}')")
if new_version ~= "" and new_md5 ~= "" then
local old_version = ucic:get_first(name, 'global_rules', "chnlist_version", "nil")
local old_md5 = luci.sys.exec("echo -n $(md5sum " .. rule_path .. "/chnlist | awk '{print $1}')")
if old_md5 ~= new_md5 or old_version ~= new_version then
log("开始更新chnlist...")
wget(url_main .. "/cdn.txt", "/tmp/chnlist_tmp")
local download_md5 = luci.sys.exec("echo -n $([ -f '/tmp/chnlist_tmp' ] && md5sum /tmp/chnlist_tmp | awk '{print $1}')")
if download_md5 == new_md5 then
luci.sys.exec("mv -f /tmp/chnlist_tmp " .. rule_path .. "/chnlist")
ucic:set(name, ucic:get_first(name, 'global_rules'), "chnlist_version", new_version)
reboot = 1
log("更新chnlist成功...")
end
log("开始更新chnlist...")
local old_md5 = luci.sys.exec("echo -n $(md5sum " .. rule_path .. "/chnlist | awk '{print $1}')")
local status = fetch_chnlist()
if status == 200 then
generate_chnlist()
local new_md5 = luci.sys.exec("echo -n $([ -f '/tmp/chnlist_tmp' ] && md5sum /tmp/chnlist_tmp | awk '{print $1}')")
if old_md5 ~= new_md5 then
luci.sys.exec("mv -f /tmp/chnlist_tmp " .. rule_path .. "/chnlist")
ucic:set(name, ucic:get_first(name, 'global_rules'), "chnlist_version", new_version)
reboot = 1
log("更新chnlist成功...")
else
log("chnlist版本一致不用更新。")
end
else
log("chnlist文件下载失败")
end
os.remove("/tmp/chnlist_1")
os.remove("/tmp/chnlist_2")
os.remove("/tmp/chnlist_3")
os.remove("/tmp/cdn_tmp")
os.remove("/tmp/chnlist_tmp")
end
end
if (enable_custom_url) == 0 then
local version = curl(url_main .. "/version1")
if version and tonumber(version) ~= 0 then
if tonumber(gfwlist_update) == 1 then
log("开始更新gfwlist...")
local gfwlist = luci.sys.exec("echo -n $(echo '" .. version .. "' | sed -n 1p)")
local new_version = luci.sys.exec("echo -n $(echo '" .. gfwlist .. "' | awk '{print $1}')")
local new_md5 = luci.sys.exec("echo -n $(echo '" .. gfwlist .. "' | awk '{print $3}')")
if new_version ~= "" and new_md5 ~= "" then
local old_version = ucic:get_first(name, 'global_rules', "gfwlist_version", "nil")
local old_md5 = luci.sys.exec("echo -n $(md5sum " .. rule_path .. "/gfwlist.conf | awk '{print $1}')")
if old_md5 ~= new_md5 or old_version ~= new_version then
curl(url_main .. "/gfwlist.conf", "/tmp/gfwlist_tmp")
local download_md5 = luci.sys.exec("echo -n $([ -f '/tmp/gfwlist_tmp' ] && md5sum /tmp/gfwlist_tmp | awk '{print $1}')")
if download_md5 == new_md5 then
luci.sys.exec("mv -f /tmp/gfwlist_tmp " .. rule_path .. "/gfwlist.conf")
ucic:set(name, ucic:get_first(name, 'global_rules'), "gfwlist_version", new_version)
reboot = 1
log("更新gfwlist成功...")
end
else
log("gfwlist版本一致不用更新。")
end
else
log("gfwlist文件下载失败")
end
end
if tonumber(chnroute_update) == 1 and tonumber(enable_custom_url) == 0 then
log("开始更新chnroute...")
local chnroute = luci.sys.exec("echo -n $(echo '" .. version .. "' | sed -n 2p)")
local new_version = luci.sys.exec("echo -n $(echo '" .. chnroute .. "' | awk '{print $1}')")
local new_md5 = luci.sys.exec("echo -n $(echo '" .. chnroute .. "' | awk '{print $3}')")
if new_version ~= "" and new_md5 ~= "" then
local old_version = ucic:get_first(name, 'global_rules', "chnroute_version", "nil")
local old_md5 = luci.sys.exec("echo -n $(md5sum " .. rule_path .. "/chnroute | awk '{print $1}')")
if old_md5 ~= new_md5 or old_version ~= new_version then
curl(url_main .. "/chnroute.txt", "/tmp/chnroute_tmp")
local download_md5 = luci.sys.exec("echo -n $([ -f '/tmp/chnroute_tmp' ] && md5sum /tmp/chnroute_tmp | awk '{print $1}')")
if download_md5 == new_md5 then
luci.sys.exec("mv -f /tmp/chnroute_tmp " .. rule_path .. "/chnroute")
ucic:set(name, ucic:get_first(name, 'global_rules'), "chnroute_version", new_version)
reboot = 1
log("更新chnroute成功...")
end
else
log("chnroute版本一致不用更新。")
end
else
log("chnroute文件下载失败")
end
end
if tonumber(chnlist_update) == 1 then
log("开始更新chnlist...")
local chnlist = luci.sys.exec("echo -n $(echo '" .. version .. "' | sed -n 4p)")
local new_version = luci.sys.exec("echo -n $(echo '" .. chnlist .. "' | awk '{print $1}')")
local new_md5 = luci.sys.exec("echo -n $(echo '" .. chnlist .. "' | awk '{print $3}')")
if new_version ~= "" and new_md5 ~= "" then
local old_version = ucic:get_first(name, 'global_rules', "chnlist_version", "nil")
local old_md5 = luci.sys.exec("echo -n $(md5sum " .. rule_path .. "/chnlist | awk '{print $1}')")
if old_md5 ~= new_md5 or old_version ~= new_version then
curl(url_main .. "/cdn.txt", "/tmp/chnlist_tmp")
local download_md5 = luci.sys.exec("echo -n $([ -f '/tmp/chnlist_tmp' ] && md5sum /tmp/chnlist_tmp | awk '{print $1}')")
if download_md5 == new_md5 then
luci.sys.exec("mv -f /tmp/chnlist_tmp " .. rule_path .. "/chnlist")
ucic:set(name, ucic:get_first(name, 'global_rules'), "chnlist_version", new_version)
reboot = 1
log("更新chnlist成功...")
end
else
log("chnlist版本一致不用更新。")
end
else
log("chnlist文件下载失败")
end
end
else
log("版本信息下载失败!")
end
end
ucic:set(name, ucic:get_first(name, 'global_rules'), "gfwlist_update", gfwlist_update)
ucic:set(name, ucic:get_first(name, 'global_rules'), "chnroute_update", chnroute_update)
ucic:set(name, ucic:get_first(name, 'global_rules'), "chnlist_update", chnlist_update)
@ -149,4 +378,5 @@ luci.sys.call("uci commit " .. name)
if reboot == 1 then
log("重启服务,应用新的规则。")
luci.sys.call("/usr/share/" .. name .. "/iptables.sh flush_ipset && /etc/init.d/" .. name .. " restart")
end
end
log("规则脚本执行完毕...")

View File

@ -71,12 +71,12 @@
1.202.0.0/15
1.204.0.0/14
2.20.54.23
3.5.214.0/23
3.5.216.0/24
8.128.0.0/10
8.209.36.0/22
8.209.40.0/21
8.209.48.0/20
8.209.192.0/18
8.210.0.0/15
8.211.0.0/16
8.212.0.0/14
8.216.0.0/13
14.0.0.0/21
@ -98,6 +98,7 @@
14.196.0.0/15
14.204.0.0/15
14.208.0.0/12
20.62.0.0/24
20.81.0.0/24
20.134.160.0/20
20.139.160.0/20
@ -190,7 +191,15 @@
39.0.64.0/18
39.0.128.0/17
39.64.0.0/11
39.96.0.0/13
39.96.0.0/16
39.97.0.0/17
39.97.128.0/18
39.97.192.0/21
39.97.200.0/22
39.97.208.0/20
39.97.224.0/19
39.98.0.0/15
39.100.0.0/14
39.104.0.0/14
39.108.0.0/16
39.109.120.0/23
@ -436,7 +445,7 @@
43.242.16.0/20
43.242.48.0/22
43.242.53.0/24
43.242.54.0/23
43.242.54.0/24
43.242.56.0/21
43.242.64.0/22
43.242.72.0/21
@ -465,6 +474,7 @@
43.246.0.0/18
43.246.64.0/19
43.246.96.0/22
43.246.147.0/24
43.246.228.0/22
43.247.4.0/22
43.247.8.0/22
@ -580,6 +590,8 @@
45.40.208.0/21
45.40.224.0/19
45.65.16.0/20
45.87.53.0/24
45.87.54.0/23
45.112.132.0/22
45.112.188.0/22
45.112.208.0/22
@ -956,6 +968,7 @@
82.156.0.0/15
87.254.207.0/24
91.223.53.0/24
91.234.36.0/24
91.239.190.0/24
93.183.14.0/24
93.183.18.0/24
@ -965,11 +978,13 @@
101.2.172.0/22
101.4.0.0/14
101.16.0.0/12
101.32.0.0/14
101.32.112.0/20
101.32.128.0/17
101.33.0.0/16
101.34.0.0/15
101.36.0.0/18
101.36.64.0/20
101.36.88.0/21
101.36.96.0/19
101.36.128.0/17
101.37.0.0/16
101.38.0.0/15
@ -1082,7 +1097,7 @@
103.4.168.0/22
103.4.184.0/22
103.5.36.0/22
103.5.52.0/23
103.5.52.0/24
103.5.56.0/22
103.5.152.0/22
103.5.168.0/22
@ -1542,7 +1557,6 @@
103.68.100.0/22
103.68.128.0/22
103.69.16.0/22
103.69.212.0/23
103.70.8.0/22
103.70.148.0/22
103.70.236.0/22
@ -1629,7 +1643,6 @@
103.79.188.0/22
103.79.192.0/20
103.79.208.0/21
103.79.243.0/24
103.80.44.0/22
103.80.72.0/22
103.80.176.0/21
@ -1888,7 +1901,6 @@
103.107.208.0/20
103.108.52.0/22
103.108.160.0/21
103.108.194.0/24
103.108.196.0/22
103.108.208.0/21
103.108.224.0/22
@ -1897,7 +1909,7 @@
103.109.20.0/22
103.109.48.0/22
103.109.88.0/22
103.109.106.0/23
103.109.107.0/24
103.109.248.0/22
103.110.32.0/22
103.110.92.0/22
@ -2050,7 +2062,6 @@
103.138.248.0/23
103.139.22.0/23
103.139.134.0/23
103.139.136.0/23
103.139.172.0/23
103.139.204.0/23
103.139.212.0/23
@ -2075,7 +2086,7 @@
103.142.156.0/23
103.142.180.0/23
103.142.186.0/23
103.142.220.0/23
103.142.221.0/24
103.142.230.0/24
103.142.234.0/23
103.142.238.0/23
@ -2092,16 +2103,14 @@
103.144.136.0/23
103.144.158.0/23
103.145.40.0/22
103.145.73.0/24
103.145.80.0/23
103.145.90.0/23
103.145.92.0/22
103.145.98.0/23
103.145.107.0/24
103.145.188.0/23
103.146.6.0/23
103.146.72.0/23
103.146.90.0/23
103.146.91.0/24
103.146.126.0/23
103.146.138.0/23
103.146.236.0/23
@ -2110,6 +2119,28 @@
103.147.198.0/23
103.147.206.0/23
103.148.174.0/23
103.149.6.0/23
103.149.17.0/24
103.149.44.0/23
103.149.190.0/23
103.149.210.0/23
103.149.214.0/23
103.149.220.0/23
103.149.242.0/23
103.149.244.0/22
103.149.248.0/23
103.150.24.0/23
103.150.66.0/23
103.150.72.0/23
103.150.122.0/23
103.150.126.0/23
103.150.128.0/22
103.150.146.0/23
103.150.164.0/23
103.150.172.0/23
103.150.200.0/23
103.150.210.0/23
103.150.216.0/23
103.192.0.0/19
103.192.48.0/21
103.192.56.0/22
@ -2161,7 +2192,6 @@
103.198.200.0/22
103.198.216.0/21
103.198.224.0/20
103.198.240.0/21
103.199.164.0/22
103.199.196.0/22
103.199.228.0/22
@ -2343,7 +2373,8 @@
103.220.160.0/19
103.220.192.0/21
103.220.200.0/22
103.220.240.0/20
103.220.240.0/21
103.220.252.0/22
103.221.0.0/19
103.221.32.0/21
103.221.88.0/21
@ -2383,6 +2414,7 @@
103.224.220.0/22
103.224.224.0/21
103.224.232.0/22
103.225.32.0/22
103.226.40.0/22
103.226.56.0/21
103.226.80.0/22
@ -2454,7 +2486,7 @@
103.235.56.0/21
103.235.80.0/22
103.235.85.0/24
103.235.86.0/23
103.235.87.0/24
103.235.128.0/20
103.235.144.0/21
103.235.184.0/22
@ -2636,7 +2668,12 @@
106.2.16.0/20
106.2.32.0/19
106.2.64.0/18
106.2.128.0/17
106.2.128.0/20
106.2.144.0/21
106.2.152.0/22
106.2.156.0/23
106.2.160.0/19
106.2.192.0/18
106.3.16.0/20
106.3.32.0/19
106.3.64.0/20
@ -2850,7 +2887,6 @@
114.28.128.0/18
114.28.192.0/19
114.28.232.0/22
114.28.236.0/23
114.28.240.0/20
114.31.64.0/21
114.54.0.0/15
@ -3160,11 +3196,6 @@
118.191.248.0/21
118.192.0.0/16
118.193.0.0/22
118.193.32.0/20
118.193.56.0/21
118.193.68.0/22
118.193.72.0/24
118.193.77.0/24
118.193.96.0/19
118.194.0.0/17
118.194.128.0/18
@ -3353,7 +3384,9 @@
121.101.0.0/18
121.101.208.0/20
121.192.0.0/13
121.200.192.0/21
121.200.192.0/23
121.200.194.0/24
121.200.196.0/22
121.201.0.0/16
121.204.0.0/14
121.224.0.0/12
@ -3362,14 +3395,14 @@
122.0.64.0/18
122.0.128.0/17
122.4.0.0/14
122.9.0.0/16
122.10.132.0/23
122.10.136.0/23
122.10.196.0/23
122.10.216.0/22
122.10.228.0/22
122.10.232.0/21
122.10.240.0/21
122.10.248.0/22
122.10.250.0/23
122.11.0.0/17
122.12.0.0/15
122.14.0.0/17
@ -3391,7 +3424,6 @@
122.112.0.0/18
122.112.64.0/19
122.112.96.0/22
122.112.107.0/24
122.112.118.0/24
122.112.122.0/24
122.112.125.0/24
@ -3434,7 +3466,13 @@
123.49.136.0/22
123.49.152.0/21
123.49.160.0/19
123.49.192.0/18
123.49.192.0/19
123.49.224.0/20
123.49.240.0/23
123.49.243.0/24
123.49.245.0/24
123.49.246.0/23
123.49.248.0/21
123.50.160.0/19
123.52.0.0/14
123.56.0.0/15
@ -3443,7 +3481,8 @@
123.58.80.0/21
123.58.88.0/22
123.58.96.0/19
123.58.128.0/17
123.58.128.0/18
123.58.224.0/19
123.59.0.0/16
123.61.0.0/16
123.62.0.0/16
@ -3509,7 +3548,10 @@
124.68.0.0/17
124.68.128.0/18
124.68.192.0/19
124.68.224.0/20
124.68.224.0/23
124.68.226.0/24
124.68.228.0/22
124.68.232.0/21
124.68.240.0/23
124.68.242.0/24
124.68.244.0/23
@ -3589,22 +3631,23 @@
129.204.0.0/16
129.211.0.0/16
129.223.254.0/24
129.227.99.0/24
130.36.146.0/23
130.214.218.0/23
131.228.96.0/24
131.253.12.0/29
131.253.12.80/28
131.253.12.240/29
132.159.251.0/24
132.232.0.0/16
132.237.134.0/24
132.237.150.0/24
134.175.0.0/16
135.84.247.0/24
135.84.255.0/24
135.159.208.0/20
135.244.80.0/20
137.59.59.0/24
137.59.88.0/22
138.32.244.0/22
138.32.244.0/24
139.5.56.0/21
139.5.80.0/22
139.5.92.0/22
@ -3756,6 +3799,7 @@
150.242.232.0/21
150.242.240.0/21
150.242.248.0/22
150.248.0.0/16
150.255.0.0/16
152.32.178.0/23
152.104.128.0/17
@ -3796,6 +3840,7 @@
157.148.0.0/16
157.156.0.0/16
157.255.0.0/16
158.116.80.0/22
159.75.0.0/16
159.221.232.0/22
159.226.0.0/16
@ -3836,7 +3881,6 @@
163.53.160.0/20
163.53.188.0/22
163.53.220.0/22
163.53.236.0/22
163.53.240.0/22
163.116.202.0/23
163.125.0.0/16
@ -3846,7 +3890,16 @@
163.204.0.0/16
163.244.246.0/24
164.52.80.0/24
165.84.251.0/25
165.84.251.128/26
165.84.251.192/27
165.84.251.224/28
165.84.251.240/29
165.84.251.248/30
165.84.251.253
165.84.251.254/31
165.156.30.0/24
165.254.82.27
166.111.0.0/16
167.139.0.0/16
167.189.0.0/16
@ -4031,7 +4084,6 @@
192.102.204.0/22
192.124.154.0/24
192.137.31.0/24
192.139.136.0/24
192.140.128.0/21
192.140.136.0/22
192.140.156.0/22
@ -4044,12 +4096,15 @@
193.9.22.0/24
193.17.120.0/22
193.20.64.0/22
193.32.54.0/24
193.112.0.0/16
193.143.92.0/24
193.200.196.0/24
193.200.222.160/28
194.138.136.0/24
194.138.202.0/23
194.138.245.0/24
195.142.215.0/24
198.175.100.0/22
198.208.17.0/24
198.208.19.0/24
@ -4409,6 +4464,16 @@
202.146.188.0/22
202.146.196.0/22
202.146.200.0/21
202.147.12.0/26
202.147.12.64/27
202.147.12.96/28
202.147.12.128/29
202.147.12.136/30
202.147.12.140/31
202.147.12.142
202.147.12.144/28
202.147.12.160/27
202.147.12.192/26
202.147.144.0/20
202.148.32.0/20
202.148.64.0/18
@ -4429,7 +4494,6 @@
202.157.192.0/19
202.158.160.0/19
202.158.242.0/24
202.160.140.0/22
202.160.156.0/22
202.160.176.0/20
202.162.67.0/24
@ -4854,7 +4918,16 @@
203.22.163.0/24
203.22.166.0/24
203.22.170.0/24
203.22.176.0/21
203.22.176.0/22
203.22.180.0/23
203.22.182.0/30
203.22.182.6/31
203.22.182.8/29
203.22.182.16/28
203.22.182.32/27
203.22.182.64/26
203.22.182.128/25
203.22.183.0/24
203.22.194.0/24
203.22.242.0/23
203.22.245.0/24
@ -4963,7 +5036,6 @@
203.26.148.0/23
203.26.154.0/24
203.26.158.0/23
203.26.161.0/24
203.26.170.0/24
203.26.173.0/24
203.26.176.0/24
@ -5180,7 +5252,9 @@
203.34.161.0/24
203.34.162.0/24
203.34.187.0/24
203.34.192.0/21
203.34.192.0/22
203.34.197.0/24
203.34.198.0/23
203.34.204.0/22
203.34.232.0/24
203.34.240.0/24
@ -5372,7 +5446,6 @@
203.119.113.0/24
203.119.114.0/23
203.119.116.0/22
203.119.120.0/21
203.119.128.0/17
203.123.58.0/24
203.128.32.0/19
@ -5442,7 +5515,9 @@
203.193.224.0/19
203.195.64.0/19
203.195.128.0/17
203.196.0.0/20
203.196.0.0/21
203.196.10.0/23
203.196.12.0/22
203.196.28.0/22
203.201.181.0/24
203.201.182.0/24
@ -5458,14 +5533,9 @@
203.212.80.0/20
203.217.164.0/22
203.223.0.0/20
203.223.16.0/24
203.223.22.0/24
204.55.160.0/24
204.74.96.0/24
204.114.176.0/23
206.219.44.0/23
206.219.50.0/23
206.219.52.0/23
207.89.20.0/24
210.2.0.0/23
210.2.2.0/24
@ -5474,7 +5544,6 @@
210.2.8.0/21
210.2.24.0/21
210.5.0.0/19
210.5.56.0/24
210.5.60.0/24
210.5.128.0/19
210.7.56.0/21
@ -5572,6 +5641,7 @@
211.160.0.0/13
212.64.0.0/17
212.129.128.0/17
213.199.169.0/24
218.0.0.0/12
218.16.0.0/13
218.24.0.0/14

View File

@ -1,8 +1,6 @@
#!/usr/bin/lua
------------------------------------------------
-- This file from luci-app-ssr-plus transplant to luci-app-passwall
-- This file is part of the luci-app-ssr-plus subscribe.lua
-- @author William Chan <root@williamchan.me>
------------------------------------------------
require 'nixio'
@ -10,6 +8,7 @@ require 'uci'
require 'luci.util'
require 'luci.jsonc'
require 'luci.sys'
local _api = require "luci.model.cbi.passwall.api.api"
-- these global functions are accessed all the time by the event handler
-- so caching them is worth the effort
@ -23,6 +22,7 @@ local application = 'passwall'
local uciType = 'nodes'
local ucic2 = uci.cursor()
local arg2 = arg[2]
local allowInsecure_default = ucic2:get(application, "@global_subscribe[0]", "allowInsecure")
ucic2:revert(application)
local log = function(...)
@ -68,7 +68,22 @@ do
end
import_config("tcp")
import_config("udp")
import_config("socks")
ucic2:foreach(application, "socks", function(t)
local node = t.node
local currentNode
if node then
currentNode = ucic2:get_all(application, node)
end
CONFIG[#CONFIG + 1] = {
log = true,
remarks = "Socks节点" .. t[".name"],
currentNode = currentNode,
set = function(server)
ucic2:set(application, t[".name"], "node", server)
end
}
end)
local tcp_node1_table = ucic2:get(application, "@auto_switch[0]", "tcp_node1")
if tcp_node1_table then
@ -110,40 +125,29 @@ do
end
ucic2:foreach(application, uciType, function(node)
if node.type == 'V2ray_shunt' then
if node.type == 'V2ray' and node.v2ray_protocol == '_shunt' then
local node_id = node[".name"]
local youtube_node_id = node.youtube_node
local netflix_node_id = node.netflix_node
local default_node_id = node.default_node
ucic2:foreach(application, "shunt_rules", function(e)
local _node_id = node[e[".name"]] or nil
local _node
if _node_id then
_node = ucic2:get_all(application, _node_id)
end
CONFIG[#CONFIG + 1] = {
log = false,
currentNode = _node,
remarks = "V2ray分流" .. e.remarks .. "节点",
set = function(server)
ucic2:set(application, node_id, e[".name"], server)
end
}
end)
local youtube_node
local netflix_node
local default_node_id = node.default_node
local default_node
if youtube_node_id then
youtube_node = ucic2:get_all(application, youtube_node_id)
end
if netflix_node_id then
netflix_node = ucic2:get_all(application, netflix_node_id)
end
if default_node_id then
default_node = ucic2:get_all(application, default_node_id)
end
CONFIG[#CONFIG + 1] = {
log = false,
currentNode = youtube_node,
remarks = "V2ray分流youtube节点",
set = function(server)
ucic2:set(application, node_id, "youtube_node", server)
end
}
CONFIG[#CONFIG + 1] = {
log = false,
currentNode = netflix_node,
remarks = "V2ray分流Netflix节点",
set = function(server)
ucic2:set(application, node_id, "netflix_node", server)
end
}
CONFIG[#CONFIG + 1] = {
log = false,
currentNode = default_node,
@ -152,7 +156,7 @@ do
ucic2:set(application, node_id, "default_node", server)
end
}
elseif node.type == 'V2ray_balancing' then
elseif node.type == 'V2ray' and node.v2ray_protocol == '_balancing' then
local node_id = node[".name"]
local nodes = {}
local new_nodes = {}
@ -370,7 +374,7 @@ local function processData(szType, content, add_mode)
if info.tls == "tls" or info.tls == "1" then
result.v2ray_stream_security = "tls"
result.tls_serverName = info.host
result.tls_allowInsecure = 1
result.tls_allowInsecure = allowInsecure_default
else
result.v2ray_stream_security = "none"
end
@ -428,7 +432,7 @@ local function processData(szType, content, add_mode)
if Info then
local address, port, peer
local password = Info[1]
local allowInsecure = 1
local allowInsecure = allowInsecure_default
local params = {}
local hostInfo = split(Info[2], ":")
if hostInfo then
@ -469,14 +473,19 @@ local function processData(szType, content, add_mode)
return nil
end
if not result.remarks then
result.remarks = result.address .. ':' .. result.port
if result.address and result.port then
result.remarks = result.address .. ':' .. result.port
else
result.remarks = "NULL"
end
end
return result
end
-- wget
local function wget(url)
-- curl
local function curl(url)
local ua = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36"
local stdout = luci.sys.exec('/usr/bin/wget --user-agent="' .. ua .. '" --no-check-certificate -t 3 -T 10 -O- "' .. url .. '"')
local stdout = luci.sys.exec('curl -sL --user-agent "' .. ua .. '" -k --retry 3 --connect-timeout 3 "' .. url .. '"')
return trim(stdout)
end
@ -485,19 +494,29 @@ local function truncate_nodes()
local function clear(type)
local node_num = ucic2:get(application, "@global_other[0]", type .. "_node_num") or 1
for i = 1, node_num, 1 do
local node = ucic2:get(application, "@global[0]", type.."_node" .. i)
local node = ucic2:get(application, "@global[0]", type .. "_node" .. i)
if node then
local is_sub_node = ucic2:get(application, node, "is_sub") or 0
if is_sub_node == "1" then
is_stop = 1
ucic2:set(application, '@global[0]', type.."_node" .. i, "nil")
ucic2:set(application, '@global[0]', type .. "_node" .. i, "nil")
end
end
end
end
clear("tcp")
clear("udp")
clear("socks")
ucic2:foreach(application, "socks", function(t)
local node = t.node
if node then
local is_sub_node = ucic2:get(application, node, "is_sub") or 0
if is_sub_node == "1" then
is_stop = 1
ucic2:set(application, t[".name"], "node", "nil")
end
end
end)
ucic2:foreach(application, uciType, function(node)
if (node.is_sub or node.hashkey) and node.add_mode ~= '导入' then
@ -516,7 +535,7 @@ local function select_node(nodes, config)
local server
if config.currentNode then
-- 特别优先级 V2ray分流 + 备注
if config.currentNode.type == 'V2ray_shunt' then
if config.currentNode.type == 'V2ray' and config.currentNode.v2ray_protocol == '_shunt' then
for id, node in pairs(nodes) do
if node.remarks == config.currentNode.remarks then
log('选择【' .. config.remarks .. '】V2ray分流匹配节点' .. node.remarks)
@ -526,7 +545,7 @@ local function select_node(nodes, config)
end
end
-- 特别优先级 V2ray负载均衡 + 备注
if config.currentNode.type == 'V2ray_balancing' then
if config.currentNode.type == 'V2ray' and config.currentNode.v2ray_protocol == '_balancing' then
for id, node in pairs(nodes) do
if node.remarks == config.currentNode.remarks then
log('选择【' .. config.remarks .. '】V2ray负载均衡匹配节点' .. node.remarks)
@ -620,6 +639,9 @@ local function update_node(manual)
for _, v in ipairs(nodeResult) do
for _, vv in ipairs(v) do
local cfgid = ucic2:add(application, uciType)
local uuid = _api.gen_uuid()
ucic2:rename(application, cfgid, uuid)
cfgid = uuid
for kkk, vvv in pairs(vv) do
ucic2:set(application, cfgid, kkk, vvv)
end
@ -631,9 +653,7 @@ local function update_node(manual)
local nodes = {}
local ucic3 = uci.cursor()
ucic3:foreach(application, uciType, function(node)
if (node.port and node.address and node.remarks) or node.type == 'V2ray_shunt' or node.type == 'V2ray_balancing' then
nodes[node['.name']] = node
end
nodes[node['.name']] = node
end)
for _, config in pairs(CONFIG) do
if config.nodes and type(config.nodes) == "table" then
@ -721,6 +741,7 @@ local function parse_link(raw, remark, manual)
if result then
if is_filter_keyword(result.remarks) or
not result.address or
result.remarks == "NULL" or
result.address:match("[^0-9a-zA-Z%-%_%.%s]") or -- 中文做地址的 也没有人拿中文域名搞就算中文域也有Puny Code SB 机场
not result.address:find("%.") or -- 虽然没有.也算域,不过应该没有人会这样干吧
result.address:sub(#result.address) == "." -- 结尾是.
@ -749,7 +770,7 @@ local execute = function()
local remark = obj.remark
local url = obj.url
log('正在订阅: ' .. url)
local raw = wget(url)
local raw = curl(url)
parse_link(raw, remark)
end
end)

View File

@ -5,6 +5,7 @@ LOG_FILE=/var/log/$CONFIG.log
echolog() {
local d="$(date "+%Y-%m-%d %H:%M:%S")"
#echo -e "$d: $1"
echo -e "$d: $1" >> $LOG_FILE
}
@ -21,18 +22,19 @@ test_url() {
[ -n "$2" ] && try=$2
local timeout=2
[ -n "$3" ] && timeout=$3
status=$(/usr/bin/wget -4 --no-check-certificate --spider --timeout=$timeout --tries $try "$url" 2>/dev/null)
if [ "$?" == 0 ]; then
status=200
else
status=$(/usr/bin/wget --no-check-certificate --spider --timeout=$timeout --tries $try "$url" 2>/dev/null)
[ "$?" == 0 ] && status=200
fi
local extra_params=$4
status=$(/usr/bin/curl -I -o /dev/null -skL $extra_params --connect-timeout $timeout --retry $try -w %{http_code} "$url")
case "$status" in
204|\
200)
status=200
;;
esac
echo $status
}
test_proxy() {
local try=5
local try=3
result=0
status=$(test_url "https://www.google.com/generate_204" $try)
if [ "$status" = "200" ]; then
@ -68,6 +70,22 @@ test_auto_switch() {
return 2
elif [ "$status" == 1 ]; then
echolog "自动切换检测:${type}_${index}节点异常,开始切换节点!"
#检测自动切换列表主节点是否能使用
local main_node=$(echo $b_tcp_nodes | awk -F ' ' '{print $1}')
if [ "$now_node" != "$main_node" ]; then
local tmp_port=$(/usr/share/passwall/app.sh get_new_port 61080 tcp)
/usr/share/passwall/app.sh run_socks "$main_node" "127.0.0.1" "$tmp_port" "/var/etc/passwall/auto_switch_main.json" "10"
proxy_status=$(test_url "https://www.google.com/generate_204" 3 3 "-x socks5h://127.0.0.1:$tmp_port")
ps -w | grep -v "grep" | grep "/var/etc/passwall/auto_switch_main.json" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
if [ "$proxy_status" -eq 200 ]; then
#主节点正常,切换到主节点
echolog "自动切换检测:${type}_${index}主节点正常,切换到主节点!"
/usr/share/passwall/app.sh node_switch $type $2 $index $main_node
return 0
fi
fi
local new_node
in_backup_nodes=$(echo $b_tcp_nodes | grep $now_node)
# 判断当前节点是否存在于备用节点列表里
@ -100,31 +118,32 @@ test_auto_switch() {
}
start() {
if [ "$(ps -w | grep -v grep | grep $CONFIG/test.sh | wc -l)" -gt 2 ]; then
exit 1
fi
ENABLED=$(config_t_get global enabled 0)
[ "$ENABLED" != 1 ] && return 1
ENABLED=$(config_t_get auto_switch enable 0)
[ "$ENABLED" != 1 ] && return 1
delay=$(config_t_get auto_switch testing_time 1)
sleep ${delay}m
while [ "$ENABLED" -eq 1 ]
do
# TCP_NODE_NUM=$(config_t_get global_other tcp_node_num 1)
# 暂时只能检测TCP1
TCP_NODE_NUM=1
for i in $(seq 1 $TCP_NODE_NUM); do
eval TCP_NODE$i=\"$(config_t_get auto_switch tcp_node$i nil)\"
eval tmp=\$TCP_NODE$i
[ -n "$tmp" -a "$tmp" != "nil" ] && {
test_auto_switch TCP tcp $i "$tmp"
}
done
(
flock -xn 200
[ "$?" != "0" ] && exit 0
ENABLED=$(config_t_get global enabled 0)
[ "$ENABLED" != 1 ] && return 1
ENABLED=$(config_t_get auto_switch enable 0)
[ "$ENABLED" != 1 ] && return 1
delay=$(config_t_get auto_switch testing_time 1)
sleep ${delay}m
done
while [ "$ENABLED" -eq 1 ]
do
# TCP_NODE_NUM=$(config_t_get global_other tcp_node_num 1)
# 暂时只能检测TCP1
TCP_NODE_NUM=1
for i in $(seq 1 $TCP_NODE_NUM); do
eval TCP_NODE$i=\"$(config_t_get auto_switch tcp_node$i nil)\"
eval tmp=\$TCP_NODE$i
[ -n "$tmp" -a "$tmp" != "nil" ] && {
test_auto_switch TCP tcp $i "$tmp"
}
done
delay=$(config_t_get auto_switch testing_time 1)
sleep ${delay}m
done
) 200>"/var/lock/passwall_auto_switch.lock"
}
case $1 in