Update On Sat Nov 1 19:37:49 CET 2025

This commit is contained in:
github-action[bot]
2025-11-01 19:37:50 +01:00
parent 4d8ef8721d
commit 451ea7a595
155 changed files with 7139 additions and 4094 deletions

View File

@@ -5,8 +5,9 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2
PKG_VERSION:=25.9.24
PKG_VERSION:=25.11.2
PKG_RELEASE:=1
PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \

View File

@@ -219,7 +219,7 @@ local TCP_REDIR_PORTS = m:get("@global_forwarding[0]", "tcp_redir_ports")
o = s:option(Value, "tcp_redir_ports", translate("TCP Redir Ports"))
o:value("", translate("Use global config") .. "(" .. TCP_REDIR_PORTS .. ")")
o:value("1:65535", translate("All"))
o:value("22,25,53,143,465,587,853,993,995,80,443", translate("Common Use"))
o:value("22,25,53,80,143,443,465,587,853,873,993,995,5222,8080,8443,9418", translate("Common Use"))
o:value("80,443", "80,443")
o.validate = port_validate
o:depends({ _hide_node_option = "1", ['!reverse'] = true })

View File

@@ -176,20 +176,21 @@ o.cfgvalue = function(t, n)
type = type .. " " .. protocol
end
local address = m:get(n, "address") or ""
local port = m:get(n, "port") or m:get(n, "hysteria_hop") or m:get(n, "hysteria2_hop") or ""
local port = m:get(n, "port") or ""
local port_s = (port ~= "") and port or m:get(n, "hysteria_hop") or m:get(n, "hysteria2_hop") or ""
str = str .. translate(type) .. "" .. remarks
if address ~= "" and port ~= "" then
port = port:gsub(":", "-")
if address ~= "" and port_s ~= "" then
port_s = port_s:gsub(":", "-")
if show_node_info == "1" then
if datatypes.ip6addr(address) then
str = str .. string.format("[%s]:%s", address, port)
str = str .. string.format("[%s]:%s", address, port_s)
else
str = str .. string.format("%s:%s", address, port)
str = str .. string.format("%s:%s", address, port_s)
end
end
str = str .. string.format("<input type='hidden' id='cbid.%s.%s.address' value='%s'/>", appname, n, address)
str = str .. string.format("<input type='hidden' id='cbid.%s.%s.port' value='%s'/>", appname, n, port)
end
str = str .. string.format("<input type='hidden' id='cbid.%s.%s.address' value='%s'/>", appname, n, address)
str = str .. string.format("<input type='hidden' id='cbid.%s.%s.port' value='%s'/>", appname, n, port)
return str
end

View File

@@ -83,9 +83,9 @@ o.validate = port_validate
---- TCP Redir Ports
o = s:option(Value, "tcp_redir_ports", translate("TCP Redir Ports"))
o.default = "22,25,53,143,465,587,853,993,995,80,443"
o.default = "22,25,53,80,143,443,465,587,853,873,993,995,5222,8080,8443,9418"
o:value("1:65535", translate("All"))
o:value("22,25,53,143,465,587,853,993,995,80,443", translate("Common Use"))
o:value("22,25,53,80,143,443,465,587,853,873,993,995,5222,8080,8443,9418", translate("Common Use"))
o:value("80,443", translate("Only Web"))
o.validate = port_validate

View File

