@ -2,8 +2,6 @@
. /usr/share/libubox/jshn.sh
IP4 = "ip -4"
IP6 = "ip -6"
IPS = "ipset"
IPT4 = "iptables -t mangle -w"
IPT6 = "ip6tables -t mangle -w"
@ -22,18 +20,9 @@ IPv6_REGEX="${IPv6_REGEX}:((:[0-9a-fA-F]{1,4}){1,7}|:)|"
IPv6_REGEX = " ${ IPv6_REGEX } fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}| "
IPv6_REGEX = " ${ IPv6_REGEX } ::(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])| "
IPv6_REGEX = " ${ IPv6_REGEX } ([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]) "
IPv4_REGEX = "((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
MWAN3_STATUS_DIR = "/var/run/mwan3"
MWAN3TRACK_STATUS_DIR = "/var/run/mwan3track"
MWAN3_INTERFACE_MAX = ""
DEFAULT_LOWEST_METRIC = 256
MMX_MASK = ""
MMX_DEFAULT = ""
MMX_BLACKHOLE = ""
MM_BLACKHOLE = ""
MMX_UNREACHABLE = ""
MM_UNREACHABLE = ""
command -v ip6tables > /dev/null
NO_IPV6 = $?
@ -43,14 +32,15 @@ mwan3_push_update()
# helper function to build an update string to pass on to
# IPTR or IPS RESTORE. Modifies the 'update' variable in
# the local scope.
update = " $update
$* " ;
update = " $update " $'\n' " $* " ;
}
mwan3_update_dev_to_table( )
{
local _tid
# shellcheck disable=SC2034
mwan3_dev_tbl_ipv4 = " "
# shellcheck disable=SC2034
mwan3_dev_tbl_ipv6 = " "
update_table( )
@ -81,25 +71,11 @@ mwan3_update_iface_to_table()
config_foreach update_table interface
}
mwan3_get_true_iface( )
{
local family V
_true_iface = $2
config_get family " $iface " family ipv4
if [ " $family " = "ipv4" ] ; then
V = 4
elif [ " $family " = "ipv6" ] ; then
V = 6
fi
ubus call " network.interface. ${ iface } _ ${ V } " status & >/dev/null && _true_iface = " ${ iface } _ ${ V } "
export " $1 = $_true_iface "
}
mwan3_route_line_dev( )
{
# must have mwan3 config already loaded
# arg 1 is route device
local _tid route_line route_device route_family entry curr_table
local _tid route_line route_device route_family entry curr_table
route_line = $2
route_family = $3
route_device = $( echo " $route_line " | sed -ne "s/.*dev \([^ ]*\).*/\1/p" )
@ -130,63 +106,6 @@ mwan3_count_one_bits()
echo $count
}
# maps the 1st parameter so it only uses the bits allowed by the bitmask (2nd parameter)
# which means spreading the bits of the 1st parameter to only use the bits that are set to 1 in the 2nd parameter
# 0 0 0 0 0 1 0 1 (0x05) 1st parameter
# 1 0 1 0 1 0 1 0 (0xAA) 2nd parameter
# 1 0 1 result
mwan3_id2mask( )
{
local bit_msk bit_val result
bit_val = 0
result = 0
for bit_msk in $( seq 0 31) ; do
if [ $(( ( $2 >>bit_msk) & 1 )) = "1" ] ; then
if [ $(( ( $1 >>bit_val) & 1 )) = "1" ] ; then
result = $(( result| ( 1 <<bit_msk)) )
fi
bit_val = $(( bit_val+1))
fi
done
printf "0x%x" $result
}
mwan3_init( )
{
local bitcnt
local mmdefault
[ -d $MWAN3_STATUS_DIR ] || mkdir -p $MWAN3_STATUS_DIR /iface_state
# mwan3's MARKing mask (at least 3 bits should be set)
if [ -e " ${ MWAN3_STATUS_DIR } /mmx_mask " ] ; then
MMX_MASK = $( cat " ${ MWAN3_STATUS_DIR } /mmx_mask " )
MWAN3_INTERFACE_MAX = $( uci_get_state mwan3 globals iface_max)
else
config_load mwan3
config_get MMX_MASK globals mmx_mask '0x3F00'
echo " $MMX_MASK " | tr 'A-F' 'a-f' > " ${ MWAN3_STATUS_DIR } /mmx_mask "
LOG debug " Using firewall mask ${ MMX_MASK } "
bitcnt = $( mwan3_count_one_bits MMX_MASK)
mmdefault = $(( ( 1 <<bitcnt) - 1 ))
MWAN3_INTERFACE_MAX = $(( $mmdefault - 3 ))
uci_toggle_state mwan3 globals iface_max " $MWAN3_INTERFACE_MAX "
LOG debug " Max interface count is ${ MWAN3_INTERFACE_MAX } "
fi
# mark mask constants
bitcnt = $( mwan3_count_one_bits MMX_MASK)
mmdefault = $(( ( 1 <<bitcnt) - 1 ))
MM_BLACKHOLE = $(( $mmdefault - 2 ))
MM_UNREACHABLE = $(( $mmdefault - 1 ))
# MMX_DEFAULT should equal MMX_MASK
MMX_DEFAULT = $( mwan3_id2mask mmdefault MMX_MASK)
MMX_BLACKHOLE = $( mwan3_id2mask MM_BLACKHOLE MMX_MASK)
MMX_UNREACHABLE = $( mwan3_id2mask MM_UNREACHABLE MMX_MASK)
}
mwan3_lock( ) {
lock /var/run/mwan3.lock
#LOG debug "$1 $2 (lock)"
@ -197,22 +116,6 @@ mwan3_unlock() {
lock -u /var/run/mwan3.lock
}
mwan3_get_src_ip( )
{
local family _src_ip true_iface
true_iface = $2
unset " $1 "
config_get family " $true_iface " family ipv4
if [ " $family " = "ipv4" ] ; then
network_get_ipaddr _src_ip " $true_iface "
[ -n " $_src_ip " ] || _src_ip = "0.0.0.0"
elif [ " $family " = "ipv6" ] ; then
network_get_ipaddr6 _src_ip " $true_iface "
[ -n " $_src_ip " ] || _src_ip = "::"
fi
export " $1 = $_src_ip "
}
mwan3_get_iface_id( )
{
local _tmp
@ -220,14 +123,13 @@ mwan3_get_iface_id()
_tmp = " ${ mwan3_iface_tbl ##* ${ 2 } = } "
_tmp = ${ _tmp %% * }
export " $1 = $_tmp "
new_val = $_tmp
}
mwan3_set_custom_ipset_v4( )
{
local custom_network_v4
for custom_network_v4 in $( $IP4 route list table " $1 " | awk '{print $1}' | egrep '[0-9]{1,3}(\.[0-9]{1,3}){3}' ) ; do
for custom_network_v4 in $( $IP4 route list table " $1 " | awk '{print $1}' | grep -E " $IPv4_REGEX " ) ; do
LOG notice " Adding network $custom_network_v4 from table $1 to mwan3_custom_v4 ipset "
mwan3_push_update -! add mwan3_custom_v4 " $custom_network_v4 "
done
@ -237,7 +139,7 @@ mwan3_set_custom_ipset_v6()
{
local custom_network_v6
for custom_network_v6 in $( $IP6 route list table " $1 " | awk '{print $1}' | e grep " $IPv6_REGEX " ) ; do
for custom_network_v6 in $( $IP6 route list table " $1 " | awk '{print $1}' | grep -E " $IPv6_REGEX " ) ; do
LOG notice " Adding network $custom_network_v6 from table $1 to mwan3_custom_v6 ipset "
mwan3_push_update -! add mwan3_custom_v6 " $custom_network_v6 "
done
@ -263,7 +165,6 @@ mwan3_set_custom_ipset()
mwan3_set_connected_ipv4( )
{
local connected_network_v4 candidate_list cidr_list
local ipv4regex = '[0-9]{1,3}(\.[0-9]{1,3}){3}'
$IPS -! create mwan3_connected_v4 hash:net
$IPS create mwan3_connected_v4_temp hash:net
@ -274,7 +175,7 @@ mwan3_set_connected_ipv4()
$IP4 route | awk '{print $1}'
$IP4 route list table 0 | awk '{print $2}'
}
for connected_network_v4 in $( route_lists | egrep " $ipv4regex " ) ; do
for connected_network_v4 in $( route_lists | grep -E " $IPv4_REGEX " ) ; do
if [ -z " ${ connected_network_v4 ##*/* } " ] ; then
cidr_list = " $cidr_list $connected_network_v4 "
else
@ -294,40 +195,44 @@ mwan3_set_connected_ipv4()
$IPS swap mwan3_connected_v4_temp mwan3_connected_v4
$IPS destroy mwan3_connected_v4_temp
$IPS -! add mwan3_connected mwan3_connected_v4
}
mwan3_set_connected_iptables ( )
mwan3_set_connected_ipv6 ( )
{
local connected_network_v6 source_network_v6 error
local connected_network_v6 error
local update = ""
mwan3_set_connected_ipv4
[ $NO_IPV6 -eq 0 ] || return
[ $NO_IPV6 -eq 0 ] && {
mwan3_push_update -! create mwan3_connected_v6 hash:net family inet6
mwan3_push_update flush mwan3_connected_v6
mwan3_push_update -! create mwan3_connected_v6 hash:net family inet6
mwan3_push_update flush mwan3_connected_v6
for connected_network_v6 in $( $IP6 route | awk '{print $1}' | e grep " $IPv6_REGEX " ) ; do
mwan3_push_update -! add mwan3_connected_v6 " $connected_network_v6 "
done
for connected_network_v6 in $( $IP6 route | awk '{print $1}' | grep -E " $IPv6_REGEX " ) ; do
mwan3_push_update -! add mwan3_connected_v6 " $connected_network_v6 "
done
mwan3_push_update -! create mwan3_source_v6 hash:net family inet6
for source_network_v6 in $( $IP6 addr ls | sed -ne 's/ *inet6 \([^ \/]*\).* scope global.*/\1/p' ) ; do
mwan3_push_update -! add mwan3_source_v6 " $source_network_v6 "
done
}
mwan3_push_update -! add mwan3_connected mwan3_connected_v6
error = $( echo " $update " | $IPS restore 2>& 1) || LOG error " set_connected_ipv6: $error "
}
mwan3_set_connected_ipset( )
{
local error
local update = ""
mwan3_push_update -! create mwan3_connected list:set
mwan3_push_update flush mwan3_connected
mwan3_push_update -! add mwan3_connected mwan3_connected_v4
[ $NO_IPV6 -eq 0 ] && mwan3_push_update -! add mwan3_connected mwan3_connected_v6
mwan3_push_update -! create mwan3_dynamic_v4 hash:net
mwan3_push_update -! add mwan3_connected mwan3_dynamic_v4
[ $NO_IPV6 -eq 0 ] && mwan3_push_update -! create mwan3_dynamic_v6 hash:net family inet6
[ $NO_IPV6 -eq 0 ] && mwan3_push_update -! add mwan3_connected mwan3_dynamic_v6
error = $( echo " $update " | $IPS restore 2>& 1) || LOG error " set_connected_iptables: $error "
if [ $NO_IPV6 -eq 0 ] ; then
mwan3_push_update -! create mwan3_dynamic_v6 hash:net family inet6
mwan3_push_update -! add mwan3_connected mwan3_dynamic_v6
fi
error = $( echo " $update " | $IPS restore 2>& 1) || LOG error " set_connected_ipset: $error "
}
mwan3_set_general_rules( )
@ -336,12 +241,12 @@ mwan3_set_general_rules()
for IP in " $IP4 " " $IP6 " ; do
[ " $IP " = " $IP6 " ] && [ $NO_IPV6 -ne 0 ] && continue
RULE_NO = $(( $ MM_BLACKHOLE+ 2000 ))
RULE_NO = $(( MM_BLACKHOLE+2000))
if [ -z " $( $IP rule list | awk -v var = " $RULE_NO : " '$1 == var' ) " ] ; then
$IP rule add pref $RULE_NO fwmark $MMX_BLACKHOLE /$MMX_MASK blackhole
fi
RULE_NO = $(( $ MM_UNREACHABLE+ 2000 ))
RULE_NO = $(( MM_UNREACHABLE+2000))
if [ -z " $( $IP rule list | awk -v var = " $RULE_NO : " '$1 == var' ) " ] ; then
$IP rule add pref $RULE_NO fwmark $MMX_UNREACHABLE /$MMX_MASK unreachable
fi
@ -353,7 +258,7 @@ mwan3_set_general_iptables()
local IPT current update error
for IPT in " $IPT4 " " $IPT6 " ; do
[ " $IPT " = " $IPT6 " ] && [ $NO_IPV6 -ne 0 ] && continue
current = " $( $IPT -S) "
current = " $( $IPT -S) " $'\n'
update = "*mangle"
if [ -n " ${ current ##*-N mwan3_ifaces_in* } " ] ; then
mwan3_push_update -N mwan3_ifaces_in
@ -395,15 +300,10 @@ mwan3_set_general_iptables()
-p ipv6-icmp \
-m icmp6 --icmpv6-type 137 \
-j RETURN
# do not mangle outgoing echo request
mwan3_push_update -A mwan3_hook \
-m set --match-set mwan3_source_v6 src \
-p ipv6-icmp \
-m icmp6 --icmpv6-type 128 \
-j RETURN
fi
mwan3_push_update -A mwan3_hook \
-m mark --mark 0x0/$MMX_MASK \
-j CONNMARK --restore-mark --nfmask " $MMX_MASK " --ctmask " $MMX_MASK "
mwan3_push_update -A mwan3_hook \
-m mark --mark 0x0/$MMX_MASK \
@ -439,7 +339,7 @@ mwan3_set_general_iptables()
mwan3_create_iface_iptables( )
{
local id family connected_name IPT IPTR current update error
local id family IPT IPTR current update error
config_get family " $1 " family ipv4
mwan3_get_iface_id id " $1 "
@ -447,26 +347,22 @@ mwan3_create_iface_iptables()
[ -n " $id " ] || return 0
if [ " $family " = "ipv4" ] ; then
connected_name = mwan3_connected
IPT = " $IPT4 "
IPTR = " $IPT4R "
$IPS -! create $connected_name list:set
elif [ " $family " = "ipv6" ] && [ $NO_IPV6 -eq 0 ] ; then
connected_name = mwan3_connected_v6
IPT = " $IPT6 "
IPTR = " $IPT6R "
$IPS -! create $connected_name hash:net family inet6
else
return
fi
current = " $( $IPT -S) "
current = " $( $IPT -S) " $'\n'
update = "*mangle"
if [ -n " ${ current ##*-N mwan3_ifaces_in* } " ] ; then
mwan3_push_update -N mwan3_ifaces_in
fi
if [ -n " ${ current ##*-N mwan3_iface_in_ $1 * } " ] ; then
if [ -n " ${ current ##*-N mwan3_iface_in_ $1 $'\n' * } " ] ; then
mwan3_push_update -N " mwan3_iface_in_ $1 "
else
mwan3_push_update -F " mwan3_iface_in_ $1 "
@ -474,23 +370,23 @@ mwan3_create_iface_iptables()
mwan3_push_update -A " mwan3_iface_in_ $1 " \
-i " $2 " \
-m set --match-set $connected_name src \
-m mark --mark 0x0/$MMX_MASK \
-m set --match-set mwan3_connected src \
-m mark --mark " 0x0/$MMX_MASK " \
-m comment --comment "default" \
-j MARK --set-xmark $MMX_DEFAULT /$MMX_MASK
-j MARK --set-xmark " $MMX_DEFAULT /$MMX_MASK "
mwan3_push_update -A " mwan3_iface_in_ $1 " \
-i " $2 " \
-m mark --mark 0x0/$MMX_MASK \
-m mark --mark " 0x0/$MMX_MASK " \
-m comment --comment " $1 " \
-j MARK --set-xmark $( mwan3_id2mask id MMX_MASK) /$MMX_MASK
-j MARK --set-xmark " $( mwan3_id2mask id MMX_MASK) /$MMX_MASK "
if [ -n " ${ current ##*-A mwan3_ifaces_in -m mark --mark 0x0/ $MMX_MASK -j mwan3_iface_in_ ${ 1 } * } " ] ; then
if [ -n " ${ current ##*-A mwan3_ifaces_in -m mark --mark 0x0/ $MMX_MASK -j mwan3_iface_in_ ${ 1 } $'\n' * } " ] ; then
mwan3_push_update -A mwan3_ifaces_in \
-m mark --mark 0x0/$MMX_MASK \
-j " mwan3_iface_in_ $1 "
LOG debug " create_iface_iptables: mwan3_iface_in_ $1 not in iptables, adding "
LOG debug " create_iface_iptables: mwan3_iface_in_ $1 not in iptables, adding "
else
LOG debug " create_iface_iptables: mwan3_iface_in_ $1 already in iptables, skip "
LOG debug " create_iface_iptables: mwan3_iface_in_ $1 already in iptables, skip "
fi
mwan3_push_update COMMIT
@ -521,45 +417,17 @@ mwan3_delete_iface_iptables()
}
mwan3_create_iface_route ( )
mwan3_get_routes ( )
{
local id via metric V V_ IP family
local iface device cmd true_iface
iface = $1
device = $2
config_get family " $iface " family ipv4
mwan3_get_iface_id id " $iface "
[ -n " $id " ] || return 0
mwan3_get_true_iface true_iface $iface
if [ " $family " = "ipv4" ] ; then
V_ = ""
IP = " $IP4 "
elif [ " $family " = "ipv6" ] ; then
V_ = 6
IP = " $IP6 "
fi
network_get_gateway${ V_ } via " $true_iface "
{ [ -z " $via " ] || [ " $via " = "0.0.0.0" ] || [ " $via " = "::" ] ; } && unset via
network_get_metric metric " $true_iface "
$IP route flush table " $id "
cmd = " $IP route add table $id default \
${ via : +via } $via \
${ metric : +metric } $metric \
dev $2 "
$cmd || LOG warn " ip cmd failed $cmd "
local source_routing
config_get_bool source_routing globals source_routing 0
[ $source_routing -eq 0 ] && unset source_routing
$IP route list table main | sed -ne " /^linkdown/T; s/expires \([0-9]\+\)sec//;s/error [0-9]\+//; ${ source_routing : +s/default \( .* \) from [^ ]*/default \1 /; } p " | uniq
}
mwan3_add_non_default _iface_route( )
mwan3_create_iface_route( )
{
local tid route_line family IP id
local tid route_line family IP id tbl
config_get family " $1 " family ipv4
mwan3_get_iface_id id " $1 "
@ -571,10 +439,15 @@ mwan3_add_non_default_iface_route()
IP = " $IP6 "
fi
tbl = $( $IP route list table $id 2>/dev/null) $'\n'
mwan3_update_dev_to_table
$IP route list table main | grep -v "^default\|linkdown\|^::/0\|^fe80::/64\|^unreachable" | while read route_line; do
mwan3_get_routes | while read -r route_line; do
mwan3_route_line_dev "tid" " $route_line " " $family "
{ [ -z " ${ route_line ##default* } " ] || [ -z " ${ route_line ##fe80 : : /64* } " ] ; } && [ " $tid " != " $id " ] && continue
if [ -z " $tid " ] || [ " $tid " = " $id " ] ; then
# possible that routes are already in the table
# if 'connected' was called after 'ifup'
[ -n " $tbl " ] && [ -z " ${ tbl ##* $route_line $'\n' * } " ] && continue
$IP route add table $id $route_line ||
LOG warn " failed to add $route_line to table $id "
fi
@ -582,63 +455,21 @@ mwan3_add_non_default_iface_route()
done
}
mwan3_add_all_nondefault_routes( )
{
local tid IP route_line ipv family active_tbls tid
add_active_tbls( )
{
let tid++
config_get family " $1 " family ipv4
[ " $family " != " $ipv " ] && return
$IP route list table $tid 2>/dev/null | grep -q "^default\|^::/0" && {
active_tbls = " $active_tbls ${ tid } "
}
}
add_route( )
{
let tid++
[ -n " ${ active_tbls ##* $tid * } " ] && return
$IP route add table $tid $route_line ||
LOG warn " failed to add $route_line to table $tid "
}
mwan3_update_dev_to_table
for ipv in ipv4 ipv6; do
[ " $ipv " = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue
if [ " $ipv " = "ipv4" ] ; then
IP = " $IP4 "
elif [ " $ipv " = "ipv6" ] ; then
IP = " $IP6 "
fi
tid = 0
active_tbls = " "
config_foreach add_active_tbls interface
$IP route list table main | grep -v "^default\|linkdown\|^::/0\|^fe80::/64\|^unreachable" | while read route_line; do
mwan3_route_line_dev "tid" " $route_line " " $ipv "
if [ -n " $tid " ] ; then
$IP route add table $tid $route_line
else
config_foreach add_route interface
fi
done
done
}
mwan3_delete_iface_route( )
{
local id
local id family
config_get family " $1 " family ipv4
mwan3_get_iface_id id " $1 "
[ -n " $id " ] || return 0
if [ -z " $id " ] ; then
LOG warn " delete_iface_route: could not find table id for interface $1 "
return 0
fi
if [ " $family " = "ipv4" ] ; then
$IP4 route flush table " $id "
fi
if [ " $family " = "ipv6" ] && [ $NO_IPV6 -eq 0 ] ; then
elif [ " $family " = "ipv6" ] && [ $NO_IPV6 -eq 0 ] ; then
$IP6 route flush table " $id "
fi
}
@ -660,21 +491,16 @@ mwan3_create_iface_rules()
return
fi
while [ -n " $( $IP rule list | awk '$1 == "' $(( $id + 1000 )) :'"' ) " ] ; do
$IP rule del pref $(( $id + 1000 ))
done
while [ -n " $( $IP rule list | awk '$1 == "' $(( $id + 2000 )) :'"' ) " ] ; do
$IP rule del pref $(( $id + 2000 ))
done
mwan3_delete_iface_rules " $1 "
$IP rule add pref $(( $id + 1000 )) iif " $2 " lookup " $id "
$IP rule add pref $(( $id + 2000 )) fwmark $( mwan3_id2mask id MMX_MASK) /$MMX_MASK lookup " $id "
$IP rule add pref $(( id+1000)) iif " $2 " lookup " $id "
$IP rule add pref $(( id+2000)) fwmark " $( mwan3_id2mask id MMX_MASK) / $MMX_MASK " lookup " $id "
$IP rule add pref $(( id+3000)) fwmark " $( mwan3_id2mask id MMX_MASK) / $MMX_MASK " unreachable
}
mwan3_delete_iface_rules( )
{
local id family
local id family IP rule_id
config_get family " $1 " family ipv4
mwan3_get_iface_id id " $1 "
@ -689,12 +515,8 @@ mwan3_delete_iface_rules()
return
fi
while [ -n " $( $IP rule list | awk '$1 == "' $(( $id + 1000 )) :'"' ) " ] ; do
$IP rule del pref $(( $id + 1000 ))
done
while [ -n " $( $IP rule list | awk '$1 == "' $(( $id + 2000 )) :'"' ) " ] ; do
$IP rule del pref $(( $id + 2000 ))
for rule_id in $( ip rule list | awk '$1 % 1000 == ' $id ' && $1 > 1000 && $1 < 4000 {print substr($1,0,4)}' ) ; do
$IP rule del pref $rule_id
done
}
@ -713,39 +535,6 @@ mwan3_delete_iface_ipset_entries()
done
}
mwan3_rtmon( )
{
local protocol
for protocol in "ipv4" "ipv6" ; do
pid = " $( pgrep -f " mwan3rtmon $protocol " ) "
[ " $protocol " = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue
if [ " ${ pid } " = "" ] ; then
[ -x /usr/sbin/mwan3rtmon ] && /usr/sbin/mwan3rtmon $protocol &
fi
done
}
mwan3_track( )
{
local track_ips pids
mwan3_list_track_ips( )
{
track_ips = " $track_ips $1 "
}
config_list_foreach " $1 " track_ip mwan3_list_track_ips
# don't match device in case it changed from last launch
if pids = $( pgrep -f " mwan3track $1 " ) ; then
kill -TERM $pids > /dev/null 2>& 1
sleep 1
kill -KILL $( pgrep -f " mwan3track $1 " ) > /dev/null 2>& 1
fi
if [ -n " $track_ips " ] ; then
[ -x /usr/sbin/mwan3track ] && MWAN3_STARTUP = 0 /usr/sbin/mwan3track " $1 " " $2 " " $3 " " $4 " $track_ips &
fi
}
mwan3_set_policy( )
{
@ -776,7 +565,7 @@ mwan3_set_policy()
IPT = " $IPT6 "
IPTR = " $IPT6R "
fi
current = " $( $IPT -S) "
current = " $( $IPT -S) " $'\n'
update = "*mangle"
if [ " $family " = "ipv4" ] && [ $is_offline -eq 0 ] ; then
@ -785,7 +574,7 @@ mwan3_set_policy()
total_weight_v4 = $weight
lowest_metric_v4 = $metric
elif [ " $metric " -eq " $lowest_metric_v4 " ] ; then
total_weight_v4 = $(( $ total_weight_v4+ $ weight))
total_weight_v4 = $(( total_weight_v4+weight))
total_weight = $total_weight_v4
else
return
@ -796,7 +585,7 @@ mwan3_set_policy()
total_weight_v6 = $weight
lowest_metric_v6 = $metric
elif [ " $metric " -eq " $lowest_metric_v6 " ] ; then
total_weight_v6 = $(( $ total_weight_v6+ $ weight))
total_weight_v6 = $(( total_weight_v6+weight))
total_weight = $total_weight_v6
else
return
@ -807,9 +596,9 @@ mwan3_set_policy()
mwan3_push_update -A " mwan3_policy_ $policy " \
-m mark --mark 0x0/$MMX_MASK \
-m comment --comment \" $iface $weight $weight \" \
-j MARK --set-xmark $( mwan3_id2mask id MMX_MASK) /$MMX_MASK
-j MARK --set-xmark " $( mwan3_id2mask id MMX_MASK) /$MMX_MASK "
elif [ $is_offline -eq 0 ] ; then
probability = $(( $ weight* 1000 / $ total_weight))
probability = $(( weight*1000/ total_weight))
if [ " $probability " -lt 10 ] ; then
probability = " 0.00 $probability "
elif [ $probability -lt 100 ] ; then
@ -826,7 +615,7 @@ mwan3_set_policy()
--mode random \
--probability " $probability " \
-m comment --comment \" $iface $weight $total_weight \" \
-j MARK --set-xmark $( mwan3_id2mask id MMX_MASK) /$MMX_MASK
-j MARK --set-xmark " $( mwan3_id2mask id MMX_MASK) /$MMX_MASK "
elif [ -n " $device " ] ; then
echo " $current " | grep -q " ^-A mwan3_policy_ $policy .*--comment .* [0-9]* [0-9]* " ||
mwan3_push_update -I " mwan3_policy_ $policy " \
@ -855,10 +644,10 @@ mwan3_create_policies_iptables()
for IPT in " $IPT4 " " $IPT6 " ; do
[ " $IPT " = " $IPT6 " ] && [ $NO_IPV6 -ne 0 ] && continue
current = " $( $IPT -S) "
current = " $( $IPT -S) " $'\n'
update = "*mangle"
if [ -n " ${ current ##*-N mwan3_policy_ $1 * } " ] ; then
mwan3_push_update -N " mwan3_policy_ $1 "
if [ -n " ${ current ##*-N mwan3_policy_ $1 $'\n' * } " ] ; then
mwan3_push_update -N " mwan3_policy_ $1 "
fi
mwan3_push_update -F " mwan3_policy_ $1 "
@ -915,14 +704,14 @@ mwan3_set_sticky_iptables()
mwan3_get_iface_id id " $1 "
[ -n " $id " ] || return 0
if [ -z " ${ current ##*-N mwan3_iface_in_ $1 * } " ] ; then
if [ -z " ${ current ##*-N mwan3_iface_in_ $1 $'\n' * } " ] ; then
mwan3_push_update -I " mwan3_rule_ $rule " \
-m mark --mark $( mwan3_id2mask id MMX_MASK) /$MMX_MASK \
-m mark --mark " $( mwan3_id2mask id MMX_MASK) /$MMX_MASK " \
-m set ! --match-set " mwan3_sticky_ $rule " src,src \
-j MARK --set-xmark 0x0/$MMX_MASK
-j MARK --set-xmark " 0x0/$MMX_MASK "
mwan3_push_update -I " mwan3_rule_ $rule " \
-m mark --mark 0/$MMX_MASK \
-j MARK --set-xmark $( mwan3_id2mask id MMX_MASK) /$MMX_MASK
-m mark --mark " 0/$MMX_MASK " \
-j MARK --set-xmark " $( mwan3_id2mask id MMX_MASK) /$MMX_MASK "
fi
fi
done
@ -932,7 +721,7 @@ mwan3_set_user_iptables_rule()
{
local ipset family proto policy src_ip src_port src_iface src_dev
local sticky dest_ip dest_port use_policy timeout policy
local global_logging rule_logging loglevel rule_policy rule ipv
local global_logging rule_logging loglevel rule_policy rule ipv
rule = " $1 "
ipv = " $2 "
@ -952,6 +741,18 @@ mwan3_set_user_iptables_rule()
config_get global_logging globals logging 0
config_get loglevel globals loglevel notice
[ " $ipv " = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && return
[ " $family " = "ipv4" ] && [ " $ipv " = "ipv6" ] && return
[ " $family " = "ipv6" ] && [ " $ipv " = "ipv4" ] && return
for ipaddr in " $src_ip " " $dest_ip " ; do
if [ -n " $ipaddr " ] && { { [ " $ipv " = "ipv4" ] && echo " $ipaddr " | grep -qE " $IPv6_REGEX " ; } ||
{ [ " $ipv " = "ipv6" ] && echo " $ipaddr " | grep -qE $IPv4_REGEX ; } } ; then
LOG warn " invalid $ipv address $ipaddr specified for rule $rule "
return
fi
done
if [ -n " $src_iface " ] ; then
network_get_device src_dev " $src_iface "
if [ -z " $src_dev " ] ; then
@ -963,9 +764,9 @@ mwan3_set_user_iptables_rule()
[ -z " $dest_ip " ] && unset dest_ip
[ -z " $src_ip " ] && unset src_ip
[ -z " $ipset " ] && unset ipset
[ -z " $src_port " ] && unset src_port
[ -z " $dest_port " ] && unset dest_port
if [ " $proto " != 'tcp' ] && [ " $proto " != 'udp' ] ; then
[ -z " $src_port " ] && unset src_port
[ -z " $dest_port " ] && unset dest_port
if [ " $proto " != 'tcp' ] && [ " $proto " != 'udp' ] ; then
[ -n " $src_port " ] && {
LOG warn " src_port set to ' $src_port ' but proto set to ' $proto ' not tcp or udp. src_port will be ignored "
}
@ -1013,16 +814,12 @@ mwan3_set_user_iptables_rule()
fi
fi
[ " $ipv " = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && return
[ " $family " = "ipv4" ] && [ " $ipv " = "ipv6" ] && return
[ " $family " = "ipv6" ] && [ " $ipv " = "ipv4" ] && return
if [ $rule_policy -eq 1 ] && [ -n " ${ current ##*-N $policy * } " ] ; then
if [ $rule_policy -eq 1 ] && [ -n " ${ current ##*-N $policy $'\n' * } " ] ; then
mwan3_push_update -N " $policy "
fi
if [ $rule_policy -eq 1 ] && [ " $sticky " -eq 1 ] ; then
if [ -n " ${ current ##*-N mwan3_rule_ $1 * } " ] ; then
if [ -n " ${ current ##*-N mwan3_rule_ $1 $'\n' * } " ] ; then
mwan3_push_update -N " mwan3_rule_ $1 "
fi
@ -1117,7 +914,7 @@ mwan3_set_user_rules()
fi
[ " $ipv " = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue
update = "*mangle"
current = " $( $IPT -S) "
current = " $( $IPT -S) " $'\n'
if [ -n " ${ current ##*-N mwan3_rules* } " ] ; then
@ -1136,6 +933,83 @@ mwan3_set_user_rules()
}
mwan3_interface_hotplug_shutdown( )
{
local interface status device ifdown
interface = " $1 "
ifdown = " $2 "
[ -f $MWAN3TRACK_STATUS_DIR /$interface /STATUS ] && {
status = $( cat $MWAN3TRACK_STATUS_DIR /$interface /STATUS)
}
[ " $status " != "online" ] && [ " $ifdown " != 1 ] && return
if [ " $ifdown " = 1 ] ; then
env -i ACTION = ifdown \
INTERFACE = $interface \
DEVICE = $device \
sh /etc/hotplug.d/iface/15-mwan3
else
[ " $status " = "online" ] && {
env -i MWAN3_SHUTDOWN = "1" \
ACTION = "disconnected" \
INTERFACE = " $interface " \
DEVICE = " $device " /sbin/hotplug-call iface
}
fi
}
mwan3_interface_shutdown( )
{
mwan3_interface_hotplug_shutdown $1
mwan3_track_clean $1
}
mwan3_ifup( )
{
local up l3_device status interface true_iface mwan3_startup
interface = $1
mwan3_startup = $2
if [ " ${ mwan3_startup } " != 1 ] ; then
# It is not necessary to obtain a lock here, because it is obtained in the hotplug
# script, but we still want to do the check to print a useful error message
/etc/init.d/mwan3 running || {
echo 'The service mwan3 is global disabled.'
echo 'Please execute "/etc/init.d/mwan3 start" first.'
exit 1
}
config_load mwan3
fi
mwan3_get_true_iface true_iface $interface
status = $( ubus -S call network.interface.$true_iface status)
[ -n " $status " ] && {
json_load " $status "
json_get_vars up l3_device
}
hotplug_startup( )
{
env -i MWAN3_STARTUP = $mwan3_startup ACTION = ifup \
INTERFACE = $interface DEVICE = $l3_device \
sh /etc/hotplug.d/iface/15-mwan3
}
if [ " $up " != "1" ] || [ -z " $l3_device " ] ; then
return
fi
if [ " ${ mwan3_startup } " = 1 ] ; then
hotplug_startup &
hotplug_pids = " $hotplug_pids $! "
else
hotplug_startup
fi
}
mwan3_set_iface_hotplug_state( ) {
local iface = $1
local state = $2
@ -1151,7 +1025,7 @@ mwan3_get_iface_hotplug_state() {
mwan3_report_iface_status( )
{
local device result track_ips track ing IP IPT
local device result tracking IP IPT
mwan3_get_iface_id id " $1 "
network_get_device device " $1 "
@ -1170,8 +1044,9 @@ mwan3_report_iface_status()
if [ -z " $id " ] || [ -z " $device " ] ; then
result = "offline"
elif [ -n " $( $IP rule | awk '$1 == "' $(( $id + 1000 )) :'"' ) " ] && \
[ -n " $( $IP rule | awk '$1 == "' $(( $id + 2000 )) :'"' ) " ] && \
elif [ -n " $( $IP rule | awk '$1 == "' $(( id+1000)) :'"' ) " ] && \
[ -n " $( $IP rule | awk '$1 == "' $(( id+2000)) :'"' ) " ] && \
[ -n " $( $IP rule | awk '$1 == "' $(( id+3000)) :'"' ) " ] && \
[ -n " $( $IPT -S mwan3_iface_in_$1 2> /dev/null) " ] && \
[ -n " $( $IP route list table $id default dev $device 2> /dev/null) " ] ; then
json_init
@ -1183,11 +1058,12 @@ mwan3_report_iface_status()
json_get_vars online uptime
json_select ..
json_select ..
online = " $( printf '%02dh:%02dm:%02ds\n' $(( $ online/ 3600 )) $(( $ online% 3600 / 60 )) $(( $ online% 60 )) ) "
uptime = " $( printf '%02dh:%02dm:%02ds\n' $(( $ uptime/ 3600 )) $(( $ uptime% 3600 / 60 )) $(( $ uptime% 60 )) ) "
online = " $( printf '%02dh:%02dm:%02ds\n' $(( online/ 3600)) $(( online%3600/ 60)) $(( online%60)) ) "
uptime = " $( printf '%02dh:%02dm:%02ds\n' $(( uptime/ 3600)) $(( uptime%3600/ 60)) $(( uptime%60)) ) "
result = " $( mwan3_get_iface_hotplug_state $1 ) $online , uptime $uptime "
elif [ -n " $( $IP rule | awk '$1 == "' $(( $id + 1000 )) :'"' ) " ] || \
[ -n " $( $IP rule | awk '$1 == "' $(( $id + 2000 )) :'"' ) " ] || \
elif [ -n " $( $IP rule | awk '$1 == "' $(( id+1000)) :'"' ) " ] || \
[ -n " $( $IP rule | awk '$1 == "' $(( id+2000)) :'"' ) " ] || \
[ -n " $( $IP rule | awk '$1 == "' $(( id+3000)) :'"' ) " ] || \
[ -n " $( $IPT -S mwan3_iface_in_$1 2> /dev/null) " ] || \
[ -n " $( $IP route list table $id default dev $device 2> /dev/null) " ] ; then
result = "error"
@ -1197,22 +1073,7 @@ mwan3_report_iface_status()
result = "disabled"
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 $device " ) " ] ; then
tracking = "active"
else
tracking = "down"
fi
else
tracking = "not enabled"
fi
tracking = " $( mwan3_get_mwan3track_status $1 ) "
echo " interface $1 is $result and tracking is $tracking "
}
@ -1225,10 +1086,10 @@ mwan3_report_policies()
total_weight = $( $ipt -S " $policy " | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | head -1 | awk '{print $3}' )
if [ ! -z " ${ total_weight ##*[!0-9]* } " ] ; then
if [ -n " ${ total_weight ##*[!0-9]* } " ] ; then
for iface in $( $ipt -S " $policy " | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | awk '{print $1}' ) ; do
weight = $( $ipt -S " $policy " | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | awk '$1 == "' $iface '"' | awk '{print $2}' )
percent = $(( $ weight* 100 / $ total_weight))
percent = $(( weight*100/ total_weight))
echo " $iface ( $percent %) "
done
else
@ -1306,6 +1167,6 @@ mwan3_flush_conntrack()
mwan3_track_clean( )
{
rm -rf " $ MWAN3_STATUS_DIR/ ${ 1 } " & > /dev/null
rm -rf " ${ MWAN3_STATUS_DIR : ? } / ${ 1 } " & > /dev/null
rmdir --ignore-fail-on-non-empty " $MWAN3_STATUS_DIR "
}