Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion applications/luci-app-passwall/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
include $(TOPDIR)/rules.mk

PKG_NAME:=luci-app-passwall
PKG_VERSION:=25.11.1
PKG_VERSION:=25.11.14
PKG_RELEASE:=1

PKG_CONFIG_DEPENDS:= \
Expand Down
79 changes: 73 additions & 6 deletions applications/luci-app-passwall/luasrc/controller/passwall.lua
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,18 @@ function index()
entry({"admin", "services", appname, "connect_status"}, call("connect_status")).leaf = true
entry({"admin", "services", appname, "ping_node"}, call("ping_node")).leaf = true
entry({"admin", "services", appname, "urltest_node"}, call("urltest_node")).leaf = true
entry({"admin", "services", appname, "add_node"}, call("add_node")).leaf = true
entry({"admin", "services", appname, "set_node"}, call("set_node")).leaf = true
entry({"admin", "services", appname, "copy_node"}, call("copy_node")).leaf = true
entry({"admin", "services", appname, "clear_all_nodes"}, call("clear_all_nodes")).leaf = true
entry({"admin", "services", appname, "delete_select_nodes"}, call("delete_select_nodes")).leaf = true
entry({"admin", "services", appname, "get_node"}, call("get_node")).leaf = true
entry({"admin", "services", appname, "update_rules"}, call("update_rules")).leaf = true
entry({"admin", "services", appname, "subscribe_del_node"}, call("subscribe_del_node")).leaf = true
entry({"admin", "services", appname, "subscribe_del_all"}, call("subscribe_del_all")).leaf = true
entry({"admin", "services", appname, "subscribe_manual"}, call("subscribe_manual")).leaf = true
entry({"admin", "services", appname, "subscribe_manual_all"}, call("subscribe_manual_all")).leaf = true
entry({"admin", "services", appname, "flush_set"}, call("flush_set")).leaf = true

--[[rule_list]]
entry({"admin", "services", appname, "read_rulelist"}, call("read_rulelist")).leaf = true
Expand Down Expand Up @@ -138,6 +141,7 @@ function link_add_node()
local chunk = http.formvalue("chunk")
local chunk_index = tonumber(http.formvalue("chunk_index"))
local total_chunks = tonumber(http.formvalue("total_chunks"))
local group = http.formvalue("group") or "default"

if chunk and chunk_index ~= nil and total_chunks ~= nil then
-- 按顺序拼接到文件
Expand All @@ -152,7 +156,7 @@ function link_add_node()
end
-- 如果是最后一片,才执行
if chunk_index + 1 == total_chunks then
luci.sys.call("lua /usr/share/passwall/subscribe.lua add log")
luci.sys.call("lua /usr/share/passwall/subscribe.lua add " .. group)
end
end
end
Expand Down Expand Up @@ -397,6 +401,21 @@ function urltest_node()
http_write_json(e)
end

function add_node()
local redirect = http.formvalue("redirect")

local uuid = api.gen_short_uuid()
uci:section(appname, "nodes", uuid)

if redirect == "1" then
api.uci_save(uci, appname)
http.redirect(api.url("node_config", uuid))
else
api.uci_save(uci, appname, true, true)
http_write_json({result = uuid})
end
end

function set_node()
local protocol = http.formvalue("protocol")
local section = http.formvalue("section")
Expand All @@ -420,7 +439,7 @@ function copy_node()
end)
end
end
uci:delete(appname, uuid, "add_from")
uci:delete(appname, uuid, "group")
uci:set(appname, uuid, "add_mode", 1)
api.uci_save(uci, appname)
http.redirect(api.url("node_config", uuid))
Expand Down Expand Up @@ -458,6 +477,7 @@ end

function delete_select_nodes()
local ids = http.formvalue("ids")
local redirect = http.formvalue("redirect")
string.gsub(ids, '[^' .. "," .. ']+', function(w)
if (uci:get(appname, "@global[0]", "tcp_node") or "") == w then
uci:delete(appname, '@global[0]', "tcp_node")
Expand Down Expand Up @@ -532,18 +552,51 @@ function delete_select_nodes()
end
end)
if (uci:get(appname, w, "add_mode") or "0") == "2" then
local add_from = uci:get(appname, w, "add_from") or ""
if add_from ~= "" then
local group = uci:get(appname, w, "group") or ""
if group ~= "" then
uci:foreach(appname, "subscribe_list", function(t)
if t["remark"] == add_from then
if t["remark"] == group then
uci:delete(appname, t[".name"], "md5")
end
end)
end
end
uci:delete(appname, w)
end)
api.uci_save(uci, appname, true, true)
if redirect == "1" then
api.uci_save(uci, appname)
http.redirect(api.url("node_list"))
else
api.uci_save(uci, appname, true, true)
end
end


