update 2025-04-29 09:45:01

This commit is contained in:
kenzok8 2025-04-29 09:45:01 +08:00
parent 2cd25398e5
commit 91c7cc9ee4
7 changed files with 204 additions and 0 deletions

View File

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

View File

@ -8,6 +8,9 @@ if not singbox_bin then
return
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 appname = "passwall"
@ -56,6 +59,9 @@ end
if singbox_tags:find("with_quic") then
o:value("hysteria2", "Hysteria2")
end
if version_ge_1_12_0 then
o:value("anytls", "AnyTLS")
end
o:value("_urltest", translate("URLTest"))
o:value("_shunt", translate("Shunt"))
o:value("_iface", translate("Custom Interface"))
@ -248,6 +254,7 @@ o:depends({ [_n("protocol")] = "shadowsocks" })
o:depends({ [_n("protocol")] = "shadowsocksr" })
o:depends({ [_n("protocol")] = "trojan" })
o:depends({ [_n("protocol")] = "tuic" })
o:depends({ [_n("protocol")] = "anytls" })
o = s:option(ListValue, _n("security"), translate("Encrypt Method"))
for a, t in ipairs(security_list) do o:value(t) end
@ -428,6 +435,7 @@ o:depends({ [_n("protocol")] = "vless" })
o:depends({ [_n("protocol")] = "http" })
o:depends({ [_n("protocol")] = "trojan" })
o:depends({ [_n("protocol")] = "shadowsocks" })
o:depends({ [_n("protocol")] = "anytls" })
o = s:option(ListValue, _n("alpn"), translate("alpn"))
o.default = "default"
@ -513,6 +521,7 @@ if singbox_tags:find("with_utls") then
o:depends({ [_n("protocol")] = "shadowsocks", [_n("utls")] = true })
o:depends({ [_n("protocol")] = "socks", [_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:depends({ [_n("utls")] = true, [_n("reality")] = true })
@ -731,6 +740,7 @@ o:depends({ [_n("protocol")] = "hysteria" })
o:depends({ [_n("protocol")] = "vless" })
o:depends({ [_n("protocol")] = "tuic" })
o:depends({ [_n("protocol")] = "hysteria2" })
o:depends({ [_n("protocol")] = "anytls" })
o = s:option(ListValue, _n("chain_proxy"), translate("Chain Proxy"))
o:value("", translate("Close(Not use)"))

View File

@ -8,6 +8,9 @@ if not singbox_bin then
return
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}'")
@ -47,6 +50,9 @@ end
if singbox_tags:find("with_quic") then
o:value("hysteria2", "Hysteria2")
end
if version_ge_1_12_0 then
o:value("anytls", "AnyTLS")
end
o:value("direct", "Direct")
o = s:option(Value, _n("port"), translate("Listen Port"))
@ -70,6 +76,7 @@ o:depends({ [_n("protocol")] = "http" })
o = s:option(Value, _n("username"), translate("Username"))
o:depends({ [_n("auth")] = true })
o:depends({ [_n("protocol")] = "naive" })
o:depends({ [_n("protocol")] = "anytls" })
o = s:option(Value, _n("password"), translate("Password"))
o.password = true
@ -77,6 +84,7 @@ o:depends({ [_n("auth")] = true })
o:depends({ [_n("protocol")] = "shadowsocks" })
o:depends({ [_n("protocol")] = "naive" })
o:depends({ [_n("protocol")] = "tuic" })
o:depends({ [_n("protocol")] = "anytls" })
if singbox_tags:find("with_quic") then
o = s:option(Value, _n("hysteria_up_mbps"), translate("Max upload Mbps"))
@ -220,6 +228,7 @@ o:depends({ [_n("protocol")] = "http" })
o:depends({ [_n("protocol")] = "vmess" })
o:depends({ [_n("protocol")] = "vless" })
o:depends({ [_n("protocol")] = "trojan" })
o:depends({ [_n("protocol")] = "anytls" })
if singbox_tags:find("with_reality_server") then
-- [[ REALITY部分 ]] --
@ -229,6 +238,7 @@ if singbox_tags:find("with_reality_server") then
o:depends({ [_n("protocol")] = "vmess", [_n("tls")] = true })
o:depends({ [_n("protocol")] = "vless", [_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:depends({ [_n("reality")] = true })

View File

@ -522,6 +522,8 @@ function get_valid_nodes()
protocol = "HY"
elseif protocol == "hysteria2" then
protocol = "HY2"
elseif protocol == "anytls" then
protocol = "AnyTLS"
else
protocol = protocol:gsub("^%l",string.upper)
end
@ -566,6 +568,8 @@ function get_node_remarks(n)
protocol = "HY"
elseif protocol == "hysteria2" then
protocol = "HY2"
elseif protocol == "anytls" then
protocol = "AnyTLS"
else
protocol = protocol:gsub("^%l",string.upper)
end

View File

@ -441,6 +441,13 @@ function gen_outbound(flag, node, tag, proxy_table)
}
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
for key, value in pairs(protocol_table) do
result[key] = value
@ -730,6 +737,18 @@ function gen_config_server(node)
}
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
protocol_table = {
network = (node.d_protocol ~= "TCP,UDP") and node.d_protocol or nil,

View File

@ -546,6 +546,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("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);
if (params[0] == "&") {
params = params.substring(1);
@ -1373,6 +1408,66 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin
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 (opt.get(dom_prefix + 'port').value) {
opt.get(dom_prefix + 'port').focus();

View File

@ -1290,6 +1290,70 @@ local function processData(szType, content, add_mode, add_from)
end
result.type = 'sing-box'
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
log('暂时不支持' .. szType .. "类型的节点订阅,跳过此节点。")
return nil