mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-03 20:53:56 +08:00
🌴 Sync 2026-09-22 14:48:47
This commit is contained in:
1 parent
bf4289d9a4
commit
fdc72bdc39
17 files changed
+260
-91
No files matched your search
@@ -454,7 +454,8 @@ fwlive_adaptive_merge_reply() {
|
||||
_adapt=1
|
||||
fwlive_adaptive_enabled || _adapt=0
|
||||
case "$_body" in
|
||||
*\}) ;;
|
||||
'{}') _sep= ;;
|
||||
*\}) _sep=, ;;
|
||||
*) printf '%s' "$_body"; return 0 ;;
|
||||
esac
|
||||
_base=${_body%\}}
|
||||
@@ -466,26 +467,26 @@ fwlive_adaptive_merge_reply() {
|
||||
esac
|
||||
if [ "$_adapt" = 0 ]; then
|
||||
if [ "$_has_msgs" = 1 ]; then
|
||||
printf '%s,"adaptive":0}' "$_base"
|
||||
printf '%s%s"adaptive":0}' "$_base" "$_sep"
|
||||
else
|
||||
printf '%s,"adaptive":0,"messages_received":%s}' "$_base" "$_msgs"
|
||||
printf '%s%s"adaptive":0,"messages_received":%s}' "$_base" "$_sep" "$_msgs"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
if [ "$_shed" = 1 ]; then
|
||||
if [ "$_has_msgs" = 1 ]; then
|
||||
printf '%s,"adaptive":1%s,"truncated":%s,"shed":{"level":"hot","limit":%s}}' \
|
||||
"$_base" "$_effective" "$_trunc" "$_limit"
|
||||
printf '%s%s"adaptive":1%s,"truncated":%s,"shed":{"level":"hot","limit":%s}}' \
|
||||
"$_base" "$_sep" "$_effective" "$_trunc" "$_limit"
|
||||
else
|
||||
printf '%s,"adaptive":1,"messages_received":%s%s,"truncated":%s,"shed":{"level":"hot","limit":%s}}' \
|
||||
"$_base" "$_msgs" "$_effective" "$_trunc" "$_limit"
|
||||
printf '%s%s"adaptive":1,"messages_received":%s%s,"truncated":%s,"shed":{"level":"hot","limit":%s}}' \
|
||||
"$_base" "$_sep" "$_msgs" "$_effective" "$_trunc" "$_limit"
|
||||
fi
|
||||
else
|
||||
if [ "$_has_msgs" = 1 ]; then
|
||||
printf '%s,"adaptive":1%s,"truncated":%s}' "$_base" "$_effective" "$_trunc"
|
||||
printf '%s%s"adaptive":1%s,"truncated":%s}' "$_base" "$_sep" "$_effective" "$_trunc"
|
||||
else
|
||||
printf '%s,"adaptive":1,"messages_received":%s%s,"truncated":%s}' \
|
||||
"$_base" "$_msgs" "$_effective" "$_trunc"
|
||||
printf '%s%s"adaptive":1,"messages_received":%s%s,"truncated":%s}' \
|
||||
"$_base" "$_sep" "$_msgs" "$_effective" "$_trunc"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -28,7 +28,7 @@ function has_hint(s, lc) {
|
||||
}
|
||||
function non_fw_prefix(s, lc) {
|
||||
lc = tolower(s)
|
||||
return lc ~ "^(dnsmasq|procd|ubusd|netifd|odhcpd|logd|dropbear|uhttpd|hostapd|wpad)([^a-z0-9_]|$)"
|
||||
return lc ~ "^(dnsmasq|procd|ubusd|netifd|odhcpd|logd|dropbear|uhttpd|hostapd|wpad)([^a-z0-9_-]|$)"
|
||||
}
|
||||
function detect_action(s, words, n, i, w, wl, lc, start, pos, before, afterc, best, bestpos) {
|
||||
n = split("ACCEPT ALLOW PASS DROP REJECT DENY BLOCK", words, " ")
|
||||
|
||||
@@ -445,40 +445,41 @@ restore_wan_log_baseline() {
|
||||
}
|
||||
|
||||
wan_filter_log_enabled() {
|
||||
log_val="$1"
|
||||
[ -n "$log_val" ] || return 1
|
||||
case "$log_val" in
|
||||
*[!0-9]*) return 1 ;;
|
||||
esac
|
||||
log_val=$(wan_filter_log_decimal "$1") || return 1
|
||||
[ $((log_val & 1)) -ne 0 ]
|
||||
}
|
||||
|
||||
wan_filter_log_decimal() {
|
||||
_log_val="$1"
|
||||
case "$_log_val" in
|
||||
''|*[!0-9]*) return 1 ;;
|
||||
esac
|
||||
while [ "${_log_val#0}" != "$_log_val" ]; do
|
||||
_log_val=${_log_val#0}
|
||||
done
|
||||
[ -n "$_log_val" ] || _log_val=0
|
||||
printf '%s' "$_log_val"
|
||||
}
|
||||
|
||||
wan_filter_log_target_value() {
|
||||
current="$1"
|
||||
current=$(wan_filter_log_decimal "$1") || {
|
||||
printf '1'
|
||||
return 0
|
||||
}
|
||||
if wan_filter_log_enabled "$current"; then
|
||||
printf '%s' "$current"
|
||||
return 0
|
||||
fi
|
||||
case "$current" in
|
||||
''|*[!0-9]*)
|
||||
printf '1'
|
||||
;;
|
||||
*)
|
||||
printf '%d' $((current | 1))
|
||||
;;
|
||||
esac
|
||||
printf '%d' $((current | 1))
|
||||
}
|
||||
|
||||
# Clear filter-log bit 0 only. Prints remaining value, or empty when the option
|
||||
# should be deleted (no bits left / non-numeric / already empty).
|
||||
wan_filter_log_clear_value() {
|
||||
current="$1"
|
||||
case "$current" in
|
||||
''|*[!0-9]*)
|
||||
printf ''
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
current=$(wan_filter_log_decimal "$1") || {
|
||||
printf ''
|
||||
return 0
|
||||
}
|
||||
cleared=$((current & ~1))
|
||||
if [ "$cleared" -eq 0 ]; then
|
||||
printf ''
|
||||
@@ -677,11 +678,27 @@ restore_wan_zone_log() {
|
||||
logger -t fwlive "WAN log rollback skipped: firewall changes pending" 2>/dev/null || true
|
||||
return 1
|
||||
fi
|
||||
# Capture the committed value before staging our rollback. If another
|
||||
# writer stages a firewall delta after this point, the post-stage guard
|
||||
# below must be able to undo only our rollback staging without reverting
|
||||
# the other writer's change.
|
||||
committed=$(wan_zone_log_value "$zone")
|
||||
if [ -z "$previous" ]; then
|
||||
uci -q delete "firewall.${zone}.log" 2>/dev/null || true
|
||||
else
|
||||
uci -q set "firewall.${zone}.log=${previous}" 2>/dev/null || true
|
||||
fi
|
||||
_staged=$(uci -q changes firewall 2>/dev/null || true)
|
||||
_foreign=$(wan_log_foreign_staged_lines "$zone" "$_staged")
|
||||
if [ -n "$_foreign" ]; then
|
||||
if [ -z "$committed" ]; then
|
||||
uci delete "firewall.${zone}.log" 2>/dev/null || true
|
||||
else
|
||||
uci set "firewall.${zone}.log=${committed}" 2>/dev/null || true
|
||||
fi
|
||||
logger -t fwlive "WAN log rollback skipped after stage: firewall changes staged by another writer" 2>/dev/null || true
|
||||
return 1
|
||||
fi
|
||||
uci commit firewall 2>/dev/null || true
|
||||
}
|
||||
|
||||
@@ -692,13 +709,14 @@ restore_wan_zone_log() {
|
||||
# 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
|
||||
# to `uci commit firewall` in the toggle flow, so callers cannot bypass it —
|
||||
# gated by:
|
||||
# Staging and committing therefore live INSIDE this function, gated by:
|
||||
# 1. a pending re-check BEFORE our own delta exists in staging (foreign-only);
|
||||
# 2. a post-stage re-check AFTER our set/delete: if anything besides our
|
||||
# log option is staged, undo our staging (restore the pre-stage committed
|
||||
# value) and abort without commit — foreign staging stays intact.
|
||||
# The reload-failure rollback has its own pre/post-stage guard for the same
|
||||
# reason; it must not bypass this invariant merely because it is compensating
|
||||
# for a failed reload.
|
||||
# Residual window: a writer that stages between the post-stage check and
|
||||
# `uci commit` can still ride along; post-commit verification detects a
|
||||
# mismatched log bit. Same-option races (another writer also staging
|
||||
@@ -977,6 +995,20 @@ run_logging_selftest() {
|
||||
echo 'wan_filter_log_enabled 2: expected false' >&2
|
||||
return 1
|
||||
fi
|
||||
for leading_value in 011 010 08 0; do
|
||||
if ! wan_filter_log_decimal "$leading_value" >/dev/null; then
|
||||
echo "wan_filter_log_decimal $leading_value: expected decimal digits" >&2
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
if wan_filter_log_enabled '08' || wan_filter_log_enabled '010'; then
|
||||
echo 'leading-zero even values: expected false' >&2
|
||||
return 1
|
||||
fi
|
||||
if ! wan_filter_log_enabled '011'; then
|
||||
echo 'leading-zero odd value: expected true' >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
got=$(wan_filter_log_target_value '')
|
||||
if [ "$got" != '1' ]; then
|
||||
@@ -995,6 +1027,16 @@ run_logging_selftest() {
|
||||
echo "wan_filter_log_target_value 1: expected 1 got $got" >&2
|
||||
return 1
|
||||
fi
|
||||
got=$(wan_filter_log_target_value '08')
|
||||
if [ "$got" != '9' ]; then
|
||||
echo "wan_filter_log_target_value 08: expected 9 got $got" >&2
|
||||
return 1
|
||||
fi
|
||||
got=$(wan_filter_log_target_value '011')
|
||||
if [ "$got" != '11' ]; then
|
||||
echo "wan_filter_log_target_value 011: expected 11 got $got" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Disable clears bit 0 only: log=3 -> 2; log=1 -> delete (empty).
|
||||
got=$(wan_filter_log_clear_value '3')
|
||||
@@ -1015,6 +1057,17 @@ run_logging_selftest() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
got=$(wan_filter_log_clear_value '010')
|
||||
if [ "$got" != '10' ]; then
|
||||
echo "wan_filter_log_clear_value 010: expected 10 got $got" >&2
|
||||
return 1
|
||||
fi
|
||||
got=$(wan_filter_log_clear_value '0')
|
||||
if [ -n "$got" ]; then
|
||||
echo "wan_filter_log_clear_value 0: expected empty got $got" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Enable/disable parity around multi-bit values.
|
||||
got=$(wan_filter_log_target_value '2')
|
||||
if [ "$got" != '3' ]; then
|
||||
|
||||
@@ -564,7 +564,8 @@ resolve_addresses() {
|
||||
start=$(date +%s)
|
||||
# Optional JSON on $1 (rpcd may also pass argv $3 at the call site); else stdin.
|
||||
input=$(read_rpc_input "$1")
|
||||
count=0
|
||||
lookups=0
|
||||
truncated=0
|
||||
OUT=''
|
||||
|
||||
if ! command -v jshn >/dev/null 2>&1; then
|
||||
@@ -597,27 +598,51 @@ resolve_addresses() {
|
||||
return 0
|
||||
}
|
||||
while IFS= read -r ip; do
|
||||
[ "$count" -ge "$RESOLVE_MAX" ] && break
|
||||
if [ "$lookups" -ge "$RESOLVE_MAX" ]; then
|
||||
truncated=1
|
||||
break
|
||||
fi
|
||||
# Abort cleanly once the whole-call wall-clock budget is spent;
|
||||
# never START a lookup past the budget.
|
||||
now=$(date +%s)
|
||||
[ $((now - start)) -ge "$RESOLVE_BUDGET" ] && break
|
||||
if [ $((now - start)) -ge "$RESOLVE_BUDGET" ]; then
|
||||
truncated=1
|
||||
break
|
||||
fi
|
||||
# Missing/empty element: set -u cannot read bare $ip.
|
||||
if ! is_resolvable_address "${ip:-}"; then
|
||||
continue
|
||||
fi
|
||||
lookups=$((lookups + 1))
|
||||
# NXDOMAIN / timeout: resolve_hostname returns 1. set -e
|
||||
# cannot apply to this assignment.
|
||||
name=$(resolve_hostname "$ip") || name=
|
||||
if [ -n "$name" ]; then
|
||||
map_add "$ip" "$name"
|
||||
count=$((count + 1))
|
||||
else
|
||||
# Record a completed miss so the view can fail-mark NXDOMAIN
|
||||
# without treating the unprocessed truncated tail as tried.
|
||||
# map_add skips empty values (rules-map labels); resolve needs them.
|
||||
esc_key=$(printf '%s' "$ip" | json_escape)
|
||||
case "$OUT" in
|
||||
*"\"$esc_key\":"*) ;;
|
||||
*)
|
||||
if [ -n "$OUT" ]; then
|
||||
OUT="${OUT},"
|
||||
fi
|
||||
OUT="${OUT}\"${esc_key}\":\"\""
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
done <<EOF
|
||||
$_addresses
|
||||
EOF
|
||||
|
||||
printf '{"names":{%s}}' "$OUT"
|
||||
if [ "$truncated" -eq 1 ]; then
|
||||
printf '{"names":{%s},"truncated":true}' "$OUT"
|
||||
else
|
||||
printf '{"names":{%s}}' "$OUT"
|
||||
fi
|
||||
}
|
||||
|
||||
check_eq() {
|
||||
|
||||
Reference in new issue
Block a user