function get_node()
local id = http.formvalue("id")
local result = {}
local show_node_info = api.uci_get_type("@global_other[0]", "show_node_info", "0")

function add_is_ipv6_key(o)
if o and o.address and show_node_info == "1" then
local f = api.get_ipv6_full(o.address)
if f ~= "" then
o.ipv6 = true
o.full_address = f
end
end
end

if id then
result = uci:get_all(appname, id)
add_is_ipv6_key(result)
else
uci:foreach(appname, "nodes", function(t)
add_is_ipv6_key(t)
result[#result + 1] = t
end)
end
http_write_json(result)
end

function update_rules()
Expand Down Expand Up @@ -816,3 +869,17 @@ function subscribe_manual_all()
luci.sys.call("lua /usr/share/" .. appname .. "/subscribe.lua start all manual >/dev/null 2>&1 &")
http_write_json({ success = true, msg = "Subscribe triggered." })
end

function flush_set()
local redirect = http.formvalue("redirect") or "0"
local reload = http.formvalue("reload") or "0"
if reload == "1" then
uci:set(appname, '@global[0]', "flush_set", "1")
api.uci_save(uci, appname, true, true)
else
api.sh_uci_set(appname, "@global[0]", "flush_set", "1", true)
end
if redirect == "1" then
http.redirect(api.url("log"))
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ local port_validate = function(self, value, t)
end

local nodes_table = {}
local shunt_list = {}
for k, e in ipairs(api.get_valid_nodes()) do
nodes_table[#nodes_table + 1] = e
end
Expand Down Expand Up @@ -202,6 +203,9 @@ o:depends({ _tcp_node_bool = "1" })
for k, v in pairs(nodes_table) do
s.fields["tcp_node"]:value(v.id, v["remark"])
s.fields["udp_node"]:value(v.id, v["remark"])
if v.protocol and v.protocol == "_shunt" then
shunt_list[#shunt_list + 1] = v
end
end

o = s:option(DummyValue, "_udp_node_bool", "")
Expand Down Expand Up @@ -313,11 +317,7 @@ o.default = "0"
o:depends({ _tcp_node_bool = "1" })

---- DNS Forward Mode
o = s:option(ListValue, "dns_mode", translate("Filter Mode"),
"<font color='red'>" .. translate(
"If the node uses Xray/Sing-Box shunt, select the matching filter mode (Xray/Sing-Box).") ..
"</font>")
o:depends({ _tcp_node_bool = "1" })
o = s:option(ListValue, "dns_mode", translate("Filter Mode"))
if api.is_finded("dns2socks") then
o:value("dns2socks", "dns2socks")
end
Expand All @@ -327,6 +327,19 @@ end
if has_xray then
o:value("xray", "Xray")
end
o.remove = function(self, section)
local f = s.fields["tcp_node"]
local id_val = f and f:formvalue(section) or ""
if id_val == "" then
return m:del(section, self.option)
end
for k, v in pairs(shunt_list) do
if v.id == id_val then
local new_val = (v.type == "Xray") and "xray" or "sing-box"
return m:set(section, self.option, new_val)
end
end
end

o = s:option(ListValue, "xray_dns_mode", translate("Request protocol"))
o:value("tcp", "TCP")
Expand Down Expand Up @@ -439,4 +452,21 @@ o:value("direct", translate("Direct DNS"))
o.description = desc .. "</ul>"
o:depends({dns_shunt = "dnsmasq", tcp_proxy_mode = "proxy", chn_list = "direct"})

for k, v in pairs(nodes_table) do
if v.protocol ~= "_shunt" then
s.fields["dns_mode"]:depends({ _tcp_node_bool = "1", tcp_node = v.id })
end
end
for k, v in pairs(shunt_list) do
if v.type == "Xray" and has_xray then
s.fields["xray_dns_mode"]:depends({ _tcp_node_bool = "1", tcp_node = v.id })
end
if v.type == "sing-box" and has_singbox then
s.fields["singbox_dns_mode"]:depends({ _tcp_node_bool = "1", tcp_node = v.id })
end
if has_xray or has_singbox then
s.fields["remote_dns_client_ip"]:depends({ tcp_node = v.id })
end
end

return m
Original file line number Diff line number Diff line change
Expand Up @@ -322,11 +322,37 @@ o:depends("direct_dns_mode", "tcp")
o = s:taboption("DNS", Flag, "filter_proxy_ipv6", translate("Filter Proxy Host IPv6"), translate("Experimental feature."))
o.default = "0"

-- TCP分流时dns过滤模式保存逻辑
function dns_mode_save(section)
for k, v in pairs(shunt_list) do
local f = s.fields[v.id .. "-type"]
if f then
local type_val = f:formvalue(section)
if type_val and (type_val == "Xray" or type_val == "sing-box") then
local dns_shunt_val = s.fields["dns_shunt"]:formvalue(section)
local dns_mode_val = (dns_shunt_val ~= "smartdns") and "dns_mode" or "smartdns_dns_mode"
local current_val = m:get(section, dns_mode_val) or ""
local new_val = (type_val == "Xray") and "xray" or "sing-box"

if current_val ~= new_val then
m:set(section, dns_mode_val, new_val)
m:del(section, (dns_mode_val == "dns_mode") and "smartdns_dns_mode" or "dns_mode")
end

local dns_field = s.fields[type_val == "Xray" and "xray_dns_mode" or "singbox_dns_mode"]
local v2ray_dns_mode = dns_field and dns_field:formvalue(section)
if v2ray_dns_mode and m:get(section, "v2ray_dns_mode") ~= v2ray_dns_mode then
m:set(section, "v2ray_dns_mode", v2ray_dns_mode)
end

break
end
end
end
end

---- DNS Forward Mode
o = s:taboption("DNS", ListValue, "dns_mode", translate("Filter Mode"),
"<font color='red'>" .. translate(
"If the node uses Xray/Sing-Box shunt, select the matching filter mode (Xray/Sing-Box).") ..
"</font>")
o = s:taboption("DNS", ListValue, "dns_mode", translate("Filter Mode"))
o:value("udp", translatef("Requery DNS By %s", "UDP"))
o:value("tcp", translatef("Requery DNS By %s", "TCP"))
if api.is_finded("dns2socks") then
Expand All @@ -338,24 +364,34 @@ end
if has_xray then
o:value("xray", "Xray")
end
if api.is_finded("smartdns") then
o:depends({ dns_shunt = "smartdns", ['!reverse'] = true })
o:depends({ dns_shunt = "chinadns-ng", tcp_node = "" })
o:depends({ dns_shunt = "dnsmasq", tcp_node = "" })
o.remove = function(self, section)
local f = s.fields["smartdns_dns_mode"]
if f and f:formvalue(section) then
return m:del(section, self.option)
end
dns_mode_save(section)
end

---- SmartDNS Forward Mode
if api.is_finded("smartdns") then
o = s:taboption("DNS", ListValue, "smartdns_dns_mode", translate("Filter Mode"),
"<font color='red'>" .. translate(
"If the node uses Xray/Sing-Box shunt, select the matching filter mode (Xray/Sing-Box).") ..
"</font>")
o = s:taboption("DNS", ListValue, "smartdns_dns_mode", translate("Filter Mode"))
o:value("socks", "Socks")
if has_singbox then
o:value("sing-box", "Sing-Box")
end
if has_xray then
o:value("xray", "Xray")
end
o:depends({ dns_shunt = "smartdns" })
o:depends({ dns_shunt = "smartdns", tcp_node = "" })
o.remove = function(self, section)
local f = s.fields["dns_mode"]
if f and f:formvalue(section) then
return m:del(section, self.option)
end
dns_mode_save(section)
end

o = s:taboption("DNS", DynamicList, "smartdns_remote_dns", translate("Remote DNS"))
o:value("tcp://1.1.1.1")
Expand Down Expand Up @@ -400,7 +436,7 @@ if api.is_finded("smartdns") then
end
end

o = s:taboption("DNS", ListValue, "xray_dns_mode", translate("Request protocol"))
o = s:taboption("DNS", ListValue, "xray_dns_mode", translate("Remote DNS") .. " " .. translate("Request protocol"))
o:value("tcp", "TCP")
o:value("tcp+doh", "TCP + DoH (" .. translate("A/AAAA type") .. ")")
o:depends("dns_mode", "xray")
Expand All @@ -414,7 +450,7 @@ o.write = function(self, section, value)
end
end

o = s:taboption("DNS", ListValue, "singbox_dns_mode", translate("Request protocol"))
o = s:taboption("DNS", ListValue, "singbox_dns_mode", translate("Remote DNS") .. " " .. translate("Request protocol"))
o:value("tcp", "TCP")
o:value("doh", "DoH")
o:depends("dns_mode", "sing-box")
Expand Down Expand Up @@ -493,7 +529,10 @@ o:depends({dns_mode = "xray", dns_shunt = "chinadns-ng"})
o:depends({smartdns_dns_mode = "xray", dns_shunt = "smartdns"})
o.validate = function(self, value, t)
if value and value == "1" then
local _dns_mode = s.fields["dns_mode"]:formvalue(t) or s.fields["smartdns_dns_mode"]:formvalue(t)
local _dns_mode = s.fields["dns_mode"]:formvalue(t)
if not _dns_mode and s.fields["smartdns_dns_mode"] then
_dns_mode = s.fields["smartdns_dns_mode"]:formvalue(t)
end
local _tcp_node = s.fields["tcp_node"]:formvalue(t)
if _dns_mode and _tcp_node then
if m:get(_tcp_node, "type"):lower() ~= _dns_mode then
Expand Down Expand Up @@ -544,16 +583,19 @@ o = s:taboption("DNS", Flag, "dns_redirect", translate("DNS Redirect"), translat
o.default = "1"
o.rmempty = false

if (m:get("@global_forwarding[0]", "use_nft") or "0") == "1" then
o = s:taboption("DNS", Button, "clear_ipset", translate("Clear NFTSET"), translate("Try this feature if the rule modification does not take effect."))
else
o = s:taboption("DNS", Button, "clear_ipset", translate("Clear IPSET"), translate("Try this feature if the rule modification does not take effect."))
end
o.inputstyle = "remove"
function o.write(e, e)
m:set("@global[0]", "flush_set", "1")
api.uci_save(m.uci, appname, true, true)
luci.http.redirect(api.url("log"))
local use_nft = m:get("@global_forwarding[0]", "use_nft") == "1"
local set_title = api.i18n.translate(use_nft and "Clear NFTSET on Reboot" or "Clear IPSET on Reboot")
o = s:taboption("DNS", Flag, "flush_set_on_reboot", set_title, translate("Clear IPSET/NFTSET on service reboot. This may increase reboot time."))
o.default = "0"
o.rmempty = false

set_title = api.i18n.translate(use_nft and "Clear NFTSET" or "Clear IPSET")
o = s:taboption("DNS", DummyValue, "clear_ipset", set_title, translate("Try this feature if the rule modification does not take effect."))
o.rawhtml = true
function o.cfgvalue(self, section)
return string.format(
[[<button type="button" class="cbi-button cbi-button-remove" onclick="location.href='%s'">%s</button>]],
api.url("flush_set") .. "?redirect=1&reload=1", set_title)
end

s:tab("Proxy", translate("Mode"))
Expand Down Expand Up @@ -733,6 +775,21 @@ for k, v in pairs(nodes_table) do
else
s2.fields["node"]:value(v.id, v["remark"])
end

if v.protocol ~= "_shunt" then
s.fields["dns_mode"]:depends({ dns_shunt = "chinadns-ng", tcp_node = v.id })
s.fields["dns_mode"]:depends({ dns_shunt = "dnsmasq", tcp_node = v.id })
if api.is_finded("smartdns") then
s.fields["smartdns_dns_mode"]:depends({ dns_shunt = "smartdns", tcp_node = v.id })
end
end
end

for k, v in pairs(shunt_list) do
s.fields["xray_dns_mode"]:depends({ [v.id .. "-type"] = "Xray", tcp_node = v.id })
s.fields["singbox_dns_mode"]:depends({ [v.id .. "-type"] = "sing-box", tcp_node = v.id })
s.fields["remote_dns_client_ip"]:depends({ tcp_node = v.id })
s.fields["remote_fakedns"]:depends({ tcp_node = v.id })
end

m:append(Template(appname .. "/global/footer"))
Expand Down
Loading
Loading