Great stuff, David !

Thanks for sharing.

Lonnie



> On Jun 5, 2018, at 7:09 PM, David Kerr <da...@kerr.net> wrote:
> 
> 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