diff --git a/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 b/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 index 196b03257..320e7f787 100644 --- a/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 +++ b/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 @@ -9,6 +9,8 @@ SCRIPTNAME="mwan3-hotplug" [ "$ACTION" = "ifup" ] || [ "$ACTION" = "ifdown" ] || [ "$ACTION" = "connected" ] || [ "$ACTION" = "disconnected" ] || exit 1 [ -n "$INTERFACE" ] || exit 2 +[ "$FIRSTCONNECT" = "1" ] || [ "$MWAN3_SHUTDOWN" = "1" ] && exit 0 + if { [ "$ACTION" = "ifup" ] || [ "$ACTION" = "connected" ] ; } && [ -z "$DEVICE" ]; then LOG notice "$ACTION called on $INTERFACE with no device set" exit 3 @@ -17,10 +19,9 @@ fi [ "$MWAN3_STARTUP" = 1 ] || mwan3_lock "$ACTION" "$INTERFACE" config_load mwan3 -config_get_bool enabled globals 'enabled' '0' -[ "${enabled}" -gt 0 ] || { +/etc/init.d/mwan3 running || { [ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$INTERFACE" - LOG notice "mwan3 hotplug on $INTERFACE not called because globally disabled" + LOG notice "mwan3 hotplug $ACTION on $INTERFACE not called because globally disabled" mwan3_flush_conntrack "$INTERFACE" "$ACTION" exit 0 } @@ -41,7 +42,6 @@ if [ "$MWAN3_STARTUP" != 1 ] && [ "$ACTION" = "ifup" ]; 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_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$INTERFACE" @@ -49,53 +49,47 @@ config_get_bool enabled $INTERFACE 'enabled' '0' exit 0 } -trackpid=$(pgrep -f "mwan3track $INTERFACE ") - +config_get initial_state $INTERFACE initial_state "online" if [ "$initial_state" = "offline" ]; then status=$(cat $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS 2>/dev/null || echo unknown) + [ "$status" = "online" ] || status=offline else status=online fi -[ -z "$TRUE_INTERFACE" ] && mwan3_get_true_iface TRUE_INTERFACE $INTERFACE - -binary_status=$status -[ "$binary_status" = "online" ] || binary_status=offline +if [ "$ACTION" = ifup ] || [ "$ACTION" = ifdown ]; then + initscript=/etc/init.d/mwan3 + . /lib/functions/procd.sh +fi LOG notice "Execute $ACTION event on interface $INTERFACE (${DEVICE:-unknown})" case "$ACTION" in - ifup|connected) + connected) + mwan3_set_iface_hotplug_state $INTERFACE "online" + mwan3_set_policies_iptables + ;; + ifup) mwan3_create_iface_iptables $INTERFACE $DEVICE mwan3_create_iface_rules $INTERFACE $DEVICE - [ "$MWAN3_STARTUP" != 1 ] && mwan3_create_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 - mwan3_track $INTERFACE $DEVICE "$binary_status" "$src_ip" - LOG notice "Started tracker [$!] on interface $INTERFACE (${DEVICE:-unknown})" + mwan3_set_iface_hotplug_state $INTERFACE "$status" + if [ "$MWAN3_STARTUP" != 1 ]; then + mwan3_create_iface_route $INTERFACE $DEVICE + [ "$status" = "online" ] && mwan3_set_policies_iptables fi - [ "$MWAN3_STARTUP" != 1 ] && [ "$binary_status" == "online" ] && mwan3_set_policies_iptables - - ;; - ifdown|disconnected) + [ "$ACTION" = ifup ] && procd_running mwan3 "track_$INTERFACE" && procd_send_signal mwan3 "track_$INTERFACE" USR2 + ;; + disconnected) + mwan3_set_iface_hotplug_state $INTERFACE "offline" + mwan3_set_policies_iptables + ;; + ifdown) mwan3_set_iface_hotplug_state $INTERFACE "offline" mwan3_delete_iface_ipset_entries $INTERFACE 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 + procd_running mwan3 "track_$INTERFACE" && procd_send_signal mwan3 "track_$INTERFACE" USR1 mwan3_set_policies_iptables ;; esac 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 2ec5c79a3..698fe0909 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_STARTUP" = 1 ] || mwan3_lock "$ACTION" "$DEVICE-user" + [ "$MWAN3_SHUTDOWN" != 1 ] && mwan3_lock "$ACTION" "$DEVICE-user" - config_load mwan3 - config_get_bool enabled globals 'enabled' '0' - [ "${enabled}" -gt 0 ] || { - [ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$DEVICE-user" + [ "$MWAN3_SHUTDOWN" != 1 ] && ! /etc/init.d/mwan3 running && { + mwan3_unlock "$ACTION" "$DEVICE-user" exit 0 } + config_load mwan3 + config_get_bool enabled "$INTERFACE" enabled 0 [ "${enabled}" -eq 1 ] || { - [ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$DEVICE-user" + [ "$MWAN3_SHUTDOWN" != 1 ] && mwan3_unlock "$ACTION" "$DEVICE-user" exit 0 } - [ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$DEVICE-user" + [ "$MWAN3_SHUTDOWN" != 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 ba9d920cb..595fabf77 100755 --- a/net/mwan3/files/etc/init.d/mwan3 +++ b/net/mwan3/files/etc/init.d/mwan3 @@ -1,31 +1,114 @@ #!/bin/sh /etc/rc.common +. /lib/functions.sh +. /lib/mwan3/common.sh +. /lib/functions/network.sh +. /lib/mwan3/mwan3.sh + START=19 USE_PROCD=1 -boot() { - . /lib/config/uci.sh - # disabled until mwan3 start runs so hotplug scripts - # do not start prematurely - uci_toggle_state mwan3 globals enabled "0" - rc_procd start_service +service_running() { + [ -d "$MWAN3_STATUS_DIR" ] } -# FIXME -# fd 1000 is an inherited lock file descriptor for preventing concurrent -# init script executions. Close it here to prevent the mwan3 daemon from -# inheriting it further to avoid holding the lock indefinitely. +start_tracker() { + local enabled interface + interface=$1 + config_get_bool enabled $interface 'enabled' '0' + [ $enabled -eq 0 ] && return -reload_service() { - /usr/sbin/mwan3 restart 1000>&- + procd_open_instance "track_${1}" + procd_set_param command /usr/sbin/mwan3track $interface + procd_set_param respawn + procd_close_instance } start_service() { - /usr/sbin/mwan3 start 1000>&- + local enabled hotplug_pids + + config_load mwan3 + mwan3_init + config_foreach start_tracker interface + + mwan3_lock "command" "mwan3" + + mwan3_update_iface_to_table + mwan3_set_connected_ipset + mwan3_set_custom_ipset + mwan3_set_general_rules + mwan3_set_general_iptables + config_foreach mwan3_ifup interface 1 + wait $hotplug_pids + mwan3_set_policies_iptables + mwan3_set_user_rules + + mwan3_unlock "command" "mwan3" + + procd_open_instance rtmon_ipv4 + procd_set_param command /usr/sbin/mwan3rtmon ipv4 + procd_set_param respawn + procd_close_instance + + if command -v ip6tables > /dev/null; then + procd_open_instance rtmon_ipv6 + procd_set_param command /usr/sbin/mwan3rtmon ipv6 + procd_set_param respawn + procd_close_instance + fi } stop_service() { - /usr/sbin/mwan3 stop 1000>&- + local ipset rule IP IPTR IPT family table tid + + mwan3_lock "command" "mwan3" + + config_load mwan3 + mwan3_init + config_foreach mwan3_interface_shutdown interface + + 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 | grep -E '^[1-3][0-9]{3}\:' | cut -d ':' -f 1); do + $IP rule del pref $rule &> /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 + $IPS -q destroy $ipset + done + + for ipset in $($IPS -n list | grep mwan3 | grep -E '_v4|_v6'); do + $IPS -q destroy $ipset + done + + rm -rf $MWAN3_STATUS_DIR $MWAN3TRACK_STATUS_DIR + + mwan3_unlock "command" "mwan3" } service_triggers() { diff --git a/net/mwan3/files/lib/mwan3/common.sh b/net/mwan3/files/lib/mwan3/common.sh index 3b1560897..53557a6ef 100644 --- a/net/mwan3/files/lib/mwan3/common.sh +++ b/net/mwan3/files/lib/mwan3/common.sh @@ -5,8 +5,13 @@ get_uptime() { echo "${uptime%%.*}" } +IP4="ip -4" +IP6="ip -6" SCRIPTNAME="$(basename "$0")" MWAN3TRACK_STATUS_DIR="/var/run/mwan3track" + +MAX_SLEEP=$(((1<<31)-1)) + LOG() { local facility=$1; shift @@ -16,3 +21,132 @@ LOG() [ "$facility" = "debug" ] && return logger -t "${SCRIPTNAME}[$$]" -p $facility "$*" } +mwan3_get_src_ip() +{ + local family _src_ip true_iface device addr_cmd default_ip IP sed_str + true_iface=$2 + unset "$1" + config_get family "$true_iface" family ipv4 + if [ "$family" = "ipv4" ]; then + addr_cmd='network_get_ipaddr' + default_ip="0.0.0.0" + sed_str='s/ *inet \([^ \/]*\).*/\1/;T; pq' + IP="$IP4" + elif [ "$family" = "ipv6" ]; then + addr_cmd='network_get_ipaddr6' + default_ip="::" + sed_str='s/ *inet6 \([^ \/]*\).* scope.*/\1/;T; pq' + IP="$IP6" + fi + + $addr_cmd _src_ip "$true_iface" + if [ -z "$_src_ip" ]; then + network_get_device device $true_iface + _src_ip=$($IP address ls dev $device 2>/dev/null | sed -ne "$sed_str") + if [ -n "$_src_ip" ]; then + LOG warn "no src $family address found from netifd for interface '$true_iface' dev '$device' guessing $_src_ip" + else + _src_ip="$default_ip" + LOG warn "no src $family address found for interface '$true_iface' dev '$device'" + fi + fi + export "$1=$_src_ip" +} + +mwan3_get_mwan3track_status() +{ + local track_ips pid + mwan3_list_track_ips() + { + track_ips="$1 $track_ips" + } + config_list_foreach "$1" track_ip mwan3_list_track_ips + + if [ -n "$track_ips" ]; then + pid="$(pgrep -f "mwan3track $1$")" + if [ -n "$pid" ]; then + if [ "$(cat /proc/"$(pgrep -P $pid)"/cmdline)" = "sleep${MAX_SLEEP}" ]; then + tracking="paused" + else + tracking="active" + fi + else + tracking="down" + fi + else + tracking="not enabled" + fi + echo "$tracking" +} + +mwan3_init() +{ + local bitcnt + local mmdefault + + [ -d $MWAN3_STATUS_DIR ] || mkdir -p $MWAN3_STATUS_DIR/iface_state + + # mwan3's MARKing mask (at least 3 bits should be set) + if [ -e "${MWAN3_STATUS_DIR}/mmx_mask" ]; then + MMX_MASK=$(cat "${MWAN3_STATUS_DIR}/mmx_mask") + MWAN3_INTERFACE_MAX=$(uci_get_state mwan3 globals iface_max) + else + config_load mwan3 + config_get MMX_MASK globals mmx_mask '0x3F00' + echo "$MMX_MASK"| tr 'A-F' 'a-f' > "${MWAN3_STATUS_DIR}/mmx_mask" + LOG debug "Using firewall mask ${MMX_MASK}" + + bitcnt=$(mwan3_count_one_bits MMX_MASK) + mmdefault=$(((1<>bit_msk)&1)) = "1" ]; then + if [ $((($1>>bit_val)&1)) = "1" ]; then + result=$((result|(1<>>>>>> 2a4e0dc6d... review comments diff --git a/net/mwan3/files/lib/mwan3/mwan3.sh b/net/mwan3/files/lib/mwan3/mwan3.sh index 111fea067..dad2f4994 100644 --- a/net/mwan3/files/lib/mwan3/mwan3.sh +++ b/net/mwan3/files/lib/mwan3/mwan3.sh @@ -2,8 +2,6 @@ . /usr/share/libubox/jshn.sh -IP4="ip -4" -IP6="ip -6" IPS="ipset" IPT4="iptables -t mangle -w" IPT6="ip6tables -t mangle -w" @@ -42,8 +40,7 @@ mwan3_push_update() # helper function to build an update string to pass on to # IPTR or IPS RESTORE. Modifies the 'update' variable in # the local scope. - update="$update -$*"; + update="$update"$'\n'"$*"; } mwan3_update_dev_to_table() @@ -198,22 +195,6 @@ mwan3_unlock() { lock -u /var/run/mwan3.lock } -mwan3_get_src_ip() -{ - local family _src_ip true_iface - true_iface=$2 - unset "$1" - config_get family "$true_iface" family ipv4 - if [ "$family" = "ipv4" ]; then - network_get_ipaddr _src_ip "$true_iface" - [ -n "$_src_ip" ] || _src_ip="0.0.0.0" - elif [ "$family" = "ipv6" ]; then - network_get_ipaddr6 _src_ip "$true_iface" - [ -n "$_src_ip" ] || _src_ip="::" - fi - export "$1=$_src_ip" -} - mwan3_get_iface_id() { local _tmp @@ -643,39 +624,6 @@ mwan3_delete_iface_ipset_entries() done } -mwan3_rtmon() -{ - local protocol - for protocol in "ipv4" "ipv6"; do - pid="$(pgrep -f "mwan3rtmon $protocol")" - [ "$protocol" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue - if [ "${pid}" = "" ]; then - [ -x /usr/sbin/mwan3rtmon ] && /usr/sbin/mwan3rtmon $protocol & - fi - done -} - -mwan3_track() -{ - local track_ips pids - - mwan3_list_track_ips() - { - track_ips="$track_ips $1" - } - config_list_foreach "$1" track_ip mwan3_list_track_ips - - # don't match device in case it changed from last launch - if pids=$(pgrep -f "mwan3track $1 "); then - kill -TERM $pids > /dev/null 2>&1 - sleep 1 - kill -KILL $(pgrep -f "mwan3track $1 ") > /dev/null 2>&1 - fi - - if [ -n "$track_ips" ]; then - [ -x /usr/sbin/mwan3track ] && MWAN3_STARTUP=0 /usr/sbin/mwan3track "$1" "$2" "$3" "$4" $track_ips & - fi -} mwan3_set_policy() { @@ -1066,6 +1014,83 @@ mwan3_set_user_rules() } +mwan3_interface_hotplug_shutdown() +{ + local interface status device ifdown + interface="$1" + ifdown="$2" + [ -f $MWAN3TRACK_STATUS_DIR/$interface/STATUS ] && { + status=$(cat $MWAN3TRACK_STATUS_DIR/$interface/STATUS) + } + + [ "$status" != "online" ] && [ "$ifdown" != 1 ] && return + + if [ "$ifdown" = 1 ]; then + env -i ACTION=ifdown \ + INTERFACE=$interface \ + DEVICE=$device \ + sh /etc/hotplug.d/iface/15-mwan3 + else + [ "$status" = "online" ] && { + env -i MWAN3_SHUTDOWN="1" \ + ACTION="disconnected" \ + INTERFACE="$interface" \ + DEVICE="$device" /sbin/hotplug-call iface + } + fi + +} + +mwan3_interface_shutdown() +{ + mwan3_interface_hotplug_shutdown $1 + mwan3_track_clean $1 +} + +mwan3_ifup() +{ + local up l3_device status interface true_iface mwan3_startup + + interface=$1 + mwan3_startup=$2 + + if [ "${mwan3_startup}" != 1 ]; then + # It is not necessary to obtain a lock here, because it is obtained in the hotplug + # script, but we still want to do the check to print a useful error message + /etc/init.d/mwan3 running || { + echo 'The service mwan3 is global disabled.' + echo 'Please execute "/etc/init.d/mwan3 start" first.' + exit 1 + } + config_load mwan3 + fi + mwan3_get_true_iface true_iface $interface + status=$(ubus -S call network.interface.$true_iface status) + + [ -n "$status" ] && { + json_load "$status" + json_get_vars up l3_device + } + hotplug_startup() + { + env -i MWAN3_STARTUP=$mwan3_startup ACTION=ifup \ + INTERFACE=$interface DEVICE=$l3_device \ + sh /etc/hotplug.d/iface/15-mwan3 + } + + if [ "$up" != "1" ] || [ -z "$l3_device" ]; then + return + fi + + if [ "${mwan3_startup}" = 1 ]; then + hotplug_startup & + hotplug_pids="$hotplug_pids $!" + else + hotplug_startup + fi + +} + mwan3_set_iface_hotplug_state() { local iface=$1 local state=$2 @@ -1081,7 +1106,7 @@ mwan3_get_iface_hotplug_state() { mwan3_report_iface_status() { - local device result track_ips tracking IP IPT + local device result tracking IP IPT mwan3_get_iface_id id "$1" network_get_device device "$1" @@ -1129,22 +1154,7 @@ mwan3_report_iface_status() result="disabled" fi - mwan3_list_track_ips() - { - track_ips="$1 $track_ips" - } - config_list_foreach "$1" track_ip mwan3_list_track_ips - - if [ -n "$track_ips" ]; then - if [ -n "$(pgrep -f "mwan3track $1 $device")" ]; then - tracking="active" - else - tracking="down" - fi - else - tracking="not enabled" - fi - + tracking="$(mwan3_get_mwan3track_status $1)" echo " interface $1 is $result and tracking is $tracking" } diff --git a/net/mwan3/files/usr/libexec/rpcd/mwan3 b/net/mwan3/files/usr/libexec/rpcd/mwan3 index 33e3e0284..76f557e9f 100755 --- a/net/mwan3/files/usr/libexec/rpcd/mwan3 +++ b/net/mwan3/files/usr/libexec/rpcd/mwan3 @@ -77,16 +77,13 @@ get_mwan3_status() { local online=0 local offline=0 local up="0" - local enabled pid device time_p time_n time_u time_d status + local enabled device time_p time_n time_u time_d status track_status network_get_device device $1 if [ "${iface}" = "${iface_select}" ] || [ "${iface_select}" = "" ]; then - pid="$(pgrep -f "mwan3track $iface $device")" - if [ "${pid}" != "" ]; then - running="1" - fi - + track_status="$(mwan3_get_mwan3track_status "$1")" + [ "$track_status" = "active" ] && running="1" time_p="$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/TIME")" [ -z "${time_p}" ] || { time_n="$(get_uptime)" diff --git a/net/mwan3/files/usr/sbin/mwan3 b/net/mwan3/files/usr/sbin/mwan3 index 5928172d9..cbd79e9ea 100755 --- a/net/mwan3/files/usr/sbin/mwan3 +++ b/net/mwan3/files/usr/sbin/mwan3 @@ -26,25 +26,23 @@ Available commands: EOF } -ifdown() -{ + +ifdown() { if [ -z "$1" ]; then - echo "Error: Expecting interface. Usage: mwan3 ifdown " && exit 0 + echo "Error: Expecting interface. Usage: mwan3 ifdown " + exit 0 fi if [ -n "$2" ]; then - echo "Error: Too many arguments. Usage: mwan3 ifdown " && exit 0 + echo "Error: Too many arguments. Usage: mwan3 ifdown " + exit 0 fi - ACTION=ifdown INTERFACE=$1 /sbin/hotplug-call iface - - kill $(pgrep -f "mwan3track $1 ") &> /dev/null - mwan3_track_clean $1 + mwan3_interface_hotplug_shutdown "$1" 1 } -ifup() -{ - local enabled up l3_device status interface true_iface +ifup() { + . /etc/init.d/mwan3 if [ -z "$1" ]; then echo "Expecting interface. Usage: mwan3 ifup " @@ -56,46 +54,7 @@ ifup() exit 0 fi - 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) - - [ -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 [ "${MWAN3_STARTUP}" = 1 ]; then - hotplug_startup & - hotplug_pids="$hotplug_pids $!" - else - hotplug_startup - fi - + mwan3_ifup "$1" } interfaces() @@ -148,108 +107,20 @@ status() rules } -start() -{ - local enabled hotplug_pids MWAN3_STARTUP - MWAN3_STARTUP=1 - mwan3_lock "command" "mwan3" - uci_toggle_state mwan3 globals enabled "1" - 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_routes - mwan3_set_policies_iptables - mwan3_set_user_rules - - - mwan3_unlock "command" "mwan3" - mwan3_rtmon - unset MWAN3_STARTUP +start() { + /etc/init.d/mwan3 enable + /etc/init.d/mwan3 start } -stop() -{ - 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 - - 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 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 | grep -E '^[1-3][0-9]{3}\:' | cut -d ':' -f 1); do - $IP rule del pref $rule &> /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 - $IPS -q destroy $ipset - done - - for ipset in $($IPS -n list | grep mwan3 | grep -E '_v4|_v6'); do - $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" - +stop() { + /etc/init.d/mwan3 disable + /etc/init.d/mwan3 stop } restart() { - stop - start + /etc/init.d/mwan3 enable + /etc/init.d/mwan3 stop + /etc/init.d/mwan3 start } case "$1" in diff --git a/net/mwan3/files/usr/sbin/mwan3rtmon b/net/mwan3/files/usr/sbin/mwan3rtmon index ff7183ae2..ee470837e 100755 --- a/net/mwan3/files/usr/sbin/mwan3rtmon +++ b/net/mwan3/files/usr/sbin/mwan3rtmon @@ -31,7 +31,7 @@ mwan3_add_all_routes() config_get family "$1" family ipv4 config_get initial_state "$1" initial_state "online" [ "$family" != "$ipv" ] && return - if [ "$initial_state" = "online" ] && $IPT -S "mwan3_iface_in_$1" &> /dev/null; then + if $IPT -S "mwan3_iface_in_$1" &> /dev/null; then active_tbls="$active_tbls${tid} " fi } diff --git a/net/mwan3/files/usr/sbin/mwan3track b/net/mwan3/files/usr/sbin/mwan3track index 863eb76ff..32b741ee2 100755 --- a/net/mwan3/files/usr/sbin/mwan3track +++ b/net/mwan3/files/usr/sbin/mwan3track @@ -1,6 +1,7 @@ #!/bin/sh . /lib/functions.sh +. /lib/functions/network.sh . /lib/mwan3/common.sh INTERFACE="" @@ -9,20 +10,33 @@ PING="/bin/ping" IFDOWN_EVENT=0 IFUP_EVENT=0 +TRACK_OUTPUT=$MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_OUTPUT + +mwan3_init + +stop_subprocs() { + [ -n "$SLEEP_PID" ] && kill "$SLEEP_PID" && unset SLEEP_PID + [ -n "$TRACK_PID" ] && kill "$TRACK_PID" && unset TRACK_PID +} clean_up() { - LOG notice "Stopping mwan3track for interface \"${INTERFACE}\"" + LOG notice "Stopping mwan3track for interface \"${INTERFACE}\". Status was \"${STATUS}\"" + stop_subprocs exit 0 } if_down() { LOG info "Detect ifdown event on interface ${INTERFACE} (${DEVICE})" IFDOWN_EVENT=1 + stop_subprocs } if_up() { LOG info "Detect ifup event on interface ${INTERFACE} (${DEVICE})" + IFDOWN_EVENT=0 IFUP_EVENT=1 + STARTED=1 + stop_subprocs } validate_track_method() { @@ -63,9 +77,10 @@ validate_track_method() { } disconnected() { - echo "offline" > /var/run/mwan3track/$INTERFACE/STATUS - get_uptime > /var/run/mwan3track/$INTERFACE/OFFLINE - echo "0" > /var/run/mwan3track/$INTERFACE/ONLINE + STATUS='offline' + echo "offline" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS + get_uptime > $MWAN3TRACK_STATUS_DIR/$INTERFACE/OFFLINE + echo "0" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/ONLINE score=0 [ "$1" = 1 ] && return LOG notice "Interface $INTERFACE ($DEVICE) is offline" @@ -73,6 +88,7 @@ disconnected() { } connected() { + STATUS='online' echo "online" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS echo "0" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/OFFLINE get_uptime > $MWAN3TRACK_STATUS_DIR/$INTERFACE/ONLINE @@ -80,12 +96,48 @@ connected() { 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 + env -i FIRSTCONNECT=$1 ACTION="connected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface +} + +disabled() { + STATUS='disabled' + echo "disabled" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS + STARTED=0 } firstconnect() { + local true_iface + network_flush_cache + + mwan3_get_true_iface true_iface $INTERFACE + network_get_device DEVICE $true_iface + + if [ "$STATUS" != "online" ]; then + config_get STATUS $INTERFACE initial_state "online" + fi + + if ! network_is_up $true_iface || [ -z "$DEVICE" ]; then + disabled + return + fi + + mwan3_get_src_ip SRC_IP $true_iface + + # pinging IPv6 hosts with an interface is troublesome + # https://bugs.openwrt.org/index.php?do=details&task_id=2897 + # https://bugs.openwrt.org/index.php?do=details&task_id=2167 + # https://forum.openwrt.org/t/ping-and-traceroute-failing-for-eth0-3-on-ipv6/44680/11 + # so use the IP address of the interface + if [ "$family" = "ipv6" ]; then + SOURCE="$SRC_IP" + else + SOURCE="$DEVICE" + fi + + LOG debug "firstconnect: called on $INTERFACE/$true_iface ($DEVICE). Status is $STATUS. SRC_IP is $SRC_IP" + + STARTED=1 if [ "$STATUS" = "offline" ]; then disconnected 1 else @@ -107,15 +159,13 @@ main() { local recovery_interval down up size local keep_failure_interval check_quality failure_latency local recovery_latency failure_loss recovery_loss - local max_ttl httping_ssl - - [ -z "$5" ] && echo "Error: should not be started manually" && exit 0 + local max_ttl httping_ssl family track_ips INTERFACE=$1 - DEVICE=$2 - STATUS=$3 - SRC_IP=$4 - mkdir -p /var/run/mwan3track/$INTERFACE + STATUS="" + STARTED=0 + mkdir -p $MWAN3TRACK_STATUS_DIR/$INTERFACE + trap clean_up TERM trap if_down USR1 trap if_up USR2 @@ -148,20 +198,23 @@ main() { 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 sleep_time result ping_status loss latency + mwan3_list_track_ips() + { + track_ips="$track_ips $1" + } + config_list_foreach "$1" track_ip mwan3_list_track_ips local score=$((down+up)) - local track_ips=$(echo $* | cut -d ' ' -f 5-99) local host_up_count=0 local lost=0 local turn=0 - local ping_protocol=4 - local sleep_time result ping_result ping_result_raw ping_status loss latency firstconnect while true; do - + [ $STARTED -eq 0 ] && { sleep $MAX_SLEEP & SLEEP_PID=$!; wait; } + unset SLEEP_PID sleep_time=$interval - for track_ip in $track_ips; do if [ $host_up_count -lt $reliability ]; then case "$track_method" in @@ -169,50 +222,47 @@ 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 [ -z ${track_ip##*:*} ]; then - ping_protocol=6 - else - unset SRC_IP - fi + if [ $check_quality -eq 0 ]; then - $PING -$ping_protocol -I ${SRC_IP:-$DEVICE} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip &> /dev/null + $PING -${family#ipv} -I ${SOURCE} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip &> /dev/null & + TRACK_PID=$! + wait $TRACK_PID result=$? else - 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 -${family#ipv} -I ${SOURCE} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip 2>/dev/null > $TRACK_OUTPUT & + TRACK_PID=$! + wait $TRACK_PID 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/%//')" + loss=$(grep $TRACK_OUTPUT "packet loss" | cut -d "," -f3 | awk '{print $1}' | sed -e 's/%//') if [ "$ping_status" -ne 0 ] || [ "$loss" -eq 100 ]; then latency=999999 loss=100 else - latency="$(echo "$ping_result" | grep -E 'rtt|round-trip' | cut -d "=" -f2 | cut -d "/" -f2 | cut -d "." -f1)" + latency="$(grep $TRACK_OUTPUT -E 'rtt|round-trip' | cut -d "=" -f2 | cut -d "/" -f2 | cut -d "." -f1)" fi fi ;; arping) - arping -I $DEVICE -c $count -w $timeout -q $track_ip &> /dev/null + arping -I $DEVICE -c $count -w $timeout -q $track_ip &> /dev/null & + TRACK_PID=$! + wait $TRACK_PID result=$? ;; httping) if [ "$httping_ssl" -eq 1 ]; then - httping -y $SRC_IP -c $count -t $timeout -q "https://$track_ip" &> /dev/null + httping -y $SRC_IP -c $count -t $timeout -q "https://$track_ip" &> /dev/null & else - httping -y $SRC_IP -c $count -t $timeout -q "http://$track_ip" &> /dev/null + httping -y $SRC_IP -c $count -t $timeout -q "http://$track_ip" &> /dev/null & fi + TRACK_PID=$! + wait $TRACK_PID result=$? ;; - nping-tcp) - result=$(nping -e $DEVICE -c $count $track_ip --tcp | grep Lost | awk '{print $12}') - ;; - nping-udp) - result=$(nping -e $DEVICE -c $count $track_ip --udp | grep Lost | awk '{print $12}') - ;; - nping-icmp) - result=$(nping -e $DEVICE -c $count $track_ip --icmp | grep Lost | awk '{print $12}') - ;; - nping-arp) - result=$(nping -e $DEVICE -c $count $track_ip --arp | grep Lost | awk '{print $12}') + nping-*) + nping -c $count $track_ip --${FAMILY#nping-} > $TRACK_OUTPUT & + TRACK_PID=$! + wait $TRACK_PID + result=$(grep $TRACK_OUTPUT Lost | awk '{print $12}') ;; esac if [ $check_quality -eq 0 ]; then @@ -247,11 +297,11 @@ main() { 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/$INTERFACE/TRACK_${track_ip} + echo "skipped" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_${track_ip} fi fi else - echo "skipped" > /var/run/mwan3track/$INTERFACE/TRACK_${track_ip} + echo "skipped" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_${track_ip} fi done @@ -287,7 +337,7 @@ main() { fi if [ $score -eq $up ]; then - connected $INTERFACE $DEVICE + connected fi fi @@ -304,7 +354,8 @@ main() { if [ "${IFDOWN_EVENT}" -eq 1 ]; then LOG debug "Register ifdown event on interface ${INTERFACE} (${DEVICE})" - disconnected 1 + disabled + disconnected IFDOWN_EVENT=0 fi if [ "${IFUP_EVENT}" -eq 1 ]; then