💐 Sync 2025-11-05 00:13:10
This commit is contained in:
@@ -7,6 +7,8 @@ PKG_VERSION:=190
|
||||
PKG_RELEASE:=3
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NONE_V2RAY \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_V2ray \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Xray \
|
||||
@@ -39,9 +41,9 @@ PKG_CONFIG_DEPENDS:= \
|
||||
LUCI_TITLE:=SS/SSR/V2Ray/Trojan/NaiveProxy/Tuic/ShadowTLS/Hysteria/Socks5/Tun LuCI interface
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_DEPENDS:= \
|
||||
+coreutils +coreutils-base64 +dns2tcp +dnsmasq-full +@PACKAGE_dnsmasq_full_ipset +ipset +kmod-ipt-nat +jq \
|
||||
+ip-full +iptables +iptables-mod-tproxy +lua +lua-neturl +libuci-lua +microsocks \
|
||||
+tcping +resolveip +shadowsocksr-libev-ssr-check +curl +nping \
|
||||
+coreutils +coreutils-base64 +dns2tcp +dnsmasq-full \
|
||||
+jq +ip-full +lua +lua-neturl +libuci-lua +microsocks \
|
||||
+tcping +resolveip +curl +nping \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:curl \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:v2ray-core \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Xray:curl \
|
||||
@@ -68,14 +70,40 @@ LUCI_DEPENDS:= \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Xray_Plugin:xray-plugin \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-local \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-redir \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server:shadowsocksr-libev-ssr-server \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-redir \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server:shadowsocksr-libev-ssr-check \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Trojan:trojan
|
||||
|
||||
|
||||
define Package/$(PKG_NAME)/config
|
||||
select PACKAGE_luci-lib-ipkg if PACKAGE_$(PKG_NAME)
|
||||
select PACKAGE_luci-lua-runtime if PACKAGE_$(PKG_NAME)
|
||||
|
||||
choice
|
||||
prompt "Transparent Proxy Backend"
|
||||
default PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy if ! PACKAGE_firewall4
|
||||
default PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy if PACKAGE_firewall4
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy
|
||||
bool "Iptables Transparent Proxy"
|
||||
select PACKAGE_dnsmasq_full_ipset
|
||||
select PACKAGE_ipset
|
||||
select PACKAGE_iptables
|
||||
select PACKAGE_iptables-zz-legacy
|
||||
select PACKAGE_iptables-mod-conntrack-extra
|
||||
select PACKAGE_iptables-mod-iprange
|
||||
select PACKAGE_iptables-mod-socket
|
||||
select PACKAGE_iptables-mod-tproxy
|
||||
select PACKAGE_kmod-ipt-nat
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy
|
||||
bool "Nftables Transparent Proxy"
|
||||
select PACKAGE_dnsmasq_full_nftset
|
||||
select PACKAGE_nftables
|
||||
select PACKAGE_kmod-nft-socket
|
||||
select PACKAGE_kmod-nft-tproxy
|
||||
select PACKAGE_kmod-nft-nat
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Shadowsocks Client Selection"
|
||||
default PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client if aarch64||arm||i386||mips||mipsel||x86_64
|
||||
|
||||
@@ -28,8 +28,9 @@ function index()
|
||||
entry({"admin", "services", "shadowsocksr", "reset"}, call("act_reset"))
|
||||
entry({"admin", "services", "shadowsocksr", "restart"}, call("act_restart"))
|
||||
entry({"admin", "services", "shadowsocksr", "delete"}, call("act_delete"))
|
||||
--[[Backup]]
|
||||
--[[Backup]]
|
||||
entry({"admin", "services", "shadowsocksr", "backup"}, call("create_backup")).leaf = true
|
||||
|
||||
end
|
||||
|
||||
function subscribe()
|
||||
@@ -46,40 +47,74 @@ function act_status()
|
||||
end
|
||||
|
||||
function act_ping()
|
||||
local e = {}
|
||||
local domain = luci.http.formvalue("domain")
|
||||
local port = luci.http.formvalue("port")
|
||||
local transport = luci.http.formvalue("transport")
|
||||
local wsPath = luci.http.formvalue("wsPath")
|
||||
local tls = luci.http.formvalue("tls")
|
||||
e.index = luci.http.formvalue("index")
|
||||
local iret = luci.sys.call("ipset add ss_spec_wan_ac " .. domain .. " 2>/dev/null")
|
||||
if transport == "ws" then
|
||||
local prefix = tls=='1' and "https://" or "http://"
|
||||
local address = prefix..domain..':'..port..wsPath
|
||||
local result = luci.sys.exec("curl --http1.1 -m 2 -ksN -o /dev/null -w 'time_connect=%{time_connect}\nhttp_code=%{http_code}' -H 'Connection: Upgrade' -H 'Upgrade: websocket' -H 'Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==' -H 'Sec-WebSocket-Version: 13' "..address)
|
||||
e.socket = string.match(result,"http_code=(%d+)")=="101"
|
||||
e.ping = tonumber(string.match(result, "time_connect=(%d+.%d%d%d)"))*1000
|
||||
else
|
||||
local socket = nixio.socket("inet", "stream")
|
||||
socket:setopt("socket", "rcvtimeo", 3)
|
||||
socket:setopt("socket", "sndtimeo", 3)
|
||||
e.socket = socket:connect(domain, port)
|
||||
socket:close()
|
||||
e.ping = luci.sys.exec(string.format("echo -n $(tcping -q -c 1 -i 1 -t 2 -p %s %s 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}') 2>/dev/null", port, domain))
|
||||
if (e.ping == "") 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" % domain)
|
||||
if (e.ping == "") then
|
||||
-- UDP ping test using nping
|
||||
e.ping = luci.sys.exec(string.format("echo -n $(nping --udp -c 1 -p %s %s 2>/dev/null | grep -o 'Avg rtt: [0-9.]*ms' | awk '{print $3}' | sed 's/ms//' | head -1) 2>/dev/null", port, domain))
|
||||
end
|
||||
end
|
||||
end
|
||||
if (iret == 0) then
|
||||
luci.sys.call(" ipset del ss_spec_wan_ac " .. domain)
|
||||
end
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
local e = {}
|
||||
local domain = luci.http.formvalue("domain")
|
||||
local port = tonumber(luci.http.formvalue("port") or 0)
|
||||
local transport = luci.http.formvalue("transport")
|
||||
local wsPath = luci.http.formvalue("wsPath") or ""
|
||||
local tls = luci.http.formvalue("tls")
|
||||
e.index = luci.http.formvalue("index")
|
||||
|
||||
local use_nft = luci.sys.call("command -v nft >/dev/null") == 0
|
||||
local iret = false
|
||||
|
||||
if use_nft then
|
||||
iret = luci.sys.call("nft add element inet ss_spec ss_spec_wan_ac { " .. domain .. " } 2>/dev/null") == 0
|
||||
else
|
||||
iret = luci.sys.call("ipset add ss_spec_wan_ac " .. domain .. " 2>/dev/null") == 0
|
||||
end
|
||||
|
||||
if transport == "ws" then
|
||||
local prefix = tls == '1' and "https://" or "http://"
|
||||
local address = prefix .. domain .. ':' .. port .. wsPath
|
||||
local result = luci.sys.exec(
|
||||
"curl --http1.1 -m 2 -ksN -o /dev/null " ..
|
||||
"-w 'time_connect=%{time_connect}\nhttp_code=%{http_code}' " ..
|
||||
"-H 'Connection: Upgrade' -H 'Upgrade: websocket' " ..
|
||||
"-H 'Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==' " ..
|
||||
"-H 'Sec-WebSocket-Version: 13' " .. address
|
||||
)
|
||||
e.socket = string.match(result,"http_code=(%d+)") == "101"
|
||||
local ping_time = tonumber(string.match(result, "time_connect=(%d+.%d%d%d)"))
|
||||
e.ping = ping_time and ping_time * 1000 or nil
|
||||
else
|
||||
-- TCP ping
|
||||
local socket = nixio.socket("inet", "stream")
|
||||
socket:setopt("socket", "rcvtimeo", 3)
|
||||
socket:setopt("socket", "sndtimeo", 3)
|
||||
e.socket = socket:connect(domain, port)
|
||||
socket:close()
|
||||
|
||||
e.ping = tonumber(luci.sys.exec(string.format(
|
||||
"tcping -q -c 1 -i 1 -t 2 -p %d %s 2>/dev/null | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}'",
|
||||
port, domain
|
||||
)))
|
||||
|
||||
if not e.ping then
|
||||
e.ping = tonumber(luci.sys.exec(string.format(
|
||||
"ping -c 1 -W 1 %s 2>/dev/null | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}'",
|
||||
domain
|
||||
)))
|
||||
end
|
||||
|
||||
if not e.ping then
|
||||
e.ping = tonumber(luci.sys.exec(string.format(
|
||||
"nping --udp -c 1 -p %d %s 2>/dev/null | grep -o 'Avg rtt: [0-9.]*ms' | awk '{print $3}' | sed 's/ms//' | head -1",
|
||||
port, domain
|
||||
)))
|
||||
end
|
||||
end
|
||||
|
||||
if iret then
|
||||
if use_nft then
|
||||
luci.sys.call("nft delete element inet ss_spec ss_spec_wan_ac { " .. domain .. " } 2>/dev/null")
|
||||
else
|
||||
luci.sys.call("ipset del ss_spec_wan_ac " .. domain .. " 2>/dev/null")
|
||||
end
|
||||
end
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
|
||||
function check_status()
|
||||
@@ -101,28 +136,46 @@ function check_port()
|
||||
local s
|
||||
local server_name = ""
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local iret = 1
|
||||
local use_nft = luci.sys.call("command -v nft >/dev/null") == 0
|
||||
|
||||
uci:foreach("shadowsocksr", "servers", function(s)
|
||||
if s.alias then
|
||||
server_name = s.alias
|
||||
elseif s.server and s.server_port then
|
||||
server_name = "%s:%s" % {s.server, s.server_port}
|
||||
server_name = s.server .. ":" .. s.server_port
|
||||
end
|
||||
iret = luci.sys.call("ipset add ss_spec_wan_ac " .. s.server .. " 2>/dev/null")
|
||||
socket = nixio.socket("inet", "stream")
|
||||
|
||||
-- 临时加入 set
|
||||
local iret = false
|
||||
if use_nft then
|
||||
iret = luci.sys.call("nft add element inet ss_spec ss_spec_wan_ac { " .. s.server .. " } 2>/dev/null") == 0
|
||||
else
|
||||
iret = luci.sys.call("ipset add ss_spec_wan_ac " .. s.server .. " 2>/dev/null") == 0
|
||||
end
|
||||
|
||||
-- TCP 测试
|
||||
local socket = nixio.socket("inet", "stream")
|
||||
socket:setopt("socket", "rcvtimeo", 3)
|
||||
socket:setopt("socket", "sndtimeo", 3)
|
||||
ret = socket:connect(s.server, s.server_port)
|
||||
if tostring(ret) == "true" then
|
||||
socket:close()
|
||||
retstring = retstring .. "<font><b style='color:green'>[" .. server_name .. "] OK.</b></font><br />"
|
||||
local ret = socket:connect(s.server, s.server_port)
|
||||
socket:close()
|
||||
|
||||
if ret then
|
||||
retstring = retstring .. string.format("<font><b style='color:green'>[%s] OK.</b></font><br />", server_name)
|
||||
else
|
||||
retstring = retstring .. "<font><b style='color:red'>[" .. server_name .. "] Error.</b></font><br />"
|
||||
retstring = retstring .. string.format("<font><b style='color:red'>[%s] Error.</b></font><br />", server_name)
|
||||
end
|
||||
if iret == 0 then
|
||||
luci.sys.call("ipset del ss_spec_wan_ac " .. s.server)
|
||||
|
||||
-- 删除临时 set
|
||||
if iret then
|
||||
if use_nft then
|
||||
luci.sys.call("nft delete element inet ss_spec ss_spec_wan_ac { " .. s.server .. " } 2>/dev/null")
|
||||
else
|
||||
luci.sys.call("ipset del ss_spec_wan_ac " .. s.server)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({ret = retstring})
|
||||
end
|
||||
|
||||
@@ -4,14 +4,22 @@ local uci = require "luci.model.uci".cursor()
|
||||
-- 获取 LAN IP 地址
|
||||
function lanip()
|
||||
local lan_ip
|
||||
lan_ip = luci.sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F '/' '{print $1}' | tr -d '\n'")
|
||||
|
||||
-- 尝试从 UCI 直接读取
|
||||
lan_ip = luci.sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F'/' '{print $1}' | tr -d '\\n'")
|
||||
|
||||
-- 尝试从 LAN 接口信息中读取(优先 ifname,再 fallback 到 device)
|
||||
if not lan_ip or lan_ip == "" then
|
||||
lan_ip = luci.sys.exec("ip address show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) | grep -w 'inet' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -1 | tr -d '\n'")
|
||||
lan_ip = luci.sys.exec([[
|
||||
ip -4 addr show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) 2>/dev/null \
|
||||
| grep -w 'inet' | awk '{print $2}' | cut -d'/' -f1 | grep -v '^127\.' | head -n1 | tr -d '\n']])
|
||||
end
|
||||
|
||||
-- 取任意一个 global IPv4 地址
|
||||
if not lan_ip or lan_ip == "" then
|
||||
lan_ip = luci.sys.exec("ip addr show | grep -w 'inet' | grep 'global' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -n 1 | tr -d '\n'")
|
||||
lan_ip = luci.sys.exec([[
|
||||
ip -4 addr show scope global 2>/dev/null \
|
||||
| grep -w 'inet' | awk '{print $2}' | cut -d'/' -f1 | grep -v '^127\.' | head -n1 | tr -d '\n']])
|
||||
end
|
||||
|
||||
return lan_ip
|
||||
|
||||
@@ -264,7 +264,7 @@ s = m:section(NamedSection, sid, "servers")
|
||||
s.anonymous = true
|
||||
s.addremove = false
|
||||
|
||||
o = s:option(DummyValue, "ssr_url", "SS/SSR/V2RAY/TROJAN/HYSTERIA2 URL")
|
||||
o = s:option(DummyValue, "ssr_url", "SS/SSR/V2RAY/TROJAN/TUIC/HYSTERIA2 URL")
|
||||
o.rawhtml = true
|
||||
o.template = "shadowsocksr/ssrurl"
|
||||
o.value = sid
|
||||
@@ -1285,15 +1285,26 @@ o = s:option(ListValue, "tuic_alpn", translate("TUIC ALPN"))
|
||||
o.default = ""
|
||||
o:value("", translate("Default"))
|
||||
o:value("h3")
|
||||
o:value("h2")
|
||||
o:value("h3,h2")
|
||||
o:value("spdy/3.1")
|
||||
o:value("h3,spdy/3.1")
|
||||
o:depends("type", "tuic")
|
||||
|
||||
-- IP STACK PREFERENCE
|
||||
o = s:option(ListValue, "ipstack_prefer", translate("IP Stack Preference"))
|
||||
o.default = ""
|
||||
o:value("", translate("Default"))
|
||||
o:value("v4first")
|
||||
o:value("v6first")
|
||||
o:depends("tuic_dual_stack", true)
|
||||
|
||||
-- [[ allowInsecure ]]--
|
||||
o = s:option(Flag, "insecure", translate("allowInsecure"))
|
||||
o.rmempty = false
|
||||
o:depends("tls", true)
|
||||
o:depends("type", "hysteria2")
|
||||
o:depends("type", "tuic")
|
||||
o.description = translate("If true, allowss insecure connection at TLS client, e.g., TLS server uses unverifiable certificates.")
|
||||
|
||||
-- [[ Hysteria2 TLS pinSHA256 ]] --
|
||||
|
||||
@@ -8,14 +8,22 @@ local uci = require "luci.model.uci".cursor()
|
||||
-- 获取 LAN IP 地址
|
||||
function lanip()
|
||||
local lan_ip
|
||||
lan_ip = luci.sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F '/' '{print $1}' | tr -d '\n'")
|
||||
|
||||
-- 尝试从 UCI 直接读取
|
||||
lan_ip = luci.sys.exec("uci -q get network.lan.ipaddr 2>/dev/null | awk -F'/' '{print $1}' | tr -d '\\n'")
|
||||
|
||||
-- 尝试从 LAN 接口信息中读取(优先 ifname,再 fallback 到 device)
|
||||
if not lan_ip or lan_ip == "" then
|
||||
lan_ip = luci.sys.exec("ip address show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) | grep -w 'inet' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -1 | tr -d '\n'")
|
||||
lan_ip = luci.sys.exec([[
|
||||
ip -4 addr show $(uci -q -p /tmp/state get network.lan.ifname || uci -q -p /tmp/state get network.lan.device) 2>/dev/null \
|
||||
| grep -w 'inet' | awk '{print $2}' | cut -d'/' -f1 | grep -v '^127\.' | head -n1 | tr -d '\n']])
|
||||
end
|
||||
|
||||
-- 取任意一个 global IPv4 地址
|
||||
if not lan_ip or lan_ip == "" then
|
||||
lan_ip = luci.sys.exec("ip addr show | grep -w 'inet' | grep 'global' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -n 1 | tr -d '\n'")
|
||||
lan_ip = luci.sys.exec([[
|
||||
ip -4 addr show scope global 2>/dev/null \
|
||||
| grep -w 'inet' | awk '{print $2}' | cut -d'/' -f1 | grep -v '^127\.' | head -n1 | tr -d '\n']])
|
||||
end
|
||||
|
||||
return lan_ip
|
||||
|
||||
@@ -75,9 +75,9 @@ function export_ssr_url(btn, urlname, sid) {
|
||||
textarea.select();
|
||||
try {
|
||||
document.execCommand("copy"); // Security exception may be thrown by some browsers.
|
||||
s.innerHTML = "<font color='green'><%:Copy SSR to clipboard successfully.%></font>";
|
||||
s.innerHTML = "<font style=\'color:green\'><%:Copy SSR to clipboard successfully.%></font>";
|
||||
} catch (ex) {
|
||||
s.innerHTML = "<font color='red'><%:Unable to copy SSR to clipboard.%></font>";
|
||||
s.innerHTML = "<font style=\'color:red\'><%:Unable to copy SSR to clipboard.%></font>";
|
||||
} finally {
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
@@ -89,7 +89,7 @@ function import_ssr_url(btn, urlname, sid) {
|
||||
if (!s) return false;
|
||||
var ssrurl = prompt("<%:Paste sharing link here%>", "");
|
||||
if (ssrurl == null || ssrurl == "") {
|
||||
s.innerHTML = "<font color='red'><%:User cancelled.%></font>";
|
||||
s.innerHTML = "<font style=\'color:red\'><%:User cancelled.%></font>";
|
||||
return false;
|
||||
}
|
||||
s.innerHTML = "";
|
||||
@@ -97,18 +97,6 @@ function import_ssr_url(btn, urlname, sid) {
|
||||
ssrurl = ssrurl.replace(/&([a-zA-Z]+);/g, '&').replace(/\s*#\s*/, '#').trim(); //一些奇葩的链接用"&"当做"&","#"前后带空格
|
||||
var ssu = ssrurl.split('://');
|
||||
//console.log(ssu.length);
|
||||
if (ssu[0] === "ss") {
|
||||
var queryStr = "";
|
||||
if (ssu[1].indexOf("?") > -1) {
|
||||
queryStr = ssu[1].split("?")[1]; // 提取 ? 后面的参数
|
||||
}
|
||||
var params = new URLSearchParams(queryStr);
|
||||
if (params.get("type")) {
|
||||
// 替换协议头
|
||||
ssrurl = ssrurl.replace(/^ss:\/\//i, "shadowsocks://");
|
||||
var ssu = ssrurl.split('://');
|
||||
}
|
||||
}
|
||||
var event = document.createEvent("HTMLEvents");
|
||||
event.initEvent("change", true, true);
|
||||
switch (ssu[0]) {
|
||||
@@ -189,136 +177,281 @@ function import_ssr_url(btn, urlname, sid) {
|
||||
|
||||
// 再分离 ? 或 /?(参数)
|
||||
var queryIndex = (url0 = url0.replace('/?', '?')).indexOf("?");
|
||||
var queryStr = "";
|
||||
var query = "";
|
||||
if (queryIndex >= 0) {
|
||||
queryStr = url0.substring(queryIndex + 1);
|
||||
query = url0.substring(queryIndex + 1);
|
||||
url0 = url0.substring(0, queryIndex);
|
||||
}
|
||||
|
||||
var params = Object.fromEntries(new URLSearchParams(queryStr));
|
||||
var params = Object.fromEntries(new URLSearchParams(query));
|
||||
|
||||
// 判断是否 SIP002 格式(即含 @)
|
||||
if (url0.indexOf("@") !== -1) {
|
||||
// === SIP002 格式 ===
|
||||
var sipIndex = url0.indexOf("@");
|
||||
// 先 URL 解码 base64 再解码
|
||||
var userInfoB64 = decodeURIComponent(url0.substring(0, sipIndex));
|
||||
var userInfo = b64decsafe(userInfoB64);
|
||||
var userInfoSplitIndex = userInfo.indexOf(":");
|
||||
if(userInfoSplitIndex < 0) {
|
||||
// 格式错误
|
||||
s.innerHTML = "<font style='color:red'><%:Userinfo format error.%></font>";
|
||||
break;
|
||||
}
|
||||
var method = userInfo.substring(0, userInfoSplitIndex);
|
||||
var password = userInfo.substring(userInfoSplitIndex + 1);
|
||||
var serverPart = url0.substring(sipIndex + 1);
|
||||
var serverInfo = serverPart.split(":");
|
||||
if ( ! params.type) {
|
||||
// 普通 SS 导入逻辑
|
||||
// 判断是否 SIP002 格式(即含 @)
|
||||
if (url0.indexOf("@") !== -1) {
|
||||
// === SIP002 格式 ===
|
||||
var sipIndex = url0.indexOf("@");
|
||||
// 先 URL 解码 base64 再解码
|
||||
var userInfoB64 = decodeURIComponent(url0.substring(0, sipIndex));
|
||||
var userInfo = b64decsafe(userInfoB64);
|
||||
var userInfoSplitIndex = userInfo.indexOf(":");
|
||||
if(userInfoSplitIndex < 0) {
|
||||
// 格式错误
|
||||
s.innerHTML = "<font style='color:red'><%:Userinfo format error.%></font>";
|
||||
break;
|
||||
}
|
||||
var method = userInfo.substring(0, userInfoSplitIndex);
|
||||
var password = userInfo.substring(userInfoSplitIndex + 1);
|
||||
var serverPart = url0.substring(sipIndex + 1);
|
||||
var serverInfo = serverPart.split(":");
|
||||
|
||||
var server = serverInfo[0];
|
||||
var port = serverInfo[1];
|
||||
var server = serverInfo[0];
|
||||
var port = serverInfo[1];
|
||||
|
||||
var plugin = "", pluginOpts = "";
|
||||
if (params.plugin) {
|
||||
var pluginParams = decodeURIComponent(params.plugin).split(";");
|
||||
plugin = pluginParams.shift();
|
||||
pluginOpts = pluginParams.join(";");
|
||||
}
|
||||
} else {
|
||||
// === Base64 SS2022 / 普通格式 的整体编码格式 ===
|
||||
// 先 URL 解码整个字符串
|
||||
var decodedUrl0 = decodeURIComponent(url0);
|
||||
var sstr = b64decsafe(decodedUrl0);
|
||||
if (!sstr) {
|
||||
s.innerHTML = "<font style='color:red'><%:Base64 sstr failed.%></font>";
|
||||
break;
|
||||
}
|
||||
|
||||
// 支持 SS2022 / 普通格式
|
||||
var regex2022 = /^([^:]+):([^:]+):([^@]+)@([^:]+):(\d+)$/;
|
||||
var regexNormal = /^([^:]+):([^@]+)@([^:]+):(\d+)$/;
|
||||
|
||||
var m2022 = sstr.match(regex2022);
|
||||
var mNormal = sstr.match(regexNormal);
|
||||
|
||||
if (m2022) {
|
||||
var method = m2022[1];
|
||||
var password = m2022[2] + ":" + m2022[3];
|
||||
var server = m2022[4];
|
||||
var port = m2022[5];
|
||||
} else if (mNormal) {
|
||||
var method = mNormal[1];
|
||||
var password = mNormal[2];
|
||||
var server = mNormal[3];
|
||||
var port = mNormal[4];
|
||||
var plugin = "", pluginOpts = "";
|
||||
if (params.plugin) {
|
||||
var pluginParams = decodeURIComponent(params.plugin).split(";");
|
||||
plugin = pluginParams.shift();
|
||||
pluginOpts = pluginParams.join(";");
|
||||
}
|
||||
} else {
|
||||
s.innerHTML = "<font style='color:red'><%:SS URL base64 sstr format not recognized.%></font>";
|
||||
break;
|
||||
}
|
||||
// === Base64 SS2022 / 普通格式 的整体编码格式 ===
|
||||
// 先 URL 解码整个字符串
|
||||
var decodedUrl0 = decodeURIComponent(url0);
|
||||
var sstr = b64decsafe(decodedUrl0);
|
||||
if (!sstr) {
|
||||
s.innerHTML = "<font style='color:red'><%:Base64 sstr failed.%></font>";
|
||||
break;
|
||||
}
|
||||
|
||||
var plugin = "", pluginOpts = "";
|
||||
if (params["shadow-tls"]) {
|
||||
try {
|
||||
var decoded_tls = JSON.parse(atob(decodeURIComponent(params["shadow-tls"])));
|
||||
plugin = "shadow-tls";
|
||||
var versionFlag = "";
|
||||
if (decoded_tls.version && !isNaN(decoded_tls.version)) {
|
||||
versionFlag = "v" + decoded_tls.version + "=1;";
|
||||
// 支持 SS2022 / 普通格式
|
||||
var regex2022 = /^([^:]+):([^:]+):([^@]+)@([^:]+):(\d+)$/;
|
||||
var regexNormal = /^([^:]+):([^@]+)@([^:]+):(\d+)$/;
|
||||
|
||||
var m2022 = sstr.match(regex2022);
|
||||
var mNormal = sstr.match(regexNormal);
|
||||
|
||||
if (m2022) {
|
||||
var method = m2022[1];
|
||||
var password = m2022[2] + ":" + m2022[3];
|
||||
var server = m2022[4];
|
||||
var port = m2022[5];
|
||||
} else if (mNormal) {
|
||||
var method = mNormal[1];
|
||||
var password = mNormal[2];
|
||||
var server = mNormal[3];
|
||||
var port = mNormal[4];
|
||||
} else {
|
||||
s.innerHTML = "<font style='color:red'><%:SS URL base64 sstr format not recognized.%></font>";
|
||||
break;
|
||||
}
|
||||
|
||||
var plugin = "", pluginOpts = "";
|
||||
if (params["shadow-tls"]) {
|
||||
try {
|
||||
var decoded_tls = JSON.parse(atob(decodeURIComponent(params["shadow-tls"])));
|
||||
plugin = "shadow-tls";
|
||||
var versionFlag = "";
|
||||
if (decoded_tls.version && !isNaN(decoded_tls.version)) {
|
||||
versionFlag = "v" + decoded_tls.version + "=1;";
|
||||
}
|
||||
pluginOpts = versionFlag + "host=" + (decoded_tls.host || "") + ";passwd=" + (decoded_tls.password || "");
|
||||
} catch (e) {
|
||||
console.log("shadow-tls decode failed:", e);
|
||||
}
|
||||
pluginOpts = versionFlag + "host=" + (decoded_tls.host || "") + ";passwd=" + (decoded_tls.password || "");
|
||||
} catch (e) {
|
||||
console.log("shadow-tls decode failed:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 判断密码是否经过url编码
|
||||
const isURLEncodedPassword = function(pwd) {
|
||||
if (!/%[0-9A-Fa-f]{2}/.test(pwd)) return false;
|
||||
// 判断密码是否经过url编码
|
||||
const isURLEncodedPassword = function(pwd) {
|
||||
if (!/%[0-9A-Fa-f]{2}/.test(pwd)) return false;
|
||||
try {
|
||||
const decoded = decodeURIComponent(pwd.replace(/\+/g, "%20"));
|
||||
const reencoded = encodeURIComponent(decoded);
|
||||
return reencoded === pwd;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (isURLEncodedPassword(password)) {
|
||||
password = decodeURIComponent(password); // 解码URL编码
|
||||
} else {
|
||||
password = password; // 保持原始值
|
||||
}
|
||||
|
||||
// === 填充配置项 ===
|
||||
var has_ss_type = (ss_type === "ss-rust") ? "ss-rust" : "ss-libev";
|
||||
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = ssu[0];
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.has_ss_type')[0].value = has_ss_type;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.has_ss_type')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = server;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = port;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = password || "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].value = method;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].dispatchEvent(event);
|
||||
|
||||
if (plugin && plugin !== "none") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_plugin')[0].checked = true; // 设置 enable_plugin 为 true
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_plugin')[0].dispatchEvent(event); // 触发事件
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin')[0].value = plugin;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin')[0].dispatchEvent(event);
|
||||
if (plugin !== undefined) {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin_opts')[0].value = pluginOpts || "";
|
||||
}
|
||||
} else {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_plugin')[0].checked = false;
|
||||
}
|
||||
|
||||
if (param != undefined) {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURIComponent(param);
|
||||
}
|
||||
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
|
||||
return false;
|
||||
} else {
|
||||
try {
|
||||
const decoded = decodeURIComponent(pwd.replace(/\+/g, "%20"));
|
||||
const reencoded = encodeURIComponent(decoded);
|
||||
return reencoded === pwd;
|
||||
} catch (e) {
|
||||
// Xray SS 导入逻辑
|
||||
// 拆分 @,判断是否是 base64 userinfo 的格式
|
||||
var parts = url0.split("@");
|
||||
if (parts.length > 1) {
|
||||
// @ 前是 base64(method:password),后面是 server:port?params
|
||||
var userinfo = b64decsafe(parts[0]);
|
||||
var sepIndex = userinfo.indexOf(":");
|
||||
if (sepIndex > -1) {
|
||||
method = userinfo.slice(0, sepIndex);
|
||||
password = userinfo.slice(sepIndex + 1); //一些链接用明文uuid做密码
|
||||
}
|
||||
}
|
||||
var url = new URL("http://" + url0 + (param ? "#" + encodeURIComponent(param) : ""));
|
||||
|
||||
} catch(e) {
|
||||
alert(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (isURLEncodedPassword(password)) {
|
||||
password = decodeURIComponent(password); // 解码URL编码
|
||||
} else {
|
||||
password = password; // 保持原始值
|
||||
}
|
||||
|
||||
// === 填充配置项 ===
|
||||
var has_ss_type = (ss_type === "ss-rust") ? "ss-rust" : "ss-libev";
|
||||
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = ssu[0];
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.has_ss_type')[0].value = has_ss_type;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.has_ss_type')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = server;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = port;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = password || "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].value = method;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.encrypt_method_ss')[0].dispatchEvent(event);
|
||||
|
||||
if (plugin && plugin !== "none") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_plugin')[0].checked = true; // 设置 enable_plugin 为 true
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_plugin')[0].dispatchEvent(event); // 触发事件
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin')[0].value = plugin;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin')[0].dispatchEvent(event);
|
||||
if (plugin !== undefined) {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.plugin_opts')[0].value = pluginOpts || "";
|
||||
// Check if the elements exist before trying to modify them
|
||||
function setElementValue(name, value) {
|
||||
const element = document.getElementsByName(name)[0];
|
||||
if (element) {
|
||||
if (typeof value === 'boolean') {
|
||||
element.checked = value;
|
||||
} else {
|
||||
element.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_plugin')[0].checked = false;
|
||||
}
|
||||
function dispatchEventIfExists(name, event) {
|
||||
const element = document.getElementsByName(name)[0];
|
||||
if (element) {
|
||||
element.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.alias', url.hash ? decodeURIComponent(url.hash.slice(1)) : "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.type', "v2ray");
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.type', event);
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.v2ray_protocol', "shadowsocks");
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.v2ray_protocol', event);
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.server', url.hostname);
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.server_port', url.port || "80");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.password', password || url.username);
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.transport',
|
||||
params.type === "http" ? "h2" :
|
||||
(["xhttp", "splithttp"].includes(params.type) ? "xhttp" :
|
||||
(["tcp", "raw"].includes(params.type) ? "raw" :
|
||||
(params.type || "raw")))
|
||||
);
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.transport', event);
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.encrypt_method_ss', method || params.encryption || "none");
|
||||
if ([ "tls", "xtls", "reality" ].includes(params.security)) {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.' + params.security, true);
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.' + params.security, event);
|
||||
|
||||
if (param != undefined) {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURIComponent(param);
|
||||
if (params.security === "tls") {
|
||||
if (params.ech && params.ech.trim() !== "") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.enable_ech', true); // 设置 enable_ech 为 true
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.enable_ech', event); // 触发事件
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.ech_config', params.ech || "");
|
||||
}
|
||||
if (params.allowInsecure === "1") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.insecure', true); // 设置 insecure 为 true
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.insecure', event); // 触发事件
|
||||
}
|
||||
}
|
||||
if (params.security === "reality") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.reality_publickey', params.pbk ? decodeURIComponent(params.pbk) : "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.reality_shortid', params.sid || "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.reality_spiderx', params.spx ? decodeURIComponent(params.spx) : "");
|
||||
if (params.pqv && params.pqv.trim() !== "") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.enable_mldsa65verify', true); // 设置 enable_mldsa65verify 为 true
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.enable_mldsa65verify', event); // 触发事件
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.reality_mldsa65verify', params.pqv || "");
|
||||
}
|
||||
}
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.tls_flow', params.flow || "none");
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.tls_flow', event);
|
||||
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.tls_alpn', params.alpn || "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.fingerprint', params.fp || "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.tls_host', params.sni || "");
|
||||
}
|
||||
switch (params.type) {
|
||||
case "ws":
|
||||
if (params.security !== "tls") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.ws_host', params.host ? decodeURIComponent(params.host) : "");
|
||||
}
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.ws_path', params.path ? decodeURIComponent(params.path) : "/");
|
||||
break;
|
||||
case "httpupgrade":
|
||||
if (params.security !== "tls") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.httpupgrade_host', params.host ? decodeURIComponent(params.host) : "");
|
||||
}
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.httpupgrade_path', params.path ? decodeURIComponent(params.path) : "/");
|
||||
break;
|
||||
case "xhttp":
|
||||
case "splithttp":
|
||||
if (params.security !== "tls") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_host', params.host ? decodeURIComponent(params.host) : "");
|
||||
}
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_mode', params.mode || "auto");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_path', params.path ? decodeURIComponent(params.path) : "/");
|
||||
if (params.extra && params.extra.trim() !== "") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra', true); // 设置 enable_xhttp_extra 为 true
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra', event); // 触发事件
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_extra', params.extra || "");
|
||||
}
|
||||
break;
|
||||
case "kcp":
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.kcp_guise', params.headerType || "none");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.seed', params.seed || "");
|
||||
break;
|
||||
case "http":
|
||||
/* this is non-standard, bullshit */
|
||||
case "h2":
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.h2_host', params.host ? decodeURIComponent(params.host) : "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.h2_path', params.path ? decodeURIComponent(params.path) : "");
|
||||
break;
|
||||
case "quic":
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.quic_guise', params.headerType || "none");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.quic_security', params.quicSecurity || "none");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.quic_key', params.key || "");
|
||||
break;
|
||||
case "grpc":
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.serviceName', params.serviceName || "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.grpc_mode', params.mode || "gun");
|
||||
break;
|
||||
case "tcp":
|
||||
case "raw":
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.tcp_guise', params.headerType || "none");
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.tcp_guise', event);
|
||||
if (params.headerType === "http") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.http_host', params.host ? decodeURIComponent(params.host) : "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.http_path', params.path ? decodeURIComponent(params.path) : "");
|
||||
}
|
||||
break;
|
||||
}
|
||||
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
|
||||
return false;
|
||||
}
|
||||
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
|
||||
return false;
|
||||
case "ssr":
|
||||
var sstr = b64decsafe((ssu[1] || "").replace(/#.*/, "").trim());
|
||||
var ploc = sstr.indexOf("/?");
|
||||
@@ -349,7 +482,7 @@ function import_ssr_url(btn, urlname, sid) {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.protocol_param')[0].value = dictvalue(pdict, 'protoparam');
|
||||
var rem = pdict['remarks'];
|
||||
if (typeof (rem) != 'undefined' && rem != '' && rem.length > 0) document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = b64decutf8safe(rem);
|
||||
s.innerHTML = "<font color='green'><%:Import configuration information successfully.%></font>";
|
||||
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
|
||||
return false;
|
||||
case "trojan":
|
||||
try {
|
||||
@@ -360,93 +493,117 @@ function import_ssr_url(btn, urlname, sid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = url.hash ? decodeURIComponent(url.hash.slice(1)) : "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "v2ray";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].value = "trojan";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = url.hostname;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = url.port || "80";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = decodeURIComponent(url.username);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].checked = true;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = params.get("sni");
|
||||
if (params.get("allowInsecure") === "1") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = true; // 设置 insecure 为 true
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].dispatchEvent(event); // 触发事件
|
||||
}
|
||||
if (params.get("ech") && params.get("ech").trim() !== "") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_ech')[0].checked = true; // 设置 enable_ech 为 true
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_ech')[0].dispatchEvent(event); // 触发事件
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ech_config')[0].value = params.get("ech");
|
||||
|
||||
}
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].value =
|
||||
params.get("type") == "http" ? "h2" :
|
||||
(["xhttp", "splithttp"].includes(params.get("type")) ? "xhttp" :
|
||||
(["tcp", "raw"].includes(params.get("type")) ? "raw" :
|
||||
(params.get("type") || "raw")));
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].dispatchEvent(event);
|
||||
if (params.get("security") === "tls") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_alpn')[0].value = params.get("alpn") || "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.fingerprint')[0].value = params.get("fp") || "";
|
||||
}
|
||||
switch (params.get("type")) {
|
||||
case "ws":
|
||||
if (params.get("security") !== "tls") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ws_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
|
||||
if (!params.get("type")) {
|
||||
// 普通 Trojan 导入逻辑
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = url.hash ? decodeURIComponent(url.hash.slice(1)) : "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "trojan";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = url.hostname;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = url.port || "80";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = decodeURIComponent(url.username);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].checked = true;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = params.get("peer") || params.get("sni");
|
||||
if (params.get("allowInsecure") === "1") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = true; // 设置 insecure 为 true
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].dispatchEvent(event); // 触发事件
|
||||
}
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ws_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
|
||||
break;
|
||||
case "httpupgrade":
|
||||
if (params.get("security") !== "tls") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.httpupgrade_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
|
||||
if (params.get("tfo") === "1") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.fast_open')[0].checked = true; // 设置 fast_open 为 true
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.fast_open')[0].dispatchEvent(event); // 触发事件
|
||||
}
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.httpupgrade_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
|
||||
break;
|
||||
case "xhttp":
|
||||
case "splithttp":
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_mode')[0].value = params.get("mode") || "auto";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
|
||||
if (params.get("extra") && params.get("extra").trim() !== "") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra')[0].checked = true; // 设置 enable_xhttp_extra 为 true
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra')[0].dispatchEvent(event); // 触发事件
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_extra')[0].value = params.get("extra") || "";
|
||||
}
|
||||
break;
|
||||
case "kcp":
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.kcp_guise')[0].value = params.get("headerType") || "none";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.seed')[0].value = params.get("seed") || "";
|
||||
break;
|
||||
case "http":
|
||||
/* this is non-standard, bullshit */
|
||||
case "h2":
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.h2_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.h2_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
|
||||
break;
|
||||
case "quic":
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_guise')[0].value = params.get("headerType") || "none";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_security')[0].value = params.get("quicSecurity") || "none";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_key')[0].value = params.get("key") || "";
|
||||
break;
|
||||
case "grpc":
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.serviceName')[0].value = params.get("serviceName") || "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.grpc_mode')[0].value = params.get("mode") || "gun";
|
||||
break;
|
||||
case "raw":
|
||||
case "tcp":
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tcp_guise')[0].value = params.get("headerType") || "none";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tcp_guise')[0].dispatchEvent(event);
|
||||
if (params.get("headerType") === "http") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
s.innerHTML = "<font color='green'><%:Import configuration information successfully.%></font>";
|
||||
return false;
|
||||
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
|
||||
return false;
|
||||
} else {
|
||||
// Xray Trojan 导入逻辑
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = url.hash ? decodeURIComponent(url.hash.slice(1)) : "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "v2ray";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].value = "trojan";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = url.hostname;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = url.port || "80";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = decodeURIComponent(url.username);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].checked = true;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = params.get("sni");
|
||||
if (params.get("allowInsecure") === "1") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = true; // 设置 insecure 为 true
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].dispatchEvent(event); // 触发事件
|
||||
}
|
||||
if (params.get("ech") && params.get("ech").trim() !== "") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_ech')[0].checked = true; // 设置 enable_ech 为 true
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_ech')[0].dispatchEvent(event); // 触发事件
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ech_config')[0].value = params.get("ech");
|
||||
}
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].value =
|
||||
params.get("type") == "http" ? "h2" :
|
||||
(["xhttp", "splithttp"].includes(params.get("type")) ? "xhttp" :
|
||||
(["tcp", "raw"].includes(params.get("type")) ? "raw" :
|
||||
(params.get("type") || "raw")));
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].dispatchEvent(event);
|
||||
if (params.get("security") === "tls") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_alpn')[0].value = params.get("alpn") || "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.fingerprint')[0].value = params.get("fp") || "";
|
||||
}
|
||||
switch (params.get("type")) {
|
||||
case "ws":
|
||||
if (params.get("security") !== "tls") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ws_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
|
||||
}
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ws_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
|
||||
break;
|
||||
case "httpupgrade":
|
||||
if (params.get("security") !== "tls") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.httpupgrade_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
|
||||
}
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.httpupgrade_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
|
||||
break;
|
||||
case "xhttp":
|
||||
case "splithttp":
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_mode')[0].value = params.get("mode") || "auto";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
|
||||
if (params.get("extra") && params.get("extra").trim() !== "") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra')[0].checked = true; // 设置 enable_xhttp_extra 为 true
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra')[0].dispatchEvent(event); // 触发事件
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.xhttp_extra')[0].value = params.get("extra") || "";
|
||||
}
|
||||
break;
|
||||
case "kcp":
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.kcp_guise')[0].value = params.get("headerType") || "none";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.seed')[0].value = params.get("seed") || "";
|
||||
break;
|
||||
case "http":
|
||||
/* this is non-standard, bullshit */
|
||||
case "h2":
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.h2_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.h2_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
|
||||
break;
|
||||
case "quic":
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_guise')[0].value = params.get("headerType") || "none";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_security')[0].value = params.get("quicSecurity") || "none";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_key')[0].value = params.get("key") || "";
|
||||
break;
|
||||
case "grpc":
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.serviceName')[0].value = params.get("serviceName") || "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.grpc_mode')[0].value = params.get("mode") || "gun";
|
||||
break;
|
||||
case "raw":
|
||||
case "tcp":
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tcp_guise')[0].value = params.get("headerType") || "none";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tcp_guise')[0].dispatchEvent(event);
|
||||
if (params.get("headerType") === "http") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
|
||||
return false;
|
||||
}
|
||||
case "vmess":
|
||||
var sstr = b64DecodeUnicode((ssu[1] || "").replace(/#.*/, "").trim());
|
||||
var ploc = sstr.indexOf("/?");
|
||||
@@ -532,7 +689,7 @@ function import_ssr_url(btn, urlname, sid) {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.mux')[0].checked = true;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.mux')[0].dispatchEvent(event);
|
||||
}
|
||||
s.innerHTML = "<font color='green'><%:Import configuration information successfully.%></font>";
|
||||
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
|
||||
return false;
|
||||
case "vless":
|
||||
try {
|
||||
@@ -664,153 +821,85 @@ function import_ssr_url(btn, urlname, sid) {
|
||||
}
|
||||
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
|
||||
return false;
|
||||
case "shadowsocks":
|
||||
try {
|
||||
// 处理完整 ss:// 链接
|
||||
var urlinfo = ssu[1];
|
||||
// 拆分 @,判断是否是 base64 userinfo 的格式
|
||||
var parts = urlinfo.split("@");
|
||||
if (parts.length > 1) {
|
||||
// @ 前是 base64(method:password),后面是 server:port?params
|
||||
var userinfo = b64decsafe(parts[0]);
|
||||
var sepIndex = userinfo.indexOf(":");
|
||||
if (sepIndex > -1) {
|
||||
method = userinfo.slice(0, sepIndex);
|
||||
password = userinfo.slice(sepIndex + 1); //一些链接用明文uuid做密码
|
||||
}
|
||||
}
|
||||
var url = new URL("http://" + urlinfo);
|
||||
case "tuic":
|
||||
var url0 = (ssu[1] || "");
|
||||
var param = "";
|
||||
|
||||
var params = url.searchParams;
|
||||
// 先分离 #(alias)
|
||||
var hashIndex = url0.indexOf("#");
|
||||
if (hashIndex >= 0) {
|
||||
param = url0.substring(hashIndex + 1);
|
||||
url0 = url0.substring(0, hashIndex);
|
||||
}
|
||||
|
||||
} catch(e) {
|
||||
alert(e);
|
||||
return false;
|
||||
// 再分离 ? 或 /?(参数)
|
||||
var queryIndex = (url0 = url0.replace('/?', '?')).indexOf("?");
|
||||
var query = "";
|
||||
if (queryIndex >= 0) {
|
||||
query = url0.substring(queryIndex + 1);
|
||||
url0 = url0.substring(0, queryIndex);
|
||||
}
|
||||
// Check if the elements exist before trying to modify them
|
||||
function setElementValue(name, value) {
|
||||
const element = document.getElementsByName(name)[0];
|
||||
if (element) {
|
||||
if (typeof value === 'boolean') {
|
||||
element.checked = value;
|
||||
} else {
|
||||
element.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
function dispatchEventIfExists(name, event) {
|
||||
const element = document.getElementsByName(name)[0];
|
||||
if (element) {
|
||||
element.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.alias', url.hash ? decodeURIComponent(url.hash.slice(1)) : "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.type', "v2ray");
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.type', event);
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.v2ray_protocol', "shadowsocks");
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.v2ray_protocol', event);
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.server', url.hostname);
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.server_port', url.port || "80");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.password', password || url.username);
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.transport',
|
||||
params.get("type") === "http" ? "h2" :
|
||||
(["xhttp", "splithttp"].includes(params.get("type")) ? "xhttp" :
|
||||
(["tcp", "raw"].includes(params.get("type")) ? "raw" :
|
||||
(params.get("type") || "raw")))
|
||||
);
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.transport', event);
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.encrypt_method_ss', method || params.get("encryption") || "none");
|
||||
if ([ "tls", "xtls", "reality" ].includes(params.get("security"))) {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.' + params.get("security"), true);
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.' + params.get("security"), event);
|
||||
|
||||
if (params.get("security") === "tls") {
|
||||
if (params.get("ech") && params.get("ech").trim() !== "") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.enable_ech', true); // 设置 enable_ech 为 true
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.enable_ech', event); // 触发事件
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.ech_config', params.get("ech") || "");
|
||||
}
|
||||
if (params.get("allowInsecure") === "1") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.insecure', true); // 设置 insecure 为 true
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.insecure', event); // 触发事件
|
||||
}
|
||||
}
|
||||
if (params.get("security") === "reality") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.reality_publickey', params.get("pbk") ? decodeURIComponent(params.get("pbk")) : "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.reality_shortid', params.get("sid") || "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.reality_spiderx', params.get("spx") ? decodeURIComponent(params.get("spx")) : "");
|
||||
if (params.get("pqv") && params.get("pqv").trim() !== "") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.enable_mldsa65verify', true); // 设置 enable_mldsa65verify 为 true
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.enable_mldsa65verify', event); // 触发事件
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.reality_mldsa65verify', params.get("pqv") || "");
|
||||
}
|
||||
}
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.tls_flow', params.get("flow") || "none");
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.tls_flow', event);
|
||||
var params = Object.fromEntries(new URLSearchParams(query));
|
||||
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.tls_alpn', params.get("alpn") || "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.fingerprint', params.get("fp") || "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.tls_host', params.get("sni") || "");
|
||||
}
|
||||
switch (params.get("type")) {
|
||||
case "ws":
|
||||
if (params.get("security") !== "tls") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.ws_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
|
||||
}
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.ws_path', params.get("path") ? decodeURIComponent(params.get("path")) : "/");
|
||||
break;
|
||||
case "httpupgrade":
|
||||
if (params.get("security") !== "tls") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.httpupgrade_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
|
||||
}
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.httpupgrade_path', params.get("path") ? decodeURIComponent(params.get("path")) : "/");
|
||||
break;
|
||||
case "xhttp":
|
||||
case "splithttp":
|
||||
if (params.get("security") !== "tls") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
|
||||
}
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_mode', params.get("mode") || "auto");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_path', params.get("path") ? decodeURIComponent(params.get("path")) : "/");
|
||||
if (params.get("extra") && params.get("extra").trim() !== "") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra', true); // 设置 enable_xhttp_extra 为 true
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.enable_xhttp_extra', event); // 触发事件
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.xhttp_extra', params.get("extra") || "");
|
||||
}
|
||||
break;
|
||||
case "kcp":
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.kcp_guise', params.get("headerType") || "none");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.seed', params.get("seed") || "");
|
||||
break;
|
||||
case "http":
|
||||
/* this is non-standard, bullshit */
|
||||
case "h2":
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.h2_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.h2_path', params.get("path") ? decodeURIComponent(params.get("path")) : "");
|
||||
break;
|
||||
case "quic":
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.quic_guise', params.get("headerType") || "none");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.quic_security', params.get("quicSecurity") || "none");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.quic_key', params.get("key") || "");
|
||||
break;
|
||||
case "grpc":
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.serviceName', params.get("serviceName") || "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.grpc_mode', params.get("mode") || "gun");
|
||||
break;
|
||||
case "tcp":
|
||||
case "raw":
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.tcp_guise', params.get("headerType") || "none");
|
||||
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.tcp_guise', event);
|
||||
if (params.get("headerType") === "http") {
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.http_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
|
||||
setElementValue('cbid.shadowsocksr.' + sid + '.http_path', params.get("path") ? decodeURIComponent(params.get("path")) : "");
|
||||
}
|
||||
var sipIndex = url0.indexOf("@");
|
||||
var userInfo = url0.substring(0, sipIndex); // 格式:uuid:password
|
||||
var hostPart = url0.substring(sipIndex + 1); // 格式:hostname:port
|
||||
var userInfoSplitIndex = userInfo.indexOf(":");
|
||||
if(userInfoSplitIndex < 0) {
|
||||
// 格式错误
|
||||
s.innerHTML = "<font style='color:red'><%:Userinfo format error.%></font>";
|
||||
break;
|
||||
}
|
||||
s.innerHTML = "<font color='green'><%:Import configuration information successfully.%></font>";
|
||||
|
||||
var method = userInfo.substring(0, userInfoSplitIndex);
|
||||
var password = userInfo.substring(userInfoSplitIndex + 1);
|
||||
|
||||
var url = new URL("http://" + hostPart); // 用 URL 提取 host 与 port
|
||||
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = ssu[0];
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = url.hostname;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = url.port;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_uuid')[0].value = method;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_ip')[0].value = params.ip || "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_passwd')[0].value = password;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.udp_relay_mode')[0].value = params.udp_relay_mode || "native";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.congestion_control')[0].value = params.congestion_control || "cubic";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_alpn')[0].value = params.alpn || "";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.heartbeat')[0].value = params.heartbeat || "3";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.timeout')[0].value = params.timeout || "8";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.gc_interval')[0].value = params.gc_interval || "3";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.gc_lifetime')[0].value = params.gc_lifetime || "15";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.send_window')[0].value = params.send_window || "20971520";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.receive_window')[0].value = params.receive_window || "10485760";
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_max_package_size')[0].value = params.max_packet_size || "1500";
|
||||
if (params["disable_sni"] === "1" || params["disable_sni"] === "true") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.disable_sni')[0].checked = true;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.disable_sni')[0].dispatchEvent(event);
|
||||
}
|
||||
if (params["zero_rtt_handshake"] === "1" || params["zero_rtt_handshake"] === "true") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.zero_rtt_handshake')[0].checked = true;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.zero_rtt_handshake')[0].dispatchEvent(event);
|
||||
}
|
||||
if (params["dual_stack"] === "1" || params["dual_stack"] === "true") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_dual_stack')[0].checked = true;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_dual_stack')[0].dispatchEvent(event);
|
||||
if (params.ipstack_prefer && params.ipstack_prefer.trim() !== "") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ipstack_prefer')[0].value = params.ipstack_prefer;
|
||||
}
|
||||
}
|
||||
if (params["allowInsecure"] === "1" || params["allowInsecure"] === "true") {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = true;
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].dispatchEvent(event);
|
||||
}
|
||||
if (param != undefined) {
|
||||
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURIComponent(param);
|
||||
}
|
||||
s.innerHTML = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
|
||||
return false;
|
||||
default:
|
||||
s.innerHTML = "<font color='red'><%:Invalid format.%></font>";
|
||||
s.innerHTML = "<font style=\'color:red\'><%:Invalid format.%></font>";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1258,8 +1258,18 @@ start_server() {
|
||||
[ "$(uci_get_by_name $1 enable 0)" == "0" ] && return 1
|
||||
let server_count=server_count+1
|
||||
if [ "$server_count" == "1" ]; then
|
||||
if ! (iptables-save -t filter | grep SSR-SERVER-RULE >/dev/null); then
|
||||
iptables -N SSR-SERVER-RULE && iptables -t filter -I INPUT -j SSR-SERVER-RULE
|
||||
if command -v nft >/dev/null 2>&1; then
|
||||
# nftables / fw4
|
||||
if ! nft list chain inet fw4 SSR-SERVER-RULE >/dev/null 2>&1; then
|
||||
nft add chain inet fw4 SSR-SERVER-RULE
|
||||
nft insert rule inet fw4 input jump SSR-SERVER-RULE
|
||||
fi
|
||||
else
|
||||
# iptables / fw3
|
||||
if ! (iptables-save -t filter | grep -q "SSR-SERVER-RULE"); then
|
||||
iptables -N SSR-SERVER-RULE
|
||||
iptables -t filter -I INPUT -j SSR-SERVER-RULE
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
local type=$(uci_get_by_name $1 type)
|
||||
@@ -1287,17 +1297,15 @@ start_server() {
|
||||
echolog "Server:Socks5 Server$server_count Started!"
|
||||
;;
|
||||
esac
|
||||
ssr_server_port=$(uci show shadowsocksr | grep 'server_config.*server_port' | awk -F"'" '{print $2}' | tr "\n" " ")
|
||||
if [ -n "$ssr_server_port" ]; then
|
||||
uci -q delete firewall.shadowsocksr_server
|
||||
uci set firewall.shadowsocksr_server=rule
|
||||
uci set firewall.shadowsocksr_server.name="shadowsocksr_server"
|
||||
uci set firewall.shadowsocksr_server.target="ACCEPT"
|
||||
uci set firewall.shadowsocksr_server.src="wan"
|
||||
uci set firewall.shadowsocksr_server.dest_port="$ssr_server_port"
|
||||
uci set firewall.shadowsocksr_server.enabled="1"
|
||||
uci commit firewall
|
||||
/etc/init.d/firewall reload >/dev/null 2>&1
|
||||
server_port=$(uci_get_by_name $1 server_port)
|
||||
if command -v nft >/dev/null 2>&1; then
|
||||
# nftables / fw4
|
||||
nft add rule inet fw4 SSR-SERVER-RULE tcp dport $server_port accept
|
||||
nft add rule inet fw4 SSR-SERVER-RULE udp dport $server_port accept
|
||||
else
|
||||
# iptables / fw3
|
||||
iptables -t filter -A SSR-SERVER-RULE -p tcp --dport $server_port -j ACCEPT
|
||||
iptables -t filter -A SSR-SERVER-RULE -p udp --dport $server_port -j ACCEPT
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
@@ -1307,17 +1315,37 @@ start_server() {
|
||||
if [ ! -f $FWI ]; then
|
||||
echo '#!/bin/sh' >$FWI
|
||||
fi
|
||||
extract_rules() {
|
||||
echo "*filter"
|
||||
iptables-save -t filter | grep SSR-SERVER-RULE | sed -e "s/^-A INPUT/-I INPUT/"
|
||||
echo 'COMMIT'
|
||||
}
|
||||
cat <<-EOF >>$FWI
|
||||
iptables-save -c | grep -v "SSR-SERVER" | iptables-restore -c
|
||||
iptables-restore -n <<-EOT
|
||||
$(extract_rules)
|
||||
EOT
|
||||
EOF
|
||||
if command -v nft >/dev/null 2>&1; then
|
||||
# nftables / fw4
|
||||
extract_rules() {
|
||||
nft list chain inet fw4 SSR-SERVER-RULE 2>/dev/null | \
|
||||
grep -v 'chain SSR-SERVER-RULE' | grep -v '^\s*{' | grep -v '^\s*}' | sed 's/ counter//g'
|
||||
}
|
||||
cat <<-EOF >>$FWI
|
||||
nft flush chain inet fw4 SSR-SERVER-RULE 2>/dev/null || true
|
||||
nft -f - <<-EOT
|
||||
table inet fw4 {
|
||||
chain SSR-SERVER-RULE {
|
||||
type filter hook input priority 0; policy accept;
|
||||
$(extract_rules)
|
||||
}
|
||||
}
|
||||
EOT
|
||||
EOF
|
||||
else
|
||||
# iptables / fw3
|
||||
extract_rules() {
|
||||
echo "*filter"
|
||||
iptables-save -t filter | grep SSR-SERVER-RULE | sed -e "s/^-A INPUT/-I INPUT/"
|
||||
echo 'COMMIT'
|
||||
}
|
||||
cat <<-EOF >>$FWI
|
||||
iptables-save -c | grep -v "SSR-SERVER" | iptables-restore -c
|
||||
iptables-restore -n <<-EOT
|
||||
$(extract_rules)
|
||||
EOT
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
config_load $NAME
|
||||
@@ -1455,6 +1483,28 @@ stop() {
|
||||
unlock
|
||||
set_lock
|
||||
/usr/bin/ssr-rules -f
|
||||
if command -v nft >/dev/null 2>&1; then
|
||||
# nftables / fw4
|
||||
#local srulecount=$(nft list ruleset 2>/dev/null | grep -c 'SSR-SERVER-RULE')
|
||||
#local srulecount=$(nft list chain inet fw4 SSR-SERVER-RULE 2>/dev/null | grep -c 'dport')
|
||||
local srulecount=$(nft list chain inet fw4 SSR-SERVER-RULE | grep -vE '^\s*(chain|{|})' | wc -l)
|
||||
else
|
||||
# iptables / fw3
|
||||
local srulecount=$(iptables -L | grep SSR-SERVER-RULE | wc -l)
|
||||
fi
|
||||
if [ $srulecount -gt 0 ]; then
|
||||
if command -v nft >/dev/null 2>&1; then
|
||||
# nftables / fw4
|
||||
nft flush chain inet fw4 SSR-SERVER-RULE 2>/dev/null || true
|
||||
nft delete rule inet fw4 input jump SSR-SERVER-RULE 2>/dev/null || true
|
||||
nft delete chain inet fw4 SSR-SERVER-RULE 2>/dev/null || true
|
||||
else
|
||||
# iptables / fw3
|
||||
iptables -F SSR-SERVER-RULE
|
||||
iptables -t filter -D INPUT -j SSR-SERVER-RULE
|
||||
iptables -X SSR-SERVER-RULE 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
if [ -z "$switch_server" ]; then
|
||||
$PS -w | grep -v "grep" | grep ssr-switch | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 &
|
||||
rm -f /var/lock/ssr-switch.lock
|
||||
@@ -1465,7 +1515,7 @@ stop() {
|
||||
( \
|
||||
# Graceful kill first, so programs have the chance to stop its subprocesses
|
||||
$PS -w | grep -v "grep" | grep "$TMP_PATH" | awk '{print $1}' | xargs kill >/dev/null 2>&1 ; \
|
||||
sleep 1s; \
|
||||
sleep 3s; \
|
||||
# Force kill hanged programs
|
||||
$PS -w | grep -v "grep" | grep "$TMP_PATH" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 ; \
|
||||
)
|
||||
@@ -1488,9 +1538,6 @@ stop() {
|
||||
|
||||
/etc/init.d/dnsmasq restart >/dev/null 2>&1
|
||||
fi
|
||||
uci -q delete firewall.shadowsocksr_server
|
||||
uci commit firewall
|
||||
/etc/init.d/firewall reload >/dev/null 2>&1
|
||||
del_cron
|
||||
unset_lock
|
||||
}
|
||||
|
||||
@@ -1,37 +1,7 @@
|
||||
aaplimg.com
|
||||
account.synology.com
|
||||
apple-cloudkit.com
|
||||
apple.co
|
||||
apple.com
|
||||
apple.com.cn
|
||||
appstore.com
|
||||
bilibili.com
|
||||
bilibili.cn
|
||||
bilivideo.com
|
||||
bilivideo.cn
|
||||
biliapi.com
|
||||
biliapi.net
|
||||
bilibili.cn
|
||||
bilibili.com
|
||||
bilivideo.cn
|
||||
bilivideo.com
|
||||
bing.com
|
||||
cdn-apple.com
|
||||
checkip.dyndns.org
|
||||
checkip.synology.com
|
||||
checkipv6.synology.com
|
||||
checkport.synology.com
|
||||
crashlytics.com
|
||||
ddns.synology.com
|
||||
gitmirror.com
|
||||
icloud-content.com
|
||||
icloud.com
|
||||
icloud.com.cn
|
||||
images-cn.ssl-images-amazon.com
|
||||
mirrorlist.centos.org
|
||||
mzstatic.com
|
||||
office365.com
|
||||
officecdn-microsoft-com.akamaized.net
|
||||
teamviewer.com
|
||||
whatismyip.akamai.com
|
||||
windows.com
|
||||
windowsupdate.com
|
||||
worldbank.org
|
||||
worldscientific.com
|
||||
www-cdn.icloud.com.akadns.net
|
||||
apple.com
|
||||
@@ -9,12 +9,12 @@
|
||||
|
||||
# Detect firewall version and set appropriate tools
|
||||
detect_firewall() {
|
||||
if command -v fw4 >/dev/null 2>&1 && [ -f /usr/share/nftables.d/ruleset-post/99-shadowsocksr.nft ]; then
|
||||
USE_NFT=1
|
||||
NFT="nft"
|
||||
elif command -v nft >/dev/null 2>&1 && [ "$(uci get firewall.@defaults[0].syn_flood 2>/dev/null)" != "" ] && [ ! -f /etc/config/firewall3 ]; then
|
||||
USE_NFT=1
|
||||
NFT="nft"
|
||||
if command -v nft >/dev/null 2>&1 && \
|
||||
[ -n "$(uci get firewall.@defaults[0].syn_flood 2>/dev/null)" ] && \
|
||||
! grep -q "fw3" /etc/init.d/firewall 2>/dev/null; then
|
||||
USE_NFT=1
|
||||
NFT="nft"
|
||||
FWI=$(uci get firewall.shadowsocksr.path 2>/dev/null) # firewall include file
|
||||
else
|
||||
USE_NFT=0
|
||||
IPT="iptables -t nat" # alias of iptables
|
||||
@@ -26,6 +26,7 @@ detect_firewall() {
|
||||
detect_firewall
|
||||
|
||||
TAG="_SS_SPEC_RULE_" # comment tag
|
||||
|
||||
usage() {
|
||||
cat <<-EOF
|
||||
Usage: ssr-rules [options]
|
||||
@@ -83,10 +84,14 @@ flush_r() {
|
||||
flush_nftables() {
|
||||
# Remove nftables rules and sets
|
||||
$NFT delete table inet ss_spec 2>/dev/null
|
||||
$NFT delete table ip ss_spec 2>/dev/null
|
||||
$NFT delete table ip ss_spec_mangle 2>/dev/null
|
||||
|
||||
# Clean up routing rules
|
||||
ip rule del fwmark 0x01/0x01 table 100 2>/dev/null
|
||||
ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null
|
||||
|
||||
[ -n "$FWI" ] && echo '#!/bin/sh' >"$FWI"
|
||||
|
||||
return 0
|
||||
}
|
||||
@@ -128,43 +133,43 @@ ipset_r() {
|
||||
}
|
||||
|
||||
ipset_nft() {
|
||||
[ -f "$IGNORE_LIST" ] && /usr/share/shadowsocksr/chinaipset.sh $IGNORE_LIST
|
||||
[ -f "$IGNORE_LIST" ] && /usr/share/shadowsocksr/chinaipset.sh "$IGNORE_LIST"
|
||||
|
||||
# Create nftables table and sets
|
||||
$NFT add table inet ss_spec 2>/dev/null
|
||||
$NFT add set inet ss_spec ss_spec_wan_ac { type ipv4_addr\; flags interval\; } 2>/dev/null
|
||||
$NFT add set inet ss_spec gmlan { type ipv4_addr\; flags interval\; } 2>/dev/null
|
||||
$NFT add set inet ss_spec fplan { type ipv4_addr\; flags interval\; } 2>/dev/null
|
||||
$NFT add set inet ss_spec bplan { type ipv4_addr\; flags interval\; } 2>/dev/null
|
||||
$NFT add set inet ss_spec whitelist { type ipv4_addr\; flags interval\; } 2>/dev/null
|
||||
$NFT add set inet ss_spec blacklist { type ipv4_addr\; flags interval\; } 2>/dev/null
|
||||
$NFT add set inet ss_spec netflix { type ipv4_addr\; flags interval\; } 2>/dev/null
|
||||
$NFT add set inet ss_spec ss_spec_wan_ac '{ type ipv4_addr; flags interval; }' 2>/dev/null
|
||||
$NFT add set inet ss_spec gmlan '{ type ipv4_addr; flags interval; }' 2>/dev/null
|
||||
$NFT add set inet ss_spec fplan '{ type ipv4_addr; flags interval; }' 2>/dev/null
|
||||
$NFT add set inet ss_spec bplan '{ type ipv4_addr; flags interval; }' 2>/dev/null
|
||||
$NFT add set inet ss_spec whitelist '{ type ipv4_addr; flags interval; }' 2>/dev/null
|
||||
$NFT add set inet ss_spec blacklist '{ type ipv4_addr; flags interval; }' 2>/dev/null
|
||||
$NFT add set inet ss_spec netflix '{ type ipv4_addr; flags interval; }' 2>/dev/null
|
||||
|
||||
# Add IP addresses to sets
|
||||
for ip in $LAN_GM_IP; do
|
||||
$NFT add element inet ss_spec gmlan { $ip }
|
||||
$NFT add element inet ss_spec gmlan "{ $ip }"
|
||||
done
|
||||
for ip in $LAN_FP_IP; do
|
||||
$NFT add element inet ss_spec fplan { $ip }
|
||||
$NFT add element inet ss_spec fplan "{ $ip }"
|
||||
done
|
||||
for ip in $LAN_BP_IP; do
|
||||
$NFT add element inet ss_spec bplan { $ip }
|
||||
$NFT add element inet ss_spec bplan "{ $ip }"
|
||||
done
|
||||
for ip in $WAN_BP_IP; do
|
||||
$NFT add element inet ss_spec whitelist { $ip }
|
||||
$NFT add element inet ss_spec whitelist "{ $ip }"
|
||||
done
|
||||
for ip in $WAN_FW_IP; do
|
||||
$NFT add element inet ss_spec blacklist { $ip }
|
||||
$NFT add element inet ss_spec blacklist "{ $ip }"
|
||||
done
|
||||
|
||||
# Create main chain for WAN access control
|
||||
$NFT add chain inet ss_spec ss_spec_wan_ac { type nat hook prerouting priority dstnat\; }
|
||||
$NFT add chain inet ss_spec ss_spec_wan_ac '{ type nat hook prerouting priority dstnat; }' 2>/dev/null
|
||||
$NFT add rule inet ss_spec ss_spec_wan_ac tcp dport 53 ip daddr 127.0.0.0/8 return
|
||||
$NFT add rule inet ss_spec ss_spec_wan_ac tcp dport != 53 ip daddr $server return
|
||||
$NFT add rule inet ss_spec ss_spec_wan_ac tcp dport != 53 ip daddr "$server" return
|
||||
|
||||
# Add special IP ranges to WAN AC set
|
||||
for ip in $(gen_spec_iplist); do
|
||||
$NFT add element inet ss_spec ss_spec_wan_ac { $ip }
|
||||
$NFT add element inet ss_spec ss_spec_wan_ac "{ $ip }"
|
||||
done
|
||||
|
||||
# Set up mode-specific rules
|
||||
@@ -212,19 +217,19 @@ ipset_nft() {
|
||||
|
||||
# Shunt/Netflix rules
|
||||
if [ "$SHUNT_PORT" != "0" ]; then
|
||||
for ip in $(cat ${SHUNT_LIST:=/dev/null} 2>/dev/null); do
|
||||
$NFT add element inet ss_spec netflix { $ip }
|
||||
for ip in $(cat "${SHUNT_LIST:=/dev/null}" 2>/dev/null); do
|
||||
$NFT add element inet ss_spec netflix "{ $ip }"
|
||||
done
|
||||
case "$SHUNT_PORT" in
|
||||
1)
|
||||
$NFT add rule inet ss_spec ss_spec_wan_ac tcp dport $PROXY_PORTS ip daddr @netflix redirect to :$local_port
|
||||
$NFT add rule inet ss_spec ss_spec_wan_ac tcp dport "$PROXY_PORTS" ip daddr @netflix redirect to :"$local_port"
|
||||
;;
|
||||
*)
|
||||
$NFT add rule inet ss_spec ss_spec_wan_ac tcp dport $PROXY_PORTS ip daddr @netflix redirect to :$SHUNT_PORT
|
||||
if [ "$SHUNT_PROXY" == "1" ]; then
|
||||
$NFT add rule inet ss_spec ss_spec_wan_ac tcp dport $PROXY_PORTS ip daddr $SHUNT_IP redirect to :$local_port
|
||||
$NFT add rule inet ss_spec ss_spec_wan_ac tcp dport "$PROXY_PORTS" ip daddr @netflix redirect to :"$SHUNT_PORT"
|
||||
if [ "$SHUNT_PROXY" = "1" ]; then
|
||||
$NFT add rule inet ss_spec ss_spec_wan_ac tcp dport "$PROXY_PORTS" ip daddr "$SHUNT_IP" redirect to :"$local_port"
|
||||
else
|
||||
$NFT add element inet ss_spec whitelist { $SHUNT_IP }
|
||||
$NFT add element inet ss_spec whitelist "{ $SHUNT_IP }"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
@@ -233,12 +238,12 @@ ipset_nft() {
|
||||
}
|
||||
|
||||
ipset_iptables() {
|
||||
[ -f "$IGNORE_LIST" ] && /usr/share/shadowsocksr/chinaipset.sh $IGNORE_LIST
|
||||
[ -f "$IGNORE_LIST" ] && /usr/share/shadowsocksr/chinaipset.sh "$IGNORE_LIST"
|
||||
$IPT -N SS_SPEC_WAN_AC 2>/dev/null
|
||||
$IPT -I SS_SPEC_WAN_AC -p tcp --dport 53 -d 127.0.0.0/8 -j RETURN
|
||||
$IPT -I SS_SPEC_WAN_AC -p tcp ! --dport 53 -d $server -j RETURN
|
||||
$IPT -I SS_SPEC_WAN_AC -p tcp ! --dport 53 -d "$server" -j RETURN
|
||||
ipset -N gmlan hash:net 2>/dev/null
|
||||
for ip in $LAN_GM_IP; do ipset -! add gmlan $ip; done
|
||||
for ip in $LAN_GM_IP; do ipset -! add gmlan "$ip"; done
|
||||
case "$RUNMODE" in
|
||||
router)
|
||||
ipset -! -R <<-EOF || return 1
|
||||
@@ -267,34 +272,34 @@ ipset_iptables() {
|
||||
;;
|
||||
esac
|
||||
ipset -N fplan hash:net 2>/dev/null
|
||||
for ip in $LAN_FP_IP; do ipset -! add fplan $ip; done
|
||||
for ip in $LAN_FP_IP; do ipset -! add fplan "$ip"; done
|
||||
$IPT -I SS_SPEC_WAN_AC -m set --match-set fplan src -j SS_SPEC_WAN_FW
|
||||
ipset -N bplan hash:net 2>/dev/null
|
||||
for ip in $LAN_BP_IP; do ipset -! add bplan $ip; done
|
||||
for ip in $LAN_BP_IP; do ipset -! add bplan "$ip"; done
|
||||
$IPT -I SS_SPEC_WAN_AC -m set --match-set bplan src -j RETURN
|
||||
ipset -N whitelist hash:net 2>/dev/null
|
||||
ipset -N blacklist hash:net 2>/dev/null
|
||||
$IPT -I SS_SPEC_WAN_AC -m set --match-set blacklist dst -j SS_SPEC_WAN_FW
|
||||
$IPT -I SS_SPEC_WAN_AC -m set --match-set whitelist dst -j RETURN
|
||||
if [ $(ipset list music -name -quiet | grep music) ]; then
|
||||
if ipset list music -name -quiet >/dev/null 2>&1; then
|
||||
$IPT -I SS_SPEC_WAN_AC -m set --match-set music dst -j RETURN 2>/dev/null
|
||||
fi
|
||||
for ip in $WAN_BP_IP; do ipset -! add whitelist $ip; done
|
||||
for ip in $WAN_FW_IP; do ipset -! add blacklist $ip; done
|
||||
for ip in $WAN_BP_IP; do ipset -! add whitelist "$ip"; done
|
||||
for ip in $WAN_FW_IP; do ipset -! add blacklist "$ip"; done
|
||||
if [ "$SHUNT_PORT" != "0" ]; then
|
||||
ipset -N netflix hash:net 2>/dev/null
|
||||
for ip in $(cat ${SHUNT_LIST:=/dev/null} 2>/dev/null); do ipset -! add netflix $ip; done
|
||||
for ip in $(cat "${SHUNT_LIST:=/dev/null}" 2>/dev/null); do ipset -! add netflix "$ip"; done
|
||||
case "$SHUNT_PORT" in
|
||||
0) ;;
|
||||
1)
|
||||
$IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports $local_port
|
||||
$IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports "$local_port"
|
||||
;;
|
||||
*)
|
||||
$IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports $SHUNT_PORT
|
||||
if [ "$SHUNT_PROXY" == "1" ]; then
|
||||
$IPT -I SS_SPEC_WAN_AC -p tcp -d $SHUNT_IP -j REDIRECT --to-ports $local_port
|
||||
$IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports "$SHUNT_PORT"
|
||||
if [ "$SHUNT_PROXY" = "1" ]; then
|
||||
$IPT -I SS_SPEC_WAN_AC -p tcp -d "$SHUNT_IP" -j REDIRECT --to-ports "$local_port"
|
||||
else
|
||||
ipset -! add whitelist $SHUNT_IP
|
||||
ipset -! add whitelist "$SHUNT_IP"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
@@ -312,28 +317,38 @@ fw_rule() {
|
||||
}
|
||||
|
||||
fw_rule_nft() {
|
||||
# Create forward chain for nftables
|
||||
$NFT add chain inet ss_spec ss_spec_wan_fw
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 0.0.0.0/8 return
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 10.0.0.0/8 return
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 127.0.0.0/8 return
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 169.254.0.0/16 return
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 172.16.0.0/12 return
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 192.168.0.0/16 return
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 224.0.0.0/4 return
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 240.0.0.0/4 return
|
||||
|
||||
# Create forward chain with better error handling
|
||||
if ! $NFT list chain inet ss_spec ss_spec_wan_fw >/dev/null 2>&1; then
|
||||
$NFT add chain inet ss_spec ss_spec_wan_fw 2>/dev/null || {
|
||||
loger 3 "Failed to create forward chain"
|
||||
return 1
|
||||
}
|
||||
fi
|
||||
|
||||
# Exclude special local addresses
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 0.0.0.0/8 return 2>/dev/null
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 10.0.0.0/8 return 2>/dev/null
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 127.0.0.0/8 return 2>/dev/null
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 169.254.0.0/16 return 2>/dev/null
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 172.16.0.0/12 return 2>/dev/null
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 192.168.0.0/16 return 2>/dev/null
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 224.0.0.0/4 return 2>/dev/null
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw ip daddr 240.0.0.0/4 return 2>/dev/null
|
||||
|
||||
# redirect/translation: when PROXY_PORTS present, redirect those tcp ports to local_port
|
||||
if [ -n "$PROXY_PORTS" ]; then
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw tcp $PROXY_PORTS redirect to :$local_port 2>/dev/null || {
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw tcp dport "$PROXY_PORTS" redirect to :"$local_port" 2>/dev/null || {
|
||||
loger 3 "Can't redirect, please check nftables."
|
||||
exit 1
|
||||
}
|
||||
else
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw tcp dport != 22 redirect to :$local_port 2>/dev/null || {
|
||||
# default: redirect everything except ssh(22)
|
||||
$NFT add rule inet ss_spec ss_spec_wan_fw tcp dport != 22 redirect to :"$local_port" 2>/dev/null || {
|
||||
loger 3 "Can't redirect, please check nftables."
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -347,7 +362,7 @@ fw_rule_iptables() {
|
||||
$IPT -A SS_SPEC_WAN_FW -d 192.168.0.0/16 -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_FW -d 224.0.0.0/4 -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_FW -d 240.0.0.0/4 -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_FW -p tcp $PROXY_PORTS -j REDIRECT --to-ports $local_port 2>/dev/null || {
|
||||
$IPT -A SS_SPEC_WAN_FW -p tcp $PROXY_PORTS -j REDIRECT --to-ports "$local_port" 2>/dev/null || {
|
||||
loger 3 "Can't redirect, please check the iptables."
|
||||
exit 1
|
||||
}
|
||||
@@ -366,13 +381,13 @@ ac_rule() {
|
||||
ac_rule_nft() {
|
||||
local MATCH_SET_CONDITION=""
|
||||
if [ -n "$LAN_AC_IP" ]; then
|
||||
# Create LAN access control set
|
||||
$NFT add set inet ss_spec ss_spec_lan_ac { type ipv4_addr\; flags interval\; } 2>/dev/null
|
||||
for ip in ${LAN_AC_IP:1}; do
|
||||
$NFT add element inet ss_spec ss_spec_lan_ac { $ip }
|
||||
# Create LAN access control set if needed
|
||||
$NFT add set inet ss_spec ss_spec_lan_ac '{ type ipv4_addr; flags interval; }' 2>/dev/null
|
||||
for ip in ${LAN_AC_IP#?}; do
|
||||
[ -n "$ip" ] && $NFT add element inet ss_spec ss_spec_lan_ac "{ $ip }" 2>/dev/null
|
||||
done
|
||||
|
||||
case "${LAN_AC_IP:0:1}" in
|
||||
|
||||
case "${LAN_AC_IP%${LAN_AC_IP#?}}" in
|
||||
w | W)
|
||||
MATCH_SET_CONDITION="ip saddr @ss_spec_lan_ac"
|
||||
;;
|
||||
@@ -385,23 +400,24 @@ ac_rule_nft() {
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Create prerouting rules
|
||||
|
||||
# Build a rule in the prerouting hook chain that jumps to business chain with conditions
|
||||
if [ -z "$Interface" ]; then
|
||||
# generic prerouting jump already exists (see ipset_nft), but if we have MATCH_SET_CONDITION we add a more specific rule
|
||||
if [ -n "$MATCH_SET_CONDITION" ]; then
|
||||
$NFT add rule inet ss_spec ss_spec_wan_ac tcp dport $EXT_ARGS $MATCH_SET_CONDITION comment "\"$TAG\"" goto ss_spec_wan_ac
|
||||
else
|
||||
$NFT add rule inet ss_spec ss_spec_wan_ac tcp dport $EXT_ARGS comment "\"$TAG\"" goto ss_spec_wan_ac
|
||||
# add a more specific rule at the top of ss_spec_prerouting
|
||||
$NFT insert rule inet ss_spec ss_spec_prerouting tcp $MATCH_SET_CONDITION comment "\"$TAG\"" jump ss_spec_wan_ac 2>/dev/null
|
||||
fi
|
||||
else
|
||||
# For each Interface, find its actual ifname and add an iifname-limited prerouting rule
|
||||
for name in $Interface; do
|
||||
local IFNAME=$(uci -P /var/state get network.$name.ifname 2>/dev/null)
|
||||
[ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network.$name.device 2>/dev/null)
|
||||
local IFNAME=$(uci -P /var/state get network."$name".ifname 2>/dev/null)
|
||||
[ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network."$name".device 2>/dev/null)
|
||||
if [ -n "$IFNAME" ]; then
|
||||
if [ -n "$MATCH_SET_CONDITION" ]; then
|
||||
$NFT add rule inet ss_spec ss_spec_wan_ac iifname $IFNAME tcp dport $EXT_ARGS $MATCH_SET_CONDITION comment "\"$TAG\"" goto ss_spec_wan_ac
|
||||
$NFT insert rule inet ss_spec ss_spec_prerouting iifname "$IFNAME" tcp $MATCH_SET_CONDITION comment "\"$TAG\"" jump ss_spec_wan_ac 2>/dev/null
|
||||
else
|
||||
$NFT add rule inet ss_spec ss_spec_wan_ac iifname $IFNAME tcp dport $EXT_ARGS comment "\"$TAG\"" goto ss_spec_wan_ac
|
||||
$NFT insert rule inet ss_spec ss_spec_prerouting iifname "$IFNAME" tcp comment "\"$TAG\"" jump ss_spec_wan_ac 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
done
|
||||
@@ -409,21 +425,21 @@ ac_rule_nft() {
|
||||
|
||||
case "$OUTPUT" in
|
||||
1)
|
||||
# Add output rules
|
||||
$NFT add chain inet ss_spec ss_spec_output { type nat hook output priority dstnat\; }
|
||||
$NFT add rule inet ss_spec ss_spec_output tcp dport $EXT_ARGS comment "\"$TAG\"" goto ss_spec_wan_ac
|
||||
# create output hook chain & route output traffic into router chain
|
||||
$NFT add chain inet ss_spec ss_spec_output '{ type nat hook output priority dstnat; }' 2>/dev/null
|
||||
$NFT add rule inet ss_spec ss_spec_output tcp comment "\"$TAG\"" jump ss_spec_wan_ac 2>/dev/null
|
||||
;;
|
||||
2)
|
||||
# Router mode output rules
|
||||
$NFT add set inet ss_spec ssr_gen_router { type ipv4_addr\; flags interval\; } 2>/dev/null
|
||||
# router mode output chain: create ssr_gen_router set & router chain
|
||||
$NFT add set inet ss_spec ssr_gen_router '{ type ipv4_addr; flags interval; }' 2>/dev/null
|
||||
for ip in $(gen_spec_iplist); do
|
||||
$NFT add element inet ss_spec ssr_gen_router { $ip }
|
||||
[ -n "$ip" ] && $NFT add element inet ss_spec ssr_gen_router "{ $ip }" 2>/dev/null
|
||||
done
|
||||
$NFT add chain inet ss_spec ss_spec_router
|
||||
$NFT add rule inet ss_spec ss_spec_router ip daddr @ssr_gen_router return
|
||||
$NFT add rule inet ss_spec ss_spec_router goto ss_spec_wan_fw
|
||||
$NFT add chain inet ss_spec ss_spec_output { type nat hook output priority dstnat\; }
|
||||
$NFT add rule inet ss_spec ss_spec_output tcp dport comment "\"$TAG\"" goto ss_spec_router
|
||||
$NFT add chain inet ss_spec ss_spec_router 2>/dev/null
|
||||
$NFT add rule inet ss_spec ss_spec_router ip daddr @ssr_gen_router return 2>/dev/null
|
||||
$NFT add rule inet ss_spec ss_spec_router jump ss_spec_wan_fw 2>/dev/null
|
||||
$NFT add chain inet ss_spec ss_spec_output '{ type nat hook output priority dstnat; }' 2>/dev/null
|
||||
$NFT add rule inet ss_spec ss_spec_output tcp comment "\"$TAG\"" jump ss_spec_router 2>/dev/null
|
||||
;;
|
||||
esac
|
||||
return 0
|
||||
@@ -431,7 +447,7 @@ ac_rule_nft() {
|
||||
|
||||
ac_rule_iptables() {
|
||||
if [ -n "$LAN_AC_IP" ]; then
|
||||
case "${LAN_AC_IP:0:1}" in
|
||||
case "${LAN_AC_IP%${LAN_AC_IP#?}}" in
|
||||
w | W)
|
||||
MATCH_SET="-m set --match-set ss_spec_lan_ac src"
|
||||
;;
|
||||
@@ -446,14 +462,14 @@ ac_rule_iptables() {
|
||||
fi
|
||||
ipset -! -R <<-EOF || return 1
|
||||
create ss_spec_lan_ac hash:net
|
||||
$(for ip in ${LAN_AC_IP:1}; do echo "add ss_spec_lan_ac $ip"; done)
|
||||
$(for ip in ${LAN_AC_IP#?}; do echo "add ss_spec_lan_ac $ip"; done)
|
||||
EOF
|
||||
if [ -z "$Interface" ]; then
|
||||
$IPT -I PREROUTING 1 -p tcp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_WAN_AC
|
||||
else
|
||||
for name in $Interface; do
|
||||
local IFNAME=$(uci -P /var/state get network.$name.ifname 2>/dev/null)
|
||||
[ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network.$name.device 2>/dev/null)
|
||||
local IFNAME=$(uci -P /var/state get network."$name".ifname 2>/dev/null)
|
||||
[ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network."$name".device 2>/dev/null)
|
||||
[ -n "$IFNAME" ] && $IPT -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p tcp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_WAN_AC
|
||||
done
|
||||
fi
|
||||
@@ -487,75 +503,85 @@ tp_rule() {
|
||||
}
|
||||
|
||||
tp_rule_nft() {
|
||||
# Set up routing for TPROXY
|
||||
ip rule add fwmark 0x01/0x01 table 100
|
||||
ip route add local 0.0.0.0/0 dev lo table 100
|
||||
|
||||
# Create TPROXY chain in mangle table
|
||||
[ -n "$TPROXY" ] || return 0
|
||||
|
||||
# set up routing table for tproxy
|
||||
ip rule add fwmark 0x01/0x01 table 100 2>/dev/null
|
||||
ip route add local 0.0.0.0/0 dev lo table 100 2>/dev/null
|
||||
|
||||
# create mangle table and tproxy chain
|
||||
$NFT add table ip ss_spec_mangle 2>/dev/null
|
||||
$NFT add chain ip ss_spec_mangle ss_spec_tproxy { type filter hook prerouting priority mangle\; }
|
||||
|
||||
# Add basic return rules
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport 53 return
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 0.0.0.0/8 return
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 10.0.0.0/8 return
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 127.0.0.0/8 return
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 169.254.0.0/16 return
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 172.16.0.0/12 return
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 192.168.0.0/16 return
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 224.0.0.0/4 return
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 240.0.0.0/4 return
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport != 53 ip daddr $SERVER return
|
||||
|
||||
# Handle different UDP server
|
||||
# use priority mangle for compatibility with other rules
|
||||
$NFT add chain ip ss_spec_mangle ss_spec_tproxy '{ type filter hook prerouting priority mangle; }' 2>/dev/null
|
||||
|
||||
# basic return rules in tproxy chain
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport 53 return 2>/dev/null
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 0.0.0.0/8 return 2>/dev/null
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 10.0.0.0/8 return 2>/dev/null
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 127.0.0.0/8 return 2>/dev/null
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 169.254.0.0/16 return 2>/dev/null
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 172.16.0.0/12 return 2>/dev/null
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 192.168.0.0/16 return 2>/dev/null
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 224.0.0.0/4 return 2>/dev/null
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr 240.0.0.0/4 return 2>/dev/null
|
||||
|
||||
# avoid redirecting to udp server address - 修正变量名
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport != 53 ip daddr "$server" return 2>/dev/null
|
||||
|
||||
# if server != SERVER add SERVER to whitelist set (so tproxy won't touch it)
|
||||
if [ "$server" != "$SERVER" ]; then
|
||||
$NFT add element inet ss_spec whitelist { $SERVER }
|
||||
$NFT add element inet ss_spec whitelist "{ $SERVER }" 2>/dev/null
|
||||
fi
|
||||
|
||||
# Access control rules
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip saddr @bplan return
|
||||
|
||||
# access control and tproxy rules
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip saddr @bplan return 2>/dev/null
|
||||
if [ -n "$PROXY_PORTS" ]; then
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp $PROXY_PORTS ip saddr @fplan tproxy to :$LOCAL_PORT meta mark set 0x01
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport "$PROXY_PORTS" ip saddr @fplan tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
|
||||
else
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip saddr @fplan tproxy to :$LOCAL_PORT meta mark set 0x01
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip saddr @fplan tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
|
||||
fi
|
||||
|
||||
# Handle different run modes for nftables
|
||||
case "$RUNMODE" in
|
||||
router)
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr @ss_spec_wan_ac return
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr @china return
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport 80 drop
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip saddr @gmlan ip daddr != @china tproxy to :$LOCAL_PORT meta mark set 0x01
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr @ss_spec_wan_ac return 2>/dev/null
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr @china return 2>/dev/null
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport 80 drop 2>/dev/null
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip saddr @gmlan ip daddr != @china tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
|
||||
if [ -n "$PROXY_PORTS" ]; then
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp $PROXY_PORTS ip daddr != @ss_spec_wan_ac tproxy to :$LOCAL_PORT meta mark set 0x01
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport "$PROXY_PORTS" ip daddr != @ss_spec_wan_ac tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
|
||||
else
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr != @ss_spec_wan_ac tproxy to :$LOCAL_PORT meta mark set 0x01
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr != @ss_spec_wan_ac tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
|
||||
fi
|
||||
;;
|
||||
gfw)
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr @china return
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport 80 drop
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip daddr @china return 2>/dev/null
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport 80 drop 2>/dev/null
|
||||
if [ -n "$PROXY_PORTS" ]; then
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp $PROXY_PORTS ip daddr @gfwlist tproxy to :$LOCAL_PORT meta mark set 0x01
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport "$PROXY_PORTS" ip daddr @gfwlist tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
|
||||
fi
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip saddr @gmlan ip daddr != @china tproxy to :$LOCAL_PORT meta mark set 0x01
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip saddr @gmlan ip daddr != @china tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
|
||||
;;
|
||||
oversea)
|
||||
if [ -n "$PROXY_PORTS" ]; then
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp $PROXY_PORTS ip saddr @oversea tproxy to :$LOCAL_PORT meta mark set 0x01
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp $PROXY_PORTS ip daddr @china tproxy to :$LOCAL_PORT meta mark set 0x01
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport "$PROXY_PORTS" ip saddr @oversea tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport "$PROXY_PORTS" ip daddr @china tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
|
||||
fi
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip saddr @gmlan tproxy to :$LOCAL_PORT meta mark set 0x01
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp ip saddr @gmlan tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
|
||||
;;
|
||||
all)
|
||||
if [ -n "$PROXY_PORTS" ]; then
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp $PROXY_PORTS tproxy to :$LOCAL_PORT meta mark set 0x01
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport "$PROXY_PORTS" tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
|
||||
else
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp tproxy to :$LOCAL_PORT meta mark set 0x01
|
||||
$NFT add rule ip ss_spec_mangle ss_spec_tproxy udp tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# insert jump from ip prerouting to our tproxy chain
|
||||
$NFT add rule ip ss_spec_mangle prerouting udp comment "\"$TAG\"" jump ss_spec_tproxy 2>/dev/null
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
tp_rule_iptables() {
|
||||
@@ -572,8 +598,8 @@ tp_rule_iptables() {
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -d 192.168.0.0/16 -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -d 224.0.0.0/4 -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -d 240.0.0.0/4 -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp ! --dport 53 -d $SERVER -j RETURN
|
||||
[ "$server" != "$SERVER" ] && ipset -! add whitelist $SERVER
|
||||
$ipt -A SS_SPEC_TPROXY -p udp ! --dport 53 -d "$SERVER" -j RETURN
|
||||
[ "$server" != "$SERVER" ] && ipset -! add whitelist "$SERVER"
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -m set --match-set bplan src -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set fplan src -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
case "$RUNMODE" in
|
||||
@@ -603,8 +629,8 @@ tp_rule_iptables() {
|
||||
$ipt -I PREROUTING 1 -p udp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_TPROXY
|
||||
else
|
||||
for name in $Interface; do
|
||||
local IFNAME=$(uci -P /var/state get network.$name.ifname 2>/dev/null)
|
||||
[ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network.$name.device 2>/dev/null)
|
||||
local IFNAME=$(uci -P /var/state get network."$name".ifname 2>/dev/null)
|
||||
[ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network."$name".device 2>/dev/null)
|
||||
[ -n "$IFNAME" ] && $ipt -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p udp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_TPROXY
|
||||
done
|
||||
fi
|
||||
@@ -653,15 +679,17 @@ gen_include() {
|
||||
|
||||
gen_include_nft() {
|
||||
# Generate nftables include file for firewall4
|
||||
cat <<-EOF >>$FWI
|
||||
[ -n "$FWI" ] && echo '#!/bin/sh' >"$FWI"
|
||||
cat <<-'EOF' >>"$FWI"
|
||||
# Clear existing ss_spec tables
|
||||
nft delete table inet ss_spec 2>/dev/null
|
||||
nft delete table ip ss_spec 2>/dev/null
|
||||
nft delete table ip ss_spec_mangle 2>/dev/null
|
||||
|
||||
|
||||
# Restore shadowsocks nftables rules
|
||||
$(nft list ruleset | grep -A 1000 "table inet ss_spec\|table ip ss_spec")
|
||||
nft list ruleset | awk '/table (inet|ip) ss_spec/{flag=1} flag'
|
||||
EOF
|
||||
chmod +x "$FWI"
|
||||
}
|
||||
|
||||
gen_include_iptables() {
|
||||
@@ -709,7 +737,7 @@ while getopts ":m:s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:I:oOuUfgrczh" arg; do
|
||||
LAN_BP_IP=$OPTARG
|
||||
;;
|
||||
b)
|
||||
WAN_BP_IP=$(for ip in $OPTARG; do echo $ip; done)
|
||||
WAN_BP_IP=$(for ip in $OPTARG; do echo "$ip"; done)
|
||||
;;
|
||||
w)
|
||||
WAN_FW_IP=$OPTARG
|
||||
@@ -767,10 +795,15 @@ while getopts ":m:s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:I:oOuUfgrczh" arg; do
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$server" -o -z "$local_port" ]; then
|
||||
if [ -z "$server" ] || [ -z "$local_port" ]; then
|
||||
usage 2
|
||||
fi
|
||||
|
||||
if ! echo "$local_port" | grep -qE '^[0-9]+$'; then
|
||||
loger 3 "Invalid local port: $local_port"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$TPROXY" in
|
||||
1)
|
||||
SERVER=$server
|
||||
@@ -782,7 +815,10 @@ case "$TPROXY" in
|
||||
;;
|
||||
esac
|
||||
|
||||
flush_r && fw_rule && ipset_r && ac_rule && tp_rule && gen_include
|
||||
RET=$?
|
||||
[ "$RET" = 0 ] || loger 3 "Start failed!"
|
||||
exit $RET
|
||||
if flush_r && fw_rule && ipset_r && ac_rule && tp_rule && gen_include; then
|
||||
loger 5 "Rules applied successfully"
|
||||
exit 0
|
||||
else
|
||||
loger 3 "Start failed!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -331,8 +331,8 @@ end
|
||||
mux = (server.v2ray_protocol ~= "wireguard") and {
|
||||
-- mux
|
||||
enabled = (server.mux == "1"), -- Mux
|
||||
concurrency = (server.mux == "1" and (tonumber(server.concurrency) or -1)) or nil, -- TCP 最大并发
|
||||
xudpConcurrency = (server.mux == "1" and (tonumber(server.xudpConcurrency) or 16)) or nil, -- UDP 最大并发
|
||||
concurrency = (server.mux == "1" and (tonumber(server.concurrency) or -1)) or nil, -- TCP 最大并发连接数
|
||||
xudpConcurrency = (server.mux == "1" and (tonumber(server.xudpConcurrency) or 16)) or nil, -- UDP 最大并发连接数
|
||||
xudpProxyUDP443 = (server.mux == "1" and (server.xudpProxyUDP443 or "reject")) or nil -- 对被代理的 UDP/443 流量处理方式
|
||||
} or nil
|
||||
}
|
||||
@@ -631,6 +631,8 @@ local tuic = {
|
||||
return nil
|
||||
end
|
||||
end)() or nil,
|
||||
ipstack_prefer = (server.tuic_dual_stack == "1") and server.ipstack_prefer or nil,
|
||||
skip_cert_verify = (server.insecure == "1" or server.insecure == true or server.insecure == "true"),
|
||||
disable_sni = (server.disable_sni == "1") and true or false,
|
||||
zero_rtt_handshake = (server.zero_rtt_handshake == "1") and true or false,
|
||||
send_window = tonumber(server.send_window),
|
||||
@@ -715,3 +717,4 @@ function config:handleIndex(index)
|
||||
end
|
||||
local f = config:new()
|
||||
f:handleIndex(server.type)
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ config server_subscribe
|
||||
option auto_update_day_time '2'
|
||||
option auto_update_min_time '0'
|
||||
option user_agent 'v2rayN/9.99'
|
||||
option filter_words '过期时间/剩余流量/QQ群/官网/防失联地址/回国'
|
||||
option filter_words '过期/套餐/剩余/QQ群/官网/防失联/回国'
|
||||
|
||||
config access_control
|
||||
option lan_ac_mode '0'
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user