Merge pull request #13169 from aaronjg/mwan3-owner-procd
mwan3: mwan3track via default routing table and use procd from mwan3track & mwan3rtmon
This commit is contained in:
commit
9485b9401d
12 changed files with 1097 additions and 751 deletions
|
@ -8,10 +8,11 @@
|
||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=mwan3
|
PKG_NAME:=mwan3
|
||||||
PKG_VERSION:=2.9.0
|
PKG_VERSION:=2.10.0
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
PKG_MAINTAINER:=Florian Eckert <fe@dev.tdt.de>
|
PKG_MAINTAINER:=Florian Eckert <fe@dev.tdt.de>
|
||||||
PKG_LICENSE:=GPL-2.0
|
PKG_LICENSE:=GPL-2.0
|
||||||
|
PKG_CONFIG_DEPENDS:=CONFIG_IPV6
|
||||||
|
|
||||||
include $(INCLUDE_DIR)/package.mk
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
|
||||||
|
@ -61,8 +62,13 @@ fi
|
||||||
exit 0
|
exit 0
|
||||||
endef
|
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
|
define Package/mwan3/install
|
||||||
$(CP) ./files/* $(1)
|
$(CP) ./files/* $(1)
|
||||||
|
$(CP) $(PKG_BUILD_DIR)/libwrap_mwan3_sockopt.so.1.0 $(1)/lib/mwan3/
|
||||||
endef
|
endef
|
||||||
|
|
||||||
$(eval $(call BuildPackage,mwan3))
|
$(eval $(call BuildPackage,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'
|
config globals 'globals'
|
||||||
option mmx_mask '0x3F00'
|
option mmx_mask '0x3F00'
|
||||||
|
@ -10,15 +12,6 @@ config interface 'wan'
|
||||||
list track_ip '208.67.220.220'
|
list track_ip '208.67.220.220'
|
||||||
option family 'ipv4'
|
option family 'ipv4'
|
||||||
option reliability '2'
|
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'
|
config interface 'wan6'
|
||||||
option enabled '0'
|
option enabled '0'
|
||||||
|
@ -28,11 +21,6 @@ config interface 'wan6'
|
||||||
list track_ip '2620:0:ccc::2'
|
list track_ip '2620:0:ccc::2'
|
||||||
option family 'ipv6'
|
option family 'ipv6'
|
||||||
option reliability '2'
|
option reliability '2'
|
||||||
option count '1'
|
|
||||||
option timeout '2'
|
|
||||||
option interval '5'
|
|
||||||
option down '3'
|
|
||||||
option up '8'
|
|
||||||
|
|
||||||
config interface 'wanb'
|
config interface 'wanb'
|
||||||
option enabled '0'
|
option enabled '0'
|
||||||
|
@ -42,15 +30,6 @@ config interface 'wanb'
|
||||||
list track_ip '208.67.220.220'
|
list track_ip '208.67.220.220'
|
||||||
option family 'ipv4'
|
option family 'ipv4'
|
||||||
option reliability '1'
|
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'
|
config interface 'wanb6'
|
||||||
option enabled '0'
|
option enabled '0'
|
||||||
|
@ -60,11 +39,6 @@ config interface 'wanb6'
|
||||||
list track_ip '2620:0:ccc::2'
|
list track_ip '2620:0:ccc::2'
|
||||||
option family 'ipv6'
|
option family 'ipv6'
|
||||||
option reliability '1'
|
option reliability '1'
|
||||||
option count '1'
|
|
||||||
option timeout '2'
|
|
||||||
option interval '5'
|
|
||||||
option down '3'
|
|
||||||
option up '8'
|
|
||||||
|
|
||||||
config member 'wan_m1_w3'
|
config member 'wan_m1_w3'
|
||||||
option interface 'wan'
|
option interface 'wan'
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
SCRIPTNAME="mwan3-hotplug"
|
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
|
[ -n "$INTERFACE" ] || exit 2
|
||||||
if ( [ "$ACTION" = "ifup" ] || [ "$ACTION" = "connected" ] ) && [ -z "$DEVICE" ]; then
|
[ "$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"
|
LOG notice "$ACTION called on $INTERFACE with no device set"
|
||||||
exit 3
|
exit 3
|
||||||
fi
|
fi
|
||||||
|
@ -17,10 +19,9 @@ fi
|
||||||
[ "$MWAN3_STARTUP" = 1 ] || mwan3_lock "$ACTION" "$INTERFACE"
|
[ "$MWAN3_STARTUP" = 1 ] || mwan3_lock "$ACTION" "$INTERFACE"
|
||||||
|
|
||||||
config_load mwan3
|
config_load mwan3
|
||||||
config_get_bool enabled globals 'enabled' '0'
|
/etc/init.d/mwan3 running || {
|
||||||
[ "${enabled}" -gt 0 ] || {
|
|
||||||
[ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$INTERFACE"
|
[ "$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"
|
mwan3_flush_conntrack "$INTERFACE" "$ACTION"
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
@ -33,15 +34,14 @@ $IPT4 -S mwan3_hook &>/dev/null || {
|
||||||
|
|
||||||
mwan3_init
|
mwan3_init
|
||||||
[ "$MWAN3_STARTUP" = 1 ] || {
|
[ "$MWAN3_STARTUP" = 1 ] || {
|
||||||
mwan3_set_connected_iptables
|
config_get family $INTERFACE family ipv4
|
||||||
mwan3_set_custom_ipset
|
mwan3_set_connected_${family}
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ "$MWAN3_STARTUP" != 1 ]; then
|
if [ "$MWAN3_STARTUP" != 1 ] && [ "$ACTION" = "ifup" ]; then
|
||||||
mwan3_set_user_iface_rules $INTERFACE $DEVICE
|
mwan3_set_user_iface_rules $INTERFACE $DEVICE
|
||||||
fi
|
fi
|
||||||
|
|
||||||
config_get initial_state $INTERFACE initial_state "online"
|
|
||||||
config_get_bool enabled $INTERFACE 'enabled' '0'
|
config_get_bool enabled $INTERFACE 'enabled' '0'
|
||||||
[ "${enabled}" -eq 1 ] || {
|
[ "${enabled}" -eq 1 ] || {
|
||||||
[ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$INTERFACE"
|
[ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$INTERFACE"
|
||||||
|
@ -49,54 +49,47 @@ config_get_bool enabled $INTERFACE 'enabled' '0'
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
trackpid=$(pgrep -f "mwan3track $INTERFACE ")
|
config_get initial_state $INTERFACE initial_state "online"
|
||||||
|
|
||||||
if [ "$initial_state" = "offline" ]; then
|
if [ "$initial_state" = "offline" ]; then
|
||||||
status=$(cat $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS 2>/dev/null || echo unknown)
|
status=$(cat $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS 2>/dev/null || echo unknown)
|
||||||
|
[ "$status" = "online" ] || status=offline
|
||||||
else
|
else
|
||||||
status=online
|
status=online
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ -z "$TRUE_INTERFACE" ] && mwan3_get_true_iface TRUE_INTERFACE $INTERFACE
|
if [ "$ACTION" = ifup ] || [ "$ACTION" = ifdown ]; then
|
||||||
|
initscript=/etc/init.d/mwan3
|
||||||
|
. /lib/functions/procd.sh
|
||||||
|
fi
|
||||||
|
|
||||||
binary_status=$status
|
LOG notice "Execute $ACTION event on interface $INTERFACE (${DEVICE:-unknown})"
|
||||||
[ "$binary_status" = "online" ] || binary_status=offline
|
|
||||||
|
|
||||||
LOG notice "Execute "$ACTION" event on interface $INTERFACE (${DEVICE:-unknown})"
|
|
||||||
|
|
||||||
case "$ACTION" in
|
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_iptables $INTERFACE $DEVICE
|
||||||
mwan3_create_iface_rules $INTERFACE $DEVICE
|
mwan3_create_iface_rules $INTERFACE $DEVICE
|
||||||
|
mwan3_set_iface_hotplug_state $INTERFACE "$status"
|
||||||
|
if [ "$MWAN3_STARTUP" != 1 ]; then
|
||||||
mwan3_create_iface_route $INTERFACE $DEVICE
|
mwan3_create_iface_route $INTERFACE $DEVICE
|
||||||
[ "$MWAN3_STARTUP" != 1 ] && mwan3_add_non_default_iface_route $INTERFACE $DEVICE
|
[ "$status" = "online" ] && mwan3_set_policies_iptables
|
||||||
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
|
fi
|
||||||
else
|
[ "$ACTION" = ifup ] && procd_running mwan3 "track_$INTERFACE" && procd_send_signal mwan3 "track_$INTERFACE" USR2
|
||||||
mwan3_track $INTERFACE $DEVICE "$binary_status" "$src_ip"
|
|
||||||
LOG notice "Started tracker [$!] on interface $INTERFACE (${DEVICE:-unknown})"
|
|
||||||
fi
|
|
||||||
[ "$MWAN3_STARTUP" != 1 ] && [ "$binary_status" == "online" ] && mwan3_set_policies_iptables
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
ifdown|disconnected)
|
disconnected)
|
||||||
|
mwan3_set_iface_hotplug_state $INTERFACE "offline"
|
||||||
|
mwan3_set_policies_iptables
|
||||||
|
;;
|
||||||
|
ifdown)
|
||||||
mwan3_set_iface_hotplug_state $INTERFACE "offline"
|
mwan3_set_iface_hotplug_state $INTERFACE "offline"
|
||||||
mwan3_delete_iface_ipset_entries $INTERFACE
|
mwan3_delete_iface_ipset_entries $INTERFACE
|
||||||
mwan3_delete_iface_rules $INTERFACE
|
mwan3_delete_iface_rules $INTERFACE
|
||||||
mwan3_delete_iface_route $INTERFACE
|
mwan3_delete_iface_route $INTERFACE
|
||||||
mwan3_delete_iface_iptables $INTERFACE
|
mwan3_delete_iface_iptables $INTERFACE
|
||||||
if [ "$ACTION" = "ifdown" ]; then
|
procd_running mwan3 "track_$INTERFACE" && procd_send_signal mwan3 "track_$INTERFACE" USR1
|
||||||
[ -n "$trackpid" ] && kill -USR1 "$trackpid"
|
|
||||||
fi
|
|
||||||
mwan3_set_policies_iptables
|
mwan3_set_policies_iptables
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -4,22 +4,22 @@
|
||||||
. /lib/functions.sh
|
. /lib/functions.sh
|
||||||
. /lib/mwan3/mwan3.sh
|
. /lib/mwan3/mwan3.sh
|
||||||
|
|
||||||
[ "$MWAN3_STARTUP" = 1 ] || mwan3_lock "$ACTION" "$DEVICE-user"
|
[ "$MWAN3_SHUTDOWN" != 1 ] && mwan3_lock "$ACTION" "$DEVICE-user"
|
||||||
|
|
||||||
config_load mwan3
|
[ "$MWAN3_SHUTDOWN" != 1 ] && ! /etc/init.d/mwan3 running && {
|
||||||
config_get_bool enabled globals 'enabled' '0'
|
mwan3_unlock "$ACTION" "$DEVICE-user"
|
||||||
[ "${enabled}" -gt 0 ] || {
|
|
||||||
[ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$DEVICE-user"
|
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config_load mwan3
|
||||||
|
|
||||||
config_get_bool enabled "$INTERFACE" enabled 0
|
config_get_bool enabled "$INTERFACE" enabled 0
|
||||||
[ "${enabled}" -eq 1 ] || {
|
[ "${enabled}" -eq 1 ] || {
|
||||||
[ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$DEVICE-user"
|
[ "$MWAN3_SHUTDOWN" != 1 ] && mwan3_unlock "$ACTION" "$DEVICE-user"
|
||||||
exit 0
|
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" \
|
env -i ACTION="$ACTION" INTERFACE="$INTERFACE" DEVICE="$DEVICE" \
|
||||||
/bin/sh /etc/mwan3.user
|
/bin/sh /etc/mwan3.user
|
||||||
|
|
|
@ -1,31 +1,114 @@
|
||||||
#!/bin/sh /etc/rc.common
|
#!/bin/sh /etc/rc.common
|
||||||
|
|
||||||
|
. /lib/functions.sh
|
||||||
|
. /lib/mwan3/common.sh
|
||||||
|
. /lib/functions/network.sh
|
||||||
|
. /lib/mwan3/mwan3.sh
|
||||||
|
|
||||||
START=19
|
START=19
|
||||||
USE_PROCD=1
|
USE_PROCD=1
|
||||||
|
|
||||||
boot() {
|
service_running() {
|
||||||
. /lib/config/uci.sh
|
[ -d "$MWAN3_STATUS_DIR" ]
|
||||||
# disabled until mwan3 start runs so hotplug scripts
|
|
||||||
# do not start prematurely
|
|
||||||
uci_toggle_state mwan3 globals enabled "0"
|
|
||||||
rc_procd start_service
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# FIXME
|
start_tracker() {
|
||||||
# fd 1000 is an inherited lock file descriptor for preventing concurrent
|
local enabled interface
|
||||||
# init script executions. Close it here to prevent the mwan3 daemon from
|
interface=$1
|
||||||
# inheriting it further to avoid holding the lock indefinitely.
|
config_get_bool enabled $interface 'enabled' '0'
|
||||||
|
[ $enabled -eq 0 ] && return
|
||||||
|
|
||||||
reload_service() {
|
procd_open_instance "track_${1}"
|
||||||
/usr/sbin/mwan3 restart 1000>&-
|
procd_set_param command /usr/sbin/mwan3track $interface
|
||||||
|
procd_set_param respawn
|
||||||
|
procd_close_instance
|
||||||
}
|
}
|
||||||
|
|
||||||
start_service() {
|
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() {
|
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() {
|
service_triggers() {
|
||||||
|
|
|
@ -5,7 +5,24 @@ get_uptime() {
|
||||||
echo "${uptime%%.*}"
|
echo "${uptime%%.*}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IP4="ip -4"
|
||||||
|
IP6="ip -6"
|
||||||
SCRIPTNAME="$(basename "$0")"
|
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()
|
LOG()
|
||||||
{
|
{
|
||||||
local facility=$1; shift
|
local facility=$1; shift
|
||||||
|
@ -13,5 +30,150 @@ LOG()
|
||||||
# when this release is out of beta, the comment in the line below
|
# when this release is out of beta, the comment in the line below
|
||||||
# should be removed
|
# should be removed
|
||||||
[ "$facility" = "debug" ] && return
|
[ "$facility" = "debug" ] && return
|
||||||
logger -t "$SCRIPTNAME[$$]" -p $facility "$*"
|
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 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 "$interface" 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<<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)
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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
|
||||||
|
}
|
||||||
|
|
||||||
|
# counts how many bits are set to 1
|
||||||
|
# n&(n-1) clears the lowest bit set to 1
|
||||||
|
mwan3_count_one_bits()
|
||||||
|
{
|
||||||
|
local count n
|
||||||
|
count=0
|
||||||
|
n=$(($1))
|
||||||
|
while [ "$n" -gt "0" ]; do
|
||||||
|
n=$((n&(n-1)))
|
||||||
|
count=$((count+1))
|
||||||
|
done
|
||||||
|
echo $count
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
. /usr/share/libubox/jshn.sh
|
. /usr/share/libubox/jshn.sh
|
||||||
|
|
||||||
IP4="ip -4"
|
|
||||||
IP6="ip -6"
|
|
||||||
IPS="ipset"
|
IPS="ipset"
|
||||||
IPT4="iptables -t mangle -w"
|
IPT4="iptables -t mangle -w"
|
||||||
IPT6="ip6tables -t mangle -w"
|
IPT6="ip6tables -t mangle -w"
|
||||||
|
@ -22,18 +20,9 @@ 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}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}::(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])"
|
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"
|
|
||||||
MWAN3TRACK_STATUS_DIR="/var/run/mwan3track"
|
|
||||||
MWAN3_INTERFACE_MAX=""
|
|
||||||
DEFAULT_LOWEST_METRIC=256
|
DEFAULT_LOWEST_METRIC=256
|
||||||
MMX_MASK=""
|
|
||||||
MMX_DEFAULT=""
|
|
||||||
MMX_BLACKHOLE=""
|
|
||||||
MM_BLACKHOLE=""
|
|
||||||
|
|
||||||
MMX_UNREACHABLE=""
|
|
||||||
MM_UNREACHABLE=""
|
|
||||||
|
|
||||||
command -v ip6tables > /dev/null
|
command -v ip6tables > /dev/null
|
||||||
NO_IPV6=$?
|
NO_IPV6=$?
|
||||||
|
@ -43,14 +32,15 @@ mwan3_push_update()
|
||||||
# helper function to build an update string to pass on to
|
# helper function to build an update string to pass on to
|
||||||
# IPTR or IPS RESTORE. Modifies the 'update' variable in
|
# IPTR or IPS RESTORE. Modifies the 'update' variable in
|
||||||
# the local scope.
|
# the local scope.
|
||||||
update="$update
|
update="$update"$'\n'"$*";
|
||||||
$*";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mwan3_update_dev_to_table()
|
mwan3_update_dev_to_table()
|
||||||
{
|
{
|
||||||
local _tid
|
local _tid
|
||||||
|
# shellcheck disable=SC2034
|
||||||
mwan3_dev_tbl_ipv4=" "
|
mwan3_dev_tbl_ipv4=" "
|
||||||
|
# shellcheck disable=SC2034
|
||||||
mwan3_dev_tbl_ipv6=" "
|
mwan3_dev_tbl_ipv6=" "
|
||||||
|
|
||||||
update_table()
|
update_table()
|
||||||
|
@ -81,20 +71,6 @@ mwan3_update_iface_to_table()
|
||||||
config_foreach update_table interface
|
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()
|
mwan3_route_line_dev()
|
||||||
{
|
{
|
||||||
# must have mwan3 config already loaded
|
# must have mwan3 config already loaded
|
||||||
|
@ -130,63 +106,6 @@ mwan3_count_one_bits()
|
||||||
echo $count
|
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() {
|
mwan3_lock() {
|
||||||
lock /var/run/mwan3.lock
|
lock /var/run/mwan3.lock
|
||||||
#LOG debug "$1 $2 (lock)"
|
#LOG debug "$1 $2 (lock)"
|
||||||
|
@ -197,22 +116,6 @@ mwan3_unlock() {
|
||||||
lock -u /var/run/mwan3.lock
|
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()
|
mwan3_get_iface_id()
|
||||||
{
|
{
|
||||||
local _tmp
|
local _tmp
|
||||||
|
@ -220,14 +123,13 @@ mwan3_get_iface_id()
|
||||||
_tmp="${mwan3_iface_tbl##* ${2}=}"
|
_tmp="${mwan3_iface_tbl##* ${2}=}"
|
||||||
_tmp=${_tmp%% *}
|
_tmp=${_tmp%% *}
|
||||||
export "$1=$_tmp"
|
export "$1=$_tmp"
|
||||||
new_val=$_tmp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mwan3_set_custom_ipset_v4()
|
mwan3_set_custom_ipset_v4()
|
||||||
{
|
{
|
||||||
local custom_network_v4
|
local custom_network_v4
|
||||||
|
|
||||||
for custom_network_v4 in $($IP4 route list table "$1" | awk '{print $1}' | egrep '[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"
|
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"
|
mwan3_push_update -! add mwan3_custom_v4 "$custom_network_v4"
|
||||||
done
|
done
|
||||||
|
@ -237,7 +139,7 @@ mwan3_set_custom_ipset_v6()
|
||||||
{
|
{
|
||||||
local custom_network_v6
|
local custom_network_v6
|
||||||
|
|
||||||
for custom_network_v6 in $($IP6 route list table "$1" | awk '{print $1}' | egrep "$IPv6_REGEX"); do
|
for custom_network_v6 in $($IP6 route list table "$1" | awk '{print $1}' | grep -E "$IPv6_REGEX"); do
|
||||||
LOG notice "Adding network $custom_network_v6 from table $1 to mwan3_custom_v6 ipset"
|
LOG notice "Adding network $custom_network_v6 from table $1 to mwan3_custom_v6 ipset"
|
||||||
mwan3_push_update -! add mwan3_custom_v6 "$custom_network_v6"
|
mwan3_push_update -! add mwan3_custom_v6 "$custom_network_v6"
|
||||||
done
|
done
|
||||||
|
@ -263,7 +165,6 @@ mwan3_set_custom_ipset()
|
||||||
mwan3_set_connected_ipv4()
|
mwan3_set_connected_ipv4()
|
||||||
{
|
{
|
||||||
local connected_network_v4 candidate_list cidr_list
|
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 hash:net
|
||||||
$IPS create mwan3_connected_v4_temp hash:net
|
$IPS create mwan3_connected_v4_temp hash:net
|
||||||
|
|
||||||
|
@ -274,7 +175,7 @@ mwan3_set_connected_ipv4()
|
||||||
$IP4 route | awk '{print $1}'
|
$IP4 route | awk '{print $1}'
|
||||||
$IP4 route list table 0 | awk '{print $2}'
|
$IP4 route list table 0 | awk '{print $2}'
|
||||||
}
|
}
|
||||||
for connected_network_v4 in $(route_lists | egrep "$ipv4regex"); do
|
for connected_network_v4 in $(route_lists | grep -E "$IPv4_REGEX"); do
|
||||||
if [ -z "${connected_network_v4##*/*}" ]; then
|
if [ -z "${connected_network_v4##*/*}" ]; then
|
||||||
cidr_list="$cidr_list $connected_network_v4"
|
cidr_list="$cidr_list $connected_network_v4"
|
||||||
else
|
else
|
||||||
|
@ -294,40 +195,44 @@ mwan3_set_connected_ipv4()
|
||||||
|
|
||||||
$IPS swap mwan3_connected_v4_temp mwan3_connected_v4
|
$IPS swap mwan3_connected_v4_temp mwan3_connected_v4
|
||||||
$IPS destroy mwan3_connected_v4_temp
|
$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 connected_network_v6 error
|
||||||
local update=""
|
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 -! create mwan3_connected_v6 hash:net family inet6
|
||||||
mwan3_push_update flush mwan3_connected_v6
|
mwan3_push_update flush mwan3_connected_v6
|
||||||
|
|
||||||
for connected_network_v6 in $($IP6 route | awk '{print $1}' | egrep "$IPv6_REGEX"); do
|
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"
|
mwan3_push_update -! add mwan3_connected_v6 "$connected_network_v6"
|
||||||
done
|
done
|
||||||
|
|
||||||
mwan3_push_update -! create mwan3_source_v6 hash:net family inet6
|
mwan3_push_update -! add mwan3_connected mwan3_connected_v6
|
||||||
for source_network_v6 in $($IP6 addr ls | sed -ne 's/ *inet6 \([^ \/]*\).* scope global.*/\1/p'); do
|
error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_connected_ipv6: $error"
|
||||||
mwan3_push_update -! add mwan3_source_v6 "$source_network_v6"
|
|
||||||
done
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mwan3_set_connected_ipset()
|
||||||
|
{
|
||||||
|
local error
|
||||||
|
local update=""
|
||||||
|
|
||||||
mwan3_push_update -! create mwan3_connected list:set
|
mwan3_push_update -! create mwan3_connected list:set
|
||||||
mwan3_push_update flush mwan3_connected
|
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 -! create mwan3_dynamic_v4 hash:net
|
||||||
mwan3_push_update -! add mwan3_connected mwan3_dynamic_v4
|
mwan3_push_update -! add mwan3_connected mwan3_dynamic_v4
|
||||||
|
|
||||||
[ $NO_IPV6 -eq 0 ] && mwan3_push_update -! create mwan3_dynamic_v6 hash:net family inet6
|
if [ $NO_IPV6 -eq 0 ]; then
|
||||||
[ $NO_IPV6 -eq 0 ] && mwan3_push_update -! add mwan3_connected mwan3_dynamic_v6
|
mwan3_push_update -! create mwan3_dynamic_v6 hash:net family inet6
|
||||||
error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_connected_iptables: $error"
|
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()
|
mwan3_set_general_rules()
|
||||||
|
@ -336,12 +241,12 @@ mwan3_set_general_rules()
|
||||||
|
|
||||||
for IP in "$IP4" "$IP6"; do
|
for IP in "$IP4" "$IP6"; do
|
||||||
[ "$IP" = "$IP6" ] && [ $NO_IPV6 -ne 0 ] && continue
|
[ "$IP" = "$IP6" ] && [ $NO_IPV6 -ne 0 ] && continue
|
||||||
RULE_NO=$(($MM_BLACKHOLE+2000))
|
RULE_NO=$((MM_BLACKHOLE+2000))
|
||||||
if [ -z "$($IP rule list | awk -v var="$RULE_NO:" '$1 == var')" ]; then
|
if [ -z "$($IP rule list | awk -v var="$RULE_NO:" '$1 == var')" ]; then
|
||||||
$IP rule add pref $RULE_NO fwmark $MMX_BLACKHOLE/$MMX_MASK blackhole
|
$IP rule add pref $RULE_NO fwmark $MMX_BLACKHOLE/$MMX_MASK blackhole
|
||||||
fi
|
fi
|
||||||
|
|
||||||
RULE_NO=$(($MM_UNREACHABLE+2000))
|
RULE_NO=$((MM_UNREACHABLE+2000))
|
||||||
if [ -z "$($IP rule list | awk -v var="$RULE_NO:" '$1 == var')" ]; then
|
if [ -z "$($IP rule list | awk -v var="$RULE_NO:" '$1 == var')" ]; then
|
||||||
$IP rule add pref $RULE_NO fwmark $MMX_UNREACHABLE/$MMX_MASK unreachable
|
$IP rule add pref $RULE_NO fwmark $MMX_UNREACHABLE/$MMX_MASK unreachable
|
||||||
fi
|
fi
|
||||||
|
@ -353,7 +258,7 @@ mwan3_set_general_iptables()
|
||||||
local IPT current update error
|
local IPT current update error
|
||||||
for IPT in "$IPT4" "$IPT6"; do
|
for IPT in "$IPT4" "$IPT6"; do
|
||||||
[ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue
|
[ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue
|
||||||
current="$($IPT -S)"
|
current="$($IPT -S)"$'\n'
|
||||||
update="*mangle"
|
update="*mangle"
|
||||||
if [ -n "${current##*-N mwan3_ifaces_in*}" ]; then
|
if [ -n "${current##*-N mwan3_ifaces_in*}" ]; then
|
||||||
mwan3_push_update -N mwan3_ifaces_in
|
mwan3_push_update -N mwan3_ifaces_in
|
||||||
|
@ -395,15 +300,10 @@ mwan3_set_general_iptables()
|
||||||
-p ipv6-icmp \
|
-p ipv6-icmp \
|
||||||
-m icmp6 --icmpv6-type 137 \
|
-m icmp6 --icmpv6-type 137 \
|
||||||
-j RETURN
|
-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
|
fi
|
||||||
mwan3_push_update -A mwan3_hook \
|
mwan3_push_update -A mwan3_hook \
|
||||||
|
-m mark --mark 0x0/$MMX_MASK \
|
||||||
-j CONNMARK --restore-mark --nfmask "$MMX_MASK" --ctmask "$MMX_MASK"
|
-j CONNMARK --restore-mark --nfmask "$MMX_MASK" --ctmask "$MMX_MASK"
|
||||||
mwan3_push_update -A mwan3_hook \
|
mwan3_push_update -A mwan3_hook \
|
||||||
-m mark --mark 0x0/$MMX_MASK \
|
-m mark --mark 0x0/$MMX_MASK \
|
||||||
|
@ -439,7 +339,7 @@ mwan3_set_general_iptables()
|
||||||
|
|
||||||
mwan3_create_iface_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
|
config_get family "$1" family ipv4
|
||||||
mwan3_get_iface_id id "$1"
|
mwan3_get_iface_id id "$1"
|
||||||
|
@ -447,26 +347,22 @@ mwan3_create_iface_iptables()
|
||||||
[ -n "$id" ] || return 0
|
[ -n "$id" ] || return 0
|
||||||
|
|
||||||
if [ "$family" = "ipv4" ]; then
|
if [ "$family" = "ipv4" ]; then
|
||||||
connected_name=mwan3_connected
|
|
||||||
IPT="$IPT4"
|
IPT="$IPT4"
|
||||||
IPTR="$IPT4R"
|
IPTR="$IPT4R"
|
||||||
$IPS -! create $connected_name list:set
|
|
||||||
|
|
||||||
elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
|
elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
|
||||||
connected_name=mwan3_connected_v6
|
|
||||||
IPT="$IPT6"
|
IPT="$IPT6"
|
||||||
IPTR="$IPT6R"
|
IPTR="$IPT6R"
|
||||||
$IPS -! create $connected_name hash:net family inet6
|
|
||||||
else
|
else
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
current="$($IPT -S)"
|
|
||||||
|
current="$($IPT -S)"$'\n'
|
||||||
update="*mangle"
|
update="*mangle"
|
||||||
if [ -n "${current##*-N mwan3_ifaces_in*}" ]; then
|
if [ -n "${current##*-N mwan3_ifaces_in*}" ]; then
|
||||||
mwan3_push_update -N mwan3_ifaces_in
|
mwan3_push_update -N mwan3_ifaces_in
|
||||||
fi
|
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"
|
mwan3_push_update -N "mwan3_iface_in_$1"
|
||||||
else
|
else
|
||||||
mwan3_push_update -F "mwan3_iface_in_$1"
|
mwan3_push_update -F "mwan3_iface_in_$1"
|
||||||
|
@ -474,17 +370,17 @@ mwan3_create_iface_iptables()
|
||||||
|
|
||||||
mwan3_push_update -A "mwan3_iface_in_$1" \
|
mwan3_push_update -A "mwan3_iface_in_$1" \
|
||||||
-i "$2" \
|
-i "$2" \
|
||||||
-m set --match-set $connected_name src \
|
-m set --match-set mwan3_connected src \
|
||||||
-m mark --mark 0x0/$MMX_MASK \
|
-m mark --mark "0x0/$MMX_MASK" \
|
||||||
-m comment --comment "default" \
|
-m comment --comment "default" \
|
||||||
-j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
|
-j MARK --set-xmark "$MMX_DEFAULT/$MMX_MASK"
|
||||||
mwan3_push_update -A "mwan3_iface_in_$1" \
|
mwan3_push_update -A "mwan3_iface_in_$1" \
|
||||||
-i "$2" \
|
-i "$2" \
|
||||||
-m mark --mark 0x0/$MMX_MASK \
|
-m mark --mark "0x0/$MMX_MASK" \
|
||||||
-m comment --comment "$1" \
|
-m comment --comment "$1" \
|
||||||
-j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
|
-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 \
|
mwan3_push_update -A mwan3_ifaces_in \
|
||||||
-m mark --mark 0x0/$MMX_MASK \
|
-m mark --mark 0x0/$MMX_MASK \
|
||||||
-j "mwan3_iface_in_$1"
|
-j "mwan3_iface_in_$1"
|
||||||
|
@ -521,45 +417,17 @@ mwan3_delete_iface_iptables()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mwan3_create_iface_route()
|
mwan3_get_routes()
|
||||||
{
|
{
|
||||||
local id via metric V V_ IP family
|
local source_routing
|
||||||
local iface device cmd true_iface
|
config_get_bool source_routing globals source_routing 0
|
||||||
|
[ $source_routing -eq 0 ] && unset source_routing
|
||||||
iface=$1
|
$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
|
||||||
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"
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
config_get family "$1" family ipv4
|
||||||
mwan3_get_iface_id id "$1"
|
mwan3_get_iface_id id "$1"
|
||||||
|
|
||||||
|
@ -571,10 +439,15 @@ mwan3_add_non_default_iface_route()
|
||||||
IP="$IP6"
|
IP="$IP6"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
tbl=$($IP route list table $id 2>/dev/null)$'\n'
|
||||||
mwan3_update_dev_to_table
|
mwan3_update_dev_to_table
|
||||||
$IP route list table main | grep -v "^default\|linkdown\|^::/0\|^fe80::/64\|^unreachable" | while read route_line; do
|
mwan3_get_routes | while read -r route_line; do
|
||||||
mwan3_route_line_dev "tid" "$route_line" "$family"
|
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
|
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 ||
|
$IP route add table $id $route_line ||
|
||||||
LOG warn "failed to add $route_line to table $id"
|
LOG warn "failed to add $route_line to table $id"
|
||||||
fi
|
fi
|
||||||
|
@ -582,63 +455,21 @@ mwan3_add_non_default_iface_route()
|
||||||
done
|
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 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()
|
mwan3_delete_iface_route()
|
||||||
{
|
{
|
||||||
local id
|
local id family
|
||||||
|
|
||||||
config_get family "$1" family ipv4
|
config_get family "$1" family ipv4
|
||||||
mwan3_get_iface_id id "$1"
|
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
|
if [ "$family" = "ipv4" ]; then
|
||||||
$IP4 route flush table "$id"
|
$IP4 route flush table "$id"
|
||||||
fi
|
elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
|
||||||
|
|
||||||
if [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
|
|
||||||
$IP6 route flush table "$id"
|
$IP6 route flush table "$id"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -660,21 +491,16 @@ mwan3_create_iface_rules()
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
while [ -n "$($IP rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
|
mwan3_delete_iface_rules "$1"
|
||||||
$IP rule del pref $(($id+1000))
|
|
||||||
done
|
|
||||||
|
|
||||||
while [ -n "$($IP rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
|
$IP rule add pref $((id+1000)) iif "$2" lookup "$id"
|
||||||
$IP rule del pref $(($id+2000))
|
$IP rule add pref $((id+2000)) fwmark "$(mwan3_id2mask id MMX_MASK)/$MMX_MASK" lookup "$id"
|
||||||
done
|
$IP rule add pref $((id+3000)) fwmark "$(mwan3_id2mask id MMX_MASK)/$MMX_MASK" unreachable
|
||||||
|
|
||||||
$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"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mwan3_delete_iface_rules()
|
mwan3_delete_iface_rules()
|
||||||
{
|
{
|
||||||
local id family
|
local id family IP rule_id
|
||||||
|
|
||||||
config_get family "$1" family ipv4
|
config_get family "$1" family ipv4
|
||||||
mwan3_get_iface_id id "$1"
|
mwan3_get_iface_id id "$1"
|
||||||
|
@ -689,12 +515,8 @@ mwan3_delete_iface_rules()
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
while [ -n "$($IP rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
|
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 $(($id+1000))
|
$IP rule del pref $rule_id
|
||||||
done
|
|
||||||
|
|
||||||
while [ -n "$($IP rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
|
|
||||||
$IP rule del pref $(($id+2000))
|
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,39 +535,6 @@ mwan3_delete_iface_ipset_entries()
|
||||||
done
|
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()
|
mwan3_set_policy()
|
||||||
{
|
{
|
||||||
|
@ -776,7 +565,7 @@ mwan3_set_policy()
|
||||||
IPT="$IPT6"
|
IPT="$IPT6"
|
||||||
IPTR="$IPT6R"
|
IPTR="$IPT6R"
|
||||||
fi
|
fi
|
||||||
current="$($IPT -S)"
|
current="$($IPT -S)"$'\n'
|
||||||
update="*mangle"
|
update="*mangle"
|
||||||
|
|
||||||
if [ "$family" = "ipv4" ] && [ $is_offline -eq 0 ]; then
|
if [ "$family" = "ipv4" ] && [ $is_offline -eq 0 ]; then
|
||||||
|
@ -785,7 +574,7 @@ mwan3_set_policy()
|
||||||
total_weight_v4=$weight
|
total_weight_v4=$weight
|
||||||
lowest_metric_v4=$metric
|
lowest_metric_v4=$metric
|
||||||
elif [ "$metric" -eq "$lowest_metric_v4" ]; then
|
elif [ "$metric" -eq "$lowest_metric_v4" ]; then
|
||||||
total_weight_v4=$(($total_weight_v4+$weight))
|
total_weight_v4=$((total_weight_v4+weight))
|
||||||
total_weight=$total_weight_v4
|
total_weight=$total_weight_v4
|
||||||
else
|
else
|
||||||
return
|
return
|
||||||
|
@ -796,7 +585,7 @@ mwan3_set_policy()
|
||||||
total_weight_v6=$weight
|
total_weight_v6=$weight
|
||||||
lowest_metric_v6=$metric
|
lowest_metric_v6=$metric
|
||||||
elif [ "$metric" -eq "$lowest_metric_v6" ]; then
|
elif [ "$metric" -eq "$lowest_metric_v6" ]; then
|
||||||
total_weight_v6=$(($total_weight_v6+$weight))
|
total_weight_v6=$((total_weight_v6+weight))
|
||||||
total_weight=$total_weight_v6
|
total_weight=$total_weight_v6
|
||||||
else
|
else
|
||||||
return
|
return
|
||||||
|
@ -807,9 +596,9 @@ mwan3_set_policy()
|
||||||
mwan3_push_update -A "mwan3_policy_$policy" \
|
mwan3_push_update -A "mwan3_policy_$policy" \
|
||||||
-m mark --mark 0x0/$MMX_MASK \
|
-m mark --mark 0x0/$MMX_MASK \
|
||||||
-m comment --comment \"$iface $weight $weight\" \
|
-m comment --comment \"$iface $weight $weight\" \
|
||||||
-j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
|
-j MARK --set-xmark "$(mwan3_id2mask id MMX_MASK)/$MMX_MASK"
|
||||||
elif [ $is_offline -eq 0 ]; then
|
elif [ $is_offline -eq 0 ]; then
|
||||||
probability=$(($weight*1000/$total_weight))
|
probability=$((weight*1000/total_weight))
|
||||||
if [ "$probability" -lt 10 ]; then
|
if [ "$probability" -lt 10 ]; then
|
||||||
probability="0.00$probability"
|
probability="0.00$probability"
|
||||||
elif [ $probability -lt 100 ]; then
|
elif [ $probability -lt 100 ]; then
|
||||||
|
@ -826,7 +615,7 @@ mwan3_set_policy()
|
||||||
--mode random \
|
--mode random \
|
||||||
--probability "$probability" \
|
--probability "$probability" \
|
||||||
-m comment --comment \"$iface $weight $total_weight\" \
|
-m comment --comment \"$iface $weight $total_weight\" \
|
||||||
-j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
|
-j MARK --set-xmark "$(mwan3_id2mask id MMX_MASK)/$MMX_MASK"
|
||||||
elif [ -n "$device" ]; then
|
elif [ -n "$device" ]; then
|
||||||
echo "$current" | grep -q "^-A mwan3_policy_$policy.*--comment .* [0-9]* [0-9]*" ||
|
echo "$current" | grep -q "^-A mwan3_policy_$policy.*--comment .* [0-9]* [0-9]*" ||
|
||||||
mwan3_push_update -I "mwan3_policy_$policy" \
|
mwan3_push_update -I "mwan3_policy_$policy" \
|
||||||
|
@ -855,9 +644,9 @@ mwan3_create_policies_iptables()
|
||||||
|
|
||||||
for IPT in "$IPT4" "$IPT6"; do
|
for IPT in "$IPT4" "$IPT6"; do
|
||||||
[ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue
|
[ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue
|
||||||
current="$($IPT -S)"
|
current="$($IPT -S)"$'\n'
|
||||||
update="*mangle"
|
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"
|
mwan3_push_update -N "mwan3_policy_$1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -915,14 +704,14 @@ mwan3_set_sticky_iptables()
|
||||||
mwan3_get_iface_id id "$1"
|
mwan3_get_iface_id id "$1"
|
||||||
|
|
||||||
[ -n "$id" ] || return 0
|
[ -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" \
|
mwan3_push_update -I "mwan3_rule_$rule" \
|
||||||
-m mark --mark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK \
|
-m mark --mark "$(mwan3_id2mask id MMX_MASK)/$MMX_MASK" \
|
||||||
-m set ! --match-set "mwan3_sticky_$rule" src,src \
|
-m set ! --match-set "mwan3_sticky_$rule" src,src \
|
||||||
-j MARK --set-xmark 0x0/$MMX_MASK
|
-j MARK --set-xmark "0x0/$MMX_MASK"
|
||||||
mwan3_push_update -I "mwan3_rule_$rule" \
|
mwan3_push_update -I "mwan3_rule_$rule" \
|
||||||
-m mark --mark 0/$MMX_MASK \
|
-m mark --mark "0/$MMX_MASK" \
|
||||||
-j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
|
-j MARK --set-xmark "$(mwan3_id2mask id MMX_MASK)/$MMX_MASK"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
@ -952,6 +741,18 @@ mwan3_set_user_iptables_rule()
|
||||||
config_get global_logging globals logging 0
|
config_get global_logging globals logging 0
|
||||||
config_get loglevel globals loglevel notice
|
config_get loglevel globals loglevel notice
|
||||||
|
|
||||||
|
[ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && return
|
||||||
|
[ "$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
|
if [ -n "$src_iface" ]; then
|
||||||
network_get_device src_dev "$src_iface"
|
network_get_device src_dev "$src_iface"
|
||||||
if [ -z "$src_dev" ]; then
|
if [ -z "$src_dev" ]; then
|
||||||
|
@ -1013,16 +814,12 @@ mwan3_set_user_iptables_rule()
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && return
|
if [ $rule_policy -eq 1 ] && [ -n "${current##*-N $policy$'\n'*}" ]; then
|
||||||
[ "$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"
|
mwan3_push_update -N "$policy"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $rule_policy -eq 1 ] && [ "$sticky" -eq 1 ]; then
|
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"
|
mwan3_push_update -N "mwan3_rule_$1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -1117,7 +914,7 @@ mwan3_set_user_rules()
|
||||||
fi
|
fi
|
||||||
[ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue
|
[ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue
|
||||||
update="*mangle"
|
update="*mangle"
|
||||||
current="$($IPT -S)"
|
current="$($IPT -S)"$'\n'
|
||||||
|
|
||||||
|
|
||||||
if [ -n "${current##*-N mwan3_rules*}" ]; then
|
if [ -n "${current##*-N mwan3_rules*}" ]; then
|
||||||
|
@ -1136,6 +933,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() {
|
mwan3_set_iface_hotplug_state() {
|
||||||
local iface=$1
|
local iface=$1
|
||||||
local state=$2
|
local state=$2
|
||||||
|
@ -1151,7 +1025,7 @@ mwan3_get_iface_hotplug_state() {
|
||||||
|
|
||||||
mwan3_report_iface_status()
|
mwan3_report_iface_status()
|
||||||
{
|
{
|
||||||
local device result track_ips tracking IP IPT
|
local device result tracking IP IPT
|
||||||
|
|
||||||
mwan3_get_iface_id id "$1"
|
mwan3_get_iface_id id "$1"
|
||||||
network_get_device device "$1"
|
network_get_device device "$1"
|
||||||
|
@ -1170,8 +1044,9 @@ mwan3_report_iface_status()
|
||||||
|
|
||||||
if [ -z "$id" ] || [ -z "$device" ]; then
|
if [ -z "$id" ] || [ -z "$device" ]; then
|
||||||
result="offline"
|
result="offline"
|
||||||
elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" ] && \
|
elif [ -n "$($IP rule | awk '$1 == "'$((id+1000)):'"')" ] && \
|
||||||
[ -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" ] && \
|
[ -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 "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" ] && \
|
||||||
[ -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
|
[ -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
|
||||||
json_init
|
json_init
|
||||||
|
@ -1183,11 +1058,12 @@ mwan3_report_iface_status()
|
||||||
json_get_vars online uptime
|
json_get_vars online uptime
|
||||||
json_select ..
|
json_select ..
|
||||||
json_select ..
|
json_select ..
|
||||||
online="$(printf '%02dh:%02dm:%02ds\n' $(($online/3600)) $(($online%3600/60)) $(($online%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)))"
|
uptime="$(printf '%02dh:%02dm:%02ds\n' $((uptime/3600)) $((uptime%3600/60)) $((uptime%60)))"
|
||||||
result="$(mwan3_get_iface_hotplug_state $1) $online, uptime $uptime"
|
result="$(mwan3_get_iface_hotplug_state $1) $online, uptime $uptime"
|
||||||
elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" ] || \
|
elif [ -n "$($IP rule | awk '$1 == "'$((id+1000)):'"')" ] || \
|
||||||
[ -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" ] || \
|
[ -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 "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" ] || \
|
||||||
[ -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
|
[ -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
|
||||||
result="error"
|
result="error"
|
||||||
|
@ -1197,22 +1073,7 @@ mwan3_report_iface_status()
|
||||||
result="disabled"
|
result="disabled"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mwan3_list_track_ips()
|
tracking="$(mwan3_get_mwan3track_status $1)"
|
||||||
{
|
|
||||||
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
|
|
||||||
|
|
||||||
echo " interface $1 is $result and tracking is $tracking"
|
echo " interface $1 is $result and tracking is $tracking"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1225,10 +1086,10 @@ mwan3_report_policies()
|
||||||
|
|
||||||
total_weight=$($ipt -S "$policy" | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | head -1 | awk '{print $3}')
|
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
|
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}')
|
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%)"
|
echo " $iface ($percent%)"
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
|
@ -1306,6 +1167,6 @@ mwan3_flush_conntrack()
|
||||||
|
|
||||||
mwan3_track_clean()
|
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"
|
rmdir --ignore-fail-on-non-empty "$MWAN3_STATUS_DIR"
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,16 +77,13 @@ get_mwan3_status() {
|
||||||
local online=0
|
local online=0
|
||||||
local offline=0
|
local offline=0
|
||||||
local up="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
|
network_get_device device $1
|
||||||
|
|
||||||
if [ "${iface}" = "${iface_select}" ] || [ "${iface_select}" = "" ]; then
|
if [ "${iface}" = "${iface_select}" ] || [ "${iface_select}" = "" ]; then
|
||||||
pid="$(pgrep -f "mwan3track $iface $device")"
|
track_status="$(mwan3_get_mwan3track_status "$1")"
|
||||||
if [ "${pid}" != "" ]; then
|
[ "$track_status" = "active" ] && running="1"
|
||||||
running="1"
|
|
||||||
fi
|
|
||||||
|
|
||||||
time_p="$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/TIME")"
|
time_p="$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/TIME")"
|
||||||
[ -z "${time_p}" ] || {
|
[ -z "${time_p}" ] || {
|
||||||
time_n="$(get_uptime)"
|
time_n="$(get_uptime)"
|
||||||
|
|
|
@ -22,29 +22,27 @@ Available commands:
|
||||||
connected Show directly connected networks
|
connected Show directly connected networks
|
||||||
rules Show active rules
|
rules Show active rules
|
||||||
status Show all status
|
status Show all status
|
||||||
|
use <iface> <cmd> Run a command bound to <iface> and avoid mwan3 rules
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
ifdown()
|
|
||||||
{
|
ifdown() {
|
||||||
if [ -z "$1" ]; then
|
if [ -z "$1" ]; then
|
||||||
echo "Error: Expecting interface. Usage: mwan3 ifdown <interface>" && exit 0
|
echo "Error: Expecting interface. Usage: mwan3 ifdown <interface>"
|
||||||
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$2" ]; then
|
if [ -n "$2" ]; then
|
||||||
echo "Error: Too many arguments. Usage: mwan3 ifdown <interface>" && exit 0
|
echo "Error: Too many arguments. Usage: mwan3 ifdown <interface>"
|
||||||
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACTION=ifdown INTERFACE=$1 /sbin/hotplug-call iface
|
mwan3_interface_hotplug_shutdown "$1" 1
|
||||||
|
|
||||||
kill $(pgrep -f "mwan3track $1 ") &> /dev/null
|
|
||||||
mwan3_track_clean $1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ifup()
|
ifup() {
|
||||||
{
|
. /etc/init.d/mwan3
|
||||||
local device enabled up l3_device status interface true_iface
|
|
||||||
|
|
||||||
if [ -z "$1" ]; then
|
if [ -z "$1" ]; then
|
||||||
echo "Expecting interface. Usage: mwan3 ifup <interface>"
|
echo "Expecting interface. Usage: mwan3 ifup <interface>"
|
||||||
|
@ -56,46 +54,7 @@ ifup()
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
interface=$1
|
mwan3_ifup "$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
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interfaces()
|
interfaces()
|
||||||
|
@ -104,40 +63,40 @@ interfaces()
|
||||||
|
|
||||||
echo "Interface status:"
|
echo "Interface status:"
|
||||||
config_foreach mwan3_report_iface_status interface
|
config_foreach mwan3_report_iface_status interface
|
||||||
echo -e
|
echo
|
||||||
}
|
}
|
||||||
|
|
||||||
policies()
|
policies()
|
||||||
{
|
{
|
||||||
echo "Current ipv4 policies:"
|
echo "Current ipv4 policies:"
|
||||||
mwan3_report_policies_v4
|
mwan3_report_policies_v4
|
||||||
echo -e
|
echo
|
||||||
[ $NO_IPV6 -ne 0 ] && return
|
[ $NO_IPV6 -ne 0 ] && return
|
||||||
echo "Current ipv6 policies:"
|
echo "Current ipv6 policies:"
|
||||||
mwan3_report_policies_v6
|
mwan3_report_policies_v6
|
||||||
echo -e
|
echo
|
||||||
}
|
}
|
||||||
|
|
||||||
connected()
|
connected()
|
||||||
{
|
{
|
||||||
echo "Directly connected ipv4 networks:"
|
echo "Directly connected ipv4 networks:"
|
||||||
mwan3_report_connected_v4
|
mwan3_report_connected_v4
|
||||||
echo -e
|
echo
|
||||||
[ $NO_IPV6 -ne 0 ] && return
|
[ $NO_IPV6 -ne 0 ] && return
|
||||||
echo "Directly connected ipv6 networks:"
|
echo "Directly connected ipv6 networks:"
|
||||||
mwan3_report_connected_v6
|
mwan3_report_connected_v6
|
||||||
echo -e
|
echo
|
||||||
}
|
}
|
||||||
|
|
||||||
rules()
|
rules()
|
||||||
{
|
{
|
||||||
echo "Active ipv4 user rules:"
|
echo "Active ipv4 user rules:"
|
||||||
mwan3_report_rules_v4
|
mwan3_report_rules_v4
|
||||||
echo -e
|
echo
|
||||||
[ $NO_IPV6 -ne 0 ] && return
|
[ $NO_IPV6 -ne 0 ] && return
|
||||||
echo "Active ipv6 user rules:"
|
echo "Active ipv6 user rules:"
|
||||||
mwan3_report_rules_v6
|
mwan3_report_rules_v6
|
||||||
echo -e
|
echo
|
||||||
}
|
}
|
||||||
|
|
||||||
status()
|
status()
|
||||||
|
@ -148,113 +107,51 @@ status()
|
||||||
rules
|
rules
|
||||||
}
|
}
|
||||||
|
|
||||||
start()
|
start() {
|
||||||
{
|
/etc/init.d/mwan3 enable
|
||||||
local enabled hotplug_pids MWAN3_STARTUP
|
/etc/init.d/mwan3 start
|
||||||
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_nondefault_routes
|
|
||||||
mwan3_set_policies_iptables
|
|
||||||
mwan3_set_user_rules
|
|
||||||
|
|
||||||
|
|
||||||
mwan3_unlock "command" "mwan3"
|
|
||||||
mwan3_rtmon
|
|
||||||
unset MWAN3_STARTUP
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stop()
|
stop() {
|
||||||
{
|
/etc/init.d/mwan3 disable
|
||||||
local ipset rule IP IPTR IPT kill_pid family table tid
|
/etc/init.d/mwan3 stop
|
||||||
|
|
||||||
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 | egrep '^[1-2][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"
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
restart() {
|
restart() {
|
||||||
stop
|
/etc/init.d/mwan3 enable
|
||||||
start
|
/etc/init.d/mwan3 stop
|
||||||
|
/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
|
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
|
mwan3_init
|
||||||
|
# shellcheck disable=SC2048
|
||||||
$*
|
$*
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
|
|
@ -5,82 +5,139 @@
|
||||||
. /lib/mwan3/mwan3.sh
|
. /lib/mwan3/mwan3.sh
|
||||||
. /lib/mwan3/common.sh
|
. /lib/mwan3/common.sh
|
||||||
|
|
||||||
|
trap_with_arg()
|
||||||
|
{
|
||||||
|
func="$1" ; shift
|
||||||
|
pid="$1" ; shift
|
||||||
|
for sig ; do
|
||||||
|
# shellcheck disable=SC2064
|
||||||
|
trap "$func $sig $pid" "$sig"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
func_trap()
|
||||||
|
{
|
||||||
|
kill -${1} ${2} 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
mwan3_add_all_routes()
|
||||||
|
{
|
||||||
|
local tid IP IPT route_line family active_tbls tid initial_state
|
||||||
|
local ipv=$1
|
||||||
|
|
||||||
|
add_active_tbls()
|
||||||
|
{
|
||||||
|
let tid++
|
||||||
|
config_get family "$1" family ipv4
|
||||||
|
config_get initial_state "$1" initial_state "online"
|
||||||
|
[ "$family" != "$ipv" ] && return
|
||||||
|
if $IPT -S "mwan3_iface_in_$1" &> /dev/null; then
|
||||||
|
active_tbls="$active_tbls${tid} "
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
add_route()
|
||||||
|
{
|
||||||
|
let tid++
|
||||||
|
[ -n "${active_tbls##* $tid *}" ] && return
|
||||||
|
$IP route add table $tid $route_line ||
|
||||||
|
LOG warn "failed to add $route_line to table $tid"
|
||||||
|
}
|
||||||
|
|
||||||
|
mwan3_update_dev_to_table
|
||||||
|
[ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && return
|
||||||
|
if [ "$ipv" = "ipv4" ]; then
|
||||||
|
IP="$IP4"
|
||||||
|
IPT="$IPT4"
|
||||||
|
elif [ "$ipv" = "ipv6" ]; then
|
||||||
|
IP="$IP6"
|
||||||
|
IPT="$IPT6"
|
||||||
|
fi
|
||||||
|
tid=0
|
||||||
|
active_tbls=" "
|
||||||
|
config_foreach add_active_tbls interface
|
||||||
|
[ $active_tbls = " " ] && return
|
||||||
|
mwan3_get_routes | while read -r route_line; do
|
||||||
|
mwan3_route_line_dev "tid" "$route_line" "$ipv"
|
||||||
|
if [ -n "$tid" ] && [ -z "${active_tbls##* $tid *}" ]; then
|
||||||
|
$IP route add table $tid $route_line
|
||||||
|
elif [ -n "${route_line##default*}" ] && [ -n "${route_line##fe80::/64*}" ]; then
|
||||||
|
config_foreach add_route interface
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
mwan3_rtmon_route_handle()
|
mwan3_rtmon_route_handle()
|
||||||
{
|
{
|
||||||
config_load mwan3
|
local action route_line family tbl device line route_line_exp tid source_routing
|
||||||
local section action route_line family tbl device metric tos dst line
|
|
||||||
local route_device tid
|
|
||||||
route_line=${1##"Deleted "}
|
route_line=${1##"Deleted "}
|
||||||
route_family=$2
|
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
|
if [ "$route_family" = "ipv4" ]; then
|
||||||
IP="$IP4"
|
IP="$IP4"
|
||||||
elif [ "$route_family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
|
elif [ "$route_family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
|
||||||
IP="$IP6"
|
IP="$IP6"
|
||||||
|
route_line=$(echo "$route_line" | sed "$route_line_exp")
|
||||||
else
|
else
|
||||||
|
LOG warn "route update called with invalid family - $route_family"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$route_line" == "$1" ]; then
|
# don't try to add routes when link has gone down
|
||||||
action="add"
|
if [ -z "${route_line##linkdown*}" ]; then
|
||||||
else
|
LOG debug "not adding route due to linkdown - skipping $route_line"
|
||||||
action="del"
|
return
|
||||||
fi
|
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() {
|
handle_route() {
|
||||||
tbl=$($IP route list table $tid)
|
local iface=$1
|
||||||
if [ $action = "add" ]; then
|
tbl=$($IP route list table $tid 2>/dev/null)$'\n'
|
||||||
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
|
|
||||||
|
|
||||||
[ $action = "add" ] && [ -z "${tbl##*$route_line*}" ] && return
|
if [ "$(cat /var/run/mwan3track/$iface/STATUS)" != "online" ]; then
|
||||||
[ $action = "del" ] && [ -n "${tbl##*$route_line*}" ] && return
|
LOG debug "interface $iface is offline - skipping $route_line";
|
||||||
network_get_device device "$section"
|
return
|
||||||
LOG debug "adjusting route $device: $IP route "$action" table $tid $route_line"
|
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 ||
|
$IP route "$action" table $tid $route_line ||
|
||||||
LOG warn "failed: $IP route $action table $tid $route_line"
|
LOG warn "failed: $IP route $action table $tid $route_line"
|
||||||
}
|
}
|
||||||
handle_route_cb(){
|
handle_route_cb(){
|
||||||
|
local iface=$1
|
||||||
let tid++
|
let tid++
|
||||||
config_get family "$section" family ipv4
|
config_get family "$iface" family ipv4
|
||||||
[ "$family" != "$route_family" ] && return
|
[ "$family" != "$route_family" ] && return
|
||||||
handle_route
|
handle_route "$iface"
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ $action = "add" ]; then
|
mwan3_update_dev_to_table
|
||||||
## handle old routes from 'change' or 'replace'
|
mwan3_route_line_dev "tid" "$route_line" "$route_family"
|
||||||
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 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
|
|
||||||
|
|
||||||
if [ -n "$tid" ]; then
|
if [ -n "$tid" ]; then
|
||||||
handle_route
|
handle_route
|
||||||
else
|
elif [ -n "${route_line##default*}" ] && [ -n "${route_line##fe80::/64*}" ]; then
|
||||||
config_foreach handle_route_cb interface
|
config_foreach handle_route_cb interface
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -92,19 +149,35 @@ main()
|
||||||
config_load mwan3
|
config_load mwan3
|
||||||
family=$1
|
family=$1
|
||||||
[ -z $family ] && family=ipv4
|
[ -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"
|
IP="$IP6"
|
||||||
else
|
else
|
||||||
IP="$IP4"
|
IP="$IP4"
|
||||||
fi
|
fi
|
||||||
mwan3_init
|
mwan3_init
|
||||||
|
mwan3_lock "mwan3rtmon" "start"
|
||||||
$IP monitor route | while read line; do
|
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
|
[ -z "${line##*table*}" ] && continue
|
||||||
LOG debug "handling route update $family $line"
|
LOG debug "handling route update $family $line"
|
||||||
mwan3_lock "service" "mwan3rtmon"
|
mwan3_lock "service" "mwan3rtmon"
|
||||||
mwan3_rtmon_route_handle "$line" "$family"
|
mwan3_rtmon_route_handle "$line" "$family"
|
||||||
mwan3_unlock "service" "mwan3rtmon"
|
mwan3_unlock "service" "mwan3rtmon"
|
||||||
done
|
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 "$@"
|
main "$@"
|
||||||
|
|
|
@ -1,37 +1,64 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
. /lib/functions.sh
|
. /lib/functions.sh
|
||||||
|
. /lib/functions/network.sh
|
||||||
. /lib/mwan3/common.sh
|
. /lib/mwan3/common.sh
|
||||||
|
|
||||||
INTERFACE=""
|
INTERFACE=""
|
||||||
DEVICE=""
|
DEVICE=""
|
||||||
PING="/bin/ping"
|
|
||||||
|
|
||||||
IFDOWN_EVENT=0
|
IFDOWN_EVENT=0
|
||||||
IFUP_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
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
clean_up() {
|
||||||
LOG notice "Stopping mwan3track for interface \"${INTERFACE}\""
|
LOG notice "Stopping mwan3track for interface \"${INTERFACE}\". Status was \"${STATUS}\""
|
||||||
|
stop_subprocs
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if_down() {
|
if_down() {
|
||||||
LOG info "Detect ifdown event on interface ${INTERFACE} (${DEVICE})"
|
LOG info "Detect ifdown event on interface ${INTERFACE} (${DEVICE})"
|
||||||
IFDOWN_EVENT=1
|
IFDOWN_EVENT=1
|
||||||
|
stop_subprocs
|
||||||
}
|
}
|
||||||
|
|
||||||
if_up() {
|
if_up() {
|
||||||
LOG info "Detect ifup event on interface ${INTERFACE} (${DEVICE})"
|
LOG info "Detect ifup event on interface ${INTERFACE} (${DEVICE})"
|
||||||
|
IFDOWN_EVENT=0
|
||||||
IFUP_EVENT=1
|
IFUP_EVENT=1
|
||||||
|
STARTED=1
|
||||||
|
stop_subprocs
|
||||||
}
|
}
|
||||||
|
|
||||||
validate_track_method() {
|
validate_track_method() {
|
||||||
case "$1" in
|
case "$1" in
|
||||||
ping)
|
ping)
|
||||||
[ -x "$PING" ] || {
|
if [ -x "/usr/bin/ping" ] && [ "$(/usr/bin/ping -V | grep -o '[0-9]*$')" -gt 20150519 ]; then
|
||||||
LOG warn "Missing ping. Please enable ping util and recompile busybox."
|
# -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
|
return 1
|
||||||
}
|
fi
|
||||||
;;
|
;;
|
||||||
arping)
|
arping)
|
||||||
command -v arping 1>/dev/null 2>&1 || {
|
command -v arping 1>/dev/null 2>&1 || {
|
||||||
|
@ -44,10 +71,6 @@ validate_track_method() {
|
||||||
LOG warn "Missing httping. Please install httping package."
|
LOG warn "Missing httping. Please install httping package."
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
[ -n "$2" -a "$2" != "0.0.0.0" -a "$2" != "::" ] || {
|
|
||||||
LOG warn "Cannot determine source IP for the interface which is required by httping."
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
;;
|
;;
|
||||||
nping-*)
|
nping-*)
|
||||||
command -v nping 1>/dev/null 2>&1 || {
|
command -v nping 1>/dev/null 2>&1 || {
|
||||||
|
@ -62,30 +85,63 @@ validate_track_method() {
|
||||||
esac
|
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() {
|
disconnected() {
|
||||||
echo "offline" > /var/run/mwan3track/$INTERFACE/STATUS
|
STATUS='offline'
|
||||||
echo "$(get_uptime)" > /var/run/mwan3track/$INTERFACE/OFFLINE
|
echo "offline" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS
|
||||||
echo "0" > /var/run/mwan3track/$INTERFACE/ONLINE
|
get_uptime > $MWAN3TRACK_STATUS_DIR/$INTERFACE/OFFLINE
|
||||||
|
echo "0" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/ONLINE
|
||||||
score=0
|
score=0
|
||||||
[ "$1" == 1 ] && return
|
[ "$1" = 1 ] && return
|
||||||
LOG notice "Interface $INTERFACE ($DEVICE) is offline"
|
LOG notice "Interface $INTERFACE ($DEVICE) is offline"
|
||||||
env -i ACTION="disconnected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface
|
env -i ACTION="disconnected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface
|
||||||
}
|
}
|
||||||
|
|
||||||
connected() {
|
connected() {
|
||||||
echo "online" > /var/run/mwan3track/$INTERFACE/STATUS
|
STATUS='online'
|
||||||
echo "0" > /var/run/mwan3track/$INTERFACE/OFFLINE
|
echo "online" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS
|
||||||
echo "$(get_uptime)" > /var/run/mwan3track/$INTERFACE/ONLINE
|
echo "0" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/OFFLINE
|
||||||
|
get_uptime > $MWAN3TRACK_STATUS_DIR/$INTERFACE/ONLINE
|
||||||
host_up_count=0
|
host_up_count=0
|
||||||
lost=0
|
lost=0
|
||||||
turn=0
|
turn=0
|
||||||
loss=0
|
loss=0
|
||||||
[ "$1" == 1 ] && return
|
|
||||||
LOG notice "Interface $INTERFACE ($DEVICE) is online"
|
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() {
|
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 $INTERFACE
|
||||||
|
|
||||||
|
LOG debug "firstconnect: called on $INTERFACE/$true_iface ($DEVICE). Status is $STATUS. SRC_IP is $SRC_IP"
|
||||||
|
|
||||||
|
STARTED=1
|
||||||
if [ "$STATUS" = "offline" ]; then
|
if [ "$STATUS" = "offline" ]; then
|
||||||
disconnected 1
|
disconnected 1
|
||||||
else
|
else
|
||||||
|
@ -94,14 +150,12 @@ firstconnect() {
|
||||||
}
|
}
|
||||||
|
|
||||||
update_status() {
|
update_status() {
|
||||||
local status track_ip
|
local track_ip=$1
|
||||||
track_ip=$1
|
|
||||||
status=$2
|
|
||||||
|
|
||||||
echo "$1" > /var/run/mwan3track/$INTERFACE/TRACK_${track_ip}
|
echo "$2" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_${track_ip}
|
||||||
[ -z "$3" ] && return
|
[ -z "$3" ] && return
|
||||||
echo "$3" > /var/run/mwan3track/$INTERFACE/LATENCY_${track_ip}
|
echo "$3" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/LATENCY_${track_ip}
|
||||||
echo "$4" > /var/run/mwan3track/$INTERFACE/LOSS_${track_ip}
|
echo "$4" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/LOSS_${track_ip}
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
|
@ -109,23 +163,23 @@ main() {
|
||||||
local recovery_interval down up size
|
local recovery_interval down up size
|
||||||
local keep_failure_interval check_quality failure_latency
|
local keep_failure_interval check_quality failure_latency
|
||||||
local recovery_latency failure_loss recovery_loss
|
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 track_ips do_log
|
||||||
|
|
||||||
INTERFACE=$1
|
INTERFACE=$1
|
||||||
DEVICE=$2
|
STATUS=""
|
||||||
STATUS=$3
|
STARTED=0
|
||||||
SRC_IP=$4
|
mkdir -p $MWAN3TRACK_STATUS_DIR/$INTERFACE
|
||||||
mkdir -p /var/run/mwan3track/$INTERFACE
|
|
||||||
trap clean_up TERM
|
trap clean_up TERM
|
||||||
trap if_down USR1
|
trap if_down USR1
|
||||||
trap if_up USR2
|
trap if_up USR2
|
||||||
|
|
||||||
config_load mwan3
|
config_load mwan3
|
||||||
|
config_get FAMILY $INTERFACE family ipv4
|
||||||
config_get track_method $INTERFACE track_method ping
|
config_get track_method $INTERFACE track_method ping
|
||||||
config_get_bool httping_ssl $INTERFACE httping_ssl 0
|
config_get_bool httping_ssl $INTERFACE httping_ssl 0
|
||||||
validate_track_method $track_method $SRC_IP || {
|
validate_track_method $track_method || {
|
||||||
track_method=ping
|
track_method=ping
|
||||||
if validate_track_method $track_method; then
|
if validate_track_method $track_method; then
|
||||||
LOG warn "Using ping to track interface $INTERFACE avaliability"
|
LOG warn "Using ping to track interface $INTERFACE avaliability"
|
||||||
|
@ -150,110 +204,102 @@ main() {
|
||||||
config_get recovery_latency $INTERFACE recovery_latency 500
|
config_get recovery_latency $INTERFACE recovery_latency 500
|
||||||
config_get failure_loss $INTERFACE failure_loss 40
|
config_get failure_loss $INTERFACE failure_loss 40
|
||||||
config_get recovery_loss $INTERFACE recovery_loss 10
|
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 score=$((down+up))
|
||||||
local track_ips=$(echo $* | cut -d ' ' -f 5-99)
|
|
||||||
local host_up_count=0
|
local host_up_count=0
|
||||||
local lost=0
|
local lost=0
|
||||||
local turn=0
|
local turn=0
|
||||||
local ping_protocol=4
|
|
||||||
local sleep_time result ping_result ping_result_raw ping_status loss latency
|
|
||||||
|
|
||||||
firstconnect
|
firstconnect
|
||||||
while true; do
|
while true; do
|
||||||
|
[ $STARTED -eq 0 ] && { sleep $MAX_SLEEP & SLEEP_PID=$!; wait; }
|
||||||
|
unset SLEEP_PID
|
||||||
sleep_time=$interval
|
sleep_time=$interval
|
||||||
|
|
||||||
for track_ip in $track_ips; do
|
for track_ip in $track_ips; do
|
||||||
if [ $host_up_count -lt $reliability ]; then
|
if [ $host_up_count -lt $reliability ]; then
|
||||||
case "$track_method" in
|
case "$track_method" in
|
||||||
ping)
|
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 [ -z ${track_ip##*:*} ]; then
|
|
||||||
ping_protocol=6
|
|
||||||
else
|
|
||||||
unset SRC_IP
|
|
||||||
fi
|
|
||||||
if [ $check_quality -eq 0 ]; then
|
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
|
WRAP $PING -c $count -W $timeout -s $size -t $max_ttl -q $track_ip &> /dev/null &
|
||||||
|
TRACK_PID=$!
|
||||||
|
wait $TRACK_PID
|
||||||
result=$?
|
result=$?
|
||||||
else
|
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)"
|
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=$?
|
ping_status=$?
|
||||||
ping_result=$(echo "$ping_result_raw" | tail -n2)
|
loss="$(sed $TRACK_OUTPUT -ne 's/.*\([0-9]\+\)% packet loss.*/\1/p')"
|
||||||
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
|
if [ "$ping_status" -ne 0 ] || [ "$loss" -eq 100 ]; then
|
||||||
latency=999999
|
latency=999999
|
||||||
loss=100
|
loss=100
|
||||||
else
|
else
|
||||||
latency="$(echo "$ping_result" | grep -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
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
arping)
|
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=$?
|
result=$?
|
||||||
;;
|
;;
|
||||||
httping)
|
httping)
|
||||||
if [ "$httping_ssl" -eq 1 ]; then
|
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
|
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
|
fi
|
||||||
|
TRACK_PID=$!
|
||||||
|
wait $TRACK_PID
|
||||||
result=$?
|
result=$?
|
||||||
;;
|
;;
|
||||||
nping-tcp)
|
nping-*)
|
||||||
result=$(nping -e $DEVICE -c $count $track_ip --tcp | grep Lost | awk '{print $12}')
|
WRAP nping -c $count $track_ip --${FAMILY#nping-} > $TRACK_OUTPUT &
|
||||||
;;
|
TRACK_PID=$!
|
||||||
nping-udp)
|
wait $TRACK_PID
|
||||||
result=$(nping -e $DEVICE -c $count $track_ip --udp | grep Lost | awk '{print $12}')
|
result=$(grep $TRACK_OUTPUT 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}')
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
do_log=""
|
||||||
if [ $check_quality -eq 0 ]; then
|
if [ $check_quality -eq 0 ]; then
|
||||||
if [ $result -eq 0 ]; then
|
if [ $result -eq 0 ]; then
|
||||||
let host_up_count++
|
let host_up_count++
|
||||||
update_status "$track_ip" "up"
|
update_status "$track_ip" "up"
|
||||||
|
|
||||||
if [ $score -le $up ]; then
|
[ $score -le $up ] && do_log="success"
|
||||||
LOG info "Check ($track_method) success for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
let lost++
|
let lost++
|
||||||
update_status "$track_ip" "down"
|
update_status "$track_ip" "down"
|
||||||
|
|
||||||
if [ $score -gt $up ]; then
|
[ $score -gt $up ] && do_log="failed"
|
||||||
LOG info "Check ($track_method) failed for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
[ -n "$do_log" ] && LOG info "Check ($track_method) ${do_log} for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
||||||
|
|
||||||
else
|
else
|
||||||
if [ "$loss" -ge "$failure_loss" -o "$latency" -ge "$failure_latency" ]; then
|
if [ "$loss" -ge "$failure_loss" ] || [ "$latency" -ge "$failure_latency" ]; then
|
||||||
let lost++
|
let lost++
|
||||||
update_status "$track_ip" "down" $latency $loss
|
update_status "$track_ip" "down" $latency $loss
|
||||||
|
|
||||||
if [ $score -gt $up ]; then
|
[ $score -gt $up ] && do_log="failed"
|
||||||
LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) failed for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
elif [ "$loss" -le "$recovery_loss" ] && [ "$latency" -le "$recovery_latency" ]; then
|
||||||
fi
|
|
||||||
elif [ "$loss" -le "$recovery_loss" -a "$latency" -le "$recovery_latency" ]; then
|
|
||||||
let host_up_count++
|
let host_up_count++
|
||||||
update_status "$track_ip" "up" $latency $loss
|
update_status "$track_ip" "up" $latency $loss
|
||||||
|
|
||||||
if [ $score -le $up ]; then
|
[ $score -le $up ] && do_log="success"
|
||||||
LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) success for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
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
|
fi
|
||||||
else
|
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}
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -262,9 +308,7 @@ main() {
|
||||||
|
|
||||||
if [ $score -lt $up ]; then
|
if [ $score -lt $up ]; then
|
||||||
score=0
|
score=0
|
||||||
[ ${keep_failure_interval} -eq 1 ] && {
|
[ ${keep_failure_interval} -eq 1 ] && sleep_time=$failure_interval
|
||||||
sleep_time=$failure_interval
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
sleep_time=$failure_interval
|
sleep_time=$failure_interval
|
||||||
fi
|
fi
|
||||||
|
@ -274,31 +318,31 @@ main() {
|
||||||
score=0
|
score=0
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if [ $score -lt $(($down+$up)) ] && [ $lost -gt 0 ]; then
|
if [ $score -lt $((down+up)) ] && [ $lost -gt 0 ]; then
|
||||||
LOG info "Lost $(($lost*$count)) ping(s) on interface $INTERFACE ($DEVICE). Current score: $score"
|
LOG info "Lost $((lost*count)) ping(s) on interface $INTERFACE ($DEVICE). Current score: $score"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
let score++
|
let score++
|
||||||
lost=0
|
lost=0
|
||||||
|
|
||||||
if [ $score -gt $up ]; then
|
if [ $score -gt $up ]; then
|
||||||
echo "online" > /var/run/mwan3track/$INTERFACE/STATUS
|
echo "online" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS
|
||||||
score=$(($down+$up))
|
score=$((down+up))
|
||||||
elif [ $score -le $up ]; then
|
elif [ $score -le $up ]; then
|
||||||
sleep_time=$recovery_interval
|
sleep_time=$recovery_interval
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $score -eq $up ]; then
|
if [ $score -eq $up ]; then
|
||||||
connected $INTERFACE $DEVICE
|
connected
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
let turn++
|
let turn++
|
||||||
mkdir -p "/var/run/mwan3track/${1}"
|
mkdir -p "$MWAN3TRACK_STATUS_DIR/${1}"
|
||||||
echo "${lost}" > /var/run/mwan3track/$INTERFACE/LOST
|
echo "${lost}" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/LOST
|
||||||
echo "${score}" > /var/run/mwan3track/$INTERFACE/SCORE
|
echo "${score}" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/SCORE
|
||||||
echo "${turn}" > /var/run/mwan3track/$INTERFACE/TURN
|
echo "${turn}" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TURN
|
||||||
echo "$(get_uptime)" > /var/run/mwan3track/$INTERFACE/TIME
|
get_uptime > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TIME
|
||||||
|
|
||||||
host_up_count=0
|
host_up_count=0
|
||||||
sleep "${sleep_time}" &
|
sleep "${sleep_time}" &
|
||||||
|
@ -306,7 +350,8 @@ main() {
|
||||||
|
|
||||||
if [ "${IFDOWN_EVENT}" -eq 1 ]; then
|
if [ "${IFDOWN_EVENT}" -eq 1 ]; then
|
||||||
LOG debug "Register ifdown event on interface ${INTERFACE} (${DEVICE})"
|
LOG debug "Register ifdown event on interface ${INTERFACE} (${DEVICE})"
|
||||||
disconnected 1
|
disabled
|
||||||
|
disconnected
|
||||||
IFDOWN_EVENT=0
|
IFDOWN_EVENT=0
|
||||||
fi
|
fi
|
||||||
if [ "${IFUP_EVENT}" -eq 1 ]; then
|
if [ "${IFUP_EVENT}" -eq 1 ]; then
|
||||||
|
|
255
net/mwan3/src/sockopt_wrap.c
Normal file
255
net/mwan3/src/sockopt_wrap.c
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Aaron Goodman <aaronjg@alumni.stanford.edu>. 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 <dlfcn.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <net/ethernet.h>
|
||||||
|
#include <linux/if_packet.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
Loading…
Reference in a new issue