mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-10-29 17:45:13 +08:00
update 2026-07-28 01:38:11
This commit is contained in:
1 parent
20b786ab77
commit
25d570431d
6243 files changed
+2850542
No files matched your search
@@ -0,0 +1,128 @@
|
||||
|
||||
config global
|
||||
option enabled '0'
|
||||
option node_socks_port '1070'
|
||||
option localhost_proxy '1'
|
||||
option client_proxy '1'
|
||||
option socks_enabled '0'
|
||||
option acl_enable '0'
|
||||
option node 'rulenode'
|
||||
option direct_dns_protocol 'auto'
|
||||
option direct_dns_query_strategy 'UseIP'
|
||||
option remote_dns_protocol 'tcp'
|
||||
option remote_dns '1.1.1.1'
|
||||
option remote_dns_query_strategy 'UseIPv4'
|
||||
option dns_hosts 'cloudflare-dns.com 1.1.1.1
|
||||
dns.google.com 8.8.8.8'
|
||||
option log_node '1'
|
||||
option loglevel 'error'
|
||||
|
||||
config global_haproxy
|
||||
option balancing_enable '0'
|
||||
|
||||
config global_delay
|
||||
option start_daemon '1'
|
||||
option start_delay '60'
|
||||
|
||||
config global_forwarding
|
||||
option tcp_no_redir_ports 'disable'
|
||||
option udp_no_redir_ports 'disable'
|
||||
option tcp_redir_ports '1:65535'
|
||||
option udp_redir_ports '1:65535'
|
||||
option accept_icmp '0'
|
||||
option prefer_nft '1'
|
||||
option tcp_proxy_way 'redirect'
|
||||
option ipv6_tproxy '0'
|
||||
|
||||
config global_xray
|
||||
option sniffing_override_dest '0'
|
||||
|
||||
config global_other
|
||||
option auto_detection_time 'tcping'
|
||||
option show_node_info '0'
|
||||
|
||||
config global_rules
|
||||
option geosite_update '1'
|
||||
option geoip_update '1'
|
||||
option v2ray_location_asset '/usr/share/v2ray/'
|
||||
option geoip_url 'https://github.com/Loyalsoldier/geoip/releases/latest/download/geoip.dat'
|
||||
option geosite_url 'https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat'
|
||||
|
||||
config global_app
|
||||
option geoview_file '/usr/bin/geoview'
|
||||
option xray_file '/usr/bin/xray'
|
||||
option hysteria_file '/usr/bin/hysteria'
|
||||
option sing_box_file '/usr/bin/sing-box'
|
||||
|
||||
config global_subscribe
|
||||
option filter_keyword_mode '1'
|
||||
|
||||
config global_singbox
|
||||
|
||||
config shunt_rules 'China'
|
||||
option remarks 'China'
|
||||
option network 'tcp,udp'
|
||||
option domain_list 'geosite:cn'
|
||||
option ip_list 'geoip:cn'
|
||||
|
||||
config shunt_rules 'Iran'
|
||||
option remarks 'Iran'
|
||||
option network 'tcp,udp'
|
||||
option domain_list 'geosite:ir
|
||||
#rule-set:remote:https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geosite-ir.srs'
|
||||
option ip_list 'geoip:ir
|
||||
#rule-set:remote:https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geoip-ir.srs'
|
||||
|
||||
config shunt_rules 'Russia_Block'
|
||||
option remarks 'Russia_Block'
|
||||
option network 'tcp,udp'
|
||||
option domain_list 'geosite:ru-blocked
|
||||
#rule-set:remote:https://raw.githubusercontent.com/runetfreedom/russia-v2ray-rules-dat/refs/heads/release/sing-box/rule-set-geosite/geosite-ru-blocked.srs'
|
||||
option ip_list 'geoip:ru-blocked
|
||||
#rule-set:remote:https://raw.githubusercontent.com/runetfreedom/russia-v2ray-rules-dat/refs/heads/release/sing-box/rule-set-geoip/geoip-ru-blocked.srs'
|
||||
|
||||
config shunt_rules 'Russia'
|
||||
option remarks 'Russia'
|
||||
option network 'tcp,udp'
|
||||
option ip_list 'geoip:ru
|
||||
#rule-set:remote:https://raw.githubusercontent.com/runetfreedom/russia-v2ray-rules-dat/refs/heads/release/sing-box/rule-set-geoip/geoip-ru.srs'
|
||||
|
||||
config shunt_rules 'PrivateIP'
|
||||
option remarks 'PrivateIP'
|
||||
option network 'tcp,udp'
|
||||
option ip_list '10.0.0.0/8
|
||||
127.0.0.0/8
|
||||
198.51.100.0/24
|
||||
192.0.0.0/24
|
||||
169.254.0.0/16
|
||||
224.0.0.0/3
|
||||
192.168.0.0/16
|
||||
192.88.99.0/24
|
||||
100.64.0.0/10
|
||||
172.16.0.0/12
|
||||
0.0.0.0/8
|
||||
192.0.2.0/24
|
||||
203.0.113.0/24'
|
||||
|
||||
config nodes 'examplenode'
|
||||
option remarks 'Example'
|
||||
option type 'Xray'
|
||||
option protocol 'socks'
|
||||
option address 'passwall2.github'
|
||||
option port '1080'
|
||||
option tls '0'
|
||||
option transport 'raw'
|
||||
option tcp_guise 'none'
|
||||
option tcp_fast_open '0'
|
||||
option tcpMptcp '0'
|
||||
|
||||
config nodes 'rulenode'
|
||||
option remarks 'rulenode'
|
||||
option type 'Xray'
|
||||
option protocol '_shunt'
|
||||
option PrivateIP '_direct'
|
||||
option default_node 'examplenode'
|
||||
option domainStrategy 'IPOnDemand'
|
||||
option domainMatcher 'hybrid'
|
||||
option write_ipset_direct '1'
|
||||
option enable_geoview_ip '1'
|
||||
+1363
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,13 @@
|
||||
0.0.0.0/8
|
||||
10.0.0.0/8
|
||||
100.64.0.0/10
|
||||
127.0.0.0/8
|
||||
169.254.0.0/16
|
||||
172.16.0.0/12
|
||||
192.168.0.0/16
|
||||
224.0.0.0/4
|
||||
240.0.0.0/4
|
||||
::/127
|
||||
fc00::/7
|
||||
fe80::/10
|
||||
ff00::/8
|
||||
@@ -0,0 +1,26 @@
|
||||
courier.push.apple.com
|
||||
rbsxbxp-mim.vivox.com
|
||||
rbsxbxp.www.vivox.com
|
||||
rbsxbxp-ws.vivox.com
|
||||
rbspsxp.www.vivox.com
|
||||
rbspsxp-mim.vivox.com
|
||||
rbspsxp-ws.vivox.com
|
||||
rbswxp.www.vivox.com
|
||||
rbswxp-mim.vivox.com
|
||||
disp-rbspsp-5-1.vivox.com
|
||||
disp-rbsxbp-5-1.vivox.com
|
||||
proxy.rbsxbp.vivox.com
|
||||
proxy.rbspsp.vivox.com
|
||||
proxy.rbswp.vivox.com
|
||||
rbswp.vivox.com
|
||||
rbsxbp.vivox.com
|
||||
rbspsp.vivox.com
|
||||
rbspsp.www.vivox.com
|
||||
rbswp.www.vivox.com
|
||||
rbsxbp.www.vivox.com
|
||||
rbsxbxp.vivox.com
|
||||
rbspsxp.vivox.com
|
||||
rbswxp.vivox.com
|
||||
Mijia Cloud
|
||||
dlg.io.mi.com
|
||||
marscdn.c2c.wechat.com
|
||||
@@ -0,0 +1,236 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local api = require ("luci.passwall2.api")
|
||||
local appname = api.appname
|
||||
local fs = api.fs
|
||||
local jsonc = api.jsonc
|
||||
local uci = api.uci
|
||||
local sys = api.sys
|
||||
|
||||
local log = api.log
|
||||
|
||||
function get_ip_port_from(str)
|
||||
local result_port = sys.exec("echo -n " .. str .. " | sed -n 's/^.*[:#]\\([0-9]*\\)$/\\1/p'")
|
||||
local result_ip = sys.exec(string.format("__host=%s;__varport=%s;", str, result_port) .. "echo -n ${__host%%${__varport:+[:#]${__varport}*}}")
|
||||
return result_ip, result_port
|
||||
end
|
||||
|
||||
local var = api.get_args(arg)
|
||||
local haproxy_path = var["-path"]
|
||||
local haproxy_conf = var["-conf"]
|
||||
local haproxy_dns = "127.0.0.1"
|
||||
|
||||
local cpu_thread = sys.exec('echo -n $(cat /proc/cpuinfo | grep "processor" | wc -l)') or "1"
|
||||
local health_check_type = uci:get(appname, "@global_haproxy[0]", "health_check_type") or "tcp"
|
||||
local health_check_inter = uci:get(appname, "@global_haproxy[0]", "health_check_inter") or "20"
|
||||
local balancingStrategy = uci:get(appname, "@global_haproxy[0]", "balancingStrategy") or "roundrobin"
|
||||
local console_port = uci:get(appname, "@global_haproxy[0]", "console_port")
|
||||
local bind_local = uci:get(appname, "@global_haproxy[0]", "bind_local") or "0"
|
||||
local bind_address = "0.0.0.0"
|
||||
if bind_local == "1" then bind_address = "127.0.0.1" end
|
||||
|
||||
log(0, "HAProxy: ")
|
||||
log(1, api.i18n.translatef("Console Port: %s", console_port))
|
||||
fs.mkdir(haproxy_path)
|
||||
local haproxy_file = haproxy_path .. "/" .. haproxy_conf
|
||||
|
||||
local f_out = io.open(haproxy_file, "a")
|
||||
|
||||
local haproxy_config = [[
|
||||
global
|
||||
daemon
|
||||
log 127.0.0.1 local2
|
||||
maxconn 60000
|
||||
stats socket {{path}}/haproxy.sock
|
||||
nbthread {{nbthread}}
|
||||
external-check
|
||||
insecure-fork-wanted
|
||||
spread-checks 50
|
||||
tune.max-checks-per-thread 5
|
||||
|
||||
defaults
|
||||
mode tcp
|
||||
log global
|
||||
option tcplog
|
||||
option dontlognull
|
||||
option http-server-close
|
||||
#option forwardfor except 127.0.0.0/8
|
||||
option redispatch
|
||||
retries 2
|
||||
timeout http-request 10s
|
||||
timeout queue 1m
|
||||
timeout connect 10s
|
||||
timeout client 1m
|
||||
timeout server 1m
|
||||
timeout http-keep-alive 10s
|
||||
timeout check 10s
|
||||
maxconn 3000
|
||||
|
||||
resolvers mydns
|
||||
resolve_retries 1
|
||||
timeout resolve 5s
|
||||
hold valid 600s
|
||||
{{dns}}
|
||||
]]
|
||||
|
||||
haproxy_config = haproxy_config:gsub("{{path}}", haproxy_path)
|
||||
haproxy_config = haproxy_config:gsub("{{nbthread}}", cpu_thread)
|
||||
|
||||
local mydns = ""
|
||||
local index = 0
|
||||
string.gsub(haproxy_dns, '[^' .. "," .. ']+', function(w)
|
||||
index = index + 1
|
||||
local s = w:gsub("#", ":")
|
||||
if not s:find(":") then
|
||||
s = s .. ":53"
|
||||
end
|
||||
mydns = mydns .. (index > 1 and "\n" or "") .. " " .. string.format("nameserver dns%s %s", index, s)
|
||||
end)
|
||||
haproxy_config = haproxy_config:gsub("{{dns}}", mydns)
|
||||
|
||||
f_out:write(haproxy_config)
|
||||
|
||||
local listens = {}
|
||||
|
||||
uci:foreach(appname, "haproxy_config", function(t)
|
||||
if t.enabled == "1" then
|
||||
local server_remark
|
||||
local server_address
|
||||
local server_port
|
||||
local lbss = t.lbss
|
||||
local listen_port = tonumber(t.haproxy_port) or 0
|
||||
local server_node = uci:get_all(appname, lbss)
|
||||
local hop = (health_check_type == "passwall_logic") and (server_node.hysteria_hop or server_node.hysteria2_hop) or nil
|
||||
hop = hop and hop:gsub(":", "-") or nil
|
||||
if server_node and server_node.address and (server_node.port or hop) then
|
||||
server_remark = server_node.address .. ":" .. (server_node.port or hop)
|
||||
server_address = server_node.address
|
||||
server_port = server_node.port or hop
|
||||
t.origin_address = server_address
|
||||
t.origin_port = server_port
|
||||
if health_check_type == "passwall_logic" then
|
||||
if server_node.type ~= "Socks" then
|
||||
local relay_port = server_node.port
|
||||
local new_port = api.get_new_port()
|
||||
local config_file = string.format("haproxy_%s_%s.json", t[".name"], new_port)
|
||||
sys.call(string.format('/usr/share/%s/app.sh run_socks "%s"> /dev/null',
|
||||
appname,
|
||||
string.format("flag=%s node=%s bind=%s socks_port=%s config_file=%s",
|
||||
new_port, --flag
|
||||
server_node[".name"], --node
|
||||
"127.0.0.1", --bind
|
||||
new_port, --socks port
|
||||
config_file --config file
|
||||
)
|
||||
)
|
||||
)
|
||||
server_address = "127.0.0.1"
|
||||
server_port = new_port
|
||||
end
|
||||
end
|
||||
else
|
||||
server_address, server_port = get_ip_port_from(lbss)
|
||||
server_remark = server_address .. ":" .. server_port
|
||||
t.origin_address = server_address
|
||||
t.origin_port = server_port
|
||||
end
|
||||
if server_address and server_port and listen_port > 0 then
|
||||
if not listens[listen_port] then
|
||||
listens[listen_port] = {}
|
||||
end
|
||||
t.server_remark = server_remark
|
||||
t.server_address = server_address
|
||||
t.server_port = server_port
|
||||
table.insert(listens[listen_port], t)
|
||||
else
|
||||
log(1, api.i18n.translate("Discard one obviously invalid node."))
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local inter = tonumber((health_check_inter or "20"):match("^%d+"))
|
||||
inter = (inter and inter >= 20) and inter or 20
|
||||
local inter_arg = "inter " .. inter .. "s fastinter " .. inter / 2 .. "s downinter " .. inter * 1.5 .. "s"
|
||||
|
||||
local sortTable = {}
|
||||
for i in pairs(listens) do
|
||||
if i ~= nil then
|
||||
table.insert(sortTable, i)
|
||||
end
|
||||
end
|
||||
table.sort(sortTable, function(a,b) return (a < b) end)
|
||||
|
||||
for i, port in pairs(sortTable) do
|
||||
log(1, api.i18n.translatef("Entrance %s:%s", bind_address, port))
|
||||
|
||||
f_out:write("\n" .. string.format([[
|
||||
listen %s
|
||||
bind %s:%s
|
||||
mode tcp
|
||||
balance %s
|
||||
]], port, bind_address, port, balancingStrategy))
|
||||
|
||||
if health_check_type == "passwall_logic" then
|
||||
f_out:write(string.format([[
|
||||
option external-check
|
||||
external-check command "/usr/share/%s/haproxy_check.sh"
|
||||
]], appname))
|
||||
end
|
||||
|
||||
local count_M, count_B = 1, 1
|
||||
for i, o in ipairs(listens[port]) do
|
||||
local remark = o.server_remark or ""
|
||||
-- To prevent duplicate names from causing the program to fail to run.
|
||||
if tostring(o.backup) ~= "1" then
|
||||
remark = "M" .. count_M .. "-" .. remark
|
||||
count_M = count_M + 1
|
||||
else
|
||||
remark = "B" .. count_B .. "-" .. remark
|
||||
count_B = count_B + 1
|
||||
end
|
||||
local server = o.server_address .. ":" .. o.server_port
|
||||
local server_conf = "server {{remark}} {{server}} weight {{weight}} {{resolvers}} check {{inter_arg}} rise 2 fall 2 {{backup}}"
|
||||
server_conf = server_conf:gsub("{{remark}}", remark)
|
||||
server_conf = server_conf:gsub("{{server}}", server)
|
||||
server_conf = server_conf:gsub("{{weight}}", o.lbweight)
|
||||
local resolvers = "resolvers mydns"
|
||||
if api.is_ip(o.server_address) then
|
||||
resolvers = ""
|
||||
end
|
||||
server_conf = server_conf:gsub("{{resolvers}}", resolvers)
|
||||
server_conf = server_conf:gsub("{{inter_arg}}", inter_arg)
|
||||
server_conf = server_conf:gsub("{{backup}}", tostring(o.backup) == "1" and "backup" or "")
|
||||
|
||||
f_out:write(" " .. api.trim(server_conf) .. "\n")
|
||||
|
||||
if o.export ~= "0" then
|
||||
sys.call(string.format(". /usr/share/%s/utils.sh ; add_ip2route %s %s", appname, o.origin_address, o.export))
|
||||
end
|
||||
|
||||
log(2, string.format(api.i18n.translatef("Node: %s:%s, Weight: %s", o.origin_address, o.origin_port, o.lbweight)))
|
||||
end
|
||||
end
|
||||
|
||||
-- Console config
|
||||
local console_user = uci:get(appname, "@global_haproxy[0]", "console_user")
|
||||
local console_password = uci:get(appname, "@global_haproxy[0]", "console_password")
|
||||
local str = [[
|
||||
listen console
|
||||
bind 0.0.0.0:%s
|
||||
mode http
|
||||
stats refresh 30s
|
||||
stats uri /
|
||||
stats admin if TRUE
|
||||
%s
|
||||
]]
|
||||
f_out:write("\n" .. string.format(str, console_port, (console_user and console_user ~= "" and console_password and console_password ~= "") and "stats auth " .. console_user .. ":" .. console_password or ""))
|
||||
|
||||
f_out:close()
|
||||
|
||||
-- Built-in health check URL
|
||||
if health_check_type == "passwall_logic" then
|
||||
local probeUrl = uci:get(appname, "@global_haproxy[0]", "health_probe_url") or "https://www.google.com/generate_204"
|
||||
local f_url = io.open(haproxy_path .. "/Probe_URL", "w")
|
||||
f_url:write(probeUrl)
|
||||
f_url:close()
|
||||
end
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/bin/sh
|
||||
|
||||
export PATH=/usr/sbin:/usr/bin:/sbin:/bin:/root/bin
|
||||
CONFIG=passwall2
|
||||
|
||||
listen_address=$1
|
||||
listen_port=$2
|
||||
server_address=$3
|
||||
server_port=$4
|
||||
|
||||
busybox pgrep -af "${CONFIG}/" | grep -E 'app\.sh.*(start|stop)|nftables\.sh|iptables\.sh|subscribe\.lua' >/dev/null && {
|
||||
# No detection during specific task execution
|
||||
exit 0
|
||||
}
|
||||
|
||||
probe_file="/tmp/etc/${CONFIG}/haproxy/Probe_URL"
|
||||
probeUrl="https://www.google.com/generate_204"
|
||||
if [ -f "$probe_file" ]; then
|
||||
firstLine=$(head -n 1 "$probe_file" | tr -d ' \t\n')
|
||||
[ -n "$firstLine" ] && probeUrl="$firstLine"
|
||||
fi
|
||||
|
||||
extra_params="-x socks5h://${server_address}:${server_port}"
|
||||
if /usr/bin/curl --help all | grep -q "\-\-retry-all-errors"; then
|
||||
extra_params="${extra_params} --retry-all-errors"
|
||||
fi
|
||||
|
||||
status=$(/usr/bin/curl -I -o /dev/null -skL ${extra_params} --connect-timeout 3 --retry 1 --max-time 6 -w "%{http_code}" "${probeUrl}")
|
||||
|
||||
case "$status" in
|
||||
200|204)
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,372 @@
|
||||
local api = require "luci.passwall2.api"
|
||||
local appname = "passwall2"
|
||||
local uci = api.uci
|
||||
local sys = api.sys
|
||||
local jsonc = api.jsonc
|
||||
local fs = api.fs
|
||||
local datatypes = api.datatypes
|
||||
local TMP = {}
|
||||
|
||||
local function tinsert(table_name, val)
|
||||
if table_name and type(table_name) == "table" then
|
||||
if not TMP[table_name] then
|
||||
TMP[table_name] = {}
|
||||
end
|
||||
if TMP[table_name][val] then
|
||||
return false
|
||||
end
|
||||
table.insert(table_name, val)
|
||||
TMP[table_name][val] = true
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function backup_servers()
|
||||
local DNSMASQ_DNS = uci:get("dhcp", "@dnsmasq[0]", "server")
|
||||
if DNSMASQ_DNS and #DNSMASQ_DNS > 0 then
|
||||
uci:set(appname, "@global[0]", "dnsmasq_servers", DNSMASQ_DNS)
|
||||
api.uci_save(uci, appname, true)
|
||||
end
|
||||
end
|
||||
|
||||
local function restore_servers()
|
||||
local dns_table = {}
|
||||
local DNSMASQ_DNS = uci:get("dhcp", "@dnsmasq[0]", "server")
|
||||
if DNSMASQ_DNS and #DNSMASQ_DNS > 0 then
|
||||
for k, v in ipairs(DNSMASQ_DNS) do
|
||||
tinsert(dns_table, v)
|
||||
end
|
||||
end
|
||||
local OLD_SERVER = uci:get(appname, "@global[0]", "dnsmasq_servers")
|
||||
if OLD_SERVER and #OLD_SERVER > 0 then
|
||||
for k, v in ipairs(OLD_SERVER) do
|
||||
tinsert(dns_table, v)
|
||||
end
|
||||
uci:delete(appname, "@global[0]", "dnsmasq_servers")
|
||||
api.uci_save(uci, appname, true)
|
||||
end
|
||||
if dns_table and #dns_table > 0 then
|
||||
uci:set_list("dhcp", "@dnsmasq[0]", "server", dns_table)
|
||||
api.uci_save(uci, "dhcp", true)
|
||||
end
|
||||
end
|
||||
|
||||
function stretch()
|
||||
local dnsmasq_server = uci:get("dhcp", "@dnsmasq[0]", "server")
|
||||
local dnsmasq_noresolv = uci:get("dhcp", "@dnsmasq[0]", "noresolv")
|
||||
local _flag
|
||||
if dnsmasq_server and #dnsmasq_server > 0 then
|
||||
for k, v in ipairs(dnsmasq_server) do
|
||||
if not v:find("/") then
|
||||
_flag = true
|
||||
end
|
||||
end
|
||||
end
|
||||
if not _flag and dnsmasq_noresolv == "1" then
|
||||
uci:delete("dhcp", "@dnsmasq[0]", "noresolv")
|
||||
local RESOLVFILE = "/tmp/resolv.conf.d/resolv.conf.auto"
|
||||
local file = io.open(RESOLVFILE, "r")
|
||||
if not file then
|
||||
RESOLVFILE = "/tmp/resolv.conf.auto"
|
||||
else
|
||||
local size = file:seek("end")
|
||||
file:close()
|
||||
if size == 0 then
|
||||
RESOLVFILE = "/tmp/resolv.conf.auto"
|
||||
end
|
||||
end
|
||||
uci:set("dhcp", "@dnsmasq[0]", "resolvfile", RESOLVFILE)
|
||||
api.uci_save(uci, "dhcp", true)
|
||||
end
|
||||
end
|
||||
|
||||
function restart(var)
|
||||
local LOG = var["LOG"]
|
||||
sys.call("/etc/init.d/dnsmasq restart >/dev/null 2>&1")
|
||||
if LOG == "1" then
|
||||
api.log(0, api.i18n.translate("Restart dnsmasq service."))
|
||||
end
|
||||
end
|
||||
|
||||
function logic_restart(var)
|
||||
local LOG = var["LOG"]
|
||||
local DEFAULT_DNS = api.get_cache_var("DEFAULT_DNS")
|
||||
if DEFAULT_DNS then
|
||||
backup_servers()
|
||||
--sys.call("sed -i '/list server/d' /etc/config/dhcp >/dev/null 2>&1")
|
||||
local dns_table = {}
|
||||
local dnsmasq_server = uci:get("dhcp", "@dnsmasq[0]", "server")
|
||||
if dnsmasq_server and #dnsmasq_server > 0 then
|
||||
for k, v in ipairs(dnsmasq_server) do
|
||||
if v:find("/") then
|
||||
tinsert(dns_table, v)
|
||||
end
|
||||
end
|
||||
uci:set_list("dhcp", "@dnsmasq[0]", "server", dns_table)
|
||||
api.uci_save(uci, "dhcp", true)
|
||||
end
|
||||
sys.call("/etc/init.d/dnsmasq restart >/dev/null 2>&1")
|
||||
restore_servers()
|
||||
else
|
||||
sys.call("/etc/init.d/dnsmasq restart >/dev/null 2>&1")
|
||||
end
|
||||
if LOG == "1" then
|
||||
api.log(0, api.i18n.translate("Restart dnsmasq service."))
|
||||
end
|
||||
end
|
||||
|
||||
function copy_instance(var)
|
||||
local LISTEN_PORT = var["LISTEN_PORT"]
|
||||
local TMP_DNSMASQ_PATH = var["TMP_DNSMASQ_PATH"]
|
||||
local conf_lines = {}
|
||||
local DEFAULT_DNSMASQ_CFGID = sys.exec("echo -n $(uci -q show dhcp.@dnsmasq[0] | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')")
|
||||
for line in io.lines("/tmp/etc/dnsmasq.conf." .. DEFAULT_DNSMASQ_CFGID) do
|
||||
local filter
|
||||
if line:find("passwall2") then filter = true end
|
||||
if line:find("ubus") then filter = true end
|
||||
if line:find("dhcp") then filter = true end
|
||||
if line:find("server=") == 1 then filter = true end
|
||||
if line:find("port=") == 1 then filter = true end
|
||||
if line:find("conf%-dir=") == 1 then
|
||||
filter = true
|
||||
if TMP_DNSMASQ_PATH then
|
||||
local tmp_path = line:sub(1 + #"conf-dir=")
|
||||
sys.call(string.format("cp -r %s/* %s/ 2>/dev/null", tmp_path, TMP_DNSMASQ_PATH))
|
||||
end
|
||||
end
|
||||
if line:find("address=") == 1 or (line:find("server=") == 1 and line:find("/")) then filter = nil end
|
||||
if not filter then
|
||||
tinsert(conf_lines, line)
|
||||
end
|
||||
end
|
||||
tinsert(conf_lines, "port=" .. LISTEN_PORT)
|
||||
if TMP_DNSMASQ_PATH then
|
||||
sys.call("rm -rf " .. TMP_DNSMASQ_PATH .. "/*passwall2*")
|
||||
end
|
||||
if var["return"] == "1" then
|
||||
return conf_lines
|
||||
end
|
||||
if #conf_lines > 0 then
|
||||
local DNSMASQ_CONF = var["DNSMASQ_CONF"]
|
||||
local conf_out = io.open(DNSMASQ_CONF, "a")
|
||||
conf_out:write(table.concat(conf_lines, "\n"))
|
||||
conf_out:write("\n")
|
||||
conf_out:close()
|
||||
end
|
||||
end
|
||||
|
||||
function add_rule(var)
|
||||
local FLAG = var["FLAG"]
|
||||
local TMP_DNSMASQ_PATH = var["TMP_DNSMASQ_PATH"]
|
||||
local DNSMASQ_CONF_FILE = var["DNSMASQ_CONF_FILE"]
|
||||
local LISTEN_PORT = var["LISTEN_PORT"]
|
||||
local DEFAULT_DNS = var["DEFAULT_DNS"]
|
||||
local LOCAL_DNS = var["LOCAL_DNS"]
|
||||
local TUN_DNS = var["TUN_DNS"]
|
||||
local NFTFLAG = var["NFTFLAG"]
|
||||
local CACHE_PATH = api.CACHE_PATH
|
||||
local CACHE_FLAG = "dnsmasq_" .. FLAG
|
||||
local CACHE_DNS_PATH = CACHE_PATH .. "/" .. CACHE_FLAG
|
||||
local CACHE_TEXT_FILE = CACHE_DNS_PATH .. ".txt"
|
||||
|
||||
local list1 = {}
|
||||
|
||||
local function check_dns(domain, dns)
|
||||
if domain == "" or domain:find("#") then
|
||||
return false
|
||||
end
|
||||
if not dns then
|
||||
return
|
||||
end
|
||||
for k,v in ipairs(list1[domain].dns) do
|
||||
if dns == v then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function check_ipset(domain, ipset)
|
||||
if domain == "" or domain:find("#") then
|
||||
return false
|
||||
end
|
||||
if not ipset then
|
||||
return
|
||||
end
|
||||
for k,v in ipairs(list1[domain].ipsets) do
|
||||
if ipset == v then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function set_domain_dns(domain, dns)
|
||||
if domain == "" or domain:find("#") then
|
||||
return
|
||||
end
|
||||
if not dns then
|
||||
return
|
||||
end
|
||||
if not list1[domain] then
|
||||
list1[domain] = {
|
||||
dns = {},
|
||||
ipsets = {}
|
||||
}
|
||||
end
|
||||
for line in string.gmatch(dns, '[^' .. "," .. ']+') do
|
||||
if not check_dns(domain, line) then
|
||||
table.insert(list1[domain].dns, line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function set_domain_ipset(domain, ipset)
|
||||
if domain == "" or domain:find("#") then
|
||||
return
|
||||
end
|
||||
if not ipset then
|
||||
return
|
||||
end
|
||||
if not list1[domain] then
|
||||
list1[domain] = {
|
||||
dns = {},
|
||||
ipsets = {}
|
||||
}
|
||||
end
|
||||
for line in string.gmatch(ipset, '[^' .. "," .. ']+') do
|
||||
if not check_ipset(domain, line) then
|
||||
table.insert(list1[domain].ipsets, line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local cache_text = ""
|
||||
local nodes_address_md5 = sys.exec("echo -n $(uci show passwall2 | grep '\\.address') | md5sum")
|
||||
local new_text = TMP_DNSMASQ_PATH .. DNSMASQ_CONF_FILE .. DEFAULT_DNS .. LOCAL_DNS .. TUN_DNS .. nodes_address_md5 .. NFTFLAG
|
||||
if fs.access(CACHE_TEXT_FILE) then
|
||||
for line in io.lines(CACHE_TEXT_FILE) do
|
||||
cache_text = line
|
||||
end
|
||||
end
|
||||
|
||||
if cache_text ~= new_text then
|
||||
api.remove(CACHE_DNS_PATH .. "*")
|
||||
end
|
||||
|
||||
local dnsmasq_default_dns = TUN_DNS
|
||||
|
||||
local setflag_4= (NFTFLAG == "1") and "4#inet#passwall2#" or ""
|
||||
local setflag_6= (NFTFLAG == "1") and "6#inet#passwall2#" or ""
|
||||
|
||||
if not fs.access(CACHE_DNS_PATH) then
|
||||
fs.mkdir(CACHE_DNS_PATH)
|
||||
|
||||
local fwd_dns
|
||||
|
||||
-- Always use domestic DNS to resolve node domain names
|
||||
if true then
|
||||
fwd_dns = LOCAL_DNS
|
||||
uci:foreach(appname, "nodes", function(t)
|
||||
local function process_address(address)
|
||||
address = (address or ""):lower()
|
||||
if address == "engage.cloudflareclient.com" then return end
|
||||
if datatypes.hostname(address) then
|
||||
set_domain_dns(address, fwd_dns)
|
||||
set_domain_ipset(address, setflag_4 .. "psw2_vps," .. setflag_6 .. "psw2_vps6")
|
||||
end
|
||||
end
|
||||
process_address(t.address)
|
||||
process_address(t.download_address)
|
||||
end)
|
||||
end
|
||||
|
||||
if list1 and next(list1) then
|
||||
local server_out = io.open(CACHE_DNS_PATH .. "/001-server.conf", "a")
|
||||
local ipset_out = io.open(CACHE_DNS_PATH .. "/ipset.conf", "a")
|
||||
local set_name = "ipset"
|
||||
if NFTFLAG == "1" then
|
||||
set_name = "nftset"
|
||||
end
|
||||
for key, value in pairs(list1) do
|
||||
if value.dns and #value.dns > 0 then
|
||||
for i, dns in ipairs(value.dns) do
|
||||
server_out:write(string.format("server=/.%s/%s", key, dns) .. "\n")
|
||||
end
|
||||
end
|
||||
if value.ipsets and #value.ipsets > 0 then
|
||||
local ipsets_str = ""
|
||||
for i, ipset in ipairs(value.ipsets) do
|
||||
ipsets_str = ipsets_str .. ipset .. ","
|
||||
end
|
||||
ipsets_str = ipsets_str:sub(1, #ipsets_str - 1)
|
||||
ipset_out:write(string.format("%s=/.%s/%s", set_name, key, ipsets_str) .. "\n")
|
||||
end
|
||||
end
|
||||
server_out:close()
|
||||
ipset_out:close()
|
||||
end
|
||||
|
||||
local f_out = io.open(CACHE_TEXT_FILE, "a")
|
||||
f_out:write(new_text)
|
||||
f_out:close()
|
||||
end
|
||||
|
||||
api.remove(TMP_DNSMASQ_PATH)
|
||||
fs.symlink(CACHE_DNS_PATH, TMP_DNSMASQ_PATH)
|
||||
|
||||
if DNSMASQ_CONF_FILE ~= "nil" then
|
||||
local conf_lines = {}
|
||||
if LISTEN_PORT then
|
||||
--Copy dnsmasq instance
|
||||
conf_lines = copy_instance({
|
||||
["LISTEN_PORT"] = LISTEN_PORT,
|
||||
["TMP_DNSMASQ_PATH"] = TMP_DNSMASQ_PATH,
|
||||
["return"] = "1"
|
||||
})
|
||||
--dhcp.leases to hostsMore actions
|
||||
local hosts = "/tmp/etc/" .. appname .. "_tmp/dhcp-hosts"
|
||||
sys.call("touch " .. hosts)
|
||||
tinsert(conf_lines, "addn-hosts=" .. hosts)
|
||||
else
|
||||
--Modify the default dnsmasq service
|
||||
end
|
||||
tinsert(conf_lines, string.format("conf-dir=%s", TMP_DNSMASQ_PATH))
|
||||
if dnsmasq_default_dns then
|
||||
for s in string.gmatch(dnsmasq_default_dns, '[^' .. "," .. ']+') do
|
||||
tinsert(conf_lines, string.format("server=%s", s))
|
||||
end
|
||||
tinsert(conf_lines, "all-servers")
|
||||
tinsert(conf_lines, "no-poll")
|
||||
tinsert(conf_lines, "no-resolv")
|
||||
|
||||
if FLAG == "default" then
|
||||
api.set_cache_var("DEFAULT_DNS", DEFAULT_DNS)
|
||||
end
|
||||
end
|
||||
if #conf_lines > 0 then
|
||||
local conf_out = io.open(DNSMASQ_CONF_FILE, "a")
|
||||
conf_out:write(table.concat(conf_lines, "\n"))
|
||||
conf_out:write("\n")
|
||||
conf_out:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
_G.stretch = stretch
|
||||
_G.restart = restart
|
||||
_G.logic_restart = logic_restart
|
||||
_G.copy_instance = copy_instance
|
||||
_G.add_rule = add_rule
|
||||
|
||||
if arg[1] then
|
||||
local func =_G[arg[1]]
|
||||
if func then
|
||||
local var = nil
|
||||
if arg[2] then
|
||||
var = jsonc.parse(arg[2])
|
||||
end
|
||||
func(var)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
if #arg > 0 then
|
||||
local api = require "luci.passwall2.api"
|
||||
local str = arg[1]
|
||||
table.remove(arg, 1)
|
||||
print(api.i18n.translatef(str, unpack(arg)))
|
||||
end
|
||||
+1113
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,50 @@
|
||||
#!/bin/sh
|
||||
# dhcp.leases to hosts
|
||||
|
||||
. /usr/share/passwall2/utils.sh
|
||||
LOCK_FILE=${LOCK_PATH}/${CONFIG}_lease2hosts.lock
|
||||
LEASE_FILE="/tmp/dhcp.leases"
|
||||
HOSTS_FILE="$TMP_PATH2/dhcp-hosts"
|
||||
TMP_FILE="/tmp/dhcp-hosts.tmp"
|
||||
|
||||
exec 99>"$LOCK_FILE"
|
||||
flock -n 99
|
||||
if [ "$?" != 0 ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
reload_dnsmasq_pids() {
|
||||
local pidfile pid
|
||||
find $TMP_PATH/acl -type f -name 'dnsmasq.pid' 2>/dev/null | while read pidfile; do
|
||||
if [ -s "$pidfile" ]; then
|
||||
read pid < "$pidfile"
|
||||
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
||||
kill -HUP "$pid"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
while true; do
|
||||
|
||||
if [ -f "$LEASE_FILE" ]; then
|
||||
awk 'NF >= 4 && $4 != "*" {print $3" "$4}' "$LEASE_FILE" | sort > "$TMP_FILE"
|
||||
if [ -s "$TMP_FILE" ]; then
|
||||
if [ ! -f "$HOSTS_FILE" ] || ! cmp -s "$TMP_FILE" "$HOSTS_FILE"; then
|
||||
mv "$TMP_FILE" "$HOSTS_FILE"
|
||||
reload_dnsmasq_pids
|
||||
else
|
||||
rm -f "$TMP_FILE"
|
||||
fi
|
||||
else
|
||||
if [ -s "$HOSTS_FILE" ]; then
|
||||
: > "$HOSTS_FILE"
|
||||
reload_dnsmasq_pids
|
||||
fi
|
||||
rm -f "$TMP_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
sleep 60
|
||||
|
||||
done 2>/dev/null
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /usr/share/passwall2/utils.sh
|
||||
LOCK_FILE=${LOCK_PATH}/${CONFIG}_monitor.lock
|
||||
|
||||
ENABLED=$(config_t_get global enabled 0)
|
||||
[ "$ENABLED" != 1 ] && return 1
|
||||
ENABLED=$(config_t_get global_delay start_daemon 0)
|
||||
[ "$ENABLED" != 1 ] && return 1
|
||||
sleep 58s
|
||||
while [ "$ENABLED" -eq 1 ]; do
|
||||
[ -f "$LOCK_FILE" ] && {
|
||||
sleep 6s
|
||||
continue
|
||||
}
|
||||
touch $LOCK_FILE
|
||||
[ -d ${TMP_SCRIPT_FUNC_PATH} ] && {
|
||||
for filename in $(ls ${TMP_SCRIPT_FUNC_PATH} | grep -v "^_"); do
|
||||
cmd=$(cat ${TMP_SCRIPT_FUNC_PATH}/${filename})
|
||||
cmd_check=$(echo $cmd | awk -F '>' '{print $1}')
|
||||
icount=$(busybox pgrep -f "$(echo $cmd_check)" | wc -l)
|
||||
if [ $icount = 0 ]; then
|
||||
#echo "${cmd} crashed, restarting." >> /tmp/log/passwall2.log
|
||||
eval $(echo "nohup ${cmd} 2>&1 &") >/dev/null 2>&1 &
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
rm -f $LOCK_FILE
|
||||
sleep 58s
|
||||
done
|
||||
+1130
File diff suppressed because it is too large.
Load diff
+253
@@ -0,0 +1,253 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
local api = require "luci.passwall2.api"
|
||||
local name = api.appname
|
||||
local fs = api.fs
|
||||
local log = api.log
|
||||
local sys = api.sys
|
||||
local uci = api.uci
|
||||
local jsonc = api.jsonc
|
||||
|
||||
local arg1 = arg[1]
|
||||
local arg2 = arg[2]
|
||||
local arg3 = arg[3]
|
||||
|
||||
local reboot = 0
|
||||
local geoip_update = "0"
|
||||
local geosite_update = "0"
|
||||
|
||||
local geoip_url = uci:get(name, "@global_rules[0]", "geoip_url") or "https://github.com/Loyalsoldier/geoip/releases/latest/download/geoip.dat"
|
||||
local geosite_url = uci:get(name, "@global_rules[0]", "geosite_url") or "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat"
|
||||
local asset_location = uci:get(name, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"
|
||||
asset_location = asset_location:match("/$") and asset_location or (asset_location .. "/")
|
||||
local backup_path = "/tmp/bak_v2ray/"
|
||||
|
||||
if arg3 == "cron" then
|
||||
arg2 = nil
|
||||
end
|
||||
|
||||
-- curl
|
||||
local function curl(url, file)
|
||||
local http_code = 0
|
||||
local header_str = ""
|
||||
local args = {
|
||||
"-skL",
|
||||
"--retry 3",
|
||||
"--connect-timeout 3",
|
||||
"--max-time 300",
|
||||
"--speed-limit 51200 --speed-time 15",
|
||||
'-A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36"',
|
||||
"--dump-header -",
|
||||
"-w '\\n%{http_code}'"
|
||||
}
|
||||
if file then
|
||||
args[#args + 1] = "-o " .. file
|
||||
end
|
||||
local return_code, result = api.curl_auto(url, nil, args)
|
||||
if result and result ~= "" then
|
||||
local body, code = result:match("^(.-)%s*([0-9]+)$")
|
||||
if code then
|
||||
http_code = tonumber(code) or 0
|
||||
header_str = body
|
||||
else
|
||||
http_code = tonumber(result:match("(%d+)%s*$")) or 0
|
||||
end
|
||||
end
|
||||
if header_str ~= "" then
|
||||
header_str = header_str:gsub("\r", "")
|
||||
end
|
||||
return http_code, header_str
|
||||
end
|
||||
|
||||
local function non_file_check(file_path, header_content)
|
||||
local remote_file_size = nil
|
||||
local local_file_size = tonumber(fs.stat(file_path, "size") or 0)
|
||||
if local_file_size == 0 then
|
||||
log(2, api.i18n.translate("Downloaded file is empty or an error occurred while reading it."))
|
||||
return true
|
||||
end
|
||||
if header_content and header_content ~= "" then
|
||||
for size in header_content:gmatch("[Cc]ontent%-[Ll]ength:%s*(%d+)") do
|
||||
local s = tonumber(size)
|
||||
if s and s > 0 then
|
||||
remote_file_size = s
|
||||
end
|
||||
end
|
||||
end
|
||||
if remote_file_size and remote_file_size ~= local_file_size then
|
||||
log(2, api.i18n.translatef("Download file size verification error. Original file size: %sB. Downloaded file size: %sB.", remote_file_size, local_file_size))
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function fetch_geofile(geo_name, geo_type, url)
|
||||
local tmp_path = "/tmp/" .. geo_name
|
||||
local asset_path = asset_location .. geo_name
|
||||
local down_filename = url:match("^.*/([^/?#]+)")
|
||||
local sha_url = url:gsub(down_filename, down_filename .. ".sha256sum")
|
||||
local sha_path = tmp_path .. ".sha256sum"
|
||||
|
||||
local function verify_sha256(sha_file)
|
||||
return sys.call("sha256sum -c " .. sha_file .. " > /dev/null 2>&1") == 0
|
||||
end
|
||||
|
||||
local sha_verify, _ = curl(sha_url, sha_path) == 200
|
||||
if sha_verify then
|
||||
local f = io.open(sha_path, "r")
|
||||
if f then
|
||||
local content = f:read("*l")
|
||||
f:close()
|
||||
if content then
|
||||
content = content:gsub("(%x+)%s+.+", "%1 " .. tmp_path)
|
||||
f = io.open(sha_path, "w")
|
||||
if f then
|
||||
f:write(content)
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
if fs.access(asset_path) then
|
||||
sys.call(string.format("cp -f %s %s", asset_path, tmp_path))
|
||||
if verify_sha256(sha_path) then
|
||||
log(1, api.i18n.translatef("%s version is the same and does not need to be updated.", geo_type))
|
||||
return 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local sret_tmp, header = curl(url, tmp_path)
|
||||
if sret_tmp == 200 and non_file_check(tmp_path, header) then
|
||||
log(1, api.i18n.translatef("%s an error occurred during the file download process. Please try downloading again.", geo_type))
|
||||
os.remove(tmp_path)
|
||||
sret_tmp, header = curl(url, tmp_path)
|
||||
if sret_tmp == 200 and non_file_check(tmp_path, header) then
|
||||
sret_tmp = 0
|
||||
log(1, api.i18n.translatef("%s an error occurred while downloading the file. Please check your network or the download link and try again!", geo_type))
|
||||
end
|
||||
end
|
||||
if sret_tmp == 200 then
|
||||
if sha_verify then
|
||||
if verify_sha256(sha_path) then
|
||||
sys.call(string.format("mkdir -p %s && mv -f %s %s", backup_path, asset_path, backup_path))
|
||||
sys.call(string.format("mkdir -p %s && mv -f %s %s", asset_location, tmp_path, asset_path))
|
||||
reboot = 1
|
||||
log(1, api.i18n.translatef("%s update success.", geo_type))
|
||||
else
|
||||
log(1, api.i18n.translatef("%s update failed, please try again later.", geo_type))
|
||||
return 1
|
||||
end
|
||||
else
|
||||
if fs.access(asset_path) and sys.call(string.format("cmp -s %s %s", tmp_path, asset_path)) == 0 then
|
||||
log(1, api.i18n.translatef("%s version is the same and does not need to be updated.", geo_type))
|
||||
return 0
|
||||
end
|
||||
sys.call(string.format("mkdir -p %s && mv -f %s %s", backup_path, asset_path, backup_path))
|
||||
sys.call(string.format("mkdir -p %s && mv -f %s %s", asset_location, tmp_path, asset_path))
|
||||
reboot = 1
|
||||
log(1, api.i18n.translatef("%s update success.", geo_type))
|
||||
end
|
||||
else
|
||||
log(1, api.i18n.translatef("%s update failed, please try again later.", geo_type))
|
||||
return 1
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
local function fetch_geoip()
|
||||
fetch_geofile("geoip.dat", "geoip", geoip_url)
|
||||
end
|
||||
|
||||
local function fetch_geosite()
|
||||
fetch_geofile("geosite.dat", "geosite", geosite_url)
|
||||
end
|
||||
|
||||
local function remove_tmp_geofile(name)
|
||||
os.remove("/tmp/" .. name .. ".dat")
|
||||
os.remove("/tmp/" .. name .. ".dat.sha256sum")
|
||||
end
|
||||
|
||||
if arg2 then
|
||||
string.gsub(arg2, '[^' .. "," .. ']+', function(w)
|
||||
if w == "geoip" then
|
||||
geoip_update = "1"
|
||||
end
|
||||
if w == "geosite" then
|
||||
geosite_update = "1"
|
||||
end
|
||||
end)
|
||||
else
|
||||
geoip_update = uci:get(name, "@global_rules[0]", "geoip_update") or "1"
|
||||
geosite_update = uci:get(name, "@global_rules[0]", "geosite_update") or "1"
|
||||
end
|
||||
if geoip_update == "0" and geosite_update == "0" then
|
||||
os.exit(0)
|
||||
end
|
||||
|
||||
local function check_instance(action)
|
||||
local rule_lock = "/var/lock/" .. name .. "_rule_update.lock"
|
||||
local sub_lock = "/var/lock/" .. name .. "_subscribe.lock"
|
||||
|
||||
if action == "start" then
|
||||
math.randomseed(os.time() + math.floor(os.clock() * 1000))
|
||||
api.nixio.nanosleep(0, math.random(100, 1000) * 1000000)
|
||||
if fs.access(rule_lock) then
|
||||
log(0, api.i18n.translatef("[Rule update] instance is running; please try again later.") .. "\n")
|
||||
os.exit(0)
|
||||
else
|
||||
luci.sys.call("touch " .. rule_lock)
|
||||
end
|
||||
elseif action == "end" then
|
||||
luci.sys.call("rm -f " .. rule_lock)
|
||||
return
|
||||
end
|
||||
|
||||
if fs.access(sub_lock) then
|
||||
log(0, api.i18n.translatef("[Subscription] instance is running; [Rule Update] queue and wait.") .. "\n")
|
||||
end
|
||||
while fs.access(sub_lock) do
|
||||
api.nixio.nanosleep(2, 0)
|
||||
end
|
||||
end
|
||||
|
||||
check_instance("start")
|
||||
|
||||
log(0, api.i18n.translate("Start updating the rules..."))
|
||||
local function safe_call(func, err_msg)
|
||||
xpcall(func, function(e)
|
||||
log(1, e)
|
||||
log(1, debug.traceback())
|
||||
log(1, err_msg)
|
||||
end)
|
||||
end
|
||||
|
||||
if geoip_update == "1" then
|
||||
log(1, api.i18n.translatef("%s Start updating...", "geoip"))
|
||||
safe_call(fetch_geoip, api.i18n.translatef("%s update error!", "geoip"))
|
||||
remove_tmp_geofile("geoip")
|
||||
end
|
||||
|
||||
if geosite_update == "1" then
|
||||
log(1, api.i18n.translatef("%s Start updating...", "geosite"))
|
||||
safe_call(fetch_geosite, api.i18n.translatef("%s update error!", "geosite"))
|
||||
remove_tmp_geofile("geosite")
|
||||
end
|
||||
|
||||
uci:set(name, "@global_rules[0]", "geoip_update", geoip_update)
|
||||
uci:set(name, "@global_rules[0]", "geosite_update", geosite_update)
|
||||
api.uci_save(uci, name, true)
|
||||
|
||||
if reboot == 1 then
|
||||
if arg3 == "cron" then
|
||||
if not fs.access("/var/lock/" .. name .. ".lock") then
|
||||
sys.call("touch /tmp/lock/" .. name .. "_cron.lock")
|
||||
end
|
||||
end
|
||||
|
||||
log(1, api.i18n.translate("Restart the service and apply the new rules."))
|
||||
uci:set(name, "@global[0]", "flush_set", "1")
|
||||
api.uci_save(uci, name, true, true)
|
||||
end
|
||||
log(0, api.i18n.translate("The rules have been updated..."))
|
||||
|
||||
check_instance("end")
|
||||
@@ -0,0 +1,191 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /usr/share/passwall2/utils.sh
|
||||
APP_FILE=${APP_PATH}/app.sh
|
||||
|
||||
flag=0
|
||||
|
||||
check_process() {
|
||||
while busybox pgrep -af "${CONFIG}/" | grep -E 'app\.sh.*(start|stop)|nftables\.sh|iptables\.sh|subscribe\.lua' >/dev/null; do
|
||||
sleep 6s
|
||||
done
|
||||
}
|
||||
|
||||
test_url() {
|
||||
local url=$1
|
||||
local try=1
|
||||
[ -n "$2" ] && try=$2
|
||||
local timeout=2
|
||||
[ -n "$3" ] && timeout=$3
|
||||
local extra_params=$4
|
||||
if /usr/bin/curl --help all | grep -q "\-\-retry-all-errors"; then
|
||||
extra_params="--retry-all-errors ${extra_params}"
|
||||
fi
|
||||
local status=$(/usr/bin/curl -I -o /dev/null -skL ${extra_params} --connect-timeout ${timeout} --retry ${try} -w %{http_code} "$url")
|
||||
case "$status" in
|
||||
204)
|
||||
status=200
|
||||
;;
|
||||
esac
|
||||
echo $status
|
||||
}
|
||||
|
||||
test_proxy() {
|
||||
local result=0
|
||||
local status=$(test_url "${probe_url}" ${retry_num} ${connect_timeout} "-x socks5h://127.0.0.1:${socks_port}")
|
||||
if [ "$status" = "200" ]; then
|
||||
result=0
|
||||
else
|
||||
local status2=$(test_url "https://www.baidu.com" ${retry_num} ${connect_timeout})
|
||||
if [ "$status2" = "200" ]; then
|
||||
result=1
|
||||
else
|
||||
result=2
|
||||
ping -c 3 -W 1 223.5.5.5 > /dev/null 2>&1
|
||||
[ $? -eq 0 ] && {
|
||||
result=1
|
||||
}
|
||||
fi
|
||||
fi
|
||||
echo $result
|
||||
}
|
||||
|
||||
test_node() {
|
||||
local node_id=$1
|
||||
local _type=$(echo $(config_n_get ${node_id} type) | tr 'A-Z' 'a-z')
|
||||
[ -n "${_type}" ] && {
|
||||
check_process
|
||||
local _tmp_port=$(get_new_port 48800 tcp,udp)
|
||||
NO_REC_PROCESS=1 $APP_FILE run_socks flag="test_node_${node_id}" node=${node_id} bind=127.0.0.1 socks_port=${_tmp_port} config_file=test_node_${node_id}.json
|
||||
sleep 2s
|
||||
local curlx="socks5h://127.0.0.1:${_tmp_port}"
|
||||
local _proxy_status=$(test_url "${probe_url}" ${retry_num} ${connect_timeout} "-x $curlx")
|
||||
# Kill the SS plugin process
|
||||
local pid_file="/tmp/etc/${CONFIG}/test_node_${node_id}_plugin.pid"
|
||||
[ -s "$pid_file" ] && kill -9 "$(head -n 1 "$pid_file")" >/dev/null 2>&1
|
||||
busybox pgrep -af "test_node_${node_id}" | awk '! /socks_auto_switch\.sh/{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
rm -rf /tmp/etc/${CONFIG}/test_node_${node_id}*.*
|
||||
if [ "${_proxy_status}" -eq 200 ]; then
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
test_auto_switch() {
|
||||
flag=$((flag + 1))
|
||||
local b_nodes=$1
|
||||
local now_node=$2
|
||||
[ -z "$now_node" ] && {
|
||||
if [ -n "$(get_cache_var "socks_${id}")" ]; then
|
||||
now_node=$(get_cache_var "socks_${id}")
|
||||
else
|
||||
#log_i18n 0 "Socks switch detection: Unknown error."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
[ $flag -le 1 ] && {
|
||||
main_node=$now_node
|
||||
}
|
||||
|
||||
local status=$(test_proxy)
|
||||
if [ "$status" = "2" ]; then
|
||||
log_i18n 0 "Socks switch detection: Unable to connect to the network. Please check if the network is working properly!"
|
||||
return 2
|
||||
fi
|
||||
|
||||
# Check if the main node is usable
|
||||
if [ "$restore_switch" = "1" ] && [ -n "$main_node" ] && [ "$now_node" != "$main_node" ]; then
|
||||
test_node ${main_node}
|
||||
[ $? -eq 0 ] && {
|
||||
check_process
|
||||
# The main node is working properly; switch to the main node.
|
||||
log_i18n 0 "Socks switch detection: Primary node 【%s: [%s]】 is normal. Switch to the primary node!" "${id}" "$(config_n_get $main_node type)" "$(config_n_get $main_node remarks)"
|
||||
$APP_FILE socks_node_switch flag=${id} new_node=${main_node}
|
||||
[ $? -eq 0 ] && {
|
||||
log_i18n 0 "Socks switch detection: %s node switch complete!" "${id}"
|
||||
}
|
||||
return 0
|
||||
}
|
||||
fi
|
||||
|
||||
if [ "$status" = "0" ]; then
|
||||
#log_i18n 0 "Socks switch detection: %s 【%s:[%s]】 normal." "${id}" "$(config_n_get $now_node type)" "$(config_n_get $now_node remarks)"
|
||||
return 0
|
||||
elif [ "$status" = "1" ]; then
|
||||
local new_node msg
|
||||
if [ "$backup_node_num" -gt 1 ]; then
|
||||
# When there are multiple backup nodes
|
||||
local first_node found node
|
||||
for node in $b_nodes; do
|
||||
[ -z "$first_node" ] && first_node="$node" # Record the first node.
|
||||
[ "$found" = "1" ] && { new_node="$node"; break; } # Find the current node and then retrieve the next one.
|
||||
[ "$node" = "$now_node" ] && found=1 # Mark the current node found.
|
||||
done
|
||||
# If the current node is not found, or if the current node is the last node, then take the first node.
|
||||
[ -z "$new_node" ] && new_node="$first_node"
|
||||
local msg2="$(i18n "next backup node")"
|
||||
[ "$now_node" = "$main_node" ] && msg2="$(i18n "backup node")"
|
||||
msg="$(i18n "switch to %s test detect!" "${msg2}")"
|
||||
else
|
||||
# When there is only one backup node, poll with the primary node.
|
||||
new_node=$([ "$now_node" = "$main_node" ] && echo "$b_nodes" || echo "$main_node")
|
||||
local msg2="$(i18n "main node")"
|
||||
[ "$now_node" = "$main_node" ] && msg2="$(i18n "backup node")"
|
||||
msg="$(i18n "switch to %s test detect!" "${msg2}")"
|
||||
fi
|
||||
log_i18n 0 "Socks switch detection: %s 【%s:[%s]】 abnormal, %s" "${id}" "$(config_n_get $now_node type)" "$(config_n_get $now_node remarks)" "${msg}"
|
||||
test_node ${new_node}
|
||||
if [ $? -eq 0 ]; then
|
||||
# [ "$restore_switch" = "0" ] && {
|
||||
# uci set $CONFIG.${id}.node=$new_node
|
||||
# [ -z "$(echo $b_nodes | grep $main_node)" ] && uci add_list $CONFIG.${id}.autoswitch_backup_node=$main_node
|
||||
# uci commit $CONFIG
|
||||
# }
|
||||
check_process
|
||||
log_i18n 0 "Socks switch detection: %s 【%s:[%s]】 normal, switch to this node!" "${id}" "$(config_n_get $new_node type)" "$(config_n_get $new_node remarks)"
|
||||
$APP_FILE socks_node_switch flag=${id} new_node=${new_node}
|
||||
[ $? -eq 0 ] && {
|
||||
log_i18n 0 "Socks switch detection: %s node switch complete!" "${id}"
|
||||
}
|
||||
return 0
|
||||
else
|
||||
test_auto_switch "${b_nodes}" ${new_node}
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
start() {
|
||||
id=$1
|
||||
LOCK_FILE=${LOCK_PATH}/${CONFIG}_socks_auto_switch_${id}.lock
|
||||
main_node=$(config_n_get $id node)
|
||||
socks_port=$(config_n_get $id port 0)
|
||||
delay=$(config_n_get $id autoswitch_testing_time 30)
|
||||
connect_timeout=$(config_n_get $id autoswitch_connect_timeout 3)
|
||||
retry_num=$(config_n_get $id autoswitch_retry_num 1)
|
||||
restore_switch=$(config_n_get $id autoswitch_restore_switch 0)
|
||||
probe_url=$(config_n_get $id autoswitch_probe_url "https://www.google.com/generate_204")
|
||||
backup_node=$(lua_api "get_socks_backup_nodes(\"${id}\")")
|
||||
if [ -n "$backup_node" ]; then
|
||||
backup_node_num=$(printf "%s\n" "$backup_node" | wc -w)
|
||||
if [ "$backup_node_num" -eq 1 ]; then
|
||||
[ "$main_node" = "$backup_node" ] && return
|
||||
fi
|
||||
else
|
||||
return
|
||||
fi
|
||||
while [ -n "$backup_node" ]; do
|
||||
[ -f "$LOCK_FILE" ] && {
|
||||
sleep 6s
|
||||
continue
|
||||
}
|
||||
check_process
|
||||
touch $LOCK_FILE
|
||||
test_auto_switch "$backup_node"
|
||||
rm -f $LOCK_FILE
|
||||
sleep ${delay}
|
||||
done
|
||||
}
|
||||
|
||||
start $@
|
||||
+2589
File diff suppressed because it is too large.
Load diff
+70
@@ -0,0 +1,70 @@
|
||||
#!/bin/sh
|
||||
## Loop update script
|
||||
|
||||
. /usr/share/passwall2/utils.sh
|
||||
LOCK_FILE=${LOCK_PATH}/${CONFIG}_tasks.lock
|
||||
|
||||
CFG_UPDATE_INT=0
|
||||
|
||||
exec 99>"$LOCK_FILE"
|
||||
flock -n 99
|
||||
if [ "$?" != 0 ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
while true
|
||||
do
|
||||
|
||||
if [ "$CFG_UPDATE_INT" -ne 0 ]; then
|
||||
|
||||
restart_week_mode=$(config_t_get global_delay restart_week_mode)
|
||||
restart_interval_mode=$(config_t_get global_delay restart_interval_mode)
|
||||
restart_interval_mode=$(expr "$restart_interval_mode" \* 60)
|
||||
if [ -n "$restart_week_mode" ]; then
|
||||
[ "$restart_week_mode" = "8" ] && {
|
||||
[ "$(expr "$CFG_UPDATE_INT" % "$restart_interval_mode")" -eq 0 ] && { /etc/init.d/$CONFIG restart > /dev/null 2>&1 & }
|
||||
}
|
||||
fi
|
||||
|
||||
rules_update_week_mode=$(config_t_get global_rules update_week_mode)
|
||||
rules_update_interval_mode=$(config_t_get global_rules update_interval_mode)
|
||||
rules_update_interval_mode=$(expr "$rules_update_interval_mode" \* 60)
|
||||
if [ -n "$rules_update_week_mode" ]; then
|
||||
[ "$rules_update_week_mode" = "8" ] && {
|
||||
[ "$(expr "$CFG_UPDATE_INT" % "$rules_update_interval_mode")" -eq 0 ] && { lua $APP_PATH/rule_update.lua log all cron > /dev/null 2>&1 & }
|
||||
}
|
||||
fi
|
||||
|
||||
TMP_SUB_PATH=$TMP_PATH/sub_tasks
|
||||
mkdir -p $TMP_SUB_PATH
|
||||
for item in $(uci show ${CONFIG} | grep "=subscribe_list" | cut -d '.' -sf 2 | cut -d '=' -sf 1); do
|
||||
sub_update_week_mode=$(config_n_get $item update_week_mode)
|
||||
if [ -n "$sub_update_week_mode" ]; then
|
||||
cfgid=$(uci show ${CONFIG}.$item | head -n 1 | cut -d '.' -sf 2 | cut -d '=' -sf 1)
|
||||
remark=$(config_n_get $item remark)
|
||||
sub_update_interval_mode=$(config_n_get $item update_interval_mode)
|
||||
echo "$cfgid" >> $TMP_SUB_PATH/${sub_update_week_mode}_${sub_update_interval_mode}
|
||||
fi
|
||||
done
|
||||
|
||||
[ -d "${TMP_SUB_PATH}" ] && {
|
||||
for name in $(ls ${TMP_SUB_PATH}); do
|
||||
sub_update_week_mode=$(echo $name | awk -F '_' '{print $1}')
|
||||
sub_update_interval_mode=$(echo $name | awk -F '_' '{print $2}')
|
||||
sub_update_interval_mode=$(expr "$sub_update_interval_mode" \* 60)
|
||||
cfgids=$(echo -n $(cat ${TMP_SUB_PATH}/${name}) | sed 's# #,#g')
|
||||
[ "$sub_update_week_mode" = "8" ] && {
|
||||
[ "$(expr "$CFG_UPDATE_INT" % "$sub_update_interval_mode")" -eq 0 ] && { lua $APP_PATH/subscribe.lua start $cfgids cron > /dev/null 2>&1 & }
|
||||
}
|
||||
|
||||
done
|
||||
rm -rf $TMP_SUB_PATH
|
||||
}
|
||||
|
||||
fi
|
||||
|
||||
CFG_UPDATE_INT=$(expr "$CFG_UPDATE_INT" + 10)
|
||||
|
||||
sleep 600
|
||||
|
||||
done 2>/dev/null
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /usr/share/passwall2/utils.sh
|
||||
|
||||
test_url() {
|
||||
local url=$1
|
||||
local try=1
|
||||
[ -n "$2" ] && try=$2
|
||||
local timeout=2
|
||||
[ -n "$3" ] && timeout=$3
|
||||
local extra_params=$4
|
||||
curl --help all | grep "\-\-retry-all-errors" > /dev/null
|
||||
[ $? == 0 ] && extra_params="--retry-all-errors ${extra_params}"
|
||||
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() {
|
||||
result=0
|
||||
status=$(test_url "https://www.google.com/generate_204" ${retry_num} ${connect_timeout})
|
||||
if [ "$status" = "200" ]; then
|
||||
result=0
|
||||
else
|
||||
status2=$(test_url "https://www.baidu.com" ${retry_num} ${connect_timeout})
|
||||
if [ "$status2" = "200" ]; then
|
||||
result=1
|
||||
else
|
||||
result=2
|
||||
ping -c 3 -W 1 223.5.5.5 > /dev/null 2>&1
|
||||
[ $? -eq 0 ] && {
|
||||
result=1
|
||||
}
|
||||
fi
|
||||
fi
|
||||
echo $result
|
||||
}
|
||||
|
||||
url_test_node() {
|
||||
result=0
|
||||
local node_id=$1
|
||||
local _type=$(echo $(config_n_get ${node_id} type) | tr 'A-Z' 'a-z')
|
||||
[ -n "${_type}" ] && {
|
||||
local _tmp_port=$(get_new_port 48900 tcp,udp)
|
||||
NO_REC_PROCESS=1 /usr/share/${CONFIG}/app.sh run_socks flag="url_test_${node_id}" node=${node_id} bind=127.0.0.1 socks_port=${_tmp_port} config_file=url_test_${node_id}.json
|
||||
sleep 2s
|
||||
local curlx="socks5h://127.0.0.1:${_tmp_port}"
|
||||
local probeUrl=$(config_t_get global_other url_test_url https://www.google.com/generate_204)
|
||||
result=$(curl --connect-timeout 3 --max-time 5 -o /dev/null -I -skL -w "%{http_code}:%{time_pretransfer}" -x ${curlx} "${probeUrl}")
|
||||
# End the SS plugin process
|
||||
local pid_file="/tmp/etc/${CONFIG}/url_test_${node_id}_plugin.pid"
|
||||
[ -s "$pid_file" ] && kill -9 "$(head -n 1 "$pid_file")" >/dev/null 2>&1
|
||||
busybox pgrep -af "url_test_${node_id}" | awk '! /test\.sh/{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
rm -rf /tmp/etc/${CONFIG}/*url_test_${node_id}*.*
|
||||
}
|
||||
echo $result
|
||||
}
|
||||
|
||||
arg1=$1
|
||||
shift
|
||||
case $arg1 in
|
||||
test_url)
|
||||
test_url $@
|
||||
;;
|
||||
url_test_node)
|
||||
url_test_node $@
|
||||
;;
|
||||
esac
|
||||
+485
@@ -0,0 +1,485 @@
|
||||
#!/bin/sh
|
||||
# Copyright (C) 2022-2025 xiaorouji
|
||||
# Copyright (C) 2026 Openwrt-Passwall Organization
|
||||
|
||||
CONFIG=passwall2
|
||||
APP_PATH=/usr/share/${CONFIG}
|
||||
TMP_PATH=/tmp/etc/${CONFIG}
|
||||
TMP_PATH2=${TMP_PATH}_tmp
|
||||
LOCK_PATH=/tmp/lock
|
||||
LOG_FILE=/tmp/log/${CONFIG}.log
|
||||
TMP_ACL_PATH=${TMP_PATH}/acl
|
||||
TMP_BIN_PATH=${TMP_PATH}/bin
|
||||
TMP_IFACE_PATH=${TMP_PATH}/iface
|
||||
TMP_ROUTE_PATH=${TMP_PATH}/route
|
||||
TMP_SCRIPT_FUNC_PATH=${TMP_PATH}/script_func
|
||||
TMP_PROCESS_LIST_PATH=${TMP_PATH}/process_list
|
||||
|
||||
. /lib/functions/network.sh
|
||||
|
||||
config_get_type() {
|
||||
local ret=$(uci -q get "${CONFIG}.${1}" 2>/dev/null)
|
||||
echo "${ret:=$2}"
|
||||
}
|
||||
|
||||
config_n_get() {
|
||||
local ret=$(uci -q get "${CONFIG}.${1}.${2}" 2>/dev/null)
|
||||
echo "${ret:=$3}"
|
||||
}
|
||||
|
||||
config_t_get() {
|
||||
local index=${4:-0}
|
||||
local ret=$(uci -q get "${CONFIG}.@${1}[${index}].${2}" 2>/dev/null)
|
||||
echo "${ret:=${3}}"
|
||||
}
|
||||
|
||||
config_t_set() {
|
||||
local index=${4:-0}
|
||||
local ret=$(uci -q set "${CONFIG}.@${1}[${index}].${2}=${3}" 2>/dev/null)
|
||||
}
|
||||
|
||||
eval_set_val() {
|
||||
for i in $@; do
|
||||
for j in $i; do
|
||||
eval $j
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
eval_unset_val() {
|
||||
for i in $@; do
|
||||
for j in $i; do
|
||||
eval unset $j
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
eval_cache_var() {
|
||||
[ -s "$TMP_PATH/var" ] && eval $(cat "$TMP_PATH/var")
|
||||
}
|
||||
|
||||
get_cache_var() {
|
||||
local key="${1}"
|
||||
[ -n "${key}" ] && [ -s "$TMP_PATH/var" ] && {
|
||||
echo $(cat $TMP_PATH/var | grep "^${key}=" | awk -F '=' '{print $2}' | tail -n 1 | awk -F'"' '{print $2}')
|
||||
}
|
||||
}
|
||||
|
||||
set_cache_var() {
|
||||
local key="${1}"
|
||||
shift 1
|
||||
local val="$@"
|
||||
[ -n "${key}" ] && [ -n "${val}" ] && {
|
||||
[ ! -d $TMP_PATH ] && mkdir -p $TMP_PATH
|
||||
sed -i "/${key}=/d" $TMP_PATH/var >/dev/null 2>&1
|
||||
echo "${key}=\"${val}\"" >> $TMP_PATH/var
|
||||
eval ${key}=\"${val}\"
|
||||
}
|
||||
}
|
||||
|
||||
echolog() {
|
||||
echo -e "$*" >>$LOG_FILE
|
||||
}
|
||||
|
||||
echolog_date() {
|
||||
local d="$(date "+%Y-%m-%d %H:%M:%S")"
|
||||
echolog "$d: $*"
|
||||
}
|
||||
|
||||
i18n() {
|
||||
echo "$(lua ${APP_PATH}/i18n.lua "$@")"
|
||||
}
|
||||
|
||||
log() {
|
||||
local num="$1"
|
||||
shift
|
||||
local content="$@"
|
||||
local indent=""
|
||||
if [ "$num" -ge 1 ]; then
|
||||
for i in $(seq 1 ${num}); do
|
||||
indent="${indent} "
|
||||
done
|
||||
echolog_date "${indent}- ${content}"
|
||||
else
|
||||
echolog_date "${content}"
|
||||
fi
|
||||
}
|
||||
|
||||
log_i18n() {
|
||||
local num="$1"
|
||||
shift
|
||||
log ${num} "$(i18n "$@")"
|
||||
}
|
||||
|
||||
clean_log() {
|
||||
logsnum=$(cat $LOG_FILE 2>/dev/null | wc -l)
|
||||
[ "$logsnum" -gt 1000 ] && {
|
||||
echo "" > $LOG_FILE
|
||||
log_i18n 0 "Log file is too long, clear it!"
|
||||
}
|
||||
}
|
||||
|
||||
lua_api() {
|
||||
local func=${1}
|
||||
[ -z "${func}" ] && {
|
||||
echo ""
|
||||
return
|
||||
}
|
||||
echo $(lua -e "local api = require 'luci.passwall2.api' print(api.${func})")
|
||||
}
|
||||
|
||||
check_host() {
|
||||
local f=${1}
|
||||
a=$(echo $f | grep "\/")
|
||||
[ -n "$a" ] && return 1
|
||||
# Determine if it contains Chinese characters.
|
||||
local tmp=$(echo -n $f | awk '{print gensub(/[!-~]/,"","g",$0)}')
|
||||
[ -n "$tmp" ] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
first_type() {
|
||||
[ "${1#/}" != "$1" ] && [ -x "$1" ] && echo "$1" && return
|
||||
for p in "/bin/$1" "/usr/bin/$1" "${TMP_BIN_PATH:-/tmp}/$1"; do
|
||||
[ -x "$p" ] && echo "$p" && return
|
||||
done
|
||||
command -v "$1" 2>/dev/null || command -v "$2" 2>/dev/null
|
||||
}
|
||||
|
||||
get_enabled_anonymous_secs() {
|
||||
uci -q show "${CONFIG}" | grep "${1}\[.*\.enabled='1'" | cut -d '.' -sf2
|
||||
}
|
||||
|
||||
get_geoip() {
|
||||
local geo_output_path="$TMP_PATH2/geo_output"
|
||||
mkdir -p ${geo_output_path}
|
||||
local geoip_code="$1"
|
||||
local geoip_type_flag=""
|
||||
local output_path="${geo_output_path}/geoip-${geoip_code}-$2"
|
||||
[ ! -s "${output_path}" ] && {
|
||||
local geoip_path="$(config_t_get global_rules v2ray_location_asset)"
|
||||
geoip_path="${geoip_path%*/}/geoip.dat"
|
||||
local bin="$(first_type $(config_t_get global_app geoview_file) geoview)"
|
||||
[ -n "$bin" ] && [ -s "$geoip_path" ] || { echo ""; return; }
|
||||
case "$2" in
|
||||
"ipv4") geoip_type_flag="-ipv6=false" ;;
|
||||
"ipv6") geoip_type_flag="-ipv4=false" ;;
|
||||
esac
|
||||
"$bin" -input "$geoip_path" -list "$geoip_code" $geoip_type_flag -lowmem=true -output ${output_path}
|
||||
}
|
||||
[ -s "${output_path}" ] && cat "${output_path}"
|
||||
}
|
||||
|
||||
get_host_ip() {
|
||||
local host=$2
|
||||
local count=$3
|
||||
[ -z "$count" ] && count=3
|
||||
local isip=""
|
||||
local ip=""
|
||||
if [ "$1" == "ipv6" ]; then
|
||||
isip=$(echo $host | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}")
|
||||
if [ -n "$isip" ]; then
|
||||
ip=$(echo "$host" | tr -d '[]')
|
||||
fi
|
||||
else
|
||||
isip=$(echo $host | grep -E "([0-9]{1,3}[\.]){3}[0-9]{1,3}")
|
||||
[ -n "$isip" ] && ip=$isip
|
||||
fi
|
||||
[ -z "$isip" ] && {
|
||||
local t=4
|
||||
[ "$1" == "ipv6" ] && t=6
|
||||
local vpsrip=$(resolveip -$t -t $count $host | awk 'NR==1{print}')
|
||||
ip=$vpsrip
|
||||
}
|
||||
[ -n "$ip" ] && echo "$ip"
|
||||
}
|
||||
|
||||
get_node_host_ip() {
|
||||
local ip
|
||||
local address=$(config_n_get $1 address)
|
||||
[ -n "$address" ] && {
|
||||
local use_ipv6=$(config_n_get $1 use_ipv6)
|
||||
local network_type="ipv4"
|
||||
[ "$use_ipv6" == "1" ] && network_type="ipv6"
|
||||
ip=$(get_host_ip $network_type $address)
|
||||
}
|
||||
echo $ip
|
||||
}
|
||||
|
||||
get_ip_port_from() {
|
||||
local __host=${1}; shift 1
|
||||
local __ipv=${1}; shift 1
|
||||
local __portv=${1}; shift 1
|
||||
local __ucipriority=${1}; shift 1
|
||||
|
||||
local val1 val2
|
||||
if [ -n "${__ucipriority}" ]; then
|
||||
val2=$(config_n_get ${__host} port $(echo $__host | sed -n 's/^.*[:#]\([0-9]*\)$/\1/p'))
|
||||
val1=$(config_n_get ${__host} address "${__host%%${val2:+[:#]${val2}*}}")
|
||||
else
|
||||
val2=$(echo $__host | sed -n 's/^.*[:#]\([0-9]*\)$/\1/p')
|
||||
val1="${__host%%${val2:+[:#]${val2}*}}"
|
||||
fi
|
||||
eval "${__ipv}=\"$val1\"; ${__portv}=\"$val2\""
|
||||
}
|
||||
|
||||
host_from_url(){
|
||||
local f=${1}
|
||||
|
||||
## Remove protocol part of url ##
|
||||
f="${f##http://}"
|
||||
f="${f##https://}"
|
||||
f="${f##ftp://}"
|
||||
f="${f##sftp://}"
|
||||
|
||||
## Remove username and/or username:password part of URL ##
|
||||
f="${f##*:*@}"
|
||||
f="${f##*@}"
|
||||
|
||||
## Remove rest of urls ##
|
||||
f="${f%%/*}"
|
||||
echo "${f%%:*}"
|
||||
}
|
||||
|
||||
hosts_foreach() {
|
||||
local __hosts
|
||||
eval "__hosts=\$${1}"; shift 1
|
||||
local __func=${1}; shift 1
|
||||
local __default_port=${1}; shift 1
|
||||
local __ret=1
|
||||
|
||||
[ -z "${__hosts}" ] && return 0
|
||||
local __ip __port
|
||||
for __host in $(echo $__hosts | sed 's/[ ,]/\n/g'); do
|
||||
get_ip_port_from "$__host" "__ip" "__port"
|
||||
eval "$__func \"${__host}\" \"\${__ip}\" \"\${__port:-${__default_port}}\" \"$@\""
|
||||
__ret=$?
|
||||
[ ${__ret} -ge ${ERROR_NO_CATCH:-1} ] && return ${__ret}
|
||||
done
|
||||
}
|
||||
|
||||
get_first_dns() {
|
||||
local __hosts_val=${1}; shift 1
|
||||
__first() {
|
||||
[ -z "${2}" ] && return 0
|
||||
echo "${2}#${3}"
|
||||
return 1
|
||||
}
|
||||
eval "hosts_foreach \"${__hosts_val}\" __first \"$@\""
|
||||
}
|
||||
|
||||
get_last_dns() {
|
||||
local __hosts_val=${1}; shift 1
|
||||
local __first __last
|
||||
__every() {
|
||||
[ -z "${2}" ] && return 0
|
||||
__last="${2}#${3}"
|
||||
__first=${__first:-${__last}}
|
||||
}
|
||||
eval "hosts_foreach \"${__hosts_val}\" __every \"$@\""
|
||||
[ "${__first}" == "${__last}" ] || echo "${__last}"
|
||||
}
|
||||
|
||||
check_port_exists() {
|
||||
local port=$1
|
||||
local protocol=$2
|
||||
[ -n "$protocol" ] || protocol="tcp,udp"
|
||||
local result=
|
||||
if [ "$protocol" = "tcp" ]; then
|
||||
result=$(netstat -tln | grep -c ":$port ")
|
||||
elif [ "$protocol" = "udp" ]; then
|
||||
result=$(netstat -uln | grep -c ":$port ")
|
||||
elif [ "$protocol" = "tcp,udp" ]; then
|
||||
result=$(netstat -tuln | grep -c ":$port ")
|
||||
fi
|
||||
echo "${result}"
|
||||
}
|
||||
|
||||
get_new_port() {
|
||||
local default_start_port=2001
|
||||
local min_port=1025
|
||||
local max_port=49151
|
||||
local port=$1
|
||||
local last_get_new_port_auto
|
||||
if [ "$1" == "auto" ]; then
|
||||
last_get_new_port_auto=$(get_cache_var "last_get_new_port_auto")
|
||||
if [ -n "$last_get_new_port_auto" ]; then
|
||||
port=$last_get_new_port_auto
|
||||
port=$(expr $port + 1)
|
||||
else
|
||||
port=$default_start_port
|
||||
fi
|
||||
fi
|
||||
[ "$port" -lt $min_port -o "$port" -gt $max_port ] && port=$default_start_port
|
||||
local protocol=$(echo $2 | tr 'A-Z' 'a-z')
|
||||
local result=$(check_port_exists $port $protocol)
|
||||
if [ "$result" != 0 ]; then
|
||||
local temp=
|
||||
if [ "$port" -lt $max_port ]; then
|
||||
temp=$(expr $port + 1)
|
||||
elif [ "$port" -gt $min_port ]; then
|
||||
temp=$(expr $port - 1)
|
||||
else
|
||||
temp=$default_start_port
|
||||
fi
|
||||
get_new_port $temp $protocol
|
||||
else
|
||||
[ "$1" == "auto" ] && set_cache_var "last_get_new_port_auto" "$port"
|
||||
echo $port
|
||||
fi
|
||||
}
|
||||
|
||||
has_1_65535() {
|
||||
local val="$1"
|
||||
val=${val//:/-}
|
||||
case ",$val," in
|
||||
*,1-65535,*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
add_ip2route() {
|
||||
local ip=$(get_host_ip "ipv4" $1)
|
||||
[ -z "$ip" ] && {
|
||||
log 1 "$(i18n "Unable to resolve [%s], route table addition failed!" "${1}")"
|
||||
return 1
|
||||
}
|
||||
local remarks="${1}"
|
||||
[ "$remarks" != "$ip" ] && remarks="${1}(${ip})"
|
||||
|
||||
local gateway device
|
||||
network_get_gateway gateway "$2"
|
||||
network_get_device device "$2"
|
||||
[ -z "${device}" ] && device=$(ubus call "network.interface.$2" status 2>/dev/null | jsonfilter -e '@.device' 2>/dev/null)
|
||||
[ -z "${device}" ] && [ -d "/sys/class/net/$2" ] && device="$2"
|
||||
[ -z "${device}" ] && device="$2"
|
||||
|
||||
if [ -n "${gateway}" ]; then
|
||||
route add -host ${ip} gw ${gateway} dev ${device} >/dev/null 2>&1
|
||||
echo "$ip" >> $TMP_ROUTE_PATH/${device}
|
||||
log 1 "$(i18n "[%s] was successfully added to the routing table of interface [%s]!" "${remarks}" "${device}")"
|
||||
else
|
||||
log 1 "$(i18n "Adding [%s] to the [%s] routing table failed! The reason is that the [%s] gateway cannot be found." "${remarks}" "${device}" "${device}")"
|
||||
fi
|
||||
}
|
||||
|
||||
delete_ip2route() {
|
||||
[ -d "${TMP_ROUTE_PATH}" ] && {
|
||||
for interface in $(ls ${TMP_ROUTE_PATH}); do
|
||||
for ip in $(cat ${TMP_ROUTE_PATH}/${interface}); do
|
||||
route del -host ${ip} dev ${interface} >/dev/null 2>&1
|
||||
done
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
ln_run() {
|
||||
local queue_run=${1}
|
||||
local file_func=${2}
|
||||
local ln_name=${3}
|
||||
local output=${4}
|
||||
shift 4;
|
||||
|
||||
if [ "${file_func%%/*}" != "${file_func}" ]; then
|
||||
[ ! -L "${file_func}" ] && {
|
||||
ln -s "${file_func}" "${TMP_BIN_PATH}/${ln_name}" >/dev/null 2>&1
|
||||
file_func="${TMP_BIN_PATH}/${ln_name}"
|
||||
}
|
||||
[ -x "${file_func}" ] || log 1 "$(i18n "%s does not have execute permissions and cannot be started: %s %s" "$(readlink ${file_func})" "${file_func}" "$*")"
|
||||
fi
|
||||
#echo "${file_func} $*" >&2
|
||||
[ -n "${file_func}" ] || log 1 "$(i18n "%s not found, unable to start..." "${ln_name}")"
|
||||
|
||||
[ "${queue_run}" == "1" ] && {
|
||||
mkdir -p $TMP_PROCESS_LIST_PATH
|
||||
process_count=$(ls $TMP_PROCESS_LIST_PATH | grep -v "^_" | wc -l)
|
||||
process_count=$((process_count + 1))
|
||||
echo "${file_func:-log 1 "${ln_name}"} $@ >${output}" > $TMP_PROCESS_LIST_PATH/$process_count
|
||||
return
|
||||
}
|
||||
|
||||
${file_func:-log 1 "${ln_name}"} "$@" >${output} 2>&1 &
|
||||
|
||||
[ -n "$NO_REC_PROCESS" ] && return
|
||||
|
||||
process_count=$(ls $TMP_SCRIPT_FUNC_PATH | grep -v "^_" | wc -l)
|
||||
process_count=$((process_count + 1))
|
||||
echo "${file_func:-log 1 "${ln_name}"} $@ >${output}" > $TMP_SCRIPT_FUNC_PATH/$process_count
|
||||
}
|
||||
|
||||
run_process_queue() {
|
||||
[ -d ${TMP_PROCESS_LIST_PATH} ] && {
|
||||
mkdir -p ${TMP_SCRIPT_FUNC_PATH}
|
||||
for filename in $(ls ${TMP_PROCESS_LIST_PATH}); do
|
||||
cmd=$(cat ${TMP_PROCESS_LIST_PATH}/${filename})
|
||||
cmd_check=$(echo $cmd | awk -F '>' '{print $1}')
|
||||
icount=$(busybox pgrep -f "$(echo $cmd_check)" | wc -l)
|
||||
if [ $icount = 0 ]; then
|
||||
eval $(echo "nohup ${cmd} 2>&1 &") >/dev/null 2>&1 &
|
||||
fi
|
||||
mv -f ${TMP_PROCESS_LIST_PATH}/${filename} ${TMP_SCRIPT_FUNC_PATH}/queued_${filename}
|
||||
done
|
||||
}
|
||||
rm -rf ${TMP_PROCESS_LIST_PATH}
|
||||
}
|
||||
|
||||
kill_all() {
|
||||
kill -9 $(pidof "$@") >/dev/null 2>&1
|
||||
}
|
||||
|
||||
get_wan_ips() {
|
||||
local family="$1"
|
||||
local NET_ADDR
|
||||
local iface
|
||||
local INTERFACES=$(ubus call network.interface dump | jsonfilter -e \
|
||||
'@.interface[!(@.interface ~ /lan/) && !(@.l3_device ~ /\./) && @.route[0]].interface')
|
||||
for iface in $INTERFACES; do
|
||||
local addr
|
||||
if [ "$family" = "ip6" ]; then
|
||||
network_get_ipaddr6 addr "$iface"
|
||||
case "$addr" in
|
||||
""|fe80*) continue ;;
|
||||
esac
|
||||
else
|
||||
network_get_ipaddr addr "$iface"
|
||||
case "$addr" in
|
||||
""|"0.0.0.0") continue ;;
|
||||
esac
|
||||
fi
|
||||
case " $NET_ADDR " in
|
||||
*" $addr "*) ;;
|
||||
*) NET_ADDR="${NET_ADDR:+$NET_ADDR }$addr" ;;
|
||||
esac
|
||||
done
|
||||
echo "$NET_ADDR"
|
||||
}
|
||||
|
||||
get_local_ips() {
|
||||
local family="$1"
|
||||
local ALL_IPS WAN_IPS ip NET_ADDR
|
||||
if [ "$family" = "ip6" ]; then
|
||||
ALL_IPS=$(ip -o -6 addr show scope global | awk '{print $4}' | cut -d/ -f1)
|
||||
WAN_IPS=$(get_wan_ips ip6)
|
||||
else
|
||||
ALL_IPS=$(ip -o -4 addr show scope global | awk '{print $4}' | cut -d/ -f1)
|
||||
WAN_IPS=$(get_wan_ips ip4)
|
||||
fi
|
||||
# Supplementary loop (not included in scope global)
|
||||
[ "$family" = "ip6" ] && ALL_IPS="$ALL_IPS ::1"
|
||||
[ "$family" != "ip6" ] && ALL_IPS="$ALL_IPS 127.0.0.1"
|
||||
for ip in $ALL_IPS; do
|
||||
case "$ip" in
|
||||
""|0.0.0.0|::) continue ;;
|
||||
esac
|
||||
case " $WAN_IPS " in
|
||||
*" $ip "*) continue ;;
|
||||
esac
|
||||
case " $NET_ADDR " in
|
||||
*" $ip "*) ;;
|
||||
*) NET_ADDR="${NET_ADDR:+$NET_ADDR }$ip" ;;
|
||||
esac
|
||||
done
|
||||
for ip in $NET_ADDR; do
|
||||
echo "$ip"
|
||||
done
|
||||
}
|
||||
Reference in new issue
Block a user