diff options
author | Aaron Goodman <aaronjg@stanford.edu> | 2020-10-11 18:37:25 -0400 |
---|---|---|
committer | Aaron Goodman <aaronjg@stanford.edu> | 2020-10-16 09:54:48 -0400 |
commit | bbbc6127abf132a92cc73dd23fa88409dc2b9abd (patch) | |
tree | b0e0de516771222523a601f4cd6c1063e30bacb7 /net/mwan3/files | |
parent | fb4a2d99eff3af53d4eea2db36d270a140bde6bf (diff) |
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 <aaronjg@stanford.edu>
Diffstat (limited to 'net/mwan3/files')
-rw-r--r-- | net/mwan3/files/lib/mwan3/common.sh | 27 | ||||
-rw-r--r-- | net/mwan3/files/lib/mwan3/mwan3.sh | 93 | ||||
-rwxr-xr-x | net/mwan3/files/usr/sbin/mwan3track | 48 |
3 files changed, 49 insertions, 119 deletions
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<<bit_msk))) - fi - bit_val=$((bit_val+1)) - fi - done - printf "0x%x" $result -} - -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<<bitcnt)-1)) - MWAN3_INTERFACE_MAX=$((mmdefault-3)) - uci_toggle_state mwan3 globals iface_max "$MWAN3_INTERFACE_MAX" - LOG debug "Max interface count is ${MWAN3_INTERFACE_MAX}" - fi - - # mark mask constants - bitcnt=$(mwan3_count_one_bits MMX_MASK) - mmdefault=$(((1<<bitcnt)-1)) - MM_BLACKHOLE=$((mmdefault-2)) - MM_UNREACHABLE=$((mmdefault-1)) - - # MMX_DEFAULT should equal MMX_MASK - MMX_DEFAULT=$(mwan3_id2mask mmdefault MMX_MASK) - MMX_BLACKHOLE=$(mwan3_id2mask MM_BLACKHOLE MMX_MASK) - MMX_UNREACHABLE=$(mwan3_id2mask MM_UNREACHABLE MMX_MASK) -} - mwan3_lock() { lock /var/run/mwan3.lock #LOG debug "$1 $2 (lock)" @@ -281,7 +201,7 @@ mwan3_set_connected_ipv4() mwan3_set_connected_ipv6() { - local connected_network_v6 source_network_v6 error + local connected_network_v6 error local update="" [ $NO_IPV6 -eq 0 ] || return @@ -292,10 +212,6 @@ mwan3_set_connected_ipv6() 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 -! add mwan3_connected mwan3_connected_v6 error=$(echo "$update" | $IPS restore 2>&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}') |