@@ -3,9 +3,29 @@ local appname = api.appname
local datatypes = api.datatypes
m = Map(appname, "Sing-Box/Xray " .. translate("Shunt Rule"))
m.redirect = api.url()
m.redirect = api.url("rule")
api.set_apply_on_parse(m)
if not arg[1] or not m:get(arg[1]) then
luci.http.redirect(m.redirect)
end
-- Add inline CSS to map description
m.description = (m.description or "") .. [[
<style>
/* Scope to passwall2 CBI fields so it won't leak elsewhere */
div[id^="cbid.passwall2."] .cbi-value-field {
display: flex;
flex-wrap: wrap;
gap: 1em;
}
div[id^="cbid.passwall2."] .cbi-checkbox {
display: inline-flex;
align-items: center;
}
</style>
]]
function clean_text(text)
local nbsp = string.char(0xC2, 0xA0) -- 不间断空格U+00A0
local fullwidth_space = string.char(0xE3, 0x80, 0x80) -- 全角空格U+3000
@@ -31,10 +51,16 @@ protocol = s:option(MultiValue, "protocol", translate("Protocol"))
protocol:value("http")
protocol:value("tls")
protocol:value("bittorrent")
protocol.widget = "checkbox"
protocol.default = nil
protocol.optional = false
o = s:option(MultiValue, "inbound", translate("Inbound Tag"))
o:value("tproxy", translate("Transparent proxy"))
o:value("socks", "Socks")
o.widget = "checkbox"
o.default = nil
o.optional = false
network = s:option(ListValue, "network", translate("Network"))
network:value("tcp,udp", "TCP UDP")

View File

