Compare commits

...

3 Commits

Author SHA1 Message Date
action
e3177747c8 update 2026-07-15 21:24:49 2026-07-15 21:24:49 +08:00
action
50b85ff317 update 2026-07-15 17:56:48 2026-07-15 17:56:48 +08:00
action
a67d83bfc0 update 2026-07-15 14:09:58 2026-07-15 14:09:58 +08:00
19 changed files with 121 additions and 140 deletions

View File

@ -116,6 +116,11 @@ define Package/dae/install
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/dae $(1)/usr/bin/dae
$(INSTALL_DIR) $(1)/etc/dae/
$(INSTALL_CONF) $(PKG_BUILD_DIR)/example.dae $(1)/etc/dae/
$(INSTALL_CONF) $(CURDIR)/files/config.dae $(1)/etc/dae/config.dae
$(INSTALL_DIR) $(1)/etc/dae/config.d/
$(INSTALL_CONF) $(CURDIR)/files/config.d/dns.dae $(1)/etc/dae/config.d/dns.dae
$(INSTALL_CONF) $(CURDIR)/files/config.d/node.dae $(1)/etc/dae/config.d/node.dae
$(INSTALL_CONF) $(CURDIR)/files/config.d/route.dae $(1)/etc/dae/config.d/route.dae
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) $(CURDIR)/files/dae.config $(1)/etc/config/dae
$(INSTALL_DIR) $(1)/etc/init.d

View File

@ -0,0 +1,25 @@
# dns.dae
dns {
optimistic_cache_ttl: 86400
max_cache_size: 4096
upstream {
localdns: 'udp://127.0.0.1:53'
overseadns: 'tcp+udp://1.0.0.1:53'
nodedns: 'udp://111.222.333.444:53'
}
routing {
request {
sub(sub_name) -> overseadns
subnode(sub_name) && subnode(name_keyword: 114514) -> nodedns
qtype(https) -> reject
qname(geosite:gfw) -> overseadns
fallback: localdns
}
response {
upstream(overseadns) -> accept
qname(geosite:private) -> accept
ip(geoip:cn) -> accept
fallback: overseadns
}
}
}

View File

@ -0,0 +1,19 @@
# node.dae
node {
node1: 'xxx'
node2: 'xxx'
}
subscription {
my_sub: 'https://www.example.com/subscription/link'
}
group {
my_group {
filter: subtag(my_sub) && !name(keyword: 'ExpireAt:')
filter: subtag(my_sub2)
policy: min_moving_avg
}
local_group {
filter: name(node1, node2)
policy: fixed(0)
}
}

View File

@ -0,0 +1,22 @@
# route.dae
routing {
pname(dnsmasq, zerotier-one) -> must_direct
dip(224.0.0.0/3, 'ff00::/8', geoip:private) -> direct
domain(geosite:category-bank-cn, geosite:boc@!cn, geosite:synology) -> direct
domain(geosite:category-ai-!cn, geosite:google, geosite:category-entertainment, geosite:gfw, geosite:github, geosite:spotify) && l4proto(udp) && dport(443) -> block
domain(geosite:spotify) -> proxy
domain(geosite:category-entertainment) -> proxy
domain(geosite:category-ai-!cn, geosite:google, geosite:github) -> proxy
domain(geosite:gfw) -> proxy
dip(geoip:telegram) -> proxy
dip(geoip:cn) -> direct
l4proto(udp) && dport(443) -> block
fallback: proxy
}

18
dae/files/config.dae Normal file
View File

