mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-09 13:38:05 +08:00
🦄 Sync 2026-11-08 01:37:11
This commit is contained in:
1 parent
3d26c9667a
commit
18b7d51c1a
6 files changed
+141
-67
No files matched your search
@@ -1,8 +1,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-trafficctl
|
||||
PKG_VERSION:=1.26.3
|
||||
PKG_RELEASE:=21
|
||||
PKG_VERSION:=1.26.4
|
||||
PKG_RELEASE:=22
|
||||
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
PKG_MAINTAINER:=Denis Iusupov <yusdyr@gmail.com>
|
||||
|
||||
@@ -316,6 +316,14 @@ function fmtRate(kbit) {
|
||||
return kbit + ' ' + _('kbit/s');
|
||||
}
|
||||
|
||||
// A ceiling as one figure, or both when upload has its own (#66). An upload
|
||||
// figure of 0 means the backend found no upload ceiling to report; the
|
||||
// download one is still the limit, so it is shown alone.
|
||||
function fmtCeiling(kbit, kbitUp) {
|
||||
if (!kbitUp || kbitUp <= 0 || kbitUp === kbit) return fmtRate(kbit);
|
||||
return '↓ ' + fmtRate(kbit) + ' / ↑ ' + fmtRate(kbitUp);
|
||||
}
|
||||
|
||||
// Render a "↓ down / ↑ up" speed cell. Both halves come from the same
|
||||
// bytes_in/bytes_out sample, so they are always consistent with each other.
|
||||
function renderSpeedCell(cell, sd) {
|
||||
@@ -1240,6 +1248,7 @@ function buildSummaryTable(rows, sortCol, sortDir, onSort, onSelect, speedMap, d
|
||||
r._backlog = sh ? sh.backlog : 0;
|
||||
r._throttle_kbit = (r.shape_kbit || 0) > 0 ? r.shape_kbit : (r.rate_limit_kbit || 0);
|
||||
r._throttle_mode = (r.shape_kbit || 0) > 0 ? 'shaper' : ((r.rate_limit_kbit || 0) > 0 ? 'limiter' : 'none');
|
||||
r._throttle_kbit_up = r._throttle_mode === 'shaper' ? (r.shape_kbit_up || 0) : (r.rate_limit_kbit_up || 0);
|
||||
});
|
||||
|
||||
var sorted = rows.slice().sort(function(a, b) {
|
||||
@@ -1381,8 +1390,8 @@ function buildSummaryTable(rows, sortCol, sortDir, onSort, onSelect, speedMap, d
|
||||
cellMap.app = E('div', { 'class': 'td tc-center' }, appBadge);
|
||||
|
||||
var throttleBadge;
|
||||
if (r._throttle_mode === 'shaper') { throttleBadge = E('span', { 'class': 'tc-c-speed tc-fw-bold', 'title': _('Shaper (tc/HTB queue)') }, '≈ ' + fmtRate(r._throttle_kbit)); }
|
||||
else if (r._throttle_mode === 'limiter') { throttleBadge = E('span', { 'class': 'tc-c-warn tc-fw-bold', 'title': _('Limiter (nft drop)') }, '⚡ ' + fmtRate(r._throttle_kbit)); }
|
||||
if (r._throttle_mode === 'shaper') { throttleBadge = E('span', { 'class': 'tc-c-speed tc-fw-bold', 'title': _('Shaper (tc/HTB queue)') }, '≈ ' + fmtCeiling(r._throttle_kbit, r._throttle_kbit_up)); }
|
||||
else if (r._throttle_mode === 'limiter') { throttleBadge = E('span', { 'class': 'tc-c-warn tc-fw-bold', 'title': _('Limiter (nft drop)') }, '⚡ ' + fmtCeiling(r._throttle_kbit, r._throttle_kbit_up)); }
|
||||
else { throttleBadge = E('span', { 'class': 'tc-c-faint' }, '—'); }
|
||||
cellMap._throttle_kbit = E('div', { 'class': 'td tc-center' }, throttleBadge);
|
||||
|
||||
@@ -1868,6 +1877,8 @@ return view.extend({
|
||||
}
|
||||
renderRecentChips();
|
||||
updateModeUI();
|
||||
// The split row describes the device it was opened for.
|
||||
_upPinned = false;
|
||||
runQuery();
|
||||
}
|
||||
|
||||
@@ -2274,6 +2285,9 @@ return view.extend({
|
||||
// it would close the field (and overwrite what is being typed) a few
|
||||
// seconds after it was opened.
|
||||
var _customPinned = false;
|
||||
// The upload row's counterpart: set while the operator has it open
|
||||
// for editing, so the poll does not refill or close it under them.
|
||||
var _upPinned = false;
|
||||
var _modeSelected = 'shaper';
|
||||
|
||||
var rateChipsRow = E('div', {'class':'tc-chips-row'});
|
||||
@@ -2379,13 +2393,29 @@ return view.extend({
|
||||
var upToggleBtn = E('span', {'class': 'tc-chip',
|
||||
'data-tip': _('Give upload its own ceiling instead of matching download')
|
||||
}, '⇅ ' + _('Split up/down'));
|
||||
upToggleBtn.addEventListener('click', function() {
|
||||
upRow.classList.toggle('tc-hidden');
|
||||
var on = !upRow.classList.contains('tc-hidden');
|
||||
function showUpRow(on) {
|
||||
upRow.classList.toggle('tc-hidden', !on);
|
||||
upToggleBtn.classList.toggle('tc-chip--active', on);
|
||||
if (on) { upInput.focus(); } else { upInput.value = ''; }
|
||||
if (!on) { upInput.value = ''; }
|
||||
}
|
||||
upToggleBtn.addEventListener('click', function() {
|
||||
var on = upRow.classList.contains('tc-hidden');
|
||||
showUpRow(on);
|
||||
_upPinned = on;
|
||||
if (on) { upInput.focus(); }
|
||||
updateScopeExplain();
|
||||
});
|
||||
// The row has no button of its own: Enter applies the pair, as does
|
||||
// picking a download rate.
|
||||
upInput.addEventListener('keydown', function(ev) {
|
||||
if (ev.key !== 'Enter') { return; }
|
||||
ev.preventDefault();
|
||||
if (getRateKbit() === '0') {
|
||||
setStatus(statusDiv, 'error', _('Pick a download speed as well: the upload one is applied with it.'));
|
||||
return;
|
||||
}
|
||||
applyRate();
|
||||
});
|
||||
rateChipsRow.appendChild(upToggleBtn);
|
||||
|
||||
// Mode: segmented toggle (Shaper default)
|
||||
@@ -2634,6 +2664,7 @@ return view.extend({
|
||||
scopeRow,
|
||||
rateChipsRow,
|
||||
customRow,
|
||||
upRow,
|
||||
subnetLimitsBox
|
||||
]);
|
||||
|
||||
@@ -2680,6 +2711,7 @@ return view.extend({
|
||||
var name = '';
|
||||
var kbit = getRateKbit();
|
||||
var kbitUp = getRateKbitUp();
|
||||
_upPinned = false;
|
||||
// A block target has no single tc classid, so the shaper can't
|
||||
// express it — force the limiter rather than silently doing nothing.
|
||||
var mode = all ? 'limiter' : _modeSelected;
|
||||
@@ -3119,12 +3151,12 @@ return view.extend({
|
||||
}
|
||||
}
|
||||
if ((data.shape_kbit || 0) > 0) {
|
||||
parts.push(_('Shaped: <b style=\"color:var(--tc-speed)\">🌊 %s</b>').format(fmtRate(data.shape_kbit)));
|
||||
parts.push(_('Shaped: <b style=\"color:var(--tc-speed)\">🌊 %s</b>').format(fmtCeiling(data.shape_kbit, data.shape_kbit_up)));
|
||||
var sm = self._shapeMap[data.ip || searchSelect.getValue()] || {};
|
||||
if ((sm.backlog||0) > 0) parts.push(_('Queued: <b style=\"color:var(--tc-speed)\">%s</b>').format(fmtBytes(sm.backlog)));
|
||||
if ((sm.bytes||0) > 0) parts.push(_('Passed: <b>%s</b>').format(fmtBytes(sm.bytes)));
|
||||
} else if ((data.rate_limit_kbit || 0) > 0) {
|
||||
parts.push(_('Speed limit: <b style=\"color:var(--tc-warn)\">⚡ %s</b>').format(fmtRate(data.rate_limit_kbit)));
|
||||
parts.push(_('Speed limit: <b style=\"color:var(--tc-warn)\">⚡ %s</b>').format(fmtCeiling(data.rate_limit_kbit, data.rate_limit_kbit_up)));
|
||||
var dm = self._dropMap[data.ip || searchSelect.getValue()] || {};
|
||||
if ((dm.packets||0) > 0) {
|
||||
parts.push(_('Dropped: <b style="color:var(--tc-err)">🚫 %d pkts / %s</b>').format(Number(dm.packets) || 0, fmtBytes(dm.bytes||0)));
|
||||
@@ -3175,6 +3207,19 @@ return view.extend({
|
||||
customRow.classList.add('tc-hidden');
|
||||
}
|
||||
|
||||
// Show the upload ceiling that is installed, so reopening a
|
||||
// device with a split limit does not look symmetric.
|
||||
var curUp = curShapeRate > 0 ? (data.shape_kbit_up || 0) : (data.rate_limit_kbit_up || 0);
|
||||
if (!_upPinned && document.activeElement !== upInput) {
|
||||
var split = curRate > 0 && curUp > 0 && curUp !== curRate;
|
||||
showUpRow(split);
|
||||
if (split) {
|
||||
_upUnit = curUp % 1000 === 0 ? 'mbit' : 'kbit';
|
||||
upInput.value = _upUnit === 'mbit' ? curUp / 1000 : curUp;
|
||||
updateUpUnitBtns();
|
||||
}
|
||||
}
|
||||
|
||||
while (connsDiv.firstChild) connsDiv.removeChild(connsDiv.firstChild);
|
||||
if (!data.connections || data.connections.length === 0) {
|
||||
connsDiv.appendChild(E('p', {'style':'color:var(--tc-muted);padding:12px 0'}, _('No active connections.')));
|
||||
|
||||
@@ -751,6 +751,9 @@ msgstr ""
|
||||
msgid "Persist rules"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pick a download speed as well: the upload one is applied with it."
|
||||
msgstr ""
|
||||
|
||||
msgid "Pick a rate to apply it to this target, or Off to remove its limit."
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -161,38 +161,35 @@ if [ -n "$MAC" ]; then
|
||||
done
|
||||
fi
|
||||
|
||||
# Get rate limit
|
||||
RATE_LIM=0
|
||||
# Get rate limit, each direction: upload has its own ceiling since #83.
|
||||
RATE_LIM=0; RATE_LIM_UP=0
|
||||
if [ "$TCTL_FW" = "nft" ]; then
|
||||
RATE_LIM=$(nft list table netdev tm_ratelimit 2>/dev/null | tctl_rl_rate_kbit "$IP")
|
||||
RL_DUMP=$(nft list table netdev tm_ratelimit 2>/dev/null)
|
||||
RATE_LIM=$(echo "$RL_DUMP" | tctl_rl_rate_kbit "$IP")
|
||||
RATE_LIM_UP=$(echo "$RL_DUMP" | tctl_rl_rate_kbit "$IP" saddr)
|
||||
else
|
||||
# The address as a whole field, not a substring (see tctl_rl_rate_kbit).
|
||||
RATE_LIM=$(iptables -t mangle -L FORWARD -nv 2>/dev/null | grep "rl_ratelimit" \
|
||||
| awk -v ip="$IP" '{ for (i = 1; i <= NF; i++) if ($i == ip || $i == ip "/32") { print; next } }' \
|
||||
| grep -oE '[0-9]+kbit' | head -1 | sed 's/kbit//')
|
||||
# The download rule is listed first; the upload one is the "_ul" name.
|
||||
RL_DUMP=$(iptables -t mangle -L FORWARD -nv 2>/dev/null | grep "rl_ratelimit" \
|
||||
| awk -v ip="$IP" '{ for (i = 1; i <= NF; i++) if ($i == ip || $i == ip "/32") { print; next } }')
|
||||
RATE_LIM=$(echo "$RL_DUMP" | grep -oE '[0-9]+kbit' | head -1 | sed 's/kbit//')
|
||||
RATE_LIM_UP=$(echo "$RL_DUMP" | grep -E 'rl_ratelimit.*_ul' | grep -oE '[0-9]+kbit' | head -1 | sed 's/kbit//')
|
||||
fi
|
||||
[ -z "$RATE_LIM" ] && RATE_LIM=0
|
||||
[ -z "$RATE_LIM_UP" ] && RATE_LIM_UP=0
|
||||
|
||||
# Get shape rate
|
||||
SHAPE_KBIT=0
|
||||
o3=$(echo "$IP" | cut -d. -f3)
|
||||
o4=$(echo "$IP" | cut -d. -f4)
|
||||
dec=$((o3 * 256 + o4))
|
||||
hex=$(printf "%x" "$dec")
|
||||
classid="1:$hex"
|
||||
# Skip reserved HTB classes (root 1:1 and default 1:fffe)
|
||||
shape_info=""
|
||||
case "$hex" in 1|fffe) ;; *) shape_info=$(tc class show dev "$LAN_DEV" classid "$classid" 2>/dev/null) ;; esac
|
||||
if [ -n "$shape_info" ]; then
|
||||
SHAPE_KBIT=$(echo "$shape_info" | grep -oE 'rate [0-9]+[A-Za-z]+' | head -1 | awk '{
|
||||
rate=$2; num=rate+0
|
||||
if (rate ~ /Gbit/) print num*1000000
|
||||
else if (rate ~ /Mbit/) print num*1000
|
||||
else if (rate ~ /[Kk]bit/) print num
|
||||
else print num
|
||||
}')
|
||||
# Get shape rate. The classid is looked up in shapes.json, never derived from
|
||||
# the address: minors are allocated (see lookup_shape_kbit in
|
||||
# trafficctl-summary.sh). Download is the class on the LAN device, upload the
|
||||
# one with the same classid on the IFB.
|
||||
SHAPE_KBIT=0; SHAPE_KBIT_UP=0
|
||||
classid=$(tctl_shape_classmap | awk -v ip="$IP" '$1==ip{print $2; exit}')
|
||||
if [ -n "$classid" ]; then
|
||||
SHAPE_KBIT=$(tctl_tc_class_rates "$LAN_DEV" | awk -v c="$classid" '$1==c{print $2; exit}')
|
||||
SHAPE_KBIT_UP=$(tctl_tc_class_rates "$(tctl_shape_ifb_dev)" | awk -v c="$classid" '$1==c{print $2; exit}')
|
||||
fi
|
||||
[ -z "$SHAPE_KBIT" ] && SHAPE_KBIT=0
|
||||
[ -z "$SHAPE_KBIT_UP" ] && SHAPE_KBIT_UP=0
|
||||
|
||||
# Parse conntrack for connections and totals
|
||||
TIMESTAMP=$(date +%s)
|
||||
@@ -404,7 +401,7 @@ tctl_wifi_block_pending "$([ "$WIFI_BLOCKED" = "true" ] && echo 1 || echo 0)" "$
|
||||
&& WIFI_PENDING=true
|
||||
|
||||
# Output final JSON
|
||||
printf '{"ip":"%s","name":"%s","mac":"%s","conn_type":"%s","conn_last":"%s","timestamp":%d,"blocked":%s,"block_packets":%d,"block_bytes":%.0f,"wifi_blocked":%s,"wifi_block_pending":%s,"total":%.0f,"protocols":{"tcp":%d,"udp":%d,"other":%d},"tcp_states":{"established":%d,"time_wait":%d,"syn_sent":%d,"close_wait":%d},"connections":[%s],"rate_limit_kbit":%d,"shape_kbit":%d}\n' \
|
||||
printf '{"ip":"%s","name":"%s","mac":"%s","conn_type":"%s","conn_last":"%s","timestamp":%d,"blocked":%s,"block_packets":%d,"block_bytes":%.0f,"wifi_blocked":%s,"wifi_block_pending":%s,"total":%.0f,"protocols":{"tcp":%d,"udp":%d,"other":%d},"tcp_states":{"established":%d,"time_wait":%d,"syn_sent":%d,"close_wait":%d},"connections":[%s],"rate_limit_kbit":%d,"rate_limit_kbit_up":%d,"shape_kbit":%d,"shape_kbit_up":%d}\n' \
|
||||
"$IP" "$NAME" "$MAC" "$CONN_TYPE" "$CONN_LAST" "$TIMESTAMP" "$BLOCKED" "$BLOCK_PACKETS" "$BLOCK_BYTES" \
|
||||
"$WIFI_BLOCKED" "$WIFI_PENDING" "$TOTAL" "$N_TCP" "$N_UDP" "$N_OTHER" \
|
||||
"$EST" "$TW" "$SS" "$CW" "$CONNS_OUT" "$RATE_LIM" "$SHAPE_KBIT"
|
||||
"$EST" "$TW" "$SS" "$CW" "$CONNS_OUT" "$RATE_LIM" "$RATE_LIM_UP" "$SHAPE_KBIT" "$SHAPE_KBIT_UP"
|
||||
@@ -284,7 +284,7 @@ tctl_ratelimit_add() {
|
||||
--hashlimit-mode dstip --hashlimit-name "rl_${comment}" \
|
||||
-j DROP -m comment --comment "$comment" 2>/dev/null
|
||||
iptables -t mangle -A FORWARD -s "$ip" -m hashlimit \
|
||||
--hashlimit-above "${rate_kbit}kbit/sec" --hashlimit-burst "${rate_kbit}kbit" \
|
||||
--hashlimit-above "${rate_kbit_up}kbit/sec" --hashlimit-burst "${rate_kbit_up}kbit" \
|
||||
--hashlimit-mode srcip --hashlimit-name "rl_${comment}_ul" \
|
||||
-j DROP -m comment --comment "${comment}_ul" 2>/dev/null
|
||||
fi
|
||||
@@ -339,12 +339,16 @@ tctl_ratelimit_remove() {
|
||||
# The readers that only knew "kbytes" turned the latter into 0 — or, in the
|
||||
# stats, into 8 kbit/s. Every unit goes back to bytes by nft's factor, and
|
||||
# bytes to kbit by the package's own, SI (see tctl_rate_bytes).
|
||||
#
|
||||
# The second argument picks the direction: "daddr" (the default) is the
|
||||
# download rule, "saddr" the IPv4 upload one, which carries its own ceiling
|
||||
# since the two directions could differ (#83).
|
||||
tctl_rl_rate_kbit() {
|
||||
awk -v ip="$1" "$TCTL_NFT_RATE_AWK"'
|
||||
awk -v ip="$1" -v fld="${2:-daddr}" "$TCTL_NFT_RATE_AWK"'
|
||||
/limit rate over/ {
|
||||
hit = 0
|
||||
for (i = 1; i < NF; i++)
|
||||
if ($i == "daddr" && ($(i+1) == ip || $(i+1) == ip "/32")) { hit = 1; break }
|
||||
if ($i == fld && ($(i+1) == ip || $(i+1) == ip "/32")) { hit = 1; break }
|
||||
if (!hit) next
|
||||
for (j = i; j < NF - 1; j++)
|
||||
if ($j == "over") { printf "%.0f\n", tctl_rate_kbit($(j+1), $(j+2)); exit }
|
||||
@@ -1068,6 +1072,38 @@ tctl_shape_classmap() {
|
||||
}'
|
||||
}
|
||||
|
||||
# The IFB device upload shaping runs on (see trafficctl-shape.sh).
|
||||
tctl_shape_ifb_dev() {
|
||||
local d
|
||||
d=$(uci -q get trafficctl.main.shape_ifb 2>/dev/null)
|
||||
echo "${d:-tctl-ifb0}"
|
||||
}
|
||||
|
||||
# "classid rate_kbit" for every per-device HTB class on a device, from one tc
|
||||
# call. On the LAN device that is the download ceiling, on the IFB the upload
|
||||
# one: a shape uses the same classid on both.
|
||||
tctl_tc_class_rates() {
|
||||
command -v tc >/dev/null 2>&1 || return 0
|
||||
tc class show dev "$1" 2>/dev/null | awk '
|
||||
/^class htb 1:/ {
|
||||
classid=$3
|
||||
minor=classid; sub(/^1:/,"",minor)
|
||||
if (minor=="1" || minor=="fffe") next
|
||||
rate=0
|
||||
for (i=1;i<=NF;i++) {
|
||||
if ($i=="rate") {
|
||||
v=$(i+1)
|
||||
if (v ~ /Gbit/) { sub(/Gbit/,"",v); rate=(v+0)*1000000 }
|
||||
else if (v ~ /Mbit/) { sub(/Mbit/,"",v); rate=(v+0)*1000 }
|
||||
else if (v ~ /[Kk]bit/){ sub(/[Kk]bit/,"",v); rate=v+0 }
|
||||
else { rate=(v+0)/1000 }
|
||||
break
|
||||
}
|
||||
}
|
||||
print classid, rate
|
||||
}'
|
||||
}
|
||||
|
||||
tctl_seen_normalize() {
|
||||
printf '%s' "$1" | tr 'A-Z' 'a-z'
|
||||
}
|
||||
|
||||
@@ -220,27 +220,10 @@ else
|
||||
RL_DUMP=$(iptables -t mangle -L FORWARD -nv 2>/dev/null)
|
||||
fi
|
||||
|
||||
# tc HTB classes → "classid rate_kbit" map (one tc call, parsed once)
|
||||
TC_MAP=""
|
||||
if command -v tc >/dev/null 2>&1; then
|
||||
TC_MAP=$(tc class show dev "$PRIMARY_LAN_DEV" 2>/dev/null | awk '
|
||||
/^class htb 1:/ {
|
||||
classid=$3
|
||||
minor=classid; sub(/^1:/,"",minor)
|
||||
if (minor=="1" || minor=="fffe") next
|
||||
rate=0
|
||||
for (i=1;i<=NF;i++) {
|
||||
if ($i=="rate") {
|
||||
v=$(i+1)
|
||||
if (v ~ /Gbit/) { sub(/Gbit/,"",v); rate=(v+0)*1000000 }
|
||||
else if (v ~ /Mbit/) { sub(/Mbit/,"",v); rate=(v+0)*1000 }
|
||||
else if (v ~ /[Kk]bit/){ sub(/[Kk]bit/,"",v); rate=v+0 }
|
||||
break
|
||||
}
|
||||
}
|
||||
print classid, rate
|
||||
}')
|
||||
fi
|
||||
# tc HTB classes → "classid rate_kbit" maps (one tc call per device, parsed
|
||||
# once): download on the LAN device, upload on the IFB.
|
||||
TC_MAP=$(tctl_tc_class_rates "$PRIMARY_LAN_DEV")
|
||||
TC_MAP_UP=$(tctl_tc_class_rates "$(tctl_shape_ifb_dev)")
|
||||
|
||||
# address → classid, from shapes.json (see tctl_shape_classmap).
|
||||
SHAPE_MAP=$(tctl_shape_classmap)
|
||||
@@ -348,13 +331,17 @@ lookup_block_bytes() {
|
||||
echo "${b:-0}"
|
||||
}
|
||||
|
||||
# $2 "up" reads the upload ceiling instead of the download one.
|
||||
lookup_rate_limit() {
|
||||
local ip="$1" r
|
||||
local ip="$1" r fld=daddr pat='rl_ratelimit'
|
||||
[ "$2" = "up" ] && { fld=saddr; pat='rl_ratelimit.*_ul'; }
|
||||
if [ "$TCTL_FW" = "nft" ]; then
|
||||
r=$(echo "$RL_DUMP" | tctl_rl_rate_kbit "$ip")
|
||||
r=$(echo "$RL_DUMP" | tctl_rl_rate_kbit "$ip" "$fld")
|
||||
else
|
||||
# The address as a whole field, not a substring (see tctl_rl_rate_kbit).
|
||||
r=$(echo "$RL_DUMP" | grep "rl_ratelimit" \
|
||||
# The download rule is listed first, so it is the first match either
|
||||
# way; the upload one is the only "_ul" name.
|
||||
r=$(echo "$RL_DUMP" | grep -E "$pat" \
|
||||
| awk -v ip="$ip" '{ for (i = 1; i <= NF; i++) if ($i == ip || $i == ip "/32") { print; next } }' \
|
||||
| grep -oE '[0-9]+kbit' | head -1 | sed 's/kbit//')
|
||||
fi
|
||||
@@ -365,11 +352,15 @@ lookup_rate_limit() {
|
||||
# allocated, so deriving put the first shaped device's rate on 192.168.x.2 and
|
||||
# showed 0 for the device actually shaped — and the Telegram bot built its
|
||||
# "Shape — Remove" button from this field.
|
||||
#
|
||||
# $2 "up" reads the upload class on the IFB. 0 there with a download shape set
|
||||
# means upload is not shaped at all (no kmod-ifb), not that it matches.
|
||||
lookup_shape_kbit() {
|
||||
local ip="$1" classid r
|
||||
local ip="$1" classid r map="$TC_MAP"
|
||||
[ "$2" = "up" ] && map="$TC_MAP_UP"
|
||||
classid=$(echo "$SHAPE_MAP" | awk -v ip="$ip" '$1==ip{print $2; exit}')
|
||||
[ -n "$classid" ] || { echo 0; return; }
|
||||
r=$(echo "$TC_MAP" | awk -v c="$classid" '$1==c{print $2; exit}')
|
||||
r=$(echo "$map" | awk -v c="$classid" '$1==c{print $2; exit}')
|
||||
echo "${r:-0}"
|
||||
}
|
||||
|
||||
@@ -402,7 +393,9 @@ for ip in $ACTIVE_IPS; do
|
||||
BLOCK_BYTES=$(lookup_block_bytes "$ip")
|
||||
WIFI_BLK=$(lookup_wifi_blocked "$MAC")
|
||||
RATE_LIM=$(lookup_rate_limit "$ip")
|
||||
RATE_LIM_UP=$(lookup_rate_limit "$ip" up)
|
||||
SHAPE=$(lookup_shape_kbit "$ip")
|
||||
SHAPE_UP=$(lookup_shape_kbit "$ip" up)
|
||||
APP=$(lookup_app "$ip")
|
||||
if [ -z "$NAME" ]; then
|
||||
NAME="*"
|
||||
@@ -462,13 +455,13 @@ for ip in $ACTIVE_IPS; do
|
||||
else
|
||||
printf ","
|
||||
fi
|
||||
printf '{"ip":"%s","name":"%s","mac":"%s","conn_type":"%s","conn_last":"%s","app":"%s","conns":%d,"total":%.0f,"tcp":%.0f,"udp":%.0f,"blocked":%s,"block_bytes":%.0f,"wifi_blocked":%s,"wifi_block_pending":%s,"rate_limit_kbit":%.0f,"shape_kbit":%.0f}' \
|
||||
printf '{"ip":"%s","name":"%s","mac":"%s","conn_type":"%s","conn_last":"%s","app":"%s","conns":%d,"total":%.0f,"tcp":%.0f,"udp":%.0f,"blocked":%s,"block_bytes":%.0f,"wifi_blocked":%s,"wifi_block_pending":%s,"rate_limit_kbit":%.0f,"rate_limit_kbit_up":%.0f,"shape_kbit":%.0f,"shape_kbit_up":%.0f}' \
|
||||
"$ip" "$NAME" "$MAC" "$CONN_TYPE" "$CONN_LAST" "$APP" "$CONNS" "$TOTAL" "$TCP" "$UDP" \
|
||||
"$([ "$BLOCKED" = "1" ] && echo true || echo false)" \
|
||||
"$BLOCK_BYTES" \
|
||||
"$([ "$WIFI_BLK" = "1" ] && echo true || echo false)" \
|
||||
"$([ "$WIFI_PENDING" = "1" ] && echo true || echo false)" \
|
||||
"$RATE_LIM" "$SHAPE"
|
||||
"$RATE_LIM" "$RATE_LIM_UP" "$SHAPE" "$SHAPE_UP"
|
||||
done
|
||||
printf "]\n"
|
||||
|
||||
|
||||
Reference in new issue
Block a user