✨ Sync 2026-06-07 00:43:45

This commit is contained in:
github-actions[bot] committed 2026-06-07 00:43:45 +08:00
1 parent 75dec81517
commit 85f7b195f8
18 files changed
+4294 -2

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
config daede 'config'
option active_backend 'daed'
@@ -0,0 +1,153 @@
#!/bin/sh
# Patch the daed package's /etc/init.d/daed to clean up /run/netns/daens on
# stop_service(). Without this, restarting daed fails with:
# fatal: failed to create netns: open /run/netns/daens: file exists
#
# This script lives under /etc/uci-defaults/ which OpenWrt runs once on
# every package install/upgrade and then removes - so each time luci-app-daede
# is (re-)installed we re-patch the daed init.d even if it was overwritten
# by a daed package upgrade in between.
#
# The patch is idempotent: a marker comment guards against double-injection.
set -e
# luci-app-daede owns its own LuCI menu and view path. Remove stale files from
# the official luci-app-daed package and earlier daede builds that reused
# /view/daed.
rm -f /usr/share/luci/menu.d/luci-app-daed.json
rm -f /usr/share/rpcd/acl.d/luci-app-daed.json
rm -rf /usr/share/luci-app-daed
rm -rf /www/luci-static/resources/view/daed
rm -f /usr/lib/lua/luci/i18n/daed.zh-cn.lmo
rm -f /tmp/luci-indexcache.* 2>/dev/null || true
rm -rf /tmp/luci-modulecache/* 2>/dev/null || true
if [ -f /etc/config/daed_luci ]; then
old_backend="$(uci -q get daed_luci.config.active_backend || true)"
if ! uci -q get daede.config >/dev/null 2>&1; then
touch /etc/config/daede
uci -q set daede.config=daede
case "$old_backend" in
dae|daed) uci -q set daede.config.active_backend="$old_backend" ;;
esac
uci -q commit daede
elif ! uci -q get daede.config.active_backend >/dev/null 2>&1; then
case "$old_backend" in
dae|daed)
uci -q set daede.config.active_backend="$old_backend"
uci -q commit daede
;;
esac
fi
rm -f /etc/config/daed_luci
fi
if ! uci -q get daede.config >/dev/null 2>&1; then
touch /etc/config/daede
uci -q set daede.config=daede
if [ -f /etc/init.d/daed ]; then
uci -q set daede.config.active_backend='daed'
else
uci -q set daede.config.active_backend='dae'
fi
uci -q commit daede
fi
# Remove --disable-timestamp from dae init so log lines carry timestamps
DAE_INIT="/etc/init.d/dae"
if [ -f "$DAE_INIT" ]; then
sed -i 's/--disable-timestamp//' "$DAE_INIT"
sed -i '/procd_append_param command *$/d' "$DAE_INIT"
fi
# dae expects geoip.dat / geosite.dat under /usr/share/dae/;
# v2ray-geoip installs them to /usr/share/v2ray/. Create symlinks.
if [ -f /usr/share/v2ray/geoip.dat ] && [ ! -f /usr/share/dae/geoip.dat ]; then
mkdir -p /usr/share/dae
ln -sf /usr/share/v2ray/geoip.dat /usr/share/dae/geoip.dat
fi
if [ -f /usr/share/v2ray/geosite.dat ] && [ ! -f /usr/share/dae/geosite.dat ]; then
mkdir -p /usr/share/dae
ln -sf /usr/share/v2ray/geosite.dat /usr/share/dae/geosite.dat
fi
if [ -f /usr/share/v2ray/geoip.dat ] && [ ! -f /usr/share/daed/geoip.dat ]; then
mkdir -p /usr/share/daed
ln -sf /usr/share/v2ray/geoip.dat /usr/share/daed/geoip.dat
fi
if [ -f /usr/share/v2ray/geosite.dat ] && [ ! -f /usr/share/daed/geosite.dat ]; then
mkdir -p /usr/share/daed
ln -sf /usr/share/v2ray/geosite.dat /usr/share/daed/geosite.dat
fi
# Seed default dae form sections (group/routing/dns) for the LuCI editor.
# Idempotent: only add what's missing. Lives in the `dae` UCI package,
# consumed by gen-dae-config.sh.
if [ -f /etc/config/dae ]; then
if ! uci -q show dae | grep -q "=group$"; then
g="$(uci add dae group)"
uci -q set "dae.$g.name=proxy"
uci -q set "dae.$g.policy=min_moving_avg"
fi
if ! uci -q get dae.routing >/dev/null 2>&1; then
uci -q set dae.routing=routing
uci -q set dae.routing.private_direct=1
uci -q set dae.routing.cn_direct=1
uci -q set dae.routing.block_ads=0
uci -q set dae.routing.fallback=proxy
fi
if ! uci -q get dae.dns >/dev/null 2>&1; then
uci -q set dae.dns=dns
uci -q set dae.dns.cn_upstream='udp://dns.alidns.com:53'
uci -q set dae.dns.fallback_upstream='tcp+udp://dns.google:53'
fi
# Migrate legacy group filters to the unified source / name_filter fields,
# then drop the old keys so the form shows real, editable values (the old
# fields used to re-populate the new ones and looked un-deletable).
# `uci get` joins a list into one space-separated line; the unquoted $() word-
# splits it back into items. dae tags/keywords are whitespace-free, so this is
# the intended split (do NOT set IFS=newline here — it would merge the items).
i=0
while uci -q get "dae.@group[$i]" >/dev/null 2>&1; do
if [ -z "$(uci -q get dae.@group[$i].source)" ]; then
for v in $(uci -q get dae.@group[$i].filter_sub 2>/dev/null); do
uci -q add_list dae.@group[$i].source="$v"
done
fi
if [ -z "$(uci -q get dae.@group[$i].name_filter)" ]; then
for v in $(uci -q get dae.@group[$i].filter_node 2>/dev/null); do
uci -q add_list dae.@group[$i].name_filter="$v"
done
fi
uci -q delete dae.@group[$i].filter_sub 2>/dev/null
uci -q delete dae.@group[$i].filter_node 2>/dev/null
i=$((i+1))
done
uci -q commit dae
fi
INIT="/etc/init.d/daed"
MARKER="# luci-app-daede: netns-cleanup"
[ -f "$INIT" ] || exit 0
grep -q "$MARKER" "$INIT" && exit 0
# Inject `ip netns del daens 2>/dev/null || true` right after `rm -f "$LOG"`
# inside stop_service(). awk is more reliable than sed for multiline contexts.
awk -v marker="$MARKER" '
BEGIN { in_stop = 0; injected = 0 }
/^stop_service\(\)/ { in_stop = 1 }
in_stop && /^}/ { in_stop = 0 }
{ print }
in_stop && !injected && /rm -f "\$LOG"/ {
print "\tip netns del daens 2>/dev/null || true " marker
injected = 1
}
' "$INIT" > "${INIT}.new" && mv "${INIT}.new" "$INIT"
chmod +x "$INIT"
exit 0
reload_service() {
restart
}
@@ -0,0 +1,368 @@
#!/bin/sh
# SPDX-License-Identifier: Apache-2.0
#
# gen-dae-config.sh - build /etc/dae/config.dae from the dae UCI form sections,
# validate with `dae validate`, then overwrite + hot reload only on success.
#
# generate read UCI -> render config.dae -> validate -> overwrite + hot reload
# import parse existing config.dae subscription{}/node{} -> fill UCI form
#
# UCI model (package dae):
# config subscription tag/url, enabled
# config node tag/link, enabled
# config group name/policy, list source, list name_filter
# (old list filter_sub/filter_node still read as fallback)
# config routing 'routing' private_direct/cn_direct/block_ads/fallback, list custom
# config dns 'dns' cn_upstream/fallback_upstream
. /lib/functions.sh
CONFIG_DAE="/etc/dae/config.dae"
TMP_GEN="/tmp/dae-gen.dae"
DAE_BIN="/usr/bin/dae"
DAE_INITD="/etc/init.d/dae"
# dae single-quoted strings have no escaping; strip quotes/newlines defensively.
sanitize() {
printf '%s' "$1" | tr -d "'" | tr -d '\n\r'
}
# ===================== generate =====================
SUB_BUF=""
NODE_BUF=""
GROUP_BUF=""
FIRST_GROUP=""
emit_sub() {
local s="$1" tag url enabled
config_get tag "$s" tag ""
config_get url "$s" url ""
config_get_bool enabled "$s" enabled 1
[ "$enabled" = "1" ] || return 0
url="$(sanitize "$url")"
[ -n "$url" ] || return 0
tag="$(sanitize "$tag")"
if [ -n "$tag" ]; then
SUB_BUF="${SUB_BUF} ${tag}: '${url}'
"
else
SUB_BUF="${SUB_BUF} '${url}'
"
fi
}
emit_node() {
local s="$1" tag link enabled
config_get tag "$s" tag ""
config_get link "$s" link ""
config_get_bool enabled "$s" enabled 1
[ "$enabled" = "1" ] || return 0
link="$(sanitize "$link")"
[ -n "$link" ] || return 0
tag="$(sanitize "$tag")"
if [ -n "$tag" ]; then
NODE_BUF="${NODE_BUF} ${tag}: '${link}'
"
else
NODE_BUF="${NODE_BUF} '${link}'
"
fi
}
emit_group() {
local s="$1" name policy
config_get name "$s" name ""
config_get policy "$s" policy "min_moving_avg"
name="$(sanitize "$name")"
[ -n "$name" ] || return 0
[ -n "$FIRST_GROUP" ] || FIRST_GROUP="$name"
GROUP_BUF="${GROUP_BUF} ${name} {
"
# Build the source: 'source' entries that match a subscription tag become
# subtag(), the rest (node tags / keywords) become name(). Old filter_sub /
# filter_node configs still work as a fallback when 'source' is unset.
SUBS_ACC=""; NODES_ACC=""; KW_ACC=""
# source: new field, else old filter_sub (decoupled from the name filter so
# editing one never silently drops the other)
config_list_foreach "$s" source _collect_source
[ -z "$SUBS_ACC" ] && [ -z "$NODES_ACC" ] && config_list_foreach "$s" filter_sub _collect_source
# optional name filter narrows the subscription pool only (AND); hand-picked
# nodes are explicit choices and stay in unconditionally
config_list_foreach "$s" name_filter _collect_kw
[ -z "$KW_ACC" ] && config_list_foreach "$s" filter_node _collect_kw
local andclause=""
[ -n "$KW_ACC" ] && andclause=" && name(${KW_ACC})"
local emitted=0
# multiple filter lines = OR, so subtag and name lines union the sources
if [ -n "$SUBS_ACC" ]; then
GROUP_BUF="${GROUP_BUF} filter: subtag(${SUBS_ACC})${andclause}
"
emitted=1
fi
if [ -n "$NODES_ACC" ]; then
GROUP_BUF="${GROUP_BUF} filter: name(${NODES_ACC})
"
emitted=1
fi
# name filter with no source = filter the whole pool by name
if [ "$emitted" = 0 ] && [ -n "$KW_ACC" ]; then
GROUP_BUF="${GROUP_BUF} filter: name(${KW_ACC})
"
fi
GROUP_BUF="${GROUP_BUF} policy: ${policy}
}
"
SUBS_ACC=""; NODES_ACC=""; KW_ACC=""
}
SUBS_ACC=""
NODES_ACC=""
KW_ACC=""
# Subscription tags, space-padded for membership tests (" tag " match).
SUB_TAGS=""
collect_subtag() {
local t; config_get t "$1" tag ""
t="$(sanitize "$t")"
[ -n "$t" ] && SUB_TAGS="${SUB_TAGS} ${t} "
}
is_subtag() {
case "$SUB_TAGS" in *" $1 "*) return 0 ;; *) return 1 ;; esac
}
# dae filter args are bare only for plain identifiers; anything with regex
# chars / CJK / spaces must be wrapped as regex: '...' or the lexer chokes.
filter_arg() {
case "$1" in
*[!A-Za-z0-9_]*) printf "regex: '%s'" "$1" ;;
*) printf '%s' "$1" ;;
esac
}
# name-filter args do substring matching: regex metachars -> regex:, else keyword:.
# Intentionally stricter than filter_arg: a plain CJK keyword here stays a
# substring `keyword:` match, whereas filter_arg wraps any non-word char as regex.
kw_arg() {
if printf '%s' "$1" | grep -q '[][|().*+?^$\\]'; then
printf "regex: '%s'" "$1"
else
printf "keyword: '%s'" "$1"
fi
}
# classify a source entry: subscription tag -> subtag bucket, else name bucket
_collect_source() {
local v="$(sanitize "$1")"
[ -n "$v" ] || return 0
if is_subtag "$v"; then
SUBS_ACC="${SUBS_ACC:+$SUBS_ACC, }$(filter_arg "$v")"
else
NODES_ACC="${NODES_ACC:+$NODES_ACC, }$(filter_arg "$v")"
fi
}
_collect_kw() {
local v="$(sanitize "$1")"
[ -n "$v" ] || return 0
KW_ACC="${KW_ACC:+$KW_ACC, }$(kw_arg "$v")"
}
generate() {
config_load dae
# global overridable knobs (fall back to defaults)
local dial_mode log_level wan_interface lan_interface
config_get dial_mode config dial_mode "domain"
config_get log_level config log_level "info"
config_get wan_interface config wan_interface "auto"
config_get lan_interface config lan_interface ""
SUB_BUF=""; NODE_BUF=""; GROUP_BUF=""; FIRST_GROUP=""
SUB_TAGS=""
config_foreach collect_subtag subscription
config_foreach emit_sub subscription
config_foreach emit_node node
config_foreach emit_group group
# fall back to a default group when none defined
if [ -z "$GROUP_BUF" ]; then
GROUP_BUF=" proxy {
policy: min_moving_avg
}
"
FIRST_GROUP="proxy"
fi
# routing / dns singletons
local private_direct cn_direct block_ads fallback cn_up fb_up
config_get_bool private_direct routing private_direct 1
config_get_bool cn_direct routing cn_direct 1
config_get_bool block_ads routing block_ads 0
config_get fallback routing fallback "$FIRST_GROUP"
[ -n "$fallback" ] || fallback="$FIRST_GROUP"
fallback="$(sanitize "$fallback")"
config_get cn_up dns cn_upstream "udp://dns.alidns.com:53"
config_get fb_up dns fallback_upstream "tcp+udp://dns.google:53"
cn_up="$(sanitize "$cn_up")"
fb_up="$(sanitize "$fb_up")"
{
echo "# Auto-generated by luci-app-daede form. Manual edits are overwritten on next save."
echo "global {"
echo " tproxy_port: 12345"
echo " tproxy_port_protect: true"
echo " log_level: ${log_level}"
[ -n "$lan_interface" ] && echo " lan_interface: ${lan_interface}"
echo " wan_interface: ${wan_interface}"
echo " auto_config_kernel_parameter: true"
echo " dial_mode: ${dial_mode}"
echo " tcp_check_url: 'http://cp.cloudflare.com,1.1.1.1,2606:4700:4700::1111'"
echo " udp_check_dns: 'dns.google:53,8.8.8.8,2001:4860:4860::8888'"
echo " check_interval: 30s"
echo " check_tolerance: 50ms"
echo "}"
echo ""
if [ -n "$SUB_BUF" ]; then
echo "subscription {"
printf '%s' "$SUB_BUF"
echo "}"
echo ""
fi
if [ -n "$NODE_BUF" ]; then
echo "node {"
printf '%s' "$NODE_BUF"
echo "}"
echo ""
fi
echo "dns {"
echo " ipversion_prefer: 4"
echo " upstream {"
echo " cndns: '${cn_up}'"
echo " fallbackdns: '${fb_up}'"
echo " }"
echo " routing {"
echo " request {"
echo " qname(geosite:cn) -> cndns"
echo " fallback: fallbackdns"
echo " }"
echo " }"
echo "}"
echo ""
echo "group {"
printf '%s' "$GROUP_BUF"
echo "}"
echo ""
echo "routing {"
echo " pname(NetworkManager) -> direct"
# multicast / broadcast direct (geoip:private doesn't cover these)
echo " dip(224.0.0.0/3) -> direct"
echo " dip(255.255.255.255/32) -> direct"
echo " dip('ff00::/8') -> direct"
[ "$private_direct" = "1" ] && echo " dip(geoip:private) -> direct"
# NTP time sync direct
echo " l4proto(udp) && dport(123) -> direct"
# OS connectivity checks direct (avoid captive-portal false positives)
echo " domain(connectivitycheck.gstatic.com) -> direct"
echo " domain(msftconnecttest.com) -> direct"
if [ "$cn_direct" = "1" ]; then
echo " dip(geoip:cn) -> direct"
echo " domain(geosite:cn) -> direct"
fi
[ "$block_ads" = "1" ] && echo " domain(geosite:category-ads-all) -> block"
config_list_foreach routing custom _emit_custom
echo " fallback: ${fallback}"
echo "}"
} > "$TMP_GEN"
chmod 600 "$TMP_GEN" # dae rejects world/group-accessible config files
# overwrite live config only if validation passes
local out
out="$("$DAE_BIN" validate -c "$TMP_GEN" 2>&1)"
if [ $? -ne 0 ]; then
echo "validate failed: $(echo "$out" | head -1)" >&2
rm -f "$TMP_GEN"
return 1
fi
mkdir -p /etc/dae
cat "$TMP_GEN" > "$CONFIG_DAE"
chmod 600 "$CONFIG_DAE"
rm -f "$TMP_GEN"
if /usr/bin/pgrep -x dae >/dev/null 2>&1; then
"$DAE_INITD" hot_reload >/dev/null 2>&1
fi
echo "ok"
return 0
}
_emit_custom() {
local line="$(printf '%s' "$1" | tr -d '\n\r')"
[ -n "$line" ] || return 0
echo " ${line}"
}
# ===================== import =====================
# Fill the UCI form from an existing config.dae subscription{}/node{} block.
# Idempotent: wipe same-type sections first, then rebuild from file.
import_block() {
# $1=block name (subscription|node) $2=uci section type $3=link/url field
local block="$1" stype="$2" field="$3"
awk -v blk="$block" '
$0 ~ "^[[:space:]]*"blk"[[:space:]]*\\{" { inb=1; next }
inb && /^[[:space:]]*\}/ { inb=0 }
inb { print }
' "$CONFIG_DAE" 2>/dev/null | while IFS= read -r raw; do
# drop comment, trim
line="$(printf '%s' "$raw" | sed 's/#.*$//' | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')"
[ -n "$line" ] || continue
tag=""; val=""
case "$line" in
\'*|\"*)
# starts with a quote -> untagged link
val="$line"
;;
[A-Za-z0-9_]*:*)
# identifier ':' link -> tagged (split on first colon)
tag="$(printf '%s' "$line" | sed "s/[[:space:]]*:.*//")"
val="$(printf '%s' "$line" | sed "s/^[^:]*:[[:space:]]*//")"
;;
*)
val="$line"
;;
esac
# strip surrounding quotes
val="$(printf '%s' "$val" | sed "s/^['\"]//; s/['\"]$//")"
[ -n "$val" ] || continue
# skip dae example placeholders (ss://LINK, server-ip:port, localhost:1080 ...)
case "$val" in
*://LINK|*LINK*|*server-ip*|*://localhost:*|*example.com*) continue ;;
esac
sid="$(uci add dae "$stype")"
[ -n "$tag" ] && uci set "dae.$sid.tag=$tag"
uci set "dae.$sid.$field=$val"
uci set "dae.$sid.enabled=1"
done
}
do_import() {
[ -f "$CONFIG_DAE" ] || { echo "no config.dae" >&2; return 1; }
while uci -q delete dae.@subscription[0] >/dev/null 2>&1; do :; done
while uci -q delete dae.@node[0] >/dev/null 2>&1; do :; done
import_block subscription subscription url
import_block node node link
uci commit dae
echo "ok"
}
# ===================== entry =====================
case "$1" in
generate) generate ;;
import) do_import ;;
*) echo "usage: $0 {generate|import}" >&2; exit 2 ;;
esac
+32
View File
@@ -0,0 +1,32 @@
#!/bin/sh
# pkg-info.sh <package>
# Prints "<installed>\t<latest>" for the named package, where either field is
# empty when unknown. Used by the Updates view to decide whether to enable
# the [Upgrade] button.
PKG="$1"
case "$PKG" in
dae|daed|luci-app-daede) ;;
*) echo "" ; exit 64 ;;
esac
installed=""
latest=""
if command -v apk >/dev/null 2>&1; then
if apk info -e "$PKG" >/dev/null 2>&1; then
installed=$(apk list -I "$PKG" 2>/dev/null | awk -v p="$PKG" '
$1 ~ "^" p "-" {
sub("^" p "-", "", $1);
print $1;
exit
}
')
fi
latest=$(apk search "^${PKG}\$" 2>/dev/null | sort -V | tail -1 | sed "s/^${PKG}-//")
elif command -v opkg >/dev/null 2>&1; then
installed=$(opkg status "$PKG" 2>/dev/null | awk -F': ' '$1=="Version"{print $2; exit}')
latest=$(opkg info "$PKG" 2>/dev/null | awk -F': ' '$1=="Version"{print $2; exit}')
fi
printf '%s\t%s\n' "$installed" "$latest"
@@ -0,0 +1,27 @@
#!/bin/sh
# proxy-check.sh - test whether dae's transparent proxy can actually reach a
# blocked site (default YouTube). dae proxies the router's own WAN-bound traffic
# (wan_interface), so a plain request from here is routed through dae just like a
# LAN client would be. Prints one line: ok=<0|1> code=<http> ms=<n>
URL="${1:-https://www.youtube.com/generate_204}"
code=000
ms=0
if command -v curl >/dev/null 2>&1; then
out="$(curl -4 -sL --max-time 8 --connect-timeout 4 \
-o /dev/null -w '%{http_code} %{time_total}' "$URL" 2>/dev/null)"
code="$(printf '%s' "$out" | awk '{print $1}')"
t="$(printf '%s' "$out" | awk '{print $2}')"
[ -n "$code" ] || code=000
ms="$(awk -v x="${t:-0}" 'BEGIN{printf "%d", x*1000}')"
else
# busybox wget has no status/timing output — success is exit 0
if wget -q -T 8 -O /dev/null "$URL" 2>/dev/null; then code=204; else code=000; fi
fi
ok=0
case "$code" in 200|204|301|302) ok=1 ;; esac
echo "ok=$ok code=$code ms=$ms"
+69
View File
@@ -0,0 +1,69 @@
#!/bin/sh
# update-geo.sh <geoip|geosite>
# Fork-and-detach so the LuCI RPC call returns immediately. The diagnostics
# card polls the .dat file's mtime/size to detect completion. A lock file
# in /tmp prevents concurrent runs.
TYPE="$1"
case "$TYPE" in
geoip)
URL="https://github.com/v2fly/geoip/releases/latest/download/geoip.dat"
DEST="/usr/share/v2ray/geoip.dat"
;;
geosite)
URL="https://github.com/v2fly/domain-list-community/releases/latest/download/dlc.dat"
DEST="/usr/share/v2ray/geosite.dat"
;;
*)
echo "usage: $0 <geoip|geosite>" >&2
exit 64
;;
esac
LOCK="/tmp/luci-app-daede.${TYPE}.lock"
LOG="/tmp/luci-app-daede.${TYPE}.log"
if [ -f "$LOCK" ]; then
# Lock is fresh (< 5 min)? Refuse. Stale? Remove and proceed.
mtime=$(date -r "$LOCK" +%s 2>/dev/null || echo 0)
age=$(( $(date +%s) - mtime ))
if [ "$age" -lt 300 ]; then
echo "${TYPE} update already in progress (PID $(cat "$LOCK" 2>/dev/null), age ${age}s)" >&2
exit 75
fi
rm -f "$LOCK"
fi
if ! ( set -C; echo "$$" >"$LOCK" ) 2>/dev/null; then
echo "${TYPE} update already in progress" >&2
exit 75
fi
# Spawn detached worker — parent returns immediately to LuCI.
(
exec >"$LOG" 2>&1
trap 'rm -f "$LOCK"' EXIT INT TERM
TMP="${DEST}.new"
mkdir -p "$(dirname "$DEST")"
echo "$(date '+%F %T') begin: $URL"
if ! curl -fsSL --connect-timeout 15 --max-time 240 -o "$TMP" "$URL"; then
echo "$(date '+%F %T') download failed"
rm -f "$TMP"
exit 1
fi
size=$(wc -c < "$TMP" 2>/dev/null || echo 0)
if [ "$size" -lt 102400 ]; then
echo "$(date '+%F %T') file too small ($size bytes)"
rm -f "$TMP"
exit 2
fi
mv "$TMP" "$DEST"
echo "$(date '+%F %T') updated $DEST ($size bytes)"
) </dev/null >/dev/null 2>&1 &
echo "started in background, see $LOG"
exit 0
+68
View File
@@ -0,0 +1,68 @@
#!/bin/sh
# update-pkg.sh <dae|daed|luci-app-daede>
# Refresh package indexes and upgrade the named package via apk (25.12+) or
# opkg (24.10). Forks the work to background so the LuCI RPC call returns
# immediately; the result is streamed to /tmp/luci-app-daede.pkg.<name>.log.
PKG="$1"
case "$PKG" in
dae|daed|luci-app-daede) ;;
*)
echo "usage: $0 <dae|daed|luci-app-daede>" >&2
exit 64
;;
esac
LOCK="/tmp/luci-app-daede.pkg-${PKG}.lock"
LOG="/tmp/luci-app-daede.pkg-${PKG}.log"
if [ -f "$LOCK" ]; then
mtime=$(date -r "$LOCK" +%s 2>/dev/null || echo 0)
age=$(( $(date +%s) - mtime ))
if [ "$age" -lt 300 ]; then
echo "${PKG} update already in progress (PID $(cat "$LOCK" 2>/dev/null), age ${age}s)" >&2
exit 75
fi
rm -f "$LOCK"
fi
if ! ( set -C; echo "$$" >"$LOCK" ) 2>/dev/null; then
echo "${PKG} update already in progress" >&2
exit 75
fi
(
exec >"$LOG" 2>&1
trap 'rm -f "$LOCK"' EXIT INT TERM
echo "$(date '+%F %T') begin upgrade: $PKG"
if command -v apk >/dev/null 2>&1; then
echo "--- apk update ---"
apk update 2>&1
echo "--- apk upgrade $PKG ---"
# --no-self-upgrade so apk itself does not jump versions mid-op
apk upgrade --no-self-upgrade "$PKG" 2>&1
rc=$?
elif command -v opkg >/dev/null 2>&1; then
echo "--- opkg update ---"
opkg update 2>&1
echo "--- opkg upgrade $PKG ---"
opkg upgrade "$PKG" 2>&1
rc=$?
else
echo "no package manager found"
exit 3
fi
echo "$(date '+%F %T') done (rc=$rc)"
# luci-app-daede upgrade replaces ACL JSON — reload rpcd so changes apply.
if [ "$PKG" = "luci-app-daede" ] && [ "$rc" = "0" ]; then
echo "reloading rpcd to pick up new ACL"
/etc/init.d/rpcd reload 2>&1
fi
) </dev/null >/dev/null 2>&1 &
echo "started in background, see $LOG"
exit 0
@@ -0,0 +1,36 @@
{
"admin/services/daede": {
"title": "daede",
"order": 20,
"action": {
"type": "firstchild"
},
"depends": {
"acl": [ "luci-app-daede" ]
}
},
"admin/services/daede/config": {
"title": "Settings",
"order": 10,
"action": {
"type": "view",
"path": "daede/config"
}
},
"admin/services/daede/updates": {
"title": "Updates",
"order": 20,
"action": {
"type": "view",
"path": "daede/updates"
}
},
"admin/services/daede/log": {
"title": "Log",
"order": 30,
"action": {
"type": "view",
"path": "daede/log"
}
}
}
@@ -0,0 +1,74 @@
{
"luci-app-daede": {
"description": "Grant access to dae/daed configuration",
"read": {
"file": {
"/etc/init.d/dae": [ "read" ],
"/etc/init.d/daed": [ "read" ],
"/etc/config/daede": [ "read" ],
"/etc/dae/config.dae": [ "read" ],
"/etc/dae/example.dae": [ "read" ],
"/var/log/dae/dae.log": [ "read" ],
"/var/log/daed/daed.log": [ "read" ],
"/usr/share/v2ray/geoip.dat": [ "read" ],
"/usr/share/v2ray/geosite.dat": [ "read" ],
"/sys/kernel/btf/vmlinux": [ "read" ],
"/run/netns/daens": [ "read" ],
"/tmp/luci-app-daede.geoip.log": [ "read" ],
"/tmp/luci-app-daede.geosite.log": [ "read" ],
"/tmp/luci-app-daede.pkg-dae.log": [ "read" ],
"/tmp/luci-app-daede.pkg-daed.log": [ "read" ],
"/tmp/luci-app-daede.pkg-luci-app-daede.log": [ "read" ],
"/usr/bin/pgrep -x dae": [ "exec" ],
"/usr/bin/pgrep -x daed": [ "exec" ],
"/usr/bin/dae validate -c /tmp/dae-validate.dae": [ "exec" ],
"/usr/bin/dae --version": [ "exec" ],
"/bin/rm -f /tmp/dae-validate.dae": [ "exec" ],
"/usr/share/luci-app-daede/pkg-info.sh dae": [ "exec" ],
"/usr/share/luci-app-daede/pkg-info.sh daed": [ "exec" ],
"/usr/share/luci-app-daede/pkg-info.sh luci-app-daede": [ "exec" ],
"/usr/share/luci-app-daede/proxy-check.sh": [ "exec" ]
},
"ubus": {
"service": [ "list" ]
},
"uci": [ "dae", "daed", "daede" ]
},
"write": {
"file": {
"/etc/dae/config.dae": [ "write" ],
"/tmp/dae-validate.dae": [ "write" ],
"/etc/config/daede": [ "write" ],
"/var/log/dae/dae.log": [ "write" ],
"/var/log/daed/daed.log": [ "write" ],
"/etc/init.d/dae start": [ "exec" ],
"/etc/init.d/dae stop": [ "exec" ],
"/etc/init.d/dae restart": [ "exec" ],
"/etc/init.d/dae enable": [ "exec" ],
"/etc/init.d/dae disable": [ "exec" ],
"/etc/init.d/dae hot_reload": [ "exec" ],
"/etc/init.d/daed start": [ "exec" ],
"/etc/init.d/daed stop": [ "exec" ],
"/etc/init.d/daed restart": [ "exec" ],
"/etc/init.d/daed enable": [ "exec" ],
"/etc/init.d/daed disable": [ "exec" ],
"/sbin/uci set dae.config.enabled=*": [ "exec" ],
"/sbin/uci set daed.config.enabled=*": [ "exec" ],
"/sbin/uci set daede.config=daede": [ "exec" ],
"/sbin/uci set daede.config.active_backend=*": [ "exec" ],
"/sbin/uci commit dae": [ "exec" ],
"/sbin/uci commit daed": [ "exec" ],
"/sbin/uci commit daede": [ "exec" ],
"/sbin/ip netns del daens": [ "exec" ],
"/usr/share/luci-app-daede/update-geo.sh geoip": [ "exec" ],
"/usr/share/luci-app-daede/update-geo.sh geosite": [ "exec" ],
"/usr/share/luci-app-daede/update-pkg.sh dae": [ "exec" ],
"/usr/share/luci-app-daede/update-pkg.sh daed": [ "exec" ],
"/usr/share/luci-app-daede/update-pkg.sh luci-app-daede": [ "exec" ],
"/usr/share/luci-app-daede/gen-dae-config.sh generate": [ "exec" ],
"/usr/share/luci-app-daede/gen-dae-config.sh import": [ "exec" ]
},
"uci": [ "dae", "daed", "daede" ]
}
}
}