🎄 Sync 2026-08-10 20:58:00

This commit is contained in:
github-actions[bot] committed 2026-08-10 20:58:00 +08:00
1 parent f93918f4ae
commit e68eb29c6f
37 files changed
+318 -551

No files matched your search

+2 -2
View File
@@ -6,9 +6,9 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=dae PKG_NAME:=dae
PKG_VERSION:=2026.08.05 PKG_VERSION:=2026.08.05
PKG_RELEASE:=33 PKG_RELEASE:=34
PKG_SOURCE:=dae-src-2026.08.05-479f43645df5.tar.gz PKG_SOURCE:=dae-src-2026.08.05-fc1a5bf558fd.tar.gz
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/dae-src PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/dae-src
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_HASH:=skip PKG_HASH:=skip
+2 -2
View File
@@ -6,9 +6,9 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=daed PKG_NAME:=daed
PKG_VERSION:=2026.08.05 PKG_VERSION:=2026.08.05
PKG_RELEASE:=44 PKG_RELEASE:=45
PKG_SOURCE:=daed-src-2026.08.05-c389546b8c1f.tar.gz PKG_SOURCE:=daed-src-2026.08.05-1d87c2949acc.tar.gz
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/daed-src PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/daed-src
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_HASH:=skip PKG_HASH:=skip
@@ -1048,6 +1048,15 @@ return view.extend({
so.depends({type: /^(zerotier|wireguard|masque|openvpn)$/}); so.depends({type: /^(zerotier|wireguard|masque|openvpn)$/});
so.modalonly = true; so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'ipstack_congestion_controller', _('IP stack') + ': ' + _('Congestion controller'));
so.value('', _('Keep default'));
so.value('cubic', _('cubic'));
so.value('reno', _('reno'));
so.value('bbr', _('bbr'));
so.value('bbr3', _('bbr3'));
so.depends({ipstack: /^(auto|mips)$/}); // not empty not gvisor
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'congestion_controller', _('Congestion controller')); so = ss.taboption('field_general', form.ListValue, 'congestion_controller', _('Congestion controller'));
so.default = hm.congestion_controller[0][0]; so.default = hm.congestion_controller[0][0];
hm.congestion_controller.forEach((res) => { hm.congestion_controller.forEach((res) => {
@@ -1055,7 +1064,6 @@ return view.extend({
}) })
so.depends({type: /^(tuic|shadowquic|trusttunnel)$/}); so.depends({type: /^(tuic|shadowquic|trusttunnel)$/});
so.depends({type: 'masque', masque_network: /^(|h3-l4proxy)$/}); so.depends({type: 'masque', masque_network: /^(|h3-l4proxy)$/});
so.depends({ipstack: /^(auto|mips)$/}); // not empty not gvisor
so.modalonly = true; so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'bbr_profile', _('BBR profile')); so = ss.taboption('field_general', form.ListValue, 'bbr_profile', _('BBR profile'));
@@ -171,6 +171,14 @@ migrate() {
uci_remove "$CONF" "$1" zerotier_ipstack uci_remove "$CONF" "$1" zerotier_ipstack
uci_set "$CONF" "$1" ipstack "$zerotier_ipstack" uci_set "$CONF" "$1" ipstack "$zerotier_ipstack"
fi fi
# congestion_controller -> ipstack_congestion_controller
if isDefined "$1" congestion_controller && (isDefined "$1" zerotier_ipstack || isDefined "$1" ipstack); then
local congestion_controller
config_get congestion_controller "$1" congestion_controller ""
uci_remove "$CONF" "$1" congestion_controller
uci_set "$CONF" "$1" ipstack_congestion_controller "$congestion_controller"
fi
} }
config_foreach migrate node config_foreach migrate node
@@ -678,12 +678,12 @@ uci.foreach(uciconf, ucinode, (cfg) => {
/* Extra fields */ /* Extra fields */
"ip-stack": cfg.ipstack ? { "ip-stack": cfg.ipstack ? {
mode: cfg.ipstack, mode: cfg.ipstack,
"congestion-controller": replace(cfg.congestion_controller, 'new_reno', 'reno') "congestion-controller": cfg.ipstack_congestion_controller
} : null, } : null,
"udp-over-stream": strToBool(cfg.shadowquic_udp_over_stream || cfg.tuic_udp_over_stream), "udp-over-stream": strToBool(cfg.shadowquic_udp_over_stream || cfg.tuic_udp_over_stream),
"heartbeat-interval": strToInt(cfg.tuic_heartbeat) || null, "heartbeat-interval": strToInt(cfg.tuic_heartbeat) || null,
"keep-alive-interval": strToInt(cfg.shadowquic_heartbeat) || null, "keep-alive-interval": strToInt(cfg.shadowquic_heartbeat) || null,
"congestion-controller": cfg.type in ['zerotier', 'wireguard', 'masque', 'openvpn'] ? null : cfg.congestion_controller, "congestion-controller": cfg.congestion_controller,
"bbr-profile": cfg.bbr_profile, "bbr-profile": cfg.bbr_profile,
"max-open-streams": strToInt(cfg.max_open_streams) || null, "max-open-streams": strToInt(cfg.max_open_streams) || null,
+1 -1
View File
@@ -4,7 +4,7 @@ LUCI_TITLE:=Information dashboard for 3G/LTE dongle
LUCI_DEPENDS:=+modeminfo LUCI_DEPENDS:=+modeminfo
PKG_LICENSE:=GPLv3 PKG_LICENSE:=GPLv3
PKG_VERSION:=0.4.8 PKG_VERSION:=0.4.8
PKG_RELEASE:=11 PKG_RELEASE:=12
include $(TOPDIR)/feeds/luci/luci.mk include $(TOPDIR)/feeds/luci/luci.mk
+2 -2
View File
@@ -16,7 +16,7 @@ Supported devices:
- Sierra Wireless EM7455/EM9191 - Sierra Wireless EM7455/EM9191
- HP LT4220 - Telit LN940(HP LT4220)/LM960
- Dell DW5821e/DW5829e - Dell DW5821e/DW5829e
@@ -43,7 +43,7 @@ Supported devices:
|modeminfo |common files | |modeminfo |common files |
|modeminfo-qmi |Qualcomm MSM Interface support | |modeminfo-qmi |Qualcomm MSM Interface support |
|modeminfo-serial-quectel |Quectel modems support | |modeminfo-serial-quectel |Quectel modems support |
|modeminfo-serial-telit |Telit LN940 (HP LT4220) modem support | |modeminfo-serial-telit |Telit LN940(HP LT4220)/LM960 modem support |
|modeminfo-serial-huawei |Huawei MU709/ME909/E3372(stick mode, LTE only) modems support| |modeminfo-serial-huawei |Huawei MU709/ME909/E3372(stick mode, LTE only) modems support|
|modeminfo-serial-sierra |Sierra EM7455/EM9191 modem support | |modeminfo-serial-sierra |Sierra EM7455/EM9191 modem support |
|modeminfo-serial-simcom |SimCOM modems support | |modeminfo-serial-simcom |SimCOM modems support |
+1 -1
View File
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall PKG_NAME:=luci-app-passwall
PKG_VERSION:=26.8.1 PKG_VERSION:=26.8.1
PKG_RELEASE:=211 PKG_RELEASE:=212
PKG_PO_VERSION:=$(PKG_VERSION) PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \ PKG_CONFIG_DEPENDS:= \
@@ -49,18 +49,6 @@ m.uci:foreach(appname, "socks", function(s)
end end
end) end)
local dynamicList_write = function(self, section, value)
local new_t = {}
if type(value) == "table" then
new_t = api.table_remove_duplicates(value)
else
new_t = { value }
end
local new_val = table.concat(new_t, " ")
return DynamicList.write(self, section, new_val)
end
-- [[ ACLs Settings ]]-- -- [[ ACLs Settings ]]--
s = m:section(NamedSection, cfgid, translate("ACLs"), translate("ACLs")) s = m:section(NamedSection, cfgid, translate("ACLs"), translate("ACLs"))
s.addremove = false s.addremove = false
@@ -173,7 +161,6 @@ sources.validate = function(self, value, t)
return value return value
end end
sources.write = dynamicList_write
o = s:option(ListValue, "mode", translate("Mode")) o = s:option(ListValue, "mode", translate("Mode"))
o:value("0", translate("No Proxy")) o:value("0", translate("No Proxy"))
@@ -372,15 +372,6 @@ if api.is_finded("smartdns") then
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return m:get(section, self.option) or {"tcp://1.1.1.1"} return m:get(section, self.option) or {"tcp://1.1.1.1"}
end end
function o.write(self, section, value)
local new_t = {}
if type(value) == "table" then
new_t = api.table_remove_duplicates(value)
else
new_t = { value }
end
return DynamicList.write(self, section, new_t)
end
end end
o = s:taboption("DNS", ListValue, "xray_dns_mode", translate("Remote DNS") .. " " .. translate("Request protocol")) o = s:taboption("DNS", ListValue, "xray_dns_mode", translate("Remote DNS") .. " " .. translate("Request protocol"))
@@ -156,6 +156,12 @@ o:value("UseIPv6v4", translate("Prefer IPv6"))
o:value("UseIPv4", translate("IPv4 Only")) o:value("UseIPv4", translate("IPv4 Only"))
o:value("UseIPv6", translate("IPv6 Only")) o:value("UseIPv6", translate("IPv6 Only"))
o = s:option(Flag, "allowInsecure", translate("allowInsecure"))
o.default = "0"
o.rmempty = false
o.description = translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped.") .. "<br>" ..
translate("Used when the node link does not include this parameter.")
o = s:option(ListValue, "filter_keyword_mode", translate("Filter keyword Mode")) o = s:option(ListValue, "filter_keyword_mode", translate("Filter keyword Mode"))
o.default = "5" o.default = "5"
o:value("0", translate("Close")) o:value("0", translate("Close"))
@@ -164,19 +164,6 @@ source.validate = function(self, value, t)
return value return value
end end
local dynamicList_write = function(self, section, value)
local new_t = {}
if type(value) == "table" then
new_t = api.table_remove_duplicates(value)
else
new_t = { value }
end
local new_val = table.concat(new_t, " ")
return DynamicList.write(self, section, new_val)
end
source.write = dynamicList_write
--[[ --[[
-- Too low usage rate, hidden -- Too low usage rate, hidden
sourcePort = s:option(Value, "sourcePort", translate("Source port")) sourcePort = s:option(Value, "sourcePort", translate("Source port"))
@@ -116,12 +116,12 @@ if load_balancing_options then -- [[ Load balancing Start ]]
end end
end end
-- 读取旧 DynamicList -- 读取旧 DynamicList
function o.cfgvalue(self, section) function o.custom_cfgvalue(self, section)
return m.uci:get_list(appname, section, "balancing_node") or {} return table.concat(m:get(section, "balancing_node") or {}, " ")
end end
-- 写入保持 DynamicList -- 写入保持 DynamicList
function o.custom_write(self, section, value) function o.custom_write(self, section, value)
local old = m.uci:get_list(appname, section, "balancing_node") or {} local old = m:get(section, "balancing_node") or {}
local new, set = {}, {} local new, set = {}, {}
for v in value:gmatch("%S+") do for v in value:gmatch("%S+") do
new[#new + 1] = v new[#new + 1] = v
@@ -129,13 +129,13 @@ if load_balancing_options then -- [[ Load balancing Start ]]
end end
for _, v in ipairs(old) do for _, v in ipairs(old) do
if not set[v] then if not set[v] then
m.uci:set_list(appname, section, "balancing_node", new) m:set(section, "balancing_node", new)
return return
end end
set[v] = nil set[v] = nil
end end
for _ in pairs(set) do for _ in pairs(set) do
m.uci:set_list(appname, section, "balancing_node", new) m:set(section, "balancing_node", new)
return return
end end
end end
@@ -115,12 +115,12 @@ if load_urltest_options then -- [[ URLTest Start ]]
end end
end end
-- 读取旧 DynamicList -- 读取旧 DynamicList
function o.cfgvalue(self, section) function o.custom_cfgvalue(self, section)
return m.uci:get_list(appname, section, "urltest_node") or {} return table.concat(m:get(section, "urltest_node") or {}, " ")
end end
-- 写入保持 DynamicList -- 写入保持 DynamicList
function o.custom_write(self, section, value) function o.custom_write(self, section, value)
local old = m.uci:get_list(appname, section, "urltest_node") or {} local old = m:get(section, "urltest_node") or {}
local new, set = {}, {} local new, set = {}, {}
for v in value:gmatch("%S+") do for v in value:gmatch("%S+") do
new[#new + 1] = v new[#new + 1] = v
@@ -128,13 +128,13 @@ if load_urltest_options then -- [[ URLTest Start ]]
end end
for _, v in ipairs(old) do for _, v in ipairs(old) do
if not set[v] then if not set[v] then
m.uci:set_list(appname, section, "urltest_node", new) m:set(section, "urltest_node", new)
return return
end end
set[v] = nil set[v] = nil
end end
for _ in pairs(set) do for _ in pairs(set) do
m.uci:set_list(appname, section, "urltest_node", new) m:set(section, "urltest_node", new)
return return
end end
end end
@@ -216,15 +216,6 @@ o:depends({ [_n("reality")] = true })
o = s:option(DynamicList, _n("reality_serverNames"), translate("serverNames")) o = s:option(DynamicList, _n("reality_serverNames"), translate("serverNames"))
o:depends({ [_n("reality")] = true }) o:depends({ [_n("reality")] = true })
function o.custom_write(self, section, value)
local new_t = {}
if type(value) == "table" then
new_t = api.table_remove_duplicates(value)
else
new_t = { value }
end
m:set(section, self.option:sub(1 + #option_prefix), new_t)
end
o = s:option(ListValue, _n("alpn"), translate("alpn")) o = s:option(ListValue, _n("alpn"), translate("alpn"))
o.default = "default" o.default = "default"
+36 -3
View File
@@ -1014,7 +1014,6 @@ local default_file_tree = {
} }
local function get_api_json(url) local function get_api_json(url)
local jsonc = require "luci.jsonc"
local gh_proxy = uci_get_type("global_app", "github_proxy", "0") local gh_proxy = uci_get_type("global_app", "github_proxy", "0")
local return_code, content local return_code, content
if gh_proxy == "1" then if gh_proxy == "1" then
@@ -1345,6 +1344,25 @@ function set_default_cbi()
self.template = appname .. "/cbi/tvalue" self.template = appname .. "/cbi/tvalue"
end end
end end
if true then
--DynamicList
local DynamicList = cbi.DynamicList
function DynamicList.write(self, section, value)
local new_t = {}
if type(value) == "table" then
new_t = table_remove_duplicates(value)
else
new_t = { value }
end
local new_val
if self.cast == "string" then
new_val = table.concat(new_t, " ")
else
new_val = new_t
end
return cbi.AbstractValue.write(self, section, new_val)
end
end
end end
function return_map(map) function return_map(map)
@@ -1369,6 +1387,7 @@ function return_map(map)
end end
function luci_types(id, m, s, type_name, option_prefix) function luci_types(id, m, s, type_name, option_prefix)
local cbi = require "luci.cbi"
local fv_type local fv_type
local field_type = s.fields["type"] local field_type = s.fields["type"]
if field_type then if field_type then
@@ -1406,11 +1425,25 @@ function luci_types(id, m, s, type_name, option_prefix)
if self.custom_write then if self.custom_write then
self:custom_write(section, value) self:custom_write(section, value)
else else
local new_val = value
if util.instanceof(self, cbi.DynamicList) then
local new_t = {}
if type(value) == "table" then
new_t = table_remove_duplicates(value)
else
new_t = { value }
end
if self.cast == "string" then
new_val = table.concat(new_t, " ")
else
new_val = new_t
end
end
if self.rewrite_option then if self.rewrite_option then
m:set(section, self.rewrite_option, value) m:set(section, self.rewrite_option, new_val)
else else
if self.option:find(option_prefix) == 1 then if self.option:find(option_prefix) == 1 then
m:set(section, self.option:sub(1 + #option_prefix), value) m:set(section, self.option:sub(1 + #option_prefix), new_val)
end end
end end
end end
+3
View File
@@ -1283,6 +1283,9 @@ msgstr "使用全局配置"
msgid "User-Agent" msgid "User-Agent"
msgstr "用户代理(User-Agent)" msgstr "用户代理(User-Agent)"
msgid "Used when the node link does not include this parameter."
msgstr "当节点链接未包含该参数时,将使用此设置。"
msgid "Add" msgid "Add"
msgstr "添加" msgstr "添加"
@@ -220,7 +220,7 @@ local function encode_vless(node)
local link = "vless://" .. node.uuid .. "@" .. o.server .. ":" .. o.port local link = "vless://" .. node.uuid .. "@" .. o.server .. ":" .. o.port
local p = {} local p = {}
if node.flow then table.insert(p, "flow=" .. urlencode(node.flow)) end if type(node.flow) == "string" and node.flow:sub(1, 5) == "xtls-" then table.insert(p, "flow=" .. urlencode(node.flow)) end
if node.encryption then table.insert(p, "encryption=" .. urlencode(node.encryption)) end if node.encryption then table.insert(p, "encryption=" .. urlencode(node.encryption)) end
-- TLS -- TLS
@@ -29,6 +29,7 @@ local has_ssr = api.is_finded("ssr-local") and api.is_finded("ssr-redir")
local has_singbox = api.finded_com("sing-box") local has_singbox = api.finded_com("sing-box")
local has_xray = api.finded_com("xray") local has_xray = api.finded_com("xray")
local has_hysteria2 = api.finded_com("hysteria") local has_hysteria2 = api.finded_com("hysteria")
local DEFAULT_ALLOWINSECURE = true
local DEFAULT_FILTER_KEYWORD_MODE = uci:get(appname, "@global_subscribe[0]", "filter_keyword_mode") or "0" local DEFAULT_FILTER_KEYWORD_MODE = uci:get(appname, "@global_subscribe[0]", "filter_keyword_mode") or "0"
local DEFAULT_FILTER_KEYWORD_DISCARD_LIST = uci:get(appname, "@global_subscribe[0]", "filter_discard_list") or {} local DEFAULT_FILTER_KEYWORD_DISCARD_LIST = uci:get(appname, "@global_subscribe[0]", "filter_discard_list") or {}
local DEFAULT_FILTER_KEYWORD_KEEP_LIST = uci:get(appname, "@global_subscribe[0]", "filter_keep_list") or {} local DEFAULT_FILTER_KEYWORD_KEEP_LIST = uci:get(appname, "@global_subscribe[0]", "filter_keep_list") or {}
@@ -516,6 +517,7 @@ end
-- 处理数据 -- 处理数据
local function processData(szType, content, add_mode, group, sub_cfg) local function processData(szType, content, add_mode, group, sub_cfg)
--log(2, content, add_mode, group) --log(2, content, add_mode, group)
local sub_allowinsecure = DEFAULT_ALLOWINSECURE
local sub_ss_type = DEFAULT_SS_TYPE local sub_ss_type = DEFAULT_SS_TYPE
local sub_trojan_type = DEFAULT_TROJAN_TYPE local sub_trojan_type = DEFAULT_TROJAN_TYPE
local sub_vmess_type = DEFAULT_VMESS_TYPE local sub_vmess_type = DEFAULT_VMESS_TYPE
@@ -523,6 +525,9 @@ local function processData(szType, content, add_mode, group, sub_cfg)
local sub_hysteria2_type = DEFAULT_HYSTERIA2_TYPE local sub_hysteria2_type = DEFAULT_HYSTERIA2_TYPE
local sub_hy_up_mbps, sub_hy_down_mbps = 1000, 1000 local sub_hy_up_mbps, sub_hy_down_mbps = 1000, 1000
if sub_cfg then if sub_cfg then
if sub_cfg.allowInsecure and sub_cfg.allowInsecure ~= "1" then
sub_allowinsecure = nil
end
local ss_type = sub_cfg.ss_type or "global" local ss_type = sub_cfg.ss_type or "global"
if ss_type ~= "global" and core_has[ss_type] then if ss_type ~= "global" and core_has[ss_type] then
sub_ss_type = ss_type sub_ss_type = ss_type
@@ -695,7 +700,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.tls_serverName = (info.sni and info.sni ~= "") and info.sni or info.host result.tls_serverName = (info.sni and info.sni ~= "") and info.sni or info.host
result.tls_pinSHA256 = info.pcs result.tls_pinSHA256 = info.pcs
result.tls_CertByName = info.vcn result.tls_CertByName = info.vcn
result.tls_allowInsecure = info.allowinsecure or info.allowInsecure or info.insecure local insecure = info.allowinsecure or info.allowInsecure or info.insecure
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0")
else else
result.tls = "0" result.tls = "0"
end end
@@ -971,7 +977,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.reality_mldsa65Verify = params.pqv or nil result.reality_mldsa65Verify = params.pqv or nil
end end
end end
result.tls_allowInsecure = params.allowinsecure or params.allowInsecure or params.insecure 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.uot = params.udp result.uot = params.udp
else else
result.error_msg = "请更换 Xray 或 Sing-Box 来支持 SS 更多的传输方式。" result.error_msg = "请更换 Xray 或 Sing-Box 来支持 SS 更多的传输方式。"
@@ -1089,7 +1096,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
end end
result.tls_pinSHA256 = params.pcs result.tls_pinSHA256 = params.pcs
result.tls_CertByName = params.vcn result.tls_CertByName = params.vcn
result.tls_allowInsecure = params.allowinsecure or params.allowInsecure or params.insecure 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")
end end
if not params.type then params.type = "tcp" end if not params.type then params.type = "tcp" end
@@ -1344,7 +1352,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.use_mldsa65Verify = (params.pqv and params.pqv ~= "") and "1" or nil result.use_mldsa65Verify = (params.pqv and params.pqv ~= "") and "1" or nil
result.reality_mldsa65Verify = params.pqv or nil result.reality_mldsa65Verify = params.pqv or nil
end end
result.tls_allowInsecure = params.allowinsecure or params.allowInsecure or params.insecure 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")
end end
result.port = port result.port = port
@@ -1400,7 +1409,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.hysteria_auth_type = "string" result.hysteria_auth_type = "string"
result.hysteria_auth_password = params.auth result.hysteria_auth_password = params.auth
result.tls_serverName = params.peer or params.sni or "" result.tls_serverName = params.peer or params.sni or ""
result.tls_allowInsecure = params.allowinsecure or params.allowInsecure or params.insecure 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 result.alpn = params.alpn
result.hysteria_up_mbps = params.upmbps or sub_hy_up_mbps result.hysteria_up_mbps = params.upmbps or sub_hy_up_mbps
result.hysteria_down_mbps = params.downmbps or sub_hy_down_mbps result.hysteria_down_mbps = params.downmbps or sub_hy_down_mbps
@@ -1445,7 +1455,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.tls_serverName = params.sni result.tls_serverName = params.sni
result.tls_pinSHA256 = params.pcs or params.pinsha256 result.tls_pinSHA256 = params.pcs or params.pinsha256
result.tls_CertByName = params.vcn result.tls_CertByName = params.vcn
result.tls_allowInsecure = params.allowinsecure or params.insecure local insecure = params.allowinsecure or params.insecure
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0")
result.hysteria2_up_mbps = params.upmbps or (sub_cfg and sub_hy_up_mbps or nil) result.hysteria2_up_mbps = params.upmbps or (sub_cfg and sub_hy_up_mbps or nil)
result.hysteria2_down_mbps = params.downmbps or (sub_cfg and sub_hy_down_mbps or nil) result.hysteria2_down_mbps = params.downmbps or (sub_cfg and sub_hy_down_mbps or nil)
result.hysteria2_hop = params.mport result.hysteria2_hop = params.mport
@@ -1526,7 +1537,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.tuic_alpn = params.alpn or "h3" result.tuic_alpn = params.alpn or "h3"
result.tuic_congestion_control = params.congestion_control or "cubic" result.tuic_congestion_control = params.congestion_control or "cubic"
result.tuic_udp_relay_mode = params.udp_relay_mode or "native" result.tuic_udp_relay_mode = params.udp_relay_mode or "native"
result.tls_allowInsecure = params.allowinsecure or params.insecure or params.allow_insecure local insecure = params.allowinsecure or params.insecure or params.allow_insecure
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0")
elseif szType == "anytls" then elseif szType == "anytls" then
if has_singbox then if has_singbox then
result.type = 'sing-box' result.type = 'sing-box'
@@ -1593,7 +1605,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
end end
end end
result.port = port result.port = port
result.tls_allowInsecure = params.allowinsecure or params.insecure local insecure = params.allowinsecure or params.insecure
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0")
end end
elseif szType == 'naive+https' or szType == 'naive+quic' then elseif szType == 'naive+https' or szType == 'naive+quic' then
if has_singbox then if has_singbox then
+1 -1
View File
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2 PKG_NAME:=luci-app-passwall2
PKG_VERSION:=26.8.7 PKG_VERSION:=26.8.7
PKG_RELEASE:=75 PKG_RELEASE:=76
PKG_PO_VERSION:=$(PKG_VERSION) PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \ PKG_CONFIG_DEPENDS:= \
@@ -171,19 +171,6 @@ node_socks_bind_local:depends({ node = "", ["!reverse"] = true })
s:tab("DNS", translate("DNS")) s:tab("DNS", translate("DNS"))
o = s:taboption("DNS", TextValue, "direct_dns_shunt", translate("Direct domain DNS routing"))
o.description = "<br /><ul>"
.. "<li>" .. translate("Subdomain (recommended): Begining with 'domain:' and the rest is a domain. When the targeting domain is exactly the value, or is a subdomain of the value, this rule takes effect. Example: rule 'domain:v2ray.com' matches 'www.v2ray.com', 'v2ray.com', but not 'xv2ray.com'.") .. "</li>"
.. "<li>" .. translate("Full domain: Begining with 'full:' and the rest is a domain. When the targeting domain is exactly the value, the rule takes effect. Example: rule 'domain:v2ray.com' matches 'v2ray.com', but not 'www.v2ray.com'.") .. "</li>"
.. "<li>" .. translate("Such as:") .. "</li>"
.. "<li>" .. "domain:my-nodes.com tcp://223.5.5.5" .. "</li>"
.. "<li>" .. "domain:vpn.com udp://119.29.29.29:53" .. "</li>"
.. "<li>" .. "full:www.dnspod.com https://120.53.53.53/dns-query" .. "</li>"
.. "<li>" .. '<a style="color:red">' .. translate("Please note that the program will not start if the format is incorrect!") .. '</a>' .. "</li>"
.. "</ul>"
o.rows = 3
o.wrap = "off"
o = s:taboption("DNS", ListValue, "direct_dns_query_strategy", translate("Direct Query Strategy")) o = s:taboption("DNS", ListValue, "direct_dns_query_strategy", translate("Direct Query Strategy"))
o.default = "UseIP" o.default = "UseIP"
o:value("UseIP") o:value("UseIP")
+3 -2
View File
@@ -5,7 +5,6 @@ nixio = require "nixio"
fs = require "nixio.fs" fs = require "nixio.fs"
sys = require "luci.sys" sys = require "luci.sys"
uci = require"luci.model.uci".cursor() uci = require"luci.model.uci".cursor()
cbi = require "luci.cbi"
util = require "luci.util" util = require "luci.util"
datatypes = require "luci.cbi.datatypes" datatypes = require "luci.cbi.datatypes"
jsonc = require "luci.jsonc" jsonc = require "luci.jsonc"
@@ -1014,7 +1013,6 @@ local default_file_tree = {
} }
function get_api_json(url) function get_api_json(url)
local jsonc = require "luci.jsonc"
local return_code, content = curl_logic(url, nil, curl_args) local return_code, content = curl_logic(url, nil, curl_args)
if return_code ~= 0 or content == "" then return {} end if return_code ~= 0 or content == "" then return {} end
return jsonc.parse(content) or {} return jsonc.parse(content) or {}
@@ -1387,6 +1385,7 @@ function set_apply_on_parse(map)
end end
function set_default_cbi() function set_default_cbi()
local cbi = require "luci.cbi"
if true then if true then
--TextValue --TextValue
local TextValue = cbi.TextValue local TextValue = cbi.TextValue
@@ -1418,6 +1417,7 @@ function set_default_cbi()
end end
function return_map(map) function return_map(map)
local cbi = require "luci.cbi"
local api = require "luci.passwall2.api" local api = require "luci.passwall2.api"
if true then if true then
-- header -- header
@@ -1438,6 +1438,7 @@ function return_map(map)
end end
function luci_types(id, m, s, type_name, option_prefix) function luci_types(id, m, s, type_name, option_prefix)
local cbi = require "luci.cbi"
local fv_type local fv_type
local field_type = s.fields["type"] local field_type = s.fields["type"]
if field_type then if field_type then
@@ -111,34 +111,6 @@ for i, v in ipairs(cipherSuites) do
end end
]]-- ]]--
function parseDNS(str)
local result_dns_server
-- [proto]://[ip]
-- [proto]://[ip]:[port]
-- https://[ip]/[path]
-- https://[ip]:[port]/[path]
local _a = api.parseURL(str)
if _a then
if _a.protocol == "tcp" or _a.protocol == "udp" or _a.protocol == "https" then
result_dns_server = {
type = _a.protocol,
server = _a.hostname
}
if _a.port then
result_dns_server.server_port = _a.port
else
if _a.protocol == "https" then
result_dns_server.server_port = 443
else
result_dns_server.server_port = 53
end
end
result_dns_server.path = _a.pathname
end
end
return result_dns_server
end
function gen_outbound(flag, node, tag, proxy_table) function gen_outbound(flag, node, tag, proxy_table)
local result = nil local result = nil
if node then if node then
@@ -2023,6 +1995,7 @@ function gen_config(var)
else default_dns_flag = "direct" else default_dns_flag = "direct"
end end
dns.final = default_dns_flag dns.final = default_dns_flag
dns.strategy = default_dns_flag == "remote" and remote_strategy or direct_strategy
-- DNS in order of shunt -- DNS in order of shunt
if dns_domain_rules and #dns_domain_rules > 0 then if dns_domain_rules and #dns_domain_rules > 0 then
@@ -2046,12 +2019,43 @@ function gen_config(var)
dns_rule.server = nil dns_rule.server = nil
end end
if value.outboundTag == "direct" then if value.outboundTag == "direct" then
dns_rule.strategy = direct_strategy local block_rule
if direct_strategy == "ipv4_only" then
block_rule = api.clone(dns_rule)
block_rule.query_type = { "AAAA" }
elseif direct_strategy == "ipv6_only" then
block_rule = api.clone(dns_rule)
block_rule.query_type = { "A" }
end
if block_rule then
block_rule.action = "predefined"
block_rule.rcode = "NOERROR"
block_rule.disable_cache = nil
block_rule.server = nil
table.insert(dns.rules, block_rule)
end
end end
if value.outboundTag ~= "block" and value.outboundTag ~= "direct" then if value.outboundTag ~= "block" and value.outboundTag ~= "direct" then
dns_rule.server = "remote" dns_rule.server = "remote"
dns_rule.rewrite_ttl = 30 dns_rule.rewrite_ttl = 30
dns_rule.strategy = remote_strategy if true then
local block_rule
if remote_strategy == "ipv4_only" then
block_rule = api.clone(dns_rule)
block_rule.query_type = { "AAAA" }
elseif remote_strategy == "ipv6_only" then
block_rule = api.clone(dns_rule)
block_rule.query_type = { "A" }
end
if block_rule then
block_rule.action = "predefined"
block_rule.rcode = "NOERROR"
block_rule.disable_cache = nil
block_rule.server = nil
block_rule.rewrite_ttl = nil
table.insert(dns.rules, block_rule)
end
end
dns_rule.client_subnet = remote_dns_client_ip dns_rule.client_subnet = remote_dns_client_ip
if value.outboundTag ~= COMMON.default_outbound_tag and remote_server.server and remote_dns_detour ~= "direct" then if value.outboundTag ~= COMMON.default_outbound_tag and remote_server.server and remote_dns_detour ~= "direct" then
local remote_dns_server = api.clone(remote_server) local remote_dns_server = api.clone(remote_server)
@@ -2062,9 +2066,13 @@ function gen_config(var)
end end
if value.fakedns then if value.fakedns then
local fakedns_dns_rule = api.clone(dns_rule) local fakedns_dns_rule = api.clone(dns_rule)
fakedns_dns_rule.query_type = { if remote_strategy == "ipv4_only" then
"A", "AAAA" fakedns_dns_rule.query_type = { "A" }
} elseif remote_strategy == "ipv6_only" then
fakedns_dns_rule.query_type = { "AAAA" }
else
fakedns_dns_rule.query_type = { "A", "AAAA" }
end
fakedns_dns_rule.server = fakedns_tag fakedns_dns_rule.server = fakedns_tag
fakedns_dns_rule.disable_cache = true fakedns_dns_rule.disable_cache = true
fakedns_dns_rule.client_subnet = nil fakedns_dns_rule.client_subnet = nil
@@ -2076,23 +2084,26 @@ function gen_config(var)
end end
end end
if default_dns_flag == "remote" then if default_dns_flag == "remote" then
local dns_rule_query_type = { "A", "AAAA" }
if remote_strategy == "ipv4_only" then
dns_rule_query_type = { "A" }
elseif remote_strategy == "ipv6_only" then
dns_rule_query_type = { "AAAA" }
end
if remote_dns_fake then if remote_dns_fake then
-- When default is not direct and enable fakedns, default DNS use FakeDNS. -- When default is not direct and enable fakedns, default DNS use FakeDNS.
local fakedns_dns_rule = { local fakedns_dns_rule = {
query_type = { query_type = dns_rule_query_type,
"A", "AAAA"
},
server = fakedns_tag, server = fakedns_tag,
disable_cache = true, disable_cache = true,
rewrite_ttl = 30, rewrite_ttl = 30
strategy = remote_strategy,
} }
table.insert(dns.rules, fakedns_dns_rule) table.insert(dns.rules, fakedns_dns_rule)
else else
local remote_dns_rule = { local remote_dns_rule = {
query_type = dns_rule_query_type,
server = "remote", server = "remote",
disable_cache = true, disable_cache = true,
strategy = remote_strategy,
} }
table.insert(dns.rules, remote_dns_rule) table.insert(dns.rules, remote_dns_rule)
end end
@@ -2328,156 +2339,7 @@ function gen_proto_config(var)
return jsonc.stringify(config, 1) return jsonc.stringify(config, 1)
end end
function gen_front_dns_config(var)
local dns_listen_port = var["dns_listen_port"]
local direct_dns_udp_server = var["direct_dns_udp_server"]
local direct_dns_udp_port = var["direct_dns_udp_port"]
local direct_dns_query_strategy = var["direct_dns_query_strategy"]
local default_dns_udp_server = var["default_dns_udp_server"]
local default_dns_udp_port = var["default_dns_udp_port"]
local dns = {
servers = {},
rules = {}
}
local inbounds = {}
local outbounds = {}
local route = {}
local direct_strategy = "prefer_ipv6"
if direct_dns_query_strategy == "UseIPv4" then
direct_strategy = "ipv4_only"
elseif direct_dns_query_strategy == "UseIPv6" then
direct_strategy = "ipv6_only"
end
table.insert(outbounds, {
type = "direct",
tag = "direct",
routing_mark = 255,
})
local direct_dns_shunt = uci:get(appname, "@global[0]", "direct_dns_shunt") or ""
if #direct_dns_shunt > 0 then
local dns_server = {}
string.gsub(direct_dns_shunt, '[^' .. "\r\n" .. ']+', function(w)
if w:find("#") == 1 then return end
local domain = sys.exec(string.format("echo -n $(echo %s | awk -F ' ' '{print $1}')", w))
local dns = sys.exec(string.format("echo -n $(echo %s | awk -F ' ' '{print $2}')", w))
if domain ~= "" and dns ~= "" then
local new_dns_server = parseDNS(dns)
if new_dns_server then
if not dns_server[dns] then
dns_server[dns] = {}
end
if not dns_server[dns].server then
dns_server[dns].server = new_dns_server
dns_server[dns].server.tag = dns
dns_server[dns].server.detour = "direct"
end
if not dns_server[dns].rule then
dns_server[dns].rule = {
action = "route",
server = dns,
domain = {},
domain_suffix = {},
domain_keyword = {}
}
end
if domain:find("full:") == 1 then
table.insert(dns_server[dns].rule.domain, domain:sub(1 + #"full:"))
elseif domain:find("domain:") == 1 then
table.insert(dns_server[dns].rule.domain_suffix, domain:sub(1 + #"domain:"))
else
table.insert(dns_server[dns].rule.domain_keyword, domain)
end
end
end
end)
for k, v in pairs(dns_server) do
table.insert(dns.servers, v.server)
if #v.rule.domain == 0 then v.rule.domain = nil end
if #v.rule.domain_suffix == 0 then v.rule.domain_suffix = nil end
if #v.rule.domain_keyword == 0 then v.rule.domain_keyword = nil end
table.insert(dns.rules, v.rule)
end
end
if direct_dns_udp_server then
table.insert(dns.servers, {
tag = "direct",
type = "udp",
server = direct_dns_udp_server,
server_port = tonumber(direct_dns_udp_port) or 53,
detour = "direct"
})
local node_domain = {}
local nodes_domain_text = sys.exec('uci show passwall2 | grep ".address=" | cut -d "\'" -f 2 | grep "[a-zA-Z]$" | sort -u')
string.gsub(nodes_domain_text, '[^' .. "\r\n" .. ']+', function(w)
w = (w or ""):lower()
table.insert(node_domain, w)
end)
if #node_domain > 0 then
table.insert(dns.rules, {
action = "route",
server = "direct",
domain = node_domain
})
end
route.default_domain_resolver = {
server = "direct",
strategy = direct_strategy
}
end
if default_dns_udp_server then
table.insert(dns.servers, {
tag = "default",
type = "udp",
server = default_dns_udp_server,
server_port = tonumber(default_dns_udp_port) or 53,
detour = "direct"
})
dns.final = "default"
else
dns.final = "direct"
end
local dns_in_inbound = {
type = "direct",
tag = "dns-in",
listen = "127.0.0.1",
listen_port = tonumber(dns_listen_port),
}
table.insert(inbounds, dns_in_inbound)
route.rules = {}
table.insert(route.rules, {
action = "hijack-dns",
inbound = dns_in_inbound.tag
})
table.insert(route.rules, {
action = "sniff",
inbound = dns_in_inbound.tag
})
route.final = "direct"
local config = {
log = {
disabled = true,
level = "debug",
timestamp = true,
},
dns = dns,
inbounds = inbounds,
outbounds = outbounds,
route = route
}
return jsonc.stringify(config, 1)
end
_G.gen_config = gen_config _G.gen_config = gen_config
_G.gen_front_dns_config = gen_front_dns_config
_G.gen_proto_config = gen_proto_config _G.gen_proto_config = gen_proto_config
_G.geo_convert_srs = geo_convert_srs _G.geo_convert_srs = geo_convert_srs
@@ -51,35 +51,6 @@ for i, v in ipairs(cipherSuites) do
end end
]]-- ]]--
function parseDNS(str)
local result_dns_server
-- [proto]://[ip]
-- [proto]://[ip]:[port]
-- https://[ip]/[path]
-- https://[ip]:[port]/[path]
local _a = api.parseURL(str)
if _a then
if _a.protocol == "tcp" or _a.protocol == "udp" or _a.protocol == "https" then
result_dns_server = {
address = str
}
if _a.protocol == "udp" then
result_dns_server.address = _a.hostname
end
if _a.port then
result_dns_server.port = _a.port
else
if _a.protocol == "https" then
result_dns_server.port = 443
else
result_dns_server.port = 53
end
end
end
end
return result_dns_server
end
function gen_outbound(flag, node, tag, proxy_table) function gen_outbound(flag, node, tag, proxy_table)
local result = nil local result = nil
if node then if node then
@@ -2186,157 +2157,7 @@ function gen_proto_config(var)
return jsonc.stringify(config, 1) return jsonc.stringify(config, 1)
end end
function gen_front_dns_config(var)
local dns_listen_port = var["dns_listen_port"]
local direct_dns_udp_server = var["direct_dns_udp_server"]
local direct_dns_udp_port = var["direct_dns_udp_port"]
local default_dns_udp_server = var["default_dns_udp_server"]
local default_dns_udp_port = var["default_dns_udp_port"]
local queryStrategy = "UseIP"
local dns = {
tag = "dns-global-direct",
disableCache = false,
disableFallback = true,
disableFallbackIfMatch = true,
queryStrategy = queryStrategy,
servers = {}
}
local inbounds = {}
local outbounds = {}
local routing = {
rules = {}
}
table.insert(outbounds, {
tag = "direct",
protocol = "freedom",
settings = {
domainStrategy = queryStrategy
},
streamSettings = {
sockopt = {
mark = 255
}
}
})
if default_dns_udp_server then
table.insert(dns.servers, {
tag = "default",
address = default_dns_udp_server,
port = tonumber(default_dns_udp_port) or 53,
queryStrategy = queryStrategy,
})
end
local direct_dns_shunt = uci:get(appname, "@global[0]", "direct_dns_shunt") or ""
if #direct_dns_shunt > 0 then
local dns_server = {}
string.gsub(direct_dns_shunt, '[^' .. "\r\n" .. ']+', function(w)
if w:find("#") == 1 then return end
local domain = sys.exec(string.format("echo -n $(echo %s | awk -F ' ' '{print $1}')", w))
local dns = sys.exec(string.format("echo -n $(echo %s | awk -F ' ' '{print $2}')", w))
if domain ~= "" and dns ~= "" then
local new_dns_server = parseDNS(dns)
if new_dns_server then
if not dns_server[dns] then
dns_server[dns] = {}
end
dns_server[dns].tag = dns
dns_server[dns].queryStrategy = queryStrategy
dns_server[dns].address = new_dns_server.address
dns_server[dns].port = new_dns_server.port
dns_server[dns].finalQuery = true
if not dns_server[dns].domains then
dns_server[dns].domains = {}
end
table.insert(dns_server[dns].domains, domain)
end
end
end)
for k, v in pairs(dns_server) do
table.insert(dns.servers, v)
table.insert(routing.rules, {
inboundTag = {
v.tag
},
outboundTag = "direct"
})
end
end
if direct_dns_udp_server then
local node_domain = {}
local nodes_domain_text = sys.exec('uci show passwall2 | grep ".address=" | cut -d "\'" -f 2 | grep "[a-zA-Z]$" | sort -u')
string.gsub(nodes_domain_text, '[^' .. "\r\n" .. ']+', function(w)
w = (w or ""):lower()
table.insert(node_domain, "full:" .. w)
end)
if #node_domain > 0 then
table.insert(dns.servers, {
tag = "dns-in-vpslist",
address = direct_dns_udp_server,
port = tonumber(direct_dns_udp_port) or 53,
queryStrategy = queryStrategy,
domains = node_domain,
finalQuery = true,
disableCache = false,
serveStale = true,
})
end
end
table.insert(inbounds, {
tag = "dns-in",
listen = "127.0.0.1",
port = tonumber(dns_listen_port),
protocol = "dokodemo-door",
settings = {
address = "0.0.0.0",
network = "tcp,udp"
}
})
table.insert(outbounds, {
tag = "dns-out",
protocol = "dns",
proxySettings = {
tag = "direct"
},
settings = {
address = direct_dns_udp_server,
port = tonumber(direct_dns_udp_port) or 53,
network = "udp",
nonIPQuery = "skip",
blockTypes = {
65
}
}
})
table.insert(routing.rules, {
inboundTag = {
"dns-in"
},
outboundTag = "dns-out"
})
local config = {
log = {
dnsLog = true,
loglevel = "debug"
},
dns = dns,
inbounds = inbounds,
outbounds = outbounds,
routing = routing
}
return jsonc.stringify(config, 1)
end
_G.gen_config = gen_config _G.gen_config = gen_config
_G.gen_front_dns_config = gen_front_dns_config
_G.gen_proto_config = gen_proto_config _G.gen_proto_config = gen_proto_config
if arg[1] then if arg[1] then
-6
View File
@@ -121,12 +121,6 @@ msgstr "0 به معنای عدم استفاده است"
msgid "Current node: %s" msgid "Current node: %s"
msgstr "گره فعلی: %s" msgstr "گره فعلی: %s"
msgid "Direct domain DNS routing"
msgstr "مسیریابی مستقیم DNS دامنه"
msgid "Please note that the program will not start if the format is incorrect!"
msgstr "لطفا توجه داشته باشید که اگر قالب نادرست باشد، برنامه شروع نخواهد شد!"
msgid "IP:Port mode acceptable, multi value split with english comma." msgid "IP:Port mode acceptable, multi value split with english comma."
msgstr "حالت IP:Port قابل قبول است، مقادیر متعدد را با کاما انگلیسی جدا کنید." msgstr "حالت IP:Port قابل قبول است، مقادیر متعدد را با کاما انگلیسی جدا کنید."
-6
View File
@@ -118,12 +118,6 @@ msgstr "0 — отключить функцию"
msgid "Current node: %s" msgid "Current node: %s"
msgstr "Текущий узел: %s" msgstr "Текущий узел: %s"
msgid "Direct domain DNS routing"
msgstr "Прямая маршрутизация DNS домена"
msgid "Please note that the program will not start if the format is incorrect!"
msgstr "Обратите внимание, что программа не запустится, если формат указан неверно!"
msgid "IP:Port mode acceptable, multi value split with english comma." msgid "IP:Port mode acceptable, multi value split with english comma."
msgstr "Допустим формат IP:Port. Несколько значений указывайте через запятую." msgstr "Допустим формат IP:Port. Несколько значений указывайте через запятую."
-6
View File
@@ -118,12 +118,6 @@ msgstr "0为不使用"
msgid "Current node: %s" msgid "Current node: %s"
msgstr "当前节点:%s" msgstr "当前节点:%s"
msgid "Direct domain DNS routing"
msgstr "直连域名 DNS 分流"
msgid "Please note that the program will not start if the format is incorrect!"
msgstr "请注意,格式不正确将无法启动!"
msgid "IP:Port mode acceptable, multi value split with english comma." msgid "IP:Port mode acceptable, multi value split with english comma."
msgstr "接受 IP:Port 形式的输入,多个以英文逗号分隔。" msgstr "接受 IP:Port 形式的输入,多个以英文逗号分隔。"
-6
View File
@@ -118,12 +118,6 @@ msgstr "0為不使用"
msgid "Current node: %s" msgid "Current node: %s"
msgstr "當前節點:%s" msgstr "當前節點:%s"
msgid "Direct domain DNS routing"
msgstr "直連網域 DNS 分流"
msgid "Please note that the program will not start if the format is incorrect!"
msgstr "請注意,格式不正確將無法啟動!"
msgid "IP:Port mode acceptable, multi value split with english comma." msgid "IP:Port mode acceptable, multi value split with english comma."
msgstr "接受 IP:Port 形式的輸入,多個以英文逗号分隔。" msgstr "接受 IP:Port 形式的輸入,多個以英文逗号分隔。"
@@ -655,58 +655,13 @@ run_global() {
set_cache_var "ACL_GLOBAL_redir_port" "$REDIR_PORT" set_cache_var "ACL_GLOBAL_redir_port" "$REDIR_PORT"
} }
run_front_dns() {
local switch=0
direct_dns_shunt=$(config_t_get global direct_dns_shunt)
direct_dns_shunt=$(echo "${direct_dns_shunt}" | grep -v "^#")
[ -n "${direct_dns_shunt}" ] && switch=1
[ "${switch}" == "1" ] && {
local config_file="${TMP_PATH}/direct_dns.json"
local log_file="${TMP_PATH}/direct_dns.log"
log_file="/dev/null"
local listen_port=$(get_new_port 10553)
json_init
json_add_string "dns_listen_port" "${listen_port}"
json_add_string "direct_dns_udp_server" "${DIRECT_DNS_UDP_SERVER}"
json_add_string "direct_dns_udp_port" "${DIRECT_DNS_UDP_PORT}"
json_add_string "direct_dns_query_strategy" "${DIRECT_DNS_QUERY_STRATEGY}"
[ -n "${ACL_GLOBAL_node}" ] && [ -n "${TUN_DNS_PORT}" ] && {
json_add_string "default_dns_udp_server" "127.0.0.1"
json_add_string "default_dns_udp_port" "${TUN_DNS_PORT}"
}
local _json_arg="$(json_dump)"
local prefer_core=""
[ -n "${XRAY_BIN}" ] && prefer_core="xray"
[ -n "${SINGBOX_BIN}" ] && prefer_core="sing-box"
if [ "${prefer_core}" = "xray" ]; then
lua $UTIL_XRAY gen_front_dns_config "${_json_arg}" > $config_file
ln_run 0 "$XRAY_BIN" "xray" "${log_file}" run -c "$config_file"
elif [ "${prefer_core}" = "sing-box" ]; then
lua $UTIL_SINGBOX gen_front_dns_config "${_json_arg}" > $config_file
ln_run 0 "$SINGBOX_BIN" "sing-box" "${log_file}" run -c "$config_file"
else
return 1
fi
FRONT_DNS_SERVER="127.0.0.1"
FRONT_DNS_PORT="${listen_port}"
}
}
run_global_dnsmasq() { run_global_dnsmasq() {
[ -z "${ACL_GLOBAL_node}" ] && [ -z "${FRONT_DNS_PORT}" ] && return [ -z "${ACL_GLOBAL_node}" ] && return
local RUN_NEW_DNSMASQ=1 local RUN_NEW_DNSMASQ=1
RUN_NEW_DNSMASQ=${DNS_REDIRECT} RUN_NEW_DNSMASQ=${DNS_REDIRECT}
DNSMASQ_DEFAULT_DNS="${AUTO_DNS}" DNSMASQ_DEFAULT_DNS="${AUTO_DNS}"
DNSMASQ_LOCAL_DNS="${LOCAL_DNS:-${AUTO_DNS}}" DNSMASQ_LOCAL_DNS="${LOCAL_DNS:-${AUTO_DNS}}"
DNSMASQ_TUN_DNS="${TUN_DNS}" DNSMASQ_TUN_DNS="${TUN_DNS}"
[ -n "${FRONT_DNS_PORT}" ] && {
DNSMASQ_DEFAULT_DNS="${FRONT_DNS_SERVER}#${FRONT_DNS_PORT}"
DNSMASQ_LOCAL_DNS="${DNSMASQ_DEFAULT_DNS}"
DNSMASQ_TUN_DNS="${DNSMASQ_DEFAULT_DNS}"
}
if [ "${RUN_NEW_DNSMASQ}" == "0" ]; then if [ "${RUN_NEW_DNSMASQ}" == "0" ]; then
#The old logic will be removed in the future. #The old logic will be removed in the future.
#Run a copy dnsmasq instance, DNS hijack that don't need a proxy devices. #Run a copy dnsmasq instance, DNS hijack that don't need a proxy devices.
@@ -1194,7 +1149,6 @@ start() {
fi fi
mkdir -p ${GLOBAL_ACL_PATH} mkdir -p ${GLOBAL_ACL_PATH}
[ "$ENABLED_DEFAULT_ACL" == 1 ] && run_global [ "$ENABLED_DEFAULT_ACL" == 1 ] && run_global
run_front_dns
run_global_dnsmasq run_global_dnsmasq
[ -n "$USE_TABLES" ] && source $APP_PATH/${USE_TABLES}.sh start [ -n "$USE_TABLES" ] && source $APP_PATH/${USE_TABLES}.sh start
set_cache_var "USE_TABLES" "$USE_TABLES" set_cache_var "USE_TABLES" "$USE_TABLES"
+1 -1
View File
@@ -17,7 +17,7 @@ LUCI_NAME:=luci-theme-footstrap
FOOTSTRAP_VERSION?= FOOTSTRAP_VERSION?=
ifneq ($(FOOTSTRAP_VERSION),) ifneq ($(FOOTSTRAP_VERSION),)
PKG_VERSION:=$(FOOTSTRAP_VERSION) PKG_VERSION:=$(FOOTSTRAP_VERSION)
PKG_RELEASE:=9 PKG_RELEASE:=10
endif endif
LUCI_TITLE:=Footstrap Theme LUCI_TITLE:=Footstrap Theme
@@ -381,6 +381,22 @@ function seed() {
adoptEntry(); adoptEntry();
} }
/* Does this document already carry the stylesheet a menu.d node names?
*
* The value is a path under /luci-static/resources (`view/foo/foo.css`), and head.ut prints it with
* a `?v=` cache key, so compare the PATH only and by suffix — the theme does not get to assume the
* resource base, and a re-hosted sheet keeps its element and its href (fs-sheets.js disables the
* <link>, it never removes it), which is exactly the "already here" this asks about. */
function documentHasSheet(css) {
const want = '/' + css.replace(/^\/+/, '');
for (const link of document.querySelectorAll('link[rel~="stylesheet"][href]')) {
const href = (link.getAttribute('href') || '').split('?')[0];
if (href.endsWith(want))
return true;
}
return false;
}
/* Attempt an in-place navigation to `pathname`. Returns true if handled as a /* Attempt an in-place navigation to `pathname`. Returns true if handled as a
* SPA nav (caller should preventDefault), false to let the browser do a normal * SPA nav (caller should preventDefault), false to let the browser do a normal
* full navigation. `push` adds a history entry (false when replaying popstate). * full navigation. `push` adds a history entry (false when replaying popstate).
@@ -402,6 +418,30 @@ function navigate(pathname, push, kbd) {
const className = tree.viewClassFor(node); const className = tree.viewClassFor(node);
if (!className) if (!className)
return false; return false;
/* A PAGE WHOSE STYLESHEET ONLY THE SERVER CAN EMIT IS NOT OURS TO SWAP INTO.
*
* A menu.d node may name its own sheet (`"css": "view/foo/foo.css"`), and the server links it
* from <head> on a full load (partials/head.ut). Nothing here can: a swap replaces #view's
* children, it does not re-render a document, so reaching such a page by CLICK would show it
* with the app's CSS missing — while reaching the same page by URL or F5 showed it styled. One
* page, two appearances, decided by how the user got there.
*
* So decline, exactly as the poisoned-document bail above does: speed is traded for
* correctness, never the other way. It costs ONE full load per such page — after it the <link>
* is in the document, this test passes, and every later visit is a swap again (fs-sheets.js
* owns the sheet from then on and re-lights it per page).
*
* Injecting the <link> here instead would work and is deliberately not done: it would put the
* theme in charge of fetching and ordering a foreign stylesheet, which is the job fs-sheets.js
* exists to keep out of the theme. The server already does it correctly.
*
* `node.css` reaches the client because /admin/menu serves the dispatcher's own tree and
* ui.js's scrubMenu() only rewrites `satisfied`. On a luci-base that predates the `css` schema
* entry the property is dropped server-side, so this is simply never true there. */
if (typeof node.css === 'string' && node.css !== '' && !documentHasSheet(node.css))
return false;
const rsegs = res.segs; const rsegs = res.segs;
/* from here on the navigation is committed */ /* from here on the navigation is committed */
+28 -15
View File
@@ -15,21 +15,26 @@
* cutting in half. The fields shrink instead of forcing that: `min-width: 0` undoes the field * cutting in half. The fields shrink instead of forcing that: `min-width: 0` undoes the field
* box in theme/60-inputs.css for this row only. * box in theme/60-inputs.css for this row only.
* *
* Keyed on the controls' OWN ids rather than on the page: `data-page` differs between the system * Keyed on the ROW's SHAPE, not on the page and not on the controls' ids. `data-page` differs
* and the kernel log, and a third-party LogreadBox has neither, while ui.js gives these two rows * between the system and the kernel log and a third-party LogreadBox has neither — but the ids
* the same ids wherever the widget is rendered. The inline `margin: 0 5px` LuCI writes on the * are no better: only the System Log is built by `tools/views.js`, and Status → Kernel Log is a
* labels stays as the horizontal spacing — only the ROW gap is ours, so nothing here has to * view of its own (`view/status/dmesg.js`) whose four rows carry `logFromTime`, `logToTime`,
* fight an inline style. */ * `invertLogRangeTime`, `invertSeverity` and `invertAscendingSort`, of which an id list written
div:has(> #logFacilitySelect), * against LogreadBox catches none — `logFacilitySelect` appears there only as a `for=`, on a
div:has(> #logTextFilter) { * label whose control is a time field. Both views wrap their rows in `#content_syslog`, and a
* filter row is exactly one that opens with a `<label>`; the scroll-to-end button's row and the
* log itself do not. That shape holds for any view built the same way.
*
* The inline `margin: 0 5px` LuCI writes on the labels stays as the horizontal spacing — only
* the ROW gap is ours, so nothing here has to fight an inline style. */
#content_syslog > div:has(> label) {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center; align-items: center;
row-gap: var(--fs-space-2); row-gap: var(--fs-space-2);
} }
div:has(> #logFacilitySelect) > label, #content_syslog > div:has(> label) > label { white-space: nowrap; }
div:has(> #logTextFilter) > label { white-space: nowrap; } #content_syslog > div:has(> label) > :is(select, input) {
#logFacilitySelect, #logSeveritySelect, #logTextFilter, #logMaxRows {
flex: 1 1 auto; flex: 1 1 auto;
/* both halves are needed and they answer different layouts: `min-width: 0` lets a FLEX item /* both halves are needed and they answer different layouts: `min-width: 0` lets a FLEX item
* shrink past its content, `max-width: 100%` clamps a GRID item to its track. A <select> * shrink past its content, `max-width: 100%` clamps a GRID item to its track. A <select>
@@ -38,6 +43,8 @@
min-width: 0; min-width: 0;
max-width: 100%; max-width: 100%;
} }
/* a checkbox is not a field: left to its own 16px, it would otherwise flex to fill the line. */
#content_syslog > div:has(> label) > input[type="checkbox"] { flex: 0 0 auto; }
/* the two numeric-ish fields keep a sane ceiling: a max-rows box as wide as the filter reads as /* the two numeric-ish fields keep a sane ceiling: a max-rows box as wide as the filter reads as
* a second search field. */ * a second search field. */
#logMaxRows { flex-basis: 6ch; max-width: 12ch; } #logMaxRows { flex-basis: 6ch; max-width: 12ch; }
@@ -47,12 +54,18 @@
* first row is a fixed alternation of exactly two filters — invert label, checkbox, name label, * first row is a fixed alternation of exactly two filters — invert label, checkbox, name label,
* control, twice — so a four-column grid puts one filter on each line. * control, twice — so a four-column grid puts one filter on each line.
* *
* The SECOND row is deliberately left to the wrapping above. It holds two filters of different * EVERY OTHER ROW is deliberately left to the wrapping above, because none of them is that
* shapes (a checkbox filter and a bare `Макс. строк:` pair), so the same four tracks would be * shape. The System Log's second row holds a checkbox filter beside a bare `Макс. строк:` pair,
* sized by items that are not each other's counterparts: measured, the max-rows box defined * and the same four tracks are then sized by items that are not each other's counterparts:
* column 2 and pushed `содержит:` and its field off the card. Wrapping puts that row's two * measured, the max-rows box defined column 2 and pushed `содержит:` and its field off the card.
* filters on two lines by itself, which is all the grid was for. */ * The Kernel Log's rows are three different shapes again — a range with two time fields, a
* severity select with a trailing `and above`, and a lone sort checkbox. Wrapping puts each of
* those on as many lines as it needs, which is all the grid was ever for; the grid is worth its
* one selector only where the alternation is exact. */
@container fs-view (max-width: 560px) { @container fs-view (max-width: 560px) {
/* the id alone, without `#content_syslog >` in front of it: two ids in one selector is
* [2,0,1], past the [1,7,0] ceiling `npm run css-metrics` holds the sheet to, and the row is
* already pinned down by the only id LuCI puts on that select. */
div:has(> #logFacilitySelect) { div:has(> #logFacilitySelect) {
display: grid; display: grid;
grid-template-columns: auto auto auto minmax(0, 1fr); grid-template-columns: auto auto auto minmax(0, 1fr);
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=modeminfo PKG_NAME:=modeminfo
PKG_VERSION:=0.4.7 PKG_VERSION:=0.4.8
PKG_RELEASE:=9 PKG_RELEASE:=10
PKG_MAINTAINER:=Konstantine Shevlakov <shevlakov@132lan.ru> PKG_MAINTAINER:=Konstantine Shevlakov <shevlakov@132lan.ru>
include $(INCLUDE_DIR)/package.mk include $(INCLUDE_DIR)/package.mk
@@ -42,6 +42,9 @@
# Telit LN940 LT4220 # Telit LN940 LT4220
1bc71900;QUALCOMM 1bc71900;QUALCOMM
1bc71901;QUALCOMM 1bc71901;QUALCOMM
# Telit LM960
1bc71040;QUALCOMM_LM960
1bc71041;QUALCOMM_LM960
# Yuge CLM920 # Yuge CLM920
12864e3c;YUGE 12864e3c;YUGE
# ThinkWill ML7820 # ThinkWill ML7820
@@ -0,0 +1,73 @@
# Qualcomm Modems (FoxConn T77W678, Telit LN940, HP LT4220)
function modem_data(){
generic_data
# hwinfo and siminfo
FAMILY_EX="Telit"
OIFS="$IFS"; IFS="|"
set -- $(echo "$O" | awk -v fam="$FAMILY_EX" '
($0 ~ fam){manuf =$0; getline model; getline fw}
/ICCID:/{split($0,i,":");gsub("\r",""); iccid=i[2]; getline imsi; getline imei}
/TSENS2/{split($0,i,",");temp=i[2]}
END{print manuf "|" model "|" fw "|" iccid "|" imsi "|" imei "|" temp}
')
MANUF=${1}; MODEL=${2}; FW=${3}; ICCID=${4}; IMSI=${5} IMEI=${6}; CHIPTEMP=${7}
IFS="$OIFS"; unset OIFS
DEVICE="$MANUF $MODEL"
OIFS="$IFS"; IFS="|"
# signal
set -- $(echo "$O" | awk -v mode="$MODE" '
BEGIN { map[1]=3; map[2]=5; map[3]=10; map[4]=15; map[5]=20 }
mode ~ /LTE/ { # LTE mode
if (/\+CEREG/){gsub("\"",""); split($0,i,","); reg=i[2]; lac=i[3]; cid=i[4]}
if (/CAINFO:/){ split($0,i,","); earfcn=i[2]; rssi=sprintf("%.0f",i[6]); rsrp=sprintf("%.0f",i[5]);
sinr=sprintf("%.0f",i[8]/5-20); rsrq=sprintf("%.0f",i[7]); pci=i[4]; bw=sprintf("%.0f",i[3]);
lte_ca=i[15]; bwc=map[bw]
}
if (/PCC info/){bwc=sprintf("%.0f",$(NF-1)); bw=map[bwc]}
cell = sprintf("%d", "0x" substr(cid, length(cid) - 1, 2))
enbid = sprintf("%d", "0x" substr(cid, 1, length(cid) - 2))
}
mode !~ /LTE/ { # 3G mode
if (/\+CREG/){gsub("\"",""); split($0,i,","); reg=i[2]; lac=i[3]; cid=i[4]}
if (/RFSTS:/){ split($0,i,","); earfcn=i[2]; rssi=sprintf("%.0f",i[6]); sinr=sprintf("%.0f",i[4])}
}
END { print reg "|" earfcn "|" lac "|" cid "|" rssi "|" sinr "|" rsrp "|" rsrq "|" pci "|" bw "|" bwc "|" lte_ca "|" enbid "|" cell}
')
EARFCN=${2}; LAC=${3}; CID=${4}; CSQ_RSSI=${5}; SINR=${6}; RSRP=${7}; RSRQ=${8}; PCI=${9}; BWDL=${10}; BWDx=${11}; LTE_CA=${12}; ENBID=${13}; CELL=${14}
IFS="$OIFS"; unset OIFS
# LTE CA calc
if [ $LTE_CA -ne 0 ]; then
OIFS="$IFS"; IFS="|"
set -- $(echo "$O" | awk -F"," -v bwc=${BWDx:=0} -v mode=$MODE '
BEGIN { map[1]=3; map[2]=5; map[3]=10; map[4]=15; map[5]=20 }
function earfcn_to_band(channel) {
if (channel <= 1) return ""
cmd = "/usr/share/modeminfo/scripts/ch_to_band " mode " " channel
cmd | getline band
close(cmd)
return band
}
/CAINFO:/{
ch[1]=14; ch[2]=25; ch[3]=36; ch[4]=47
bw[1]=15; bw[2]=26; bw[3]=37; bw[4]=48
scc = ""; bwcx = 0
for(i=1;i<=4;i++) {
if($ch[i]!=0) {
scc=scc"+"earfcn_to_band($ch[i])
bwcx=map[$bw[i]]
bwca+=bwcx
}
}
bwca=bwca+bwc
print scc"|"bwca
}
')
SCC=${1}; BWCA=${2}
IFS="$OIFS"; unset OIFS BWDx
fi
if [ $(uci -q get modeminfo.@general[0].decimail) = "1" ]; then
LAC=$(printf %d 0x$LAC)
CID=$(printf %d 0x$CID)
fi
}
@@ -0,0 +1,10 @@
ATE0
AT+COPS=3,0; +COPS?
AT+CREG=2; +CREG?
AT+CGREG=2; +CGREG?
AT+CEREG=2; +CEREG?
AT+CSQ
AT#RFSTS
AT#CAINFO?
AT+CGMI; +CGMM; +CGMR; +ICCID; +CIMI; +CGSN
AT#TEMPSENS=2
+2 -2
View File
@@ -10,12 +10,12 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=natflow PKG_NAME:=natflow
PKG_VERSION:=20260531 PKG_VERSION:=20260531
PKG_RELEASE:=62 PKG_RELEASE:=63
PKG_SOURCE:=$(PKG_VERSION).tar.xz PKG_SOURCE:=$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git
PKG_SOURCE_PROTO:=git PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=00be1cea6bcdaf0d8e79b62dff533f08f49863e8 PKG_SOURCE_VERSION:=a2e7cbafc787ba9a0e86550bd3f4d03207fb9678
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_MAINTAINER:=Chen Minqiang <ptpt52@gmail.com> PKG_MAINTAINER:=Chen Minqiang <ptpt52@gmail.com>
PKG_LICENSE:=GPL-2.0 PKG_LICENSE:=GPL-2.0