Release
This commit is contained in:
143
bin/snowpanel-shaper
Normal file
143
bin/snowpanel-shaper
Normal file
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
read_cfg() {
|
||||
python3 - "$@" <<'PY'
|
||||
import json,sys
|
||||
cands=["/var/lib/snowpanel/app.json","/etc/snowpanel/app.json","/etc/snowpanel/limits.json","/var/lib/snowpanel/limits.json"]
|
||||
rate=0
|
||||
for p in cands:
|
||||
try:
|
||||
with open(p,"r",encoding="utf-8") as f:
|
||||
j=json.load(f)
|
||||
if isinstance(j,dict):
|
||||
v=j.get("rate_mbps") or (j.get("limits",{}) if isinstance(j.get("limits"),dict) else {}).get("rate_mbps")
|
||||
if v is not None:
|
||||
rate=int(v)
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
print(rate)
|
||||
PY
|
||||
}
|
||||
|
||||
get_iface() {
|
||||
local ifs=() d4 d6
|
||||
d4=$(ip -o -4 route show to default 2>/dev/null | awk '{print $5}' | head -n1 || true)
|
||||
d6=$(ip -o -6 route show ::/0 2>/dev/null | awk '{print $5}' | head -n1 || true)
|
||||
[[ -n "${d4:-}" ]] && ifs+=("$d4")
|
||||
[[ -n "${d6:-}" && "${d6:-}" != "${d4:-}" ]] && ifs+=("$d6")
|
||||
[[ ${#ifs[@]} -eq 0 ]] && { echo ""; return 1; }
|
||||
echo "${ifs[0]}"
|
||||
}
|
||||
|
||||
get_uid() {
|
||||
local u pid
|
||||
u=$(systemctl show -p User --value snowflake-proxy 2>/dev/null || true)
|
||||
if [[ -n "${u:-}" ]]; then id -u "$u" 2>/dev/null || true; return 0; fi
|
||||
if id -u snowflake &>/dev/null; then id -u snowflake; return 0; fi
|
||||
pid=$(systemctl show -p MainPID --value snowflake-proxy 2>/dev/null || true)
|
||||
if [[ -n "${pid:-}" && -r "/proc/$pid/status" ]]; then awk '/^Uid:/{print $2; exit}' "/proc/$pid/status"; return 0; fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
ipt_add() {
|
||||
local bin="$1" chain="$2" rule="$3"
|
||||
"$bin" -t mangle -N "$chain" 2>/dev/null || true
|
||||
"$bin" -t mangle -C OUTPUT -j "$chain" 2>/dev/null || "$bin" -t mangle -A OUTPUT -j "$chain"
|
||||
eval "$bin -t mangle -C $chain $rule" 2>/dev/null || eval "$bin -t mangle -A $chain $rule"
|
||||
}
|
||||
ipt_in_add() {
|
||||
local bin="$1" chain="$2"
|
||||
"$bin" -t mangle -N "$chain" 2>/dev/null || true
|
||||
"$bin" -t mangle -C PREROUTING -j "$chain" 2>/dev/null || "$bin" -t mangle -A PREROUTING -j "$chain"
|
||||
"$bin" -t mangle -C "$chain" -j CONNMARK --restore-mark 2>/dev/null || "$bin" -t mangle -A "$chain" -j CONNMARK --restore-mark
|
||||
}
|
||||
ipt_clear() {
|
||||
local bin="$1"
|
||||
for c in SNOWPANEL SNOWPANEL_IN; do
|
||||
while "$bin" -t mangle -D OUTPUT -j SNOWPANEL 2>/dev/null; do :; done
|
||||
while "$bin" -t mangle -D PREROUTING -j SNOWPANEL_IN 2>/dev/null; do :; done
|
||||
"$bin" -t mangle -F "$c" 2>/dev/null || true
|
||||
"$bin" -t mangle -X "$c" 2>/dev/null || true
|
||||
done
|
||||
}
|
||||
|
||||
tc_clear() {
|
||||
local ifc="$1"
|
||||
tc qdisc del dev "$ifc" root 2>/dev/null || true
|
||||
tc qdisc del dev "$ifc" ingress 2>/dev/null || true
|
||||
tc qdisc del dev ifb0 root 2>/dev/null || true
|
||||
tc qdisc del dev ifb0 ingress 2>/dev/null || true
|
||||
ip link set ifb0 down 2>/dev/null || true
|
||||
ip link delete ifb0 type ifb 2>/dev/null || true
|
||||
}
|
||||
|
||||
tc_apply() {
|
||||
local ifc="$1" rate_kbit="$2"
|
||||
tc qdisc replace dev "$ifc" root handle 1: htb default 30
|
||||
tc class add dev "$ifc" parent 1: classid 1:1 htb rate 10000000kbit ceil 10000000kbit 2>/dev/null || \
|
||||
tc class change dev "$ifc" parent 1: classid 1:1 htb rate 10000000kbit ceil 10000000kbit
|
||||
tc class add dev "$ifc" parent 1:1 classid 1:10 htb rate "${rate_kbit}kbit" ceil "${rate_kbit}kbit" 2>/dev/null || \
|
||||
tc class change dev "$ifc" parent 1:1 classid 1:10 htb rate "${rate_kbit}kbit" ceil "${rate_kbit}kbit"
|
||||
tc class add dev "$ifc" parent 1:1 classid 1:30 htb rate 9000000kbit ceil 10000000kbit 2>/dev/null || \
|
||||
tc class change dev "$ifc" parent 1:1 classid 1:30 htb rate 9000000kbit ceil 10000000kbit
|
||||
tc filter replace dev "$ifc" parent 1: protocol all handle 0x1 fw flowid 1:10
|
||||
|
||||
modprobe ifb numifbs=1 2>/dev/null || true
|
||||
ip link add ifb0 type ifb 2>/dev/null || true
|
||||
ip link set dev ifb0 up
|
||||
tc qdisc replace dev "$ifc" ingress
|
||||
tc filter replace dev "$ifc" parent ffff: protocol all u32 match u32 0 0 action mirred egress redirect dev ifb0
|
||||
|
||||
tc qdisc replace dev ifb0 root handle 2: htb default 30
|
||||
tc class add dev ifb0 parent 2: classid 2:1 htb rate 10000000kbit ceil 10000000kbit 2>/dev/null || \
|
||||
tc class change dev ifb0 parent 2: classid 2:1 htb rate 10000000kbit ceil 10000000kbit
|
||||
tc class add dev ifb0 parent 2:1 classid 2:10 htb rate "${rate_kbit}kbit" ceil "${rate_kbit}kbit" 2>/dev/null || \
|
||||
tc class change dev ifb0 parent 2:1 classid 2:10 htb rate "${rate_kbit}kbit" ceil "${rate_kbit}kbit"
|
||||
tc class add dev ifb0 parent 2:1 classid 2:30 htb rate 9000000kbit ceil 10000000kbit 2>/dev/null || \
|
||||
tc class change dev ifb0 parent 2:1 classid 2:30 htb rate 9000000kbit ceil 10000000kbit
|
||||
tc filter replace dev ifb0 parent 2: protocol all handle 0x1 fw flowid 2:10
|
||||
}
|
||||
|
||||
apply() {
|
||||
local rate uid ifc per_kbit
|
||||
rate=$(read_cfg)
|
||||
uid=$(get_uid)
|
||||
ifc=$(get_iface || true)
|
||||
ipt_clear iptables || true
|
||||
ipt_clear ip6tables || true
|
||||
if [[ -z "${ifc:-}" || -z "${uid:-}" || "$rate" -le 0 ]]; then
|
||||
tc_clear "${ifc:-eth0}" || true
|
||||
exit 0
|
||||
fi
|
||||
per_kbit=$(( rate * 1000 / 2 ))
|
||||
[[ $per_kbit -lt 64 ]] && per_kbit=64
|
||||
|
||||
ipt_add iptables SNOWPANEL "-m owner --uid-owner $uid -j MARK --set-xmark 0x1/0x1"
|
||||
ipt_add iptables SNOWPANEL "-m owner --uid-owner $uid -j CONNMARK --save-mark"
|
||||
ipt_in_add iptables SNOWPANEL_IN
|
||||
if command -v ip6tables >/dev/null 2>&1; then
|
||||
ipt_add ip6tables SNOWPANEL "-m owner --uid-owner $uid -j MARK --set-xmark 0x1/0x1"
|
||||
ipt_add ip6tables SNOWPANEL "-m owner --uid-owner $uid -j CONNMARK --save-mark"
|
||||
ipt_in_add ip6tables SNOWPANEL_IN
|
||||
fi
|
||||
|
||||
tc_clear "$ifc" || true
|
||||
tc_apply "$ifc" "$per_kbit"
|
||||
}
|
||||
|
||||
clear_all() {
|
||||
local ifc
|
||||
ifc=$(get_iface || echo eth0)
|
||||
ipt_clear iptables || true
|
||||
ipt_clear ip6tables || true
|
||||
tc_clear "$ifc" || true
|
||||
}
|
||||
|
||||
cmd="${1:-apply}"
|
||||
case "$cmd" in
|
||||
apply) apply ;;
|
||||
clear) clear_all ;;
|
||||
*) apply ;;
|
||||
esac
|
||||
Reference in New Issue
Block a user