Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions net/trafficshaper/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk

PKG_NAME:=trafficshaper
PKG_VERSION:=1.0.0
PKG_RELEASE:=3
PKG_RELEASE:=4
PKG_MAINTAINER:=Luiz Angelo Daros de Luca <luizluca@gmail.com>

PKG_LICENSE:=GPL-2.0-or-later
Expand All @@ -19,7 +19,12 @@ define Package/trafficshaper
SECTION:=net
CATEGORY:=Network
TITLE:=WAN traffic shaper based on LAN addresses
DEPENDS:=+tc +kmod-sched-core +kmod-sched-connmark +kmod-ifb +iptables +IPV6:ip6tables +kmod-sched-cake +iptables-mod-conntrack-extra
DEPENDS:=+tc +kmod-sched-core +kmod-sched-connmark +kmod-ifb \
+(PACKAGE_nftables-json||PACKAGE_nftables-nojson):nftables \
+!(PACKAGE_nftables-json||PACKAGE_nftables-nojson):iptables \
+(IPV6&&!(PACKAGE_nftables-json||PACKAGE_nftables-nojson)):ip6tables \
+kmod-sched-cake \
+!(PACKAGE_nftables-json||PACKAGE_nftables-nojson):iptables-mod-conntrack-extra
PKGARCH:=all
endef

Expand Down
1 change: 1 addition & 0 deletions net/trafficshaper/files/trafficshaper.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package trafficshaper

config globals 'globals'
option mark_mask '0xFF'
option firewall_backend 'auto'

config wan 'wan'
option downlink '20000'
Expand Down
157 changes: 140 additions & 17 deletions net/trafficshaper/files/trafficshaper.init
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ die() {

APPNAME="trafficshaper"
IPT_CHAIN=$APPNAME
NFT_TABLE=$APPNAME

debug_exec(){
local err
Expand All @@ -43,6 +44,7 @@ IP="debug_exec ip"
TC="debug_exec tc"
IP4T="debug_exec iptables -w 5"
IP6T="debug_exec ip6tables -w 5"
NFT="debug_exec nft"

#QDISC="cake autorate_ingress internet ethernet diffserv4 triple-isolate"
QDISC="cake"
Expand All @@ -56,14 +58,37 @@ preinit(){
}

requires() {
if ! command -v ip6tables &>/dev/null; then
v "Disabling IPv6 as ip6tables was not found"
IP6T=true
fi

. /lib/functions/network.sh

config_load $APPNAME
config_get firewall_backend globals firewall_backend auto

case "$firewall_backend" in
auto)
if command -v nft >/dev/null; then
firewall_backend="nftables"
else
firewall_backend="iptables"
fi
;;
nft|nftables)
firewall_backend="nftables"
;;
iptables)
;;
*)
die 2 "unknown firewall_backend '$firewall_backend'"
;;
esac

if [ "$firewall_backend" = "nftables" ] && ! command -v nft &>/dev/null; then
die 1 "firewall_backend nftables selected but nft was not found"
fi

if [ "$firewall_backend" = "iptables" ] && ! command -v ip6tables &>/dev/null; then
v "Disabling IPv6 as ip6tables was not found"
IP6T=true
fi
}

