⛄ Sync 2026-11-01 12:58:10
Merge-upstream / merge (push) Waiting to run

This commit is contained in:
github-actions[bot] committed 2026-11-01 12:58:10 +08:00
1 parent d1e51134a0
commit afd9decbc5
26 files changed
+269 -97

No files matched your search

+20 -1
View File
@@ -1,7 +1,26 @@
config trafficctl 'main'
option enabled '1'
option default_mode 'limiter'
option persist_rules '0'
# Write per-device blocks and rate limits to /etc/trafficctl/rules.json so
# the ifup-lan hook can restore them after a reboot.
#
# On by default since #105. It used to ship off, which made the same
# intention behave two ways: a traffic SHAPE persists unconditionally (the
# shaper has to record which HTB class belongs to which device, so
# shapes.json is always written and always restored), while a block or a
# limit vanished on reboot — and the default mode is the limiter, so the
# out-of-the-box path was the one that forgot. That was an unexamined
# default sitting next to a deliberate one, not a design.
#
# The cost is one small write to /etc per rule CHANGE. Not periodic, so
# unlike the byte counters — which live in tmpfs precisely because they are
# rewritten every poll — this is not a flash-wear concern.
#
# NOT the same switch as the global cut's "keep after reboot": that one is
# its own opt-in because an all-devices cut can lock out whoever
# administers the router through a LAN host, so a reboot must be able to
# undo it. See the cut section below.
option persist_rules '1'
# Extra subnets to monitor (space-separated CIDRs), for downstream-router
# clients that have no kernel route on this router. Subnets with a
# "via" route over a LAN interface are picked up automatically.
@@ -61,12 +61,13 @@ if tctl_block_add "$IP" "$COMMENT"; then
else
NOTE=" — IPv4 only: no MAC known for $IP (no DHCP lease, no neighbour entry), so IPv6 is not covered"
fi
NOTE="$NOTE$(tctl_nss_note)"
NOTE="$NOTE$(tctl_nss_note)$(tctl_persist_note)"
NSS="$(tctl_nss_status)"
PERSIST=$(tctl_persist_enabled && echo true || echo false)
if [ "$SELF_BLOCK" = "true" ]; then
echo "{\"ok\":true,\"ipv6\":$([ "$TCTL_BLOCK_IPV6" = "1" ] && echo true || echo false),\"nss\":\"$NSS\",\"msg\":\"internet blocked for $IP (your device — LuCI access preserved)$NOTE\"}"
echo "{\"ok\":true,\"ipv6\":$([ "$TCTL_BLOCK_IPV6" = "1" ] && echo true || echo false),\"nss\":\"$NSS\",\"persist\":$PERSIST,\"msg\":\"internet blocked for $IP (your device — LuCI access preserved)$NOTE\"}"
else
echo "{\"ok\":true,\"ipv6\":$([ "$TCTL_BLOCK_IPV6" = "1" ] && echo true || echo false),\"nss\":\"$NSS\",\"msg\":\"internet blocked for $IP$NOTE\"}"
echo "{\"ok\":true,\"ipv6\":$([ "$TCTL_BLOCK_IPV6" = "1" ] && echo true || echo false),\"nss\":\"$NSS\",\"persist\":$PERSIST,\"msg\":\"internet blocked for $IP$NOTE\"}"
fi
else
echo "{\"ok\":false,\"msg\":\"failed to block $IP\"}"
@@ -1208,6 +1208,18 @@ tctl_nss_note() {
"$TCTL_ECM_DEBUGFS"
}
# The suffix a caller appends when the rule it just installed will not be
# written down, and so will not come back after a reboot (#105).
#
# Same principle as the IPv6 and NSS qualifiers: this package says what a
# success does NOT cover rather than letting the operator discover it later.
# Here "later" meant the next reboot, which is the worst possible moment to
# find out that a device you blocked is online again.
tctl_persist_note() {
tctl_persist_enabled && return 0
printf ' [NOT PERSISTENT: this will be lost on reboot — persistence is off. Enable it with `uci set trafficctl.main.persist_rules=1 && uci commit trafficctl`, or in Settings → Logging & Persistence, then re-apply]'
}
# Defunct the flows ECM has already accelerated.
#
# This is the NSS counterpart of the `conntrack -D` every rule change already
@@ -104,13 +104,14 @@ else
# packets never reach the Linux stack. Reporting an unqualified success
# there is the defect in #81, so every message below carries the verdict
# and the result carries the status as a field.
NSSNOTE="$(tctl_nss_note)"
NSSNOTE="$(tctl_nss_note)$(tctl_persist_note)"
NSS="$(tctl_nss_status)"
PERSIST=$(tctl_persist_enabled && echo true || echo false)
if [ "$TCTL_RL_DOWNLOAD_FAILED" = "1" ]; then
echo "{\"ok\":true,\"ipv6_upload\":$([ "$TCTL_RL_UPLOAD6_OK" = "1" ] && echo true || echo false),\"nss\":\"$NSS\",\"msg\":\"rate limit ${RATE_UP} kbit/s applied to $IP UPLOAD ONLY — WAN device not resolvable$V6NOTE$NSSNOTE\"}"
echo "{\"ok\":true,\"ipv6_upload\":$([ "$TCTL_RL_UPLOAD6_OK" = "1" ] && echo true || echo false),\"nss\":\"$NSS\",\"persist\":$PERSIST,\"msg\":\"rate limit ${RATE_UP} kbit/s applied to $IP UPLOAD ONLY — WAN device not resolvable$V6NOTE$NSSNOTE\"}"
elif [ "$TCTL_RL_UPLOAD_FAILED" = "1" ]; then
echo "{\"ok\":true,\"ipv6_upload\":false,\"nss\":\"$NSS\",\"msg\":\"rate limit ${RATE} kbit/s applied to $IP DOWNLOAD ONLY — no LAN ingress device [IPv4 only]$NSSNOTE\"}"
echo "{\"ok\":true,\"ipv6_upload\":false,\"nss\":\"$NSS\",\"persist\":$PERSIST,\"msg\":\"rate limit ${RATE} kbit/s applied to $IP DOWNLOAD ONLY — no LAN ingress device [IPv4 only]$NSSNOTE\"}"
else
echo "{\"ok\":true,\"ipv6_upload\":$([ "$TCTL_RL_UPLOAD6_OK" = "1" ] && echo true || echo false),\"nss\":\"$NSS\",\"msg\":\"rate limit $(rate_text) for $IP (both directions, $MODE)$V6NOTE$NSSNOTE\"}"
echo "{\"ok\":true,\"ipv6_upload\":$([ "$TCTL_RL_UPLOAD6_OK" = "1" ] && echo true || echo false),\"nss\":\"$NSS\",\"persist\":$PERSIST,\"msg\":\"rate limit $(rate_text) for $IP (both directions, $MODE)$V6NOTE$NSSNOTE\"}"
fi
fi