@@ -321,6 +321,10 @@ o = s:option(Value, _n("encryption"), translate("Encrypt Method") .. " (encrypti
o.default = "none"
o.placeholder = "none"
o:depends({ [_n("protocol")] = "vless" })
o.validate = function(self, value)
value = api.trim(value)
return (value == "" and "none" or value)
end
o = s:option(ListValue, _n("ss_method"), translate("Encrypt Method"))
o.rewrite_option = "method"
@@ -345,8 +349,8 @@ o = s:option(ListValue, _n("flow"), translate("flow"))
o.default = ""
o:value("", translate("Disable"))
o:value("xtls-rprx-vision")
o:depends({ [_n("protocol")] = "vless", [_n("tls")] = true, [_n("transport")] = "raw" })
o:depends({ [_n("protocol")] = "vless", [_n("tls")] = true, [_n("transport")] = "xhttp" })
o:depends({ [_n("protocol")] = "vless", [_n("transport")] = "raw" })
o:depends({ [_n("protocol")] = "vless", [_n("transport")] = "xhttp" })
o = s:option(Flag, _n("tls"), translate("TLS"))
o.default = 0

View File

@@ -84,6 +84,10 @@ o = s:option(Value, _n("decryption"), translate("Encrypt Method") .. " (decrypti
o.default = "none"
o.placeholder = "none"
o:depends({ [_n("protocol")] = "vless" })
o.validate = function(self, value)
value = api.trim(value)
return (value == "" and "none" or value)
end
o = s:option(ListValue, _n("x_ss_method"), translate("Encrypt Method"))
o.rewrite_option = "method"

View File

@@ -337,41 +337,28 @@ function is_special_node(e)
end
function is_ip(val)
if is_ipv6(val) then
val = get_ipv6_only(val)
end
return datatypes.ipaddr(val)
local str = val:match("%[(.-)%]") or val
return datatypes.ipaddr(str) or false
end
function is_ipv6(val)
local str = val
local address = val:match('%[(.*)%]')
if address then
str = address
end
if datatypes.ip6addr(str) then
return true
end
return false
local str = val:match("%[(.-)%]") or val
return datatypes.ip6addr(str) or false
end
function is_ipv6addrport(val)
if is_ipv6(val) then
local address, port = val:match('%[(.*)%]:([^:]+)$')
if port then
return datatypes.port(port)
end
local address, port = val:match("%[(.-)%]:([0-9]+)$")
if address and datatypes.ip6addr(address) and datatypes.port(port) then
return true
end
return false
end
function get_ipv6_only(val)
local result = ""
if is_ipv6(val) then
result = val
if val:match('%[(.*)%]') then
result = val:match('%[(.*)%]')
end
local inner = val:match("%[(.-)%]") or val
if datatypes.ip6addr(inner) then
result = inner
end
return result
end
@@ -380,7 +367,7 @@ function get_ipv6_full(val)
local result = ""
if is_ipv6(val) then
result = val
if not val:match('%[(.*)%]') then
if not val:match("%[.-%]") then
result = "[" .. result .. "]"
end
end

View File

@@ -146,7 +146,10 @@ function gen_outbound(flag, node, tag, proxy_table)
v2ray_transport = {
type = "http",
host = node.tcp_guise_http_host,
path = (node.tcp_guise_http_path and node.tcp_guise_http_path[1]) or "/",
path = node.tcp_guise_http_path and (function()
local first = node.tcp_guise_http_path[1]
return (first == "" or not first) and "/" or first
end)() or "/",
idle_timeout = (node.http_h2_health_check == "1") and node.http_h2_read_idle_timeout or nil,
ping_timeout = (node.http_h2_health_check == "1") and node.http_h2_health_check_timeout or nil,
}

View File

@@ -167,7 +167,13 @@ function gen_outbound(flag, node, tag, proxy_table)
header = {
type = node.tcp_guise,
request = (node.tcp_guise == "http") and {
path = node.tcp_guise_http_path or {"/"},
path = node.tcp_guise_http_path and (function()
local t, r = node.tcp_guise_http_path, {}
for _, v in ipairs(t) do
r[#r + 1] = (v == "" and "/" or v)
end
return r
end)() or {"/"},
headers = {
Host = node.tcp_guise_http_host or {}
}
@@ -213,7 +219,7 @@ function gen_outbound(flag, node, tag, proxy_table)
host = node.xhttp_host,
-- 如果包含 "extra" 节,取 "extra" 内的内容,否则直接赋值给 extra
extra = node.xhttp_extra and (function()
local success, parsed = pcall(jsonc.parse, node.xhttp_extra)
local success, parsed = pcall(jsonc.parse, node.xhttp_extra)
if success then
return parsed.extra or parsed
else
@@ -232,9 +238,12 @@ function gen_outbound(flag, node, tag, proxy_table)
id = node.uuid,
level = 0,
security = (node.protocol == "vmess") and node.security or nil,
encryption = node.encryption or "none",
flow = (node.protocol == "vless" and node.tls == "1" and (node.transport == "raw" or node.transport == "tcp" or node.transport == "xhttp") and node.flow and node.flow ~= "") and node.flow or nil
encryption = (node.protocol == "vless") and ((node.encryption and node.encryption ~= "") and node.encryption or "none") or nil,
flow = (node.protocol == "vless"
and (node.tls == "1" or (node.encryption and node.encryption ~= "" and node.encryption ~= "none"))
and (node.transport == "raw" or node.transport == "tcp" or node.transport == "xhttp")
and node.flow and node.flow ~= ""
) and node.flow or nil
}
}
}
@@ -310,7 +319,7 @@ function gen_config_server(node)
end
settings = {
clients = clients,
decryption = node.decryption or "none"
decryption = (node.protocol == "vless") and ((node.decryption and node.decryption ~= "") and node.decryption or "none") or nil
}
end
elseif node.protocol == "socks" then
@@ -460,7 +469,13 @@ function gen_config_server(node)
header = {
type = node.tcp_guise,
request = (node.tcp_guise == "http") and {
path = node.tcp_guise_http_path or {"/"},
path = node.tcp_guise_http_path and (function()
local t, r = node.tcp_guise_http_path, {}
for _, v in ipairs(t) do
r[#r + 1] = (v == "" and "/" or v)
end
return r
end)() or {"/"},
headers = {
Host = node.tcp_guise_http_host or {}
}

View File

@@ -959,6 +959,7 @@ local hysteria2_type = get_core("hysteria2_type", {{has_hysteria2,"hysteria2"},{
opt.set(dom_prefix + 'transport', "raw");
opt.set(dom_prefix + 'tcp_guise', "http");
opt.set(dom_prefix + 'tcp_guise_http_host', obfs_host || '');
opt.set(dom_prefix + 'tcp_guise_http_path', '/');
} else if (obfs === "tls") {
opt.set(dom_prefix + 'tls', true);
opt.set(dom_prefix + 'tls_serverName', obfs_host || '');
@@ -1361,11 +1362,11 @@ local hysteria2_type = get_core("hysteria2_type", {{has_hysteria2,"hysteria2"},{
opt.set(dom_prefix + 'port', m.port || "443");
opt.set(dom_prefix + 'encryption', queryParam.encryption || "none");
opt.set(dom_prefix + 'flow', (queryParam.flow || '').replace('-udp443', ''));
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 || '').replace('-udp443', ''));
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
opt.set(dom_prefix + 'tls_allowInsecure', true);
@@ -1383,7 +1384,6 @@ local hysteria2_type = get_core("hysteria2_type", {{has_hysteria2,"hysteria2"},{
if (queryParam.security == "reality") {
opt.set(dom_prefix + 'tls', true);
opt.set(dom_prefix + 'reality', true);
opt.set(dom_prefix + 'flow', (queryParam.flow || '').replace('-udp443', ''));
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
if (queryParam.fp && queryParam.fp.trim() != "") {

View File

@@ -215,18 +215,12 @@ table td, .table .td {
}
function get_address_full(id) {
try {
var address = document.getElementById("cbid.passwall2." + id + ".address").value;
var port = document.getElementById("cbid.passwall2." + id + ".port").value;
}
catch(err){}
var address = (document.getElementById("cbid.passwall2." + id + ".address") || {}).value || "";
var port = (document.getElementById("cbid.passwall2." + id + ".port") || {}).value || "";
//判断是否含有汉字
var reg = new RegExp("[\\u4E00-\\u9FFF]+","g");
if ((address != null && address != "") && (port != null && port != "") && reg.test(address) == false) {
return { address: address, port: port };
} else {
return null;
}
var reg = /[\u4E00-\u9FFF]+/;
address = !reg.test(address) ? address : "";
return { address: address, port: port };
}
//获取当前使用的节点
@@ -285,7 +279,7 @@ table td, .table .td {
function ping_node(cbi_id, dom, type) {
var full = get_address_full(cbi_id);
if (full != null) {
if ((type == "icmp" && full.address != "" ) || (type == "tcping" && full.address != "" && full.port != "")) {
dom.onclick = null
dom.innerText = "<%:Check...%>";
XHR.get('<%=api.url("ping_node")%>', {
@@ -320,7 +314,7 @@ table td, .table .td {
for (var i = 0; i < ping_value.length; i++) {
var cbi_id = ping_value[i].getAttribute("cbiid");
var full = get_address_full(cbi_id);
if (full != null) {
if ((auto_detection_time == "icmp" && full.address != "" ) || (auto_detection_time == "tcping" && full.address != "" && full.port != "")) {
var flag = false;
//当有多个相同地址和端口时合在一起
for (var j = 0; j < nodes.length; j++) {

View File

@@ -27,7 +27,7 @@ config global_delay
config global_forwarding
option tcp_no_redir_ports 'disable'
option udp_no_redir_ports 'disable'
option tcp_redir_ports '22,25,53,143,465,587,853,993,995,80,443'
option tcp_redir_ports '22,25,53,80,143,443,465,587,853,873,993,995,5222,8080,8443,9418'
option udp_redir_ports '1:65535'
option accept_icmp '0'
option use_nft '0'

View File

@@ -740,6 +740,7 @@ local function processData(szType, content, add_mode, add_from)
result.transport = "raw"
result.tcp_guise = "http"
result.tcp_guise_http_host = (obfs_host and obfs_host ~= "") and { obfs_host } or nil
result.tcp_guise_http_path = { "/" }
elseif obfs == "tls" then
result.tls = "1"
result.tls_serverName = obfs_host