Files
packages/net/mwan3/files/lib/mwan3/mwan3.sh
T
Marcin Jurkowski de4fc2b5de mwan3: support various interface tracking methods
Adds support for interface tracking using either ping, arping or
httping. This allows to track interface status on networks with filtered
ICMP traffic or simply to monitor data link layer etc.

To facilitate binding to a specified interface its IP address is passed
as a new mwan3track parameter. It's currently required by httping
and possibly by other tools that may be added in the future.

Signed-off-by: Marcin Jurkowski <marcin1j@gmail.com>
2017-08-02 17:44:07 +02:00

871 lines
24 KiB
Bash

#!/bin/sh
IP4="ip -4"
IP6="ip -6"
IPS="ipset"
IPT4="iptables -t mangle -w"
IPT6="ip6tables -t mangle -w"
LOG="logger -t mwan3 -p"
CONNTRACK_FILE="/proc/net/nf_conntrack"
mwan3_lock() {
lock /var/run/mwan3.lock
}
mwan3_unlock() {
lock -u /var/run/mwan3.lock
}
mwan3_get_iface_id()
{
local _tmp _iface _iface_count
_iface="$2"
mwan3_get_id()
{
let _iface_count++
[ "$1" == "$_iface" ] && _tmp=$_iface_count
}
config_foreach mwan3_get_id interface
export "$1=$_tmp"
}
mwan3_set_connected_iptables()
{
local connected_network_v4 connected_network_v6
$IPS -! create mwan3_connected_v4 hash:net
$IPS create mwan3_connected_v4_temp hash:net
for connected_network_v4 in $($IP4 route | awk '{print $1}' | egrep '[0-9]{1,3}(\.[0-9]{1,3}){3}'); do
$IPS -! add mwan3_connected_v4_temp $connected_network_v4
done
for connected_network_v4 in $($IP4 route list table 0 | awk '{print $2}' | egrep '[0-9]{1,3}(\.[0-9]{1,3}){3}'); do
$IPS -! add mwan3_connected_v4_temp $connected_network_v4
done
$IPS add mwan3_connected_v4_temp 224.0.0.0/3
$IPS swap mwan3_connected_v4_temp mwan3_connected_v4
$IPS destroy mwan3_connected_v4_temp
$IPS -! create mwan3_connected_v6 hash:net family inet6
$IPS create mwan3_connected_v6_temp hash:net family inet6
for connected_network_v6 in $($IP6 route | awk '{print $1}' | egrep '([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])'); do
$IPS -! add mwan3_connected_v6_temp $connected_network_v6
done
$IPS swap mwan3_connected_v6_temp mwan3_connected_v6
$IPS destroy mwan3_connected_v6_temp
$IPS -! create mwan3_connected list:set
$IPS -! add mwan3_connected mwan3_connected_v4
$IPS -! add mwan3_connected mwan3_connected_v6
}
mwan3_set_general_rules()
{
local IP
for IP in "$IP4" "$IP6"; do
if [ -z "$($IP rule list | awk '$1 == "2253:"')" ]; then
$IP rule add pref 2253 fwmark 0xfd00/0xff00 blackhole
fi
if [ -z "$($IP rule list | awk '$1 == "2254:"')" ]; then
$IP rule add pref 2254 fwmark 0xfe00/0xff00 unreachable
fi
done
}
mwan3_set_general_iptables()
{
local IPT
for IPT in "$IPT4" "$IPT6"; do
if ! $IPT -S mwan3_ifaces_in &> /dev/null; then
$IPT -N mwan3_ifaces_in
fi
if ! $IPT -S mwan3_connected &> /dev/null; then
$IPT -N mwan3_connected
$IPS -! create mwan3_connected list:set
$IPT -A mwan3_connected -m set --match-set mwan3_connected dst -j MARK --set-xmark 0xff00/0xff00
fi
if ! $IPT -S mwan3_ifaces_out &> /dev/null; then
$IPT -N mwan3_ifaces_out
fi
if ! $IPT -S mwan3_rules &> /dev/null; then
$IPT -N mwan3_rules
fi
if ! $IPT -S mwan3_hook &> /dev/null; then
$IPT -N mwan3_hook
$IPT -A mwan3_hook -j CONNMARK --restore-mark --nfmask 0xff00 --ctmask 0xff00
$IPT -A mwan3_hook -m mark --mark 0x0/0xff00 -j mwan3_ifaces_in
$IPT -A mwan3_hook -m mark --mark 0x0/0xff00 -j mwan3_connected
$IPT -A mwan3_hook -m mark --mark 0x0/0xff00 -j mwan3_ifaces_out
$IPT -A mwan3_hook -m mark --mark 0x0/0xff00 -j mwan3_rules
$IPT -A mwan3_hook -j CONNMARK --save-mark --nfmask 0xff00 --ctmask 0xff00
$IPT -A mwan3_hook -m mark ! --mark 0xff00/0xff00 -j mwan3_connected
fi
if ! $IPT -S PREROUTING | grep mwan3_hook &> /dev/null; then
$IPT -A PREROUTING -j mwan3_hook
fi
if ! $IPT -S OUTPUT | grep mwan3_hook &> /dev/null; then
$IPT -A OUTPUT -j mwan3_hook
fi
done
}
mwan3_create_iface_iptables()
{
local id family src_ip src_ipv6
config_get family $1 family ipv4
mwan3_get_iface_id id $1
[ -n "$id" ] || return 0
if [ "$family" == "ipv4" ]; then
ubus call network.interface.${1}_4 status &>/dev/null
if [ "$?" -eq "0" ]; then
network_get_ipaddr src_ip ${1}_4
else
network_get_ipaddr src_ip $1
fi
$IPS -! create mwan3_connected list:set
if ! $IPT4 -S mwan3_ifaces_in &> /dev/null; then
$IPT4 -N mwan3_ifaces_in
fi
if ! $IPT4 -S mwan3_ifaces_out &> /dev/null; then
$IPT4 -N mwan3_ifaces_out
fi
if ! $IPT4 -S mwan3_iface_in_$1 &> /dev/null; then
$IPT4 -N mwan3_iface_in_$1
fi
if ! $IPT4 -S mwan3_iface_out_$1 &> /dev/null; then
$IPT4 -N mwan3_iface_out_$1
fi
$IPT4 -F mwan3_iface_in_$1
$IPT4 -A mwan3_iface_in_$1 -i $2 -m set --match-set mwan3_connected src -m mark --mark 0x0/0xff00 -m comment --comment "default" -j MARK --set-xmark 0xff00/0xff00
$IPT4 -A mwan3_iface_in_$1 -i $2 -m mark --mark 0x0/0xff00 -m comment --comment "$1" -j MARK --set-xmark $(($id*256))/0xff00
$IPT4 -D mwan3_ifaces_in -m mark --mark 0x0/0xff00 -j mwan3_iface_in_$1 &> /dev/null
$IPT4 -A mwan3_ifaces_in -m mark --mark 0x0/0xff00 -j mwan3_iface_in_$1
$IPT4 -F mwan3_iface_out_$1
$IPT4 -A mwan3_iface_out_$1 -s $src_ip -m mark --mark 0x0/0xff00 -m comment --comment "$1" -j MARK --set-xmark $(($id*256))/0xff00
$IPT4 -D mwan3_ifaces_out -m mark --mark 0x0/0xff00 -j mwan3_iface_out_$1 &> /dev/null
$IPT4 -A mwan3_ifaces_out -m mark --mark 0x0/0xff00 -j mwan3_iface_out_$1
fi
if [ "$family" == "ipv6" ]; then
ubus call network.interface.${1}_6 status &>/dev/null
if [ "$?" -eq "0" ]; then
network_get_ipaddr6 src_ipv6 ${1}_6
else
network_get_ipaddr6 src_ipv6 $1
fi
$IPS -! create mwan3_connected_v6 hash:net family inet6
if ! $IPT6 -S mwan3_ifaces_in &> /dev/null; then
$IPT6 -N mwan3_ifaces_in
fi
if ! $IPT6 -S mwan3_ifaces_out &> /dev/null; then
$IPT6 -N mwan3_ifaces_out
fi
if ! $IPT6 -S mwan3_iface_in_$1 &> /dev/null; then
$IPT6 -N mwan3_iface_in_$1
fi
if ! $IPT6 -S mwan3_iface_out_$1 &> /dev/null; then
$IPT6 -N mwan3_iface_out_$1
fi
$IPT6 -F mwan3_iface_in_$1
$IPT6 -A mwan3_iface_in_$1 -i $2 -m set --match-set mwan3_connected_v6 src -m mark --mark 0x0/0xff00 -m comment --comment "default" -j MARK --set-xmark 0xff00/0xff00
$IPT6 -A mwan3_iface_in_$1 -i $2 -m mark --mark 0x0/0xff00 -m comment --comment "$1" -j MARK --set-xmark $(($id*256))/0xff00
$IPT6 -D mwan3_ifaces_in -m mark --mark 0x0/0xff00 -j mwan3_iface_in_$1 &> /dev/null
$IPT6 -A mwan3_ifaces_in -m mark --mark 0x0/0xff00 -j mwan3_iface_in_$1
$IPT6 -F mwan3_iface_out_$1
$IPT6 -A mwan3_iface_out_$1 -s $src_ipv6 -m mark --mark 0x0/0xff00 -m comment --comment "$1" -j MARK --set-xmark $(($id*256))/0xff00
$IPT6 -D mwan3_ifaces_out -m mark --mark 0x0/0xff00 -j mwan3_iface_out_$1 &> /dev/null
$IPT6 -A mwan3_ifaces_out -m mark --mark 0x0/0xff00 -j mwan3_iface_out_$1
fi
}
mwan3_delete_iface_iptables()
{
config_get family $1 family ipv4
if [ "$family" == "ipv4" ]; then
$IPT4 -D mwan3_ifaces_in -m mark --mark 0x0/0xff00 -j mwan3_iface_in_$1 &> /dev/null
$IPT4 -F mwan3_iface_in_$1 &> /dev/null
$IPT4 -X mwan3_iface_in_$1 &> /dev/null
$IPT4 -D mwan3_ifaces_out -m mark --mark 0x0/0xff00 -j mwan3_iface_out_$1 &> /dev/null
$IPT4 -F mwan3_iface_out_$1 &> /dev/null
$IPT4 -X mwan3_iface_out_$1 &> /dev/null
fi
if [ "$family" == "ipv6" ]; then
$IPT6 -D mwan3_ifaces_in -m mark --mark 0x0/0xff00 -j mwan3_iface_in_$1 &> /dev/null
$IPT6 -F mwan3_iface_in_$1 &> /dev/null
$IPT6 -X mwan3_iface_in_$1 &> /dev/null
$IPT6 -D mwan3_ifaces_out -m mark --mark 0x0/0xff00 -j mwan3_iface_out_$1 &> /dev/null
$IPT6 -F mwan3_iface_out_$1 &> /dev/null
$IPT6 -X mwan3_iface_out_$1 &> /dev/null
fi
}
mwan3_create_iface_route()
{
local id route_args
config_get family $1 family ipv4
mwan3_get_iface_id id $1
[ -n "$id" ] || return 0
if [ "$family" == "ipv4" ]; then
ubus call network.interface.${1}_4 status &>/dev/null
if [ "$?" -eq "0" ]; then
network_get_gateway route_args ${1}_4
else
network_get_gateway route_args $1
fi
route_args="via $route_args dev $2"
$IP4 route flush table $id
$IP4 route add table $id default $route_args
fi
if [ "$family" == "ipv6" ]; then
ubus call network.interface.${1}_6 status &>/dev/null
if [ "$?" -eq "0" ]; then
network_get_gateway6 route_args ${1}_6
else
network_get_gateway6 route_args $1
fi
route_args="via $route_args dev $2"
$IP6 route flush table $id
$IP6 route add table $id default $route_args
fi
}
mwan3_delete_iface_route()
{
local id
config_get family $1 family ipv4
mwan3_get_iface_id id $1
[ -n "$id" ] || return 0
if [ "$family" == "ipv4" ]; then
$IP4 route flush table $id
fi
if [ "$family" == "ipv6" ]; then
$IP6 route flush table $id
fi
}
mwan3_create_iface_rules()
{
local id family
config_get family $1 family ipv4
mwan3_get_iface_id id $1
[ -n "$id" ] || return 0
if [ "$family" == "ipv4" ]; then
while [ -n "$($IP4 rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
$IP4 rule del pref $(($id+1000))
done
while [ -n "$($IP4 rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
$IP4 rule del pref $(($id+2000))
done
$IP4 rule add pref $(($id+1000)) iif $2 lookup main
$IP4 rule add pref $(($id+2000)) fwmark $(($id*256))/0xff00 lookup $id
fi
if [ "$family" == "ipv6" ]; then
while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
$IP6 rule del pref $(($id+1000))
done
while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
$IP6 rule del pref $(($id+2000))
done
$IP6 rule add pref $(($id+1000)) iif $2 lookup main
$IP6 rule add pref $(($id+2000)) fwmark $(($id*256))/0xff00 lookup $id
fi
}
mwan3_delete_iface_rules()
{
local id family
config_get family $1 family ipv4
mwan3_get_iface_id id $1
[ -n "$id" ] || return 0
if [ "$family" == "ipv4" ]; then
while [ -n "$($IP4 rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
$IP4 rule del pref $(($id+1000))
done
while [ -n "$($IP4 rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
$IP4 rule del pref $(($id+2000))
done
fi
if [ "$family" == "ipv6" ]; then
while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
$IP6 rule del pref $(($id+1000))
done
while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
$IP6 rule del pref $(($id+2000))
done
fi
}
mwan3_delete_iface_ipset_entries()
{
local id setname entry
mwan3_get_iface_id id $1
[ -n "$id" ] || return 0
for setname in $(ipset -n list | grep ^mwan3_sticky_); do
for entry in $(ipset list $setname | grep "$(echo $(($id*256)) | awk '{ printf "0x%08x", $1; }')" | cut -d ' ' -f 1); do
$IPS del $setname $entry
done
done
}
mwan3_track()
{
local track_ip track_ips
mwan3_list_track_ips()
{
track_ips="$1 $track_ips"
}
config_list_foreach $1 track_ip mwan3_list_track_ips
kill $(pgrep -f "mwan3track $1") &> /dev/null
if [ -n "$track_ips" ]; then
[ -x /usr/sbin/mwan3track ] && /usr/sbin/mwan3track "$1" "$2" "$3" $track_ips &
fi
}
mwan3_track_signal()
{
local pid
pid="$(pgrep -f "mwan3track $1")"
if [ "${pid}" != "" ]; then
kill -USR1 "${pid}"
else
$LOG warn "Unable to send signal USR1 to mwan3track on interface $1 with pid ${pid}"
fi
}
mwan3_set_policy()
{
local iface_count id iface family metric probability weight
config_get iface $1 interface
config_get metric $1 metric 1
config_get weight $1 weight 1
[ -n "$iface" ] || return 0
mwan3_get_iface_id id $iface
[ -n "$id" ] || return 0
config_get family $iface family ipv4
if [ "$family" == "ipv4" ]; then
if [ -n "$($IP4 route list table $id)" ]; then
if [ "$metric" -lt "$lowest_metric_v4" ]; then
total_weight_v4=$weight
$IPT4 -F mwan3_policy_$policy
$IPT4 -A mwan3_policy_$policy -m mark --mark 0x0/0xff00 -m comment --comment "$iface $weight $weight" -j MARK --set-xmark $(($id*256))/0xff00
lowest_metric_v4=$metric
elif [ "$metric" -eq "$lowest_metric_v4" ]; then
total_weight_v4=$(($total_weight_v4+$weight))
probability=$(($weight*1000/$total_weight_v4))
if [ "$probability" -lt 10 ]; then
probability="0.00$probability"
elif [ $probability -lt 100 ]; then
probability="0.0$probability"
elif [ $probability -lt 1000 ]; then
probability="0.$probability"
else
probability="1"
fi
probability="-m statistic --mode random --probability $probability"
$IPT4 -I mwan3_policy_$policy -m mark --mark 0x0/0xff00 $probability -m comment --comment "$iface $weight $total_weight_v4" -j MARK --set-xmark $(($id*256))/0xff00
fi
fi
fi
if [ "$family" == "ipv6" ]; then
if [ -n "$($IP6 route list table $id)" ]; then
if [ "$metric" -lt "$lowest_metric_v6" ]; then
total_weight_v6=$weight
$IPT6 -F mwan3_policy_$policy
$IPT6 -A mwan3_policy_$policy -m mark --mark 0x0/0xff00 -m comment --comment "$iface $weight $weight" -j MARK --set-xmark $(($id*256))/0xff00
lowest_metric_v6=$metric
elif [ "$metric" -eq "$lowest_metric_v6" ]; then
total_weight_v6=$(($total_weight_v6+$weight))
probability=$(($weight*1000/$total_weight_v6))
if [ "$probability" -lt 10 ]; then
probability="0.00$probability"
elif [ $probability -lt 100 ]; then
probability="0.0$probability"
elif [ $probability -lt 1000 ]; then
probability="0.$probability"
else
probability="1"
fi
probability="-m statistic --mode random --probability $probability"
$IPT6 -I mwan3_policy_$policy -m mark --mark 0x0/0xff00 $probability -m comment --comment "$iface $weight $total_weight_v6" -j MARK --set-xmark $(($id*256))/0xff00
fi
fi
fi
}
mwan3_create_policies_iptables()
{
local last_resort lowest_metric_v4 lowest_metric_v6 total_weight_v4 total_weight_v6 policy IPT
policy="$1"
config_get last_resort $1 last_resort unreachable
if [ "$1" != $(echo "$1" | cut -c1-15) ]; then
$LOG warn "Policy $1 exceeds max of 15 chars. Not setting policy" && return 0
fi
for IPT in "$IPT4" "$IPT6"; do
if ! $IPT -S mwan3_policy_$1 &> /dev/null; then
$IPT -N mwan3_policy_$1
fi
$IPT -F mwan3_policy_$1
case "$last_resort" in
blackhole)
$IPT -A mwan3_policy_$1 -m mark --mark 0x0/0xff00 -m comment --comment "blackhole" -j MARK --set-xmark 0xfd00/0xff00
;;
default)
$IPT -A mwan3_policy_$1 -m mark --mark 0x0/0xff00 -m comment --comment "default" -j MARK --set-xmark 0xff00/0xff00
;;
*)
$IPT -A mwan3_policy_$1 -m mark --mark 0x0/0xff00 -m comment --comment "unreachable" -j MARK --set-xmark 0xfe00/0xff00
;;
esac
done
lowest_metric_v4=256
total_weight_v4=0
lowest_metric_v6=256
total_weight_v6=0
config_list_foreach $1 use_member mwan3_set_policy
}
mwan3_set_policies_iptables()
{
config_foreach mwan3_create_policies_iptables policy
}
mwan3_set_sticky_iptables()
{
local id iface
for iface in $($IPT4 -S $policy | cut -s -d'"' -f2 | awk '{print $1}'); do
if [ "$iface" == "$1" ]; then
mwan3_get_iface_id id $1
[ -n "$id" ] || return 0
for IPT in "$IPT4" "$IPT6"; do
if [ -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" -a -n "$($IPT -S mwan3_iface_out_$1 2> /dev/null)" ]; then
$IPT -I mwan3_rule_$rule -m mark --mark $(($id*256))/0xff00 -m set ! --match-set mwan3_sticky_$rule src,src -j MARK --set-xmark 0x0/0xff00
$IPT -I mwan3_rule_$rule -m mark --mark 0/0xff00 -j MARK --set-xmark $(($id*256))/0xff00
fi
done
fi
done
}
mwan3_set_user_iptables_rule()
{
local ipset family proto policy src_ip src_port sticky dest_ip dest_port use_policy timeout rule policy IPT
rule="$1"
config_get sticky $1 sticky 0
config_get timeout $1 timeout 600
config_get ipset $1 ipset
config_get proto $1 proto all
config_get src_ip $1 src_ip 0.0.0.0/0
config_get src_port $1 src_port 0:65535
config_get dest_ip $1 dest_ip 0.0.0.0/0
config_get dest_port $1 dest_port 0:65535
config_get use_policy $1 use_policy
config_get family $1 family any
if [ "$1" != $(echo "$1" | cut -c1-15) ]; then
$LOG warn "Rule $1 exceeds max of 15 chars. Not setting rule" && return 0
fi
if [ -n "$ipset" ]; then
ipset="-m set --match-set $ipset dst"
fi
if [ -n "$use_policy" ]; then
if [ "$use_policy" == "default" ]; then
policy="MARK --set-xmark 0xff00/0xff00"
elif [ "$use_policy" == "unreachable" ]; then
policy="MARK --set-xmark 0xfe00/0xff00"
elif [ "$use_policy" == "blackhole" ]; then
policy="MARK --set-xmark 0xfd00/0xff00"
else
if [ "$sticky" -eq 1 ]; then
policy="mwan3_policy_$use_policy"
for IPT in "$IPT4" "$IPT6"; do
if ! $IPT -S $policy &> /dev/null; then
$IPT -N $policy
fi
if ! $IPT -S mwan3_rule_$1 &> /dev/null; then
$IPT -N mwan3_rule_$1
fi
$IPT -F mwan3_rule_$1
done
$IPS -! create mwan3_sticky_v4_$rule hash:ip,mark markmask 0xff00 timeout $timeout
$IPS -! create mwan3_sticky_v6_$rule hash:ip,mark markmask 0xff00 timeout $timeout family inet6
$IPS -! create mwan3_sticky_$rule list:set
$IPS -! add mwan3_sticky_$rule mwan3_sticky_v4_$rule
$IPS -! add mwan3_sticky_$rule mwan3_sticky_v6_$rule
config_foreach mwan3_set_sticky_iptables interface
for IPT in "$IPT4" "$IPT6"; do
$IPT -A mwan3_rule_$1 -m mark --mark 0/0xff00 -j $policy
$IPT -A mwan3_rule_$1 -m mark ! --mark 0xfc00/0xfc00 -j SET --del-set mwan3_sticky_$rule src,src
$IPT -A mwan3_rule_$1 -m mark ! --mark 0xfc00/0xfc00 -j SET --add-set mwan3_sticky_$rule src,src
done
policy="mwan3_rule_$1"
else
policy="mwan3_policy_$use_policy"
for IPT in "$IPT4" "$IPT6"; do
if ! $IPT -S $policy &> /dev/null; then
$IPT -N $policy
fi
done
fi
fi
if [ "$family" == "any" ]; then
for IPT in "$IPT4" "$IPT6"; do
case $proto in
tcp|udp)
$IPT -A mwan3_rules -p $proto -s $src_ip -d $dest_ip $ipset -m multiport --sports $src_port -m multiport --dports $dest_port -m mark --mark 0/0xff00 -m comment --comment "$1" -j $policy &> /dev/null
;;
*)
$IPT -A mwan3_rules -p $proto -s $src_ip -d $dest_ip $ipset -m mark --mark 0/0xff00 -m comment --comment "$1" -j $policy &> /dev/null
;;
esac
done
elif [ "$family" == "ipv4" ]; then
case $proto in
tcp|udp)
$IPT4 -A mwan3_rules -p $proto -s $src_ip -d $dest_ip $ipset -m multiport --sports $src_port -m multiport --dports $dest_port -m mark --mark 0/0xff00 -m comment --comment "$1" -j $policy &> /dev/null
;;
*)
$IPT4 -A mwan3_rules -p $proto -s $src_ip -d $dest_ip $ipset -m mark --mark 0/0xff00 -m comment --comment "$1" -j $policy &> /dev/null
;;
esac
elif [ "$family" == "ipv6" ]; then
case $proto in
tcp|udp)
$IPT6 -A mwan3_rules -p $proto -s $src_ip -d $dest_ip $ipset -m multiport --sports $src_port -m multiport --dports $dest_port -m mark --mark 0/0xff00 -m comment --comment "$1" -j $policy &> /dev/null
;;
*)
$IPT6 -A mwan3_rules -p $proto -s $src_ip -d $dest_ip $ipset -m mark --mark 0/0xff00 -m comment --comment "$1" -j $policy &> /dev/null
;;
esac
fi
fi
}
mwan3_set_user_rules()
{
local IPT
for IPT in "$IPT4" "$IPT6"; do
if ! $IPT -S mwan3_rules &> /dev/null; then
$IPT -N mwan3_rules
fi
$IPT -F mwan3_rules
done
config_foreach mwan3_set_user_iptables_rule rule
}
mwan3_report_iface_status()
{
local device result track_ips tracking IP IPT
mwan3_get_iface_id id $1
network_get_device device $1
config_get enabled "$1" enabled 0
config_get family "$1" family ipv4
if [ "$family" == "ipv4" ]; then
IP="$IP4"
IPT="$IPT4"
fi
if [ "$family" == "ipv6" ]; then
IP="$IP6"
IPT="$IPT6"
fi
if [ -z "$id" -o -z "$device" ]; then
result="unknown"
elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')"i -a -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" -a -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" -a -n "$($IPT -S mwan3_iface_out_$1 2> /dev/null)" -a -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
result="online"
elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" -o -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" -o -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" -o -n "$($IPT -S mwan3_iface_out_$1 2> /dev/null)" -o -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
result="error"
else
if [ "$enabled" == "1" ]; then
result="offline"
else
result="disabled"
fi
fi
mwan3_list_track_ips()
{
track_ips="$1 $track_ips"
}
config_list_foreach $1 track_ip mwan3_list_track_ips
if [ -n "$track_ips" ]; then
if [ -n "$(pgrep -f "mwan3track $1")" ]; then
tracking="active"
else
tracking="down"
fi
else
tracking="not enabled"
fi
echo " interface $1 is $result and tracking is $tracking"
}
mwan3_report_policies_v4()
{
local percent policy share total_weight weight iface
for policy in $($IPT4 -S | awk '{print $2}' | grep mwan3_policy_ | sort -u); do
echo "$policy:" | sed 's/mwan3_policy_//'
[ -n "$total_weight" ] || total_weight=$($IPT4 -S $policy | cut -s -d'"' -f2 | head -1 | awk '{print $3}')
if [ ! -z "${total_weight##*[!0-9]*}" ]; then
for iface in $($IPT4 -S $policy | cut -s -d'"' -f2 | awk '{print $1}'); do
weight=$($IPT4 -S $policy | cut -s -d'"' -f2 | awk '$1 == "'$iface'"' | awk '{print $2}')
percent=$(($weight*100/$total_weight))
echo " $iface ($percent%)"
done
else
echo " $($IPT4 -S $policy | sed '/.*--comment \([^ ]*\) .*$/!d;s//\1/;q')"
fi
unset total_weight
echo -e
done
}
mwan3_report_policies_v6()
{
local percent policy share total_weight weight iface
for policy in $($IPT6 -S | awk '{print $2}' | grep mwan3_policy_ | sort -u); do
echo "$policy:" | sed 's/mwan3_policy_//'
[ -n "$total_weight" ] || total_weight=$($IPT6 -S $policy | cut -s -d'"' -f2 | head -1 | awk '{print $3}')
if [ ! -z "${total_weight##*[!0-9]*}" ]; then
for iface in $($IPT6 -S $policy | cut -s -d'"' -f2 | awk '{print $1}'); do
weight=$($IPT6 -S $policy | cut -s -d'"' -f2 | awk '$1 == "'$iface'"' | awk '{print $2}')
percent=$(($weight*100/$total_weight))
echo " $iface ($percent%)"
done
else
echo " $($IPT6 -S $policy | sed '/.*--comment \([^ ]*\) .*$/!d;s//\1/;q')"
fi
unset total_weight
echo -e
done
}
mwan3_report_connected_v4()
{
local address
if [ -n "$($IPT4 -S mwan3_connected 2> /dev/null)" ]; then
for address in $($IPS list mwan3_connected_v4 | egrep '[0-9]{1,3}(\.[0-9]{1,3}){3}'); do
echo " $address"
done
fi
}
mwan3_report_connected_v6()
{
local address
if [ -n "$($IPT6 -S mwan3_connected 2> /dev/null)" ]; then
for address in $($IPS list mwan3_connected_v6 | egrep '([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])'); do
echo " $address"
done
fi
}
mwan3_report_rules_v4()
{
if [ -n "$($IPT4 -S mwan3_rules 2> /dev/null)" ]; then
$IPT4 -L mwan3_rules -n -v 2> /dev/null | tail -n+3 | sed 's/mark.*//' | sed 's/mwan3_policy_/- /' | sed 's/mwan3_rule_/S /'
fi
}
mwan3_report_rules_v6()
{
if [ -n "$($IPT6 -S mwan3_rules 2> /dev/null)" ]; then
$IPT6 -L mwan3_rules -n -v 2> /dev/null | tail -n+3 | sed 's/mark.*//' | sed 's/mwan3_policy_/- /' | sed 's/mwan3_rule_/S /'
fi
}
mwan3_flush_conntrack()
{
local flush_conntrack
config_get flush_conntrack $1 flush_conntrack never
if [ -e "$CONNTRACK_FILE" ]; then
case $flush_conntrack in
ifup)
[ "$3" = "ifup" ] && {
echo f > ${CONNTRACK_FILE}
$LOG info "connection tracking flushed on interface $1 ($2) $3"
}
;;
ifdown)
[ "$3" = "ifdown" ] && {
echo f > ${CONNTRACK_FILE}
$LOG info "connection tracking flushed on interface $1 ($2) $3"
}
;;
always)
echo f > ${CONNTRACK_FILE}
$LOG info "connection tracking flushed on interface $1 ($2) $3"
;;
never)
$LOG info "connection tracking not flushed on interface $1 ($2) $3"
;;
esac
else
$LOG warning "connection tracking not enabled"
fi
}