do_stop() {
Expand All @@ -74,15 +99,7 @@ do_stop() {

v "Stopping $APPNAME${only_int:+ for interface $only_int}"
if [ -z "$only_int" ]; then
d "Cleaning iptables"
# Cleaning iptables
for IPT in "$IP4T" "$IP6T"; do
$IPT -t mangle -D FORWARD -j $IPT_CHAIN &>/dev/null || :
$IPT -t mangle -F $IPT_CHAIN &>/dev/null || :
$IPT -t mangle -X $IPT_CHAIN &>/dev/null || :
$IPT -t mangle -F $IPT_CHAIN-classify &>/dev/null || :
$IPT -t mangle -X $IPT_CHAIN-classify &>/dev/null || :
done
stop_firewall
fi

d "Cleaning tc"
Expand Down Expand Up @@ -156,6 +173,32 @@ mask_range() {
return 0
}

stop_firewall_iptables() {
command -v iptables &>/dev/null || return 0
command -v ip6tables &>/dev/null || IP6T=true

d "Cleaning iptables"
for IPT in "$IP4T" "$IP6T"; do
$IPT -t mangle -D FORWARD -j $IPT_CHAIN &>/dev/null || :
$IPT -t mangle -F $IPT_CHAIN &>/dev/null || :
$IPT -t mangle -X $IPT_CHAIN &>/dev/null || :
$IPT -t mangle -F $IPT_CHAIN-classify &>/dev/null || :
$IPT -t mangle -X $IPT_CHAIN-classify &>/dev/null || :
done
}

stop_firewall_nftables() {
command -v nft &>/dev/null || return 0

d "Cleaning nftables"
$NFT destroy table inet "$NFT_TABLE" &>/dev/null || :
}

stop_firewall() {
stop_firewall_iptables
stop_firewall_nftables
}

start_iptables(){
d "Creating iptables mangle rules"

Expand Down Expand Up @@ -226,6 +269,81 @@ start_iptables(){
$IP6T -t mangle -A $IPT_CHAIN-classify -j CONNMARK --save-mark --nfmask $mark_mask --ctmask $mark_mask
}

start_nftables() {
d "Creating nftables mangle rules"

config_get mark_mask globals mark_mask 0xFF
local mark_mask_dec mark_mask_inv fsb_lst class_id_max class_id_shift nft_rules
mark_mask_dec=$(($mark_mask))
mark_mask=$(printf '0x%X\n' "$mark_mask_dec")
mark_mask_inv=$(printf '0x%X\n' $((0xFFFFFFFF & ~mark_mask_dec)))

fsb_lst=$(mask_range $mark_mask)
class_id_max=$(((1<<(${fsb_lst#* } - ${fsb_lst% *} +1))+1))
class_id_shift=$((${fsb_lst% *}))

nft_rules="$(
{
printf '%s\n' "#!/usr/sbin/nft -f" ""
$NFT list table inet "$NFT_TABLE" &>/dev/null && \
printf '%s\n' "destroy table inet $NFT_TABLE"
printf '%s\n' \
"add table inet $NFT_TABLE" \
"add chain inet $NFT_TABLE forward { type filter hook forward priority mangle + 10; policy accept; }" \
"add chain inet $NFT_TABLE classify" \
"add rule inet $NFT_TABLE forward meta mark & $mark_mask != 0x0 counter return" \
"add rule inet $NFT_TABLE forward counter goto classify comment \"If no class, try to classify\""

local class class_reserved_uplink class_reserved_downlink class_nets i=2 xi nft_family
for class in $(config_foreach echo class); do
config_get class_reserved_uplink $class reserved_uplink
config_get class_reserved_downlink $class reserved_downlink
config_get class_nets $class network
if [ "$class" = default ]; then
if [ -z "$class_reserved_uplink" -a -z "$class_reserved_downlink" ] ; then
die 2 "class default must defined either reserved uplink or downlink!"
fi
if [ "$class_nets" ]; then
die 2 "class default must not have any network defined!"
fi
else
if [ "$i" -ge "$class_id_max" ]; then
die 1 "Max client classes reached. Please, use less classes or increase option mark_mask '$mark_mask' in globals. Current mask allows only $((class_id_max-2)) classes if default is the last one."
fi
fi

xi=$(printf '0x%X\n' $(((i-1)<<class_id_shift)))

for class_net in $class_nets; do
case $class_net in
*:*) nft_family="ip6" ;;
*.*) nft_family="ip" ;;
*) die 2 "Unknown address family of network $class_net in class $class!"
esac
if [ "$class_reserved_uplink" ]; then
printf '%s\n' "add rule inet $NFT_TABLE classify $nft_family saddr $class_net counter meta mark set (meta mark & $mark_mask_inv) | $xi comment \"$APPNAME-$class up\""
fi
if [ "$class_reserved_downlink" ]; then
printf '%s\n' "add rule inet $NFT_TABLE classify $nft_family daddr $class_net counter meta mark set (meta mark & $mark_mask_inv) | $xi comment \"$APPNAME-$class down\""
fi
done
: $((i++))
done

}
)"

printf '%s\n' "$nft_rules" | $NFT -c -f -
printf '%s\n' "$nft_rules" | $NFT -f -
}

start_firewall() {
case "$firewall_backend" in
nftables) start_nftables ;;
iptables) start_iptables ;;
esac
}



start_tc_interface() {
Expand Down Expand Up @@ -390,7 +508,7 @@ do_start() {
fi
default_class_id=${default_class_id% *}

[ "$only_int" ] || start_iptables
[ "$only_int" ] || start_firewall
start_tc "$default_class_id" "$only_int"

trap - EXIT
Expand All @@ -409,11 +527,15 @@ restart_service() {
}

is_running() {
$IP4T -t mangle -L $IPT_CHAIN &>/dev/null
case "$firewall_backend" in
nftables) $NFT list table inet "$NFT_TABLE" &>/dev/null ;;
iptables) $IP4T -t mangle -L $IPT_CHAIN &>/dev/null ;;
esac
}

reload_service() {
preinit
requires
if ! is_running; then
d "Not running. Nothing to reload"
return 0
Expand Down Expand Up @@ -442,7 +564,8 @@ service_triggers() {

validate_trafficshaper_global() {
uci_validate_section $APPNAME global "${1}" \
'mark_mask:uinteger:0xFF'
'mark_mask:uinteger:0xFF' \
'firewall_backend:string:auto'
}

validate_trafficshaper_wan() {
Expand Down