update 2025-05-04 16:26:33

This commit is contained in:
kenzok8 2025-05-04 16:26:33 +08:00
parent e7078b8470
commit c0c4f3d4a6
14 changed files with 467 additions and 77 deletions

View File

@ -232,6 +232,13 @@ o:value("1:65535", translate("All"))
o.validate = port_validate o.validate = port_validate
o:depends({ _hide_node_option = "1", ['!reverse'] = true }) o:depends({ _hide_node_option = "1", ['!reverse'] = true })
o = s:option(DummyValue, "tips", " ")
o.rawhtml = true
o.cfgvalue = function(t, n)
return string.format('<font color="red">%s</font>',
translate("The port settings support single ports and ranges.<br>Separate multiple ports with commas (,).<br>Example: 21,80,443,1000:2000."))
end
o = s:option(ListValue, "direct_dns_query_strategy", translate("Direct Query Strategy")) o = s:option(ListValue, "direct_dns_query_strategy", translate("Direct Query Strategy"))
o.default = "UseIP" o.default = "UseIP"
o:value("UseIP") o:value("UseIP")

View File

@ -114,6 +114,8 @@ o.cfgvalue = function(t, n)
protocol = "HY" protocol = "HY"
elseif protocol == "hysteria2" then elseif protocol == "hysteria2" then
protocol = "HY2" protocol = "HY2"
elseif protocol == "anytls" then
protocol = "AnyTLS"
else else
protocol = protocol:gsub("^%l",string.upper) protocol = protocol:gsub("^%l",string.upper)
end end

View File

@ -95,6 +95,13 @@ o.default = "1:65535"
o:value("1:65535", translate("All")) o:value("1:65535", translate("All"))
o.validate = port_validate o.validate = port_validate
o = s:option(DummyValue, "tips", " ")
o.rawhtml = true
o.cfgvalue = function(t, n)
return string.format('<font color="red">%s</font>',
translate("The port settings support single ports and ranges.<br>Separate multiple ports with commas (,).<br>Example: 21,80,443,1000:2000."))
end
---- Use nftables ---- Use nftables
o = s:option(ListValue, "use_nft", translate("Firewall tools")) o = s:option(ListValue, "use_nft", translate("Firewall tools"))
o.default = "0" o.default = "0"

View File

@ -8,6 +8,9 @@ if not singbox_bin then
return return
end end
local local_version = api.get_app_version("sing-box")
local version_ge_1_12_0 = api.compare_versions(local_version:match("[^v]+"), ">=", "1.12.0")
local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'") local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'")
local appname = api.appname local appname = api.appname
@ -59,6 +62,9 @@ end
if singbox_tags:find("with_quic") then if singbox_tags:find("with_quic") then
o:value("hysteria2", "Hysteria2") o:value("hysteria2", "Hysteria2")
end end
if version_ge_1_12_0 then
o:value("anytls", "AnyTLS")
end
o:value("_urltest", translate("URLTest")) o:value("_urltest", translate("URLTest"))
o:value("_shunt", translate("Shunt")) o:value("_shunt", translate("Shunt"))
o:value("_iface", translate("Custom Interface")) o:value("_iface", translate("Custom Interface"))
@ -254,6 +260,7 @@ o:depends({ [_n("protocol")] = "shadowsocks" })
o:depends({ [_n("protocol")] = "shadowsocksr" }) o:depends({ [_n("protocol")] = "shadowsocksr" })
o:depends({ [_n("protocol")] = "trojan" }) o:depends({ [_n("protocol")] = "trojan" })
o:depends({ [_n("protocol")] = "tuic" }) o:depends({ [_n("protocol")] = "tuic" })
o:depends({ [_n("protocol")] = "anytls" })
o = s:option(ListValue, _n("security"), translate("Encrypt Method")) o = s:option(ListValue, _n("security"), translate("Encrypt Method"))
for a, t in ipairs(security_list) do o:value(t) end for a, t in ipairs(security_list) do o:value(t) end
@ -434,6 +441,7 @@ o:depends({ [_n("protocol")] = "vless" })
o:depends({ [_n("protocol")] = "http" }) o:depends({ [_n("protocol")] = "http" })
o:depends({ [_n("protocol")] = "trojan" }) o:depends({ [_n("protocol")] = "trojan" })
o:depends({ [_n("protocol")] = "shadowsocks" }) o:depends({ [_n("protocol")] = "shadowsocks" })
o:depends({ [_n("protocol")] = "anytls" })
o = s:option(ListValue, _n("alpn"), translate("alpn")) o = s:option(ListValue, _n("alpn"), translate("alpn"))
o.default = "default" o.default = "default"
@ -527,6 +535,7 @@ if singbox_tags:find("with_utls") then
o:depends({ [_n("protocol")] = "shadowsocks", [_n("utls")] = true }) o:depends({ [_n("protocol")] = "shadowsocks", [_n("utls")] = true })
o:depends({ [_n("protocol")] = "socks", [_n("utls")] = true }) o:depends({ [_n("protocol")] = "socks", [_n("utls")] = true })
o:depends({ [_n("protocol")] = "trojan", [_n("utls")] = true }) o:depends({ [_n("protocol")] = "trojan", [_n("utls")] = true })
o:depends({ [_n("protocol")] = "anytls", [_n("utls")] = true })
o = s:option(Value, _n("reality_publicKey"), translate("Public Key")) o = s:option(Value, _n("reality_publicKey"), translate("Public Key"))
o:depends({ [_n("utls")] = true, [_n("reality")] = true }) o:depends({ [_n("utls")] = true, [_n("reality")] = true })
@ -752,6 +761,7 @@ o:depends({ [_n("protocol")] = "hysteria" })
o:depends({ [_n("protocol")] = "vless" }) o:depends({ [_n("protocol")] = "vless" })
o:depends({ [_n("protocol")] = "tuic" }) o:depends({ [_n("protocol")] = "tuic" })
o:depends({ [_n("protocol")] = "hysteria2" }) o:depends({ [_n("protocol")] = "hysteria2" })
o:depends({ [_n("protocol")] = "anytls" })
o = s:option(ListValue, _n("chain_proxy"), translate("Chain Proxy")) o = s:option(ListValue, _n("chain_proxy"), translate("Chain Proxy"))
o:value("", translate("Close(Not use)")) o:value("", translate("Close(Not use)"))

View File

@ -8,6 +8,11 @@ if not singbox_bin then
return return
end end
local local_version = api.get_app_version("sing-box")
local version_ge_1_12_0 = api.compare_versions(local_version:match("[^v]+"), ">=", "1.12.0")
local fs = api.fs
local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'") local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'")
local type_name = "sing-box" local type_name = "sing-box"
@ -48,6 +53,9 @@ end
if singbox_tags:find("with_quic") then if singbox_tags:find("with_quic") then
o:value("hysteria2", "Hysteria2") o:value("hysteria2", "Hysteria2")
end end
if version_ge_1_12_0 then
o:value("anytls", "AnyTLS")
end
o:value("direct", "Direct") o:value("direct", "Direct")
o = s:option(Value, _n("port"), translate("Listen Port")) o = s:option(Value, _n("port"), translate("Listen Port"))
@ -71,6 +79,7 @@ o:depends({ [_n("protocol")] = "http" })
o = s:option(Value, _n("username"), translate("Username")) o = s:option(Value, _n("username"), translate("Username"))
o:depends({ [_n("auth")] = true }) o:depends({ [_n("auth")] = true })
o:depends({ [_n("protocol")] = "naive" }) o:depends({ [_n("protocol")] = "naive" })
o:depends({ [_n("protocol")] = "anytls" })
o = s:option(Value, _n("password"), translate("Password")) o = s:option(Value, _n("password"), translate("Password"))
o.password = true o.password = true
@ -78,6 +87,7 @@ o:depends({ [_n("auth")] = true })
o:depends({ [_n("protocol")] = "shadowsocks" }) o:depends({ [_n("protocol")] = "shadowsocks" })
o:depends({ [_n("protocol")] = "naive" }) o:depends({ [_n("protocol")] = "naive" })
o:depends({ [_n("protocol")] = "tuic" }) o:depends({ [_n("protocol")] = "tuic" })
o:depends({ [_n("protocol")] = "anytls" })
if singbox_tags:find("with_quic") then if singbox_tags:find("with_quic") then
o = s:option(Value, _n("hysteria_up_mbps"), translate("Max upload Mbps")) o = s:option(Value, _n("hysteria_up_mbps"), translate("Max upload Mbps"))
@ -221,6 +231,7 @@ o:depends({ [_n("protocol")] = "http" })
o:depends({ [_n("protocol")] = "vmess" }) o:depends({ [_n("protocol")] = "vmess" })
o:depends({ [_n("protocol")] = "vless" }) o:depends({ [_n("protocol")] = "vless" })
o:depends({ [_n("protocol")] = "trojan" }) o:depends({ [_n("protocol")] = "trojan" })
o:depends({ [_n("protocol")] = "anytls" })
if singbox_tags:find("with_reality_server") then if singbox_tags:find("with_reality_server") then
-- [[ REALITY部分 ]] -- -- [[ REALITY部分 ]] --
@ -230,6 +241,7 @@ if singbox_tags:find("with_reality_server") then
o:depends({ [_n("protocol")] = "vmess", [_n("tls")] = true }) o:depends({ [_n("protocol")] = "vmess", [_n("tls")] = true })
o:depends({ [_n("protocol")] = "vless", [_n("tls")] = true }) o:depends({ [_n("protocol")] = "vless", [_n("tls")] = true })
o:depends({ [_n("protocol")] = "trojan", [_n("tls")] = true }) o:depends({ [_n("protocol")] = "trojan", [_n("tls")] = true })
o:depends({ [_n("protocol")] = "anytls", [_n("tls")] = true })
o = s:option(Value, _n("reality_private_key"), translate("Private Key")) o = s:option(Value, _n("reality_private_key"), translate("Private Key"))
o:depends({ [_n("reality")] = true }) o:depends({ [_n("reality")] = true })

