diff --git a/net/mwan3/Makefile b/net/mwan3/Makefile index 6ae44ad35..65e2925c3 100644 --- a/net/mwan3/Makefile +++ b/net/mwan3/Makefile @@ -8,8 +8,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=mwan3 -PKG_VERSION:=2.8.12 -PKG_RELEASE:=2 +PKG_VERSION:=2.9.0 +PKG_RELEASE:=1 PKG_MAINTAINER:=Florian Eckert PKG_LICENSE:=GPL-2.0 diff --git a/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 b/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 index 6898df819..6a7e95ac4 100644 --- a/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 +++ b/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 @@ -4,96 +4,101 @@ . /lib/functions/network.sh . /lib/mwan3/mwan3.sh . /usr/share/libubox/jshn.sh +. /lib/mwan3/common.sh -[ "$ACTION" == "ifup" -o "$ACTION" == "ifdown" ] || exit 1 +SCRIPTNAME="mwan3-hotplug" +[ "$ACTION" = "ifup" ] || [ "$ACTION" = "ifdown" ] || [ "$ACTION" = "connected" ] || [ "$ACTION" = "disconnected" ] || exit 1 [ -n "$INTERFACE" ] || exit 2 - -if [ "$ACTION" == "ifup" ]; then - [ -n "$DEVICE" ] || exit 3 +if ( [ "$ACTION" = "ifup" ] || [ "$ACTION" = "connected" ] ) && [ -z "$DEVICE" ]; then + LOG notice "$ACTION called on $INTERFACE with no device set" + exit 3 fi -mwan3_lock "$ACTION" "$INTERFACE" +[ "$MWAN3_STARTUP" = 1 ] || mwan3_lock "$ACTION" "$INTERFACE" + config_load mwan3 config_get_bool enabled globals 'enabled' '0' [ "${enabled}" -gt 0 ] || { - mwan3_unlock "$ACTION" "$INTERFACE" + [ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$INTERFACE" + LOG notice "mwan3 hotplug on $INTERFACE not called because globally disabled" mwan3_flush_conntrack "$INTERFACE" "$ACTION" exit 0 } +$IPT4 -S mwan3_hook &>/dev/null || { + mwan3_unlock "$ACTION" "$INTERFACE" + LOG warn "hotplug called on $INTERFACE before mwan3 has been set up" + exit 0 +} + mwan3_init -mwan3_set_connected_iptables -mwan3_set_custom_ipset +[ "$MWAN3_STARTUP" = 1 ] || { + mwan3_set_connected_iptables + mwan3_set_custom_ipset +} + +if [ "$MWAN3_STARTUP" != 1 ]; then + mwan3_set_user_iface_rules $INTERFACE $DEVICE +fi config_get initial_state $INTERFACE initial_state "online" config_get_bool enabled $INTERFACE 'enabled' '0' [ "${enabled}" -eq 1 ] || { - mwan3_unlock "$ACTION" "$INTERFACE" + [ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$INTERFACE" + LOG notice "mwan3 hotplug on $INTERFACE not called because interface disabled" exit 0 } -if [ "$ACTION" = "ifup" ]; then - config_get family $INTERFACE family ipv4 - if [ "$family" = "ipv4" ]; then - ubus call network.interface.${INTERFACE}_4 status &>/dev/null - if [ "$?" -eq "0" ]; then - network_get_ipaddr src_ip ${INTERFACE}_4 - else - network_get_ipaddr src_ip ${INTERFACE} - fi - [ -n "$src_ip" ] || src_ip="0.0.0.0" - elif [ "$family" = "ipv6" ]; then - ubus call network.interface.${INTERFACE}_6 status &>/dev/null - if [ "$?" -eq "0" ]; then - network_get_ipaddr6 src_ip ${INTERFACE}_6 - else - network_get_ipaddr6 src_ip ${INTERFACE} - fi - [ -n "$src_ip" ] || src_ip="::" - fi -fi +trackpid=$(pgrep -f "mwan3track $INTERFACE ") if [ "$initial_state" = "offline" ]; then - json_load "$(ubus call mwan3 status '{"section":"interfaces"}')" - json_select "interfaces" - json_select "${INTERFACE}" - json_get_var running running - json_get_var status status + status=$(cat $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS 2>/dev/null || echo unknown) else status=online - running=1 fi -$LOG notice "Execute "$ACTION" event on interface $INTERFACE (${DEVICE:-unknown})" +[ -z "$TRUE_INTERFACE" ] && mwan3_get_true_iface TRUE_INTERFACE $INTERFACE + +binary_status=$status +[ "$binary_status" = "online" ] || binary_status=offline + +LOG notice "Execute "$ACTION" event on interface $INTERFACE (${DEVICE:-unknown})" case "$ACTION" in - ifup) - mwan3_set_general_rules - mwan3_set_general_iptables + ifup|connected) mwan3_create_iface_iptables $INTERFACE $DEVICE mwan3_create_iface_rules $INTERFACE $DEVICE mwan3_create_iface_route $INTERFACE $DEVICE - if [ "${running}" -eq 1 ] && [ "${status}" = "online" ]; then - $LOG notice "Starting tracker on interface $INTERFACE (${DEVICE:-unknown})" - mwan3_set_iface_hotplug_state $INTERFACE "online" - mwan3_track $INTERFACE $DEVICE "online" "$src_ip" + [ "$MWAN3_STARTUP" != 1 ] && mwan3_add_non_default_iface_route $INTERFACE $DEVICE + mwan3_set_iface_hotplug_state $INTERFACE "$binary_status" + + mwan3_get_src_ip src_ip "$TRUE_INTERFACE" + if [ -n "${trackpid}" ]; then + device_pid=$(pgrep -f "mwan3track $INTERFACE $DEVICE ") + if [ "$device_pid" = "$trackpid" ]; then + [ "$ACTION" = ifup ] && kill -USR2 "$trackpid" + else + mwan3_track $INTERFACE $DEVICE "$binary_status" "$src_ip" + LOG notice "Restarted tracker [$!] on interface $INTERFACE (${DEVICE:-unknown})" + fi else - $LOG notice "Starting tracker on interface $INTERFACE (${DEVICE:-unknown})" - mwan3_set_iface_hotplug_state $INTERFACE "offline" - mwan3_track $INTERFACE $DEVICE "offline" "$src_ip" + mwan3_track $INTERFACE $DEVICE "$binary_status" "$src_ip" + LOG notice "Started tracker [$!] on interface $INTERFACE (${DEVICE:-unknown})" fi - mwan3_set_policies_iptables - mwan3_set_user_rules + [ "$MWAN3_STARTUP" != 1 ] && [ "$binary_status" == "online" ] && mwan3_set_policies_iptables + ;; - ifdown) + ifdown|disconnected) mwan3_set_iface_hotplug_state $INTERFACE "offline" mwan3_delete_iface_ipset_entries $INTERFACE - mwan3_track_signal $INTERFACE $DEVICE + mwan3_delete_iface_rules $INTERFACE + mwan3_delete_iface_route $INTERFACE + mwan3_delete_iface_iptables $INTERFACE + if [ "$ACTION" = "ifdown" ]; then + [ -n "$trackpid" ] && kill -USR1 "$trackpid" + fi mwan3_set_policies_iptables - mwan3_set_user_rules ;; esac - -mwan3_unlock "$ACTION" "$INTERFACE" - +[ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$INTERFACE" exit 0 diff --git a/net/mwan3/files/etc/hotplug.d/iface/16-mwan3-user b/net/mwan3/files/etc/hotplug.d/iface/16-mwan3-user index af28b1f4f..2ec5c79a3 100644 --- a/net/mwan3/files/etc/hotplug.d/iface/16-mwan3-user +++ b/net/mwan3/files/etc/hotplug.d/iface/16-mwan3-user @@ -4,22 +4,22 @@ . /lib/functions.sh . /lib/mwan3/mwan3.sh - mwan3_lock "$ACTION" "user" + [ "$MWAN3_STARTUP" = 1 ] || mwan3_lock "$ACTION" "$DEVICE-user" config_load mwan3 config_get_bool enabled globals 'enabled' '0' [ "${enabled}" -gt 0 ] || { - mwan3_unlock "$ACTION" "user" + [ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$DEVICE-user" exit 0 } config_get_bool enabled "$INTERFACE" enabled 0 [ "${enabled}" -eq 1 ] || { - mwan3_unlock "$ACTION" "user" + [ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$DEVICE-user" exit 0 } - mwan3_unlock "$ACTION" "user" + [ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$DEVICE-user" env -i ACTION="$ACTION" INTERFACE="$INTERFACE" DEVICE="$DEVICE" \ /bin/sh /etc/mwan3.user diff --git a/net/mwan3/files/etc/init.d/mwan3 b/net/mwan3/files/etc/init.d/mwan3 index e0c65889a..ba9d920cb 100755 --- a/net/mwan3/files/etc/init.d/mwan3 +++ b/net/mwan3/files/etc/init.d/mwan3 @@ -5,8 +5,9 @@ USE_PROCD=1 boot() { . /lib/config/uci.sh - uci_toggle_state mwan3 globals enabled "1" - mwan3_boot=1 + # disabled until mwan3 start runs so hotplug scripts + # do not start prematurely + uci_toggle_state mwan3 globals enabled "0" rc_procd start_service } @@ -20,7 +21,6 @@ reload_service() { } start_service() { - [ -n "${mwan3_boot}" ] && return 0 /usr/sbin/mwan3 start 1000>&- } diff --git a/net/mwan3/files/lib/mwan3/common.sh b/net/mwan3/files/lib/mwan3/common.sh index 1af129919..bb26327d5 100644 --- a/net/mwan3/files/lib/mwan3/common.sh +++ b/net/mwan3/files/lib/mwan3/common.sh @@ -4,3 +4,14 @@ get_uptime() { local uptime=$(cat /proc/uptime) echo "${uptime%%.*}" } + +SCRIPTNAME="$(basename "$0")" +LOG() +{ + local facility=$1; shift + # in development, we want to show 'debug' level logs + # when this release is out of beta, the comment in the line below + # should be removed + [ "$facility" = "debug" ] && return + logger -t "$SCRIPTNAME[$$]" -p $facility "$*" +} diff --git a/net/mwan3/files/lib/mwan3/mwan3.sh b/net/mwan3/files/lib/mwan3/mwan3.sh index ad41030ad..14af3ded2 100644 --- a/net/mwan3/files/lib/mwan3/mwan3.sh +++ b/net/mwan3/files/lib/mwan3/mwan3.sh @@ -1,4 +1,5 @@ #!/bin/sh + . /usr/share/libubox/jshn.sh IP4="ip -4" @@ -6,7 +7,8 @@ IP6="ip -6" 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}:|" @@ -69,7 +71,7 @@ mwan3_update_dev_to_table() mwan3_update_iface_to_table() { - local _tid section family cfgtype curr_table _mwan3_iface_tbl + local _tid mwan3_iface_tbl=" " update_table() { @@ -163,14 +165,14 @@ mwan3_init() 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<&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 @@ -279,41 +299,35 @@ mwan3_set_connected_ipv4() 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() @@ -336,89 +350,96 @@ 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" @@ -428,43 +449,53 @@ mwan3_create_iface_iptables() 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" } @@ -568,7 +599,6 @@ mwan3_add_all_nondefault_routes() 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" @@ -615,7 +645,7 @@ mwan3_delete_iface_route() mwan3_create_iface_rules() { - local id family + local id family IP config_get family "$1" family ipv4 mwan3_get_iface_id id "$1" @@ -623,32 +653,23 @@ mwan3_create_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 - - $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() @@ -661,26 +682,20 @@ 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() @@ -692,7 +707,7 @@ 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 @@ -712,7 +727,7 @@ mwan3_rtmon() mwan3_track() { - local track_ip track_ips pid + local track_ips pids mwan3_list_track_ips() { @@ -720,28 +735,21 @@ mwan3_track() } 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 @@ -750,22 +758,26 @@ mwan3_set_policy() [ -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 @@ -791,11 +803,11 @@ mwan3_set_policy() 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 @@ -808,63 +820,76 @@ mwan3_set_policy() 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 @@ -884,27 +909,21 @@ mwan3_set_policies_iptables() 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 } @@ -912,161 +931,209 @@ mwan3_set_sticky_iptables() 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() { @@ -1104,9 +1171,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)):'"')" ] && \ - [ -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" @@ -1120,9 +1187,9 @@ mwan3_report_iface_status() 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" @@ -1228,7 +1295,7 @@ mwan3_flush_conntrack() 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 } @@ -1240,9 +1307,5 @@ mwan3_flush_conntrack() 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" } diff --git a/net/mwan3/files/usr/sbin/mwan3 b/net/mwan3/files/usr/sbin/mwan3 index 392d7f500..fd6b5204f 100755 --- a/net/mwan3/files/usr/sbin/mwan3 +++ b/net/mwan3/files/usr/sbin/mwan3 @@ -4,6 +4,7 @@ . /usr/share/libubox/jshn.sh . /lib/functions/network.sh . /lib/mwan3/mwan3.sh +. /lib/mwan3/common.sh help() { @@ -37,52 +38,64 @@ ifdown() ACTION=ifdown INTERFACE=$1 /sbin/hotplug-call iface - kill $(pgrep -f "mwan3track $1 $2") &> /dev/null + kill $(pgrep -f "mwan3track $1 ") &> /dev/null mwan3_track_clean $1 } ifup() { - local device enabled up l3_device status - - mwan3_lock "command" "mwan3" - - config_load mwan3 - config_get_bool enabled globals 'enabled' 0 - - [ ${enabled} -gt 0 ] || { - echo "The service mwan3 is global disabled." - echo "Please execute \"/etc/init.d/mwan3 start\" first." - mwan3_unlock "command" "mwan3" - exit 1 - } + local device enabled up l3_device status interface true_iface if [ -z "$1" ]; then echo "Expecting interface. Usage: mwan3 ifup " - mwan3_unlock "command" "mwan3" exit 0 fi if [ -n "$2" ]; then echo "Too many arguments. Usage: mwan3 ifup " - mwan3_unlock "command" "mwan3" exit 0 fi - config_get enabled "$1" enabled 0 - mwan3_unlock "command" "mwan3" + interface=$1 + + 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 + config_load mwan3 + config_get_bool enabled globals 'enabled' 0 + + [ ${enabled} -gt 0 ] || { + echo "The service mwan3 is global disabled." + echo "Please execute \"/etc/init.d/mwan3 start\" first." + exit 1 + } + else + enabled=1 + fi + mwan3_get_true_iface true_iface $interface + status=$(ubus -S call network.interface.$true_iface status) - status=$(ubus -S call network.interface.$1 status) [ -n "$status" ] && { json_load "$status" json_get_vars up l3_device } + hotplug_startup() + { + MWAN3_STARTUP=$MWAN3_STARTUP ACTION=ifup INTERFACE=$interface DEVICE=$l3_device TRUE_INTERFACE=$true_iface sh /etc/hotplug.d/iface/15-mwan3 + MWAN3_STARTUP=$MWAN3_STARTUP ACTION=ifup INTERFACE=$interface DEVICE=$l3_device TRUE_INTERFACE=$true_iface sh /etc/hotplug.d/iface/16-mwan3-user + } + + if [ "$up" != "1" ] || [ -z "$l3_device" ] || [ "$enabled" != "1" ]; then + return + fi - if [ "$up" = "1" ] \ - && [ -n "$l3_device" ] \ - && [ "$enabled" = "1" ]; then - ACTION=ifup INTERFACE=$1 DEVICE=$l3_device /sbin/hotplug-call iface + if [ "${MWAN3_STARTUP}" = 1 ]; then + hotplug_startup & + hotplug_pids="$hotplug_pids $!" + else + hotplug_startup fi + } interfaces() @@ -137,58 +150,78 @@ status() start() { - local enabled - + local enabled hotplug_pids MWAN3_STARTUP + MWAN3_STARTUP=1 mwan3_lock "command" "mwan3" uci_toggle_state mwan3 globals enabled "1" - mwan3_unlock "command" "mwan3" - config_load mwan3 + + mwan3_update_iface_to_table + mwan3_set_connected_iptables + mwan3_set_custom_ipset + mwan3_set_general_rules + mwan3_set_general_iptables config_foreach ifup interface + wait $hotplug_pids + mwan3_add_all_nondefault_routes + mwan3_set_policies_iptables + mwan3_set_user_rules + + + mwan3_unlock "command" "mwan3" mwan3_rtmon + unset MWAN3_STARTUP } stop() { - local ipset route rule table IP IPT pid + local ipset rule IP IPTR IPT kill_pid family table tid mwan3_lock "command" "mwan3" uci_toggle_state mwan3 globals enabled "0" - kill -TERM $(pgrep -f "mwan3rtmon") > /dev/null 2>&1 - kill -TERM $(pgrep -f "mwan3track") > /dev/null 2>&1 + { + kill -TERM $(pgrep -f "mwan3rtmon") > /dev/null 2>&1 + kill -TERM $(pgrep -f "mwan3track") > /dev/null 2>&1 - sleep 1 - - kill -KILL $(pgrep -f "mwan3rtmon") > /dev/null 2>&1 - kill -KILL $(pgrep -f "mwan3track") > /dev/null 2>&1 + sleep 1 + kill -KILL $(pgrep -f "mwan3rtmon") > /dev/null 2>&1 + kill -KILL $(pgrep -f "mwan3track") > /dev/null 2>&1 + } & + kill_pid=$! config_load mwan3 config_foreach mwan3_track_clean interface - for IP in "$IP4" "$IP6"; do - [ "$IP" = "$IP6" ] && [ $NO_IPV6 -ne 0 ] && continue - for route in $(seq 1 $MWAN3_INTERFACE_MAX); do - $IP route flush table $route &> /dev/null + for family in ipv4 ipv6; do + if [ "$family" = "ipv4" ]; then + IPT="$IPT4" + IPTR="$IPT4R" + IP="$IP4" + elif [ "$family" = "ipv6" ]; then + [ $NO_IPV6 -ne 0 ] && continue + IPT="$IPT6" + IPTR="$IPT6R" + IP="$IP6" + fi + + for tid in $(ip route list table all | sed -ne 's/.*table \([0-9]\+\).*/\1/p'|sort -u); do + [ $tid -gt $MWAN3_INTERFACE_MAX ] && continue + $IP route flush table $tid &> /dev/null done for rule in $($IP rule list | egrep '^[1-2][0-9]{3}\:' | cut -d ':' -f 1); do $IP rule del pref $rule &> /dev/null done - done - - for IPT in "$IPT4" "$IPT6"; do - [ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue - $IPT -D PREROUTING -j mwan3_hook &> /dev/null - $IPT -D OUTPUT -j mwan3_hook &> /dev/null - - for table in $($IPT -S | awk '{print $2}' | grep mwan3 | sort -u); do - $IPT -F $table &> /dev/null - done - - for table in $($IPT -S | awk '{print $2}' | grep mwan3 | sort -u); do - $IPT -X $table &> /dev/null - done + table="$($IPT -S)" + { + echo "*mangle"; + [ -z "${table##*PREROUTING -j mwan3_hook*}" ] && echo "-D PREROUTING -j mwan3_hook" + [ -z "${table##*OUTPUT -j mwan3_hook*}" ] && echo "-D OUTPUT -j mwan3_hook" + echo "$table" | awk '{print "-F "$2}' | grep mwan3 | sort -u + echo "$table" | awk '{print "-X "$2}' | grep mwan3 | sort -u + echo "COMMIT" + } | $IPTR done for ipset in $($IPS -n list | grep mwan3_); do @@ -199,9 +232,19 @@ stop() $IPS -q destroy $ipset done + if ! pgrep -f "mwan3track" >/dev/null && ! pgrep -f "mwan3rtmon" >/dev/null; then + # mwan3track has already exited, no need to send + # TERM signal + kill $kill_pid 2>/dev/null + else + # mwan3track has not exited, wait for the killer + # to do its work + wait $kill_pid + fi + rm -rf $MWAN3_STATUS_DIR $MWAN3TRACK_STATUS_DIR + mwan3_unlock "command" "mwan3" - rm -rf $MWAN3_STATUS_DIR $MWAN3TRACK_STATUS_DIR } restart() { diff --git a/net/mwan3/files/usr/sbin/mwan3rtmon b/net/mwan3/files/usr/sbin/mwan3rtmon index 1075041bf..98a5c4b89 100755 --- a/net/mwan3/files/usr/sbin/mwan3rtmon +++ b/net/mwan3/files/usr/sbin/mwan3rtmon @@ -1,8 +1,9 @@ #!/bin/sh + . /lib/functions.sh . /lib/functions/network.sh . /lib/mwan3/mwan3.sh - +. /lib/mwan3/common.sh mwan3_rtmon_route_handle() { diff --git a/net/mwan3/files/usr/sbin/mwan3track b/net/mwan3/files/usr/sbin/mwan3track index a4ced8255..5cbf5f75d 100755 --- a/net/mwan3/files/usr/sbin/mwan3track +++ b/net/mwan3/files/usr/sbin/mwan3track @@ -3,60 +3,107 @@ . /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 @@ -70,64 +117,49 @@ main() { 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 @@ -139,16 +171,16 @@ main() { # 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/%//')" @@ -188,42 +220,40 @@ main() { 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 @@ -240,53 +270,50 @@ main() { 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 }