From b7e26dd431a35a28b64c82ad3bde1fd996af6d39 Mon Sep 17 00:00:00 2001 From: Aaron Goodman Date: Mon, 31 Aug 2020 19:15:09 -0400 Subject: [PATCH 01/12] mwan3: fixup some extra spaces and shellcheck warnings Signed-off-by: Aaron Goodman --- net/mwan3/files/etc/hotplug.d/iface/15-mwan3 | 6 +- net/mwan3/files/lib/mwan3/common.sh | 2 +- net/mwan3/files/lib/mwan3/mwan3.sh | 112 ++++++++++--------- net/mwan3/files/usr/sbin/mwan3 | 21 ++-- net/mwan3/files/usr/sbin/mwan3rtmon | 9 +- net/mwan3/files/usr/sbin/mwan3track | 34 +++--- 6 files changed, 92 insertions(+), 92 deletions(-) diff --git a/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 b/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 index 6a7e95ac4..803d3ea27 100644 --- a/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 +++ b/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 @@ -7,9 +7,9 @@ . /lib/mwan3/common.sh SCRIPTNAME="mwan3-hotplug" -[ "$ACTION" = "ifup" ] || [ "$ACTION" = "ifdown" ] || [ "$ACTION" = "connected" ] || [ "$ACTION" = "disconnected" ] || exit 1 +[ "$ACTION" = "ifup" ] || [ "$ACTION" = "ifdown" ] || [ "$ACTION" = "connected" ] || [ "$ACTION" = "disconnected" ] || exit 1 [ -n "$INTERFACE" ] || exit 2 -if ( [ "$ACTION" = "ifup" ] || [ "$ACTION" = "connected" ] ) && [ -z "$DEVICE" ]; then +if { [ "$ACTION" = "ifup" ] || [ "$ACTION" = "connected" ] ; } && [ -z "$DEVICE" ]; then LOG notice "$ACTION called on $INTERFACE with no device set" exit 3 fi @@ -62,7 +62,7 @@ fi binary_status=$status [ "$binary_status" = "online" ] || binary_status=offline -LOG notice "Execute "$ACTION" event on interface $INTERFACE (${DEVICE:-unknown})" +LOG notice "Execute $ACTION event on interface $INTERFACE (${DEVICE:-unknown})" case "$ACTION" in ifup|connected) diff --git a/net/mwan3/files/lib/mwan3/common.sh b/net/mwan3/files/lib/mwan3/common.sh index bb26327d5..62a736b37 100644 --- a/net/mwan3/files/lib/mwan3/common.sh +++ b/net/mwan3/files/lib/mwan3/common.sh @@ -13,5 +13,5 @@ LOG() # when this release is out of beta, the comment in the line below # should be removed [ "$facility" = "debug" ] && return - logger -t "$SCRIPTNAME[$$]" -p $facility "$*" + logger -t "${SCRIPTNAME}[$$]" -p $facility "$*" } diff --git a/net/mwan3/files/lib/mwan3/mwan3.sh b/net/mwan3/files/lib/mwan3/mwan3.sh index 14af3ded2..e9b3feda8 100644 --- a/net/mwan3/files/lib/mwan3/mwan3.sh +++ b/net/mwan3/files/lib/mwan3/mwan3.sh @@ -50,7 +50,9 @@ $*"; mwan3_update_dev_to_table() { local _tid + # shellcheck disable=SC2034 mwan3_dev_tbl_ipv4=" " + # shellcheck disable=SC2034 mwan3_dev_tbl_ipv6=" " update_table() @@ -99,7 +101,7 @@ mwan3_route_line_dev() { # must have mwan3 config already loaded # arg 1 is route device - local _tid route_line route_device route_family entry curr_table + local _tid route_line route_device route_family entry curr_table route_line=$2 route_family=$3 route_device=$(echo "$route_line" | sed -ne "s/.*dev \([^ ]*\).*/\1/p") @@ -170,7 +172,7 @@ mwan3_init() bitcnt=$(mwan3_count_one_bits MMX_MASK) mmdefault=$(((1< /dev/null)" ] && \ [ -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then json_init @@ -1183,11 +1184,12 @@ mwan3_report_iface_status() json_get_vars online uptime json_select .. json_select .. - online="$(printf '%02dh:%02dm:%02ds\n' $(($online/3600)) $(($online%3600/60)) $(($online%60)))" - uptime="$(printf '%02dh:%02dm:%02ds\n' $(($uptime/3600)) $(($uptime%3600/60)) $(($uptime%60)))" + online="$(printf '%02dh:%02dm:%02ds\n' $((online/3600)) $((online%3600/60)) $((online%60)))" + uptime="$(printf '%02dh:%02dm:%02ds\n' $((uptime/3600)) $((uptime%3600/60)) $((uptime%60)))" result="$(mwan3_get_iface_hotplug_state $1) $online, uptime $uptime" - elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" ] || \ - [ -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" ] || \ + elif [ -n "$($IP rule | awk '$1 == "'$((id+1000)):'"')" ] || \ + [ -n "$($IP rule | awk '$1 == "'$((id+2000)):'"')" ] || \ + [ -n "$($IP rule | awk '$1 == "'$((id+3000)):'"')" ] || \ [ -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" ] || \ [ -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then result="error" @@ -1225,10 +1227,10 @@ mwan3_report_policies() total_weight=$($ipt -S "$policy" | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | head -1 | awk '{print $3}') - if [ ! -z "${total_weight##*[!0-9]*}" ]; then + if [ -n "${total_weight##*[!0-9]*}" ]; then for iface in $($ipt -S "$policy" | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | awk '{print $1}'); do weight=$($ipt -S "$policy" | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | awk '$1 == "'$iface'"' | awk '{print $2}') - percent=$(($weight*100/$total_weight)) + percent=$((weight*100/total_weight)) echo " $iface ($percent%)" done else @@ -1306,6 +1308,6 @@ mwan3_flush_conntrack() mwan3_track_clean() { - rm -rf "$MWAN3_STATUS_DIR/${1}" &> /dev/null + rm -rf "${MWAN3_STATUS_DIR:?}/${1}" &> /dev/null rmdir --ignore-fail-on-non-empty "$MWAN3_STATUS_DIR" } diff --git a/net/mwan3/files/usr/sbin/mwan3 b/net/mwan3/files/usr/sbin/mwan3 index fd6b5204f..af66a70e1 100755 --- a/net/mwan3/files/usr/sbin/mwan3 +++ b/net/mwan3/files/usr/sbin/mwan3 @@ -44,7 +44,7 @@ ifdown() ifup() { - local device enabled up l3_device status interface true_iface + local enabled up l3_device status interface true_iface if [ -z "$1" ]; then echo "Expecting interface. Usage: mwan3 ifup " @@ -104,40 +104,40 @@ interfaces() echo "Interface status:" config_foreach mwan3_report_iface_status interface - echo -e + echo } policies() { echo "Current ipv4 policies:" mwan3_report_policies_v4 - echo -e + echo [ $NO_IPV6 -ne 0 ] && return echo "Current ipv6 policies:" mwan3_report_policies_v6 - echo -e + echo } connected() { echo "Directly connected ipv4 networks:" mwan3_report_connected_v4 - echo -e + echo [ $NO_IPV6 -ne 0 ] && return echo "Directly connected ipv6 networks:" mwan3_report_connected_v6 - echo -e + echo } rules() { echo "Active ipv4 user rules:" mwan3_report_rules_v4 - echo -e + echo [ $NO_IPV6 -ne 0 ] && return echo "Active ipv6 user rules:" mwan3_report_rules_v6 - echo -e + echo } status() @@ -205,12 +205,12 @@ stop() IP="$IP6" fi - for tid in $(ip route list table all | sed -ne 's/.*table \([0-9]\+\).*/\1/p'|sort -u); do + 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 | egrep '^[1-2][0-9]{3}\:' | cut -d ':' -f 1); do + 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)" @@ -255,6 +255,7 @@ restart() { case "$1" in ifup|ifdown|interfaces|policies|connected|rules|status|start|stop|restart) mwan3_init + # shellcheck disable=SC2048 $* ;; *) diff --git a/net/mwan3/files/usr/sbin/mwan3rtmon b/net/mwan3/files/usr/sbin/mwan3rtmon index 98a5c4b89..8a7da7a8f 100755 --- a/net/mwan3/files/usr/sbin/mwan3rtmon +++ b/net/mwan3/files/usr/sbin/mwan3rtmon @@ -8,8 +8,7 @@ mwan3_rtmon_route_handle() { config_load mwan3 - local section action route_line family tbl device metric tos dst line - local route_device tid + local section action route_line family tbl device metric tos dst line tid route_line=${1##"Deleted "} route_family=$2 @@ -48,7 +47,7 @@ mwan3_rtmon_route_handle() [ $action = "add" ] && [ -z "${tbl##*$route_line*}" ] && return [ $action = "del" ] && [ -n "${tbl##*$route_line*}" ] && return network_get_device device "$section" - LOG debug "adjusting route $device: $IP route "$action" table $tid $route_line" + 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" } @@ -69,7 +68,7 @@ mwan3_rtmon_route_handle() dst=${route_line%% *} grep_line="$dst ${tos:+tos $tos}.*table [0-9].*${metric:+metric $metric}" - $IP route list table all | grep "$grep_line" | while read line; do + $IP route list table all | grep "$grep_line" | while read -r line; do tbl=${line##*table } tbl=${tbl%% *} [ $tbl -gt $MWAN3_INTERFACE_MAX ] && continue @@ -99,7 +98,7 @@ main() fi mwan3_init - $IP monitor route | while read line; do + $IP monitor route | while read -r line; do [ -z "${line##*table*}" ] && continue LOG debug "handling route update $family $line" mwan3_lock "service" "mwan3rtmon" diff --git a/net/mwan3/files/usr/sbin/mwan3track b/net/mwan3/files/usr/sbin/mwan3track index 5cbf5f75d..a48df72b5 100755 --- a/net/mwan3/files/usr/sbin/mwan3track +++ b/net/mwan3/files/usr/sbin/mwan3track @@ -44,7 +44,7 @@ validate_track_method() { LOG warn "Missing httping. Please install httping package." return 1 } - [ -n "$2" -a "$2" != "0.0.0.0" -a "$2" != "::" ] || { + [ -n "$2" ] && { [ "$2" = "0.0.0.0" ] || [ "$2" = "::" ]; } && { LOG warn "Cannot determine source IP for the interface which is required by httping." return 1 } @@ -64,10 +64,10 @@ validate_track_method() { disconnected() { echo "offline" > /var/run/mwan3track/$INTERFACE/STATUS - echo "$(get_uptime)" > /var/run/mwan3track/$INTERFACE/OFFLINE + get_uptime > /var/run/mwan3track/$INTERFACE/OFFLINE echo "0" > /var/run/mwan3track/$INTERFACE/ONLINE score=0 - [ "$1" == 1 ] && return + [ "$1" = 1 ] && return LOG notice "Interface $INTERFACE ($DEVICE) is offline" env -i ACTION="disconnected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface } @@ -75,12 +75,12 @@ disconnected() { connected() { echo "online" > /var/run/mwan3track/$INTERFACE/STATUS echo "0" > /var/run/mwan3track/$INTERFACE/OFFLINE - echo "$(get_uptime)" > /var/run/mwan3track/$INTERFACE/ONLINE + get_uptime > /var/run/mwan3track/$INTERFACE/ONLINE host_up_count=0 lost=0 turn=0 loss=0 - [ "$1" == 1 ] && return + [ "$1" = 1 ] && return LOG notice "Interface $INTERFACE ($DEVICE) is online" env -i ACTION="connected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface } @@ -94,11 +94,9 @@ firstconnect() { } update_status() { - local status track_ip - track_ip=$1 - status=$2 + local track_ip=$1 - echo "$1" > /var/run/mwan3track/$INTERFACE/TRACK_${track_ip} + echo "$2" > /var/run/mwan3track/$INTERFACE/TRACK_${track_ip} [ -z "$3" ] && return echo "$3" > /var/run/mwan3track/$INTERFACE/LATENCY_${track_ip} echo "$4" > /var/run/mwan3track/$INTERFACE/LOSS_${track_ip} @@ -151,13 +149,13 @@ main() { config_get failure_loss $INTERFACE failure_loss 40 config_get recovery_loss $INTERFACE recovery_loss 10 - local score=$(($down+$up)) + 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 + local sleep_time result ping_result ping_result_raw ping_status loss latency firstconnect while true; do @@ -183,7 +181,7 @@ main() { 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_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="$(echo "$ping_result" | grep "packet loss" | cut -d "," -f3 | awk '{print $1}' | sed -e 's/%//')" if [ "$ping_status" -ne 0 ] || [ "$loss" -eq 100 ]; then latency=999999 loss=100 @@ -234,14 +232,14 @@ main() { fi fi else - if [ "$loss" -ge "$failure_loss" -o "$latency" -ge "$failure_latency" ]; then + if [ "$loss" -ge "$failure_loss" ] || [ "$latency" -ge "$failure_latency" ]; then let lost++ update_status "$track_ip" "down" $latency $loss if [ $score -gt $up ]; then LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) failed for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score" fi - elif [ "$loss" -le "$recovery_loss" -a "$latency" -le "$recovery_latency" ]; then + elif [ "$loss" -le "$recovery_loss" ] && [ "$latency" -le "$recovery_latency" ]; then let host_up_count++ update_status "$track_ip" "up" $latency $loss @@ -274,8 +272,8 @@ main() { 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" + 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++ @@ -283,7 +281,7 @@ main() { if [ $score -gt $up ]; then echo "online" > /var/run/mwan3track/$INTERFACE/STATUS - score=$(($down+$up)) + score=$((down+up)) elif [ $score -le $up ]; then sleep_time=$recovery_interval fi @@ -298,7 +296,7 @@ main() { echo "${lost}" > /var/run/mwan3track/$INTERFACE/LOST echo "${score}" > /var/run/mwan3track/$INTERFACE/SCORE echo "${turn}" > /var/run/mwan3track/$INTERFACE/TURN - echo "$(get_uptime)" > /var/run/mwan3track/$INTERFACE/TIME + get_uptime > /var/run/mwan3track/$INTERFACE/TIME host_up_count=0 sleep "${sleep_time}" & From 27492f64f87c1c39d802ad926ae269d47b97856c Mon Sep 17 00:00:00 2001 From: Aaron Goodman Date: Mon, 31 Aug 2020 15:49:17 -0400 Subject: [PATCH 02/12] mwan3: use MWAN3TRACK_STATUS_DIR variable throughout Signed-off-by: Aaron Goodman --- net/mwan3/files/lib/mwan3/common.sh | 1 + net/mwan3/files/lib/mwan3/mwan3.sh | 1 - net/mwan3/files/usr/sbin/mwan3track | 24 ++++++++++++------------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/net/mwan3/files/lib/mwan3/common.sh b/net/mwan3/files/lib/mwan3/common.sh index 62a736b37..3b1560897 100644 --- a/net/mwan3/files/lib/mwan3/common.sh +++ b/net/mwan3/files/lib/mwan3/common.sh @@ -6,6 +6,7 @@ get_uptime() { } SCRIPTNAME="$(basename "$0")" +MWAN3TRACK_STATUS_DIR="/var/run/mwan3track" LOG() { local facility=$1; shift diff --git a/net/mwan3/files/lib/mwan3/mwan3.sh b/net/mwan3/files/lib/mwan3/mwan3.sh index e9b3feda8..4d42f8954 100644 --- a/net/mwan3/files/lib/mwan3/mwan3.sh +++ b/net/mwan3/files/lib/mwan3/mwan3.sh @@ -24,7 +24,6 @@ IPv6_REGEX="${IPv6_REGEX}::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0- IPv6_REGEX="${IPv6_REGEX}([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])" MWAN3_STATUS_DIR="/var/run/mwan3" -MWAN3TRACK_STATUS_DIR="/var/run/mwan3track" MWAN3_INTERFACE_MAX="" DEFAULT_LOWEST_METRIC=256 MMX_MASK="" diff --git a/net/mwan3/files/usr/sbin/mwan3track b/net/mwan3/files/usr/sbin/mwan3track index a48df72b5..863eb76ff 100755 --- a/net/mwan3/files/usr/sbin/mwan3track +++ b/net/mwan3/files/usr/sbin/mwan3track @@ -73,9 +73,9 @@ disconnected() { } connected() { - echo "online" > /var/run/mwan3track/$INTERFACE/STATUS - echo "0" > /var/run/mwan3track/$INTERFACE/OFFLINE - get_uptime > /var/run/mwan3track/$INTERFACE/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 @@ -96,10 +96,10 @@ firstconnect() { update_status() { local track_ip=$1 - echo "$2" > /var/run/mwan3track/$INTERFACE/TRACK_${track_ip} + echo "$2" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_${track_ip} [ -z "$3" ] && return - echo "$3" > /var/run/mwan3track/$INTERFACE/LATENCY_${track_ip} - echo "$4" > /var/run/mwan3track/$INTERFACE/LOSS_${track_ip} + echo "$3" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/LATENCY_${track_ip} + echo "$4" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/LOSS_${track_ip} } main() { @@ -280,7 +280,7 @@ main() { lost=0 if [ $score -gt $up ]; then - echo "online" > /var/run/mwan3track/$INTERFACE/STATUS + echo "online" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS score=$((down+up)) elif [ $score -le $up ]; then sleep_time=$recovery_interval @@ -292,11 +292,11 @@ main() { fi let turn++ - mkdir -p "/var/run/mwan3track/${1}" - echo "${lost}" > /var/run/mwan3track/$INTERFACE/LOST - echo "${score}" > /var/run/mwan3track/$INTERFACE/SCORE - echo "${turn}" > /var/run/mwan3track/$INTERFACE/TURN - get_uptime > /var/run/mwan3track/$INTERFACE/TIME + 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 sleep "${sleep_time}" & From c8deccc0e70d0d872d2dfc791c1fffcbe5ec645e Mon Sep 17 00:00:00 2001 From: Aaron Goodman Date: Sat, 15 Aug 2020 19:58:55 -0400 Subject: [PATCH 03/12] mwan3: improvements to route creation handle creation of routing tables in mwan3rtmon to avoid race conditions and potentially missing routes handle ipv6 routes that have expiry update directly connected ipset when routes are added or deleted add fall through rules so that the default routing table is not used if no rule in the interface-specific routing table matches add option to comply with mwan3 source based routing get default route parameters from main routing table Signed-off-by: Aaron Goodman --- net/mwan3/files/etc/hotplug.d/iface/15-mwan3 | 7 +- net/mwan3/files/lib/mwan3/mwan3.sh | 184 ++++++------------ net/mwan3/files/usr/sbin/mwan3 | 2 +- net/mwan3/files/usr/sbin/mwan3rtmon | 186 +++++++++++++------ 4 files changed, 191 insertions(+), 188 deletions(-) diff --git a/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 b/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 index 803d3ea27..586dfc1f6 100644 --- a/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 +++ b/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 @@ -33,8 +33,8 @@ $IPT4 -S mwan3_hook &>/dev/null || { mwan3_init [ "$MWAN3_STARTUP" = 1 ] || { - mwan3_set_connected_iptables - mwan3_set_custom_ipset + config_get family $INTERFACE family ipv4 + mwan3_set_connected_${family} } if [ "$MWAN3_STARTUP" != 1 ]; then @@ -68,8 +68,7 @@ case "$ACTION" in ifup|connected) mwan3_create_iface_iptables $INTERFACE $DEVICE mwan3_create_iface_rules $INTERFACE $DEVICE - mwan3_create_iface_route $INTERFACE $DEVICE - [ "$MWAN3_STARTUP" != 1 ] && mwan3_add_non_default_iface_route $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" diff --git a/net/mwan3/files/lib/mwan3/mwan3.sh b/net/mwan3/files/lib/mwan3/mwan3.sh index 4d42f8954..7f5200d15 100644 --- a/net/mwan3/files/lib/mwan3/mwan3.sh +++ b/net/mwan3/files/lib/mwan3/mwan3.sh @@ -294,40 +294,48 @@ mwan3_set_connected_ipv4() $IPS swap mwan3_connected_v4_temp mwan3_connected_v4 $IPS destroy mwan3_connected_v4_temp + $IPS -! add mwan3_connected mwan3_connected_v4 } -mwan3_set_connected_iptables() +mwan3_set_connected_ipv6() { local connected_network_v6 source_network_v6 error local update="" - mwan3_set_connected_ipv4 + [ $NO_IPV6 -eq 0 ] || return - [ $NO_IPV6 -eq 0 ] && { - mwan3_push_update -! create mwan3_connected_v6 hash:net family inet6 - mwan3_push_update flush mwan3_connected_v6 + mwan3_push_update -! create mwan3_connected_v6 hash:net family inet6 + mwan3_push_update flush mwan3_connected_v6 - for connected_network_v6 in $($IP6 route | awk '{print $1}' | grep -E "$IPv6_REGEX"); do - mwan3_push_update -! add mwan3_connected_v6 "$connected_network_v6" - done + for connected_network_v6 in $($IP6 route | awk '{print $1}' | grep -E "$IPv6_REGEX"); do + mwan3_push_update -! add mwan3_connected_v6 "$connected_network_v6" + done - mwan3_push_update -! create mwan3_source_v6 hash:net family inet6 - for source_network_v6 in $($IP6 addr ls | sed -ne 's/ *inet6 \([^ \/]*\).* scope global.*/\1/p'); do - mwan3_push_update -! add mwan3_source_v6 "$source_network_v6" - done - } + mwan3_push_update -! create mwan3_source_v6 hash:net family inet6 + for source_network_v6 in $($IP6 addr ls | sed -ne 's/ *inet6 \([^ \/]*\).* scope global.*/\1/p'); do + mwan3_push_update -! add mwan3_source_v6 "$source_network_v6" + done + mwan3_push_update -! add mwan3_connected mwan3_connected_v6 + error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_connected_ipv6: $error" +} + +mwan3_set_connected_ipset() +{ + local error + local update="" mwan3_push_update -! create mwan3_connected list:set mwan3_push_update flush mwan3_connected - mwan3_push_update -! add mwan3_connected mwan3_connected_v4 - [ $NO_IPV6 -eq 0 ] && mwan3_push_update -! add mwan3_connected mwan3_connected_v6 mwan3_push_update -! create mwan3_dynamic_v4 hash:net mwan3_push_update -! add mwan3_connected mwan3_dynamic_v4 - [ $NO_IPV6 -eq 0 ] && mwan3_push_update -! create mwan3_dynamic_v6 hash:net family inet6 - [ $NO_IPV6 -eq 0 ] && mwan3_push_update -! add mwan3_connected mwan3_dynamic_v6 - error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_connected_iptables: $error" + if [ $NO_IPV6 -eq 0 ]; then + mwan3_push_update -! create mwan3_dynamic_v6 hash:net family inet6 + mwan3_push_update -! add mwan3_connected mwan3_dynamic_v6 + fi + + error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_connected_ipset: $error" } mwan3_set_general_rules() @@ -439,7 +447,7 @@ mwan3_set_general_iptables() mwan3_create_iface_iptables() { - local id family connected_name IPT IPTR current update error + local id family IPT IPTR current update error config_get family "$1" family ipv4 mwan3_get_iface_id id "$1" @@ -447,16 +455,11 @@ mwan3_create_iface_iptables() [ -n "$id" ] || return 0 if [ "$family" = "ipv4" ]; then - connected_name=mwan3_connected IPT="$IPT4" IPTR="$IPT4R" - $IPS -! create $connected_name list:set - elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then - connected_name=mwan3_connected_v6 IPT="$IPT6" IPTR="$IPT6R" - $IPS -! create $connected_name hash:net family inet6 else return fi @@ -474,7 +477,7 @@ mwan3_create_iface_iptables() mwan3_push_update -A "mwan3_iface_in_$1" \ -i "$2" \ - -m set --match-set $connected_name src \ + -m set --match-set mwan3_connected src \ -m mark --mark "0x0/$MMX_MASK" \ -m comment --comment "default" \ -j MARK --set-xmark "$MMX_DEFAULT/$MMX_MASK" @@ -521,45 +524,17 @@ mwan3_delete_iface_iptables() } -mwan3_create_iface_route() +mwan3_get_routes() { - local id via metric V V_ IP family - local iface device cmd true_iface - - iface=$1 - device=$2 - config_get family "$iface" family ipv4 - mwan3_get_iface_id id "$iface" - - [ -n "$id" ] || return 0 - - mwan3_get_true_iface true_iface $iface - if [ "$family" = "ipv4" ]; then - V_="" - IP="$IP4" - elif [ "$family" = "ipv6" ]; then - V_=6 - IP="$IP6" - fi - - network_get_gateway${V_} via "$true_iface" - - { [ -z "$via" ] || [ "$via" = "0.0.0.0" ] || [ "$via" = "::" ] ; } && unset via - - network_get_metric metric "$true_iface" - - $IP route flush table "$id" - cmd="$IP route add table $id default \ - ${via:+via} $via \ - ${metric:+metric} $metric \ - dev $2" - $cmd || LOG warn "ip cmd failed $cmd" - + local source_routing + config_get_bool source_routing globals source_routing 0 + [ $source_routing -eq 0 ] && unset source_routing + $IP route list table main | sed -ne "/^linkdown/T; s/expires \([0-9]\+\)sec//;s/error [0-9]\+//; ${source_routing:+s/default\(.*\) from [^ ]*/default\1/;} p" | uniq } -mwan3_add_non_default_iface_route() +mwan3_create_iface_route() { - local tid route_line family IP id + local tid route_line family IP id tbl config_get family "$1" family ipv4 mwan3_get_iface_id id "$1" @@ -571,10 +546,15 @@ mwan3_add_non_default_iface_route() IP="$IP6" fi + tbl=$($IP route list table $id 2>/dev/null)$'\n' mwan3_update_dev_to_table - $IP route list table main | grep -v "^default\|linkdown\|^::/0\|^fe80::/64\|^unreachable" | while read -r route_line; do + mwan3_get_routes | while read -r route_line; do mwan3_route_line_dev "tid" "$route_line" "$family" + { [ -z "${route_line##default*}" ] || [ -z "${route_line##fe80::/64*}" ]; } && [ "$tid" != "$id" ] && continue if [ -z "$tid" ] || [ "$tid" = "$id" ]; then + # possible that routes are already in the table + # if 'connected' was called after 'ifup' + [ -n "$tbl" ] && [ -z "${tbl##*$route_line$'\n'*}" ] && continue $IP route add table $id $route_line || LOG warn "failed to add $route_line to table $id" fi @@ -582,63 +562,21 @@ mwan3_add_non_default_iface_route() done } -mwan3_add_all_nondefault_routes() -{ - local tid IP route_line ipv family active_tbls tid - - add_active_tbls() - { - let tid++ - config_get family "$1" family ipv4 - [ "$family" != "$ipv" ] && return - $IP route list table $tid 2>/dev/null | grep -q "^default\|^::/0" && { - active_tbls="$active_tbls${tid} " - } - } - - 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 - for ipv in ipv4 ipv6; do - [ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue - if [ "$ipv" = "ipv4" ]; then - IP="$IP4" - elif [ "$ipv" = "ipv6" ]; then - IP="$IP6" - fi - tid=0 - active_tbls=" " - config_foreach add_active_tbls interface - $IP route list table main | grep -v "^default\|linkdown\|^::/0\|^fe80::/64\|^unreachable" | while read -r route_line; do - mwan3_route_line_dev "tid" "$route_line" "$ipv" - if [ -n "$tid" ]; then - $IP route add table $tid $route_line - else - config_foreach add_route interface - fi - done - done -} mwan3_delete_iface_route() { - local id + local id family config_get family "$1" family ipv4 mwan3_get_iface_id id "$1" - [ -n "$id" ] || return 0 + if [ -z "$id" ]; then + LOG warn "delete_iface_route: could not find table id for interface $1" + return 0 + fi if [ "$family" = "ipv4" ]; then $IP4 route flush table "$id" - fi - - if [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then + elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then $IP6 route flush table "$id" fi } @@ -660,21 +598,16 @@ mwan3_create_iface_rules() return fi - while [ -n "$($IP rule list | awk '$1 == "'$((id+1000)):'"')" ]; do - $IP rule del pref $((id+1000)) - done - - while [ -n "$($IP rule list | awk '$1 == "'$((id+2000)):'"')" ]; do - $IP rule del pref $((id+2000)) - done + mwan3_delete_iface_rules "$1" $IP rule add pref $((id+1000)) iif "$2" lookup "$id" $IP rule add pref $((id+2000)) fwmark "$(mwan3_id2mask id MMX_MASK)/$MMX_MASK" lookup "$id" + $IP rule add pref $((id+3000)) fwmark "$(mwan3_id2mask id MMX_MASK)/$MMX_MASK" unreachable } mwan3_delete_iface_rules() { - local id family IP + local id family IP rule_id config_get family "$1" family ipv4 mwan3_get_iface_id id "$1" @@ -689,12 +622,8 @@ mwan3_delete_iface_rules() return fi - while [ -n "$($IP rule list | awk '$1 == "'$((id+1000)):'"')" ]; do - $IP rule del pref $((id+1000)) - done - - while [ -n "$($IP rule list | awk '$1 == "'$((id+2000)):'"')" ]; do - $IP rule del pref $((id+2000)) + for rule_id in $(ip rule list | awk '$1 % 1000 == '$id' && $1 > 1000 && $1 < 4000 {print substr($1,0,4)}'); do + $IP rule del pref $rule_id done } @@ -952,6 +881,10 @@ mwan3_set_user_iptables_rule() config_get global_logging globals logging 0 config_get loglevel globals loglevel notice + [ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && return + [ "$family" = "ipv4" ] && [ "$ipv" = "ipv6" ] && return + [ "$family" = "ipv6" ] && [ "$ipv" = "ipv4" ] && return + if [ -n "$src_iface" ]; then network_get_device src_dev "$src_iface" if [ -z "$src_dev" ]; then @@ -1013,10 +946,6 @@ mwan3_set_user_iptables_rule() fi fi - [ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && return - [ "$family" = "ipv4" ] && [ "$ipv" = "ipv6" ] && return - [ "$family" = "ipv6" ] && [ "$ipv" = "ipv4" ] && return - if [ $rule_policy -eq 1 ] && [ -n "${current##*-N $policy*}" ]; then mwan3_push_update -N "$policy" fi @@ -1172,6 +1101,7 @@ mwan3_report_iface_status() result="offline" elif [ -n "$($IP rule | awk '$1 == "'$((id+1000)):'"')" ] && \ [ -n "$($IP rule | awk '$1 == "'$((id+2000)):'"')" ] && \ + [ -n "$($IP rule | awk '$1 == "'$((id+3000)):'"')" ] && \ [ -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" ] && \ [ -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then json_init diff --git a/net/mwan3/files/usr/sbin/mwan3 b/net/mwan3/files/usr/sbin/mwan3 index af66a70e1..5928172d9 100755 --- a/net/mwan3/files/usr/sbin/mwan3 +++ b/net/mwan3/files/usr/sbin/mwan3 @@ -163,7 +163,7 @@ start() mwan3_set_general_iptables config_foreach ifup interface wait $hotplug_pids - mwan3_add_all_nondefault_routes + mwan3_add_all_routes mwan3_set_policies_iptables mwan3_set_user_rules diff --git a/net/mwan3/files/usr/sbin/mwan3rtmon b/net/mwan3/files/usr/sbin/mwan3rtmon index 8a7da7a8f..ff7183ae2 100755 --- a/net/mwan3/files/usr/sbin/mwan3rtmon +++ b/net/mwan3/files/usr/sbin/mwan3rtmon @@ -5,81 +5,139 @@ . /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 [ "$initial_state" = "online" ] && $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() { - config_load mwan3 - local section action route_line family tbl device metric tos dst line tid + local action route_line family tbl device line route_line_exp tid source_routing + route_line=${1##"Deleted "} route_family=$2 + config_get_boolean 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 - if [ "$route_line" == "$1" ]; then - action="add" - else - action="del" + # 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 - # never add default route lines, since this is handled elsewhere - [ -z "${route_line##default*}" ] && return - [ -z "${route_line##::/0*}" ] && return - route_line=${route_line%% linkdown*} - route_line=${route_line%% unreachable*} - mwan3_update_dev_to_table - mwan3_route_line_dev "tid" "$route_line" "$route_family" handle_route() { - tbl=$($IP route list table $tid) - if [ $action = "add" ]; then - echo "$tbl" | grep -q "^default\|^::/0" || return - else - [ -z "$tbl" ] && return - fi - # check that action needs to be performed. May not need to take action if: - # Got a route update on ipv6 where route is already in the table - # Got a delete event, but table was already flushed + local iface=$1 + tbl=$($IP route list table $tid 2>/dev/null)$'\n' - [ $action = "add" ] && [ -z "${tbl##*$route_line*}" ] && return - [ $action = "del" ] && [ -n "${tbl##*$route_line*}" ] && return - network_get_device device "$section" - LOG debug "adjusting route $device: $IP route \"$action\" table $tid $route_line" + if [ "$(cat /var/run/mwan3track/$iface/STATUS)" != "online" ]; then + LOG debug "interface $iface is offline - 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 "$section" family ipv4 + config_get family "$iface" family ipv4 [ "$family" != "$route_family" ] && return - handle_route + handle_route "$iface" } - if [ $action = "add" ]; then - ## handle old routes from 'change' or 'replace' - metric=${route_line##*metric } - [ "$metric" = "$route_line" ] && unset metric || metric=${metric%% *} - - tos=${route_line##*tos } - [ "$tos" = "$route_line" ] && unset tos || tos=${tos%% *} - - dst=${route_line%% *} - grep_line="$dst ${tos:+tos $tos}.*table [0-9].*${metric:+metric $metric}" - $IP route list table all | grep "$grep_line" | while read -r line; do - tbl=${line##*table } - tbl=${tbl%% *} - [ $tbl -gt $MWAN3_INTERFACE_MAX ] && continue - LOG debug "removing route on ip route change/replace: $line" - $IP route del $line - done - fi + mwan3_update_dev_to_table + mwan3_route_line_dev "tid" "$route_line" "$route_family" if [ -n "$tid" ]; then handle_route - else + elif [ -n "${route_line##default*}" ] && [ -n "${route_line##fe80::/64*}" ]; then config_foreach handle_route_cb interface fi } @@ -91,19 +149,35 @@ main() config_load mwan3 family=$1 [ -z $family ] && family=ipv4 - if [ "$family" = ipv6 ]; then + 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 - - $IP monitor route | while read -r line; do - [ -z "${line##*table*}" ] && continue - LOG debug "handling route update $family $line" - mwan3_lock "service" "mwan3rtmon" - mwan3_rtmon_route_handle "$line" "$family" - mwan3_unlock "service" "mwan3rtmon" - done + mwan3_lock "mwan3rtmon" "start" + sh -c "echo \$\$; exec $IP monitor route" | { + read -r monitor_pid + trap_with_arg func_trap "$monitor_pid" SIGINT SIGTERM SIGKILL + while read -r line; do + [ -z "${line##*table*}" ] && continue + LOG debug "handling route update $family $line" + mwan3_lock "service" "mwan3rtmon" + mwan3_rtmon_route_handle "$line" "$family" + mwan3_unlock "service" "mwan3rtmon" + done + } & + child=$! + kill -SIGSTOP $child + trap_with_arg func_trap "$child" SIGINT SIGTERM SIGKILL + mwan3_set_connected_${family} + mwan3_add_all_routes ${family} + mwan3_unlock "mwan3rtmon" "start" + kill -SIGCONT $child + wait $! } main "$@" From 189f92da4af7d6c4ea9bc683d4a871f202a562c7 Mon Sep 17 00:00:00 2001 From: Aaron Goodman Date: Tue, 1 Sep 2020 19:20:41 -0400 Subject: [PATCH 04/12] mwan3: only update src_iface rules on ifup Signed-off-by: Aaron Goodman --- net/mwan3/files/etc/hotplug.d/iface/15-mwan3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 b/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 index 586dfc1f6..196b03257 100644 --- a/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 +++ b/net/mwan3/files/etc/hotplug.d/iface/15-mwan3 @@ -37,7 +37,7 @@ mwan3_init mwan3_set_connected_${family} } -if [ "$MWAN3_STARTUP" != 1 ]; then +if [ "$MWAN3_STARTUP" != 1 ] && [ "$ACTION" = "ifup" ]; then mwan3_set_user_iface_rules $INTERFACE $DEVICE fi From 5faa99f3b850c40669f231b45cca7bb7273c3083 Mon Sep 17 00:00:00 2001 From: Aaron Goodman Date: Mon, 31 Aug 2020 15:51:25 -0400 Subject: [PATCH 05/12] mwan3: fix bug when one interface is a prefix of another correctly terminate interface status checks with new lines so that interface status does not get confused when one interface is a prefix of another interface. Signed-off-by: Aaron Goodman --- net/mwan3/files/lib/mwan3/mwan3.sh | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/net/mwan3/files/lib/mwan3/mwan3.sh b/net/mwan3/files/lib/mwan3/mwan3.sh index 7f5200d15..111fea067 100644 --- a/net/mwan3/files/lib/mwan3/mwan3.sh +++ b/net/mwan3/files/lib/mwan3/mwan3.sh @@ -361,7 +361,7 @@ mwan3_set_general_iptables() local IPT current update error for IPT in "$IPT4" "$IPT6"; do [ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue - current="$($IPT -S)" + current="$($IPT -S)"$'\n' update="*mangle" if [ -n "${current##*-N mwan3_ifaces_in*}" ]; then mwan3_push_update -N mwan3_ifaces_in @@ -463,13 +463,14 @@ mwan3_create_iface_iptables() else return fi - current="$($IPT -S)" + + current="$($IPT -S)"$'\n' update="*mangle" if [ -n "${current##*-N mwan3_ifaces_in*}" ]; then mwan3_push_update -N mwan3_ifaces_in fi - if [ -n "${current##*-N mwan3_iface_in_$1*}" ]; then + if [ -n "${current##*-N mwan3_iface_in_$1$'\n'*}" ]; then mwan3_push_update -N "mwan3_iface_in_$1" else mwan3_push_update -F "mwan3_iface_in_$1" @@ -487,7 +488,7 @@ mwan3_create_iface_iptables() -m comment --comment "$1" \ -j MARK --set-xmark "$(mwan3_id2mask id MMX_MASK)/$MMX_MASK" - if [ -n "${current##*-A mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_${1}*}" ]; then + if [ -n "${current##*-A mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_${1}$'\n'*}" ]; then mwan3_push_update -A mwan3_ifaces_in \ -m mark --mark 0x0/$MMX_MASK \ -j "mwan3_iface_in_$1" @@ -705,7 +706,7 @@ mwan3_set_policy() IPT="$IPT6" IPTR="$IPT6R" fi - current="$($IPT -S)" + current="$($IPT -S)"$'\n' update="*mangle" if [ "$family" = "ipv4" ] && [ $is_offline -eq 0 ]; then @@ -784,9 +785,9 @@ mwan3_create_policies_iptables() for IPT in "$IPT4" "$IPT6"; do [ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue - current="$($IPT -S)" + current="$($IPT -S)"$'\n' update="*mangle" - if [ -n "${current##*-N mwan3_policy_$1*}" ]; then + if [ -n "${current##*-N mwan3_policy_$1$'\n'*}" ]; then mwan3_push_update -N "mwan3_policy_$1" fi @@ -844,7 +845,7 @@ mwan3_set_sticky_iptables() mwan3_get_iface_id id "$1" [ -n "$id" ] || return 0 - if [ -z "${current##*-N mwan3_iface_in_$1*}" ]; then + if [ -z "${current##*-N mwan3_iface_in_$1$'\n'*}" ]; then mwan3_push_update -I "mwan3_rule_$rule" \ -m mark --mark "$(mwan3_id2mask id MMX_MASK)/$MMX_MASK" \ -m set ! --match-set "mwan3_sticky_$rule" src,src \ @@ -946,12 +947,12 @@ mwan3_set_user_iptables_rule() fi fi - if [ $rule_policy -eq 1 ] && [ -n "${current##*-N $policy*}" ]; then + if [ $rule_policy -eq 1 ] && [ -n "${current##*-N $policy$'\n'*}" ]; then mwan3_push_update -N "$policy" fi if [ $rule_policy -eq 1 ] && [ "$sticky" -eq 1 ]; then - if [ -n "${current##*-N mwan3_rule_$1*}" ]; then + if [ -n "${current##*-N mwan3_rule_$1$'\n'*}" ]; then mwan3_push_update -N "mwan3_rule_$1" fi @@ -1046,7 +1047,7 @@ mwan3_set_user_rules() fi [ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue update="*mangle" - current="$($IPT -S)" + current="$($IPT -S)"$'\n' if [ -n "${current##*-N mwan3_rules*}" ]; then From 566293d228a48d21a04ecbc815a7ae97e26eb319 Mon Sep 17 00:00:00 2001 From: Aaron Goodman Date: Wed, 12 Aug 2020 20:38:56 -0400 Subject: [PATCH 06/12] mwan3: use procd for mwan3rtmon and mwan3track start all mwan3mon and mwan3track instances on mwan3 start if an interface is down when mwan3track starts, it waits for a signal from the hotplug script to start procd can then handle stopping all of the scripts when mwan3 is halted Signed-off-by: Aaron Goodman --- net/mwan3/files/etc/hotplug.d/iface/15-mwan3 | 60 +++---- .../files/etc/hotplug.d/iface/16-mwan3-user | 14 +- net/mwan3/files/etc/init.d/mwan3 | 111 ++++++++++-- net/mwan3/files/lib/mwan3/common.sh | 134 ++++++++++++++ net/mwan3/files/lib/mwan3/mwan3.sh | 150 ++++++++-------- net/mwan3/files/usr/libexec/rpcd/mwan3 | 9 +- net/mwan3/files/usr/sbin/mwan3 | 167 ++---------------- net/mwan3/files/usr/sbin/mwan3rtmon | 2 +- net/mwan3/files/usr/sbin/mwan3track | 143 ++++++++++----- 9 files changed, 465 insertions(+), 325 deletions(-) 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 From fb4a2d99eff3af53d4eea2db36d270a140bde6bf Mon Sep 17 00:00:00 2001 From: Aaron Goodman Date: Mon, 31 Aug 2020 19:20:17 -0400 Subject: [PATCH 07/12] mwan3: give warning if ip of incorrect family specified in a rule also use global IPv4_REGEX environment variable as consistent IPv4 regex Signed-off-by: Aaron Goodman --- net/mwan3/files/lib/mwan3/mwan3.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/net/mwan3/files/lib/mwan3/mwan3.sh b/net/mwan3/files/lib/mwan3/mwan3.sh index dad2f4994..c3113007a 100644 --- a/net/mwan3/files/lib/mwan3/mwan3.sh +++ b/net/mwan3/files/lib/mwan3/mwan3.sh @@ -20,6 +20,7 @@ IPv6_REGEX="${IPv6_REGEX}:((:[0-9a-fA-F]{1,4}){1,7}|:)|" IPv6_REGEX="${IPv6_REGEX}fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|" IPv6_REGEX="${IPv6_REGEX}::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|" IPv6_REGEX="${IPv6_REGEX}([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])" +IPv4_REGEX="((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" MWAN3_STATUS_DIR="/var/run/mwan3" MWAN3_INTERFACE_MAX="" @@ -208,7 +209,7 @@ mwan3_set_custom_ipset_v4() { local custom_network_v4 - for custom_network_v4 in $($IP4 route list table "$1" | awk '{print $1}' | grep -E '[0-9]{1,3}(\.[0-9]{1,3}){3}'); do + for custom_network_v4 in $($IP4 route list table "$1" | awk '{print $1}' | grep -E "$IPv4_REGEX"); do LOG notice "Adding network $custom_network_v4 from table $1 to mwan3_custom_v4 ipset" mwan3_push_update -! add mwan3_custom_v4 "$custom_network_v4" done @@ -244,7 +245,6 @@ mwan3_set_custom_ipset() mwan3_set_connected_ipv4() { local connected_network_v4 candidate_list cidr_list - local ipv4regex='[0-9]{1,3}(\.[0-9]{1,3}){3}' $IPS -! create mwan3_connected_v4 hash:net $IPS create mwan3_connected_v4_temp hash:net @@ -255,7 +255,7 @@ mwan3_set_connected_ipv4() $IP4 route | awk '{print $1}' $IP4 route list table 0 | awk '{print $2}' } - for connected_network_v4 in $(route_lists | grep -E "$ipv4regex"); do + for connected_network_v4 in $(route_lists | grep -E "$IPv4_REGEX"); do if [ -z "${connected_network_v4##*/*}" ]; then cidr_list="$cidr_list $connected_network_v4" else @@ -834,6 +834,14 @@ mwan3_set_user_iptables_rule() [ "$family" = "ipv4" ] && [ "$ipv" = "ipv6" ] && return [ "$family" = "ipv6" ] && [ "$ipv" = "ipv4" ] && return + for ipaddr in "$src_ip" "$dest_ip"; do + if [ -n "$ipaddr" ] && { { [ "$ipv" = "ipv4" ] && echo "$ipaddr" | grep -qE "$IPv6_REGEX"; } || + { [ "$ipv" = "ipv6" ] && echo "$ipaddr" | grep -qE $IPv4_REGEX; } }; then + LOG warn "invalid $ipv address $ipaddr specified for rule $rule" + return + fi + done + if [ -n "$src_iface" ]; then network_get_device src_dev "$src_iface" if [ -z "$src_dev" ]; then From bbbc6127abf132a92cc73dd23fa88409dc2b9abd Mon Sep 17 00:00:00 2001 From: Aaron Goodman Date: Sun, 11 Oct 2020 18:37:25 -0400 Subject: [PATCH 08/12] mwan3: use helper library for mwan3track Rather than using a special mwan3 user to manage mwan3track's tracking packets, this commit implements a small helper library to bind to device and to set a fwmark so that the tracking packets can be routed out of the correct interface. This provides a consistent method for binding to a device rather than relying on various packages potentially buggy implementations. For example: #8139 and #12836 This helper issue also allows for more tracking methods to be added even if they do not have a command line option to bind to device, such as iperf3 (eg #13050). Signed-off-by: Aaron Goodman --- net/mwan3/Makefile | 10 +- net/mwan3/files/lib/mwan3/common.sh | 27 ++- net/mwan3/files/lib/mwan3/mwan3.sh | 93 +--------- net/mwan3/files/usr/sbin/mwan3track | 48 +++--- net/mwan3/src/sockopt_wrap.c | 255 ++++++++++++++++++++++++++++ 5 files changed, 312 insertions(+), 121 deletions(-) create mode 100644 net/mwan3/src/sockopt_wrap.c diff --git a/net/mwan3/Makefile b/net/mwan3/Makefile index 65e2925c3..4850bfae4 100644 --- a/net/mwan3/Makefile +++ b/net/mwan3/Makefile @@ -8,10 +8,11 @@ include $(TOPDIR)/rules.mk PKG_NAME:=mwan3 -PKG_VERSION:=2.9.0 +PKG_VERSION:=2.10.0 PKG_RELEASE:=1 PKG_MAINTAINER:=Florian Eckert PKG_LICENSE:=GPL-2.0 +PKG_CONFIG_DEPENDS:=CONFIG_IPV6 include $(INCLUDE_DIR)/package.mk @@ -61,8 +62,13 @@ fi exit 0 endef +define Build/Compile + $(TARGET_CC) $(CFLAGS) $(LDFLAGS) $(FPIC) -shared -o $(PKG_BUILD_DIR)/libwrap_mwan3_sockopt.so.1.0 $(if $(CONFIG_IPV6),-DCONFIG_IPV6) $(PKG_BUILD_DIR)/sockopt_wrap.c -ldl +endef + define Package/mwan3/install -$(CP) ./files/* $(1) + $(CP) ./files/* $(1) + $(CP) $(PKG_BUILD_DIR)/libwrap_mwan3_sockopt.so.1.0 $(1)/lib/mwan3/ endef $(eval $(call BuildPackage,mwan3)) diff --git a/net/mwan3/files/lib/mwan3/common.sh b/net/mwan3/files/lib/mwan3/common.sh index 53557a6ef..4deb9bfeb 100644 --- a/net/mwan3/files/lib/mwan3/common.sh +++ b/net/mwan3/files/lib/mwan3/common.sh @@ -8,8 +8,19 @@ get_uptime() { IP4="ip -4" IP6="ip -6" SCRIPTNAME="$(basename "$0")" + +MWAN3_STATUS_DIR="/var/run/mwan3" MWAN3TRACK_STATUS_DIR="/var/run/mwan3track" +MWAN3_INTERFACE_MAX="" + +MMX_MASK="" +MMX_DEFAULT="" +MMX_BLACKHOLE="" +MM_BLACKHOLE="" + +MMX_UNREACHABLE="" +MM_UNREACHABLE="" MAX_SLEEP=$(((1<<31)-1)) LOG() @@ -21,6 +32,21 @@ LOG() [ "$facility" = "debug" ] && return logger -t "${SCRIPTNAME}[$$]" -p $facility "$*" } + +mwan3_get_true_iface() +{ + local family V + _true_iface=$2 + config_get family "$2" family ipv4 + if [ "$family" = "ipv4" ]; then + V=4 + elif [ "$family" = "ipv6" ]; then + V=6 + fi + ubus call "network.interface.${2}_${V}" status &>/dev/null && _true_iface="${2}_${V}" + export "$1=$_true_iface" +} + mwan3_get_src_ip() { local family _src_ip true_iface device addr_cmd default_ip IP sed_str @@ -149,4 +175,3 @@ mwan3_count_one_bits() done echo $count } ->>>>>>> 2a4e0dc6d... review comments diff --git a/net/mwan3/files/lib/mwan3/mwan3.sh b/net/mwan3/files/lib/mwan3/mwan3.sh index c3113007a..2a689c0c8 100644 --- a/net/mwan3/files/lib/mwan3/mwan3.sh +++ b/net/mwan3/files/lib/mwan3/mwan3.sh @@ -22,16 +22,7 @@ IPv6_REGEX="${IPv6_REGEX}::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0- IPv6_REGEX="${IPv6_REGEX}([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])" IPv4_REGEX="((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" -MWAN3_STATUS_DIR="/var/run/mwan3" -MWAN3_INTERFACE_MAX="" DEFAULT_LOWEST_METRIC=256 -MMX_MASK="" -MMX_DEFAULT="" -MMX_BLACKHOLE="" -MM_BLACKHOLE="" - -MMX_UNREACHABLE="" -MM_UNREACHABLE="" command -v ip6tables > /dev/null NO_IPV6=$? @@ -80,20 +71,6 @@ mwan3_update_iface_to_table() config_foreach update_table interface } -mwan3_get_true_iface() -{ - local family V - _true_iface=$2 - config_get family "$iface" family ipv4 - if [ "$family" = "ipv4" ]; then - V=4 - elif [ "$family" = "ipv6" ]; then - V=6 - fi - ubus call "network.interface.${iface}_${V}" status &>/dev/null && _true_iface="${iface}_${V}" - export "$1=$_true_iface" -} - mwan3_route_line_dev() { # must have mwan3 config already loaded @@ -129,63 +106,6 @@ mwan3_count_one_bits() echo $count } -# maps the 1st parameter so it only uses the bits allowed by the bitmask (2nd parameter) -# which means spreading the bits of the 1st parameter to only use the bits that are set to 1 in the 2nd parameter -# 0 0 0 0 0 1 0 1 (0x05) 1st parameter -# 1 0 1 0 1 0 1 0 (0xAA) 2nd parameter -# 1 0 1 result -mwan3_id2mask() -{ - local bit_msk bit_val result - bit_val=0 - result=0 - for bit_msk in $(seq 0 31); do - if [ $((($2>>bit_msk)&1)) = "1" ]; then - if [ $((($1>>bit_val)&1)) = "1" ]; then - result=$((result|(1< "${MWAN3_STATUS_DIR}/mmx_mask" - LOG debug "Using firewall mask ${MMX_MASK}" - - bitcnt=$(mwan3_count_one_bits MMX_MASK) - mmdefault=$(((1<&1) || LOG error "set_connected_ipv6: $error" } @@ -384,15 +300,10 @@ mwan3_set_general_iptables() -p ipv6-icmp \ -m icmp6 --icmpv6-type 137 \ -j RETURN - # do not mangle outgoing echo request - mwan3_push_update -A mwan3_hook \ - -m set --match-set mwan3_source_v6 src \ - -p ipv6-icmp \ - -m icmp6 --icmpv6-type 128 \ - -j RETURN fi mwan3_push_update -A mwan3_hook \ + -m mark --mark 0x0/$MMX_MASK \ -j CONNMARK --restore-mark --nfmask "$MMX_MASK" --ctmask "$MMX_MASK" mwan3_push_update -A mwan3_hook \ -m mark --mark 0x0/$MMX_MASK \ diff --git a/net/mwan3/files/usr/sbin/mwan3track b/net/mwan3/files/usr/sbin/mwan3track index 32b741ee2..e1f185200 100755 --- a/net/mwan3/files/usr/sbin/mwan3track +++ b/net/mwan3/files/usr/sbin/mwan3track @@ -19,6 +19,11 @@ stop_subprocs() { [ -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 @@ -58,10 +63,6 @@ validate_track_method() { LOG warn "Missing httping. Please install httping package." return 1 } - [ -n "$2" ] && { [ "$2" = "0.0.0.0" ] || [ "$2" = "::" ]; } && { - LOG warn "Cannot determine source IP for the interface which is required by httping." - return 1 - } ;; nping-*) command -v nping 1>/dev/null 2>&1 || { @@ -76,6 +77,12 @@ validate_track_method() { 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 @@ -124,17 +131,6 @@ firstconnect() { 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 @@ -159,7 +155,8 @@ 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 family track_ips + + local max_ttl httping_ssl track_ips INTERFACE=$1 STATUS="" @@ -171,9 +168,10 @@ main() { 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 $SRC_IP || { + validate_track_method $track_method || { track_method=ping if validate_track_method $track_method; then LOG warn "Using ping to track interface $INTERFACE avaliability" @@ -219,17 +217,13 @@ main() { if [ $host_up_count -lt $reliability ]; then case "$track_method" in ping) - # 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 [ $check_quality -eq 0 ]; then - $PING -${family#ipv} -I ${SOURCE} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip &> /dev/null & + WRAP $PING -${FAMILY#ipv} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip &> /dev/null & TRACK_PID=$! wait $TRACK_PID result=$? else - $PING -${family#ipv} -I ${SOURCE} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip 2>/dev/null > $TRACK_OUTPUT & + WRAP $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=$? @@ -243,23 +237,23 @@ main() { fi ;; arping) - arping -I $DEVICE -c $count -w $timeout -q $track_ip &> /dev/null & + 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 - httping -y $SRC_IP -c $count -t $timeout -q "https://$track_ip" &> /dev/null & + WRAP httping -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 & + WRAP httping -c $count -t $timeout -q "http://$track_ip" &> /dev/null & fi TRACK_PID=$! wait $TRACK_PID result=$? ;; nping-*) - nping -c $count $track_ip --${FAMILY#nping-} > $TRACK_OUTPUT & + WRAP nping -c $count $track_ip --${FAMILY#nping-} > $TRACK_OUTPUT & TRACK_PID=$! wait $TRACK_PID result=$(grep $TRACK_OUTPUT Lost | awk '{print $12}') diff --git a/net/mwan3/src/sockopt_wrap.c b/net/mwan3/src/sockopt_wrap.c new file mode 100644 index 000000000..695e57502 --- /dev/null +++ b/net/mwan3/src/sockopt_wrap.c @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Aaron Goodman . All Rights Reserved. + */ + +/* + * sockopt_wrap.c provides a shared library that intercepts syscalls to various + * networking functions to bind the sockets a source IP address and network device + * and to set the firewall mark on otugoing packets. Parameters are set using the + * DEVICE, SRCIP, FWMARK environment variables. + * + * Additionally the FAMILY environment variable can be set to either 'ipv4' or + * 'ipv6' to cause sockets opened with ipv6 or ipv4 to fail, respectively. + * + * Each environment variable is optional, and if not set, the library will not + * enforce the particular parameter. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +static int (*next_socket)(int domain, int type, int protocol); +static int (*next_setsockopt)(int sockfd, int level, int optname, + const void *optval, socklen_t optlen); +static int (*next_bind)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +static int (*next_close)(int fd); +static ssize_t (*next_send)(int sockfd, const void *buf, size_t len, int flags); +static ssize_t (*next_sendto)(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen); +static ssize_t (*next_sendmsg)(int sockfd, const struct msghdr *msg, int flags); +static int (*next_connect)(int sockfd, const struct sockaddr *addr, + socklen_t addrlen); +static int device=0; +static struct sockaddr_in source4 = {0}; +#ifdef CONFIG_IPV6 +static struct sockaddr_in6 source6 = {0}; +#endif +static struct sockaddr * source = 0; +static int sockaddr_size = 0; +static int is_bound [1024] = {0}; + +#define next_func(x)\ +void set_next_##x(){\ + if (next_##x) return;\ + next_##x = dlsym(RTLD_NEXT, #x);\ + dlerror_handle();\ + return;\ +} + +void dlerror_handle() +{ + char *msg; + if ((msg = dlerror()) != NULL) { + fprintf(stderr, "socket: dlopen failed : %s\n", msg); + fflush(stderr); + exit(EXIT_FAILURE); + } +} + +next_func(bind); +next_func(close); +next_func(setsockopt); +next_func(socket); +next_func(send); +next_func(sendto); +next_func(sendmsg); +next_func(connect); + +void dobind(int sockfd) +{ + if (source && sockfd < 1024 && !is_bound[sockfd]) { + set_next_bind(); + if (next_bind(sockfd, source, sockaddr_size)) { + perror("failed to bind to ip address"); + next_close(sockfd); + exit(EXIT_FAILURE); + } + is_bound[sockfd] = 1; + } +} + +int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + set_next_connect(); + dobind(sockfd); + return next_connect(sockfd, addr, addrlen); +} + +ssize_t send(int sockfd, const void *buf, size_t len, int flags) +{ + set_next_send(); + dobind(sockfd); + return next_send(sockfd, buf, len, flags); +} + +ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) +{ + set_next_sendto(); + dobind(sockfd); + return next_sendto(sockfd, buf, len, flags, dest_addr, addrlen); +} + +ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags) +{ + set_next_sendmsg(); + dobind(sockfd); + return next_sendmsg(sockfd, msg, flags); +} + +int bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + set_next_bind(); + if (device && addr->sa_family == AF_PACKET) { + ((struct sockaddr_ll*)addr)->sll_ifindex=device; + } + else if (source && addr->sa_family == AF_INET) { + ((struct sockaddr_in*)addr)->sin_addr = source4.sin_addr; + } +#ifdef CONFIG_IPV6 + else if (source && addr->sa_family == AF_INET6) { + ((struct sockaddr_in6*)addr)->sin6_addr = source6.sin6_addr; + } +#endif + if (sockfd < 1024) + is_bound[sockfd] = 1; + return next_bind(sockfd, addr, addrlen); +} + +int close (int sockfd) +{ + set_next_close(); + if (sockfd < 1024) + is_bound[sockfd]=0; + return next_close(sockfd); +} + +int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) +{ + set_next_setsockopt(); + if (level == SOL_SOCKET && (optname == SO_MARK || optname == SO_BINDTODEVICE)) + return 0; + return next_setsockopt(sockfd, level, optname, optval, optlen); +} + +int socket(int domain, int type, int protocol) +{ + int handle; + + const char *socket_str = getenv("DEVICE"); + const char *srcip_str = getenv("SRCIP"); + const char *fwmark_str = getenv("FWMARK"); + const char *family_str = getenv("FAMILY"); + const int iface_len = socket_str ? strnlen(socket_str, IFNAMSIZ) : 0; + int has_family = family_str && *family_str != 0; + int has_srcip = srcip_str && *srcip_str != 0; + const int fwmark = fwmark_str ? (int)strtol(fwmark_str, NULL, 0) : 0; + + set_next_close(); + set_next_socket(); + set_next_send(); + set_next_setsockopt(); + set_next_sendmsg(); + set_next_sendto(); + set_next_connect(); + if(has_family) { +#ifdef CONFIG_IPV6 + if(domain == AF_INET && strncmp(family_str,"ipv6",4) == 0) + return -1; +#endif + if(domain == AF_INET6 && strncmp(family_str,"ipv4",4) == 0) + return -1; + } + + if (domain != AF_INET +#ifdef CONFIG_IPV6 + && domain != AF_INET6 +#endif + ) { + return next_socket(domain, type, protocol); + } + + + if (iface_len > 0) { + if (iface_len == IFNAMSIZ) { + fprintf(stderr,"socket: Too long iface name\n"); + fflush(stderr); + exit(EXIT_FAILURE); + } + } + + if (has_srcip) { + int s; + void * addr_buf; + if (domain == AF_INET) { + addr_buf = &source4.sin_addr; + sockaddr_size=sizeof source4; + memset(&source4, 0, sockaddr_size); + source4.sin_family = domain; + source = (struct sockaddr*)&source4; + } +#ifdef CONFIG_IPV6 + else { + addr_buf = &source6.sin6_addr; + sockaddr_size=sizeof source6; + memset(&source6, 0, sockaddr_size); + source6.sin6_family=domain; + source = (struct sockaddr*)&source6; + } +#endif + s = inet_pton(domain, srcip_str, addr_buf); + if (s == 0) { + fprintf(stderr, "socket: ip address invalid format for family %s\n", + domain == AF_INET ? "AF_INET" : domain == AF_INET6 ? + "AF_INET6" : "unknown"); + return -1; + } + if (s < 0) { + perror("inet_pton"); + exit(EXIT_FAILURE); + } + } + + handle = next_socket(domain, type, protocol); + if (handle == -1 ) { + return handle; + } + + if (iface_len > 0) { + device=if_nametoindex(socket_str); + if (next_setsockopt(handle, SOL_SOCKET, SO_BINDTODEVICE, + socket_str, iface_len + 1)) { + perror("socket: setting interface name failed with error"); + next_close(handle); + exit(EXIT_FAILURE); + } + } + + if (fwmark > 0) { + if (next_setsockopt(handle, SOL_SOCKET, SO_MARK, + &fwmark, sizeof fwmark)) { + perror("failed setting mark for socket"); + next_close(handle); + exit(EXIT_FAILURE); + } + } + return handle; +} From d49ca29eca7c1ccc930ceceda1c8086c3cfaa198 Mon Sep 17 00:00:00 2001 From: Aaron Goodman Date: Tue, 25 Aug 2020 18:16:07 -0400 Subject: [PATCH 09/12] mwan3: add "use" function to mwan3 utils Use "mwan3 use" to wrap a command with interface bindings so that you can avoid the mwan3 rules and test behavior on a specific interface. eg "mwan3 use wan ping -c1 1.1.1.1" Additional binding arguments to the command will have their system calls intercepted and ignored. eg "mwan3 use wan ping -c1 -I tun0 1.1.1.1" will use the device associated with "wan", rather than "tun0". Signed-off-by: Aaron Goodman --- net/mwan3/files/lib/mwan3/common.sh | 8 +++-- net/mwan3/files/usr/sbin/mwan3 | 49 ++++++++++++++++++++++------- net/mwan3/files/usr/sbin/mwan3track | 4 +-- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/net/mwan3/files/lib/mwan3/common.sh b/net/mwan3/files/lib/mwan3/common.sh index 4deb9bfeb..daa4b2abc 100644 --- a/net/mwan3/files/lib/mwan3/common.sh +++ b/net/mwan3/files/lib/mwan3/common.sh @@ -49,10 +49,12 @@ mwan3_get_true_iface() mwan3_get_src_ip() { - local family _src_ip true_iface device addr_cmd default_ip IP sed_str - true_iface=$2 + local family _src_ip interface true_iface device addr_cmd default_ip IP sed_str + interface=$2 + mwan3_get_true_iface true_iface $interface + unset "$1" - config_get family "$true_iface" family ipv4 + config_get family "$interface" family ipv4 if [ "$family" = "ipv4" ]; then addr_cmd='network_get_ipaddr' default_ip="0.0.0.0" diff --git a/net/mwan3/files/usr/sbin/mwan3 b/net/mwan3/files/usr/sbin/mwan3 index cbd79e9ea..0251607a0 100755 --- a/net/mwan3/files/usr/sbin/mwan3 +++ b/net/mwan3/files/usr/sbin/mwan3 @@ -12,17 +12,17 @@ help() Syntax: mwan3 [command] Available commands: - start Load iptables rules, ip rules and ip routes - stop Unload iptables rules, ip rules and ip routes - restart Reload iptables rules, ip rules and ip routes - ifup Load rules and routes for specific interface - ifdown Unload rules and routes for specific interface - interfaces Show interfaces status - policies Show currently active policy - connected Show directly connected networks - rules Show active rules - status Show all status - + start Load iptables rules, ip rules and ip routes + stop Unload iptables rules, ip rules and ip routes + restart Reload iptables rules, ip rules and ip routes + ifup Load rules and routes for specific interface + ifdown Unload rules and routes for specific interface + interfaces Show interfaces status + policies Show currently active policy + connected Show directly connected networks + rules Show active rules + status Show all status + use Run a command bound to and avoid mwan3 rules EOF } @@ -123,8 +123,33 @@ restart() { /etc/init.d/mwan3 start } +wrap() { + # Run a command with the device, src_ip and fwmark set to avoid processing by mwan3 + # firewall rules + + local interface device src_ip family + mwan3_init + config_load mwan3 + + interface=$1 ; shift + [ -z "$*" ] && echo "no command specified for mwan3 wrap" && return + network_get_device device $interface + [ -z "$device" ] && echo "could not find device for $interface" && return + + mwan3_get_src_ip src_ip $interface + [ -z "$src_ip" ] && echo "could not find src_ip for $interface" && return + + config_get family $interface family + [ -z "$family" ] && echo "could not find family for $interface. Using ipv4." && family='ipv4' + + echo "Running '$*' with DEVICE=$device SRCIP=$src_ip FWMARK=$MMX_DEFAULT FAMILY=$family" + # shellcheck disable=SC2048 + FAMILY=$family DEVICE=$device SRCIP=$src_ip FWMARK=$MMX_DEFAULT LD_PRELOAD=/lib/mwan3/libwrap_mwan3_sockopt.so.1.0 $* + +} + case "$1" in - ifup|ifdown|interfaces|policies|connected|rules|status|start|stop|restart) + ifup|ifdown|interfaces|policies|connected|rules|status|start|stop|restart|use) mwan3_init # shellcheck disable=SC2048 $* diff --git a/net/mwan3/files/usr/sbin/mwan3track b/net/mwan3/files/usr/sbin/mwan3track index e1f185200..288fcd35e 100755 --- a/net/mwan3/files/usr/sbin/mwan3track +++ b/net/mwan3/files/usr/sbin/mwan3track @@ -129,7 +129,7 @@ firstconnect() { return fi - mwan3_get_src_ip SRC_IP $true_iface + mwan3_get_src_ip SRC_IP $INTERFACE LOG debug "firstconnect: called on $INTERFACE/$true_iface ($DEVICE). Status is $STATUS. SRC_IP is $SRC_IP" @@ -223,7 +223,7 @@ main() { wait $TRACK_PID result=$? else - WRAP $PING -${family#ipv} -I ${SOURCE} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip 2>/dev/null > $TRACK_OUTPUT & + WRAP $PING -${family#ipv} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip 2>/dev/null > $TRACK_OUTPUT & TRACK_PID=$! wait $TRACK_PID ping_status=$? From 1990a90702515aead6412749fb6aafb21136112d Mon Sep 17 00:00:00 2001 From: Aaron Goodman Date: Sun, 11 Oct 2020 18:43:56 -0400 Subject: [PATCH 10/12] mwan3: add back support for iputils ping With the new wrapper code, we can override the broken binding behavior of iputils ping v20101006. Signed-off-by: Aaron Goodman --- net/mwan3/files/usr/sbin/mwan3track | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/net/mwan3/files/usr/sbin/mwan3track b/net/mwan3/files/usr/sbin/mwan3track index 288fcd35e..8334209fe 100755 --- a/net/mwan3/files/usr/sbin/mwan3track +++ b/net/mwan3/files/usr/sbin/mwan3track @@ -6,7 +6,6 @@ INTERFACE="" DEVICE="" -PING="/bin/ping" IFDOWN_EVENT=0 IFUP_EVENT=0 @@ -47,10 +46,19 @@ if_up() { validate_track_method() { case "$1" in ping) - [ -x "$PING" ] || { - LOG warn "Missing ping. Please enable ping util and recompile busybox." + if [ -x "/usr/bin/ping" ] && [ "$(/usr/bin/ping -V | grep -o '[0-9]*$')" -gt 20150519 ]; then + # -4 option added in iputils c3e68ac6 + PING="/usr/bin/ping -${FAMILY#ipv}" + elif [ "$FAMILY" = "ipv6" ] && [ -x "/usr/bin/ping6" ]; then + PING="/usr/bin/ping6" + elif [ "$FAMILY" = "ipv4" ] && [ -x "/usr/bin/ping" ]; then + PING="/usr/bin/ping" + elif [ -x "/bin/ping" ]; then + PING="/bin/ping -${FAMILY#ipv}" + else + 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 || { @@ -218,12 +226,12 @@ main() { case "$track_method" in ping) if [ $check_quality -eq 0 ]; then - WRAP $PING -${FAMILY#ipv} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip &> /dev/null & + 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 -${family#ipv} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip 2>/dev/null > $TRACK_OUTPUT & + 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=$? From 41d5f486ee640f8f70e3b06cdc47ec36563bfb99 Mon Sep 17 00:00:00 2001 From: Aaron Goodman Date: Wed, 9 Sep 2020 02:21:25 -0400 Subject: [PATCH 11/12] mwan3: cleanup mwan3track - reduce duplicate logging code - simplify nping track code - simplify ping result parsing Signed-off-by: Aaron Goodman --- net/mwan3/files/usr/sbin/mwan3track | 30 ++++++++++++----------------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/net/mwan3/files/usr/sbin/mwan3track b/net/mwan3/files/usr/sbin/mwan3track index 8334209fe..b771e8fce 100755 --- a/net/mwan3/files/usr/sbin/mwan3track +++ b/net/mwan3/files/usr/sbin/mwan3track @@ -164,7 +164,7 @@ main() { local keep_failure_interval check_quality failure_latency local recovery_latency failure_loss recovery_loss - local max_ttl httping_ssl track_ips + local max_ttl httping_ssl track_ips do_log INTERFACE=$1 STATUS="" @@ -235,12 +235,12 @@ main() { TRACK_PID=$! wait $TRACK_PID ping_status=$? - loss=$(grep $TRACK_OUTPUT "packet loss" | cut -d "," -f3 | awk '{print $1}' | sed -e 's/%//') + 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="$(grep $TRACK_OUTPUT -E 'rtt|round-trip' | cut -d "=" -f2 | cut -d "/" -f2 | cut -d "." -f1)" + latency="$(sed $TRACK_OUTPUT -ne 's%\(rtt\|round-trip\).* = [^/]*/\([0-9]\+\).*%\2%p')" fi fi ;; @@ -267,40 +267,36 @@ main() { 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" - if [ $score -le $up ]; then - LOG info "Check ($track_method) success for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score" - fi + [ $score -le $up ] && do_log="success" else let lost++ update_status "$track_ip" "down" - if [ $score -gt $up ]; then - LOG info "Check ($track_method) failed for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score" - fi + [ $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 - if [ $score -gt $up ]; then - LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) failed for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score" - fi + [ $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 - if [ $score -le $up ]; then - LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) success for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score" - fi + [ $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} @@ -312,9 +308,7 @@ main() { if [ $score -lt $up ]; then score=0 - [ ${keep_failure_interval} -eq 1 ] && { - sleep_time=$failure_interval - } + [ ${keep_failure_interval} -eq 1 ] && sleep_time=$failure_interval else sleep_time=$failure_interval fi From 14d62d6599d02adb7dc6efa3e5cb239eda7bc80a Mon Sep 17 00:00:00 2001 From: James White Date: Tue, 22 Sep 2020 15:18:05 +0100 Subject: [PATCH 12/12] mwan3: Simplify default configuration, mostly use defaults Signed-off-by: James White --- net/mwan3/files/etc/config/mwan3 | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/net/mwan3/files/etc/config/mwan3 b/net/mwan3/files/etc/config/mwan3 index 926719a3c..54c449fdf 100644 --- a/net/mwan3/files/etc/config/mwan3 +++ b/net/mwan3/files/etc/config/mwan3 @@ -1,3 +1,5 @@ +# For full documentation of mwan3 configuration: +# https://openwrt.org/docs/guide-user/network/wan/multiwan/mwan3#mwan3_configuration config globals 'globals' option mmx_mask '0x3F00' @@ -10,15 +12,6 @@ config interface 'wan' list track_ip '208.67.220.220' option family 'ipv4' option reliability '2' - option count '1' - option timeout '2' - option failure_latency '1000' - option recovery_latency '500' - option failure_loss '20' - option recovery_loss '5' - option interval '5' - option down '3' - option up '8' config interface 'wan6' option enabled '0' @@ -28,11 +21,6 @@ config interface 'wan6' list track_ip '2620:0:ccc::2' option family 'ipv6' option reliability '2' - option count '1' - option timeout '2' - option interval '5' - option down '3' - option up '8' config interface 'wanb' option enabled '0' @@ -42,15 +30,6 @@ config interface 'wanb' list track_ip '208.67.220.220' option family 'ipv4' option reliability '1' - option count '1' - option timeout '2' - option failure_latency '1000' - option recovery_latency '500' - option failure_loss '20' - option recovery_loss '5' - option interval '5' - option down '3' - option up '8' config interface 'wanb6' option enabled '0' @@ -60,11 +39,6 @@ config interface 'wanb6' list track_ip '2620:0:ccc::2' option family 'ipv6' option reliability '1' - option count '1' - option timeout '2' - option interval '5' - option down '3' - option up '8' config member 'wan_m1_w3' option interface 'wan'