#!/usr/bin/env bash # Title : isp-switch # Last modified date : 30.05.2023 # Author : Martin Tonusoo # Description : Script pings anycast DNS servers IPv4 addresses # using a primary connection(wan0; Telia fiber) and # if none of those replies, then switches v4 default # route to backup connection(wwan0; Telia mobile # broadband). Once the primary connection restores, # the v4 default route is switched back to primary # connection. # Options : # Notes : "ignore_routes_with_linkdown" settings in # /etc/sysctl.conf ensure that the route is # instantly ignored if its link is down. ping_check() { ping_success=0 for ip in 1.1.1.1 8.8.8.8 9.9.9.9; do # Even if one ping out of four succeeds, then # the exit code is 0. ping -I "$1" -W 1 -c 4 -q "$ip" &>/dev/null ping_success=$(( ping_success + $? )) done if (( ping_success >= 3 )); then # All 12 pings failed. return 1 else return 0 fi } read -r ip_regex << EOF ^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)\.){3}\ (25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)$ EOF while true; do sleep 1 read -r _ _ wan0_gw _ wan0_metric _ <<-EOF $(ip -4 -o route show default dev wan0 2>/dev/null | grep -v " linkdown") EOF read -r _ _ wwan0_gw _ wwan0_metric _ <<-EOF $(ip -4 -o route show default dev wwan0 2>/dev/null | grep -v " linkdown") EOF # There is no point to proceed if both or one of the default # routes is missing. In addition, sanity check the next hop # address. if ! { [[ "$wan0_gw" =~ $ip_regex ]] || [[ "$wwan0_gw" =~ $ip_regex ]]; }; then echo "No default route found." continue elif ! [[ "$wan0_gw" =~ $ip_regex ]]; then echo "Primary default route via wan0 is missing." continue elif ! [[ "$wwan0_gw" =~ $ip_regex ]]; then echo "Failover default route via wwan0 is missing." continue fi # Default IPv4 route metric is 0. if (( ${wan0_metric:-0} < ${wwan0_metric:-0} )); then if ! ping_check wan0; then # Ping check on primary connection failed. echo "Switching to backup via $wwan0_gw dev wwan0" ip -4 route flush default ip -4 route add default via "$wwan0_gw" dev wwan0 metric 100 ip -4 route add default via "$wan0_gw" dev wan0 metric 200 fi else # Backup connection is in use. Check if it is possible # to switch back to primary connection. ip -4 route add default via "$wan0_gw" table 100 # Specifying the "priority" ensures that there are # no duplicate rules created. ip rule add oif wan0 lookup 100 priority 100 if ping_check wan0; then # Ping check on primary connection succeeded. echo "Switching to primary via $wan0_gw dev wan0" ip -4 route flush default ip -4 route add default via "$wan0_gw" dev wan0 metric 100 ip -4 route add default via "$wwan0_gw" dev wwan0 metric 200 fi ip -4 route flush table 100 ip rule delete oif wan0 lookup 100 priority 100 fi done