diff --git a/README.md b/README.md index 94d00dcd3..05c0fcdc0 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,12 @@ Install build packages: sudo apt install build-essential libncurses5-dev gawk g # Doing a native build on Linux First we need to clone and setup our tree. This will result in an openwrt/. ``` -python3 setup.py --setup +./setup.py --setup ``` Next we need to select the profile and base package selection. This setup will install the feeds, packages and generate the .config file. ``` cd openwrt -./scripts/gen_config.py ea8300 ucentral-ap wifi +./scripts/gen_config.py ea8300 ``` Finally we can build the tree. ``` diff --git a/feeds/ucentral/ratelimit/Makefile b/feeds/ucentral/ratelimit/Makefile new file mode 100644 index 000000000..6962f53f3 --- /dev/null +++ b/feeds/ucentral/ratelimit/Makefile @@ -0,0 +1,34 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=ratelimit +PKG_RELEASE:=1 + +PKG_MAINTAINER:=John Crispin + +include $(INCLUDE_DIR)/package.mk + +define Package/ratelimit + SECTION:=net + CATEGORY:=Network + TITLE:=Wireless ratelimiting + DEPENDS:=hostapd-utils +endef + +define Package/ratelimit/description + Allow Wireless client rate limiting +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Compile/Default + +endef +Build/Compile = $(Build/Compile/Default) + +define Package/ratelimit/install + $(CP) ./files/* $(1) +endef + +$(eval $(call BuildPackage,ratelimit)) diff --git a/feeds/ucentral/ratelimit/files/etc/config/ratelimit b/feeds/ucentral/ratelimit/files/etc/config/ratelimit new file mode 100644 index 000000000..a03420d21 --- /dev/null +++ b/feeds/ucentral/ratelimit/files/etc/config/ratelimit @@ -0,0 +1,3 @@ +config rate uCentral + option egress 10 + option ingress 20 diff --git a/feeds/ucentral/ratelimit/files/etc/hotplug.d/net/30-ratelimit b/feeds/ucentral/ratelimit/files/etc/hotplug.d/net/30-ratelimit new file mode 100644 index 000000000..0643d6071 --- /dev/null +++ b/feeds/ucentral/ratelimit/files/etc/hotplug.d/net/30-ratelimit @@ -0,0 +1,13 @@ +#!/bin/sh + +[ "${INTERFACE:0:4}" == "wlan" ] || exit 0 + +[ "$ACTION" == remove ] && { + ratelimit deliface $INTERFACE + exit 0 +} + +[ "$ACTION" == add ] && { + ratelimit waitiface $INTERFACE & + exit 0 +} diff --git a/feeds/ucentral/ratelimit/files/usr/bin/ratelimit b/feeds/ucentral/ratelimit/files/usr/bin/ratelimit new file mode 100755 index 000000000..8c3f4c9fa --- /dev/null +++ b/feeds/ucentral/ratelimit/files/usr/bin/ratelimit @@ -0,0 +1,159 @@ +#!/bin/sh + +wrapper() { + echo calling $* + $* +} + +TC() { + wrapper tc $* +} + +IP() { + wrapper ip $* +} + +get_id() { + addr=$1 + hashval="0x$(echo "$addr" | md5sum | head -c8)" + mask=0xfff + echo $(($hashval & $mask)) +} + +deliface() { + local ifb=rateifb$1 + local iface=$1 + + [ -d /sys/class/net/$ifb/ ] || return 0 + + logger "ratelimit: deleting old iface settings" + + IP link set $ifb down + IP link del $ifb + + TC qdisc del dev $iface root &2> /dev/null + + rm -f /tmp/ratelimit.$iface + [ -f /tmp/run/hostapd-cli-$iface.pid ] && kill "$(cat /tmp/run/hostapd-cli-$iface.pid)" +} + +addiface() { + local ifb=rateifb$1 + local iface=$1 + local ssid + + + [ -d /sys/class/net/$ifb/ ] && { + return 0 + } + + ssid=$(ubus call network.wireless status | jsonfilter -e '@[*].interfaces[@.ifname="'"$iface"'"].config.ssid') + [ -z "$ssid" ] && { + echo "ratelimit: failed to lookup ssid" + exit 1 + } + logger "ratelimit: adding new iface settings" + + uci get ratelimit.$ssid + [ $? -eq 0 ] || exit 0 + + echo -n $ssid > /tmp/ratelimit.$iface + + IP link add name $ifb type ifb + IP link set $ifb up + + sleep 1 + + TC qdisc add dev $iface root handle 1: htb default 10 + TC qdisc add dev $iface ingress + TC filter add dev $iface parent ffff: protocol all prio 10 u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev $ifb + + TC qdisc add dev $ifb root handle 1: htb default 10 + hostapd_cli -a /usr/libexec/ratelimit.sh -i $iface -P /tmp/run/hostapd-cli-$iface.pid -B +} + +delclient() { + local ifb=rateifb$1 + local iface=$1 + local mac=${2//:} + local id=$3 + + logger "ratelimit: delete old client entries" + + [ -z "$id" ] && id=$(get_id $mac) + + local mac1=${mac:0:4} + local mac2=${mac:4} + + TC filter add dev $iface protocol ip parent 1:0 prio 1 u32 match u16 0x0800 0xFFFF at -2 match u32 0x$mac2 0xFFFFFFFF at -12 match u16 0x$mac1 0xFFFF at -14 flowid 1:$id + #TC filter del dev $iface protocol ip parent 1:0 prio 1 u32 match ip dst $ip flowid 1:$id + TC class del dev $iface parent 1: classid 1:$id + + local mac1=${mac:0:8} + local mac2=${mac:8} + + TC filter add dev $ifb protocol ip parent 1:0 prio 1 u32 match u16 0x0800 0xFFFF at -2 match u16 0x$mac2 0xFFFF at -4 match u32 0x$mac1 0xFFFFFFFF at -8 flowid 1:$id + #TC filter del dev $ifb protocol ip parent 1:0 prio 1 u32 match ip src $ip flowid 1:$id + TC class del dev $ifb parent 1: classid 1:$id +} + +addclient() { + local ifb=rateifb$1 + local iface=$1 + local mac=${2//:} + local ingress=$3 + local egress=$4 + local ssid=$(cat /tmp/ratelimit.$iface) + + logger "ratelimit: adding client" + + [ -z "$egress" -o -z $ingress ] && { + egress=$(uci get ratelimit.$ssid.egress) + ingress=$(uci get ratelimit.$ssid.ingress) + } + [ -z "$egress" -o -z $ingress ] && { + logger "ratelimit: no valid rates" + exit 1 + } + + local id=$(get_id $mac) + + delclient $1 $2 $id + logger "ratelimit: add new client entries for $2" + + local mac1=${mac:0:4} + local mac2=${mac:4} + + TC class add dev $iface parent 1: classid 1:$id htb rate ${egress}mbit ceil ${egress}mbit + TC filter add dev $iface protocol ip parent 1:0 prio 1 u32 match u16 0x0800 0xFFFF at -2 match u32 0x$mac2 0xFFFFFFFF at -12 match u16 0x$mac1 0xFFFF at -14 flowid 1:$id + #TC filter add dev $iface protocol ip parent 1:0 prio 1 u32 match ip dst $ip flowid 1:$id + + local mac1=${mac:0:8} + local mac2=${mac:8} + + TC class add dev $ifb parent 1: classid 1:$id htb rate ${ingress}mbit ceil ${ingress}mbit + TC filter add dev $ifb protocol ip parent 1:0 prio 1 u32 match u16 0x0800 0xFFFF at -2 match u16 0x$mac2 0xFFFF at -4 match u32 0x$mac1 0xFFFFFFFF at -8 flowid 1:$id + #TC filter add dev $ifb protocol ip parent 1:0 prio 1 u32 match ip src $ip flowid 1:$id + + +} + +waitiface() { + local iface=$1 + + ubus -t 15 wait_for hostapd.$1 + + [ $? -eq 0 ] || exit 0 + + addiface $iface +} + +flush() { + for a in `ls /sys/class/net/ | grep rateifb`; do + deliface ${a:7} + done +} + +cmd=$1 +shift +$cmd $@ diff --git a/feeds/ucentral/ratelimit/files/usr/libexec/ratelimit.sh b/feeds/ucentral/ratelimit/files/usr/libexec/ratelimit.sh new file mode 100644 index 000000000..2da015563 --- /dev/null +++ b/feeds/ucentral/ratelimit/files/usr/libexec/ratelimit.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +case $2 in +AP-STA-CONNECTED) + ratelimit addclient $1 $3 + ;; +AP-STA-DISCONNECTED) + ratelimit delclient $1 $3 + ;; +esac diff --git a/feeds/ucentral/ucentral-schema/Makefile b/feeds/ucentral/ucentral-schema/Makefile index e95edc0a8..b0a2f19d7 100644 --- a/feeds/ucentral/ucentral-schema/Makefile +++ b/feeds/ucentral/ucentral-schema/Makefile @@ -6,7 +6,7 @@ PKG_RELEASE:=1 PKG_SOURCE_URL=https://github.com/blogic/ucentral-schema.git PKG_SOURCE_PROTO:=git PKG_SOURCE_DATE:=2021-02-15 -PKG_SOURCE_VERSION:=8396515cdd6f2c782aa0b1e2f21662d5846457b8 +PKG_SOURCE_VERSION:=9e65a86cd998d87415cf8325895a64e4d8e2e425 PKG_MAINTAINER:=John Crispin PKG_LICENSE:=BSD-3-Clause diff --git a/profiles/ucentral-ap.yml b/profiles/ucentral-ap.yml index a0b52538a..f920cabb7 100644 --- a/profiles/ucentral-ap.yml +++ b/profiles/ucentral-ap.yml @@ -31,9 +31,9 @@ packages: - usteer - udevmand - opennds + - ratelimit - rtty-openssl - sqm-scripts - - tmate - tcpdump - vxlan diffconfig: |