@ -0,0 +1,18 @@
# config.dae
# load all dae files placed in ./config.d/
include {
config.d/*.dae
}
global {
log_level:warn
check_interval:600s
check_tolerance:20ms
lan_interface:"br-lan"
wan_interface:auto
auto_config_kernel_parameter:true
sniffing_timeout:300ms
udp_check_dns: "dns.google:53,8.8.8.8,2001:4860:4860::8888"
tcp_check_url: "http://cp.cloudflare.com,1.1.1.1,2606:4700:4700::1111"
dial_mode: domain
allow_insecure: true
}

View File

@ -11,13 +11,14 @@ PROG="/usr/bin/dae"
LOG="/var/log/dae/dae.log"
DAE_HOST_IFACE="dae0"
DAE_PEER_IFACE="dae0peer"
DAENETNS="/run/netns/daens"
DAE_NETNS_NAME="daens"
DAENETNS="/run/netns/$DAE_NETNS_NAME"
RESOLV_DAE="/tmp/resolv.conf.dae"
set_chmod_640() {
chmod -R 640 /etc/dae/ 2>/dev/null || true
mkdir -p /etc/dae/config.d
mkdir -p /var/log/dae
chmod -R 640 /etc/dae/ 2>/dev/null || true
}
update_cron() {
@ -116,9 +117,9 @@ start_service() {
[ "$enabled" -eq "1" ] || return 1
config_get config_file "config" "config_file" "/etc/dae/config.dae"
"$PROG" validate -c "$config_file" || return 1
set_chmod_640
"$PROG" validate -c "$config_file" || return 1
update_cron "add"
hijack_resolv_conf
cleanup_netns

View File

@ -1,39 +1,9 @@
local fs = require "nixio.fs"
local dae = require "luci.model.dae_tools"
local m, s
m = Map("dae", translate("DNS Settings"), translate("Configure DNS settings for DAE."))
-- Check if dns config file exists, create if not
local dns_file = "/etc/dae/config.d/dns.dae"
if not fs.access(dns_file) then
fs.writefile(dns_file, [[# dns.dae
dns {
optimistic_cache_ttl: 86400
max_cache_size: 4096
upstream {
localdns: 'udp://127.0.0.1:53'
overseadns: 'tcp+udp://1.0.0.1:53'
nodedns: 'udp://111.222.333.444:53'
}
routing {
request {
sub(sub_name) -> overseadns
subnode(sub_name) && subnode(name_keyword: 114514) -> nodedns
qtype(https) -> reject
qname(geosite:gfw) -> overseadns
fallback: localdns
}
response {
upstream(overseadns) -> accept
qname(geosite:private) -> accept
ip(geoip:cn) -> accept
fallback: overseadns
}
}
}]]
)
end
s = dae.init_editor(m, "dns")
dae.add_editor(s, dns_file, "dnsconf", translate("DNS Configuration"))

View File

@ -1,31 +1,9 @@
local fs = require "nixio.fs"
local dae = require "luci.model.dae_tools"
local m, s, o
m = Map("dae", translate("Global Settings"), translate("Configure global settings for DAE."))
-- Check if config file exists, create if not
local config_file = "/etc/dae/config.dae"
if not fs.access(config_file) then
fs.writefile(config_file, [[# config.dae
# load all dae files placed in ./config.d/
include {
config.d/*.dae
}
global {
log_level:warn
check_interval:600s
check_tolerance:20ms
lan_interface:"br-lan"
wan_interface:auto
auto_config_kernel_parameter:true
sniffing_timeout:300ms
udp_check_dns: "dns.google:53,8.8.8.8,2001:4860:4860::8888"
tcp_check_url: "http://cp.cloudflare.com,1.1.1.1,2606:4700:4700::1111"
dial_mode: domain
allow_insecure: true
}]])
end
s = dae.init_editor(m, "global")

View File

@ -1,32 +1,9 @@
local fs = require "nixio.fs"
local dae = require "luci.model.dae_tools"
local m, s
m = Map("dae", translate("Node Settings"), translate("Configure nodes and groups for DAE."))
-- Check if node config file exists, create if not
local node_file = "/etc/dae/config.d/node.dae"
if not fs.access(node_file) then
fs.writefile(node_file, [[node {
node1: 'xxx'
node2: 'xxx'
}
subscription {
my_sub: 'https://www.example.com/subscription/link'
}
group {
my_group {
filter: subtag(my_sub) && !name(keyword: 'ExpireAt:')
filter: subtag(my_sub2)
policy: min_moving_avg
}
local_group {
filter: name(node1, node2)
policy: fixed(0)
}
}]]
)
end
s = dae.init_editor(m, "node")
dae.add_editor(s, node_file, "nodeconf", translate("Node Configuration"))

View File

@ -1,35 +1,9 @@
local fs = require "nixio.fs"
local dae = require "luci.model.dae_tools"
local m, s
m = Map("dae", translate("Routing Settings"), translate("Configure routing rules for DAE."))
-- Check if route config file exists, create if not
local route_file = "/etc/dae/config.d/route.dae"
if not fs.access(route_file) then
fs.writefile(route_file, [[routing {
pname(dnsmasq, zerotier-one) -> must_direct
dip(224.0.0.0/3, 'ff00::/8', geoip:private) -> direct
domain(geosite:category-bank-cn, geosite:boc@!cn, geosite:synology) -> direct
domain(geosite:category-ai-!cn, geosite:google, geosite:category-entertainment, geosite:gfw, geosite:github, geosite:spotify) && l4proto(udp) && dport(443) -> block
domain(geosite:spotify) -> proxy
domain(geosite:category-entertainment) -> proxy
domain(geosite:category-ai-!cn, geosite:google, geosite:github) -> proxy
domain(geosite:gfw) -> proxy
dip(geoip:telegram) -> proxy
dip(geoip:cn) -> direct
l4proto(udp) && dport(443) -> block
fallback: proxy
}]]
)
end
s = dae.init_editor(m, "route")
dae.add_editor(s, route_file, "routeconf", translate("Route Configuration"))

View File

@ -17,7 +17,7 @@
function(x, data) {
if(x && x.status == 200) {
var log_textarea = document.getElementById('log_textarea');
log_textarea.innerHTML = x.responseText;
log_textarea.textContent = x.responseText;
if (!scrolled) {
log_textarea.scrollTop = log_textarea.scrollHeight;
scrolled = true;

View File

@ -7,7 +7,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
PKG_VERSION:=26.7.1
PKG_VERSION:=26.7.15
PKG_RELEASE:=1
PKG_PO_VERSION:=$(PKG_VERSION)

View File

@ -441,24 +441,15 @@ o = s:option(Value, _n("tls_serverName"), "SNI " .. translate("Domain"))
o:depends({ [_n("tls")] = true })
o:depends({ [_n("protocol")] = "hysteria2" })
if api.compare_versions(os.date("%Y.%m.%d"), "<", "2026.6.1") then
o = s:option(Flag, _n("tls_allowInsecure"), translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."))
o.default = "0"
o:depends({ [_n("tls")] = true, [_n("reality")] = false })
o:depends({ [_n("protocol")] = "hysteria2" })
end
o = s:option(Value, _n("tls_pinSHA256"), translate("TLS Chain Fingerprint (SHA256)"))
o:depends({ [_n("tls")] = true, [_n("reality")] = false })
o:depends({ [_n("protocol")] = "hysteria2" })
o.description = translate("Once set, connects only when the servers chain fingerprint matches.") ..
string.format("<a href='javascript:void(0)' onclick='javascript:fetchCertSha256(this)'>%s</a>", "" .. translate("Fetch Manually"))
if api.compare_versions(xray_version, ">=", "26.1.31") then
o = s:option(Value, _n("tls_pinSHA256"), translate("TLS Chain Fingerprint (SHA256)"))
o:depends({ [_n("tls")] = true, [_n("reality")] = false })
o:depends({ [_n("protocol")] = "hysteria2" })
o.description = translate("Once set, connects only when the servers chain fingerprint matches.") ..
string.format("<a href='javascript:void(0)' onclick='javascript:fetchCertSha256(this)'>%s</a>", "" .. translate("Fetch Manually"))
o = s:option(Value, _n("tls_CertByName"), translate("TLS Certificate Name (CertName)"), translate("TLS is used to verify the leaf certificate name."))
o:depends({ [_n("tls")] = true, [_n("reality")] = false })
o:depends({ [_n("protocol")] = "hysteria2" })
end
o = s:option(Value, _n("tls_CertByName"), translate("TLS Certificate Name (CertName)"), translate("TLS is used to verify the leaf certificate name."))
o:depends({ [_n("tls")] = true, [_n("reality")] = false })
o:depends({ [_n("protocol")] = "hysteria2" })
o = s:option(Flag, _n("tls_certificate"), translate("TLS Certificate (PEM)"))
o.default = "0"

View File

@ -152,21 +152,9 @@ function gen_outbound(flag, node, tag, proxy_table)
security = node.stream_security,
tlsSettings = (node.stream_security == "tls") and {
serverName = node.tls_serverName,
allowInsecure = (function()
if node.tls_pinSHA256 and node.tls_pinSHA256 ~= "" then return nil end
if api.compare_versions(os.date("%Y.%m.%d"), "<", "2026.6.1") and node.tls_allowInsecure == "1" then return true end
end)(),
fingerprint = (node.type == "Xray" and node.utls == "1" and node.fingerprint and node.fingerprint ~= "") and node.fingerprint or nil,
pinnedPeerCertSha256 = (function()
if api.compare_versions(xray_version, "<", "26.1.31") then return nil end
if not node.tls_pinSHA256 then return "" end
return node.tls_pinSHA256
end)(),
verifyPeerCertByName = (function()
if api.compare_versions(xray_version, "<", "26.1.31") then return nil end
if not node.tls_CertByName then return "" end
return node.tls_CertByName
end)(),
pinnedPeerCertSha256 = node.tls_pinSHA256,
verifyPeerCertByName = node.tls_CertByName,
echConfigList = (node.ech == "1") and node.ech_config or nil,
certificates = (node.tls_certificate == "1" and node.tls_certificate_pem ~= "") and {
certificate = api.split(node.tls_certificate_pem, "\n"),
@ -820,7 +808,8 @@ function gen_config_server(node)
serverNames = node.reality_serverNames or {},
privateKey = node.reality_private_key,
shortIds = node.reality_shortId or "",
mldsa65Seed = (node.use_mldsa65Seed == "1") and node.reality_mldsa65Seed or nil
mldsa65Seed = (node.use_mldsa65Seed == "1") and node.reality_mldsa65Seed or nil,
minClientVer = "1.0.0"
} or nil
end
end

View File

@ -1313,6 +1313,8 @@ local current_node = map:get(section)
opt.set(dom_prefix + 'utls', true);
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
}
opt.set(dom_prefix + 'ech', !!queryParam.ech);
opt.set(dom_prefix + 'ech_config', queryParam.ech || '');
opt.set(dom_prefix + 'tls_pinSHA256', queryParam.pcs || '');
opt.set(dom_prefix + 'tls_CertByName', queryParam.vcn || '');
opt.set(

View File

@ -1069,6 +1069,10 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.reality_publicKey = params.pbk or nil
result.reality_shortId = params.sid or nil
end
if params.ech and params.ech ~= "" then
result.ech = "1"
result.ech_config = params.ech
end
result.tls_pinSHA256 = params.pcs
result.tls_CertByName = params.vcn
result.tls_allowInsecure = params.allowinsecure or params.allowInsecure or params.insecure

View File

@ -1314,6 +1314,8 @@ local current_node = map:get(section)
opt.set(dom_prefix + 'utls', true);
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
}
opt.set(dom_prefix + 'ech', !!queryParam.ech);
opt.set(dom_prefix + 'ech_config', queryParam.ech || '');
opt.set(dom_prefix + 'tls_pinSHA256', queryParam.pcs || '');
opt.set(dom_prefix + 'tls_CertByName', queryParam.vcn || '');
opt.set(

View File

@ -1368,6 +1368,10 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.reality_publicKey = params.pbk or nil
result.reality_shortId = params.sid or nil
end
if params.ech and params.ech ~= "" then
result.ech = "1"
result.ech_config = params.ech
end
result.tls_pinSHA256 = params.pcs
result.tls_CertByName = params.vcn
local insecure = params.allowinsecure or params.allowInsecure or params.insecure

View File

@ -21,13 +21,13 @@ define Download/geoip
HASH:=b71d1999439dde2de2d2b6844a2befa50c50211ff739785c005ca7c230a17d6a
endef
GEOSITE_VER:=20260714071254
GEOSITE_VER:=20260715085145
GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER)
define Download/geosite
URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/
URL_FILE:=dlc.dat
FILE:=$(GEOSITE_FILE)
HASH:=9df9913a1a2ec1579d8c80872538e5ed78aa3a74b6ee03496bbac182b1350727
HASH:=b342b28f84550f71da1b05e2d18347270ba81afd11b4d16692c537e3c4085ee7
endef
GEOSITE_IRAN_VER:=202607130116