#!/bin/sh # shellcheck disable=SC1091,SC1090 # vim: set noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 : [ -n "$1" ] || exit . /lib/functions.sh # retrieve args OMR_TRACKER_INTERFACE="$1" shift # export vars export OMR_TRACKER_INTERFACE export OMR_TRACKER_HOST export OMR_TRACKER_TIMEOUT export OMR_TRACKER_STATUS export OMR_TRACKER_DEVICE export OMR_TRACKER_DEVICE_IP export OMR_TRACKER_DEVICE_GATEWAY dscp=56 # set DSCP CS7 (56) in outgoing packets initial_hosts="$OMR_TRACKER_HOSTS" initial_timeout="$OMR_TRACKER_TIMEOUT" # set constants for rto updating # we've changed the default values of the RFC to K=3 and beta=0.25 instead of K=4 and beta=0.125 # this allows us to lower the gap between rtt and rto when the latency increases quickly as our # measurements are less frequent than the standard timeout computation of the TCP stack _init_rto() { srtt= rttvar= rto_init=$(( initial_timeout * 1000 )) rto=$rto_init } # update rto as explained in rfc6298 # rto : retransmission timeout. # rtt : round trip time # rttvar : round trip time variance # srtt : smoothed round trip time # alpha : smoothing coeff for srtt # beta : smoothing coeff for rttvar # K : coeff to increase rttvar impact on rto computation _update_rto() { if [ -z "$srtt" ]; then srtt=$1 rttvar=$(($1 / 2)) else diff=$((srtt - $1)) rttvar=$(((75 * rttvar + 25 * (diff >= 0 ? diff : -diff)) / 100)) srtt=$(((75 * srtt + 25 * $1) / 100)) fi rto=$((tmp = srtt + 3 * rttvar, tmp > rto_init ? tmp : rto_init)) } _restart() { OMR_TRACKER_HOST="${OMR_TRACKER_HOSTS%% *}" [ "$OMR_TRACKER_HOST" = "$OMR_TRACKER_HOSTS" ] || { OMR_TRACKER_HOSTS="${OMR_TRACKER_HOSTS#* } $OMR_TRACKER_HOST" _init_rto } } _post_tracking() { for tracker_bin in /usr/share/omr/post-tracking.d/*; do [ -x "$tracker_bin" ] && ( _log() { logger -t "post-tracking-${tracker_bin##*/}" "$*" } . "$tracker_bin" ) done } _ping() { local host=$1 local deviceip=$2 local localip=$3 ret=$(ping "${host}" \ -I "${deviceip}" \ -W "$OMR_TRACKER_TIMEOUT" \ -c 1 \ -q ) && echo "$ret" | grep -sq "0% packet loss" && { if [ "$localip" = "yes" ]; then OMR_TRACKER_LATENCY=$(echo "$ret" | cut -d "/" -s -f4 | cut -d "." -f1) _update_rto "$OMR_TRACKER_LATENCY" fi return } false } _httping() { local host=$1 local deviceip=$2 local localip=$3 ret=$(httping "${host}" \ -y "${deviceip}" \ -t "$OMR_TRACKER_TIMEOUT" \ -c 1 \ -q ) && echo "$ret" | grep -sq "1 ok" && { if [ "$localip" = "yes" ]; then OMR_TRACKER_LATENCY=$(echo "$ret" | cut -d "/" -s -f5 | cut -d "." -f1) _update_rto "$OMR_TRACKER_LATENCY" fi return } false } _dns() { local host=$1 local deviceip=$2 ret=$(dig @"${host}" \ -b "${deviceip}" \ +time="$OMR_TRACKER_TIMEOUT" \ +tries=1 \ openmptcprouter.com ) && echo "$ret" | grep -sq "94.23.252.192" && { OMR_TRACKER_LATENCY=$(echo "$ret" | awk '/Query time/{print $4}') _update_rto "$OMR_TRACKER_LATENCY" return } false } _none() { return } _restart # main loop while true; do # setup tracker variables OMR_TRACKER_DEVICE_IP= OMR_TRACKER_STATUS="ERROR" OMR_TRACKER_STATUS_MSG="" OMR_TRACKER_LATENCY= OMR_TRACKER_TIMEOUT=$((rto / 1000 + (rto % 1000 ? 1 : 0))) if [ -d "/sys/class/net/$OMR_TRACKER_DEVICE" ]; then # retrieve iface ip and gateway OMR_TRACKER_DEVICE_IP=$(ip -4 -br addr ls dev "$OMR_TRACKER_DEVICE" | awk -F'[ /]+' '{print $3}') #OMR_TRACKER_DEVICE_IP=$(ubus call network.interface.$OMR_TRACKER_INTERFACE status | jsonfilter -e '@["ipv4-address"][0].address' | tr -d "\n") #if [ -z "$OMR_TRACKER_DEVICE_GATEWAY" ]; then # OMR_TRACKER_DEVICE_GATEWAY=$(ip -4 r list dev "$OMR_TRACKER_DEVICE" | grep -v default | awk '/proto static/ {print $1}' | tr -d "\n") #fi if [ -z "$OMR_TRACKER_DEVICE_GATEWAY" ]; then OMR_TRACKER_DEVICE_GATEWAY=$(uci -q get "network.$OMR_TRACKER_INTERFACE.gateway") fi if [ -z "$OMR_TRACKER_DEVICE_GATEWAY" ]; then OMR_TRACKER_DEVICE_GATEWAY=$(ubus call network.interface.$OMR_TRACKER_INTERFACE status | jsonfilter -q -e '@.route[0].nexthop' | tr -d "\n") fi if [ -z "$OMR_TRACKER_DEVICE_GATEWAY" ]; then OMR_TRACKER_DEVICE_GATEWAY=$(ubus call network.interface.$OMR_TRACKER_INTERFACE status | jsonfilter -q -e '@.inactive.route[0].nexthop' | tr -d "\n") fi if [ -z "$OMR_TRACKER_DEVICE_GATEWAY" ]; then OMR_TRACKER_DEVICE_GATEWAY=$(ubus call network.interface.${OMR_TRACKER_INTERFACE}_4 status 2>/dev/null | jsonfilter -q -e '@.inactive.route[0].nexthop' | tr -d "\n") fi # execute specific tracker if [ -n "$OMR_TRACKER_DEVICE_IP" ] && [ -n "$OMR_TRACKER_DEVICE_GATEWAY" ]; then _ping "$OMR_TRACKER_DEVICE_GATEWAY" "$OMR_TRACKER_DEVICE_IP" "no" status=$? if $(exit $status); then if [ "$OMR_TRACKER_TYPE" = "none" ]; then OMR_TRACKER_STATUS="OK" else # setup loop variable tries="$OMR_TRACKER_TRIES" # loop until tries attempts have been reached while [ "$tries" -gt 0 ]; do # Check if route is not used while ! ip route add $OMR_TRACKER_HOST via $OMR_TRACKER_DEVICE_GATEWAY dev $OMR_TRACKER_DEVICE src $OMR_TRACKER_DEVICE_IP > /dev/null 2&>1 do sleep 1 _restart done if [ "$OMR_TRACKER_TYPE" = "ping" ]; then _ping "$OMR_TRACKER_HOST" "$OMR_TRACKER_DEVICE_IP" "yes" status=$? elif [ "$OMR_TRACKER_TYPE" = "httping" ]; then _httping "$OMR_TRACKER_HOST" "$OMR_TRACKER_DEVICE_IP" "yes" status=$? elif [ "$OMR_TRACKER_TYPE" = "dns" ]; then _dns "$OMR_TRACKER_HOST" "$OMR_TRACKER_DEVICE_IP" "yes" status=$? fi ip route del "$OMR_TRACKER_HOST" via "$OMR_TRACKER_DEVICE_GATEWAY" dev "$OMR_TRACKER_DEVICE" src "$OMR_TRACKER_DEVICE_IP" > /dev/null 2&>1 if $(exit $status); then OMR_TRACKER_STATUS_MSG="" OMR_TRACKER_STATUS="OK" break else OMR_TRACKER_STATUS_MSG="$OMR_TRACKER_TYPE to $OMR_TRACKER_HOST from $OMR_TRACKER_DEVICE_IP error" fi tries=$((tries - 1)) OMR_TRACKER_TIMEOUT=$((OMR_TRACKER_TIMEOUT * 2)) sleep 1 _restart done fi else OMR_TRACKER_STATUS_MSG="gateway down" fi fi fi #[ "$OMR_TRACKER_HOSTS" = "$initial_hosts" ] || [ "$OMR_TRACKER_STATUS" = "OK" ] && _post_tracking #[ "$OMR_TRACKER_STATUS" = "ERROR" ] && _restart _post_tracking _restart sleep "$OMR_TRACKER_INTERVAL" done