View File

@ -471,6 +471,8 @@ function get_valid_nodes()
protocol = "HY" protocol = "HY"
elseif protocol == "hysteria2" then elseif protocol == "hysteria2" then
protocol = "HY2" protocol = "HY2"
elseif protocol == "anytls" then
protocol = "AnyTLS"
else else
protocol = protocol:gsub("^%l",string.upper) protocol = protocol:gsub("^%l",string.upper)
end end
@ -504,9 +506,22 @@ function get_node_remarks(n)
protocol = "VMess" protocol = "VMess"
elseif protocol == "vless" then elseif protocol == "vless" then
protocol = "VLESS" protocol = "VLESS"
elseif protocol == "shadowsocks" then
protocol = "SS"
elseif protocol == "shadowsocksr" then
protocol = "SSR"
elseif protocol == "wireguard" then
protocol = "WG"
elseif protocol == "hysteria" then
protocol = "HY"
elseif protocol == "hysteria2" then
protocol = "HY2"
elseif protocol == "anytls" then
protocol = "AnyTLS"
else else
protocol = protocol:gsub("^%l",string.upper) protocol = protocol:gsub("^%l",string.upper)
end end
if type2 == "sing-box" then type2 = "Sing-Box" end
type2 = type2 .. " " .. protocol type2 = type2 .. " " .. protocol
end end
remarks = "%s[%s]" % {type2, n.remarks} remarks = "%s[%s]" % {type2, n.remarks}
@ -849,7 +864,8 @@ local default_file_tree = {
armv5 = "arm.*5", armv5 = "arm.*5",
armv6 = "arm.*6[^4]*", armv6 = "arm.*6[^4]*",
armv7 = "arm.*7", armv7 = "arm.*7",
armv8 = "arm64" armv8 = "arm64",
riscv64 = "riscv64"
} }
function get_api_json(url) function get_api_json(url)

View File

@ -382,6 +382,13 @@ function gen_outbound(flag, node, tag, proxy_table)
} }
end end
if node.protocol == "anytls" then
protocol_table = {
password = (node.password and node.password ~= "") and node.password or "",
tls = tls
}
end
if protocol_table then if protocol_table then
for key, value in pairs(protocol_table) do for key, value in pairs(protocol_table) do
result[key] = value result[key] = value
@ -667,6 +674,18 @@ function gen_config_server(node)
} }
end end
if node.protocol == "anytls" then
protocol_table = {
users = {
{
name = (node.username and node.username ~= "") and node.username or "sekai",
password = node.password
}
},
tls = tls,
}
end
if node.protocol == "direct" then if node.protocol == "direct" then
protocol_table = { protocol_table = {
network = (node.d_protocol ~= "TCP,UDP") and node.d_protocol or nil, network = (node.d_protocol ~= "TCP,UDP") and node.d_protocol or nil,

View File

@ -28,7 +28,7 @@ local api = require "luci.passwall2.api"
line-height: 1.2rem; line-height: 1.2rem;
} }
</style> </style>
<div class="cbi-section cbi-tblsection dns-con"> <div class="dns-con">
<div id="faq_dns"> <div id="faq_dns">
<ul> <ul>
<b class="faq-title"><%:DNS related issues:%></b> <b class="faq-title"><%:DNS related issues:%></b>

View File

