mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-01 16:44:23 +08:00
🍓 Sync 2026-10-01 00:51:52
This commit is contained in:
1 parent
57dc97412f
commit
d45a1cb4ad
60 files changed
+2630
-1193
No files matched your search
@@ -6,8 +6,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall2
|
||||
PKG_VERSION:=26.9.16
|
||||
PKG_RELEASE:=131
|
||||
PKG_VERSION:=26.10.1
|
||||
PKG_RELEASE:=132
|
||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
|
||||
@@ -271,11 +271,12 @@ o:value("proxy", translate("Proxy"))
|
||||
|
||||
o = s:option(Value, "user_agent", translate("User-Agent"))
|
||||
o.default = "v2rayN/9.99"
|
||||
o:value("curl", "Curl")
|
||||
o:value("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0", "Edge for Linux")
|
||||
o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0", "Edge for Windows")
|
||||
o:value("passwall2", "PassWall2")
|
||||
o:value("v2rayN/9.99", "v2rayN")
|
||||
o:value("clash.meta/v9.99.99", "Clash.Meta")
|
||||
o:value("Shadowrocket/9999 CFNetwork/3896.100.1.2.1 Darwin/27.0.0 iPhone19,7", "Shadowrocket")
|
||||
o:value("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0", "Edge for Linux")
|
||||
o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0", "Edge for Windows")
|
||||
|
||||
o = s:option(ListValue, "chain_proxy", translate("Chain Proxy"))
|
||||
o:value("", translate("Close(Not use)"))
|
||||
|
||||
@@ -560,10 +560,18 @@ o:depends({ protocol = "naive" })
|
||||
o = s:option(Flag, "tls_allowInsecure", translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."))
|
||||
o.default = "0"
|
||||
o:depends({ tls = true })
|
||||
o:depends({ protocol = "hysteria"})
|
||||
o:depends({ protocol = "hysteria" })
|
||||
o:depends({ protocol = "tuic" })
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
|
||||
o = s:option(Value, "tls_pinSHA256", translate("TLS Chain Fingerprint (SHA256)"))
|
||||
o:depends({ tls = true })
|
||||
o:depends({ protocol = "hysteria" })
|
||||
o:depends({ protocol = "tuic" })
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
o.description = translate("Once set, connects only when the server’s chain fingerprint matches.") ..
|
||||
string.format("<a href='javascript:void(0)' onclick='javascript:fetchCertSha256(this)'>%s</a>", "→ " .. translate("Fetch Manually"))
|
||||
|
||||
o = s:option(Flag, "tls_certificate", translate("TLS Certificate (PEM)"))
|
||||
o.default = "0"
|
||||
o:depends({ tls = true, reality = false })
|
||||
|
||||
@@ -227,16 +227,19 @@ function exec_call(cmd)
|
||||
end
|
||||
|
||||
function base64Decode(text)
|
||||
if not text then return '' end
|
||||
local encoded = text:gsub("%z", ""):gsub("%c", ""):gsub("_", "/"):gsub("-", "+")
|
||||
if type(text) ~= "string" then return "" end
|
||||
local encoded = text:gsub("%z", ""):gsub("%c", ""):gsub("_", "/"):gsub("-", "+"):gsub("=+$", "")
|
||||
if encoded == "" then return text end
|
||||
if not encoded:match("^[A-Za-z0-9+/]*$") then return text end
|
||||
local mod4 = #encoded % 4
|
||||
encoded = encoded .. string.sub('====', mod4 + 1)
|
||||
local result = nixio.bin.b64decode(encoded)
|
||||
if result then
|
||||
return result:gsub("%z", "")
|
||||
else
|
||||
return text
|
||||
end
|
||||
if mod4 == 1 then return text end
|
||||
local padded = encoded .. string.rep("=", (4 - mod4) % 4)
|
||||
local result = nixio.bin.b64decode(padded)
|
||||
if not result then return text end
|
||||
-- Verify that the normalized input is canonical Base64.
|
||||
local reencoded = nixio.bin.b64encode(result):gsub("=+$", "")
|
||||
if reencoded ~= encoded then return text end
|
||||
return (result:gsub("%z", ""))
|
||||
end
|
||||
|
||||
function base64Encode(text)
|
||||
@@ -1866,6 +1869,25 @@ function fetch_cert_sha256(host, port, sni, timeout)
|
||||
return fp:upper()
|
||||
end
|
||||
|
||||
function sha256_xray_sb(str)
|
||||
local decoded = base64Decode(str)
|
||||
if decoded ~= str and #decoded == 32 then return str end
|
||||
local hex = str:gsub(":", "")
|
||||
if #hex ~= 64 or not hex:match("^[A-Fa-f0-9]+$") then return str end
|
||||
local binary = hex:gsub("%x%x", function(byte)
|
||||
return string.char(tonumber(byte, 16))
|
||||
end)
|
||||
return base64Encode(binary)
|
||||
end
|
||||
|
||||
function sha256_sb_xray(str)
|
||||
local binary = base64Decode(str)
|
||||
if binary == str or #binary ~= 32 then return str end
|
||||
return (binary:gsub(".", function(byte)
|
||||
return string.format("%02X", string.byte(byte))
|
||||
end))
|
||||
end
|
||||
|
||||
function get_dnsmasq_server_domain()
|
||||
local dnsmasq_server = uci:get("dhcp", "@dnsmasq[0]", "server")
|
||||
local dnsmasq_server_t = {}
|
||||
|
||||
@@ -9,6 +9,7 @@ local ech_domain = {}
|
||||
|
||||
local local_version = api.get_app_version("sing-box"):match("[^v]+")
|
||||
local version_ge_1_14_0 = api.compare_versions(local_version, ">=", "1.14.0")
|
||||
local version_ge_1_15_0 = api.compare_versions(local_version, ">=", "1.15.0")
|
||||
|
||||
local GLOBAL = {
|
||||
DNS_SERVER = {}
|
||||
@@ -248,7 +249,7 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
enabled = true,
|
||||
disable_sni = (node.tls_disable_sni == "1") and true or false, -- Do not send the server name in ClientHello.
|
||||
server_name = node.tls_serverName, -- Used to verify the hostname on the returned certificate, unless the settings are insecure. It is also included in ClientHello to support virtual hosts, unless it is an IP address.
|
||||
insecure = node.tls_allowInsecure == "1" or (node.tls_pinSHA256 and node.tls_pinSHA256 ~= ""), -- Accepts any server certificate. (Also compatible with xray's pinnedPeerCertSha256)
|
||||
insecure = node.tls_allowInsecure == "1", -- Accepts any server certificate.
|
||||
alpn = alpn, -- A list of supported application layer protocols, arranged in order of priority. If both peers support ALPN, the protocol selected will be one of these protocols; otherwise, the connection will fail.
|
||||
--max_version = "1.3",
|
||||
fragment = fragment,
|
||||
@@ -294,6 +295,13 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
short_id = node.reality_shortId
|
||||
} or nil
|
||||
}
|
||||
if version_ge_1_15_0 then
|
||||
if node.tls_pinSHA256 and node.tls_pinSHA256 ~= "" then
|
||||
tls.certificate_sha256 = { api.sha256_xray_sb(node.tls_pinSHA256) }
|
||||
end
|
||||
else
|
||||
tls.insecure = node.tls_allowInsecure == "1" or (node.tls_pinSHA256 and node.tls_pinSHA256 ~= "")
|
||||
end
|
||||
end
|
||||
|
||||
local mux = nil
|
||||
@@ -1488,6 +1496,10 @@ function gen_config(var)
|
||||
end
|
||||
end
|
||||
if to_node then
|
||||
local chained_tag = outbound.tag .. " -> " .. to_node[".name"] .. (to_node.remarks and ":" .. to_node.remarks or "")
|
||||
for _, o in ipairs(outbounds_table) do
|
||||
if o.tag == chained_tag then return chained_tag, last_insert_outbound end
|
||||
end
|
||||
local to_outbound
|
||||
if to_node.type ~= "sing-box" then
|
||||
local tag = to_node[".name"]
|
||||
@@ -1549,7 +1561,7 @@ function gen_config(var)
|
||||
local outbound, exist
|
||||
if node.protocol == "_urltest" then
|
||||
outbound, exist = gen_urltest_outbound(node)
|
||||
if exist then
|
||||
if exist and not node.chain_proxy then
|
||||
return outbound.tag
|
||||
end
|
||||
elseif node.protocol == "_iface" then
|
||||
@@ -1583,7 +1595,7 @@ function gen_config(var)
|
||||
end
|
||||
if outbound then
|
||||
local default_outbound_tag, last_insert_outbound = set_outbound_detour(node, outbound, outbounds)
|
||||
table.insert(outbounds, outbound)
|
||||
if not exist then table.insert(outbounds, outbound) end
|
||||
if last_insert_outbound then
|
||||
table.insert(outbounds, last_insert_outbound)
|
||||
end
|
||||
@@ -2030,7 +2042,7 @@ function gen_config(var)
|
||||
tag = fakedns_tag,
|
||||
type = "fakeip",
|
||||
inet4_range = "198.18.0.0/16",
|
||||
inet6_range = "fc00::/18",
|
||||
inet6_range = "2001:2::/48",
|
||||
})
|
||||
|
||||
if not experimental then
|
||||
|
||||
@@ -186,7 +186,7 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
tlsSettings = (node.stream_security == "tls") and {
|
||||
serverName = node.tls_serverName,
|
||||
fingerprint = (node.type == "Xray" and node.utls == "1" and node.fingerprint and node.fingerprint ~= "") and node.fingerprint or nil,
|
||||
pinnedPeerCertSha256 = node.tls_pinSHA256 or "",
|
||||
pinnedPeerCertSha256 = (node.tls_pinSHA256 and node.tls_pinSHA256 ~= "") and api.sha256_sb_xray(node.tls_pinSHA256) or "",
|
||||
verifyPeerCertByName = node.tls_CertByName or "",
|
||||
echConfigList = (node.ech == "1") and node.ech_config or nil,
|
||||
certificates = (node.tls_certificate == "1" and node.tls_certificate_pem ~= "") and {
|
||||
@@ -1058,6 +1058,9 @@ function gen_config(var)
|
||||
function gen_loopback(outbound_tag, loopback_dst)
|
||||
if not outbound_tag or outbound_tag == "" then return nil end
|
||||
local inbound_tag = loopback_dst and "lo-to-" .. loopback_dst or outbound_tag .. "-lo"
|
||||
for _, o in ipairs(outbounds) do
|
||||
if o.tag == outbound_tag and o.protocol == "loopback" and o.settings.inboundTag == inbound_tag then return o end
|
||||
end
|
||||
local loopback_outbound = {
|
||||
protocol = "loopback",
|
||||
tag = outbound_tag,
|
||||
@@ -1697,7 +1700,7 @@ function gen_config(var)
|
||||
poolSize = 65535
|
||||
}
|
||||
local fakedns6 = {
|
||||
ipPool = "fc00::/18",
|
||||
ipPool = "2001:2::/48",
|
||||
poolSize = 65535
|
||||
}
|
||||
if remote_dns_query_strategy == "UseIP" then
|
||||
|
||||
@@ -22,7 +22,7 @@ local sid = self.section
|
||||
alert(res && res.msg ? res.msg : "<%:Fetch Failed%> !");
|
||||
return;
|
||||
}
|
||||
const inputs = document.querySelectorAll('input[id$=".xray_tls_pinSHA256"]');
|
||||
const inputs = document.querySelectorAll('input[id$="_tls_pinSHA256"]');
|
||||
inputs.forEach(function(input) {
|
||||
input.value = res.data;
|
||||
});
|
||||
|
||||
@@ -41,19 +41,25 @@ local current_node = map:get(section)
|
||||
}
|
||||
|
||||
function b64DecodeUnicode(str) {
|
||||
return decodeURIComponent(Array.prototype.map.call(atob(str), function (c) {
|
||||
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
||||
}).join(''));
|
||||
try {
|
||||
return decodeURIComponent(Array.prototype.map.call(atob(str), function (c) {
|
||||
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
||||
}).join(''));
|
||||
} catch (e) {}
|
||||
return str;
|
||||
}
|
||||
|
||||
function b64decutf8safe(str) {
|
||||
var l;
|
||||
const orig = str;
|
||||
let l;
|
||||
str = str.replace(/-/g, "+").replace(/_/g, "/");
|
||||
l = str.length;
|
||||
l = (4 - l % 4) % 4;
|
||||
if (l)
|
||||
str = padright(str, l, "=");
|
||||
return b64DecodeUnicode(str);
|
||||
const text = b64DecodeUnicode(str);
|
||||
if (text !== str) return text;
|
||||
return orig;
|
||||
}
|
||||
|
||||
function b64encsafe(str) {
|
||||
@@ -631,6 +637,7 @@ local current_node = map:get(section)
|
||||
params += opt.query("congestion_control", dom_prefix + "tuic_congestion_control");
|
||||
params += opt.query("udp_relay_mode", dom_prefix + "tuic_udp_relay_mode");
|
||||
params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure");
|
||||
params += opt.query("pcs", dom_prefix + "tls_pinSHA256");
|
||||
|
||||
params += "#" + encodeURI(v_alias.value);
|
||||
if (params[0] == "&") {
|
||||
@@ -661,6 +668,7 @@ local current_node = map:get(section)
|
||||
params += opt.query("alpn", dom_prefix + "alpn");
|
||||
params += opt.query("sni", dom_prefix + "tls_serverName");
|
||||
params += opt.query("insecure", dom_prefix + "tls_allowInsecure");
|
||||
params += opt.query("pcs", dom_prefix + "tls_pinSHA256");
|
||||
}
|
||||
|
||||
params += "#" + encodeURI(v_alias.value);
|
||||
@@ -1001,6 +1009,7 @@ local current_node = map:get(section)
|
||||
opt.set(dom_prefix + 'method', method || "");
|
||||
opt.set(dom_prefix + 'ss_method', method || "");
|
||||
opt.set(dom_prefix + 'tcp_fast_open', queryParam.tfo);
|
||||
|
||||
if (plugin && plugin != "none") {
|
||||
plugin = (plugin === "simple-obfs") ? "obfs-local" : plugin;
|
||||
opt.set(dom_prefix + 'plugin_enabled', true);
|
||||
@@ -1023,9 +1032,29 @@ local current_node = map:get(section)
|
||||
opt.set(dom_prefix + 'tls_allowInsecure', true);
|
||||
}
|
||||
}
|
||||
// Some ShadowTLS subscriptions utilize SIP003.
|
||||
if (plugin === "shadow-tls") {
|
||||
pluginOpts = pluginOpts.replace(/(^|;)password=/, '$1passwd=');
|
||||
pluginOpts = pluginOpts.replace(/(^|;)version=([123])(?=;|$)/, '$1v$2=1');
|
||||
if (dom_prefix === "ssrust_") {
|
||||
opt.set(dom_prefix + 'plugin_opts', pluginOpts || "");
|
||||
} else if (dom_prefix === "singbox_") {
|
||||
const opts = Object.fromEntries(pluginOpts.split(';').map(item => item.split('=', 2)));
|
||||
const host = opts.host;
|
||||
const password = opts.passwd;
|
||||
const versionKey = Object.keys(opts).find(key => /^v[123]$/.test(key));
|
||||
const version = versionKey ? versionKey.slice(1) : "1";
|
||||
opt.set(dom_prefix + 'shadowtls', true);
|
||||
opt.set(dom_prefix + 'shadowtls_version', version);
|
||||
opt.set(dom_prefix + 'shadowtls_password', password || "");
|
||||
opt.set(dom_prefix + 'shadowtls_serverName', host || "");
|
||||
opt.set(dom_prefix + 'plugin_enabled', false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
opt.set(dom_prefix + 'plugin', "none");
|
||||
}
|
||||
|
||||
if (param !== undefined) {
|
||||
opt.set('remarks', decodeURIComponent(param));
|
||||
}
|
||||
@@ -1324,29 +1353,74 @@ local current_node = map:get(section)
|
||||
}
|
||||
}
|
||||
if (link_type === "vmess") {
|
||||
var sstr = b64DecodeUnicode((link_split[1] || "").replace(/#.*/, "").trim());
|
||||
if (vmess_type == "sing-box" && has_singbox) {
|
||||
dom_prefix = "singbox_";
|
||||
opt.set('type', "sing-box");
|
||||
} else {
|
||||
} else if (has_xray) {
|
||||
dom_prefix = "xray_";
|
||||
opt.set('type', "Xray");
|
||||
}
|
||||
opt.set(dom_prefix + 'protocol', "vmess");
|
||||
var sstr = b64DecodeUnicode((link_split[1] || "").replace(/#.*/, "").trim());
|
||||
var ploc = sstr.indexOf("/?");
|
||||
var url0, param = "";
|
||||
if (ploc > 0) {
|
||||
url0 = sstr.substr(0, ploc);
|
||||
param = sstr.substr(ploc + 2);
|
||||
|
||||
let ssm = {};
|
||||
if (is_json(sstr)) {
|
||||
// vmess://base64(json)
|
||||
ssm = JSON.parse(sstr);
|
||||
} else if (sstr.indexOf("?") > 0) {
|
||||
// vmess://base64(auto:uuid@host:port)?tfo=1&remark=xxx&&alterId=0&obfs=websocket&path=%2F&obfsParam=host (obfs ~= ws obfsParam={})
|
||||
sstr = sstr.replace("/?", "?");
|
||||
const ploc = sstr.indexOf("?");
|
||||
let url0 = sstr.substr(0, ploc);
|
||||
let paramStr = sstr.substr(ploc + 2);
|
||||
|
||||
const m = new URL("http://" + b64decsafe(url0));
|
||||
if (m.username !== "") {
|
||||
ssm.security = m.username;
|
||||
ssm.id = m.password || m.username;
|
||||
} else {
|
||||
ssm.security = "auto";
|
||||
ssm.id = m.password || m.username;
|
||||
}
|
||||
ssm.add = unbracketIP(m.hostname);
|
||||
ssm.port = m.port || "443";
|
||||
|
||||
const params = {};
|
||||
const pairs = paramStr.split("&");
|
||||
for (let i = 0; i < pairs.length; i++) {
|
||||
const v = pairs[i];
|
||||
const s = v.indexOf("=");
|
||||
if (s > 0) {
|
||||
params[v.substring(0, s)] = decodeURIComponent(v.substring(s + 1));
|
||||
}
|
||||
}
|
||||
ssm.ps = params.remark || params.remarks;
|
||||
ssm.net = (params.obfs === "websocket") ? "ws" : (params.obfs || "tcp");
|
||||
ssm.path = params.path;
|
||||
ssm.aid = params.alterId || "0";
|
||||
ssm.tls = params.tls;
|
||||
ssm.sni = params.peer;
|
||||
ssm.tfo = params.tfo;
|
||||
if (is_json(params.obfsParam)) {
|
||||
const op_info = JSON.parse(params.obfsParam);
|
||||
if (op_info.header) ssm.type = op_info.header;
|
||||
if (op_info.Host) ssm.host = op_info.Host;
|
||||
} else {
|
||||
ssm.host = params.obfsParam;
|
||||
}
|
||||
ssm.allowinsecure = params.allowInsecure;
|
||||
} else {
|
||||
s.innerHTML = "<font color='red'><%:Invalid Share URL Format%></font>";
|
||||
return false;
|
||||
}
|
||||
var ssm = JSON.parse(sstr);
|
||||
|
||||
opt.set('remarks', ssm.ps);
|
||||
opt.set(dom_prefix + 'address', unbracketIP(ssm.add));
|
||||
opt.set(dom_prefix + 'port', ssm.port);
|
||||
opt.set(dom_prefix + 'uuid', ssm.id);
|
||||
opt.set(dom_prefix + 'security', ssm.security || ssm.scy || "auto");
|
||||
opt.set(dom_prefix + 'tls', ssm.tls === "tls");
|
||||
if (ssm.tls === "tls") {
|
||||
opt.set(dom_prefix + 'tls', ssm.tls === "tls" || ssm.tls === "1");
|
||||
if (ssm.tls === "tls" || ssm.tls === "1") {
|
||||
opt.set(dom_prefix + 'tls_serverName', ssm.sni || ssm.host);
|
||||
opt.set(dom_prefix + 'alpn', ssm.alpn || "default");
|
||||
if (ssm.fp && ssm.fp !== "") {
|
||||
@@ -1679,6 +1753,7 @@ local current_node = map:get(section)
|
||||
dom_prefix + 'tls_allowInsecure',
|
||||
!((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0' && (queryParam.allow_insecure ?? '0') === '0')
|
||||
);
|
||||
opt.set(dom_prefix + 'tls_pinSHA256', queryParam.pcs || queryParam.pinSHA256 || '');
|
||||
if (hash) {
|
||||
opt.set('remarks', decodeURIComponent(hash.substr(1)));
|
||||
}
|
||||
@@ -1711,29 +1786,23 @@ local current_node = map:get(section)
|
||||
}
|
||||
queryParam.security = queryParam.security || "tls";
|
||||
if (queryParam.security) {
|
||||
opt.set(dom_prefix + 'tls', true);
|
||||
if (queryParam.security == "tls") {
|
||||
opt.set(dom_prefix + 'tls', true);
|
||||
opt.set(dom_prefix + 'reality', false);
|
||||
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
|
||||
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || queryParam.peer || '');
|
||||
opt.set(dom_prefix + 'tls_allowInsecure', !((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0'));
|
||||
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 + 'alpn', queryParam.alpn || 'default');
|
||||
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || queryParam.peer || '');
|
||||
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 || '');
|
||||
}
|
||||
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
|
||||
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || queryParam.peer || '');
|
||||
if (queryParam.fp && queryParam.fp.trim() != "") {
|
||||
opt.set(dom_prefix + 'utls', true);
|
||||
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
|
||||
}
|
||||
opt.set(dom_prefix + 'tls_allowInsecure', !((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0'));
|
||||
opt.set(dom_prefix + 'tls_pinSHA256', queryParam.pcs || queryParam.pinSHA256 || '');
|
||||
}
|
||||
if (m.hash) {
|
||||
opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
|
||||
|
||||
@@ -2345,6 +2345,9 @@ msgstr "صرفنظر از گره %s، زیرا گرههای نوع %s به
|
||||
msgid "%s type node subscriptions are not currently supported, skip this node."
|
||||
msgstr "اشتراکهای گره نوع %s در حال حاضر پشتیبانی نمیشوند، صرفنظر از این گره."
|
||||
|
||||
msgid "Skipping %s node. This node URI format cannot be parsed."
|
||||
msgstr "از گره %s صرفنظر میشود. فرمت URI این گره قابل تجزیه نیست."
|
||||
|
||||
msgid "Update [%s]"
|
||||
msgstr "بهروزرسانی [%s]"
|
||||
|
||||
|
||||
@@ -2346,6 +2346,9 @@ msgstr "Пропуск сервера %s: серверы типа %s требу
|
||||
msgid "%s type node subscriptions are not currently supported, skip this node."
|
||||
msgstr "Подписки на серверы типа %s пока не поддерживаются, этот сервер пропускается."
|
||||
|
||||
msgid "Skipping %s node. This node URI format cannot be parsed."
|
||||
msgstr "Пропуск узла %s. Формат URI этого узла не поддается разбору."
|
||||
|
||||
msgid "Update [%s]"
|
||||
msgstr "Обновление [%s]"
|
||||
|
||||
|
||||
@@ -2331,6 +2331,9 @@ msgstr "跳过 %s 节点,因 %s 类型的节点需要 Sing-Box 1.12 以上版
|
||||
msgid "%s type node subscriptions are not currently supported, skip this node."
|
||||
msgstr "暂时不支持 %s 类型的节点订阅,跳过此节点。"
|
||||
|
||||
msgid "Skipping %s node. This node URI format cannot be parsed."
|
||||
msgstr "跳过 %s 节点,该节点 URI 格式无法解析。"
|
||||
|
||||
msgid "Update [%s]"
|
||||
msgstr "更新【%s】"
|
||||
|
||||
|
||||
@@ -2337,6 +2337,9 @@ msgstr "跳過 %s 節點,因 %s 類型的節點需要 Sing-Box 1.12 以上版
|
||||
msgid "%s type node subscriptions are not currently supported, skip this node."
|
||||
msgstr "暫時不支持 %s 類型的節點訂閱,跳過此節點。"
|
||||
|
||||
msgid "Skipping %s node. This node URI format cannot be parsed."
|
||||
msgstr "跳過 %s 節點,該節點 URI 格式無法解析。"
|
||||
|
||||
msgid "Update [%s]"
|
||||
msgstr "更新【%s】"
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ ip6t_m="$ip6t -t mangle -w"
|
||||
[ -z "$ip6t" -o -z "$(lsmod | grep 'ip6table_mangle')" ] && ip6t_m="eval #$ip6t_m"
|
||||
FWI=$(uci -q get firewall.passwall2.path 2>/dev/null)
|
||||
FAKE_IP="198.18.0.0/16"
|
||||
FAKE_IP_6="fc00::/18"
|
||||
FAKE_IP_6="2001:2::/48"
|
||||
|
||||
factor() {
|
||||
if [ -z "$1" ] || [ -z "$2" ]; then
|
||||
@@ -627,21 +627,25 @@ filter_direct_node_list() {
|
||||
update_wan_sets() {
|
||||
[ -z "$(command -v get_wan_ips)" ] && . "$UTILS_PATH"
|
||||
|
||||
local WAN_IP=$(get_wan_ips ip4)
|
||||
[ -n "$WAN_IP" ] && {
|
||||
ipset -F "$IPSET_WAN"
|
||||
for wan_ip in $WAN_IP; do
|
||||
ipset -! add "$IPSET_WAN" "$wan_ip"
|
||||
done
|
||||
}
|
||||
(
|
||||
flock -x 9 || exit 1
|
||||
|
||||
local WAN6_IP=$(get_wan_ips ip6)
|
||||
[ -n "$WAN6_IP" ] && {
|
||||
ipset -F "$IPSET_WAN6"
|
||||
for wan6_ip in $WAN6_IP; do
|
||||
ipset -! add "$IPSET_WAN6" "$wan6_ip"
|
||||
done
|
||||
}
|
||||
local WAN_IP=$(get_wan_ips ip4)
|
||||
[ -n "$WAN_IP" ] && {
|
||||
# ipset -F "$IPSET_WAN"
|
||||
for wan_ip in $WAN_IP; do
|
||||
ipset -! add "$IPSET_WAN" "$wan_ip"
|
||||
done
|
||||
}
|
||||
|
||||
local WAN6_IP=$(get_wan_ips ip6)
|
||||
[ -n "$WAN6_IP" ] && {
|
||||
# ipset -F "$IPSET_WAN6"
|
||||
for wan6_ip in $WAN6_IP; do
|
||||
ipset -! add "$IPSET_WAN6" "$wan6_ip"
|
||||
done
|
||||
}
|
||||
) 9>"${LOCK_PATH}/${CONFIG}_update_wan_sets.lock"
|
||||
}
|
||||
|
||||
add_firewall_rule() {
|
||||
|
||||
@@ -18,7 +18,7 @@ FWMARK="0x50535732"
|
||||
|
||||
FWI=$(uci -q get firewall.passwall2.path 2>/dev/null)
|
||||
FAKE_IP="198.18.0.0/16"
|
||||
FAKE_IP_6="fc00::/18"
|
||||
FAKE_IP_6="2001:2::/48"
|
||||
|
||||
factor() {
|
||||
local ports="$1"
|
||||
@@ -686,17 +686,21 @@ mwan3_start() {
|
||||
update_wan_sets() {
|
||||
[ -z "$(command -v get_wan_ips)" ] && . "$UTILS_PATH"
|
||||
|
||||
local WAN_IP=$(get_wan_ips ip4)
|
||||
[ -n "$WAN_IP" ] && {
|
||||
nft flush set $NFTABLE_NAME $NFTSET_WAN
|
||||
echo "$WAN_IP" | insert_nftset $NFTSET_WAN "-1"
|
||||
}
|
||||
(
|
||||
flock -x 9 || exit 1
|
||||
|
||||
local WAN6_IP=$(get_wan_ips ip6)
|
||||
[ -n "${WAN6_IP}" ] && {
|
||||
nft flush set $NFTABLE_NAME $NFTSET_WAN6
|
||||
echo "$WAN6_IP" | insert_nftset $NFTSET_WAN6 "-1"
|
||||
}
|
||||
local WAN_IP=$(get_wan_ips ip4)
|
||||
[ -n "$WAN_IP" ] && {
|
||||
# nft flush set $NFTABLE_NAME $NFTSET_WAN
|
||||
echo "$WAN_IP" | insert_nftset $NFTSET_WAN
|
||||
}
|
||||
|
||||
local WAN6_IP=$(get_wan_ips ip6)
|
||||
[ -n "${WAN6_IP}" ] && {
|
||||
# nft flush set $NFTABLE_NAME $NFTSET_WAN6
|
||||
echo "$WAN6_IP" | insert_nftset $NFTSET_WAN6
|
||||
}
|
||||
) 9>"${LOCK_PATH}/${CONFIG}_update_wan_sets.lock"
|
||||
}
|
||||
|
||||
add_firewall_rule() {
|
||||
|
||||
@@ -900,7 +900,6 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
-- if ssr_group then result.ssr_group = ssr_group end
|
||||
result.remarks = base64Decode(params.remarks)
|
||||
elseif szType == 'vmess' then
|
||||
local info = jsonParse(content)
|
||||
if sub_vmess_type == "sing-box" and has_singbox then
|
||||
result.type = 'sing-box'
|
||||
elseif sub_vmess_type == "xray" and has_xray then
|
||||
@@ -909,6 +908,58 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
log(2, i18n.translatef("Skipping the %s node is due to incompatibility with the %s core program or incorrect node usage type settings.", "VMess", "VMess"))
|
||||
return nil
|
||||
end
|
||||
-- vmess://base64(json)
|
||||
local info = jsonParse(content)
|
||||
if not info then
|
||||
-- vmess://base64(auto:uuid@host:port)?tfo=1&remark=xxx&&alterId=0&obfs=websocket&path=%2F&obfsParam=host (obfs ~= ws obfsParam={})
|
||||
if content:find("?", 1, true) then
|
||||
info = {}
|
||||
local Info = split(content:gsub("/%?", "?"), "%?")
|
||||
local sp = split(base64Decode(Info[1]), "@")
|
||||
local id_info = split(sp[1], ":")
|
||||
info.security = (#id_info > 1 and id_info[1] ~= "") and id_info[1] or "auto"
|
||||
info.id = id_info[#id_info]
|
||||
|
||||
local addr, port = sp[2], "443"
|
||||
if api.is_ipv6addrport(addr) then
|
||||
local a, p = addr:match("^%[(.+)%]:(%d+)$")
|
||||
if a then addr, port = a, p end
|
||||
addr = api.get_ipv6_only(addr)
|
||||
else
|
||||
local host_port = split(addr, ":")
|
||||
addr = host_port[1]
|
||||
if #host_port > 1 then port = host_port[#host_port] end
|
||||
end
|
||||
info.add, info.port = addr, port
|
||||
|
||||
local params = {}
|
||||
for _, v in pairs(split(Info[2], '&')) do
|
||||
local s = v:find("=", 1, true)
|
||||
if s and s > 1 then
|
||||
params[v:sub(1, s - 1)] = UrlDecode(v:sub(s + 1))
|
||||
end
|
||||
end
|
||||
info.ps = params.remark or params.remarks
|
||||
info.net = (params.obfs == "websocket") and "ws" or (params.obfs or "tcp")
|
||||
info.path = params.path
|
||||
info.aid = params.alterId or "0"
|
||||
info.tls = params.tls
|
||||
info.sni = params.peer
|
||||
info.tfo = params.tfo
|
||||
local op_info = jsonParse(params.obfsParam)
|
||||
if op_info then
|
||||
if op_info.header then info.type = op_info.header end
|
||||
if op_info.Host then info.host = op_info.Host end
|
||||
else
|
||||
info.host = params.obfsParam
|
||||
end
|
||||
info.allowinsecure = params.allowInsecure
|
||||
else
|
||||
log(2, i18n.translatef("Skipping %s node. This node URI format cannot be parsed."))
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
result.address = info.add
|
||||
result.port = info.port
|
||||
result.protocol = 'vmess'
|
||||
@@ -1068,6 +1119,11 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
if idx_pn then
|
||||
result.plugin = plugin_info:sub(1, idx_pn - 1)
|
||||
result.plugin_opts = plugin_info:sub(idx_pn + 1, #plugin_info)
|
||||
-- Some ShadowTLS subscriptions utilize SIP003.
|
||||
result.plugin_opts = result.plugin_opts:gsub("^password=", "passwd=")
|
||||
result.plugin_opts = result.plugin_opts:gsub(";password=", ";passwd=")
|
||||
result.plugin_opts = result.plugin_opts:gsub("^version=([123])", "v%1=1")
|
||||
result.plugin_opts = result.plugin_opts:gsub(";version=([123])", ";v%1=1")
|
||||
else
|
||||
result.plugin = plugin_info
|
||||
end
|
||||
@@ -1174,10 +1230,22 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
result.plugin_opts = nil
|
||||
end
|
||||
elseif result.type == 'sing-box' then
|
||||
if result.plugin ~= "obfs-local" and result.plugin ~= "v2ray-plugin" then
|
||||
if result.plugin ~= "obfs-local" and result.plugin ~= "v2ray-plugin" and result.plugin ~= "shadow-tls" then
|
||||
result.error_msg = i18n.translatef("%s unsupport SS %s plugin.", "Sing-Box", result.plugin)
|
||||
else
|
||||
result.plugin_enabled = "1"
|
||||
-- Some ShadowTLS subscriptions utilize SIP003.
|
||||
if result.plugin == "shadow-tls" then
|
||||
for item in result.plugin_opts:gmatch("[^;]+") do
|
||||
local key, value = item:match("^([^=]+)=(.*)$")
|
||||
if key == "host" then result.shadowtls_serverName = value end
|
||||
if key == "passwd" then result.shadowtls_password = value end
|
||||
if key:match("^v[123]$") then result.shadowtls_version = key:sub(2) end
|
||||
end
|
||||
result.shadowtls = "1"
|
||||
result.plugin_opts = nil
|
||||
result.plugin_enabled = nil
|
||||
end
|
||||
end
|
||||
else
|
||||
result.plugin_enabled = "1"
|
||||
@@ -1722,6 +1790,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
result.hysteria_auth_type = "string"
|
||||
result.hysteria_auth_password = params.auth
|
||||
result.tls_serverName = params.peer or params.sni or ""
|
||||
result.tls_pinSHA256 = params.pcs or params.pinSHA256
|
||||
local insecure = params.allowinsecure or params.allowInsecure or params.insecure
|
||||
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0")
|
||||
result.alpn = params.alpn
|
||||
@@ -1845,6 +1914,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
end
|
||||
result.tls_serverName = params.sni
|
||||
result.tls_disable_sni = params.disable_sni
|
||||
result.tls_pinSHA256 = params.pcs or params.pinsha256
|
||||
result.tuic_alpn = params.alpn or "h3"
|
||||
result.tuic_congestion_control = params.congestion_control or "cubic"
|
||||
result.tuic_udp_relay_mode = params.udp_relay_mode or "native"
|
||||
@@ -1900,6 +1970,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
if params.security == "tls" or params.security == "reality" then
|
||||
result.tls = "1"
|
||||
result.tls_serverName = params.sni or params.peer
|
||||
result.tls_pinSHA256 = params.pcs or params.pinsha256
|
||||
result.alpn = params.alpn
|
||||
if params.fp and params.fp ~= "" then
|
||||
result.utls = "1"
|
||||
@@ -2063,6 +2134,9 @@ local function curl(url, file, ua, mode, hwid)
|
||||
if hwid == "1" then
|
||||
curl_args[#curl_args + 1] = get_headers()
|
||||
end
|
||||
local cookie_file = "/tmp/cookie_" .. api.gen_random_char(5)
|
||||
curl_args[#curl_args + 1] = '-c "' .. cookie_file .. '" -b "' .. cookie_file .. '"'
|
||||
|
||||
local return_code, result
|
||||
if mode == "direct" then
|
||||
return_code, result = api.curl_direct(url, file, curl_args)
|
||||
@@ -2071,6 +2145,8 @@ local function curl(url, file, ua, mode, hwid)
|
||||
else
|
||||
return_code, result = api.curl_auto(url, file, curl_args)
|
||||
end
|
||||
luci.sys.call('rm -f "%s"' % cookie_file)
|
||||
|
||||
return return_code, tonumber(result)
|
||||
end
|
||||
|
||||
@@ -2599,7 +2675,7 @@ local execute = function()
|
||||
f:close()
|
||||
local raw_data = api.trim(stdout)
|
||||
local old_md5 = value.md5 or ""
|
||||
local new_md5 = luci.sys.exec("md5sum " .. tmp_file .. " 2>/dev/null | awk '{print $1}'"):gsub("\n", "")
|
||||
local new_md5 = luci.sys.exec("md5sum " .. tmp_file .. " 2>/dev/null | awk '{printf \"%s\", $1}'")
|
||||
if not manual_sub and old_md5 == new_md5 then
|
||||
log(1, i18n.translatef("Subscription: [%s] No changes, no update required.", remark))
|
||||
else
|
||||
|
||||
Reference in new issue
Block a user