|
|
- #!/bin/sh
-
- . /lib/functions.sh
- . /lib/functions/network.sh
- . /lib/mwan3/common.sh
-
- INTERFACE=""
- DEVICE=""
-
- IFDOWN_EVENT=0
- IFUP_EVENT=0
-
- stop_subprocs() {
- [ -n "$SLEEP_PID" ] && kill "$SLEEP_PID" && unset SLEEP_PID
- [ -n "$TRACK_PID" ] && kill "$TRACK_PID" && unset TRACK_PID
- }
-
- WRAP() {
- # shellcheck disable=SC2048
- FAMILY=$FAMILY DEVICE=$DEVICE SRCIP=$SRC_IP FWMARK=$MMX_DEFAULT LD_PRELOAD=/lib/mwan3/libwrap_mwan3_sockopt.so.1.0 $*
- }
-
- clean_up() {
- 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
- }
-
- ping_test_host() {
- if [ "$FAMILY" = "ipv6" ]; then
- echo "::1"
- else
- echo "127.0.0.1"
- fi
- }
-
- get_ping_command() {
- if [ -x "/usr/bin/ping" ] && /usr/bin/ping -${FAMILY#ipv} -c1 -q $(ping_test_host) &>/dev/null; then
- # -4 option added in iputils c3e68ac6 so need to check if we can use it
- # or if we must use ping and ping6
- echo "/usr/bin/ping -${FAMILY#ipv}"
- elif [ "$FAMILY" = "ipv6" ] && [ -x "/usr/bin/ping6" ]; then
- echo "/usr/bin/ping6"
- elif [ "$FAMILY" = "ipv4" ] && [ -x "/usr/bin/ping" ]; then
- echo "/usr/bin/ping"
- elif [ -x "/bin/ping" ]; then
- echo "/bin/ping -${FAMILY#ipv}"
- else
- return 1
- fi
- }
-
- validate_track_method() {
- case "$1" in
- ping)
- PING=$(get_ping_command)
- if [ $? -ne 0 ]; then
- LOG warn "Missing ping. Please enable BUSYBOX_DEFAULT_PING and recompile busybox or install iputils-ping package."
- return 1
- fi
- ;;
- arping)
- command -v arping 1>/dev/null 2>&1 || {
- 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."
- return 1
- }
- ;;
- nping-*)
- command -v nping 1>/dev/null 2>&1 || {
- LOG warn "Missing nping. Please install nping package."
- return 1
- }
- ;;
- *)
- LOG warn "Unsupported tracking method: $track_method"
- return 2
- ;;
- esac
- }
-
- validate_wrap() {
- [ -x /lib/mwan3/libwrap_mwan3_sockopt.so.1.0 ] && return
- LOG error "Missing libwrap_mwan3_sockopt. Please reinstall mwan3." &&
- exit 1
- }
-
- disconnected() {
- 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"
- env -i ACTION="disconnected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface
- }
-
- connected() {
- STATUS='online'
- echo "online" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS
- echo "0" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/OFFLINE
- get_uptime > $MWAN3TRACK_STATUS_DIR/$INTERFACE/ONLINE
- host_up_count=0
- lost=0
- turn=0
- loss=0
- LOG notice "Interface $INTERFACE ($DEVICE) is online"
- 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 $INTERFACE
-
- 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
- connected 1
- fi
- }
-
- update_status() {
- local track_ip=$1
-
- echo "$2" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_${track_ip}
- [ -z "$3" ] && return
- echo "$3" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/LATENCY_${track_ip}
- echo "$4" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/LOSS_${track_ip}
- }
-
- main() {
- local reliability count timeout interval failure_interval
- 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 track_ips do_log
-
- INTERFACE=$1
- STATUS=""
- STARTED=0
- TRACK_OUTPUT=$MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_OUTPUT
-
- mwan3_init
-
- mkdir -p $MWAN3TRACK_STATUS_DIR/$INTERFACE
-
- trap clean_up TERM
- trap if_down USR1
- trap if_up USR2
-
- config_load mwan3
- config_get FAMILY $INTERFACE family ipv4
- config_get track_method $INTERFACE track_method ping
- config_get_bool httping_ssl $INTERFACE httping_ssl 0
- validate_track_method $track_method || {
- track_method=ping
- if validate_track_method $track_method; then
- LOG warn "Using ping to track interface $INTERFACE avaliability"
- else
- LOG err "No track method avaliable"
- exit 1
- fi
- }
- 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 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 host_up_count=0
- local lost=0
- local turn=0
-
- 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
- ping)
- if [ $check_quality -eq 0 ]; then
- WRAP $PING -c $count -W $timeout -s $size -t $max_ttl -q $track_ip &> /dev/null &
- TRACK_PID=$!
- wait $TRACK_PID
- result=$?
- else
- WRAP $PING -c $count -W $timeout -s $size -t $max_ttl -q $track_ip 2>/dev/null > $TRACK_OUTPUT &
- TRACK_PID=$!
- wait $TRACK_PID
- ping_status=$?
- loss="$(sed $TRACK_OUTPUT -ne 's/.*\([0-9]\+\)% packet loss.*/\1/p')"
- if [ "$ping_status" -ne 0 ] || [ "$loss" -eq 100 ]; then
- latency=999999
- loss=100
- else
- latency="$(sed $TRACK_OUTPUT -ne 's%\(rtt\|round-trip\).* = [^/]*/\([0-9]\+\).*%\2%p')"
- fi
- fi
- ;;
- arping)
- WRAP 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
- WRAP httping -c $count -t $timeout -q "https://$track_ip" &> /dev/null &
- else
- WRAP httping -c $count -t $timeout -q "http://$track_ip" &> /dev/null &
- fi
- TRACK_PID=$!
- wait $TRACK_PID
- result=$?
- ;;
- nping-*)
- WRAP nping -c $count $track_ip --${FAMILY#nping-} > $TRACK_OUTPUT &
- TRACK_PID=$!
- wait $TRACK_PID
- result=$(grep $TRACK_OUTPUT Lost | awk '{print $12}')
- ;;
- esac
- do_log=""
- if [ $check_quality -eq 0 ]; then
- if [ $result -eq 0 ]; then
- let host_up_count++
- update_status "$track_ip" "up"
-
- [ $score -le $up ] && do_log="success"
- else
- let lost++
- update_status "$track_ip" "down"
-
- [ $score -gt $up ] && do_log="failed"
- fi
- [ -n "$do_log" ] && LOG info "Check ($track_method) ${do_log} for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
-
- else
- if [ "$loss" -ge "$failure_loss" ] || [ "$latency" -ge "$failure_latency" ]; then
- let lost++
- update_status "$track_ip" "down" $latency $loss
-
- [ $score -gt $up ] && do_log="failed"
- elif [ "$loss" -le "$recovery_loss" ] && [ "$latency" -le "$recovery_latency" ]; then
- let host_up_count++
- update_status "$track_ip" "up" $latency $loss
-
- [ $score -le $up ] && do_log="success"
- else
- echo "skipped" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_${track_ip}
- fi
- [ -n "$do_log" ] && LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) ${do_log} for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
- fi
- else
- echo "skipped" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_${track_ip}
- fi
- done
-
- if [ $host_up_count -lt $reliability ]; then
- let score--
-
- if [ $score -lt $up ]; then
- score=0
- [ ${keep_failure_interval} -eq 1 ] && sleep_time=$failure_interval
- else
- sleep_time=$failure_interval
- fi
-
- if [ $score -eq $up ]; then
- disconnected
- score=0
- fi
- else
- if [ $score -lt $((down+up)) ] && [ $lost -gt 0 ]; then
- 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" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS
- score=$((down+up))
- elif [ $score -le $up ]; then
- sleep_time=$recovery_interval
- fi
-
- if [ $score -eq $up ]; then
- connected
- fi
- fi
-
- let turn++
- mkdir -p "$MWAN3TRACK_STATUS_DIR/${1}"
- echo "${lost}" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/LOST
- echo "${score}" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/SCORE
- echo "${turn}" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TURN
- get_uptime > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TIME
-
- host_up_count=0
- if [ "${IFDOWN_EVENT}" -eq 0 ] && [ "${IFUP_EVENT}" -eq 0 ]; then
- sleep "${sleep_time}" &
- SLEEP_PID=$!
- wait
- unset SLEEP_PID
- fi
-
- if [ "${IFDOWN_EVENT}" -eq 1 ]; then
- LOG debug "Register ifdown event on interface ${INTERFACE} (${DEVICE})"
- disabled
- disconnected
- 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
- }
-
- main "$@"
|