Skip to content

Commit 39fbc5e

Browse files
SakuraFallingMad1715173329
authored andcommitted
luci-app-passwall: bump to 26.4.6
1 parent 084ffc9 commit 39fbc5e

19 files changed

Lines changed: 500 additions & 236 deletions

File tree

applications/luci-app-passwall/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
include $(TOPDIR)/rules.mk
88

99
PKG_NAME:=luci-app-passwall
10-
PKG_VERSION:=26.4.1
10+
PKG_VERSION:=26.4.6
1111
PKG_RELEASE:=1
1212

1313
PKG_CONFIG_DEPENDS:= \

applications/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,111 @@ o = s:option(Value, "remarks", translate("Remarks"))
8181
o.default = arg[1]
8282
o.rmempty = false
8383

84-
o = s:option(ListValue, "interface", translate("Source Interface"))
84+
o = s:option(Value, "interface", translate("Source Interface"))
8585
o:value("", translate("All"))
86-
local wa = require "luci.tools.webadmin"
87-
wa.cbi_add_networks(o)
86+
-- Populate with actual kernel network devices instead of UCI interface names,
87+
-- because the backend (nftables iifname / iptables -i) matches kernel device names.
88+
do
89+
local nfs = require "nixio.fs"
90+
local _cursor = require("luci.model.uci").cursor()
91+
local _sysnet = "/sys/class/net/"
92+
93+
-- Map UCI interface names to their device names and vice versa
94+
local _iface_to_dev = {}
95+
local _dev_to_ifaces = {}
96+
local _iface_proto = {}
97+
_cursor:foreach("network", "interface", function(sec)
98+
local name = sec[".name"]
99+
if name ~= "loopback" then
100+
_iface_proto[name] = sec.proto
101+
if sec.device then
102+
_iface_to_dev[name] = sec.device
103+
_dev_to_ifaces[sec.device] = _dev_to_ifaces[sec.device] or {}
104+
table.insert(_dev_to_ifaces[sec.device], name)
105+
end
106+
end
107+
end)
108+
109+
-- Classify device type using sysfs attributes
110+
local function classify_sysfs(dev)
111+
if nfs.stat(_sysnet .. dev .. "/bridge", "type") == "dir" then
112+
return translate("Bridge")
113+
elseif nfs.stat(_sysnet .. dev .. "/wireless", "type") == "dir" then
114+
return translate("Wireless Adapter")
115+
elseif dev:match("^tun") or dev:match("^tap") or dev:match("^wg") or dev:match("^ppp") then
116+
return translate("Tunnel Interface")
117+
else
118+
return translate("Ethernet Adapter")
119+
end
120+
end
121+
122+
-- Classify offline UCI interfaces by config hints
123+
local function classify_uci(dev_name, proto)
124+
if dev_name and dev_name:match("^br%-") then
125+
return translate("Bridge")
126+
elseif proto == "wireguard" or proto == "pppoe" or proto == "pptp" or proto == "l2tp" then
127+
return translate("Tunnel Interface")
128+
else
129+
return translate("Interface")
130+
end
131+
end
132+
133+
local _seen = {}
134+
local _devices = {}
135+
136+
-- Active kernel devices from /sys/class/net/.
137+
-- Skip bridge member ports (/master) and DSA master devices (/dsa) because
138+
-- nftables iifname matches the parent bridge for routed traffic, not
139+
-- individual member ports. Also skip internal virtual devices.
140+
local _iter = nfs.dir(_sysnet)
141+
if _iter then
142+
for dev in _iter do
143+
if dev ~= "lo"
144+
and not dev:match("^veth")
145+
and not dev:match("^ifb")
146+
and not dev:match("^gre")
147+
and not dev:match("^sit")
148+
and not dev:match("^ip6tnl")
149+
and not dev:match("^erspan")
150+
and not nfs.stat(_sysnet .. dev .. "/master", "type")
151+
and not nfs.stat(_sysnet .. dev .. "/dsa", "type")
152+
then
153+
local dtype = classify_sysfs(dev)
154+
local label = dtype .. ': "' .. dev .. '"'
155+
if _dev_to_ifaces[dev] then
156+
label = label .. " (" .. table.concat(_dev_to_ifaces[dev], ", ") .. ")"
157+
end
158+
_devices[#_devices + 1] = { name = dev, label = label, sort = dtype .. ":" .. dev }
159+
_seen[dev] = true
160+
end
161+
end
162+
end
163+
164+
-- UCI interfaces whose device does not currently exist (down tunnels, VPNs, etc.).
165+
-- Stored by UCI name since the kernel device is not available yet.
166+
-- Dedup by device: if two interfaces share a device, only one is shown.
167+
for iface, dev in pairs(_iface_to_dev) do
168+
if not _seen[dev] then
169+
local dtype = classify_uci(dev, _iface_proto[iface])
170+
local label = dtype .. ': "' .. iface .. '"'
171+
-- Sort offline entries after active devices
172+
_devices[#_devices + 1] = { name = iface, label = label, sort = "zzz:" .. iface }
173+
_seen[dev] = true
174+
end
175+
end
176+
177+
table.sort(_devices, function(a, b) return a.sort < b.sort end)
178+
for _, d in ipairs(_devices) do
179+
o:value(d.name, d.label)
180+
end
181+
end
182+
183+
o.validate = function(self, value, section)
184+
if value == "" or value:match("^[a-zA-Z0-9][a-zA-Z0-9%.%_%-]*$") then
185+
return value
186+
end
187+
return nil, translate("Invalid interface name")
188+
end
88189

89190
local mac_t = {}
90191
sys.net.mac_hints(function(e, t)

applications/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ if not arg[1] or not m:get(arg[1]) then
99
luci.http.redirect(m.redirect)
1010
end
1111

12+
fs = require "nixio.fs"
13+
formvalue_key = "cbid." .. appname .. "." .. arg[1] .. "."
14+
1215
local header = Template(appname .. "/node_config/header")
1316
header.api = api
1417
header.section = arg[1]
@@ -61,12 +64,18 @@ o.write = function(self, section, value)
6164
m:set(section, self.option, value)
6265
end
6366

64-
local fs = api.fs
6567
local types_dir = "/usr/lib/lua/luci/model/cbi/passwall/client/type/"
6668
s.val = {}
6769
s.val["type"] = m.uci:get(appname, arg[1], "type")
6870
s.val["protocol"] = m.uci:get(appname, arg[1], "protocol")
6971

72+
if luci.http.formvalue("cbi.submit") == "1" then
73+
local formvalue_type = luci.http.formvalue(formvalue_key .. "type")
74+
if formvalue_type then
75+
s.val["type"] = formvalue_type
76+
end
77+
end
78+
7079
o = s:option(ListValue, "type", translate("Type"))
7180

7281
if api.is_finded("ipt2socks") then

applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ local function _n(name)
2525
return option_prefix .. name
2626
end
2727

28-
local formvalue_key = "cbid." .. appname .. "." .. arg[1] .. "."
2928
local formvalue_proto = luci.http.formvalue(formvalue_key .. _n("protocol"))
3029

3130
if formvalue_proto then s.val["protocol"] = formvalue_proto end
@@ -298,6 +297,7 @@ o = s:option(ListValue, _n("flow"), translate("flow"))
298297
o.default = ""
299298
o:value("", translate("Disable"))
300299
o:value("xtls-rprx-vision")
300+
o:value("xtls-rprx-vision-udp443")
301301
o:depends({ [_n("protocol")] = "vless" })
302302

303303
---- [[hysteria2]]

applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ local function _n(name)
2525
return option_prefix .. name
2626
end
2727

28-
local formvalue_key = "cbid." .. appname .. "." .. arg[1] .. "."
2928
local formvalue_proto = luci.http.formvalue(formvalue_key .. _n("protocol"))
3029

3130
if formvalue_proto then s.val["protocol"] = formvalue_proto end

applications/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ o = s:option(ListValue, _n("flow"), translate("flow"))
121121
o.default = ""
122122
o:value("", translate("Disable"))
123123
o:value("xtls-rprx-vision")
124+
o:value("xtls-rprx-vision-udp443")
124125
o:depends({ [_n("protocol")] = "vless" })
125126

126127
---- [[ hysteria2 ]]

applications/luci-app-passwall/luasrc/passwall/util_hysteria2.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ function gen_config(var)
6363
local config = {
6464
server = server,
6565
transport = {
66-
type = node.protocol or "udp",
66+
type = "udp",
6767
udp = {
6868
hopInterval = (function()
6969
local HopIntervalStr = tostring(node.hysteria2_hop_interval or "30s")

applications/luci-app-passwall/luasrc/passwall/util_sing-box.lua

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,8 @@ function gen_outbound(flag, node, tag, proxy_table)
527527
["User-Agent"] = node.user_agent
528528
} or nil,
529529
quic = node.naive_quic == "1" and true or false,
530-
quic_congestion_control = (node.naive_quic == "1" and node.naive_congestion_control) and node.naive_congestion_control or nil
530+
quic_congestion_control = (node.naive_quic == "1" and node.naive_congestion_control) and node.naive_congestion_control or nil,
531+
tls = tls
531532
}
532533
end
533534

@@ -1812,7 +1813,9 @@ function gen_config(var)
18121813
table.insert(dns.rules, {
18131814
query_type = { "A", "AAAA" },
18141815
server = fakedns_tag,
1815-
disable_cache = true
1816+
disable_cache = true,
1817+
rewrite_ttl = 30,
1818+
strategy = remote_strategy
18161819
})
18171820
end
18181821
end
@@ -1954,7 +1957,7 @@ function gen_config(var)
19541957
}
19551958
})
19561959
for index, value in ipairs(config.outbounds) do
1957-
if not value["_flag_proxy_tag"] and not value.detour and value["_id"] and value.server and value.server_port and not no_run then
1960+
if not value["_flag_proxy_tag"] and not value.detour and value["_id"] and value.server and (value.server_port or value.server_ports) and not no_run then
19581961
sys.call(string.format("echo '%s' >> %s", value["_id"], api.TMP_PATH .. "/direct_node_list"))
19591962
end
19601963
for k, v in pairs(config.outbounds[index]) do

applications/luci-app-passwall/luasrc/passwall/util_xray.lua

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,7 @@ function gen_config(var)
746746
local fakedns = nil
747747
local routing = nil
748748
local observatory = nil
749+
local burstObservatory = nil
749750
local strategy = nil
750751
local inbounds = {}
751752
local outbounds = {}
@@ -1003,19 +1004,31 @@ function gen_config(var)
10031004
fallbackTag = fallback_node_tag,
10041005
strategy = strategy
10051006
})
1006-
if not observatory and (_node.balancingStrategy == "leastPing" or _node.balancingStrategy == "leastLoad" or fallback_node_tag) then
1007+
if _node.balancingStrategy == "leastPing" or _node.balancingStrategy == "leastLoad" or fallback_node_tag then
10071008
local t = api.format_go_time(_node.probeInterval)
10081009
if t == "0s" then
10091010
t = "60s"
10101011
elseif not t:find("[hm]") and tonumber(t:match("%d+")) < 10 then
10111012
t = "10s"
10121013
end
1013-
observatory = {
1014-
subjectSelector = { "blc-" },
1015-
probeUrl = _node.useCustomProbeUrl and _node.probeUrl or "https://www.google.com/generate_204",
1016-
probeInterval = t,
1017-
enableConcurrency = true
1018-
}
1014+
if _node.balancingStrategy == "leastLoad" then
1015+
burstObservatory = burstObservatory or {
1016+
subjectSelector = { "blc-" },
1017+
pingConfig = {
1018+
destination = _node.useCustomProbeUrl and _node.probeUrl or nil,
1019+
interval = t,
1020+
sampling = 3,
1021+
timeout = "5s"
1022+
}
1023+
}
1024+
else
1025+
observatory = observatory or {
1026+
subjectSelector = { "blc-" },
1027+
probeUrl = _node.useCustomProbeUrl and _node.probeUrl or nil,
1028+
probeInterval = t,
1029+
enableConcurrency = true
1030+
}
1031+
end
10191032
end
10201033
local loopback_outbound = gen_loopback(loopback_tag, loopback_dst)
10211034
local inbound_tag = loopback_outbound.settings.inboundTag
@@ -1034,14 +1047,25 @@ function gen_config(var)
10341047
else
10351048
local preproxy_node = get_node_by_id(node.preproxy_node)
10361049
if preproxy_node then
1037-
local preproxy_outbound = gen_outbound(node[".name"], preproxy_node)
1050+
local preproxy_outbound, exist
1051+
if preproxy_node.protocol == "_balancing" then
1052+
local balancer_tag, loopback_outbound = gen_balancer(preproxy_node)
1053+
if loopback_outbound then
1054+
preproxy_outbound = loopback_outbound
1055+
exist = true
1056+
end
1057+
else
1058+
preproxy_outbound = gen_outbound(node[".name"], preproxy_node)
1059+
end
10381060
if preproxy_outbound then
10391061
outbound.tag = preproxy_outbound.tag .. " -> " .. outbound.tag
10401062
outbound.proxySettings = {
10411063
tag = preproxy_outbound.tag,
10421064
transportLayer = true
10431065
}
1044-
last_insert_outbound = preproxy_outbound
1066+
if not exist then
1067+
last_insert_outbound = preproxy_outbound
1068+
end
10451069
default_outTag = outbound.tag
10461070
end
10471071
end
@@ -1051,17 +1075,17 @@ function gen_config(var)
10511075
local to_node = get_node_by_id(node.to_node)
10521076
if to_node then
10531077
-- Landing Node not support use special node.
1054-
if to_node.protocol:find("^_") then
1078+
if to_node.protocol and to_node.protocol:find("^_") then
10551079
to_node = nil
10561080
end
10571081
end
10581082
if to_node then
10591083
local to_outbound
10601084
if to_node.type ~= "Xray" then
1061-
local tag = to_node[".name"]
1085+
local in_tag = "inbound_" .. to_node[".name"] .. "_" .. tostring(outbound.tag)
10621086
local new_port = api.get_new_port()
10631087
table.insert(inbounds, {
1064-
tag = tag,
1088+
tag = in_tag,
10651089
listen = "127.0.0.1",
10661090
port = new_port,
10671091
protocol = "dokodemo-door",
@@ -1073,11 +1097,11 @@ function gen_config(var)
10731097
to_node.address = "127.0.0.1"
10741098
to_node.port = new_port
10751099
table.insert(rules, 1, {
1076-
inboundTag = {tag},
1100+
inboundTag = {in_tag},
10771101
outboundTag = outbound.tag
10781102
})
1079-
to_outbound = gen_outbound(node[".name"], to_node, tag, {
1080-
tag = tag,
1103+
to_outbound = gen_outbound(node[".name"], to_node, to_node[".name"], {
1104+
tag = to_node[".name"],
10811105
run_socks_instance = not no_run
10821106
})
10831107
else
@@ -1670,7 +1694,8 @@ function gen_config(var)
16701694
-- 传出连接
16711695
outbounds = outbounds,
16721696
-- 连接观测
1673-
observatory = observatory,
1697+
observatory = (not burstObservatory) and observatory or nil,
1698+
burstObservatory = burstObservatory,
16741699
-- 路由
16751700
routing = routing,
16761701
-- 本地策略
@@ -1720,14 +1745,10 @@ function gen_config(var)
17201745
else
17211746
table.insert(outbounds, blackhole_outbound)
17221747
end
1723-
17241748
for index, value in ipairs(config.outbounds) do
1725-
local s = value.settings
1726-
if not value["_flag_proxy_tag"] and value["_id"] and s and not no_run and
1727-
((s.vnext and s.vnext[1] and s.vnext[1].address and s.vnext[1].port) or
1728-
(s.servers and s.servers[1] and s.servers[1].address and s.servers[1].port) or
1729-
(s.peers and s.peers[1] and s.peers[1].endpoint) or
1730-
(s.address and s.port)) then
1749+
local pt = value.protocol
1750+
local exclude = { blackhole=1, dns=1, freedom=1, loopback=1 }
1751+
if not value["_flag_proxy_tag"] and value["_id"] and pt and not exclude[pt] and not no_run then
17311752
sys.call(string.format("echo '%s' >> %s", value["_id"], api.TMP_PATH .. "/direct_node_list"))
17321753
end
17331754
for k, v in pairs(config.outbounds[index]) do

0 commit comments

Comments
 (0)