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

This commit is contained in:
github-actions[bot]
2026-08-10 20:58:00 +08:00
parent 2f0ec626c4
commit 6ceff0781d
37 changed files with 318 additions and 551 deletions
+2 -2
View File
@@ -6,9 +6,9 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=dae
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_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_HASH:=skip
+2 -2
View File
@@ -6,9 +6,9 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=daed
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_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_HASH:=skip
@@ -1048,6 +1048,15 @@ return view.extend({
so.depends({type: /^(zerotier|wireguard|masque|openvpn)$/});
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.default = hm.congestion_controller[0][0];
hm.congestion_controller.forEach((res) => {
@@ -1055,7 +1064,6 @@ return view.extend({
})
so.depends({type: /^(tuic|shadowquic|trusttunnel)$/});
so.depends({type: 'masque', masque_network: /^(|h3-l4proxy)$/});
so.depends({ipstack: /^(auto|mips)$/}); // not empty not gvisor
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'bbr_profile', _('BBR profile'));
@@ -171,6 +171,14 @@ migrate() {
uci_remove "$CONF" "$1" zerotier_ipstack
uci_set "$CONF" "$1" ipstack "$zerotier_ipstack"
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
@@ -678,12 +678,12 @@ uci.foreach(uciconf, ucinode, (cfg) => {
/* Extra fields */
"ip-stack": cfg.ipstack ? {
mode: cfg.ipstack,
"congestion-controller": replace(cfg.congestion_controller, 'new_reno', 'reno')
"congestion-controller": cfg.ipstack_congestion_controller
} : null,
"udp-over-stream": strToBool(cfg.shadowquic_udp_over_stream || cfg.tuic_udp_over_stream),
"heartbeat-interval": strToInt(cfg.tuic_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,
"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
PKG_LICENSE:=GPLv3
PKG_VERSION:=0.4.8
PKG_RELEASE:=11
PKG_RELEASE:=12
include $(TOPDIR)/feeds/luci/luci.mk
+2 -2
View File
@@ -16,7 +16,7 @@ Supported devices:
- Sierra Wireless EM7455/EM9191
- HP LT4220
- Telit LN940(HP LT4220)/LM960
- Dell DW5821e/DW5829e
@@ -43,7 +43,7 @@ Supported devices:
|modeminfo |common files |
|modeminfo-qmi |Qualcomm MSM Interface 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-sierra |Sierra EM7455/EM9191 modem 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_VERSION:=26.8.1
PKG_RELEASE:=211
PKG_RELEASE:=212
PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \
@@ -49,18 +49,6 @@ m.uci:foreach(appname, "socks", function(s)
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 ]]--
s = m:section(NamedSection, cfgid, translate("ACLs"), translate("ACLs"))
s.addremove = false
@@ -173,7 +161,6 @@ sources.validate = function(self, value, t)
return value
end
sources.write = dynamicList_write
o = s:option(ListValue, "mode", translate("Mode"))
o:value("0", translate("No Proxy"))
@@ -372,15 +372,6 @@ if api.is_finded("smartdns") then
o.cfgvalue = function(self, section)
return m:get(section, self.option) or {"tcp://1.1.1.1"}
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
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("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.default = "5"
o:value("0", translate("Close"))
@@ -164,19 +164,6 @@ source.validate = function(self, value, t)
return value
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
sourcePort = s:option(Value, "sourcePort", translate("Source port"))
@@ -116,12 +116,12 @@ if load_balancing_options then -- [[ Load balancing Start ]]
end
end
-- 读取旧 DynamicList
function o.cfgvalue(self, section)
return m.uci:get_list(appname, section, "balancing_node") or {}
function o.custom_cfgvalue(self, section)
return table.concat(m:get(section, "balancing_node") or {}, " ")
end
-- 写入保持 DynamicList
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 = {}, {}
for v in value:gmatch("%S+") do
new[#new + 1] = v
@@ -129,13 +129,13 @@ if load_balancing_options then -- [[ Load balancing Start ]]
end
for _, v in ipairs(old) do
if not set[v] then
m.uci:set_list(appname, section, "balancing_node", new)
m:set(section, "balancing_node", new)
return
end
set[v] = nil
end
for _ in pairs(set) do
m.uci:set_list(appname, section, "balancing_node", new)
m:set(section, "balancing_node", new)
return
end
end
@@ -115,12 +115,12 @@ if load_urltest_options then -- [[ URLTest Start ]]
end
end
-- 读取旧 DynamicList
function o.cfgvalue(self, section)
return m.uci:get_list(appname, section, "urltest_node") or {}
function o.custom_cfgvalue(self, section)
return table.concat(m:get(section, "urltest_node") or {}, " ")
end
-- 写入保持 DynamicList
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 = {}, {}
for v in value:gmatch("%S+") do
new[#new + 1] = v
@@ -128,13 +128,13 @@ if load_urltest_options then -- [[ URLTest Start ]]
end
for _, v in ipairs(old) do
if not set[v] then
m.uci:set_list(appname, section, "urltest_node", new)
m:set(section, "urltest_node", new)
return
end
set[v] = nil
end
for _ in pairs(set) do
m.uci:set_list(appname, section, "urltest_node", new)
m:set(section, "urltest_node", new)
return
end
end
@@ -216,15 +216,6 @@ o:depends({ [_n("reality")] = true })
o = s:option(DynamicList, _n("reality_serverNames"), translate("serverNames"))
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.default = "default"
+36 -3
View File
@@ -1014,7 +1014,6 @@ local default_file_tree = {
}
local function get_api_json(url)
local jsonc = require "luci.jsonc"
local gh_proxy = uci_get_type("global_app", "github_proxy", "0")
local return_code, content
if gh_proxy == "1" then
@@ -1345,6 +1344,25 @@ function set_default_cbi()
self.template = appname .. "/cbi/tvalue"
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
function return_map(map)
@@ -1369,6 +1387,7 @@ function return_map(map)
end
function luci_types(id, m, s, type_name, option_prefix)
local cbi = require "luci.cbi"
local fv_type
local field_type = s.fields["type"]
if field_type then
@@ -1406,11 +1425,25 @@ function luci_types(id, m, s, type_name, option_prefix)
if self.custom_write then
self:custom_write(section, value)
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
m:set(section, self.rewrite_option, value)
m:set(section, self.rewrite_option, new_val)
else
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
+3
View File
@@ -1283,6 +1283,9 @@ msgstr "使用全局配置"
msgid "User-Agent"
msgstr "用户代理(User-Agent)"
msgid "Used when the node link does not include this parameter."
msgstr "当节点链接未包含该参数时,将使用此设置。"
msgid "Add"
msgstr "添加"
@@ -220,7 +220,7 @@ local function encode_vless(node)
local link = "vless://" .. node.uuid .. "@" .. o.server .. ":" .. o.port
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
-- 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_xray = api.finded_com("xray")
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_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 {}
@@ -516,6 +517,7 @@ end
-- 处理数据
local function processData(szType, content, add_mode, group, sub_cfg)
--log(2, content, add_mode, group)
local sub_allowinsecure = DEFAULT_ALLOWINSECURE
local sub_ss_type = DEFAULT_SS_TYPE
local sub_trojan_type = DEFAULT_TROJAN_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_hy_up_mbps, sub_hy_down_mbps = 1000, 1000
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"
if ss_type ~= "global" and core_has[ss_type] then
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_pinSHA256 = info.pcs
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
result.tls = "0"
end
@@ -971,7 +977,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
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")
result.uot = params.udp
else
result.error_msg = "请更换 Xray 或 Sing-Box 来支持 SS 更多的传输方式。"
@@ -1089,7 +1096,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
end
result.tls_pinSHA256 = params.pcs
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
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.reality_mldsa65Verify = params.pqv or nil
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
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_password = params.auth
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.hysteria_up_mbps = params.upmbps or sub_hy_up_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_pinSHA256 = params.pcs or params.pinsha256
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_down_mbps = params.downmbps or (sub_cfg and sub_hy_down_mbps or nil)
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_congestion_control = params.congestion_control or "cubic"
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
if has_singbox then
result.type = 'sing-box'
@@ -1593,7 +1605,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
end
end
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
elseif szType == 'naive+https' or szType == 'naive+quic' then
if has_singbox then
+1 -1
View File
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2
PKG_VERSION:=26.8.7
PKG_RELEASE:=75
PKG_RELEASE:=76
PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \
@@ -171,19 +171,6 @@ node_socks_bind_local:depends({ node = "", ["!reverse"] = true })
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.default = "UseIP"
o:value("UseIP")
+3 -2
View File
@@ -5,7 +5,6 @@ nixio = require "nixio"
fs = require "nixio.fs"
sys = require "luci.sys"
uci = require"luci.model.uci".cursor()
cbi = require "luci.cbi"
util = require "luci.util"
datatypes = require "luci.cbi.datatypes"
jsonc = require "luci.jsonc"
@@ -1014,7 +1013,6 @@ local default_file_tree = {
}
function get_api_json(url)
local jsonc = require "luci.jsonc"
local return_code, content = curl_logic(url, nil, curl_args)
if return_code ~= 0 or content == "" then return {} end
return jsonc.parse(content) or {}
@@ -1387,6 +1385,7 @@ function set_apply_on_parse(map)
end
function set_default_cbi()
local cbi = require "luci.cbi"
if true then
--TextValue
local TextValue = cbi.TextValue
@@ -1418,6 +1417,7 @@ function set_default_cbi()
end
function return_map(map)
local cbi = require "luci.cbi"
local api = require "luci.passwall2.api"
if true then
-- header
@@ -1438,6 +1438,7 @@ function return_map(map)
end
function luci_types(id, m, s, type_name, option_prefix)
local cbi = require "luci.cbi"
local fv_type
local field_type = s.fields["type"]
if field_type then
@@ -111,34 +111,6 @@ for i, v in ipairs(cipherSuites) do
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)
local result = nil
if node then
@@ -2023,6 +1995,7 @@ function gen_config(var)
else default_dns_flag = "direct"
end
dns.final = default_dns_flag
dns.strategy = default_dns_flag == "remote" and remote_strategy or direct_strategy
-- DNS in order of shunt
if dns_domain_rules and #dns_domain_rules > 0 then
@@ -2046,12 +2019,43 @@ function gen_config(var)
dns_rule.server = nil
end
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
if value.outboundTag ~= "block" and value.outboundTag ~= "direct" then
dns_rule.server = "remote"
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
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)
@@ -2062,9 +2066,13 @@ function gen_config(var)
end
if value.fakedns then
local fakedns_dns_rule = api.clone(dns_rule)
fakedns_dns_rule.query_type = {
"A", "AAAA"
}
if remote_strategy == "ipv4_only" then
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.disable_cache = true
fakedns_dns_rule.client_subnet = nil
@@ -2076,23 +2084,26 @@ function gen_config(var)
end
end
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
-- When default is not direct and enable fakedns, default DNS use FakeDNS.
local fakedns_dns_rule = {
query_type = {
"A", "AAAA"
},
query_type = dns_rule_query_type,
server = fakedns_tag,
disable_cache = true,
rewrite_ttl = 30,
strategy = remote_strategy,
rewrite_ttl = 30
}
table.insert(dns.rules, fakedns_dns_rule)
else
local remote_dns_rule = {
query_type = dns_rule_query_type,
server = "remote",
disable_cache = true,
strategy = remote_strategy,
}
table.insert(dns.rules, remote_dns_rule)
end
@@ -2328,156 +2339,7 @@ function gen_proto_config(var)
return jsonc.stringify(config, 1)
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_front_dns_config = gen_front_dns_config
_G.gen_proto_config = gen_proto_config
_G.geo_convert_srs = geo_convert_srs
@@ -51,35 +51,6 @@ for i, v in ipairs(cipherSuites) do
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)
local result = nil
if node then
@@ -2186,157 +2157,7 @@ function gen_proto_config(var)
return jsonc.stringify(config, 1)
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_front_dns_config = gen_front_dns_config
_G.gen_proto_config = gen_proto_config
if arg[1] then
-6
View File
@@ -121,12 +121,6 @@ msgstr "0 به معنای عدم استفاده است"
msgid "Current node: %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."
msgstr "حالت IP:Port قابل قبول است، مقادیر متعدد را با کاما انگلیسی جدا کنید."
-6
View File
@@ -118,12 +118,6 @@ msgstr "0 — отключить функцию"
msgid "Current node: %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."
msgstr "Допустим формат IP:Port. Несколько значений указывайте через запятую."
-6
View File
@@ -118,12 +118,6 @@ msgstr "0为不使用"
msgid "Current node: %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."
msgstr "接受 IP:Port 形式的输入,多个以英文逗号分隔。"
-6
View File
@@ -118,12 +118,6 @@ msgstr "0為不使用"
msgid "Current node: %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."
msgstr "接受 IP:Port 形式的輸入,多個以英文逗号分隔。"
@@ -655,58 +655,13 @@ run_global() {
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() {
[ -z "${ACL_GLOBAL_node}" ] && [ -z "${FRONT_DNS_PORT}" ] && return
[ -z "${ACL_GLOBAL_node}" ] && return
local RUN_NEW_DNSMASQ=1
RUN_NEW_DNSMASQ=${DNS_REDIRECT}
DNSMASQ_DEFAULT_DNS="${AUTO_DNS}"
DNSMASQ_LOCAL_DNS="${LOCAL_DNS:-${AUTO_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
#The old logic will be removed in the future.
#Run a copy dnsmasq instance, DNS hijack that don't need a proxy devices.
@@ -1194,7 +1149,6 @@ start() {
fi
mkdir -p ${GLOBAL_ACL_PATH}
[ "$ENABLED_DEFAULT_ACL" == 1 ] && run_global
run_front_dns
run_global_dnsmasq
[ -n "$USE_TABLES" ] && source $APP_PATH/${USE_TABLES}.sh start
set_cache_var "USE_TABLES" "$USE_TABLES"
+1 -1
View File
@@ -17,7 +17,7 @@ LUCI_NAME:=luci-theme-footstrap
FOOTSTRAP_VERSION?=
ifneq ($(FOOTSTRAP_VERSION),)
PKG_VERSION:=$(FOOTSTRAP_VERSION)
PKG_RELEASE:=9
PKG_RELEASE:=10
endif
LUCI_TITLE:=Footstrap Theme
@@ -381,6 +381,22 @@ function seed() {
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
* SPA nav (caller should preventDefault), false to let the browser do a normal
* 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);
if (!className)
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;
/* 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
* 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
* and the kernel log, and a third-party LogreadBox has neither, while ui.js gives these two rows
* the same ids wherever the widget is rendered. 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. */
div:has(> #logFacilitySelect),
div:has(> #logTextFilter) {
* Keyed on the ROW's SHAPE, not on the page and not on the controls' ids. `data-page` differs
* between the system and the kernel log and a third-party LogreadBox has neither but the ids
* are no better: only the System Log is built by `tools/views.js`, and Status Kernel Log is a
* view of its own (`view/status/dmesg.js`) whose four rows carry `logFromTime`, `logToTime`,
* `invertLogRangeTime`, `invertSeverity` and `invertAscendingSort`, of which an id list written
* against LogreadBox catches none `logFacilitySelect` appears there only as a `for=`, on a
* 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;
flex-wrap: wrap;
align-items: center;
row-gap: var(--fs-space-2);
}
div:has(> #logFacilitySelect) > label,
div:has(> #logTextFilter) > label { white-space: nowrap; }
#logFacilitySelect, #logSeveritySelect, #logTextFilter, #logMaxRows {
#content_syslog > div:has(> label) > label { white-space: nowrap; }
#content_syslog > div:has(> label) > :is(select, input) {
flex: 1 1 auto;
/* 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>
@@ -38,6 +43,8 @@
min-width: 0;
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
* a second search field. */
#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,
* 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
* shapes (a checkbox filter and a bare `Макс. строк:` pair), so the same four tracks would be
* sized by items that are not each other's counterparts: measured, the max-rows box defined
* column 2 and pushed `содержит:` and its field off the card. Wrapping puts that row's two
* filters on two lines by itself, which is all the grid was for. */
* EVERY OTHER ROW is deliberately left to the wrapping above, because none of them is that
* shape. The System Log's second row holds a checkbox filter beside a bare `Макс. строк:` pair,
* and the same four tracks are then sized by items that are not each other's counterparts:
* measured, the max-rows box defined column 2 and pushed `содержит:` and its field off the card.
* 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) {
/* 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) {
display: grid;
grid-template-columns: auto auto auto minmax(0, 1fr);
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=modeminfo
PKG_VERSION:=0.4.7
PKG_RELEASE:=9
PKG_VERSION:=0.4.8
PKG_RELEASE:=10
PKG_MAINTAINER:=Konstantine Shevlakov <shevlakov@132lan.ru>
include $(INCLUDE_DIR)/package.mk
@@ -42,6 +42,9 @@
# Telit LN940 LT4220
1bc71900;QUALCOMM
1bc71901;QUALCOMM
# Telit LM960
1bc71040;QUALCOMM_LM960
1bc71041;QUALCOMM_LM960
# Yuge CLM920
12864e3c;YUGE
# 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_VERSION:=20260531
PKG_RELEASE:=62
PKG_RELEASE:=63
PKG_SOURCE:=$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_VERSION:=00be1cea6bcdaf0d8e79b62dff533f08f49863e8
PKG_SOURCE_VERSION:=a2e7cbafc787ba9a0e86550bd3f4d03207fb9678
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_MAINTAINER:=Chen Minqiang <ptpt52@gmail.com>
PKG_LICENSE:=GPL-2.0