#!/bin/sh . /lib/functions.sh . /lib/functions/network.sh . /lib/mwan3/mwan3.sh . /lib/mwan3/common.sh trap_with_arg() { func="$1" ; shift pid="$1" ; shift for sig ; do # shellcheck disable=SC2064 trap "$func $sig $pid" "$sig" done } func_trap() { kill -${1} ${2} 2>/dev/null } mwan3_add_all_routes() { local tid IP IPT route_line family active_tbls tid initial_state local ipv=$1 add_active_tbls() { let tid++ config_get family "$1" family ipv4 config_get initial_state "$1" initial_state "online" [ "$family" != "$ipv" ] && return if $IPT -S "mwan3_iface_in_$1" &> /dev/null; then active_tbls="$active_tbls${tid} " fi } add_route() { let tid++ [ -n "${active_tbls##* $tid *}" ] && return $IP route add table $tid $route_line || LOG warn "failed to add $route_line to table $tid" } mwan3_update_dev_to_table [ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && return if [ "$ipv" = "ipv4" ]; then IP="$IP4" IPT="$IPT4" elif [ "$ipv" = "ipv6" ]; then IP="$IP6" IPT="$IPT6" fi tid=0 active_tbls=" " config_foreach add_active_tbls interface [ $active_tbls = " " ] && return mwan3_get_routes | while read -r route_line; do mwan3_route_line_dev "tid" "$route_line" "$ipv" if [ -n "$tid" ] && [ -z "${active_tbls##* $tid *}" ]; then $IP route add table $tid $route_line elif [ -n "${route_line##default*}" ] && [ -n "${route_line##fe80::/64*}" ]; then config_foreach add_route interface fi done } mwan3_rtmon_route_handle() { local action route_line family tbl device line route_line_exp tid source_routing route_line=${1##"Deleted "} route_family=$2 config_get_bool source_routing globals source_routing 0 [ $source_routing -eq 0 ] && unset source_routing if [ "$route_line" = "$1" ]; then action="replace" route_line_exp="s/expires \([0-9]\+\)sec//;s/error [0-9]\+//; ${source_routing:+s/default\(.*\) from [^ ]*/default\1/}" $IPS -! add mwan3_connected_${route_family##ip} ${route_line%% *} else action="del" route_line_exp="s/expires [0-9]\+sec//;s/error [0-9]\+//; ${source_routing:+s/default\(.*\) from [^ ]*/default\1/}" mwan3_set_connected_${route_family} fi if [ "$route_family" = "ipv4" ]; then IP="$IP4" elif [ "$route_family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then IP="$IP6" route_line=$(echo "$route_line" | sed "$route_line_exp") else LOG warn "route update called with invalid family - $route_family" return fi # don't try to add routes when link has gone down if [ -z "${route_line##linkdown*}" ]; then LOG debug "not adding route due to linkdown - skipping $route_line" return fi handle_route() { local iface=$1 tbl=$($IP route list table $tid 2>/dev/null)$'\n' if [ -n "$iface" ] && [ "$(mwan3_get_mwan3track_status $iface)" != "active" ]; then LOG debug "interface $iface is disabled - skipping '$route_line'"; return fi # check that action needs to be performed. May not need to take action if we # got a delete event, but table was already flushed if [ $action = "del" ] && [ -n "${tbl##*$route_line$'\n'*}" ]; then LOG debug "skipping already deleted route table $tid - skipping '$route_line'" return fi network_get_device device "$iface" LOG debug "adjusting route $device: '$IP route $action table $tid $route_line'" $IP route "$action" table $tid $route_line || LOG warn "failed: '$IP route $action table $tid $route_line'" } handle_route_cb(){ local iface=$1 let tid++ config_get family "$iface" family ipv4 [ "$family" != "$route_family" ] && return handle_route "$iface" } mwan3_update_dev_to_table mwan3_route_line_dev "tid" "$route_line" "$route_family" if [ -n "$tid" ]; then handle_route elif [ -n "${route_line##default*}" ] && [ -n "${route_line##fe80::/64*}" ]; then config_foreach handle_route_cb interface fi } main() { local IP family config_load mwan3 family=$1 [ -z $family ] && family=ipv4 if [ "$family" = "ipv6" ]; then if [ $NO_IPV6 -ne 0 ]; then LOG warn "mwan3rtmon started for ipv6, but ipv6 not enabled on system" exit 1 fi IP="$IP6" else IP="$IP4" fi mwan3_init sh -c "echo \$\$; exec $IP monitor route" | { read -r monitor_pid trap_with_arg func_trap "$monitor_pid" SIGINT SIGTERM SIGKILL while IFS='' read -r line; do [ -z "${line##*table*}" ] && continue LOG debug "handling route update $family '$line'" mwan3_rtmon_route_handle "$line" "$family" done } & child=$! kill -SIGSTOP $child trap_with_arg func_trap "$child" SIGINT SIGTERM SIGKILL mwan3_set_connected_${family} mwan3_add_all_routes ${family} kill -SIGCONT $child wait $! } main "$@"