If using a WAN failover that uses cellular wireless connection you may need
to carefully control how much traffic you send over that link to avoid very
high data overage costs. To this end I have implemented the following
controls on my Astlinux box...
1) Block any given local device by MAC address from using the link
For example... block my Apple TV so no video streaming to that device.
2) Block any given TCP/IP port for inbound/outbound traffic.
For example... block ports used by an online backup service
3) Rate limit any given device by MAC address to e.g. 256kbps
For example... discourage video streaming to kids iPhones while still
allowing messaging.
The above can all be implemented in firewall custom rules. Below are the
functions I implemented...
#
=============================================================================
## Function to block devices so that they cannot access network through a
given
## interface. And/or block traffic to/from a specific tcp/udp port number.
## >>>Call this function only once per interface
## Parameters:
## interface (e.g. eth2)
## MacAddrs (list of mac addresses)
## Ports (list of ports)
## The interface local IP addresses are whitelisted
block_ports_macaddrs()
{
local IFS=' '
local mac
local interface="$1"
local macs="${2//,/ }" # if comma delimited convert to space delimited
local ports="$(echo $3 | tr -s ' ' ',')" # make sure comma delimited
local chain=$(echo "FORWARD_$interface" | tr [a-z] [A-Z]) # uppercase
interface name
local ipv4=$(ip -4 addr show $interface | grep 'inet ' | awk -F' ' '{
print $2 }')
local ipv6ula=$(ip -6 addr show $interface | grep 'inet6 fd' | awk -F' '
'{ print $2 }')
iptables -N $chain 2>/dev/null
iptables -F $chain
iptables -A FORWARD_CHAIN -o $interface -j $chain
if [ -n "$ipv4" ]; then
ip4tables -A $chain -d "$ipv4" -j ACCEPT
fi
if [ -n "$ipv6ula" ]; then
ip6tables -A $chain -d "$ipv6ula" -j ACCEPT
fi
for mac in $macs; do
echo "[CUSTOM RULE] Block MAC address $mac on interface $interface"
iptables -A $chain -m mac --mac-source $mac -j DROP
done
if [ -n "$ports" ]; then
echo "[CUSTOM RULE] Block ports $ports on interface $interface"
iptables -A $chain -p tcp -m multiport --dports $ports -j DROP
iptables -A $chain -p tcp -m multiport --sports $ports -j DROP
iptables -A $chain -p udp -m multiport --dports $ports -j DROP
iptables -A $chain -p udp -m multiport --sports $ports -j DROP
fi
}
#
=============================================================================
## Function to prepare for rate limiting for traffic between local net and
## the WAN failover wireguard net. Actual packet selection for rate
## limiting will take place in iptables. This function limits only
## internal interfaces or WAN failover, not default EXTIF.
prepare_rate_limits()
{
local interface
local IFS=' '
for interface in $INT_IF $EXT2IF; do
echo "[CUSTOM RULE] Prepare $interface for rate limiting"
tc qdisc del dev $interface root 2>/dev/null
tc qdisc add dev $interface root handle 1: htb
tc class add dev $interface parent 1: classid 1:1 htb rate 256Kbit
tc class add dev $interface parent 1: classid 1:2 htb rate 512Kbit
tc class add dev $interface parent 1: classid 1:3 htb rate 1024Kbit
tc qdisc add dev $interface parent 1:1 handle 2: sfq perturb 10
tc qdisc add dev $interface parent 1:2 handle 3: sfq perturb 10
tc qdisc add dev $interface parent 1:3 handle 4: sfq perturb 10
tc filter add dev $interface protocol ip parent 1: prio 1 handle 1 fw
flowid 1:1
tc filter add dev $interface protocol ip parent 1: prio 1 handle 2 fw
flowid 1:2
tc filter add dev $interface protocol ip parent 1: prio 1 handle 3 fw
flowid 1:3
done
}
## Function to Rate limit some devices so that they cannot drive up huge
data use.
## >>>Call this function only once per interface
## This uses kernel traffic control (tc) rules set on the net interface
## Parameters:
## interface (e.g. eth2)
## MacAddrs (list of mac addresses)
## LimitMarks (list of limit-marks corresponding to each mac address)
## Mark 1: 256 Kbps, 2: 512 Kbps, 3: 1 Mbps
## Inbound packets have the packet mark restored
## Outbound packets from selected devices are marked and the packet saved
## The interface local IP addresses are whitelisted
rate_limit_macaddrs()
{
local IFS=' '
local mac
local interface="$1"
local macs="${2//,/ }" # if comma delimited convert to space delimited
local rate_marks="${3//,/ }" # if comma delimited convert to space
delimited
local chain=$(echo "FORWARD_$interface" | tr [a-z] [A-Z]) # uppercase
interface name
local ipv4=$(ip -4 addr show $interface | grep 'inet ' | awk -F' ' '{
print $2 }')
local ipv6ula=$(ip -6 addr show $interface | grep 'inet6 fd' | awk -F' '
'{ print $2 }')
iptables -N $chain -t mangle 2>/dev/null
iptables -F $chain -t mangle
iptables -A FORWARD -t mangle -i $interface -j CONNMARK --restore-mark
iptables -A FORWARD -t mangle -o $interface -j $chain
if [ -n "$ipv4" ]; then
ip4tables -A $chain -t mangle -d "$ipv4" -j ACCEPT
fi
if [ -n "$ipv6ula" ]; then
ip6tables -A $chain -t mangle -d "$ipv6ula" -j ACCEPT
fi
iptables -A $chain -t mangle -j CONNMARK --restore-mark
iptables -A $chain -t mangle -m mark ! --mark 0 -j ACCEPT
for mac in $macs; do
echo "[CUSTOM RULE] Rate limit MAC address $mac on interface $interface"
mark=${rate_marks%% *}
rate_marks=${rate_marks#* }
iptables -A $chain -t mangle -m mac --mac-source $mac -j MARK
--set-mark ${mark:-1}
done
iptables -A $chain -t mangle -j CONNMARK --save-mark
iptables -A $chain -t mangle -j ACCEPT
}
#
=============================================================================
## Make the calls to block / rate limit
prepare_rate_limits
rate_limit_macaddrs \
"$EXT2IF" \
"52:54:00:43:1c:6e 3c:2e:ff:xx:xx:xx 8c:85:90:xx:xx:xx b8:e8:56:xx:xx:xx" \
"3 1 1 2"
##^ TestVM, iPhone, MacBook, iPad
block_ports_macaddrs \
"$EXT2IF" \
"00:08:9B:xx:xx:xx 00:08:9B:xx:xx:xx 00:08:9B:xx:xx:xx 52:54:00:xx:xx:xx
08:66:98:xx:xx:xx" \
"4242"
##^ QNAP, QNAP, QNAP, UbuntuVM, AppleTV
##^ 4242 = crashplan ports
Now if you are using wireguard to create a VPN link to a failover host you
also want to repeat the above settings with "wg0" in place of "$EXT2IF" and
because the wg0 interface is taken down during a wireguard VPN restart you
also need to reset the rate limiting traffic controls "tc" commands in the
up/down script for that. For example...
#!/bin/bash
## Action: POST_UP PRE_DOWN
action="$1"
## WireGuard Interface: (ex. wg0)
interface="$2"
if [ "$action" = "POST_UP" ]; then
logger -t wireguard -p kern.info "WireGuard VPN is started on
'$interface' interface."
echo "Prepare $interface for rate limiting"
tc qdisc del dev $interface root 2>/dev/null
tc qdisc add dev $interface root handle 1: htb
tc class add dev $interface parent 1: classid 1:1 htb rate 256Kbit
tc class add dev $interface parent 1: classid 1:2 htb rate 512Kbit
tc class add dev $interface parent 1: classid 1:3 htb rate 1024Kbit
tc qdisc add dev $interface parent 1:1 handle 2: sfq perturb 10
tc qdisc add dev $interface parent 1:2 handle 3: sfq perturb 10
tc qdisc add dev $interface parent 1:3 handle 4: sfq perturb 10
tc filter add dev $interface protocol ip parent 1: prio 1 handle 1 fw
flowid 1:1
tc filter add dev $interface protocol ip parent 1: prio 1 handle 2 fw
flowid 1:2
tc filter add dev $interface protocol ip parent 1: prio 1 handle 3 fw
flowid 1:3
elif [ "$action" = "PRE_DOWN" ]; then
logger -t wireguard -p kern.info "WireGuard VPN is stopping '$interface'
interface."
fi
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Astlinux-users mailing list
Astlinux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/astlinux-users
Donations to support AstLinux are graciously accepted via PayPal to
pay...@krisk.org.