@ -4,9 +4,20 @@ local api = require "luci.passwall2.api"
<script type="text/javascript"> <script type="text/javascript">
//<![CDATA[ //<![CDATA[
function getXHR() {
if (typeof XHR === 'object' && typeof XHR.create === 'function') {
return XHR.create();
} else if (typeof XHR === 'function') {
return new XHR();
} else {
throw new Error("XHR is not supported in this environment.");
}
}
function ajax_add_node(link) { function ajax_add_node(link) {
var xhr = getXHR();
if (link) { if (link) {
XHR.get('<%=api.url("link_add_node")%>', { xhr.post('<%=api.url("link_add_node")%>', {
'link': link 'link': link
}, },
function(x, data) { function(x, data) {

View File

@ -538,6 +538,41 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin
params += opt.query("congestion_control", dom_prefix + "tuic_congestion_control"); params += opt.query("congestion_control", dom_prefix + "tuic_congestion_control");
params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure"); params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure");
params += "#" + encodeURI(v_alias.value);
if (params[0] == "&") {
params = params.substring(1);
}
url += params;
} else if (v_type === "sing-box" && opt.get(dom_prefix + "protocol").value === "anytls") {
protocol = "anytls";
var v_password = opt.get(dom_prefix + "password");
var v_port = opt.get(dom_prefix + "port");
url = encodeURIComponent(v_password.value) +
"@" + _address +
":" + v_port.value + "?";
var params = "";
if (opt.get(dom_prefix + "tls").checked) {
var v_security = "tls";
if (opt.get(dom_prefix + "fingerprint") && opt.get(dom_prefix + "fingerprint").value != "") {
let v_fp = opt.get(dom_prefix + "fingerprint").value;
params += "&fp=" + v_fp;
}
if (opt.get(dom_prefix + "reality") && opt.get(dom_prefix + "reality").checked) {
v_security = "reality";
if (opt.get(dom_prefix + "fingerprint") && opt.get(dom_prefix + "fingerprint").value != "") {
let v_fp = opt.get(dom_prefix + "fingerprint").value;
params += "&fp=" + v_fp;
}
params += opt.query("pbk", dom_prefix + "reality_publicKey");
params += opt.query("sid", dom_prefix + "reality_shortId");
}
params += "&security=" + v_security;
params += opt.query("alpn", dom_prefix + "alpn");
params += opt.query("sni", dom_prefix + "tls_serverName");
params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure");
}
params += "#" + encodeURI(v_alias.value); params += "#" + encodeURI(v_alias.value);
if (params[0] == "&") { if (params[0] == "&") {
params = params.substring(1); params = params.substring(1);
@ -639,10 +674,28 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin
} }
try { try {
obj.dispatchEvent(event); obj.dispatchEvent(event);
} catch (err) { } catch (err) {}
}
} else { } else {
//alert('<%:Faltal on set option, please help in debug: %>' + opt + ' = ' + val); //alert('<%:Faltal on set option, please help in debug: %>' + opt + ' = ' + val);
// 处理 DynamicList
var fullName = this.base + '.' + opt;
var lists = document.querySelectorAll('.cbi-dynlist');
for (var i = 0; i < lists.length; i++) {
var parent = lists[i].closest('.cbi-value');
if (!parent) continue;
// 尝试从 label 的 for 属性中提取 fullName
var label = parent.querySelector('label.cbi-value-title');
var labelFor = label?.getAttribute('for');
if (labelFor === fullName) {
var input = lists[i].querySelector('input[type="text"]');
var addBtn = lists[i].querySelector('.cbi-button-add');
if (input && addBtn) {
input.value = val;
addBtn.click();
}
break;
}
}
} }
}, },
setlist: function (opt, vlist) { setlist: function (opt, vlist) {
@ -764,6 +817,9 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin
dom_prefix = "xray_" dom_prefix = "xray_"
opt.set('type', "Xray"); opt.set('type', "Xray");
opt.set(dom_prefix + 'protocol', "shadowsocks"); opt.set(dom_prefix + 'protocol', "shadowsocks");
} else if (ss_type == "shadowsocks-rust") {
dom_prefix = "ssrust_"
opt.set('type', "SS-Rust");
} else { } else {
if (["2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"].includes(method)) { if (["2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"].includes(method)) {
dom_prefix = "ssrust_" dom_prefix = "ssrust_"
@ -782,10 +838,27 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin
opt.set(dom_prefix + 'password', password || ""); opt.set(dom_prefix + 'password', password || "");
opt.set(dom_prefix + 'method', method || ""); opt.set(dom_prefix + 'method', method || "");
opt.set(dom_prefix + 'ss_method', method || ""); opt.set(dom_prefix + 'ss_method', method || "");
opt.set(dom_prefix + 'plugin', plugin || "none");
if (plugin && plugin != "none") { if (plugin && plugin != "none") {
opt.set(dom_prefix + 'plugin_opts', pluginOpts || ""); plugin = (plugin === "simple-obfs") ? "obfs-local" : plugin;
opt.set(dom_prefix + 'plugin_enabled', true); opt.set(dom_prefix + 'plugin_enabled', true);
opt.set(dom_prefix + 'plugin', plugin || "none");
opt.set(dom_prefix + 'plugin_opts', pluginOpts || "");
//obfs-local插件转换成xray支持的格式
if (plugin == "obfs-local" && dom_prefix == "xray_") {
var obfs = pluginOpts.match(/obfs=([^;]+)/);
var obfs_host = pluginOpts.match(/obfs-host=([^;]+)/);
obfs = obfs ? obfs[1] : "";
obfs_host = obfs_host ? obfs_host[1] : "";
if (obfs === "http") {
opt.set(dom_prefix + 'transport', "raw");
opt.set(dom_prefix + 'tcp_guise', "http");
opt.set(dom_prefix + 'tcp_guise_http_host', obfs_host || '');
} else if (obfs === "tls") {
opt.set(dom_prefix + 'tls', true);
opt.set(dom_prefix + 'tls_serverName', obfs_host || '');
opt.set(dom_prefix + 'tls_allowInsecure', true);
}
}
} }
if (param !== undefined) { if (param !== undefined) {
opt.set('remarks', decodeURIComponent(param)); opt.set('remarks', decodeURIComponent(param));
@ -800,7 +873,7 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default'); opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || ''); opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
opt.set(dom_prefix + 'tls_allowInsecure', true); opt.set(dom_prefix + 'tls_allowInsecure', true);
if (queryParam.allowinsecure === '0') { if (queryParam.allowinsecure === '0' || queryParam.insecure === '0') {
opt.set(dom_prefix + 'tls_allowInsecure', false); opt.set(dom_prefix + 'tls_allowInsecure', false);
} }
if (queryParam.fp && queryParam.fp.trim() != "") { if (queryParam.fp && queryParam.fp.trim() != "") {
@ -1032,8 +1105,9 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin
tls_serverName = tls_serverName || ""; tls_serverName = tls_serverName || "";
opt.set(dom_prefix + 'tls_serverName', tls_serverName); opt.set(dom_prefix + 'tls_serverName', tls_serverName);
} }
if (queryParam.allowinsecure === '1') { opt.set(dom_prefix + 'tls_allowInsecure', true);
opt.set(dom_prefix + 'tls_allowInsecure', true); if (queryParam.allowinsecure === '0' || queryParam.insecure === '0') {
opt.set(dom_prefix + 'tls_allowInsecure', false);
} }
opt.set(dom_prefix + 'mux', queryParam.mux === '1'); opt.set(dom_prefix + 'mux', queryParam.mux === '1');
@ -1170,7 +1244,7 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default'); opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || ''); opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
opt.set(dom_prefix + 'tls_allowInsecure', true); opt.set(dom_prefix + 'tls_allowInsecure', true);
if (queryParam.allowinsecure === '0') { if (queryParam.allowinsecure === '0' || queryParam.insecure === '0') {
opt.set(dom_prefix + 'tls_allowInsecure', false); opt.set(dom_prefix + 'tls_allowInsecure', false);
} }
if (queryParam.fp && queryParam.fp.trim() != "") { if (queryParam.fp && queryParam.fp.trim() != "") {
@ -1357,13 +1431,73 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin
opt.set(dom_prefix + 'tuic_alpn', queryParam.alpn || 'default'); opt.set(dom_prefix + 'tuic_alpn', queryParam.alpn || 'default');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || ''); opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
opt.set(dom_prefix + 'tls_allowInsecure', true); opt.set(dom_prefix + 'tls_allowInsecure', true);
if (queryParam.allowinsecure === '0') { if (queryParam.allowinsecure === '0' || queryParam.insecure === '0') {
opt.set(dom_prefix + 'tls_allowInsecure', false); opt.set(dom_prefix + 'tls_allowInsecure', false);
} }
if (hash) { if (hash) {
opt.set('remarks', decodeURIComponent(hash.substr(1))); opt.set('remarks', decodeURIComponent(hash.substr(1)));
} }
} }
if (ssu[0] === "anytls") {
if (has_singbox) {
dom_prefix = "singbox_"
opt.set('type', "sing-box");
}
opt.set(dom_prefix + 'protocol', "anytls");
var m = parseNodeUrl(ssrurl);
var password = m.passwd;
if (password === "") {
s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
return false;
}
opt.set(dom_prefix + 'password', password);
opt.set(dom_prefix + 'address', m.hostname);
opt.set(dom_prefix + 'port', m.port || "443");
var queryParam = {};
if (m.search.length > 1) {
var query = m.search.replace('/?', '?').split('?')
var queryParams = query[1];
var queryArray = queryParams.split('&');
var params;
for (i = 0; i < queryArray.length; i++) {
params = queryArray[i].split('=');
queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || '');
}
}
if (queryParam.security) {
if (queryParam.security == "tls") {
opt.set(dom_prefix + 'tls', true);
opt.set(dom_prefix + 'reality', false);
opt.set(dom_prefix + 'flow', queryParam.flow || '');
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
opt.set(dom_prefix + 'tls_allowInsecure', true);
if (queryParam.allowinsecure === '0' || queryParam.insecure === '0') {
opt.set(dom_prefix + 'tls_allowInsecure', false);
}
if (queryParam.fp && queryParam.fp.trim() != "") {
opt.set(dom_prefix + 'utls', true);
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
}
}
if (queryParam.security == "reality") {
opt.set(dom_prefix + 'tls', true);
opt.set(dom_prefix + 'reality', true);
opt.set(dom_prefix + 'flow', queryParam.flow || '');
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
if (queryParam.fp && queryParam.fp.trim() != "") {
opt.set(dom_prefix + 'utls', true);
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
}
opt.set(dom_prefix + 'reality_publicKey', queryParam.pbk || '');
opt.set(dom_prefix + 'reality_shortId', queryParam.sid || '');
}
}
if (m.hash) {
opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
}
}
if (dom_prefix && dom_prefix != null) { if (dom_prefix && dom_prefix != null) {
if (opt.get(dom_prefix + 'port').value) { if (opt.get(dom_prefix + 'port').value) {
opt.get(dom_prefix + 'port').focus(); opt.get(dom_prefix + 'port').focus();

View File

@ -610,6 +610,9 @@ msgstr "填写你不希望被代理转发的端口,优先级最高。"
msgid "If you don't want to let the device in the list to go proxy, please choose all." msgid "If you don't want to let the device in the list to go proxy, please choose all."
msgstr "如果您不想让列表中的设备走代理,请选择全部。" msgstr "如果您不想让列表中的设备走代理,请选择全部。"
msgid "The port settings support single ports and ranges.<br>Separate multiple ports with commas (,).<br>Example: 21,80,443,1000:2000."
msgstr "以上端口设置支持单端口和端口范围。<br>多个端口用英文逗号(,)隔开。<br>例21,80,443,1000:2000。"
msgid "TCP Proxy Drop Ports" msgid "TCP Proxy Drop Ports"
msgstr "TCP转发屏蔽端口" msgstr "TCP转发屏蔽端口"

View File

@ -46,6 +46,43 @@ comment() {
echo "-m comment --comment '$name'" echo "-m comment --comment '$name'"
} }
#解决端口超过15个ipt无效支持单端口、端口范围
add_port_rules() {
local ipt_cmd="$1"
local port_list="$2"
local target="$3"
echo "$port_list" | grep -vq '[0-9]' && return
port_list=$(echo "$port_list" | tr -d ' ' | sed 's/-/:/g' | tr ',' '\n' | awk '!a[$0]++' | grep -v '^$')
[ -z "$port_list" ] && return
if echo "$port_list" | grep -q '^1:65535$'; then
eval "$ipt_cmd $target"
return
fi
local multiport_ports=""
local range_ports=""
local count=0
local port
for port in $port_list; do
if echo "$port" | grep -q ':'; then
range_ports="$range_ports $port"
else
multiport_ports="$multiport_ports,$port"
count=$((count + 1))
if [ "$count" -eq 15 ]; then
eval "$ipt_cmd -m multiport --dport ${multiport_ports#,} $target"
multiport_ports=""
count=0
fi
fi
done
if [ -n "$multiport_ports" ]; then
eval "$ipt_cmd -m multiport --dport ${multiport_ports#,} $target"
fi
for port in $range_ports; do
eval "$ipt_cmd --dport $port $target"
done
}
destroy_ipset() { destroy_ipset() {
for i in "$@"; do for i in "$@"; do
ipset -q -F $i ipset -q -F $i
@ -265,6 +302,7 @@ add_shunt_t_rule() {
local shunt_args=${1} local shunt_args=${1}
local t_args=${2} local t_args=${2}
local t_jump_args=${3} local t_jump_args=${3}
local t_ports_args=${4}
[ -n "${shunt_args}" ] && { [ -n "${shunt_args}" ] && {
for j in ${shunt_args}; do for j in ${shunt_args}; do
local _set_name=$(echo ${j} | awk -F ':' '{print $1}') local _set_name=$(echo ${j} | awk -F ':' '{print $1}')
@ -272,7 +310,11 @@ add_shunt_t_rule() {
[ -n "${_set_name}" ] && [ -n "${_outbound}" ] && { [ -n "${_set_name}" ] && [ -n "${_outbound}" ] && {
local _t_arg="${t_jump_args}" local _t_arg="${t_jump_args}"
[ "${_outbound}" = "direct" ] && _t_arg="-j RETURN" [ "${_outbound}" = "direct" ] && _t_arg="-j RETURN"
${t_args} $(dst ${_set_name}) ${_t_arg} if [ -z "${t_ports_args}" ] || [ "${t_ports_args}" == "1:65535" ]; then
${t_args} $(dst ${_set_name}) ${_t_arg}
else
add_port_rules "${t_args} $(dst ${_set_name})" "${t_ports_args}" "${_t_arg}"
fi
} }
done done
} }
@ -375,8 +417,8 @@ load_acl() {
[ "$tcp_no_redir_ports" != "disable" ] && { [ "$tcp_no_redir_ports" != "disable" ] && {
if [ "$tcp_no_redir_ports" != "1:65535" ]; then if [ "$tcp_no_redir_ports" != "1:65535" ]; then
$ip6t_m -A PSW2 $(comment "$remarks") ${_ipt_source} -p tcp -m multiport --dport $tcp_no_redir_ports -j RETURN 2>/dev/null add_port_rules "$ip6t_m -A PSW2 $(comment "$remarks") ${_ipt_source} -p tcp" $tcp_no_redir_ports "-j RETURN" 2>/dev/null
$ipt_tmp -A PSW2 $(comment "$remarks") ${_ipt_source} -p tcp -m multiport --dport $tcp_no_redir_ports -j RETURN add_port_rules "$ipt_tmp -A PSW2 $(comment "$remarks") ${_ipt_source} -p tcp" $tcp_no_redir_ports "-j RETURN"
echolog " - ${msg}不代理 TCP 端口[${tcp_no_redir_ports}]" echolog " - ${msg}不代理 TCP 端口[${tcp_no_redir_ports}]"
else else
#结束时会return无需加多余的规则。 #结束时会return无需加多余的规则。
@ -387,8 +429,8 @@ load_acl() {
[ "$udp_no_redir_ports" != "disable" ] && { [ "$udp_no_redir_ports" != "disable" ] && {
if [ "$udp_no_redir_ports" != "1:65535" ]; then if [ "$udp_no_redir_ports" != "1:65535" ]; then
$ip6t_m -A PSW2 $(comment "$remarks") ${_ipt_source} -p udp -m multiport --dport $udp_no_redir_ports -j RETURN 2>/dev/null add_port_rules "$ip6t_m -A PSW2 $(comment "$remarks") ${_ipt_source} -p udp" $udp_no_redir_ports "-j RETURN" 2>/dev/null
$ipt_m -A PSW2 $(comment "$remarks") ${_ipt_source} -p udp -m multiport --dport $udp_no_redir_ports -j RETURN add_port_rules "$ipt_m -A PSW2 $(comment "$remarks") ${_ipt_source} -p udp" $udp_no_redir_ports "-j RETURN"
echolog " - ${msg}不代理 UDP 端口[${udp_no_redir_ports}]" echolog " - ${msg}不代理 UDP 端口[${udp_no_redir_ports}]"
else else
#结束时会return无需加多余的规则。 #结束时会return无需加多余的规则。
@ -433,14 +475,14 @@ load_acl() {
} }
$ipt_tmp -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source} -d $FAKE_IP ${ipt_j} $ipt_tmp -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source} -d $FAKE_IP ${ipt_j}
add_shunt_t_rule "${shunt_list4}" "$ipt_tmp -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source} $(factor $tcp_redir_ports "-m multiport --dport")" "${ipt_j}" add_shunt_t_rule "${shunt_list4}" "$ipt_tmp -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source}" "${ipt_j}" $tcp_redir_ports
$ipt_tmp -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source} $(factor $tcp_redir_ports "-m multiport --dport") ${ipt_j} add_port_rules "$ipt_tmp -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source}" $tcp_redir_ports "${ipt_j}"
[ -n "${is_tproxy}" ] && $ipt_m -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source} $(REDIRECT $redir_port TPROXY) [ -n "${is_tproxy}" ] && $ipt_m -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source} $(REDIRECT $redir_port TPROXY)
[ "$PROXY_IPV6" == "1" ] && { [ "$PROXY_IPV6" == "1" ] && {
$ip6t_m -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source} -d $FAKE_IP_6 -j PSW2_RULE 2>/dev/null $ip6t_m -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source} -d $FAKE_IP_6 -j PSW2_RULE 2>/dev/null
add_shunt_t_rule "${shunt_list6}" "$ip6t_m -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source} $(factor $tcp_redir_ports "-m multiport --dport")" "${ipt_j}" 2>/dev/null add_shunt_t_rule "${shunt_list6}" "$ip6t_m -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source}" "${ipt_j}" $tcp_redir_ports 2>/dev/null
$ip6t_m -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source} $(factor $tcp_redir_ports "-m multiport --dport") -j PSW2_RULE 2>/dev/null add_port_rules "$ip6t_m -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source}" $tcp_redir_ports "-j PSW2_RULE" 2>/dev/null
$ip6t_m -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source} $(REDIRECT $redir_port TPROXY) 2>/dev/null $ip6t_m -A PSW2 $(comment "$remarks") -p tcp ${_ipt_source} $(REDIRECT $redir_port TPROXY) 2>/dev/null
} }
echolog " - ${msg2}" echolog " - ${msg2}"
@ -452,14 +494,14 @@ load_acl() {
msg2="${msg}使用 UDP 节点[$node_remark](TPROXY:${redir_port})" msg2="${msg}使用 UDP 节点[$node_remark](TPROXY:${redir_port})"
$ipt_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source} -d $FAKE_IP -j PSW2_RULE $ipt_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source} -d $FAKE_IP -j PSW2_RULE
add_shunt_t_rule "${shunt_list4}" "$ipt_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source} $(factor $udp_redir_ports "-m multiport --dport")" "-j PSW2_RULE" add_shunt_t_rule "${shunt_list4}" "$ipt_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source}" "-j PSW2_RULE" $udp_redir_ports
$ipt_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source} $(factor $udp_redir_ports "-m multiport --dport") -j PSW2_RULE add_port_rules "$ipt_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source}" $udp_redir_ports "-j PSW2_RULE"
$ipt_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source} $(REDIRECT $redir_port TPROXY) $ipt_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source} $(REDIRECT $redir_port TPROXY)
[ "$PROXY_IPV6" == "1" ] && { [ "$PROXY_IPV6" == "1" ] && {
$ip6t_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source} -d $FAKE_IP_6 -j PSW2_RULE 2>/dev/null $ip6t_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source} -d $FAKE_IP_6 -j PSW2_RULE 2>/dev/null
add_shunt_t_rule "${shunt_list6}" "$ip6t_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source} $(factor $udp_redir_ports "-m multiport --dport")" "-j PSW2_RULE" 2>/dev/null add_shunt_t_rule "${shunt_list6}" "$ip6t_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source}" "-j PSW2_RULE" $udp_redir_ports 2>/dev/null
$ip6t_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source} $(factor $udp_redir_ports "-m multiport --dport") -j PSW2_RULE 2>/dev/null add_port_rules "$ip6t_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source}" $udp_redir_ports "-j PSW2_RULE" 2>/dev/null
$ip6t_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source} $(REDIRECT $redir_port TPROXY) 2>/dev/null $ip6t_m -A PSW2 $(comment "$remarks") -p udp ${_ipt_source} $(REDIRECT $redir_port TPROXY) 2>/dev/null
} }
echolog " - ${msg2}" echolog " - ${msg2}"
@ -480,8 +522,8 @@ load_acl() {
[ -n "${is_tproxy}" ] && ipt_tmp=$ipt_m [ -n "${is_tproxy}" ] && ipt_tmp=$ipt_m
[ "$TCP_NO_REDIR_PORTS" != "disable" ] && { [ "$TCP_NO_REDIR_PORTS" != "disable" ] && {
$ip6t_m -A PSW2 $(comment "默认") -p tcp -m multiport --dport $TCP_NO_REDIR_PORTS -j RETURN add_port_rules "$ip6t_m -A PSW2 $(comment "默认") -p tcp" $TCP_NO_REDIR_PORTS "-j RETURN"
$ipt_tmp -A PSW2 $(comment "默认") -p tcp -m multiport --dport $TCP_NO_REDIR_PORTS -j RETURN add_port_rules "$ipt_tmp -A PSW2 $(comment "默认") -p tcp" $TCP_NO_REDIR_PORTS "-j RETURN"
if [ "$TCP_NO_REDIR_PORTS" != "1:65535" ]; then if [ "$TCP_NO_REDIR_PORTS" != "1:65535" ]; then
echolog " - ${msg}不代理 TCP 端口[${TCP_NO_REDIR_PORTS}]" echolog " - ${msg}不代理 TCP 端口[${TCP_NO_REDIR_PORTS}]"
else else
@ -491,8 +533,8 @@ load_acl() {
} }
[ "$UDP_NO_REDIR_PORTS" != "disable" ] && { [ "$UDP_NO_REDIR_PORTS" != "disable" ] && {
$ip6t_m -A PSW2 $(comment "默认") -p udp -m multiport --dport $UDP_NO_REDIR_PORTS -j RETURN add_port_rules "$ip6t_m -A PSW2 $(comment "默认") -p udp" $UDP_NO_REDIR_PORTS "-j RETURN"
$ipt_m -A PSW2 $(comment "默认") -p udp -m multiport --dport $UDP_NO_REDIR_PORTS -j RETURN add_port_rules "$ipt_tmp -A PSW2 $(comment "默认") -p udp" $UDP_NO_REDIR_PORTS "-j RETURN"
if [ "$UDP_NO_REDIR_PORTS" != "1:65535" ]; then if [ "$UDP_NO_REDIR_PORTS" != "1:65535" ]; then
echolog " - ${msg}不代理 UDP 端口[${UDP_NO_REDIR_PORTS}]" echolog " - ${msg}不代理 UDP 端口[${UDP_NO_REDIR_PORTS}]"
else else
@ -533,14 +575,14 @@ load_acl() {
} }
$ipt_tmp -A PSW2 $(comment "默认") -p tcp -d $FAKE_IP ${ipt_j} $ipt_tmp -A PSW2 $(comment "默认") -p tcp -d $FAKE_IP ${ipt_j}
add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_tmp -A PSW2 $(comment "默认") -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport")" "${ipt_j}" add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_tmp -A PSW2 $(comment "默认") -p tcp" "${ipt_j}" $TCP_REDIR_PORTS
$ipt_tmp -A PSW2 $(comment "默认") -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport") ${ipt_j} add_port_rules "$ipt_tmp -A PSW2 $(comment "默认") -p tcp" $TCP_REDIR_PORTS "${ipt_j}"
[ -n "${is_tproxy}" ] && $ipt_m -A PSW2 $(comment "默认") -p tcp $(REDIRECT $REDIR_PORT TPROXY) [ -n "${is_tproxy}" ] && $ipt_m -A PSW2 $(comment "默认") -p tcp $(REDIRECT $REDIR_PORT TPROXY)
[ "$PROXY_IPV6" == "1" ] && { [ "$PROXY_IPV6" == "1" ] && {
$ip6t_m -A PSW2 $(comment "默认") -p tcp -d $FAKE_IP_6 -j PSW2_RULE $ip6t_m -A PSW2 $(comment "默认") -p tcp -d $FAKE_IP_6 -j PSW2_RULE
add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_m -A PSW2 $(comment "默认") -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport")" "-j PSW2_RULE" add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_m -A PSW2 $(comment "默认") -p tcp" "-j PSW2_RULE" $TCP_REDIR_PORTS
$ip6t_m -A PSW2 $(comment "默认") -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport") -j PSW2_RULE add_port_rules "$ip6t_m -A PSW2 $(comment "默认") -p tcp" $TCP_REDIR_PORTS "-j PSW2_RULE"
$ip6t_m -A PSW2 $(comment "默认") -p tcp $(REDIRECT $REDIR_PORT TPROXY) $ip6t_m -A PSW2 $(comment "默认") -p tcp $(REDIRECT $REDIR_PORT TPROXY)
} }
@ -551,14 +593,14 @@ load_acl() {
msg2="${msg}使用 UDP 节点[$(config_n_get $NODE remarks)](TPROXY:${REDIR_PORT})" msg2="${msg}使用 UDP 节点[$(config_n_get $NODE remarks)](TPROXY:${REDIR_PORT})"
$ipt_m -A PSW2 $(comment "默认") -p udp -d $FAKE_IP -j PSW2_RULE $ipt_m -A PSW2 $(comment "默认") -p udp -d $FAKE_IP -j PSW2_RULE
add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_m -A PSW2 $(comment "默认") -p udp $(factor $UDP_REDIR_PORTS "-m multiport --dport")" "-j PSW2_RULE" add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_m -A PSW2 $(comment "默认") -p udp" "-j PSW2_RULE" $UDP_REDIR_PORTS
$ipt_m -A PSW2 $(comment "默认") -p udp $(factor $UDP_REDIR_PORTS "-m multiport --dport") -j PSW2_RULE add_port_rules "$ipt_m -A PSW2 $(comment "默认") -p udp" $UDP_REDIR_PORTS "-j PSW2_RULE"
$ipt_m -A PSW2 $(comment "默认") -p udp $(REDIRECT $REDIR_PORT TPROXY) $ipt_m -A PSW2 $(comment "默认") -p udp $(REDIRECT $REDIR_PORT TPROXY)
[ "$PROXY_IPV6" == "1" ] && { [ "$PROXY_IPV6" == "1" ] && {
$ip6t_m -A PSW2 $(comment "默认") -p udp -d $FAKE_IP_6 -j PSW2_RULE $ip6t_m -A PSW2 $(comment "默认") -p udp -d $FAKE_IP_6 -j PSW2_RULE
add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_m -A PSW2 $(comment "默认") -p udp $(factor $UDP_REDIR_PORTS "-m multiport --dport")" "-j PSW2_RULE" add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_m -A PSW2 $(comment "默认") -p udp" "-j PSW2_RULE" $UDP_REDIR_PORTS
$ip6t_m -A PSW2 $(comment "默认") -p udp $(factor $UDP_REDIR_PORTS "-m multiport --dport") -j PSW2_RULE add_port_rules "$ip6t_m -A PSW2 $(comment "默认") -p udp" $UDP_REDIR_PORTS "-j PSW2_RULE"
$ip6t_m -A PSW2 $(comment "默认") -p udp $(REDIRECT $REDIR_PORT TPROXY) $ip6t_m -A PSW2 $(comment "默认") -p udp $(REDIRECT $REDIR_PORT TPROXY)
} }
@ -825,8 +867,8 @@ add_firewall_rule() {
msg="【路由器本机】," msg="【路由器本机】,"
[ "$TCP_NO_REDIR_PORTS" != "disable" ] && { [ "$TCP_NO_REDIR_PORTS" != "disable" ] && {
$ipt_tmp -A PSW2_OUTPUT -p tcp -m multiport --dport $TCP_NO_REDIR_PORTS -j RETURN add_port_rules "$ipt_tmp -A PSW2_OUTPUT -p tcp" $TCP_NO_REDIR_PORTS "-j RETURN"
$ip6t_m -A PSW2_OUTPUT -p tcp -m multiport --dport $TCP_NO_REDIR_PORTS -j RETURN add_port_rules "$ip6t_m -A PSW2_OUTPUT -p tcp" $TCP_NO_REDIR_PORTS "-j RETURN"
if [ "$TCP_NO_REDIR_PORTS" != "1:65535" ]; then if [ "$TCP_NO_REDIR_PORTS" != "1:65535" ]; then
echolog " - ${msg}不代理 TCP 端口[${TCP_NO_REDIR_PORTS}]" echolog " - ${msg}不代理 TCP 端口[${TCP_NO_REDIR_PORTS}]"
else else
@ -836,8 +878,8 @@ add_firewall_rule() {
} }
[ "$UDP_NO_REDIR_PORTS" != "disable" ] && { [ "$UDP_NO_REDIR_PORTS" != "disable" ] && {
$ipt_m -A PSW2_OUTPUT -p udp -m multiport --dport $UDP_NO_REDIR_PORTS -j RETURN add_port_rules "$ipt_m -A PSW2_OUTPUT -p udp" $UDP_NO_REDIR_PORTS "-j RETURN"
$ip6t_m -A PSW2_OUTPUT -p udp -m multiport --dport $UDP_NO_REDIR_PORTS -j RETURN add_port_rules "$ip6t_m -A PSW2_OUTPUT -p udp" $UDP_NO_REDIR_PORTS "-j RETURN"
if [ "$UDP_NO_REDIR_PORTS" != "1:65535" ]; then if [ "$UDP_NO_REDIR_PORTS" != "1:65535" ]; then
echolog " - ${msg}不代理 UDP 端口[${UDP_NO_REDIR_PORTS}]" echolog " - ${msg}不代理 UDP 端口[${UDP_NO_REDIR_PORTS}]"
else else
@ -878,8 +920,8 @@ add_firewall_rule() {
fi fi
$ipt_tmp -A PSW2_OUTPUT -p tcp -d $FAKE_IP ${ipt_j} $ipt_tmp -A PSW2_OUTPUT -p tcp -d $FAKE_IP ${ipt_j}
add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_tmp -A PSW2_OUTPUT -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport")" "${ipt_j}" add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_tmp -A PSW2_OUTPUT -p tcp" "${ipt_j}" $TCP_REDIR_PORTS
$ipt_tmp -A PSW2_OUTPUT -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport") ${ipt_j} add_port_rules "$ipt_tmp -A PSW2_OUTPUT -p tcp" $TCP_REDIR_PORTS "${ipt_j}"
[ -z "${is_tproxy}" ] && $ipt_n -A OUTPUT -p tcp -j PSW2_OUTPUT [ -z "${is_tproxy}" ] && $ipt_n -A OUTPUT -p tcp -j PSW2_OUTPUT
[ -n "${is_tproxy}" ] && { [ -n "${is_tproxy}" ] && {
$ipt_m -A PSW2 $(comment "本机") -p tcp -i lo $(REDIRECT $REDIR_PORT TPROXY) $ipt_m -A PSW2 $(comment "本机") -p tcp -i lo $(REDIRECT $REDIR_PORT TPROXY)
@ -889,8 +931,8 @@ add_firewall_rule() {
[ "$PROXY_IPV6" == "1" ] && { [ "$PROXY_IPV6" == "1" ] && {
$ip6t_m -A PSW2_OUTPUT -p tcp -d $FAKE_IP_6 -j PSW2_RULE $ip6t_m -A PSW2_OUTPUT -p tcp -d $FAKE_IP_6 -j PSW2_RULE
add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_m -A PSW2_OUTPUT -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport")" "-j PSW2_RULE" add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_m -A PSW2_OUTPUT -p tcp" "-j PSW2_RULE" $TCP_REDIR_PORTS
$ip6t_m -A PSW2_OUTPUT -p tcp $(factor $TCP_REDIR_PORTS "-m multiport --dport") -j PSW2_RULE add_port_rules "$ip6t_m -A PSW2_OUTPUT -p tcp" $TCP_REDIR_PORTS "-j PSW2_RULE"
$ip6t_m -A PSW2 $(comment "本机") -p tcp -i lo $(REDIRECT $REDIR_PORT TPROXY) $ip6t_m -A PSW2 $(comment "本机") -p tcp -i lo $(REDIRECT $REDIR_PORT TPROXY)
$ip6t_m -A PSW2 $(comment "本机") -p tcp -i lo -j RETURN $ip6t_m -A PSW2 $(comment "本机") -p tcp -i lo -j RETURN
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -p tcp -j PSW2_OUTPUT" insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -p tcp -j PSW2_OUTPUT"
@ -907,16 +949,16 @@ add_firewall_rule() {
# 加载路由器自身代理 UDP # 加载路由器自身代理 UDP
if [ -n "$NODE" ] && [ "$UDP_LOCALHOST_PROXY" = "1" ]; then if [ -n "$NODE" ] && [ "$UDP_LOCALHOST_PROXY" = "1" ]; then
$ipt_m -A PSW2_OUTPUT -p udp -d $FAKE_IP -j PSW2_RULE $ipt_m -A PSW2_OUTPUT -p udp -d $FAKE_IP -j PSW2_RULE
add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_m -A PSW2_OUTPUT -p udp $(factor $UDP_REDIR_PORTS "-m multiport --dport")" "-j PSW2_RULE" add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_m -A PSW2_OUTPUT -p udp" "-j PSW2_RULE" $UDP_REDIR_PORTS
$ipt_m -A PSW2_OUTPUT -p udp $(factor $UDP_REDIR_PORTS "-m multiport --dport") -j PSW2_RULE add_port_rules "$ipt_m -A PSW2_OUTPUT -p udp" $UDP_REDIR_PORTS "-j PSW2_RULE"
$ipt_m -A PSW2 $(comment "本机") -p udp -i lo $(REDIRECT $REDIR_PORT TPROXY) $ipt_m -A PSW2 $(comment "本机") -p udp -i lo $(REDIRECT $REDIR_PORT TPROXY)
$ipt_m -A PSW2 $(comment "本机") -p udp -i lo -j RETURN $ipt_m -A PSW2 $(comment "本机") -p udp -i lo -j RETURN
insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -p udp -j PSW2_OUTPUT" insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -p udp -j PSW2_OUTPUT"
[ "$PROXY_IPV6" == "1" ] && { [ "$PROXY_IPV6" == "1" ] && {
$ip6t_m -A PSW2_OUTPUT -p udp -d $FAKE_IP_6 -j PSW2_RULE $ip6t_m -A PSW2_OUTPUT -p udp -d $FAKE_IP_6 -j PSW2_RULE
add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_m -A PSW2_OUTPUT -p udp $(factor $UDP_REDIR_PORTS "-m multiport --dport")" "-j PSW2_RULE" add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_m -A PSW2_OUTPUT -p udp" "-j PSW2_RULE" $UDP_REDIR_PORTS
$ip6t_m -A PSW2_OUTPUT -p udp $(factor $UDP_REDIR_PORTS "-m multiport --dport") -j PSW2_RULE add_port_rules "$ip6t_m -A PSW2_OUTPUT -p udp" $UDP_REDIR_PORTS "-j PSW2_RULE"
$ip6t_m -A PSW2 $(comment "本机") -p udp -i lo $(REDIRECT $REDIR_PORT TPROXY) $ip6t_m -A PSW2 $(comment "本机") -p udp -i lo $(REDIRECT $REDIR_PORT TPROXY)
$ip6t_m -A PSW2 $(comment "本机") -p udp -i lo -j RETURN $ip6t_m -A PSW2 $(comment "本机") -p udp -i lo -j RETURN
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -p udp -j PSW2_OUTPUT" insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -p udp -j PSW2_OUTPUT"

View File

@ -20,15 +20,26 @@ FAKE_IP="198.18.0.0/16"
FAKE_IP_6="fc00::/18" FAKE_IP_6="fc00::/18"
factor() { factor() {
if [ -z "$1" ] || [ -z "$2" ]; then local ports="$1"
echo "" if [ -z "$1" ] || [ -z "$2" ] || [ "$ports" = "1:65535" ]; then
elif [ "$1" == "1:65535" ]; then
echo "" echo ""
# acl mac address # acl mac address
elif [ -n "$(echo $1 | grep -E '([A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}')" ]; then elif echo "$1" | grep -qE '([A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}'; then
echo "$2 {$1}" echo "$2 {$1}"
else else
echo "$2 {$(echo $1 | sed 's/:/-/g')}" ports=$(echo "$ports" | tr -d ' ' | sed 's/:/-/g' | tr ',' '\n' | awk '!a[$0]++' | grep -v '^$')
[ -z "$ports" ] && { echo ""; return; }
if echo "$ports" | grep -q '^1-65535$'; then
echo ""
return
fi
local port
local port_list=""
for port in $ports; do
port_list="${port_list},$port"
done
port_list="${port_list#,}"
echo "$2 {$port_list}"
fi fi
} }

View File

@ -543,8 +543,8 @@ local function processData(szType, content, add_mode, add_from)
info.type = "none" info.type = "none"
end end
result.tcp_guise = info.type result.tcp_guise = info.type
result.tcp_guise_http_host = info.host result.tcp_guise_http_host = (info.host and info.host ~= "") and { info.host } or nil
result.tcp_guise_http_path = info.path result.tcp_guise_http_path = (info.path and info.path ~= "") and { info.path } or nil
end end
if info.net == 'kcp' or info.net == 'mkcp' then if info.net == 'kcp' or info.net == 'mkcp' then
info.net = "mkcp" info.net = "mkcp"
@ -586,7 +586,12 @@ local function processData(szType, content, add_mode, add_from)
if info.tls == "tls" or info.tls == "1" then if info.tls == "tls" or info.tls == "1" then
result.tls = "1" result.tls = "1"
result.tls_serverName = (info.sni and info.sni ~= "") and info.sni or info.host result.tls_serverName = (info.sni and info.sni ~= "") and info.sni or info.host
result.tls_allowInsecure = allowInsecure_default and "1" or "0" info.allowinsecure = info.allowinsecure or info.insecure
if info.allowinsecure and (info.allowinsecure == "1" or info.allowinsecure == "0") then
result.tls_allowInsecure = info.allowinsecure
else
result.tls_allowInsecure = allowInsecure_default and "1" or "0"
end
else else
result.tls = "0" result.tls = "0"
end end
@ -692,8 +697,27 @@ local function processData(szType, content, add_mode, add_from)
if result.plugin then if result.plugin then
if result.type == 'Xray' then if result.type == 'Xray' then
--不支持插件 -- obfs-local插件转换成xray支持的格式
result.error_msg = "Xray不支持插件." if result.plugin ~= "obfs-local" then
result.error_msg = "Xray不支持 " .. result.plugin .. " 插件."
else
local obfs = result.plugin_opts:match("obfs=([^;]+)") or ""
local obfs_host = result.plugin_opts:match("obfs%-host=([^;]+)") or ""
if obfs == "" or obfs_host == "" then
result.error_msg = "SS " .. result.plugin .. " 插件选项不完整."
end
if obfs == "http" then
result.transport = "raw"
result.tcp_guise = "http"
result.tcp_guise_http_host = (obfs_host and obfs_host ~= "") and { obfs_host } or nil
elseif obfs == "tls" then
result.tls = "1"
result.tls_serverName = obfs_host
result.tls_allowInsecure = "1"
end
result.plugin = nil
result.plugin_opts = nil
end
end end
if result.type == "sing-box" then if result.type == "sing-box" then
result.plugin_enabled = "1" result.plugin_enabled = "1"
@ -761,8 +785,8 @@ local function processData(szType, content, add_mode, add_from)
end end
if params.type == 'raw' or params.type == 'tcp' then if params.type == 'raw' or params.type == 'tcp' then
result.tcp_guise = params.headerType or "none" result.tcp_guise = params.headerType or "none"
result.tcp_guise_http_host = params.host result.tcp_guise_http_host = (params.host and params.host ~= "") and { params.host } or nil
result.tcp_guise_http_path = params.path result.tcp_guise_http_path = (params.path and params.path ~= "") and { params.path } or nil
end end
if params.type == 'kcp' or params.type == 'mkcp' then if params.type == 'kcp' or params.type == 'mkcp' then
result.transport = "mkcp" result.transport = "mkcp"
@ -790,7 +814,10 @@ local function processData(szType, content, add_mode, add_from)
result.tls = "1" result.tls = "1"
result.tls_serverName = (params.sni and params.sni ~= "") and params.sni or params.host result.tls_serverName = (params.sni and params.sni ~= "") and params.sni or params.host
result.alpn = params.alpn result.alpn = params.alpn
result.fingerprint = (params.fp and params.fp ~= "") and params.fp or "chrome" if params.fp and params.fp ~= "" then
result.utls = "1"
result.fingerprint = params.fp
end
if params.security == "reality" then if params.security == "reality" then
result.reality = "1" result.reality = "1"
result.reality_publicKey = params.pbk or nil result.reality_publicKey = params.pbk or nil
@ -798,7 +825,12 @@ local function processData(szType, content, add_mode, add_from)
result.reality_spiderX = params.spx or nil result.reality_spiderX = params.spx or nil
end end
end end
result.tls_allowInsecure = allowInsecure_default and "1" or "0" params.allowinsecure = params.allowinsecure or params.insecure
if params.allowinsecure and (params.allowinsecure == "1" or params.allowinsecure == "0") then
result.tls_allowInsecure = params.allowinsecure
else
result.tls_allowInsecure = allowInsecure_default and "1" or "0"
end
else else
result.error_msg = "请更换Xray或Sing-Box来支持SS更多的传输方式." result.error_msg = "请更换Xray或Sing-Box来支持SS更多的传输方式."
end end
@ -860,6 +892,7 @@ local function processData(szType, content, add_mode, add_from)
result.tls = '1' result.tls = '1'
result.tls_serverName = peer and peer or sni result.tls_serverName = peer and peer or sni
params.allowinsecure = params.allowinsecure or params.insecure
if params.allowinsecure then if params.allowinsecure then
if params.allowinsecure == "1" or params.allowinsecure == "0" then if params.allowinsecure == "1" or params.allowinsecure == "0" then
result.tls_allowInsecure = params.allowinsecure result.tls_allowInsecure = params.allowinsecure
@ -917,8 +950,8 @@ local function processData(szType, content, add_mode, add_from)
end end
if params.type == 'raw' or params.type == 'tcp' then if params.type == 'raw' or params.type == 'tcp' then
result.tcp_guise = params.headerType or "none" result.tcp_guise = params.headerType or "none"
result.tcp_guise_http_host = params.host result.tcp_guise_http_host = (params.host and params.host ~= "") and { params.host } or nil
result.tcp_guise_http_path = params.path result.tcp_guise_http_path = (params.path and params.path ~= "") and { params.path } or nil
end end
if params.type == 'kcp' or params.type == 'mkcp' then if params.type == 'kcp' or params.type == 'mkcp' then
result.transport = "mkcp" result.transport = "mkcp"
@ -1062,8 +1095,8 @@ local function processData(szType, content, add_mode, add_from)
end end
if params.type == 'raw' or params.type == 'tcp' then if params.type == 'raw' or params.type == 'tcp' then
result.tcp_guise = params.headerType or "none" result.tcp_guise = params.headerType or "none"
result.tcp_guise_http_host = params.host result.tcp_guise_http_host = (params.host and params.host ~= "") and { params.host } or nil
result.tcp_guise_http_path = params.path result.tcp_guise_http_path = (params.path and params.path ~= "") and { params.path } or nil
end end
if params.type == 'kcp' or params.type == 'mkcp' then if params.type == 'kcp' or params.type == 'mkcp' then
result.transport = "mkcp" result.transport = "mkcp"
@ -1114,7 +1147,10 @@ local function processData(szType, content, add_mode, add_from)
result.tls = "1" result.tls = "1"
result.tls_serverName = (params.sni and params.sni ~= "") and params.sni or params.host result.tls_serverName = (params.sni and params.sni ~= "") and params.sni or params.host
result.alpn = params.alpn result.alpn = params.alpn
result.fingerprint = (params.fp and params.fp ~= "") and params.fp or "chrome" if params.fp and params.fp ~= "" then
result.utls = "1"
result.fingerprint = params.fp
end
if params.security == "reality" then if params.security == "reality" then
result.reality = "1" result.reality = "1"
result.reality_publicKey = params.pbk or nil result.reality_publicKey = params.pbk or nil
@ -1124,7 +1160,13 @@ local function processData(szType, content, add_mode, add_from)
end end
result.port = port result.port = port
result.tls_allowInsecure = allowInsecure_default and "1" or "0"
params.allowinsecure = params.allowinsecure or params.insecure
if params.allowinsecure and (params.allowinsecure == "1" or params.allowinsecure == "0") then
result.tls_allowInsecure = params.allowinsecure
else
result.tls_allowInsecure = allowInsecure_default and "1" or "0"
end
if result.type == "sing-box" and (result.transport == "mkcp" or result.transport == "xhttp" or result.transport == "splithttp") then if result.type == "sing-box" and (result.transport == "mkcp" or result.transport == "xhttp" or result.transport == "splithttp") then
log("跳过节点:" .. result.remarks .."因Sing-Box不支持" .. szType .. "协议的" .. result.transport .. "传输方式需更换Xray。") log("跳过节点:" .. result.remarks .."因Sing-Box不支持" .. szType .. "协议的" .. result.transport .. "传输方式需更换Xray。")
@ -1167,8 +1209,12 @@ local function processData(szType, content, add_mode, add_from)
result.hysteria_auth_type = "string" result.hysteria_auth_type = "string"
result.hysteria_auth_password = params.auth result.hysteria_auth_password = params.auth
result.tls_serverName = params.peer result.tls_serverName = params.peer
if params.insecure and params.insecure == "1" then params.allowinsecure = params.allowinsecure or params.insecure
result.tls_allowInsecure = "1" if params.allowinsecure and (params.allowinsecure == "1" or params.allowinsecure == "0") then
result.tls_allowInsecure = params.allowinsecure
--log(result.remarks ..' 使用节点AllowInsecure设定: '.. result.tls_allowInsecure)
else
result.tls_allowInsecure = allowInsecure_default and "1" or "0"
end end
result.hysteria_alpn = params.alpn result.hysteria_alpn = params.alpn
result.hysteria_up_mbps = params.upmbps result.hysteria_up_mbps = params.upmbps
@ -1215,8 +1261,9 @@ local function processData(szType, content, add_mode, add_from)
result.address = host_port result.address = host_port
end end
result.tls_serverName = params.sni result.tls_serverName = params.sni
if params.insecure and (params.insecure == "1" or params.insecure == "0") then params.allowinsecure = params.allowinsecure or params.insecure
result.tls_allowInsecure = params.insecure if params.allowinsecure and (params.allowinsecure == "1" or params.allowinsecure == "0") then
result.tls_allowInsecure = params.allowinsecure
--log(result.remarks ..' 使用节点AllowInsecure设定: '.. result.tls_allowInsecure) --log(result.remarks ..' 使用节点AllowInsecure设定: '.. result.tls_allowInsecure)
else else
result.tls_allowInsecure = allowInsecure_default and "1" or "0" result.tls_allowInsecure = allowInsecure_default and "1" or "0"
@ -1278,6 +1325,7 @@ local function processData(szType, content, add_mode, add_from)
result.tls_serverName = params.sni result.tls_serverName = params.sni
result.tuic_alpn = params.alpn or "default" result.tuic_alpn = params.alpn or "default"
result.tuic_congestion_control = params.congestion_control or "cubic" result.tuic_congestion_control = params.congestion_control or "cubic"
params.allowinsecure = params.allowinsecure or params.insecure
if params.allowinsecure then if params.allowinsecure then
if params.allowinsecure == "1" or params.allowinsecure == "0" then if params.allowinsecure == "1" or params.allowinsecure == "0" then
result.tls_allowInsecure = params.allowinsecure result.tls_allowInsecure = params.allowinsecure
@ -1290,6 +1338,70 @@ local function processData(szType, content, add_mode, add_from)
end end
result.type = 'sing-box' result.type = 'sing-box'
result.protocol = "tuic" result.protocol = "tuic"
elseif szType == "anytls" then
result.type = 'sing-box'
result.protocol = "anytls"
local alias = ""
if content:find("#") then
local idx_sp = content:find("#")
alias = content:sub(idx_sp + 1, -1)
content = content:sub(0, idx_sp - 1)
end
result.remarks = UrlDecode(alias)
if content:find("@") then
local Info = split(content, "@")
result.password = UrlDecode(Info[1])
local port = "443"
Info[2] = (Info[2] or ""):gsub("/%?", "?")
local query = split(Info[2], "?")
local host_port = query[1]
local params = {}
for _, v in pairs(split(query[2], '&')) do
local t = split(v, '=')
params[t[1]] = UrlDecode(t[2])
end
-- [2001:4860:4860::8888]:443
-- 8.8.8.8:443
if host_port:find(":") then
local sp = split(host_port, ":")
port = sp[#sp]
if api.is_ipv6addrport(host_port) then
result.address = api.get_ipv6_only(host_port)
else
result.address = sp[1]
end
else
result.address = host_port
end
result.tls = "0"
if params.security == "tls" or params.security == "reality" then
result.tls = "1"
result.tls_serverName = (params.sni and params.sni ~= "") and params.sni or params.host
result.alpn = params.alpn
if params.fp and params.fp ~= "" then
result.utls = "1"
result.fingerprint = params.fp
end
if params.security == "reality" then
result.reality = "1"
result.reality_publicKey = params.pbk or nil
result.reality_shortId = params.sid or nil
end
end
result.port = port
params.allowinsecure = params.allowinsecure or params.insecure
if params.allowinsecure and (params.allowinsecure == "1" or params.allowinsecure == "0") then
result.tls_allowInsecure = params.allowinsecure
else
result.tls_allowInsecure = allowInsecure_default and "1" or "0"
end
local singbox_version = api.get_app_version("sing-box")
local version_ge_1_12 = api.compare_versions(singbox_version:match("[^v]+"), ">=", "1.12.0")
if not has_singbox or not version_ge_1_12 then
log("跳过节点:" .. result.remarks ..",因" .. szType .. "类型的节点需要 Sing-Box 1.12 以上版本支持。")
return nil
end
end
else else
log('暂时不支持' .. szType .. "类型的节点订阅,跳过此节点。") log('暂时不支持' .. szType .. "类型的节点订阅,跳过此节点。")
return nil return nil
@ -1512,10 +1624,14 @@ local function update_node(manual)
for _, vv in ipairs(list) do for _, vv in ipairs(list) do
local cfgid = uci:section(appname, "nodes", api.gen_short_uuid()) local cfgid = uci:section(appname, "nodes", api.gen_short_uuid())
for kkk, vvv in pairs(vv) do for kkk, vvv in pairs(vv) do
uci:set(appname, cfgid, kkk, vvv) if type(vvv) == "table" and next(vvv) ~= nil then
-- sing-box 域名解析策略 uci:set_list(appname, cfgid, kkk, vvv)
if kkk == "type" and vvv == "sing-box" then else
uci:set(appname, cfgid, "domain_strategy", domain_strategy_node) uci:set(appname, cfgid, kkk, vvv)
-- sing-box 域名解析策略
if kkk == "type" and vvv == "sing-box" then
uci:set(appname, cfgid, "domain_strategy", domain_strategy_node)
end
end end
end end
end end