#!/bin/sh
+
. /usr/share/libubox/jshn.sh
IP4="ip -4"
IPS="ipset"
IPT4="iptables -t mangle -w"
IPT6="ip6tables -t mangle -w"
-LOG="logger -t mwan3[$$] -p"
+IPT4R="iptables-restore -T mangle -w -n"
+IPT6R="ip6tables-restore -T mangle -w -n"
CONNTRACK_FILE="/proc/net/nf_conntrack"
IPv6_REGEX="([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|"
IPv6_REGEX="${IPv6_REGEX}([0-9a-fA-F]{1,4}:){1,7}:|"
mwan3_update_iface_to_table()
{
- local _tid section family cfgtype curr_table _mwan3_iface_tbl
+ local _tid
mwan3_iface_tbl=" "
update_table()
{
else
config_load mwan3
config_get MMX_MASK globals mmx_mask '0x3F00'
- echo "$MMX_MASK" > "${MWAN3_STATUS_DIR}/mmx_mask"
- $LOG notice "Using firewall mask ${MMX_MASK}"
+ 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 notice "Max interface count is ${MWAN3_INTERFACE_MAX}"
+ LOG debug "Max interface count is ${MWAN3_INTERFACE_MAX}"
fi
# mark mask constants
mwan3_lock() {
lock /var/run/mwan3.lock
-# $LOG debug "$1 $2 (lock)"
+ #LOG debug "$1 $2 (lock)"
}
mwan3_unlock() {
-# $LOG debug "$1 $2 (unlock)"
+ #LOG debug "$1 $2 (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
_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
- $LOG notice "Adding network $custom_network_v4 from table $1 to mwan3_custom_v4 ipset"
- $IPS -! add mwan3_custom_v4_temp "$custom_network_v4"
+ 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
}
local custom_network_v6
for custom_network_v6 in $($IP6 route list table "$1" | awk '{print $1}' | egrep "$IPv6_REGEX"); do
- $LOG notice "Adding network $custom_network_v6 from table $1 to mwan3_custom_v6 ipset"
- $IPS -! add mwan3_custom_v6_temp "$custom_network_v6"
+ 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
}
mwan3_set_custom_ipset()
{
- $IPS -! create mwan3_custom_v4 hash:net
- $IPS create mwan3_custom_v4_temp hash:net
- config_list_foreach "globals" "rt_table_lookup" mwan3_set_custom_ipset_v4
- $IPS swap mwan3_custom_v4_temp mwan3_custom_v4
- $IPS destroy mwan3_custom_v4_temp
+ local update=""
+ mwan3_push_update -! create mwan3_custom_v4 hash:net
+ config_list_foreach "globals" "rt_table_lookup" mwan3_set_custom_ipset_v4
- $IPS -! create mwan3_custom_v6 hash:net family inet6
- $IPS create mwan3_custom_v6_temp hash:net family inet6
+ mwan3_push_update -! create mwan3_custom_v6 hash:net family inet6
config_list_foreach "globals" "rt_table_lookup" mwan3_set_custom_ipset_v6
- $IPS swap mwan3_custom_v6_temp mwan3_custom_v6
- $IPS destroy mwan3_custom_v6_temp
- $IPS -! create mwan3_connected list:set
- $IPS -! add mwan3_connected mwan3_custom_v4
- $IPS -! add mwan3_connected mwan3_custom_v6
+ mwan3_push_update -! create mwan3_connected list:set
+ mwan3_push_update -! add mwan3_connected mwan3_custom_v4
+ mwan3_push_update -! add mwan3_connected mwan3_custom_v6
+ error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_custom_ipset: $error"
}
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
+
candidate_list=""
cidr_list=""
- for connected_network_v4 in $($IP4 route | awk '{print $1}' | egrep '[0-9]{1,3}(\.[0-9]{1,3}){3}'); do
- [ -z "${connected_network_v4##*/*}" ] &&
- cidr_list="$cidr_list $connected_network_v4" ||
- candidate_list="$candidate_list $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
- [ -z "${connected_network_v4##*/*}" ] &&
- cidr_list="$cidr_list $connected_network_v4" ||
- candidate_list="$candidate_list $connected_network_v4"
+ route_lists()
+ {
+ $IP4 route | awk '{print $1}'
+ $IP4 route list table 0 | awk '{print $2}'
+ }
+ for connected_network_v4 in $(route_lists | egrep "$ipv4regex"); do
+ if [ -z "${connected_network_v4##*/*}" ]; then
+ cidr_list="$cidr_list $connected_network_v4"
+ else
+ candidate_list="$candidate_list $connected_network_v4"
+ fi
done
for connected_network_v4 in $cidr_list; do
mwan3_set_connected_iptables()
{
- local connected_network_v6 source_network_v6
-
- $IPS -! create mwan3_connected_v4 hash:net
- $IPS create mwan3_connected_v4_temp hash:net
-
+ local connected_network_v6 source_network_v6 error
+ local update=""
mwan3_set_connected_ipv4
[ $NO_IPV6 -eq 0 ] && {
- $IPS -! create mwan3_connected_v6 hash:net family inet6
- $IPS create mwan3_connected_v6_temp hash:net family inet6
+ 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}' | egrep "$IPv6_REGEX"); do
- $IPS -! add mwan3_connected_v6_temp "$connected_network_v6"
+ mwan3_push_update -! add mwan3_connected_v6 "$connected_network_v6"
done
- $IPS swap mwan3_connected_v6_temp mwan3_connected_v6
- $IPS destroy mwan3_connected_v6_temp
- $IPS -! create mwan3_source_v6 hash:net family inet6
- $IPS create mwan3_source_v6_temp hash:net family inet6
+ 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
- $IPS -! add mwan3_source_v6_temp "$source_network_v6"
+ mwan3_push_update -! add mwan3_source_v6 "$source_network_v6"
done
- $IPS swap mwan3_source_v6_temp mwan3_source_v6
- $IPS destroy mwan3_source_v6_temp
}
- $IPS -! create mwan3_connected list:set
- $IPS -! add mwan3_connected mwan3_connected_v4
- [ $NO_IPV6 -eq 0 ] && $IPS -! add mwan3_connected mwan3_connected_v6
+ 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
- $IPS -! create mwan3_dynamic_v4 hash:net
- $IPS -! add mwan3_connected mwan3_dynamic_v4
+ mwan3_push_update -! create mwan3_dynamic_v4 hash:net
+ mwan3_push_update -! add mwan3_connected mwan3_dynamic_v4
- [ $NO_IPV6 -eq 0 ] && $IPS -! create mwan3_dynamic_v6 hash:net family inet6
- [ $NO_IPV6 -eq 0 ] && $IPS -! add mwan3_connected mwan3_dynamic_v6
+ [ $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"
}
mwan3_set_general_rules()
mwan3_set_general_iptables()
{
- local IPT
-
+ local IPT current update error
for IPT in "$IPT4" "$IPT6"; do
[ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue
- if ! $IPT -S mwan3_ifaces_in &> /dev/null; then
- $IPT -N mwan3_ifaces_in
+ current="$($IPT -S)"
+ update="*mangle"
+ if [ -n "${current##*-N mwan3_ifaces_in*}" ]; then
+ mwan3_push_update -N mwan3_ifaces_in
fi
- if ! $IPT -S mwan3_connected &> /dev/null; then
- $IPT -N mwan3_connected
+ if [ -n "${current##*-N mwan3_connected*}" ]; then
+ mwan3_push_update -N mwan3_connected
$IPS -! create mwan3_connected list:set
- $IPT -A mwan3_connected \
- -m set --match-set mwan3_connected dst \
- -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
+ mwan3_push_update -A mwan3_connected \
+ -m set --match-set mwan3_connected dst \
+ -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
fi
- if ! $IPT -S mwan3_rules &> /dev/null; then
- $IPT -N mwan3_rules
+ if [ -n "${current##*-N mwan3_rules*}" ]; then
+ mwan3_push_update -N mwan3_rules
fi
- if ! $IPT -S mwan3_hook &> /dev/null; then
- $IPT -N mwan3_hook
+ if [ -n "${current##*-N mwan3_hook*}" ]; then
+ mwan3_push_update -N mwan3_hook
# do not mangle ipv6 ra service
if [ "$IPT" = "$IPT6" ]; then
- $IPT6 -A mwan3_hook \
- -p ipv6-icmp \
- -m icmp6 --icmpv6-type 133 \
- -j RETURN
- $IPT6 -A mwan3_hook \
- -p ipv6-icmp \
- -m icmp6 --icmpv6-type 134 \
- -j RETURN
- $IPT6 -A mwan3_hook \
- -p ipv6-icmp \
- -m icmp6 --icmpv6-type 135 \
- -j RETURN
- $IPT6 -A mwan3_hook \
- -p ipv6-icmp \
- -m icmp6 --icmpv6-type 136 \
- -j RETURN
- $IPT6 -A mwan3_hook \
- -p ipv6-icmp \
- -m icmp6 --icmpv6-type 137 \
- -j RETURN
+ mwan3_push_update -A mwan3_hook \
+ -p ipv6-icmp \
+ -m icmp6 --icmpv6-type 133 \
+ -j RETURN
+ mwan3_push_update -A mwan3_hook \
+ -p ipv6-icmp \
+ -m icmp6 --icmpv6-type 134 \
+ -j RETURN
+ mwan3_push_update -A mwan3_hook \
+ -p ipv6-icmp \
+ -m icmp6 --icmpv6-type 135 \
+ -j RETURN
+ mwan3_push_update -A mwan3_hook \
+ -p ipv6-icmp \
+ -m icmp6 --icmpv6-type 136 \
+ -j RETURN
+ mwan3_push_update -A mwan3_hook \
+ -p ipv6-icmp \
+ -m icmp6 --icmpv6-type 137 \
+ -j RETURN
# do not mangle outgoing echo request
- $IPT6 -A mwan3_hook \
- -m set --match-set mwan3_source_v6 src \
- -p ipv6-icmp \
- -m icmp6 --icmpv6-type 128 \
- -j RETURN
+ 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
- $IPT -A mwan3_hook \
- -j CONNMARK --restore-mark --nfmask "$MMX_MASK" --ctmask "$MMX_MASK"
- $IPT -A mwan3_hook \
- -m mark --mark 0x0/$MMX_MASK \
- -j mwan3_ifaces_in
- $IPT -A mwan3_hook \
- -m mark --mark 0x0/$MMX_MASK \
- -j mwan3_connected
- $IPT -A mwan3_hook \
- -m mark --mark 0x0/$MMX_MASK \
- -j mwan3_rules
- $IPT -A mwan3_hook \
- -j CONNMARK --save-mark --nfmask "$MMX_MASK" --ctmask "$MMX_MASK"
- $IPT -A mwan3_hook \
- -m mark ! --mark $MMX_DEFAULT/$MMX_MASK \
- -j mwan3_connected
+ mwan3_push_update -A mwan3_hook \
+ -j CONNMARK --restore-mark --nfmask "$MMX_MASK" --ctmask "$MMX_MASK"
+ mwan3_push_update -A mwan3_hook \
+ -m mark --mark 0x0/$MMX_MASK \
+ -j mwan3_ifaces_in
+ mwan3_push_update -A mwan3_hook \
+ -m mark --mark 0x0/$MMX_MASK \
+ -j mwan3_connected
+ mwan3_push_update -A mwan3_hook \
+ -m mark --mark 0x0/$MMX_MASK \
+ -j mwan3_rules
+ mwan3_push_update -A mwan3_hook \
+ -j CONNMARK --save-mark --nfmask "$MMX_MASK" --ctmask "$MMX_MASK"
+ mwan3_push_update -A mwan3_hook \
+ -m mark ! --mark $MMX_DEFAULT/$MMX_MASK \
+ -j mwan3_connected
fi
- if ! $IPT -S PREROUTING | grep mwan3_hook &> /dev/null; then
- $IPT -A PREROUTING -j mwan3_hook
+ if [ -n "${current##*-A PREROUTING -j mwan3_hook*}" ]; then
+ mwan3_push_update -A PREROUTING -j mwan3_hook
fi
-
- if ! $IPT -S OUTPUT | grep mwan3_hook &> /dev/null; then
- $IPT -A OUTPUT -j mwan3_hook
+ if [ -n "${current##*-A OUTPUT -j mwan3_hook*}" ]; then
+ mwan3_push_update -A OUTPUT -j mwan3_hook
+ fi
+ mwan3_push_update COMMIT
+ mwan3_push_update ""
+ if [ "$IPT" = "$IPT4" ]; then
+ error=$(echo "$update" | $IPT4R 2>&1) || LOG error "set_general_iptables: $error"
+ else
+ error=$(echo "$update" | $IPT6R 2>&1) || LOG error "set_general_iptables: $error"
fi
done
}
mwan3_create_iface_iptables()
{
- local id family connected_name IPT
+ local id family connected_name IPT IPTR current update error
config_get family "$1" family ipv4
mwan3_get_iface_id id "$1"
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
-
- if ! $IPT -S mwan3_ifaces_in &> /dev/null; then
- $IPT -N mwan3_ifaces_in
+ current="$($IPT -S)"
+ update="*mangle"
+ if [ -n "${current##*-N mwan3_ifaces_in*}" ]; then
+ mwan3_push_update -N mwan3_ifaces_in
fi
- if ! $IPT -S "mwan3_iface_in_$1" &> /dev/null; then
- $IPT -N "mwan3_iface_in_$1"
+ if [ -n "${current##*-N mwan3_iface_in_$1*}" ]; then
+ mwan3_push_update -N "mwan3_iface_in_$1"
+ else
+ mwan3_push_update -F "mwan3_iface_in_$1"
fi
- $IPT -F "mwan3_iface_in_$1"
- $IPT -A "mwan3_iface_in_$1" \
- -i "$2" \
- -m set --match-set $connected_name src \
- -m mark --mark 0x0/$MMX_MASK \
- -m comment --comment "default" \
- -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
- $IPT -A "mwan3_iface_in_$1" \
- -i "$2" \
- -m mark --mark 0x0/$MMX_MASK \
- -m comment --comment "$1" \
- -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
+ mwan3_push_update -A "mwan3_iface_in_$1" \
+ -i "$2" \
+ -m set --match-set $connected_name src \
+ -m mark --mark 0x0/$MMX_MASK \
+ -m comment --comment "default" \
+ -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 comment --comment "$1" \
+ -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
+ 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"
+ else
+ LOG debug "create_iface_iptables: mwan3_iface_in_$1 already in iptables, skip"
+ fi
- $IPT -D mwan3_ifaces_in \
- -m mark --mark 0x0/$MMX_MASK \
- -j "mwan3_iface_in_$1" &> /dev/null
- $IPT -A mwan3_ifaces_in \
- -m mark --mark 0x0/$MMX_MASK \
- -j "mwan3_iface_in_$1"
+ mwan3_push_update COMMIT
+ mwan3_push_update ""
+ error=$(echo "$update" | $IPTR 2>&1) || LOG error "create_iface_iptables: $error"
}
add_route()
{
let tid++
- config_get family "$section" family ipv4
[ -n "${active_tbls##* $tid *}" ] && return
$IP route add table $tid $route_line ||
LOG warn "failed to add $route_line to table $tid"
mwan3_create_iface_rules()
{
- local id family
+ local id family IP
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 "$id"
- $IP4 rule add pref $(($id+2000)) fwmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK lookup "$id"
+ IP="$IP4"
+ elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
+ IP="$IP6"
+ else
+ return
fi
- if [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
-
- while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
- $IP6 rule del pref $(($id+1000))
- done
+ while [ -n "$($IP rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
+ $IP rule del pref $(($id+1000))
+ done
- while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
- $IP6 rule del pref $(($id+2000))
- done
+ while [ -n "$($IP rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
+ $IP rule del pref $(($id+2000))
+ done
- $IP6 rule add pref $(($id+1000)) iif "$2" lookup "$id"
- $IP6 rule add pref $(($id+2000)) fwmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK lookup "$id"
- fi
+ $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"
}
mwan3_delete_iface_rules()
[ -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
+ IP="$IP4"
+ elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
+ IP="$IP6"
+ else
+ return
fi
- if [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
-
- while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
- $IP6 rule del pref $(($id+1000))
- done
+ while [ -n "$($IP rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
+ $IP rule del pref $(($id+1000))
+ done
- while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
- $IP6 rule del pref $(($id+2000))
- done
- fi
+ while [ -n "$($IP rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
+ $IP rule del pref $(($id+2000))
+ done
}
mwan3_delete_iface_ipset_entries()
[ -n "$id" ] || return 0
for setname in $(ipset -n list | grep ^mwan3_sticky_); do
- for entry in $(ipset list "$setname" | grep "$(echo $(mwan3_id2mask id MMX_MASK) | awk '{ printf "0x%08x", $1; }')" | cut -d ' ' -f 1); do
+ for entry in $(ipset list "$setname" | grep "$(mwan3_id2mask id MMX_MASK | awk '{ printf "0x%08x", $1; }')" | cut -d ' ' -f 1); do
$IPS del "$setname" $entry
done
done
mwan3_track()
{
- local track_ip track_ips pid
+ local track_ips pids
mwan3_list_track_ips()
{
}
config_list_foreach "$1" track_ip mwan3_list_track_ips
- kill -TERM $(pgrep -f "mwan3track $1 $2") > /dev/null 2>&1
- sleep 1
- kill -KILL $(pgrep -f "mwan3track $1 $2") > /dev/null 2>&1
+ # 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 ] && /usr/sbin/mwan3track "$1" "$2" "$3" "$4" $track_ips &
+ [ -x /usr/sbin/mwan3track ] && MWAN3_STARTUP=0 /usr/sbin/mwan3track "$1" "$2" "$3" "$4" $track_ips &
fi
}
-mwan3_track_signal()
-{
- local pid
-
- pid="$(pgrep -f "mwan3track $1 $2")"
- [ "${pid}" != "" ] && {
- kill -USR1 "${pid}"
- }
-}
-
mwan3_set_policy()
{
- local iface_count id iface family metric probability weight device is_lowest is_offline IPT total_weight
+ local id iface family metric probability weight device is_lowest is_offline IPT IPTR total_weight current update error
is_lowest=0
config_get iface "$1" interface
[ -n "$iface" ] || return 0
network_get_device device "$iface"
- [ "$metric" -gt $DEFAULT_LOWEST_METRIC ] && $LOG warn "Member interface $iface has >$DEFAULT_LOWEST_METRIC metric. Not appending to policy" && return 0
+ [ "$metric" -gt $DEFAULT_LOWEST_METRIC ] && LOG warn "Member interface $iface has >$DEFAULT_LOWEST_METRIC metric. Not appending to policy" && return 0
mwan3_get_iface_id id "$iface"
+ [ -n "$id" ] || return 0
+
[ "$(mwan3_get_iface_hotplug_state "$iface")" = "online" ]
is_offline=$?
- [ -n "$id" ] || return 0
-
config_get family "$iface" family ipv4
if [ "$family" = "ipv4" ]; then
IPT="$IPT4"
+ IPTR="$IPT4R"
elif [ "$family" = "ipv6" ]; then
IPT="$IPT6"
+ IPTR="$IPT6R"
fi
+ current="$($IPT -S)"
+ update="*mangle"
if [ "$family" = "ipv4" ] && [ $is_offline -eq 0 ]; then
if [ "$metric" -lt "$lowest_metric_v4" ]; then
fi
fi
if [ $is_lowest -eq 1 ]; then
- $IPT -F "mwan3_policy_$policy"
- $IPT -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
+ mwan3_push_update -F "mwan3_policy_$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
elif [ $is_offline -eq 0 ]; then
probability=$(($weight*1000/$total_weight))
if [ "$probability" -lt 10 ]; then
probability="1"
fi
- $IPT -I "mwan3_policy_$policy" \
- -m mark --mark 0x0/$MMX_MASK \
- -m statistic \
- --mode random \
- --probability "$probability" \
- -m comment --comment "$iface $weight $total_weight" \
- -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
+ mwan3_push_update -I "mwan3_policy_$policy" \
+ -m mark --mark 0x0/$MMX_MASK \
+ -m statistic \
+ --mode random \
+ --probability "$probability" \
+ -m comment --comment \"$iface $weight $total_weight\" \
+ -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
elif [ -n "$device" ]; then
- $IPT -S "mwan3_policy_$policy" | grep -q '.*--comment ".* [0-9]* [0-9]*"' || \
- $IPT -I "mwan3_policy_$policy" \
- -o "$device" \
- -m mark --mark 0x0/$MMX_MASK \
- -m comment --comment "out $iface $device" \
- -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
+ echo "$current" | grep -q "^-A mwan3_policy_$policy.*--comment .* [0-9]* [0-9]*" ||
+ mwan3_push_update -I "mwan3_policy_$policy" \
+ -o "$device" \
+ -m mark --mark 0x0/$MMX_MASK \
+ -m comment --comment \"out $iface $device\" \
+ -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
fi
+ mwan3_push_update COMMIT
+ mwan3_push_update ""
+ error=$(echo "$update" | $IPTR 2>&1) || LOG error "set_policy ($1): $error"
+
}
mwan3_create_policies_iptables()
{
- local last_resort lowest_metric_v4 lowest_metric_v6 total_weight_v4 total_weight_v6 policy IPT
+ local last_resort lowest_metric_v4 lowest_metric_v6 total_weight_v4 total_weight_v6 policy IPT current update error
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
+ LOG warn "Policy $1 exceeds max of 15 chars. Not setting policy" && return 0
fi
for IPT in "$IPT4" "$IPT6"; do
[ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue
- if ! $IPT -S "mwan3_policy_$1" &> /dev/null; then
- $IPT -N "mwan3_policy_$1"
+ current="$($IPT -S)"
+ update="*mangle"
+ if [ -n "${current##*-N mwan3_policy_$1*}" ]; then
+ mwan3_push_update -N "mwan3_policy_$1"
fi
- $IPT -F "mwan3_policy_$1"
+ mwan3_push_update -F "mwan3_policy_$1"
case "$last_resort" in
blackhole)
- $IPT -A "mwan3_policy_$1" \
- -m mark --mark 0x0/$MMX_MASK \
- -m comment --comment "blackhole" \
- -j MARK --set-xmark $MMX_BLACKHOLE/$MMX_MASK
- ;;
+ mwan3_push_update -A "mwan3_policy_$1" \
+ -m mark --mark 0x0/$MMX_MASK \
+ -m comment --comment "blackhole" \
+ -j MARK --set-xmark $MMX_BLACKHOLE/$MMX_MASK
+ ;;
default)
- $IPT -A "mwan3_policy_$1" \
- -m mark --mark 0x0/$MMX_MASK \
- -m comment --comment "default" \
- -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
- ;;
+ mwan3_push_update -A "mwan3_policy_$1" \
+ -m mark --mark 0x0/$MMX_MASK \
+ -m comment --comment "default" \
+ -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
+ ;;
*)
- $IPT -A "mwan3_policy_$1" \
- -m mark --mark 0x0/$MMX_MASK \
- -m comment --comment "unreachable" \
- -j MARK --set-xmark $MMX_UNREACHABLE/$MMX_MASK
- ;;
+ mwan3_push_update -A "mwan3_policy_$1" \
+ -m mark --mark 0x0/$MMX_MASK \
+ -m comment --comment "unreachable" \
+ -j MARK --set-xmark $MMX_UNREACHABLE/$MMX_MASK
+ ;;
esac
+ mwan3_push_update COMMIT
+ mwan3_push_update ""
+ if [ "$IPT" = "$IPT4" ]; then
+ error=$(echo "$update" | $IPT4R 2>&1) || LOG error "create_policies_iptables ($1): $error"
+ else
+ error=$(echo "$update" | $IPT6R 2>&1) || LOG error "create_policies_iptables ($1): $error"
+ fi
done
lowest_metric_v4=$DEFAULT_LOWEST_METRIC
mwan3_set_sticky_iptables()
{
local id iface
-
- for iface in $($IPT4 -S "$policy" | cut -s -d'"' -f2 | awk '{print $1}'); do
-
+ for iface in $(echo "$current" | grep "^-A $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
- [ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continuea
- if [ -n "$($IPT -S "mwan3_iface_in_$1" 2> /dev/null)" ]; then
- $IPT -I "mwan3_rule_$rule" \
- -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
- $IPT -I "mwan3_rule_$rule" \
- -m mark --mark 0/$MMX_MASK \
- -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
- fi
- done
+ if [ -z "${current##*-N mwan3_iface_in_$1*}" ]; then
+ mwan3_push_update -I "mwan3_rule_$rule" \
+ -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
+ mwan3_push_update -I "mwan3_rule_$rule" \
+ -m mark --mark 0/$MMX_MASK \
+ -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
+ fi
fi
done
}
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 rule policy IPT
- local global_logging rule_logging loglevel
+ local sticky dest_ip dest_port use_policy timeout policy
+ local global_logging rule_logging loglevel rule_policy rule ipv
rule="$1"
-
+ ipv="$2"
+ rule_policy=0
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
config_get src_iface "$1" src_iface
- network_get_device src_dev "$src_iface"
config_get src_port "$1" src_port
config_get dest_ip "$1" dest_ip
config_get dest_port "$1" dest_port
config_get use_policy "$1" use_policy
config_get family "$1" family any
+ config_get rule_logging "$1" logging 0
+ config_get global_logging globals logging 0
+ config_get loglevel globals loglevel notice
+
+ if [ -n "$src_iface" ]; then
+ network_get_device src_dev "$src_iface"
+ if [ -z "$src_dev" ]; then
+ LOG notice "could not find device corresponding to src_iface $src_iface for rule $1"
+ return
+ fi
+ fi
[ -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
- [ "$proto" != 'tcp' ] && [ "$proto" != 'udp' ] && {
+ 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"
+ LOG warn "src_port set to '$src_port' but proto set to '$proto' not tcp or udp. src_port will be ignored"
}
+
[ -n "$dest_port" ] && {
- $LOG warn "dest_port set to '$dest_port' but proto set to '$proto' not tcp or udp. dest_port will be ignored"
+ LOG warn "dest_port set to '$dest_port' but proto set to '$proto' not tcp or udp. dest_port will be ignored"
}
unset src_port
unset dest_port
- }
-
- config_get rule_logging "$1" logging 0
- config_get global_logging globals logging 0
- config_get loglevel globals loglevel notice
+ fi
if [ "$1" != "$(echo "$1" | cut -c1-15)" ]; then
- $LOG warn "Rule $1 exceeds max of 15 chars. Not setting rule" && return 0
+ 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 $MMX_DEFAULT/$MMX_MASK"
- elif [ "$use_policy" = "unreachable" ]; then
- policy="MARK --set-xmark $MMX_UNREACHABLE/$MMX_MASK"
- elif [ "$use_policy" = "blackhole" ]; then
- policy="MARK --set-xmark $MMX_BLACKHOLE/$MMX_MASK"
- else
- if [ "$sticky" -eq 1 ]; then
+ if [ -z "$use_policy" ]; then
+ return
+ fi
- policy="mwan3_policy_$use_policy"
+ if [ "$use_policy" = "default" ]; then
+ policy="MARK --set-xmark $MMX_DEFAULT/$MMX_MASK"
+ elif [ "$use_policy" = "unreachable" ]; then
+ policy="MARK --set-xmark $MMX_UNREACHABLE/$MMX_MASK"
+ elif [ "$use_policy" = "blackhole" ]; then
+ policy="MARK --set-xmark $MMX_BLACKHOLE/$MMX_MASK"
+ else
+ rule_policy=1
+ policy="mwan3_policy_$use_policy"
+ if [ "$sticky" -eq 1 ]; then
+ $IPS -! create "mwan3_sticky_v4_$rule" \
+ hash:ip,mark markmask "$MMX_MASK" \
+ timeout "$timeout"
+ [ $NO_IPV6 -eq 0 ] &&
+ $IPS -! create "mwan3_sticky_v6_$rule" \
+ hash:ip,mark markmask "$MMX_MASK" \
+ timeout "$timeout" family inet6
+ $IPS -! create "mwan3_sticky_$rule" list:set
+ $IPS -! add "mwan3_sticky_$rule" "mwan3_sticky_v4_$rule"
+ [ $NO_IPV6 -eq 0 ] &&
+ $IPS -! add "mwan3_sticky_$rule" "mwan3_sticky_v6_$rule"
+ fi
+ fi
- for IPT in "$IPT4" "$IPT6"; do
- [ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue
- if ! $IPT -S "$policy" &> /dev/null; then
- $IPT -N "$policy"
- fi
+ [ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && return
+ [ "$family" = "ipv4" ] && [ "$ipv" = "ipv6" ] && return
+ [ "$family" = "ipv6" ] && [ "$ipv" = "ipv4" ] && return
- if ! $IPT -S "mwan3_rule_$1" &> /dev/null; then
- $IPT -N "mwan3_rule_$1"
- fi
+ if [ $rule_policy -eq 1 ] && [ -n "${current##*-N $policy*}" ]; then
+ mwan3_push_update -N "$policy"
+ fi
- $IPT -F "mwan3_rule_$1"
- done
+ if [ $rule_policy -eq 1 ] && [ "$sticky" -eq 1 ]; then
+ if [ -n "${current##*-N mwan3_rule_$1*}" ]; then
+ mwan3_push_update -N "mwan3_rule_$1"
+ fi
- $IPS -! create "mwan3_sticky_v4_$rule" \
- hash:ip,mark markmask "$MMX_MASK" \
- timeout "$timeout"
- $IPS -! create "mwan3_sticky_v6_$rule" \
- hash:ip,mark markmask "$MMX_MASK" \
- 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"
+ mwan3_push_update -F "mwan3_rule_$1"
+ config_foreach mwan3_set_sticky_iptables interface $ipv
- config_foreach mwan3_set_sticky_iptables interface
-
- for IPT in "$IPT4" "$IPT6"; do
- [ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue
- $IPT -A "mwan3_rule_$1" \
- -m mark --mark 0/$MMX_MASK \
- -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
- [ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue
- if ! $IPT -S "$policy" &> /dev/null; then
- $IPT -N "$policy"
- fi
- done
+ mwan3_push_update -A "mwan3_rule_$1" \
+ -m mark --mark 0/$MMX_MASK \
+ -j "$policy"
+ mwan3_push_update -A "mwan3_rule_$1" \
+ -m mark ! --mark 0xfc00/0xfc00 \
+ -j SET --del-set "mwan3_sticky_$rule" src,src
+ mwan3_push_update -A "mwan3_rule_$1" \
+ -m mark ! --mark 0xfc00/0xfc00 \
+ -j SET --add-set "mwan3_sticky_$rule" src,src
+ policy="mwan3_rule_$1"
+ fi
+ if [ "$global_logging" = "1" ] && [ "$rule_logging" = "1" ]; then
+ mwan3_push_update -A mwan3_rules \
+ -p "$proto" \
+ ${src_ip:+-s} $src_ip \
+ ${src_dev:+-i} $src_dev \
+ ${dest_ip:+-d} $dest_ip \
+ $ipset \
+ ${src_port:+-m} ${src_port:+multiport} ${src_port:+--sports} $src_port \
+ ${dest_port:+-m} ${dest_port:+multiport} ${dest_port:+--dports} $dest_port \
+ -m mark --mark 0/$MMX_MASK \
+ -m comment --comment "$1" \
+ -j LOG --log-level "$loglevel" --log-prefix "MWAN3($1)"
+ fi
- fi
- fi
- for IPT in "$IPT4" "$IPT6"; do
- [ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue
- [ "$family" = "ipv4" ] && [ "$IPT" = "$IPT6" ] && continue
- [ "$family" = "ipv6" ] && [ "$IPT" = "$IPT4" ] && continue
- [ "$global_logging" = "1" ] && [ "$rule_logging" = "1" ] && {
- $IPT -A mwan3_rules \
- -p "$proto" \
- ${src_ip:+-s} $src_ip \
- ${src_dev:+-i} $src_dev \
- ${dest_ip:+-d} $dest_ip \
- $ipset \
- ${src_port:+-m} ${src_port:+multiport} ${src_port:+--sports} $src_port \
- ${dest_port:+-m} ${dest_port:+multiport} ${dest_port:+--dports} $dest_port \
- -m mark --mark 0/$MMX_MASK \
- -m comment --comment "$1" \
- -j LOG --log-level "$loglevel" --log-prefix "MWAN3($1)"
- }
-
- $IPT -A mwan3_rules \
- -p "$proto" \
- ${src_ip:+-s} $src_ip \
- ${src_dev:+-i} $src_dev \
- ${dest_ip:+-d} $dest_ip \
- $ipset \
- ${src_port:+-m} ${src_port:+multiport} ${src_port:+--sports} $src_port \
- ${dest_port:+-m} ${dest_port:+multiport} ${dest_port:+--dports} $dest_port \
- -m mark --mark 0/$MMX_MASK \
- -j $policy
- done
+ mwan3_push_update -A mwan3_rules \
+ -p "$proto" \
+ ${src_ip:+-s} $src_ip \
+ ${src_dev:+-i} $src_dev \
+ ${dest_ip:+-d} $dest_ip \
+ $ipset \
+ ${src_port:+-m} ${src_port:+multiport} ${src_port:+--sports} $src_port \
+ ${dest_port:+-m} ${dest_port:+multiport} ${dest_port:+--dports} $dest_port \
+ -m mark --mark 0/$MMX_MASK \
+ -j $policy
+
+}
+
+mwan3_set_user_iface_rules()
+{
+ local current iface update family error device is_src_iface
+ iface=$1
+ device=$2
+
+ if [ -z "$device" ]; then
+ LOG notice "set_user_iface_rules: could not find device corresponding to iface $iface"
+ return
+ fi
+
+ config_get family "$iface" family ipv4
+
+ if [ "$family" = "ipv4" ]; then
+ IPT="$IPT4"
+ IPTR="$IPT4R"
+ elif [ "$family" = "ipv6" ]; then
+ IPT="$IPT6"
+ IPTR="$IPT6R"
fi
+ $IPT -S | grep -q "^-A mwan3_rules.*-i $device" && return
+
+ is_src_iface=0
+
+ iface_rule()
+ {
+ local src_iface
+ config_get src_iface "$1" src_iface
+ [ "$src_iface" = "$iface" ] && is_src_iface=1
+ }
+ config_foreach iface_rule rule
+ [ $is_src_iface -eq 1 ] && mwan3_set_user_rules
}
mwan3_set_user_rules()
{
- local IPT
+ local IPT IPTR ipv
+ local current update error
- for IPT in "$IPT4" "$IPT6"; do
- [ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue
- if ! $IPT -S mwan3_rules &> /dev/null; then
- $IPT -N mwan3_rules
+ for ipv in ipv4 ipv6; do
+ if [ "$ipv" = "ipv4" ]; then
+ IPT="$IPT4"
+ IPTR="$IPT4R"
+ elif [ "$ipv" = "ipv6" ]; then
+ IPT="$IPT6"
+ IPTR="$IPT6R"
fi
+ [ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue
+ update="*mangle"
+ current="$($IPT -S)"
+
+
+ if [ -n "${current##*-N mwan3_rules*}" ]; then
+ mwan3_push_update -N "mwan3_rules"
+ fi
+
+ mwan3_push_update -F mwan3_rules
- $IPT -F mwan3_rules
+ config_foreach mwan3_set_user_iptables_rule rule "$ipv"
+
+ mwan3_push_update COMMIT
+ mwan3_push_update ""
+ error=$(echo "$update" | $IPTR 2>&1) || LOG error "set_user_rules: $error"
done
- config_foreach mwan3_set_user_iptables_rule rule
+
}
mwan3_set_iface_hotplug_state() {
if [ -z "$id" ] || [ -z "$device" ]; then
result="offline"
elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" ] && \
- [ -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" ] && \
- [ -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" ] && \
- [ -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
+ [ -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" ] && \
+ [ -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
json_add_string section interfaces
json_add_string interface "$1"
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)):'"')" ] || \
- [ -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" ] || \
- [ -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
+ [ -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" ] || \
+ [ -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"
elif [ "$enabled" = "1" ]; then
result="offline"
if [ "$action" = "$flush_conntrack" ]; then
echo f > ${CONNTRACK_FILE}
- $LOG info "Connection tracking flushed for interface '$interface' on action '$action'"
+ LOG info "Connection tracking flushed for interface '$interface' on action '$action'"
fi
}
mwan3_track_clean()
{
rm -rf "$MWAN3_STATUS_DIR/${1}" &> /dev/null
- [ -d "$MWAN3_STATUS_DIR" ] && {
- if [ -z "$(ls -A "$MWAN3_STATUS_DIR")" ]; then
- rm -rf "$MWAN3_STATUS_DIR"
- fi
- }
+ rmdir --ignore-fail-on-non-empty "$MWAN3_STATUS_DIR"
}
. /lib/functions.sh
. /lib/mwan3/common.sh
-LOG="logger -t $(basename "$0")[$$] -p"
INTERFACE=""
DEVICE=""
PING="/bin/ping"
IFDOWN_EVENT=0
+IFUP_EVENT=0
clean_up() {
- $LOG notice "Stopping mwan3track for interface \"${INTERFACE}\""
+ LOG notice "Stopping mwan3track for interface \"${INTERFACE}\""
exit 0
}
if_down() {
- $LOG info "Detect ifdown event on interface ${INTERFACE} (${DEVICE})"
+ LOG info "Detect ifdown event on interface ${INTERFACE} (${DEVICE})"
IFDOWN_EVENT=1
}
+if_up() {
+ LOG info "Detect ifup event on interface ${INTERFACE} (${DEVICE})"
+ IFUP_EVENT=1
+}
+
validate_track_method() {
case "$1" in
ping)
- command -v ping 1>/dev/null 2>&1 || {
- $LOG warn "Missing ping. Please install iputils-ping package or enable ping util and recompile busybox."
+ [ -x "$PING" ] || {
+ LOG warn "Missing ping. Please enable ping util and recompile busybox."
return 1
}
;;
arping)
command -v arping 1>/dev/null 2>&1 || {
- $LOG warn "Missing arping. Please install iputils-arping package."
+ LOG warn "Missing arping. Please install iputils-arping package."
return 1
}
;;
httping)
command -v httping 1>/dev/null 2>&1 || {
- $LOG warn "Missing httping. Please install httping package."
+ LOG warn "Missing httping. Please install httping package."
return 1
}
[ -n "$2" -a "$2" != "0.0.0.0" -a "$2" != "::" ] || {
- $LOG warn "Cannot determine source IP for the interface which is required by httping."
+ LOG warn "Cannot determine source IP for the interface which is required by httping."
return 1
}
;;
nping-*)
command -v nping 1>/dev/null 2>&1 || {
- $LOG warn "Missing nping. Please install nping package."
+ LOG warn "Missing nping. Please install nping package."
return 1
}
;;
*)
- $LOG warn "Unsupported tracking method: $track_method"
+ LOG warn "Unsupported tracking method: $track_method"
return 2
;;
esac
}
+disconnected() {
+ echo "offline" > /var/run/mwan3track/$INTERFACE/STATUS
+ echo "$(get_uptime)" > /var/run/mwan3track/$INTERFACE/OFFLINE
+ echo "0" > /var/run/mwan3track/$INTERFACE/ONLINE
+ score=0
+ [ "$1" == 1 ] && return
+ LOG notice "Interface $INTERFACE ($DEVICE) is offline"
+ env -i ACTION="disconnected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface
+}
+
+connected() {
+ echo "online" > /var/run/mwan3track/$INTERFACE/STATUS
+ echo "0" > /var/run/mwan3track/$INTERFACE/OFFLINE
+ echo "$(get_uptime)" > /var/run/mwan3track/$INTERFACE/ONLINE
+ host_up_count=0
+ lost=0
+ turn=0
+ loss=0
+ [ "$1" == 1 ] && return
+ LOG notice "Interface $INTERFACE ($DEVICE) is online"
+ env -i ACTION="connected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface
+}
+
+firstconnect() {
+ if [ "$STATUS" = "offline" ]; then
+ disconnected 1
+ else
+ connected 1
+ fi
+}
+
+update_status() {
+ local status track_ip
+ track_ip=$1
+ status=$2
+
+ echo "$1" > /var/run/mwan3track/$INTERFACE/TRACK_${track_ip}
+ [ -z "$3" ] && return
+ echo "$3" > /var/run/mwan3track/$INTERFACE/LATENCY_${track_ip}
+ echo "$4" > /var/run/mwan3track/$INTERFACE/LOSS_${track_ip}
+}
+
main() {
local reliability count timeout interval failure_interval
local recovery_interval down up size
DEVICE=$2
STATUS=$3
SRC_IP=$4
- mkdir -p /var/run/mwan3track/$1
+ mkdir -p /var/run/mwan3track/$INTERFACE
trap clean_up TERM
trap if_down USR1
+ trap if_up USR2
config_load mwan3
- config_get track_method $1 track_method ping
- config_get_bool httping_ssl $1 httping_ssl 0
+ config_get track_method $INTERFACE track_method ping
+ config_get_bool httping_ssl $INTERFACE httping_ssl 0
validate_track_method $track_method $SRC_IP || {
track_method=ping
if validate_track_method $track_method; then
- $LOG warn "Using ping to track interface $INTERFACE avaliability"
+ LOG warn "Using ping to track interface $INTERFACE avaliability"
else
- $LOG err "No track method avaliable"
+ LOG err "No track method avaliable"
exit 1
fi
}
- config_get reliability $1 reliability 1
- config_get count $1 count 1
- config_get timeout $1 timeout 4
- config_get interval $1 interval 10
- config_get down $1 down 5
- config_get up $1 up 5
- config_get size $1 size 56
- config_get max_ttl $1 max_ttl 60
- config_get failure_interval $1 failure_interval $interval
- config_get_bool keep_failure_interval $1 keep_failure_interval 0
- config_get recovery_interval $1 recovery_interval $interval
- config_get_bool check_quality $1 check_quality 0
- config_get failure_latency $1 failure_latency 1000
- config_get recovery_latency $1 recovery_latency 500
- config_get failure_loss $1 failure_loss 40
- config_get recovery_loss $1 recovery_loss 10
+ config_get reliability $INTERFACE reliability 1
+ config_get count $INTERFACE count 1
+ config_get timeout $INTERFACE timeout 4
+ config_get interval $INTERFACE interval 10
+ config_get down $INTERFACE down 5
+ config_get up $INTERFACE up 5
+ config_get size $INTERFACE size 56
+ config_get max_ttl $INTERFACE max_ttl 60
+ config_get failure_interval $INTERFACE failure_interval $interval
+ config_get_bool keep_failure_interval $INTERFACE keep_failure_interval 0
+ config_get recovery_interval $INTERFACE recovery_interval $interval
+ config_get_bool check_quality $INTERFACE check_quality 0
+ config_get failure_latency $INTERFACE failure_latency 1000
+ config_get recovery_latency $INTERFACE recovery_latency 500
+ config_get failure_loss $INTERFACE failure_loss 40
+ config_get recovery_loss $INTERFACE recovery_loss 10
local score=$(($down+$up))
local track_ips=$(echo $* | cut -d ' ' -f 5-99)
local host_up_count=0
local lost=0
- local sleep_time=0
local turn=0
- local result
local ping_protocol=4
- local ping_result
- local ping_result_raw
- local ping_status
- local loss=0
- local latency=0
+ local sleep_time result ping_result ping_result_raw ping_status loss latency
- if [ "$STATUS" = "offline" ]; then
- echo "offline" > /var/run/mwan3track/$1/STATUS
- echo "0" > /var/run/mwan3track/$1/ONLINE
- echo "$(get_uptime)" > /var/run/mwan3track/$1/OFFLINE
- score=0
- else
- echo "online" > /var/run/mwan3track/$1/STATUS
- echo "0" > /var/run/mwan3track/$1/OFFLINE
- echo "$(get_uptime)" > /var/run/mwan3track/$1/ONLINE
- env -i ACTION="connected" INTERFACE="$1" DEVICE="$2" /sbin/hotplug-call iface
- fi
+ firstconnect
while true; do
sleep_time=$interval
# pinging IPv6 hosts with an interface is troublesome
# https://bugs.openwrt.org/index.php?do=details&task_id=2897
# so get the IP address of the interface and use that instead
- if echo $track_ip | grep -q ':'; then
- ADDR=$(ip -6 addr ls dev "$DEVICE" | sed -ne '/\/128/d' -e 's/ *inet6 \([^ \/]*\).* scope global.*/\1/p' | head -n1)
- [ -z "$ADDR" ] && ADDR=$(ip -6 addr ls dev "$DEVICE" | sed -ne 's/ *inet6 \([^ \/]*\).* scope global.*/\1/p')
+ if [ -z ${track_ip##*:*} ]; then
ping_protocol=6
+ else
+ unset SRC_IP
fi
if [ $check_quality -eq 0 ]; then
- $PING -$ping_protocol -I ${ADDR:-$DEVICE} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip &> /dev/null
+ $PING -$ping_protocol -I ${SRC_IP:-$DEVICE} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip &> /dev/null
result=$?
else
- ping_result_raw="$($PING -$ping_protocol -I ${ADDR:-$DEVICE} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip 2>/dev/null)"
+ ping_result_raw="$($PING -$ping_protocol -I ${SRC_IP:-$DEVICE} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip 2>/dev/null)"
ping_status=$?
ping_result=$(echo "$ping_result_raw" | tail -n2)
loss="$(echo "$ping_result" | grep "packet loss" | cut -d "," -f3 | awk '{print $1}' | sed -e 's/%//')"
if [ $check_quality -eq 0 ]; then
if [ $result -eq 0 ]; then
let host_up_count++
- echo "up" > /var/run/mwan3track/$1/TRACK_${track_ip}
+ update_status "$track_ip" "up"
+
if [ $score -le $up ]; then
- $LOG info "Check ($track_method) success for target \"$track_ip\" on interface $1 ($2)"
+ LOG info "Check ($track_method) success for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
fi
else
let lost++
- echo "down" > /var/run/mwan3track/$1/TRACK_${track_ip}
+ update_status "$track_ip" "down"
+
if [ $score -gt $up ]; then
- $LOG info "Check ($track_method) failed for target \"$track_ip\" on interface $1 ($2)"
+ LOG info "Check ($track_method) failed for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
fi
fi
else
if [ "$loss" -ge "$failure_loss" -o "$latency" -ge "$failure_latency" ]; then
let lost++
- echo "down" > /var/run/mwan3track/$1/TRACK_${track_ip}
- echo "$latency" > /var/run/mwan3track/$1/LATENCY_${track_ip}
- echo "$loss" > /var/run/mwan3track/$1/LOSS_${track_ip}
+ update_status "$track_ip" "down" $latency $loss
if [ $score -gt $up ]; then
- $LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) failed for target \"$track_ip\" on interface $1 ($2)"
+ LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) failed for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
fi
elif [ "$loss" -le "$recovery_loss" -a "$latency" -le "$recovery_latency" ]; then
let host_up_count++
- echo "up" > /var/run/mwan3track/$1/TRACK_${track_ip}
- echo "$latency" > /var/run/mwan3track/$1/LATENCY_${track_ip}
- echo "$loss" > /var/run/mwan3track/$1/LOSS_${track_ip}
+ update_status "$track_ip" "up" $latency $loss
if [ $score -le $up ]; then
- $LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) success for target \"$track_ip\" on interface $1 ($2)"
+ LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) success for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
fi
else
- echo "skipped" > /var/run/mwan3track/$1/TRACK_${track_ip}
+ echo "skipped" > /var/run/mwan3track/$INTERFACE/TRACK_${track_ip}
fi
fi
else
- echo "skipped" > /var/run/mwan3track/$1/TRACK_${track_ip}
+ echo "skipped" > /var/run/mwan3track/$INTERFACE/TRACK_${track_ip}
fi
done
fi
if [ $score -eq $up ]; then
- echo "offline" > /var/run/mwan3track/$1/STATUS
- env -i ACTION=ifdown INTERFACE=$1 DEVICE=$2 /sbin/hotplug-call iface
+ disconnected
score=0
fi
else
if [ $score -lt $(($down+$up)) ] && [ $lost -gt 0 ]; then
- $LOG info "Lost $(($lost*$count)) ping(s) on interface $1 ($2)"
+ LOG info "Lost $(($lost*$count)) ping(s) on interface $INTERFACE ($DEVICE). Current score: $score"
fi
let score++
lost=0
if [ $score -gt $up ]; then
- echo "online" > /var/run/mwan3track/$1/STATUS
+ echo "online" > /var/run/mwan3track/$INTERFACE/STATUS
score=$(($down+$up))
elif [ $score -le $up ]; then
sleep_time=$recovery_interval
fi
if [ $score -eq $up ]; then
- $LOG notice "Interface $1 ($2) is online"
- echo "online" > /var/run/mwan3track/$1/STATUS
- env -i ACTION=ifup INTERFACE=$1 DEVICE=$2 /sbin/hotplug-call iface
- exit 0
+ connected $INTERFACE $DEVICE
fi
fi
let turn++
mkdir -p "/var/run/mwan3track/${1}"
- echo "${lost}" > /var/run/mwan3track/$1/LOST
- echo "${score}" > /var/run/mwan3track/$1/SCORE
- echo "${turn}" > /var/run/mwan3track/$1/TURN
- echo "$(get_uptime)" > /var/run/mwan3track/$1/TIME
+ echo "${lost}" > /var/run/mwan3track/$INTERFACE/LOST
+ echo "${score}" > /var/run/mwan3track/$INTERFACE/SCORE
+ echo "${turn}" > /var/run/mwan3track/$INTERFACE/TURN
+ echo "$(get_uptime)" > /var/run/mwan3track/$INTERFACE/TIME
host_up_count=0
sleep "${sleep_time}" &
wait
if [ "${IFDOWN_EVENT}" -eq 1 ]; then
- echo "offline" > /var/run/mwan3track/$1/STATUS
- echo "$(get_uptime)" > /var/run/mwan3track/$1/OFFLINE
- echo "0" > /var/run/mwan3track/$1/ONLINE
- $LOG notice "Interface $1 ($2) is offline"
- env -i ACTION="disconnected" INTERFACE="$1" DEVICE="$2" /sbin/hotplug-call iface
- score=0
+ LOG debug "Register ifdown event on interface ${INTERFACE} (${DEVICE})"
+ disconnected 1
IFDOWN_EVENT=0
fi
+ if [ "${IFUP_EVENT}" -eq 1 ]; then
+ LOG debug "Register ifup event on interface ${INTERFACE} (${DEVICE})"
+ firstconnect
+ IFUP_EVENT=0
+ fi
done
}