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.

Reply via email to