diff --git a/cloudreve/Makefile b/cloudreve/Makefile index 4303dd417..d5e5fd0c0 100644 --- a/cloudreve/Makefile +++ b/cloudreve/Makefile @@ -6,11 +6,11 @@ include $(TOPDIR)/rules.mk PKG_NAME:=cloudreve PKG_VERSION:=4.18.0 -PKG_RELEASE:=17 +PKG_RELEASE:=18 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/cloudreve/Cloudreve.git -PKG_SOURCE_VERSION:=ade1866be54a3614bc643ab5f513e93a1e0dc82f +PKG_SOURCE_VERSION:=e03a104a7d42a1fa46c697f57b66e550189350ea PKG_MIRROR_HASH:=skip PKG_LICENSE:=GPL-3.0-only diff --git a/luci-app-fwlive/Makefile b/luci-app-fwlive/Makefile index be339b602..cabe9ce80 100644 --- a/luci-app-fwlive/Makefile +++ b/luci-app-fwlive/Makefile @@ -12,7 +12,7 @@ LUCI_DEPENDS:=+luci-base +logd +jsonfilter LUCI_PKGARCH:=all PKG_VERSION:=0.1.41 -PKG_RELEASE:=15 +PKG_RELEASE:=16 # Reproducible build: honor SOURCE_DATE_EPOCH from the build environment (set by docker-sdk.sh / CI). ifdef SOURCE_DATE_EPOCH diff --git a/luci-app-fwlive/htdocs/luci-static/resources/fwlive/buffer.js b/luci-app-fwlive/htdocs/luci-static/resources/fwlive/buffer.js index d291d89c4..c3062127b 100644 --- a/luci-app-fwlive/htdocs/luci-static/resources/fwlive/buffer.js +++ b/luci-app-fwlive/htdocs/luci-static/resources/fwlive/buffer.js @@ -9,7 +9,7 @@ * * While paused, ingest grows up to fetchLinesMax. Live mode caps at rowLimit. * On resume, merge (do not replace) so pause-accumulated rows survive the first - * live poll — see issue #43 pause→resume data loss. + * live poll. */ function ingestCap(paused, rowLimit, fetchLinesMax) { diff --git a/luci-app-fwlive/htdocs/luci-static/resources/fwlive/constants.js b/luci-app-fwlive/htdocs/luci-static/resources/fwlive/constants.js index 668dfedbd..780fee2a9 100644 --- a/luci-app-fwlive/htdocs/luci-static/resources/fwlive/constants.js +++ b/luci-app-fwlive/htdocs/luci-static/resources/fwlive/constants.js @@ -12,13 +12,13 @@ return baseclass.extend({ APP_VERSION: '0.1.41', ROW_LIMIT_OPTIONS: [25, 50, 100, 250, 500, 1000, 2000], DEFAULT_ROW_LIMIT: 100, - /* Row pass/deny tint (#40): classic green/red default; accessible teal/orange */ + /* Row pass/deny tint: classic green/red default; accessible teal/orange */ ROW_TINT_OPTIONS: ['off', 'classic', 'accessible'], DEFAULT_ROW_TINT: 'classic', FETCH_LINES_MAX: 2000 /* ubus poll / logd ring cap (~2000 lines ≈ typical ring) */, /* DOM budget: ~250 new/updated rows painted per second on typical LuCI routers */ RENDER_CAP_PER_SEC: 250, - /* #306 Layer 2 — measured client RTT → poll cadence (seconds). */ + /* Layer 2 — measured client RTT → poll cadence (seconds). */ POLL_CADENCE_FAST_S: 1, POLL_CADENCE_MID_S: 2, POLL_CADENCE_SLOW_S: 5, diff --git a/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js b/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js index 13d795529..05e204241 100644 --- a/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js +++ b/luci-app-fwlive/htdocs/luci-static/resources/view/status/fwlive.js @@ -24,7 +24,7 @@ const callFwlivePoll = rpc.declare({ object: 'fwlive', method: 'poll', params: ['addresses'] - /* Full reply object kept so reply.error reaches fetchEntries (#233). */ + /* Full reply object kept so reply.error reaches fetchEntries. */ }); const callFwliveRules = rpc.declare({ @@ -36,7 +36,7 @@ const callFwliveResolve = rpc.declare({ object: 'fwlive', method: 'resolve', params: ['addresses'] - /* Full reply kept so disabled:"load" reaches the view (#306 Layer 2). */ + /* Full reply kept so disabled:"load" reaches the view. */ }); const callFwliveLoggingStatus = rpc.declare({ @@ -98,11 +98,11 @@ return view.extend({ sessionSeen: null, pauseBufferLoading: false, paused: false, - /* One-shot: first live poll after unpause merges instead of replacing (#43). */ + /* One-shot: first live poll after unpause merges instead of replacing. */ resumeMerge: false, pollFn: null, pollDataInFlight: false, - /* #306 Layer 2 — visibility / RTT cadence / shed surfacing. */ + /* Layer 2 — visibility / RTT cadence / shed surfacing. */ pollEpoch: 0, pollCadenceSec: 1, rttStreakKind: null, @@ -473,7 +473,7 @@ return view.extend({ const res = await callFwliveRules(); this.rulesMap = (res && res.rules) || {}; this.firewallBackend = (res && res.backend) || 'nft'; - /* Bounds / mktemp failures are reply.error — same idea as poll (#245). */ + /* Bounds / mktemp failures are reply.error — same idea as poll. */ this.lastRulesError = (res && res.error) || null; if (this.lastRulesError) console.warn('fwlive rules map error:', this.lastRulesError); } catch (e) { @@ -829,7 +829,7 @@ return view.extend({ return typeof document !== 'undefined' && !!document.hidden; }, - /* Classify one RTT sample into hysteresis buckets (#306). + /* Classify one RTT sample into hysteresis buckets. * error and >1.5s share the slow/degraded streak so mixed failures still trip N=3. */ rttKindFromMs(ms, errored) { if (errored) return 'slow'; @@ -1099,7 +1099,7 @@ return view.extend({ const limit = this.rowLimit; const suffix = this.statusSuffix(); /* While paused the buffer can grow past the display limit — count matches - * over the full buffer so "matching" is not capped at visibleRows (#83). */ + * over the full buffer so "matching" is not capped at visibleRows. */ let shown = matchCount; if (this.paused) { const filters = this.readFilters(); @@ -1206,7 +1206,7 @@ return view.extend({ if (wasPaused && !this.paused) { this.followLive = true; - /* Merge pause buffer with the first live poll — do not replace (#43). */ + /* Merge pause buffer with the first live poll — do not replace. */ this.resumeMerge = true; const epoch = this.pollEpoch; this.fetchEntries() @@ -1671,7 +1671,7 @@ return view.extend({ } } finally { /* Only the owning epoch clears — a stale hidden-era poll must not - * drop the catch-up guard after resume (Grok #331). Resume clears + * drop the catch-up guard after resume. Resume clears * explicitly before starting the catch-up poll. */ if (epoch === this.pollEpoch) this.pollDataInFlight = false; } diff --git a/luci-app-fwlive/root/usr/libexec/fwlive-adaptive-cap.sh b/luci-app-fwlive/root/usr/libexec/fwlive-adaptive-cap.sh index 9e78c8be2..5a2a48fa5 100755 --- a/luci-app-fwlive/root/usr/libexec/fwlive-adaptive-cap.sh +++ b/luci-app-fwlive/root/usr/libexec/fwlive-adaptive-cap.sh @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2025-2026 Lucas Albers # -# Layer 1 adaptive poll cap (#306). Sourced by rpcd/fwlive. +# Layer 1 adaptive poll cap. Sourced by rpcd/fwlive. # Always on unless test/triage override (no UCI / no product config): # FWLIVE_ADAPTIVE=0|false|off|no # or sentinel ${FWLIVE_ADAPTIVE_OFF_FILE:-/fwlive-adaptive-off} @@ -18,10 +18,10 @@ # flock, lock busy, or corrupt state. Lock-busy ⇒ unlocked last-writer-wins is # acceptable (state stays one valid JSON line; ordering is not guaranteed). # Failed ubus log.read must NOT call record() — a ~0 ms failure is not "cold" -# health and must not clear an existing hot/shed cap (#329 Hermes Q1). +# health and must not clear an existing hot/shed cap. # Outside the measured duration interval: plan (pre), record/merge (post). # messages_received is 0 in Layer 1 — do not ash-scan the filter JSON after -# end_cs (Grok #329 P1); accurate count belongs in the filter or a later layer. +# end_cs; accurate count belongs in the filter or a later layer. FWLIVE_ADAPTIVE_STATE_FILE="${FWLIVE_ADAPTIVE_STATE_FILE:-/var/run/fwlive-state.json}" # Optional overrides; when unset, lock/off paths are siblings of the current state. @@ -238,7 +238,7 @@ fwlive_adaptive_with_lock() { "$@" return $? fi - # Create lock at 0600 (logging.lock #167 — world-readable fd can take LOCK_EX). + # Create lock at 0600 (world-readable fd can take LOCK_EX). if [ ! -e "$_lock" ]; then if ! ( umask 077; : >"$_lock" ) 2>/dev/null; then "$@" @@ -424,7 +424,7 @@ fwlive_adaptive_merge_reply() { } # Count log[*] via "msg" keys — helper for tests / future filter-side count. -# NOT called on the poll hot path (Grok #329 P1): ash-scanning a 2000-entry +# NOT called on the poll hot path: ash-scanning a 2000-entry # reply after end_cs is unmeasured overhead that cannot shed itself. fwlive_adaptive_count_log() { _json=$1 diff --git a/luci-app-fwlive/root/usr/libexec/fwlive-log-filter.sh b/luci-app-fwlive/root/usr/libexec/fwlive-log-filter.sh index 5c2458fd5..35562bd60 100755 --- a/luci-app-fwlive/root/usr/libexec/fwlive-log-filter.sh +++ b/luci-app-fwlive/root/usr/libexec/fwlive-log-filter.sh @@ -6,11 +6,11 @@ # Log messages are treated as data (jsonfilter + awk stdin); never interpolated # into shell command strings. Usage: ubus call log read '...' | fwlive-log-filter.sh # -# Perf (#219): one jsonfilter for @.log[*] plus one awk classify. Process +# Perf: one jsonfilter for @.log[*] plus one awk classify. Process # count is constant per poll, not O(entries). # # Entry point (pipeline). The classifier sibling is sourced and must not set -# strict mode itself (#291 C3). +# strict mode itself. set -eu # shellcheck disable=SC3040 (set -o pipefail) 2>/dev/null && set -o pipefail @@ -26,7 +26,7 @@ FILTER_DIR="$(cd "$(dirname "$0")" && pwd)" . "$FILTER_DIR/fwlive-is-firewall-event.sh" # The classifier is a package asset, not generated at request time. Fail -# closed if an incomplete install or a damaged package removed it (#321). +# closed if an incomplete install or a damaged package removed it. if [ ! -r "$CLASSIFY_AWK" ]; then printf '%s' '{"log":[],"error":"classifier_missing"}' exit 1 @@ -35,8 +35,8 @@ fi printf '%s' '{"log":[' # Prefer stdin over -s: Linux MAX_ARG_STRLEN is 128KiB; a raised logd ring # (or paused FETCH_LINES_MAX poll) can exceed that and make jsonfilter fail -# while this script still printed {"log":[]} and exited 0 (#234). -# jsonfilter miss / empty @.log is not fatal; must still close JSON (#220). -# set -e + pipefail cannot apply to this pipeline (#291 C3). +# while this script still printed {"log":[]} and exited 0. +# jsonfilter miss / empty @.log is not fatal; must still close JSON. +# set -e + pipefail cannot apply to this pipeline. jsonfilter -e '@.log[*]' 2>/dev/null | _fwlive_filter_json_entries || true printf '%s' ']}' diff --git a/luci-app-fwlive/root/usr/libexec/fwlive-logging.sh b/luci-app-fwlive/root/usr/libexec/fwlive-logging.sh index b9a67accd..3cab14eb8 100755 --- a/luci-app-fwlive/root/usr/libexec/fwlive-logging.sh +++ b/luci-app-fwlive/root/usr/libexec/fwlive-logging.sh @@ -7,13 +7,13 @@ # Sourced library (rpcd plugin, package prerm). Do not `set -euo pipefail` # here: prerm is best-effort (`restore ... || logger`; exit 0) and callers # expect soft failures. The rpcd entry point enables strict mode; critical -# paths use explicit `|| return 1` / `|| true` (#244, #291 C3). +# paths use explicit `|| return 1` / `|| true`. NF_LOG_IPV4='/proc/sys/net/netfilter/nf_log/2' NF_LOG_IPV6='/proc/sys/net/netfilter/nf_log/10' # Serialize the WAN logging read->compute->set->commit window across -# concurrent ubus write-ACL callers (#151): each toggle re-reads the current +# concurrent ubus write-ACL callers: each toggle re-reads the current # firewall..log bit, computes a target, then uci set + uci commit. Two # concurrent callers could otherwise interleave and last-commit-wins. # @@ -28,7 +28,7 @@ WAN_LOG_LOCK_FILE="${FWLIVE_WAN_LOG_LOCK_FILE:-/etc/fwlive/logging.lock}" WAN_LOG_BASELINE_FILE="${FWLIVE_WAN_LOG_BASELINE_FILE:-/etc/fwlive/wan-log-baseline}" # RFC 8259 string escape. Lives here so prerm can source this file -# standalone (#222). rpcd sources us and must not redefine this. +# standalone. rpcd sources us and must not redefine this. json_escape() { # Escape for JSON string content per RFC 8259 (including remaining C0 controls). # Slurp stdin as one string. Default awk RS is newline — RS="" is @@ -67,8 +67,8 @@ json_escape() { }' } -# Production lock dir must be owned by euid with no group/other write (#204). -# Avoid GNU/BusyBox `stat -c` — stock OpenWrt omits FEATURE_STAT_FORMAT (#232). +# Production lock dir must be owned by euid with no group/other write. +# Avoid GNU/BusyBox `stat -c` — stock OpenWrt omits FEATURE_STAT_FORMAT. wan_log_lock_dir_safe() { dir="$1" [ -n "$dir" ] || return 1 @@ -86,10 +86,10 @@ wan_log_lock_dir_safe() { # Acquire the exclusive logging lock on fd 9. Blocks until free; fails closed # (return 1) only if the lock file cannot be opened or flock is unavailable. # Create/tighten the lock to 0600 so unprivileged UIDs cannot take LOCK_EX on -# a world-readable fd (issue #167 / flock(2) allows exclusive locks on O_RDONLY). +# a world-readable fd (flock(2) allows exclusive locks on O_RDONLY). acquire_wan_log_lock() { # Fail closed on symlinks: chmod/chown/exec O_TRUNC follow the target as root - # (#204). Default lock lives under /etc/fwlive (root-only), not world-writable + # Default lock lives under /etc/fwlive (root-only), not world-writable # /var/lock. Re-check after create/tighten (TOCTOU). lock_dir="$(dirname "$WAN_LOG_LOCK_FILE")" [ -L "$lock_dir" ] && return 1 @@ -107,7 +107,7 @@ acquire_wan_log_lock() { # Probe in a subshell first: a failed `exec` redirection aborts a POSIX # non-interactive shell outright, so `|| return 1` on the real exec would # never run — and `2>/dev/null` on the same exec would permanently - # silence this process's stderr on the success path (#244). + # silence this process's stderr on the success path. ( exec 9>>"$WAN_LOG_LOCK_FILE" ) 2>/dev/null || return 1 exec 9>>"$WAN_LOG_LOCK_FILE" flock 9 2>/dev/null || { @@ -124,16 +124,16 @@ release_wan_log_lock() { find_wan_zone_section() { # Match anonymous (@zone[N]) and named (e.g. wan) sections whose name option - # is 'wan'. Prefer the first section whose type is zone (issue #168); skip + # is 'wan'. Prefer the first section whose type is zone; skip # non-zone sections that happen to share name='wan'. # uci missing / no wan zone is empty, not fatal. pipefail + set -e - # cannot apply to this pipeline (#291 C3). + # cannot apply to this pipeline. _zones=$(uci -q show firewall 2>/dev/null \ | sed -n "s/^firewall\.\([^.]*\)\.name='wan'$/\1/p") || true for zone in $_zones; do [ -n "$zone" ] || continue # uci -q get exits 1 on a missing section. Capture with || true so - # set -e cannot abort inside "$(…)" before || continue (#291 C3). + # set -e cannot abort inside "$(…)" before || continue. _type=$(uci -q get "firewall.${zone}" 2>/dev/null || true) [ "$_type" = "zone" ] || continue printf '%s' "$zone" @@ -143,7 +143,7 @@ find_wan_zone_section() { } firewall_changes_pending() { - # uci miss is "no pending changes". set -e cannot apply (#291 C3). + # uci miss is "no pending changes". set -e cannot apply. pending="$(uci -q changes firewall 2>/dev/null || true)" [ -n "$pending" ] } @@ -151,7 +151,7 @@ firewall_changes_pending() { wan_zone_log_value() { zone="$1" [ -n "$zone" ] || return 1 - # Unset option is a valid empty value; uci -q get exits 1 (#291 C3). + # Unset option is a valid empty value; uci -q get exits 1. uci -q get "firewall.${zone}.log" 2>/dev/null || true } @@ -165,7 +165,7 @@ uci_canonical_firewall_section() { | sed -n '1s/^firewall\.\([^=.]*\)=.*/\1/p' } -# True when two firewall section ids refer to the same WAN zone (issue #239). +# True when two firewall section ids refer to the same WAN zone. # Compare canonical cfg ids — do NOT treat every name=wan zone as identical # (duplicate wan sections would under-match foreign .log deltas as ours). wan_firewall_zone_same() { @@ -196,7 +196,7 @@ wan_log_staged_line_section() { esac } -# Zone ids that may appear in `uci changes` for firewall..log (issue #239). +# Zone ids that may appear in `uci changes` for firewall..log. wan_log_staged_zone_ids() { _zone="$1" _staged="$2" @@ -296,7 +296,7 @@ maybe_snapshot_wan_log_baseline() { restore_wan_log_baseline() { path="$(wan_log_baseline_path)" [ -f "$path" ] || return 0 - # Empty file is a valid "option was unset" baseline (#291 C3). + # Empty file is a valid "option was unset" baseline. baseline=$(cat "$path" 2>/dev/null || true) zone=$(find_wan_zone_section) if [ -z "$zone" ]; then @@ -417,18 +417,18 @@ collect_logging_blockers() { check_nf_log_ipv6 || logging_blockers_append 'nf_log_ipv6_missing' # Report via LOGGING_BLOCKERS, not exit status: return 1 would abort - # build_logging_status_json under set -e (#291 C3). + # build_logging_status_json under set -e. return 0 } collect_logging_warnings() { LOGGING_WARNINGS='' - # rpcd/fwlive run_with_timeout fail-closes to 127 without timeout (#229). + # rpcd/fwlive run_with_timeout fail-closes to 127 without timeout. # Warnings are diagnostics only — do not gate the enable-logging CTA. command -v timeout >/dev/null 2>&1 || logging_warnings_append 'timeout_missing' - # Report via LOGGING_WARNINGS, not exit status (#291 C3). + # Report via LOGGING_WARNINGS, not exit status. return 0 } @@ -444,9 +444,9 @@ json_null_or_string() { build_logging_status_json() { zone=$(find_wan_zone_section) - # Empty zone / unset log bit are valid; set -e cannot apply (#291 C3). + # Empty zone / unset log bit are valid; set -e cannot apply. log_val=$(wan_zone_log_value "$zone") || log_val= - # Unset log_limit is a valid empty value; uci -q get exits 1 (#291 C3). + # Unset log_limit is a valid empty value; uci -q get exits 1. limit_val= if [ -n "$zone" ]; then limit_val=$(uci -q get "firewall.${zone}.log_limit" 2>/dev/null || true) @@ -491,7 +491,7 @@ restore_wan_zone_log() { zone="$1" previous="$2" [ -n "$zone" ] || return 1 - # Refuse to publish unrelated staged firewall deltas (issue #168). + # Refuse to publish unrelated staged firewall deltas. if firewall_changes_pending; then logger -t fwlive "WAN log rollback skipped: firewall changes pending" 2>/dev/null || true return 1 @@ -508,7 +508,7 @@ restore_wan_zone_log() { # closes the read->compute->set->commit window so a concurrent toggle cannot # commit between our read and our write (no lost update / no stale overwrite). # -# TOCTOU hardening (#191): UCI staging is global per config file, so a +# TOCTOU hardening: UCI staging is global per config file, so a # non-cooperating writer (another admin's `uci set`, the LuCI firewall page) # can stage a delta AFTER the toggle's early firewall_changes_pending check. # Staging and committing therefore live INSIDE this function — the only path @@ -544,7 +544,7 @@ commit_wan_log_change() { zone_json="$2" target="$3" - # Last-moment guard (#191): runs before OUR delta is staged, so a + # Last-moment guard: runs before OUR delta is staged, so a # non-empty changes list here can only be a foreign writer's race. if firewall_changes_pending; then logger -t fwlive "WAN log toggle aborted at commit gate: firewall changes staged by another writer" 2>/dev/null || true @@ -568,7 +568,7 @@ commit_wan_log_change() { fi fi - # Post-stage guard (#191): anything besides our log option is foreign. + # Post-stage guard: anything besides our log option is foreign. # Undo our staging only (set previous / delete to match committed); leave # foreign deltas untouched and abort without commit. _staged=$(uci -q changes firewall 2>/dev/null || true) @@ -589,8 +589,8 @@ commit_wan_log_change() { # firewall_changes_pending from this package's own orphaned write — # but ONLY when nothing foreign is staged: `uci revert firewall` is # config-wide (uci has no option-level revert), and reverting would - # clobber a concurrent writer's uncommitted delta (CodeRabbit/luna - # fold, #191). With foreign staging present, leave it and warn. + # clobber a concurrent writer's uncommitted delta. With foreign + # staging present, leave it and warn. _staged=$(uci -q changes firewall 2>/dev/null || true) _total=$(printf '%s\n' "$_staged" | grep -c . 2>/dev/null || true) _ours=$(wan_log_count_our_staged_lines "$zone" "$_staged") @@ -603,7 +603,7 @@ commit_wan_log_change() { return 1 fi - # Post-commit verification (#191): confirm the committed config really + # Post-commit verification: confirm the committed config really # carries what we wrote (empty target = option must now be gone/empty). # A mismatch means another writer overtook the commit: warn loudly but do # NOT blind-revert (that would destroy unrelated committed data); the @@ -619,7 +619,7 @@ commit_wan_log_change() { # would block a concurrent toggle until the holder exits — BusyBox flock has # no -w timeout). # -# The ROLLBACK re-acquires the lock (luna fold 2026-08-10): read->compare-> +# The ROLLBACK re-acquires the lock: read->compare-> # restore is only atomic when no other writer can commit between the read and # the restore. All writers hold the same flock, so re-acquiring it makes the # decision-and-restore a serialized unit. The lock is held only for the few @@ -686,7 +686,7 @@ enable_wan_logging() { # The log bit is re-read AFTER acquiring the lock so the target is computed # from the latest committed value; a concurrent toggle cannot interleave. # Staging + commit live inside commit_wan_log_change behind its last-moment - # firewall_changes_pending re-check (#191): a foreign writer racing between + # firewall_changes_pending re-check: a foreign writer racing between # the early check above and the commit aborts the toggle instead of having # its half-finished delta published with our log bit. if ! acquire_wan_log_lock; then @@ -740,7 +740,7 @@ disable_wan_logging() { # The log bit is re-read AFTER acquiring the lock so the target is computed # from the latest committed value; a concurrent toggle cannot interleave. # Staging + commit live inside commit_wan_log_change behind its last-moment - # firewall_changes_pending re-check (#191): a foreign writer racing between + # firewall_changes_pending re-check: a foreign writer racing between # the early check above and the commit aborts the toggle instead of having # its half-finished delta published with our log bit. if ! acquire_wan_log_lock; then diff --git a/luci-app-fwlive/root/usr/libexec/rpcd/fwlive b/luci-app-fwlive/root/usr/libexec/rpcd/fwlive index 09724e264..118023715 100755 --- a/luci-app-fwlive/root/usr/libexec/rpcd/fwlive +++ b/luci-app-fwlive/root/usr/libexec/rpcd/fwlive @@ -23,7 +23,7 @@ ADAPTIVE_SH="$LIBEXEC_DIR/fwlive-adaptive-cap.sh" RESOLVE_MAX=32 # Per-lookup nslookup timeout (integer seconds — BusyBox `timeout` truncates # fractional values to 0 on OpenWrt 23.05/1.36, so 0.5 would silently -# degrade to no timeout; luna fold 2026-08-10). The wall-clock budget +# degrade to no timeout.. The wall-clock budget # below is the real whole-call bound; this per-lookup cap only prevents a # single hung resolver from dominating the budget. LAN/local-resolver # lookups are single-digit ms, so 1s is ample. Passed as argv to @@ -42,7 +42,7 @@ NFT_TIMEOUT=5 # CLI-only iptables fixture path for __rulesmap_iptables (no arbitrary paths). RULESMAP_IPTABLES_FILE='/tmp/rulesmap' -# json_escape lives in fwlive-logging.sh so prerm can source that file alone (#222). +# json_escape lives in fwlive-logging.sh so prerm can source that file alone. # shellcheck disable=SC1090,SC1091 # LOGGING_SH resolves to sibling ../fwlive-logging.sh . "$LOGGING_SH" # shellcheck disable=SC1090,SC1091 @@ -52,10 +52,10 @@ slug_key() { echo "$1" | tr '[:upper:]' '[:lower:]' | tr ' _' '--' } -# Cap rules JSON size so a huge ruleset cannot unbound an rpcd reply (#229). +# Cap rules JSON size so a huge ruleset cannot unbound an rpcd reply. RULES_MAP_MAX_KEYS=512 RULES_MAP_MAX_BYTES=65536 -# Same wall-clock bound as nft for iptables-save / ip6tables-save (#229). +# Same wall-clock bound as nft for iptables-save / ip6tables-save. # Overridable for host tests (e.g. FWLIVE_IPTABLES_TIMEOUT=1). IPTABLES_TIMEOUT="${FWLIVE_IPTABLES_TIMEOUT:-5}" @@ -70,7 +70,7 @@ map_add() { # ("foo" vs "foobar") and value false positives ("see foo"). # Quoting "$esc_key" makes the match literal (no glob escaping needed). # Callers apply UCI, then labeled (!fw4:) prefixes, then unlabeled - # cosmetics so first-wins prefers authoritative names (#230). + # cosmetics so first-wins prefers authoritative names. case "$OUT" in *"\"$esc_key\":"*) return 0 ;; esac @@ -92,7 +92,7 @@ map_add() { uci_rule_names() { # uci missing / empty firewall config is "no names", not fatal. - # pipefail + set -e cannot apply to this pipeline (#291 C3). + # pipefail + set -e cannot apply to this pipeline. uci -q show firewall 2>/dev/null | sed -n "s/^firewall\.@rule\[[0-9]*\]\.name='\(.*\)'$/\1/p" || true } @@ -142,7 +142,7 @@ run_with_timeout() { if command -v timeout >/dev/null 2>&1; then timeout "$secs" "$@" 2>/dev/null else - # Fail closed (#229): never run unbounded when timeout is absent. + # Fail closed: never run unbounded when timeout is absent. return 127 fi } @@ -170,7 +170,7 @@ map_uci_rule_names() { # Line-wise (here-doc, not an unquoted for-loop) so a name with # spaces stays one token. Names that fail is_uci_style_name are # skipped: parseRuleHint() cannot match them, and fragments of - # "My Rule" must not shadow a real rule named Rule (#226). + # "My Rule" must not shadow a real rule named Rule. # The while-read stays in the current shell (here-doc, not a # pipeline) so map_add mutations reach OUT. while IFS= read -r name || [ -n "$name" ]; do @@ -187,7 +187,7 @@ EOF } # pass=labeled|unlabeled|all — labeled before unlabeled so !fw4: beats -# an earlier cosmetic for the same prefix under first-wins (#230). +# an earlier cosmetic for the same prefix under first-wins. map_from_nft_stream() { pass="${1:-all}" while IFS= read -r line; do @@ -255,7 +255,7 @@ _fwlive_tmp_dir_ok() { # Fail closed unless the dump dir is a real directory with the sticky # bit. Without sticky, another uid can unlink a just-created mktemp # file and replace it with a symlink before we reopen with `>` as - # root (same class as #204). Optional $1 is for CLI tests; production + # root (same class as the WAN logging lock). Optional $1 is for CLI tests; production # always uses /tmp. dir="${1:-/tmp}" [ -n "$dir" ] || return 1 @@ -288,7 +288,7 @@ build_rules_map() { backend=$(detect_firewall_backend) # UCI first, then labeled stream prefixes, then unlabeled cosmetics - # (#230). First-wins keeps UCI over nft and !fw4: over cosmetic. + # First-wins keeps UCI over nft and !fw4: over cosmetic. map_uci_rule_names case "$backend" in @@ -435,16 +435,16 @@ fetch_firewall_logs() { shed_flag=${2:-0} # Adaptive plan prints: lines shed bucket start_cs=$(fwlive_adaptive_clock_cs) - # Drop dead oneshot flag — only consumed on logd's stream branch (#306). + # Drop dead oneshot flag — only consumed on logd's stream branch. if ! raw=$(ubus call log read "{\"lines\":$lines,\"stream\":false}" 2>/dev/null); then # Do not record ~0 ms as cold: failure is not healthy fast processing - # and must not clear an existing hot/shed cap (#329 Hermes Q1). + # and must not clear an existing hot/shed cap. out='{"log":[],"error":"log_read_failed"}' fwlive_adaptive_merge_reply "$out" "$shed_flag" "$lines" 0 0 return 0 fi - # Do not swallow a filter failure into a silent empty table (#220). + # Do not swallow a filter failure into a silent empty table. # If the filter exits non-zero but still printed JSON, keep it. # Empty success is not valid poll JSON — the shipped filter always # prints {"log":[...]}, but a stub/regression must not emit a blank body. @@ -455,12 +455,12 @@ fetch_firewall_logs() { fi [ -n "$out" ] || out='{"log":[],"error":"filter_empty"}' end_cs=$(fwlive_adaptive_clock_cs) - # Uptime wrap / skew: end < start — do not record as cold (Grok #329 P2). + # Uptime wrap / skew: end < start — do not record as cold. if [ "$end_cs" -ge "$start_cs" ]; then _dur=$(((end_cs - start_cs) * 10)) fwlive_adaptive_record "$_dur" "$lines" fi - # Layer 1: messages_received stays 0 — no post-filter ash count (Grok #329 P1). + # Layer 1: messages_received stays 0 — no post-filter ash count. _trunc=0 [ "$shed_flag" = 1 ] && _trunc=1 [ "$lines" -lt "$requested" ] && _trunc=1 @@ -502,7 +502,7 @@ resolve_hostname() { [ -n "$ip" ] || return 1 is_resolvable_address "$ip" || return 1 command -v nslookup >/dev/null 2>&1 || return 1 - # timeout/nslookup miss is "no PTR", not a plugin abort (#291 C3). + # timeout/nslookup miss is "no PTR", not a plugin abort. out=$(run_with_timeout "$RESOLVE_TIMEOUT" nslookup "$ip") || return 1 [ -n "$out" ] || return 1 name=$(parse_nslookup_name "$out") || return 1 @@ -510,7 +510,7 @@ resolve_hostname() { printf '%s' "$name" } -# Strict IPv4/IPv6 validation before nslookup (issue #190): the old char-class +# Strict IPv4/IPv6 validation before nslookup: the old char-class # check admitted hostname-shaped tokens of hex chars + dots/colons # (e.g. "dead.beef.cafe.baad"), letting the resolver fall back to upstream DNS # queries chosen by an authenticated session. Validate the real address @@ -523,7 +523,7 @@ is_resolvable_address() { # Reject anything outside the address alphabet BEFORE awk, so embedded # newlines/whitespace (which awk would treat as record separators) can # never let a valid first record mask trailing garbage that still reaches - # nslookup (#190, CodeRabbit/luna fold): nslookup only ever sees a single + # nslookup: nslookup only ever sees a single # token. Note the check intentionally allows only hex/colon/dot. case "$addr" in *[!0-9a-fA-F:.]*) return 1 ;; @@ -596,7 +596,7 @@ is_resolvable_address() { } resolve_addresses() { - # Missing resolver must not look like "no PTR" (#218). Check before + # Missing resolver must not look like "no PTR". Check before # starting the budget clock or reading stdin. if ! command -v nslookup >/dev/null 2>&1; then command -v logger >/dev/null 2>&1 && logger -t fwlive "nslookup not found; resolve disabled" @@ -604,14 +604,14 @@ resolve_addresses() { return 0 fi - # Load shed: previous poll was hot (#306 Layer 1). + # Load shed: previous poll was hot. if fwlive_adaptive_is_hot; then printf '{"names":{},"disabled":"load"}' return 0 fi - # Wall-clock budget clock starts at the TRUE function entry (luna - # folds 2026-08-10): the budget must bound the whole call — including + # Wall-clock budget clock starts at the TRUE function entry: the + # budget must bound the whole call — including # read_rpc_input (stalled stdin must not escape the budget) and json # parsing. `date +%s` can jump under NTP sync — accepted (worst case # the budget over- or under-runs by the jump; worker starvation is @@ -657,12 +657,12 @@ resolve_addresses() { # never START a lookup past the budget. now=$(date +%s) [ $((now - start)) -ge "$RESOLVE_BUDGET" ] && break - # Missing/empty element: set -u cannot read bare $ip (#291 C3). + # Missing/empty element: set -u cannot read bare $ip. if ! is_resolvable_address "${ip:-}"; then continue fi # NXDOMAIN / timeout: resolve_hostname returns 1. set -e - # cannot apply to this assignment (#291 C3). + # cannot apply to this assignment. name=$(resolve_hostname "$ip") || name= if [ -n "$name" ]; then map_add "$ip" "$name" @@ -729,7 +729,7 @@ run_selftest() { return 1 fi - # Issue #190: hostname-shaped tokens of hex chars + dots/colons passed the + # hostname-shaped tokens of hex chars + dots/colons passed the # old char-class check and made the resolver fall back to upstream DNS. Each case # below must REJECT (and would be ACCEPTED by the reverted char-class code). if is_resolvable_address 'ab.cd.ef.01'; then @@ -757,7 +757,7 @@ run_selftest() { echo 'is_resolvable_address: expected accept IPv6-mapped ::ffff:192.0.2.1' >&2 return 1 fi - # Multi-line input must be rejected wholesale (CodeRabbit/luna fold): awk + # Multi-line input must be rejected wholesale: awk # reads newline-separated records, so a valid first record must not mask # trailing garbage that would still reach nslookup. if is_resolvable_address "$(printf '192.0.2.1\nnot-an-address')"; then @@ -849,7 +849,7 @@ Address: 127.0.0.1:53") run_logging_selftest || return 1 - # Strict-mode smoke (#291 C3): status JSON uses soft-fail helpers + # Strict-mode smoke: status JSON uses soft-fail helpers # (uci miss, empty WAN zone). Must not abort under dash/ash set -e. _status=$(build_logging_status_json) || { echo "build_logging_status_json: aborted under set -e" >&2 @@ -950,7 +950,7 @@ case "${1:-}" in build_rules_map ;; poll) - # rpcd may omit argv $3 and pass JSON on stdin (#291 C3). + # rpcd may omit argv $3 and pass JSON on stdin. poll_logs "${3:-}" ;; resolve) diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index 65f5a12dd..c1510e612 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall PKG_VERSION:=26.9.9 -PKG_RELEASE:=274 +PKG_RELEASE:=275 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua index c38786005..89e38db31 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua @@ -20,7 +20,10 @@ for _, k in ipairs(com.order) do if k ~= "chinadns-ng" then o = s:option(Value, k:gsub("%-","_") .. "_file", translatef("%s App Path", v.name)) o.default = v.default_path or ("/usr/bin/" .. k) - o.rmempty = false + o.placeholder = o.default + function o:remove(section) + self:write(section, self.default) + end end end diff --git a/luci-app-passwall/root/usr/share/passwall/iptables.sh b/luci-app-passwall/root/usr/share/passwall/iptables.sh index 405d54576..2e19f6dca 100755 --- a/luci-app-passwall/root/usr/share/passwall/iptables.sh +++ b/luci-app-passwall/root/usr/share/passwall/iptables.sh @@ -408,16 +408,16 @@ load_acl() { else [ -n "${DIRECT_DNSMASQ_PORT}" ] && dns_redirect=${DIRECT_DNSMASQ_PORT} fi - if [ -n "${dns_redirect}" ]; then + if ([ -n "$tcp_port" ] || [ -n "$udp_port" ]) && [ -n "$dns_redirect" ]; then $ipt_m -A PSW $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN - [ "$_ipv4" != "1" ] && $ip6t_m -A PSW $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null + $ip6t_m -A PSW $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null $ipt_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN - [ "$_ipv4" != "1" ] && $ip6t_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null + $ip6t_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null $ipt_n -A PSW_DNS $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j REDIRECT --to-ports ${dns_redirect} - [ "$_ipv4" != "1" ] && $ip6t_n -A PSW_DNS $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j REDIRECT --to-ports ${dns_redirect} 2>/dev/null + $ip6t_n -A PSW_DNS $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j REDIRECT --to-ports ${dns_redirect} 2>/dev/null $ipt_n -A PSW_DNS $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j REDIRECT --to-ports ${dns_redirect} - [ "$_ipv4" != "1" ] && $ip6t_n -A PSW_DNS $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j REDIRECT --to-ports ${dns_redirect} 2>/dev/null - [ -z "$(get_cache_var "ACL_${sid}_default")" ] && echolog " - ${msg}节点不同于全局配置,DNS 重定向到专用服务器[${dns_redirect}]。" + $ip6t_n -A PSW_DNS $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j REDIRECT --to-ports ${dns_redirect} 2>/dev/null + [ -z "$(get_cache_var "ACL_${sid}_default")" ] && echolog " - ${msg}节点不同于全局配置,DNS 重定向到专用服务器[${dns_redirect}]" fi [ -n "$tcp_port" ] || [ -n "$udp_port" ] && { @@ -597,7 +597,7 @@ load_acl() { [ -n "${DIRECT_DNSMASQ_PORT}" ] && DNS_REDIRECT=${DIRECT_DNSMASQ_PORT} fi - if [ -n "${DNS_REDIRECT}" ]; then + if ([ -n "${TCP_PROXY_MODE}" ] || [ -n "${UDP_PROXY_MODE}" ]) && [ -n "$DNS_REDIRECT" ]; then $ipt_m -A PSW $(comment "默认") -p udp --dport 53 -j RETURN $ip6t_m -A PSW $(comment "默认") -p udp --dport 53 -j RETURN 2>/dev/null $ipt_m -A PSW $(comment "默认") -p tcp --dport 53 -j RETURN @@ -606,6 +606,7 @@ load_acl() { $ip6t_n -A PSW_DNS $(comment "默认") -p udp --dport 53 -j REDIRECT --to-ports ${DNS_REDIRECT} 2>/dev/null $ipt_n -A PSW_DNS $(comment "默认") -p tcp --dport 53 -j REDIRECT --to-ports ${DNS_REDIRECT} $ip6t_n -A PSW_DNS $(comment "默认") -p tcp --dport 53 -j REDIRECT --to-ports ${DNS_REDIRECT} 2>/dev/null + echolog " - ${msg}DNS 重定向到专用服务器[${DNS_REDIRECT}]" fi [ -n "${TCP_PROXY_MODE}" ] || [ -n "${UDP_PROXY_MODE}" ] && { diff --git a/luci-app-passwall/root/usr/share/passwall/nftables.sh b/luci-app-passwall/root/usr/share/passwall/nftables.sh index 26c0c5342..5338df09c 100755 --- a/luci-app-passwall/root/usr/share/passwall/nftables.sh +++ b/luci-app-passwall/root/usr/share/passwall/nftables.sh @@ -471,26 +471,13 @@ load_acl() { fi if ([ -n "$tcp_port" ] || [ -n "$udp_port" ]) && [ -n "$dns_redirect" ]; then - if [ "$PROXY_IPV6" = "1" ]; then - nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp ${_ipt_source} udp dport 53 counter accept" - nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp ${_ipt_source} tcp dport 53 counter accept" - nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto udp ${_ipt_source} udp dport 53 counter redirect to :$dns_redirect comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto tcp ${_ipt_source} tcp dport 53 counter redirect to :$dns_redirect comment \"$remarks\"" - else - nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp ${_ipt_source} udp dport 53 counter accept" - nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol tcp ${_ipt_source} tcp dport 53 counter accept" - nft "add rule $NFTABLE_NAME PSW_DNS ip protocol udp ${_ipt_source} udp dport 53 counter redirect to :$dns_redirect comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW_DNS ip protocol tcp ${_ipt_source} tcp dport 53 counter redirect to :$dns_redirect comment \"$remarks\"" - fi - [ -z "$(get_cache_var "ACL_${sid}_default")" ] && echolog " - ${msg}节点不同于全局配置,DNS 重定向到专用服务器[${dns_redirect}]。" - else - if [ "$PROXY_IPV6" = "1" ]; then - nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\"" - else - nft "add rule $NFTABLE_NAME PSW_DNS ip protocol udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW_DNS ip protocol tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\"" - fi + nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto udp ${_ipt_source} udp dport 53 counter redirect to :$dns_redirect comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto tcp ${_ipt_source} tcp dport 53 counter redirect to :$dns_redirect comment \"$remarks\"" + [ -z "$(get_cache_var "ACL_${sid}_default")" ] && echolog " - ${msg}节点不同于全局配置,DNS 重定向到专用服务器[${dns_redirect}]" fi [ -n "$tcp_port" ] || [ -n "$udp_port" ] && { @@ -670,25 +657,13 @@ load_acl() { fi if ([ -n "${TCP_PROXY_MODE}" ] || [ -n "${UDP_PROXY_MODE}" ]) && [ -n "$DNS_REDIRECT" ]; then - if [ "$PROXY_IPV6" = "1" ]; then - nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp udp dport 53 counter accept" - nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp tcp dport 53 counter accept" - nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto udp udp dport 53 counter redirect to :$DNS_REDIRECT comment \"默认\"" - nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto tcp tcp dport 53 counter redirect to :$DNS_REDIRECT comment \"默认\"" - else - nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp udp dport 53 counter accept" - nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol tcp tcp dport 53 counter accept" - nft "add rule $NFTABLE_NAME PSW_DNS ip protocol udp udp dport 53 counter redirect to :$DNS_REDIRECT comment \"默认\"" - nft "add rule $NFTABLE_NAME PSW_DNS ip protocol tcp tcp dport 53 counter redirect to :$DNS_REDIRECT comment \"默认\"" - fi - else - if [ "$PROXY_IPV6" = "1" ]; then - nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto udp udp dport 53 counter return comment \"默认\"" - nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto tcp tcp dport 53 counter return comment \"默认\"" - else - nft "add rule $NFTABLE_NAME PSW_DNS ip protocol udp udp dport 53 counter return comment \"默认\"" - nft "add rule $NFTABLE_NAME PSW_DNS ip protocol tcp tcp dport 53 counter return comment \"默认\"" - fi + nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp udp dport 53 counter return comment \"默认\"" + nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol tcp tcp dport 53 counter return comment \"默认\"" + nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp udp dport 53 counter return comment \"默认\"" + nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp tcp dport 53 counter return comment \"默认\"" + nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto udp udp dport 53 counter redirect to :${DNS_REDIRECT} comment \"默认\"" + nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto tcp tcp dport 53 counter redirect to :${DNS_REDIRECT} comment \"默认\"" + echolog " - ${msg}DNS 重定向到专用服务器[${DNS_REDIRECT}]" fi [ -n "${TCP_PROXY_MODE}" ] || [ -n "${UDP_PROXY_MODE}" ] && { @@ -1333,15 +1308,8 @@ add_firewall_rule() { if [ -n "$NODE" ] && ([ -n "${LOCALHOST_TCP_PROXY_MODE}" ] || [ -n "${LOCALHOST_UDP_PROXY_MODE}" ]); then [ -n "$DNS_REDIRECT_PORT" ] && { - if [ "$PROXY_IPV6" == "1" ]; then - #nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 meta l4proto udp udp dport 53 counter accept" - #nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 meta l4proto tcp tcp dport 53 counter accept" - nft "add rule $NFTABLE_NAME nat_output oif lo meta l4proto udp udp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW_DNS\"" - nft "add rule $NFTABLE_NAME nat_output oif lo meta l4proto tcp tcp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW_DNS\"" - else - nft "add rule $NFTABLE_NAME nat_output oif lo ip protocol udp udp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW_DNS\"" - nft "add rule $NFTABLE_NAME nat_output oif lo ip protocol tcp tcp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW_DNS\"" - fi + nft "add rule $NFTABLE_NAME nat_output meta l4proto udp oif lo udp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW_DNS\"" + nft "add rule $NFTABLE_NAME nat_output meta l4proto tcp oif lo tcp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW_DNS\"" } fi diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index 5e900d425..3bbd51a31 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 PKG_VERSION:=26.9.12 -PKG_RELEASE:=122 +PKG_RELEASE:=123 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/app_update.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/app_update.lua index 3fb4f5cc8..fb83c5183 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/app_update.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/app_update.lua @@ -14,7 +14,10 @@ local k, v for k, v in pairs(com) do o = s:option(Value, k:gsub("%-","_") .. "_file", translatef("%s App Path", v.name)) o.default = v.default_path or ("/usr/bin/" .. k) - o.rmempty = false + o.placeholder = o.default + function o:remove(section) + self:write(section, self.default) + end end o = s:option(DummyValue, "tips", " ") diff --git a/luci-app-ssr-plus/Makefile b/luci-app-ssr-plus/Makefile index 72bc961e6..56c7151ff 100644 --- a/luci-app-ssr-plus/Makefile +++ b/luci-app-ssr-plus/Makefile @@ -4,7 +4,7 @@ LUCI_TITLE:=luci-app-ssr-plus LUCI_PKGARCH:=all PKG_NAME:=luci-app-ssr-plus PKG_VERSION:=196 -PKG_RELEASE:=72 +PKG_RELEASE:=73 PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \ diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/clash_yaml.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/clash_yaml.lua index 2e7747dea..e1511e2ad 100644 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/clash_yaml.lua +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/clash_yaml.lua @@ -696,6 +696,12 @@ local function build_dns_section(dns_mode, user_dns) if not result["default-nameserver"] then result["default-nameserver"] = get_fastest_dns() end + if not result["direct-nameserver"] then + result["direct-nameserver"] = get_fastest_dns() + end + if result["direct-nameserver-follow-policy"] == nil then + result["direct-nameserver-follow-policy"] = false + end if result["respect-rules"] == nil then result["respect-rules"] = true end @@ -740,6 +746,8 @@ local function build_dns_section(dns_mode, user_dns) result["respect-rules"] = nil result["fallback-filter"] = nil result["nameserver-policy"] = nil + result["direct-nameserver"] = nil + result["direct-nameserver-follow-policy"] = nil end local upstreams = build_dns_upstreams() diff --git a/luci-mod-status/Makefile b/luci-mod-status/Makefile index a0f85de4e..54958f6bf 100644 --- a/luci-mod-status/Makefile +++ b/luci-mod-status/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI Status Pages LUCI_DEPENDS:=+luci-base +luci-app-oui +libiwinfo +rpcd-mod-iwinfo +rpcd-mod-rrdns +ucode +ucode-mod-fs +ucode-mod-ubus +ucode-mod-socket -PKG_RELEASE:=10 +PKG_RELEASE:=11 PKG_BUILD_DEPENDS:=iwinfo PKG_LICENSE:=Apache-2.0 diff --git a/luci-mod-status/htdocs/luci-static/resources/view/status/include/10_system.js b/luci-mod-status/htdocs/luci-static/resources/view/status/include/10_system.js index 5ea1a1508..06c28fea8 100644 --- a/luci-mod-status/htdocs/luci-static/resources/view/status/include/10_system.js +++ b/luci-mod-status/htdocs/luci-static/resources/view/status/include/10_system.js @@ -88,11 +88,6 @@ return baseclass.extend({ _('Architecture'), (cpuinfo.cpuinfo || boardinfo.system) + ' ' + cpubench.cpubench, _('Target Platform'), (L.isObject(boardinfo.release) ? boardinfo.release.target : ''), _('Firmware Version'), (L.isObject(boardinfo.release) ? boardinfo.release.description + ' / ' : '') + (luciversion || ''), - ? '%s%s / '.format( - boardinfo.release.description || '', - boardinfo.release.revision ? boardinfo.release.revision : '' - ) - : '') + (luciversion || ''), _('Kernel Version'), boardinfo.kernel, _('Local Time'), datestr, _('Uptime'), systeminfo.uptime ? '%t'.format(systeminfo.uptime) : null,