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
|
||||
|
||||
PKG_NAME:=mwan3
|
||||
PKG_VERSION:=2.9.0
|
||||
PKG_VERSION:=2.10.0
|
||||
PKG_RELEASE:=1
|
||||
PKG_MAINTAINER:=Florian Eckert <fe@dev.tdt.de>
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
PKG_CONFIG_DEPENDS:=CONFIG_IPV6
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
|
@ -61,8 +62,13 @@ fi
|
|||
exit 0
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(TARGET_CC) $(CFLAGS) $(LDFLAGS) $(FPIC) -shared -o $(PKG_BUILD_DIR)/libwrap_mwan3_sockopt.so.1.0 $(if $(CONFIG_IPV6),-DCONFIG_IPV6) $(PKG_BUILD_DIR)/sockopt_wrap.c -ldl
|
||||
endef
|
||||
|
||||
define Package/mwan3/install
|
||||
$(CP) ./files/* $(1)
|
||||
$(CP) ./files/* $(1)
|
||||
$(CP) $(PKG_BUILD_DIR)/libwrap_mwan3_sockopt.so.1.0 $(1)/lib/mwan3/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,mwan3))
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# For full documentation of mwan3 configuration:
|
||||
# https://openwrt.org/docs/guide-user/network/wan/multiwan/mwan3#mwan3_configuration
|
||||
|
||||
config globals 'globals'
|
||||
option mmx_mask '0x3F00'
|
||||
|
@ -10,15 +12,6 @@ config interface 'wan'
|
|||
list track_ip '208.67.220.220'
|
||||
option family 'ipv4'
|
||||
option reliability '2'
|
||||
option count '1'
|
||||
option timeout '2'
|
||||
option failure_latency '1000'
|
||||
option recovery_latency '500'
|
||||
option failure_loss '20'
|
||||
option recovery_loss '5'
|
||||
option interval '5'
|
||||
option down '3'
|
||||
option up '8'
|
||||
|
||||
config interface 'wan6'
|
||||
option enabled '0'
|
||||
|
@ -28,11 +21,6 @@ config interface 'wan6'
|
|||
list track_ip '2620:0:ccc::2'
|
||||
option family 'ipv6'
|
||||
option reliability '2'
|
||||
option count '1'
|
||||
option timeout '2'
|
||||
option interval '5'
|
||||
option down '3'
|
||||
option up '8'
|
||||
|
||||
config interface 'wanb'
|
||||
option enabled '0'
|
||||
|
@ -42,15 +30,6 @@ config interface 'wanb'
|
|||
list track_ip '208.67.220.220'
|
||||
option family 'ipv4'
|
||||
option reliability '1'
|
||||
option count '1'
|
||||
option timeout '2'
|
||||
option failure_latency '1000'
|
||||
option recovery_latency '500'
|
||||
option failure_loss '20'
|
||||
option recovery_loss '5'
|
||||
option interval '5'
|
||||
option down '3'
|
||||
option up '8'
|
||||
|
||||
config interface 'wanb6'
|
||||
option enabled '0'
|
||||
|
@ -60,11 +39,6 @@ config interface 'wanb6'
|
|||
list track_ip '2620:0:ccc::2'
|
||||
option family 'ipv6'
|
||||
option reliability '1'
|
||||
option count '1'
|
||||
option timeout '2'
|
||||
option interval '5'
|
||||
option down '3'
|
||||
option up '8'
|
||||
|
||||
config member 'wan_m1_w3'
|
||||
option interface 'wan'
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
. /lib/mwan3/common.sh
|
||||
|
||||
SCRIPTNAME="mwan3-hotplug"
|
||||
[ "$ACTION" = "ifup" ] || [ "$ACTION" = "ifdown" ] || [ "$ACTION" = "connected" ] || [ "$ACTION" = "disconnected" ] || exit 1
|
||||
[ "$ACTION" = "ifup" ] || [ "$ACTION" = "ifdown" ] || [ "$ACTION" = "connected" ] || [ "$ACTION" = "disconnected" ] || exit 1
|
||||
[ -n "$INTERFACE" ] || exit 2
|
||||
if ( [ "$ACTION" = "ifup" ] || [ "$ACTION" = "connected" ] ) && [ -z "$DEVICE" ]; then
|
||||
[ "$FIRSTCONNECT" = "1" ] || [ "$MWAN3_SHUTDOWN" = "1" ] && exit 0
|
||||
|
||||
if { [ "$ACTION" = "ifup" ] || [ "$ACTION" = "connected" ] ; } && [ -z "$DEVICE" ]; then
|
||||
LOG notice "$ACTION called on $INTERFACE with no device set"
|
||||
exit 3
|
||||
fi
|
||||
|
@ -17,10 +19,9 @@ fi
|
|||
[ "$MWAN3_STARTUP" = 1 ] || mwan3_lock "$ACTION" "$INTERFACE"
|
||||
|
||||
config_load mwan3
|
||||
config_get_bool enabled globals 'enabled' '0'
|
||||
[ "${enabled}" -gt 0 ] || {
|
||||
/etc/init.d/mwan3 running || {
|
||||
[ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$INTERFACE"
|
||||
LOG notice "mwan3 hotplug on $INTERFACE not called because globally disabled"
|
||||
LOG notice "mwan3 hotplug $ACTION on $INTERFACE not called because globally disabled"
|
||||
mwan3_flush_conntrack "$INTERFACE" "$ACTION"
|
||||
exit 0
|
||||
}
|
||||
|
@ -33,15 +34,14 @@ $IPT4 -S mwan3_hook &>/dev/null || {
|
|||
|
||||
mwan3_init
|
||||
[ "$MWAN3_STARTUP" = 1 ] || {
|
||||
mwan3_set_connected_iptables
|
||||
mwan3_set_custom_ipset
|
||||
config_get family $INTERFACE family ipv4
|
||||
mwan3_set_connected_${family}
|
||||
}
|
||||
|
||||
if [ "$MWAN3_STARTUP" != 1 ]; then
|
||||
if [ "$MWAN3_STARTUP" != 1 ] && [ "$ACTION" = "ifup" ]; then
|
||||
mwan3_set_user_iface_rules $INTERFACE $DEVICE
|
||||
fi
|
||||
|
||||
config_get initial_state $INTERFACE initial_state "online"
|
||||
config_get_bool enabled $INTERFACE 'enabled' '0'
|
||||
[ "${enabled}" -eq 1 ] || {
|
||||
[ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$INTERFACE"
|
||||
|
@ -49,54 +49,47 @@ config_get_bool enabled $INTERFACE 'enabled' '0'
|
|||
exit 0
|
||||
}
|
||||
|
||||
trackpid=$(pgrep -f "mwan3track $INTERFACE ")
|
||||
|
||||
config_get initial_state $INTERFACE initial_state "online"
|
||||
if [ "$initial_state" = "offline" ]; then
|
||||
status=$(cat $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS 2>/dev/null || echo unknown)
|
||||
[ "$status" = "online" ] || status=offline
|
||||
else
|
||||
status=online
|
||||
fi
|
||||
|
||||
[ -z "$TRUE_INTERFACE" ] && mwan3_get_true_iface TRUE_INTERFACE $INTERFACE
|
||||
if [ "$ACTION" = ifup ] || [ "$ACTION" = ifdown ]; then
|
||||
initscript=/etc/init.d/mwan3
|
||||
. /lib/functions/procd.sh
|
||||
fi
|
||||
|
||||
binary_status=$status
|
||||
[ "$binary_status" = "online" ] || binary_status=offline
|
||||
|
||||
LOG notice "Execute "$ACTION" event on interface $INTERFACE (${DEVICE:-unknown})"
|
||||
LOG notice "Execute $ACTION event on interface $INTERFACE (${DEVICE:-unknown})"
|
||||
|
||||
case "$ACTION" in
|
||||
ifup|connected)
|
||||
connected)
|
||||
mwan3_set_iface_hotplug_state $INTERFACE "online"
|
||||
mwan3_set_policies_iptables
|
||||
;;
|
||||
ifup)
|
||||
mwan3_create_iface_iptables $INTERFACE $DEVICE
|
||||
mwan3_create_iface_rules $INTERFACE $DEVICE
|
||||
mwan3_create_iface_route $INTERFACE $DEVICE
|
||||
[ "$MWAN3_STARTUP" != 1 ] && mwan3_add_non_default_iface_route $INTERFACE $DEVICE
|
||||
mwan3_set_iface_hotplug_state $INTERFACE "$binary_status"
|
||||
|
||||
mwan3_get_src_ip src_ip "$TRUE_INTERFACE"
|
||||
if [ -n "${trackpid}" ]; then
|
||||
device_pid=$(pgrep -f "mwan3track $INTERFACE $DEVICE ")
|
||||
if [ "$device_pid" = "$trackpid" ]; then
|
||||
[ "$ACTION" = ifup ] && kill -USR2 "$trackpid"
|
||||
else
|
||||
mwan3_track $INTERFACE $DEVICE "$binary_status" "$src_ip"
|
||||
LOG notice "Restarted tracker [$!] on interface $INTERFACE (${DEVICE:-unknown})"
|
||||
fi
|
||||
else
|
||||
mwan3_track $INTERFACE $DEVICE "$binary_status" "$src_ip"
|
||||
LOG notice "Started tracker [$!] on interface $INTERFACE (${DEVICE:-unknown})"
|
||||
mwan3_set_iface_hotplug_state $INTERFACE "$status"
|
||||
if [ "$MWAN3_STARTUP" != 1 ]; then
|
||||
mwan3_create_iface_route $INTERFACE $DEVICE
|
||||
[ "$status" = "online" ] && mwan3_set_policies_iptables
|
||||
fi
|
||||
[ "$MWAN3_STARTUP" != 1 ] && [ "$binary_status" == "online" ] && mwan3_set_policies_iptables
|
||||
|
||||
;;
|
||||
ifdown|disconnected)
|
||||
[ "$ACTION" = ifup ] && procd_running mwan3 "track_$INTERFACE" && procd_send_signal mwan3 "track_$INTERFACE" USR2
|
||||
;;
|
||||
disconnected)
|
||||
mwan3_set_iface_hotplug_state $INTERFACE "offline"
|
||||
mwan3_set_policies_iptables
|
||||
;;
|
||||
ifdown)
|
||||
mwan3_set_iface_hotplug_state $INTERFACE "offline"
|
||||
mwan3_delete_iface_ipset_entries $INTERFACE
|
||||
mwan3_delete_iface_rules $INTERFACE
|
||||
mwan3_delete_iface_route $INTERFACE
|
||||
mwan3_delete_iface_iptables $INTERFACE
|
||||
if [ "$ACTION" = "ifdown" ]; then
|
||||
[ -n "$trackpid" ] && kill -USR1 "$trackpid"
|
||||
fi
|
||||
procd_running mwan3 "track_$INTERFACE" && procd_send_signal mwan3 "track_$INTERFACE" USR1
|
||||
mwan3_set_policies_iptables
|
||||
;;
|
||||
esac
|
||||
|
|
|
@ -4,22 +4,22 @@
|
|||
. /lib/functions.sh
|
||||
. /lib/mwan3/mwan3.sh
|
||||
|
||||
[ "$MWAN3_STARTUP" = 1 ] || mwan3_lock "$ACTION" "$DEVICE-user"
|
||||
[ "$MWAN3_SHUTDOWN" != 1 ] && mwan3_lock "$ACTION" "$DEVICE-user"
|
||||
|
||||
config_load mwan3
|
||||
config_get_bool enabled globals 'enabled' '0'
|
||||
[ "${enabled}" -gt 0 ] || {
|
||||
[ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$DEVICE-user"
|
||||
[ "$MWAN3_SHUTDOWN" != 1 ] && ! /etc/init.d/mwan3 running && {
|
||||
mwan3_unlock "$ACTION" "$DEVICE-user"
|
||||
exit 0
|
||||
}
|
||||
|
||||
config_load mwan3
|
||||
|
||||
config_get_bool enabled "$INTERFACE" enabled 0
|
||||
[ "${enabled}" -eq 1 ] || {
|
||||
[ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$DEVICE-user"
|
||||
[ "$MWAN3_SHUTDOWN" != 1 ] && mwan3_unlock "$ACTION" "$DEVICE-user"
|
||||
exit 0
|
||||
}
|
||||
|
||||
[ "$MWAN3_STARTUP" = 1 ] || mwan3_unlock "$ACTION" "$DEVICE-user"
|
||||
[ "$MWAN3_SHUTDOWN" != 1 ] && mwan3_unlock "$ACTION" "$DEVICE-user"
|
||||
|
||||
env -i ACTION="$ACTION" INTERFACE="$INTERFACE" DEVICE="$DEVICE" \
|
||||
/bin/sh /etc/mwan3.user
|
||||
|
|
|
@ -1,31 +1,114 @@
|
|||
#!/bin/sh /etc/rc.common
|
||||
|
||||
. /lib/functions.sh
|
||||
. /lib/mwan3/common.sh
|
||||
. /lib/functions/network.sh
|
||||
. /lib/mwan3/mwan3.sh
|
||||
|
||||
START=19
|
||||
USE_PROCD=1
|
||||
|
||||
boot() {
|
||||
. /lib/config/uci.sh
|
||||
# disabled until mwan3 start runs so hotplug scripts
|
||||
# do not start prematurely
|
||||
uci_toggle_state mwan3 globals enabled "0"
|
||||
rc_procd start_service
|
||||
service_running() {
|
||||
[ -d "$MWAN3_STATUS_DIR" ]
|
||||
}
|
||||
|
||||
# FIXME
|
||||
# fd 1000 is an inherited lock file descriptor for preventing concurrent
|
||||
# init script executions. Close it here to prevent the mwan3 daemon from
|
||||
# inheriting it further to avoid holding the lock indefinitely.
|
||||
start_tracker() {
|
||||
local enabled interface
|
||||
interface=$1
|
||||
config_get_bool enabled $interface 'enabled' '0'
|
||||
[ $enabled -eq 0 ] && return
|
||||
|
||||
reload_service() {
|
||||
/usr/sbin/mwan3 restart 1000>&-
|
||||
procd_open_instance "track_${1}"
|
||||
procd_set_param command /usr/sbin/mwan3track $interface
|
||||
procd_set_param respawn
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
start_service() {
|
||||
/usr/sbin/mwan3 start 1000>&-
|
||||
local enabled hotplug_pids
|
||||
|
||||
config_load mwan3
|
||||
mwan3_init
|
||||
config_foreach start_tracker interface
|
||||
|
||||
mwan3_lock "command" "mwan3"
|
||||
|
||||
mwan3_update_iface_to_table
|
||||
mwan3_set_connected_ipset
|
||||
mwan3_set_custom_ipset
|
||||
mwan3_set_general_rules
|
||||
mwan3_set_general_iptables
|
||||
config_foreach mwan3_ifup interface 1
|
||||
wait $hotplug_pids
|
||||
mwan3_set_policies_iptables
|
||||
mwan3_set_user_rules
|
||||
|
||||
mwan3_unlock "command" "mwan3"
|
||||
|
||||
procd_open_instance rtmon_ipv4
|
||||
procd_set_param command /usr/sbin/mwan3rtmon ipv4
|
||||
procd_set_param respawn
|
||||
procd_close_instance
|
||||
|
||||
if command -v ip6tables > /dev/null; then
|
||||
procd_open_instance rtmon_ipv6
|
||||
procd_set_param command /usr/sbin/mwan3rtmon ipv6
|
||||
procd_set_param respawn
|
||||
procd_close_instance
|
||||
fi
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
/usr/sbin/mwan3 stop 1000>&-
|
||||
local ipset rule IP IPTR IPT family table tid
|
||||
|
||||
mwan3_lock "command" "mwan3"
|
||||
|
||||
config_load mwan3
|
||||
mwan3_init
|
||||
config_foreach mwan3_interface_shutdown interface
|
||||
|
||||
for family in ipv4 ipv6; do
|
||||
if [ "$family" = "ipv4" ]; then
|
||||
IPT="$IPT4"
|
||||
IPTR="$IPT4R"
|
||||
IP="$IP4"
|
||||
elif [ "$family" = "ipv6" ]; then
|
||||
[ $NO_IPV6 -ne 0 ] && continue
|
||||
IPT="$IPT6"
|
||||
IPTR="$IPT6R"
|
||||
IP="$IP6"
|
||||
fi
|
||||
|
||||
for tid in $(ip route list table all | sed -ne 's/.*table \([0-9]\+\).*/\1/p' | sort -u); do
|
||||
[ $tid -gt $MWAN3_INTERFACE_MAX ] && continue
|
||||
$IP route flush table $tid &> /dev/null
|
||||
done
|
||||
|
||||
for rule in $($IP rule list | grep -E '^[1-3][0-9]{3}\:' | cut -d ':' -f 1); do
|
||||
$IP rule del pref $rule &> /dev/null
|
||||
done
|
||||
table="$($IPT -S)"
|
||||
{
|
||||
echo "*mangle";
|
||||
[ -z "${table##*PREROUTING -j mwan3_hook*}" ] && echo "-D PREROUTING -j mwan3_hook"
|
||||
[ -z "${table##*OUTPUT -j mwan3_hook*}" ] && echo "-D OUTPUT -j mwan3_hook"
|
||||
echo "$table" | awk '{print "-F "$2}' | grep mwan3 | sort -u
|
||||
echo "$table" | awk '{print "-X "$2}' | grep mwan3 | sort -u
|
||||
echo "COMMIT"
|
||||
} | $IPTR
|
||||
done
|
||||
|
||||
for ipset in $($IPS -n list | grep mwan3_); do
|
||||
$IPS -q destroy $ipset
|
||||
done
|
||||
|
||||
for ipset in $($IPS -n list | grep mwan3 | grep -E '_v4|_v6'); do
|
||||
$IPS -q destroy $ipset
|
||||
done
|
||||
|
||||
rm -rf $MWAN3_STATUS_DIR $MWAN3TRACK_STATUS_DIR
|
||||
|
||||
mwan3_unlock "command" "mwan3"
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
|
|
|
@ -5,7 +5,24 @@ get_uptime() {
|
|||
echo "${uptime%%.*}"
|
||||
}
|
||||
|
||||
IP4="ip -4"
|
||||
IP6="ip -6"
|
||||
SCRIPTNAME="$(basename "$0")"
|
||||
|
||||
MWAN3_STATUS_DIR="/var/run/mwan3"
|
||||
MWAN3TRACK_STATUS_DIR="/var/run/mwan3track"
|
||||
|
||||
MWAN3_INTERFACE_MAX=""
|
||||
|
||||
MMX_MASK=""
|
||||
MMX_DEFAULT=""
|
||||
MMX_BLACKHOLE=""
|
||||
MM_BLACKHOLE=""
|
||||
|
||||
MMX_UNREACHABLE=""
|
||||
MM_UNREACHABLE=""
|
||||
MAX_SLEEP=$(((1<<31)-1))
|
||||
|
||||
LOG()
|
||||
{
|
||||
local facility=$1; shift
|
||||
|
@ -13,5 +30,150 @@ LOG()
|
|||
# when this release is out of beta, the comment in the line below
|
||||
# should be removed
|
||||
[ "$facility" = "debug" ] && return
|
||||
logger -t "$SCRIPTNAME[$$]" -p $facility "$*"
|
||||
logger -t "${SCRIPTNAME}[$$]" -p $facility "$*"
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
IP4="ip -4"
|
||||
IP6="ip -6"
|
||||
IPS="ipset"
|
||||
IPT4="iptables -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}::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|"
|
||||
IPv6_REGEX="${IPv6_REGEX}([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"
|
||||
IPv4_REGEX="((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
|
||||
|
||||
MWAN3_STATUS_DIR="/var/run/mwan3"
|
||||
MWAN3TRACK_STATUS_DIR="/var/run/mwan3track"
|
||||
MWAN3_INTERFACE_MAX=""
|
||||
DEFAULT_LOWEST_METRIC=256
|
||||
MMX_MASK=""
|
||||
MMX_DEFAULT=""
|
||||
MMX_BLACKHOLE=""
|
||||
MM_BLACKHOLE=""
|
||||
|
||||
MMX_UNREACHABLE=""
|
||||
MM_UNREACHABLE=""
|
||||
|
||||
command -v ip6tables > /dev/null
|
||||
NO_IPV6=$?
|
||||
|
@ -43,14 +32,15 @@ mwan3_push_update()
|
|||
# helper function to build an update string to pass on to
|
||||
# IPTR or IPS RESTORE. Modifies the 'update' variable in
|
||||
# the local scope.
|
||||
update="$update
|
||||
$*";
|
||||
update="$update"$'\n'"$*";
|
||||
}
|
||||
|
||||
mwan3_update_dev_to_table()
|
||||
{
|
||||
local _tid
|
||||
# shellcheck disable=SC2034
|
||||
mwan3_dev_tbl_ipv4=" "
|
||||
# shellcheck disable=SC2034
|
||||
mwan3_dev_tbl_ipv6=" "
|
||||
|
||||
update_table()
|
||||
|
@ -81,25 +71,11 @@ mwan3_update_iface_to_table()
|
|||
config_foreach update_table interface
|
||||
}
|
||||
|
||||
mwan3_get_true_iface()
|
||||
{
|
||||
local family V
|
||||
_true_iface=$2
|
||||
config_get family "$iface" family ipv4
|
||||
if [ "$family" = "ipv4" ]; then
|
||||
V=4
|
||||
elif [ "$family" = "ipv6" ]; then
|
||||
V=6
|
||||
fi
|
||||
ubus call "network.interface.${iface}_${V}" status &>/dev/null && _true_iface="${iface}_${V}"
|
||||
export "$1=$_true_iface"
|
||||
}
|
||||
|
||||
mwan3_route_line_dev()
|
||||
{
|
||||
# must have mwan3 config already loaded
|
||||
# arg 1 is route device
|
||||
local _tid route_line route_device route_family entry curr_table
|
||||
local _tid route_line route_device route_family entry curr_table
|
||||
route_line=$2
|
||||
route_family=$3
|
||||
route_device=$(echo "$route_line" | sed -ne "s/.*dev \([^ ]*\).*/\1/p")
|
||||
|
@ -130,63 +106,6 @@ mwan3_count_one_bits()
|
|||
echo $count
|
||||
}
|
||||
|
||||
# maps the 1st parameter so it only uses the bits allowed by the bitmask (2nd parameter)
|
||||
# which means spreading the bits of the 1st parameter to only use the bits that are set to 1 in the 2nd parameter
|
||||
# 0 0 0 0 0 1 0 1 (0x05) 1st parameter
|
||||
# 1 0 1 0 1 0 1 0 (0xAA) 2nd parameter
|
||||
# 1 0 1 result
|
||||
mwan3_id2mask()
|
||||
{
|
||||
local bit_msk bit_val result
|
||||
bit_val=0
|
||||
result=0
|
||||
for bit_msk in $(seq 0 31); do
|
||||
if [ $((($2>>bit_msk)&1)) = "1" ]; then
|
||||
if [ $((($1>>bit_val)&1)) = "1" ]; then
|
||||
result=$((result|(1<<bit_msk)))
|
||||
fi
|
||||
bit_val=$((bit_val+1))
|
||||
fi
|
||||
done
|
||||
printf "0x%x" $result
|
||||
}
|
||||
|
||||
mwan3_init()
|
||||
{
|
||||
local bitcnt
|
||||
local mmdefault
|
||||
|
||||
[ -d $MWAN3_STATUS_DIR ] || mkdir -p $MWAN3_STATUS_DIR/iface_state
|
||||
|
||||
# mwan3's MARKing mask (at least 3 bits should be set)
|
||||
if [ -e "${MWAN3_STATUS_DIR}/mmx_mask" ]; then
|
||||
MMX_MASK=$(cat "${MWAN3_STATUS_DIR}/mmx_mask")
|
||||
MWAN3_INTERFACE_MAX=$(uci_get_state mwan3 globals iface_max)
|
||||
else
|
||||
config_load mwan3
|
||||
config_get MMX_MASK globals mmx_mask '0x3F00'
|
||||
echo "$MMX_MASK"| tr 'A-F' 'a-f' > "${MWAN3_STATUS_DIR}/mmx_mask"
|
||||
LOG debug "Using firewall mask ${MMX_MASK}"
|
||||
|
||||
bitcnt=$(mwan3_count_one_bits MMX_MASK)
|
||||
mmdefault=$(((1<<bitcnt)-1))
|
||||
MWAN3_INTERFACE_MAX=$(($mmdefault-3))
|
||||
uci_toggle_state mwan3 globals iface_max "$MWAN3_INTERFACE_MAX"
|
||||
LOG debug "Max interface count is ${MWAN3_INTERFACE_MAX}"
|
||||
fi
|
||||
|
||||
# mark mask constants
|
||||
bitcnt=$(mwan3_count_one_bits MMX_MASK)
|
||||
mmdefault=$(((1<<bitcnt)-1))
|
||||
MM_BLACKHOLE=$(($mmdefault-2))
|
||||
MM_UNREACHABLE=$(($mmdefault-1))
|
||||
|
||||
# MMX_DEFAULT should equal MMX_MASK
|
||||
MMX_DEFAULT=$(mwan3_id2mask mmdefault MMX_MASK)
|
||||
MMX_BLACKHOLE=$(mwan3_id2mask MM_BLACKHOLE MMX_MASK)
|
||||
MMX_UNREACHABLE=$(mwan3_id2mask MM_UNREACHABLE MMX_MASK)
|
||||
}
|
||||
|
||||
mwan3_lock() {
|
||||
lock /var/run/mwan3.lock
|
||||
#LOG debug "$1 $2 (lock)"
|
||||
|
@ -197,22 +116,6 @@ mwan3_unlock() {
|
|||
lock -u /var/run/mwan3.lock
|
||||
}
|
||||
|
||||
mwan3_get_src_ip()
|
||||
{
|
||||
local family _src_ip true_iface
|
||||
true_iface=$2
|
||||
unset "$1"
|
||||
config_get family "$true_iface" family ipv4
|
||||
if [ "$family" = "ipv4" ]; then
|
||||
network_get_ipaddr _src_ip "$true_iface"
|
||||
[ -n "$_src_ip" ] || _src_ip="0.0.0.0"
|
||||
elif [ "$family" = "ipv6" ]; then
|
||||
network_get_ipaddr6 _src_ip "$true_iface"
|
||||
[ -n "$_src_ip" ] || _src_ip="::"
|
||||
fi
|
||||
export "$1=$_src_ip"
|
||||
}
|
||||
|
||||
mwan3_get_iface_id()
|
||||
{
|
||||
local _tmp
|
||||
|
@ -220,14 +123,13 @@ mwan3_get_iface_id()
|
|||
_tmp="${mwan3_iface_tbl##* ${2}=}"
|
||||
_tmp=${_tmp%% *}
|
||||
export "$1=$_tmp"
|
||||
new_val=$_tmp
|
||||
}
|
||||
|
||||
mwan3_set_custom_ipset_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"
|
||||
mwan3_push_update -! add mwan3_custom_v4 "$custom_network_v4"
|
||||
done
|
||||
|
@ -237,7 +139,7 @@ mwan3_set_custom_ipset_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"
|
||||
mwan3_push_update -! add mwan3_custom_v6 "$custom_network_v6"
|
||||
done
|
||||
|
@ -263,7 +165,6 @@ mwan3_set_custom_ipset()
|
|||
mwan3_set_connected_ipv4()
|
||||
{
|
||||
local connected_network_v4 candidate_list cidr_list
|
||||
local ipv4regex='[0-9]{1,3}(\.[0-9]{1,3}){3}'
|
||||
$IPS -! create mwan3_connected_v4 hash:net
|
||||
$IPS create mwan3_connected_v4_temp hash:net
|
||||
|
||||
|
@ -274,7 +175,7 @@ mwan3_set_connected_ipv4()
|
|||
$IP4 route | awk '{print $1}'
|
||||
$IP4 route list table 0 | awk '{print $2}'
|
||||
}
|
||||
for connected_network_v4 in $(route_lists | egrep "$ipv4regex"); do
|
||||
for connected_network_v4 in $(route_lists | grep -E "$IPv4_REGEX"); do
|
||||
if [ -z "${connected_network_v4##*/*}" ]; then
|
||||
cidr_list="$cidr_list $connected_network_v4"
|
||||
else
|
||||
|
@ -294,40 +195,44 @@ mwan3_set_connected_ipv4()
|
|||
|
||||
$IPS swap mwan3_connected_v4_temp mwan3_connected_v4
|
||||
$IPS destroy mwan3_connected_v4_temp
|
||||
$IPS -! add mwan3_connected mwan3_connected_v4
|
||||
|
||||
}
|
||||
|
||||
mwan3_set_connected_iptables()
|
||||
mwan3_set_connected_ipv6()
|
||||
{
|
||||
local connected_network_v6 source_network_v6 error
|
||||
local connected_network_v6 error
|
||||
local update=""
|
||||
mwan3_set_connected_ipv4
|
||||
[ $NO_IPV6 -eq 0 ] || return
|
||||
|
||||
[ $NO_IPV6 -eq 0 ] && {
|
||||
mwan3_push_update -! create mwan3_connected_v6 hash:net family inet6
|
||||
mwan3_push_update flush mwan3_connected_v6
|
||||
mwan3_push_update -! create mwan3_connected_v6 hash:net family inet6
|
||||
mwan3_push_update flush mwan3_connected_v6
|
||||
|
||||
for connected_network_v6 in $($IP6 route | awk '{print $1}' | egrep "$IPv6_REGEX"); do
|
||||
mwan3_push_update -! add mwan3_connected_v6 "$connected_network_v6"
|
||||
done
|
||||
for connected_network_v6 in $($IP6 route | awk '{print $1}' | grep -E "$IPv6_REGEX"); do
|
||||
mwan3_push_update -! add mwan3_connected_v6 "$connected_network_v6"
|
||||
done
|
||||
|
||||
mwan3_push_update -! create mwan3_source_v6 hash:net family inet6
|
||||
for source_network_v6 in $($IP6 addr ls | sed -ne 's/ *inet6 \([^ \/]*\).* scope global.*/\1/p'); do
|
||||
mwan3_push_update -! add mwan3_source_v6 "$source_network_v6"
|
||||
done
|
||||
}
|
||||
mwan3_push_update -! add mwan3_connected mwan3_connected_v6
|
||||
error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_connected_ipv6: $error"
|
||||
}
|
||||
|
||||
mwan3_set_connected_ipset()
|
||||
{
|
||||
local error
|
||||
local update=""
|
||||
|
||||
mwan3_push_update -! create mwan3_connected list:set
|
||||
mwan3_push_update flush mwan3_connected
|
||||
mwan3_push_update -! add mwan3_connected mwan3_connected_v4
|
||||
[ $NO_IPV6 -eq 0 ] && mwan3_push_update -! add mwan3_connected mwan3_connected_v6
|
||||
|
||||
mwan3_push_update -! create mwan3_dynamic_v4 hash:net
|
||||
mwan3_push_update -! add mwan3_connected mwan3_dynamic_v4
|
||||
|
||||
[ $NO_IPV6 -eq 0 ] && mwan3_push_update -! create mwan3_dynamic_v6 hash:net family inet6
|
||||
[ $NO_IPV6 -eq 0 ] && mwan3_push_update -! add mwan3_connected mwan3_dynamic_v6
|
||||
error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_connected_iptables: $error"
|
||||
if [ $NO_IPV6 -eq 0 ]; then
|
||||
mwan3_push_update -! create mwan3_dynamic_v6 hash:net family inet6
|
||||
mwan3_push_update -! add mwan3_connected mwan3_dynamic_v6
|
||||
fi
|
||||
|
||||
error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_connected_ipset: $error"
|
||||
}
|
||||
|
||||
mwan3_set_general_rules()
|
||||
|
@ -336,12 +241,12 @@ mwan3_set_general_rules()
|
|||
|
||||
for IP in "$IP4" "$IP6"; do
|
||||
[ "$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
|
||||
$IP rule add pref $RULE_NO fwmark $MMX_BLACKHOLE/$MMX_MASK blackhole
|
||||
fi
|
||||
|
||||
RULE_NO=$(($MM_UNREACHABLE+2000))
|
||||
RULE_NO=$((MM_UNREACHABLE+2000))
|
||||
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
|
||||
fi
|
||||
|
@ -353,7 +258,7 @@ mwan3_set_general_iptables()
|
|||
local IPT current update error
|
||||
for IPT in "$IPT4" "$IPT6"; do
|
||||
[ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue
|
||||
current="$($IPT -S)"
|
||||
current="$($IPT -S)"$'\n'
|
||||
update="*mangle"
|
||||
if [ -n "${current##*-N mwan3_ifaces_in*}" ]; then
|
||||
mwan3_push_update -N mwan3_ifaces_in
|
||||
|
@ -395,15 +300,10 @@ mwan3_set_general_iptables()
|
|||
-p ipv6-icmp \
|
||||
-m icmp6 --icmpv6-type 137 \
|
||||
-j RETURN
|
||||
# do not mangle outgoing echo request
|
||||
mwan3_push_update -A mwan3_hook \
|
||||
-m set --match-set mwan3_source_v6 src \
|
||||
-p ipv6-icmp \
|
||||
-m icmp6 --icmpv6-type 128 \
|
||||
-j RETURN
|
||||
|
||||
fi
|
||||
mwan3_push_update -A mwan3_hook \
|
||||
-m mark --mark 0x0/$MMX_MASK \
|
||||
-j CONNMARK --restore-mark --nfmask "$MMX_MASK" --ctmask "$MMX_MASK"
|
||||
mwan3_push_update -A mwan3_hook \
|
||||
-m mark --mark 0x0/$MMX_MASK \
|
||||
|
@ -439,7 +339,7 @@ mwan3_set_general_iptables()
|
|||
|
||||
mwan3_create_iface_iptables()
|
||||
{
|
||||
local id family connected_name IPT IPTR current update error
|
||||
local id family IPT IPTR current update error
|
||||
|
||||
config_get family "$1" family ipv4
|
||||
mwan3_get_iface_id id "$1"
|
||||
|
@ -447,26 +347,22 @@ mwan3_create_iface_iptables()
|
|||
[ -n "$id" ] || return 0
|
||||
|
||||
if [ "$family" = "ipv4" ]; then
|
||||
connected_name=mwan3_connected
|
||||
IPT="$IPT4"
|
||||
IPTR="$IPT4R"
|
||||
$IPS -! create $connected_name list:set
|
||||
|
||||
elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
|
||||
connected_name=mwan3_connected_v6
|
||||
IPT="$IPT6"
|
||||
IPTR="$IPT6R"
|
||||
$IPS -! create $connected_name hash:net family inet6
|
||||
else
|
||||
return
|
||||
fi
|
||||
current="$($IPT -S)"
|
||||
|
||||
current="$($IPT -S)"$'\n'
|
||||
update="*mangle"
|
||||
if [ -n "${current##*-N mwan3_ifaces_in*}" ]; then
|
||||
mwan3_push_update -N mwan3_ifaces_in
|
||||
fi
|
||||
|
||||
if [ -n "${current##*-N mwan3_iface_in_$1*}" ]; then
|
||||
if [ -n "${current##*-N mwan3_iface_in_$1$'\n'*}" ]; then
|
||||
mwan3_push_update -N "mwan3_iface_in_$1"
|
||||
else
|
||||
mwan3_push_update -F "mwan3_iface_in_$1"
|
||||
|
@ -474,23 +370,23 @@ mwan3_create_iface_iptables()
|
|||
|
||||
mwan3_push_update -A "mwan3_iface_in_$1" \
|
||||
-i "$2" \
|
||||
-m set --match-set $connected_name src \
|
||||
-m mark --mark 0x0/$MMX_MASK \
|
||||
-m set --match-set mwan3_connected src \
|
||||
-m mark --mark "0x0/$MMX_MASK" \
|
||||
-m comment --comment "default" \
|
||||
-j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
|
||||
-j MARK --set-xmark "$MMX_DEFAULT/$MMX_MASK"
|
||||
mwan3_push_update -A "mwan3_iface_in_$1" \
|
||||
-i "$2" \
|
||||
-m mark --mark 0x0/$MMX_MASK \
|
||||
-m mark --mark "0x0/$MMX_MASK" \
|
||||
-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 \
|
||||
-m mark --mark 0x0/$MMX_MASK \
|
||||
-j "mwan3_iface_in_$1"
|
||||
LOG debug "create_iface_iptables: mwan3_iface_in_$1 not in iptables, adding"
|
||||
LOG debug "create_iface_iptables: mwan3_iface_in_$1 not in iptables, adding"
|
||||
else
|
||||
LOG debug "create_iface_iptables: mwan3_iface_in_$1 already in iptables, skip"
|
||||
LOG debug "create_iface_iptables: mwan3_iface_in_$1 already in iptables, skip"
|
||||
fi
|
||||
|
||||
mwan3_push_update COMMIT
|
||||
|
@ -521,45 +417,17 @@ mwan3_delete_iface_iptables()
|
|||
|
||||
}
|
||||
|
||||
mwan3_create_iface_route()
|
||||
mwan3_get_routes()
|
||||
{
|
||||
local id via metric V V_ IP family
|
||||
local iface device cmd true_iface
|
||||
|
||||
iface=$1
|
||||
device=$2
|
||||
config_get family "$iface" family ipv4
|
||||
mwan3_get_iface_id id "$iface"
|
||||
|
||||
[ -n "$id" ] || return 0
|
||||
|
||||
mwan3_get_true_iface true_iface $iface
|
||||
if [ "$family" = "ipv4" ]; then
|
||||
V_=""
|
||||
IP="$IP4"
|
||||
elif [ "$family" = "ipv6" ]; then
|
||||
V_=6
|
||||
IP="$IP6"
|
||||
fi
|
||||
|
||||
network_get_gateway${V_} via "$true_iface"
|
||||
|
||||
{ [ -z "$via" ] || [ "$via" = "0.0.0.0" ] || [ "$via" = "::" ] ; } && unset via
|
||||
|
||||
network_get_metric metric "$true_iface"
|
||||
|
||||
$IP route flush table "$id"
|
||||
cmd="$IP route add table $id default \
|
||||
${via:+via} $via \
|
||||
${metric:+metric} $metric \
|
||||
dev $2"
|
||||
$cmd || LOG warn "ip cmd failed $cmd"
|
||||
|
||||
local source_routing
|
||||
config_get_bool source_routing globals source_routing 0
|
||||
[ $source_routing -eq 0 ] && unset source_routing
|
||||
$IP route list table main | sed -ne "/^linkdown/T; s/expires \([0-9]\+\)sec//;s/error [0-9]\+//; ${source_routing:+s/default\(.*\) from [^ ]*/default\1/;} p" | uniq
|
||||
}
|
||||
|
||||
mwan3_add_non_default_iface_route()
|
||||
mwan3_create_iface_route()
|
||||
{
|
||||
local tid route_line family IP id
|
||||
local tid route_line family IP id tbl
|
||||
config_get family "$1" family ipv4
|
||||
mwan3_get_iface_id id "$1"
|
||||
|
||||
|
@ -571,10 +439,15 @@ mwan3_add_non_default_iface_route()
|
|||
IP="$IP6"
|
||||
fi
|
||||
|
||||
tbl=$($IP route list table $id 2>/dev/null)$'\n'
|
||||
mwan3_update_dev_to_table
|
||||
$IP route list table main | grep -v "^default\|linkdown\|^::/0\|^fe80::/64\|^unreachable" | while read route_line; do
|
||||
mwan3_get_routes | while read -r route_line; do
|
||||
mwan3_route_line_dev "tid" "$route_line" "$family"
|
||||
{ [ -z "${route_line##default*}" ] || [ -z "${route_line##fe80::/64*}" ]; } && [ "$tid" != "$id" ] && continue
|
||||
if [ -z "$tid" ] || [ "$tid" = "$id" ]; then
|
||||
# possible that routes are already in the table
|
||||
# if 'connected' was called after 'ifup'
|
||||
[ -n "$tbl" ] && [ -z "${tbl##*$route_line$'\n'*}" ] && continue
|
||||
$IP route add table $id $route_line ||
|
||||
LOG warn "failed to add $route_line to table $id"
|
||||
fi
|
||||
|
@ -582,63 +455,21 @@ mwan3_add_non_default_iface_route()
|
|||
done
|
||||
}
|
||||
|
||||
mwan3_add_all_nondefault_routes()
|
||||
{
|
||||
local tid IP route_line ipv family active_tbls tid
|
||||
|
||||
add_active_tbls()
|
||||
{
|
||||
let tid++
|
||||
config_get family "$1" family ipv4
|
||||
[ "$family" != "$ipv" ] && return
|
||||
$IP route list table $tid 2>/dev/null | grep -q "^default\|^::/0" && {
|
||||
active_tbls="$active_tbls${tid} "
|
||||
}
|
||||
}
|
||||
|
||||
add_route()
|
||||
{
|
||||
let tid++
|
||||
[ -n "${active_tbls##* $tid *}" ] && return
|
||||
$IP route add table $tid $route_line ||
|
||||
LOG warn "failed to add $route_line to table $tid"
|
||||
}
|
||||
|
||||
mwan3_update_dev_to_table
|
||||
for ipv in ipv4 ipv6; do
|
||||
[ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue
|
||||
if [ "$ipv" = "ipv4" ]; then
|
||||
IP="$IP4"
|
||||
elif [ "$ipv" = "ipv6" ]; then
|
||||
IP="$IP6"
|
||||
fi
|
||||
tid=0
|
||||
active_tbls=" "
|
||||
config_foreach add_active_tbls interface
|
||||
$IP route list table main | grep -v "^default\|linkdown\|^::/0\|^fe80::/64\|^unreachable" | while read route_line; do
|
||||
mwan3_route_line_dev "tid" "$route_line" "$ipv"
|
||||
if [ -n "$tid" ]; then
|
||||
$IP route add table $tid $route_line
|
||||
else
|
||||
config_foreach add_route interface
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
mwan3_delete_iface_route()
|
||||
{
|
||||
local id
|
||||
local id family
|
||||
|
||||
config_get family "$1" family ipv4
|
||||
mwan3_get_iface_id id "$1"
|
||||
|
||||
[ -n "$id" ] || return 0
|
||||
if [ -z "$id" ]; then
|
||||
LOG warn "delete_iface_route: could not find table id for interface $1"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$family" = "ipv4" ]; then
|
||||
$IP4 route flush table "$id"
|
||||
fi
|
||||
|
||||
if [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
|
||||
elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
|
||||
$IP6 route flush table "$id"
|
||||
fi
|
||||
}
|
||||
|
@ -660,21 +491,16 @@ mwan3_create_iface_rules()
|
|||
return
|
||||
fi
|
||||
|
||||
while [ -n "$($IP rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
|
||||
$IP rule del pref $(($id+1000))
|
||||
done
|
||||
mwan3_delete_iface_rules "$1"
|
||||
|
||||
while [ -n "$($IP rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
|
||||
$IP rule del pref $(($id+2000))
|
||||
done
|
||||
|
||||
$IP rule add pref $(($id+1000)) iif "$2" lookup "$id"
|
||||
$IP rule add pref $(($id+2000)) fwmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK lookup "$id"
|
||||
$IP rule add pref $((id+1000)) iif "$2" lookup "$id"
|
||||
$IP rule add pref $((id+2000)) fwmark "$(mwan3_id2mask id MMX_MASK)/$MMX_MASK" lookup "$id"
|
||||
$IP rule add pref $((id+3000)) fwmark "$(mwan3_id2mask id MMX_MASK)/$MMX_MASK" unreachable
|
||||
}
|
||||
|
||||
mwan3_delete_iface_rules()
|
||||
{
|
||||
local id family
|
||||
local id family IP rule_id
|
||||
|
||||
config_get family "$1" family ipv4
|
||||
mwan3_get_iface_id id "$1"
|
||||
|
@ -689,12 +515,8 @@ mwan3_delete_iface_rules()
|
|||
return
|
||||
fi
|
||||
|
||||
while [ -n "$($IP rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
|
||||
$IP rule del pref $(($id+1000))
|
||||
done
|
||||
|
||||
while [ -n "$($IP rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
|
||||
$IP rule del pref $(($id+2000))
|
||||
for rule_id in $(ip rule list | awk '$1 % 1000 == '$id' && $1 > 1000 && $1 < 4000 {print substr($1,0,4)}'); do
|
||||
$IP rule del pref $rule_id
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -713,39 +535,6 @@ mwan3_delete_iface_ipset_entries()
|
|||
done
|
||||
}
|
||||
|
||||
mwan3_rtmon()
|
||||
{
|
||||
local protocol
|
||||
for protocol in "ipv4" "ipv6"; do
|
||||
pid="$(pgrep -f "mwan3rtmon $protocol")"
|
||||
[ "$protocol" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue
|
||||
if [ "${pid}" = "" ]; then
|
||||
[ -x /usr/sbin/mwan3rtmon ] && /usr/sbin/mwan3rtmon $protocol &
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
mwan3_track()
|
||||
{
|
||||
local track_ips pids
|
||||
|
||||
mwan3_list_track_ips()
|
||||
{
|
||||
track_ips="$track_ips $1"
|
||||
}
|
||||
config_list_foreach "$1" track_ip mwan3_list_track_ips
|
||||
|
||||
# don't match device in case it changed from last launch
|
||||
if pids=$(pgrep -f "mwan3track $1 "); then
|
||||
kill -TERM $pids > /dev/null 2>&1
|
||||
sleep 1
|
||||
kill -KILL $(pgrep -f "mwan3track $1 ") > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
if [ -n "$track_ips" ]; then
|
||||
[ -x /usr/sbin/mwan3track ] && MWAN3_STARTUP=0 /usr/sbin/mwan3track "$1" "$2" "$3" "$4" $track_ips &
|
||||
fi
|
||||
}
|
||||
|
||||
mwan3_set_policy()
|
||||
{
|
||||
|
@ -776,7 +565,7 @@ mwan3_set_policy()
|
|||
IPT="$IPT6"
|
||||
IPTR="$IPT6R"
|
||||
fi
|
||||
current="$($IPT -S)"
|
||||
current="$($IPT -S)"$'\n'
|
||||
update="*mangle"
|
||||
|
||||
if [ "$family" = "ipv4" ] && [ $is_offline -eq 0 ]; then
|
||||
|
@ -785,7 +574,7 @@ mwan3_set_policy()
|
|||
total_weight_v4=$weight
|
||||
lowest_metric_v4=$metric
|
||||
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
|
||||
else
|
||||
return
|
||||
|
@ -796,7 +585,7 @@ mwan3_set_policy()
|
|||
total_weight_v6=$weight
|
||||
lowest_metric_v6=$metric
|
||||
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
|
||||
else
|
||||
return
|
||||
|
@ -807,9 +596,9 @@ mwan3_set_policy()
|
|||
mwan3_push_update -A "mwan3_policy_$policy" \
|
||||
-m mark --mark 0x0/$MMX_MASK \
|
||||
-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
|
||||
probability=$(($weight*1000/$total_weight))
|
||||
probability=$((weight*1000/total_weight))
|
||||
if [ "$probability" -lt 10 ]; then
|
||||
probability="0.00$probability"
|
||||
elif [ $probability -lt 100 ]; then
|
||||
|
@ -826,7 +615,7 @@ mwan3_set_policy()
|
|||
--mode random \
|
||||
--probability "$probability" \
|
||||
-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
|
||||
echo "$current" | grep -q "^-A mwan3_policy_$policy.*--comment .* [0-9]* [0-9]*" ||
|
||||
mwan3_push_update -I "mwan3_policy_$policy" \
|
||||
|
@ -855,10 +644,10 @@ mwan3_create_policies_iptables()
|
|||
|
||||
for IPT in "$IPT4" "$IPT6"; do
|
||||
[ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue
|
||||
current="$($IPT -S)"
|
||||
current="$($IPT -S)"$'\n'
|
||||
update="*mangle"
|
||||
if [ -n "${current##*-N mwan3_policy_$1*}" ]; then
|
||||
mwan3_push_update -N "mwan3_policy_$1"
|
||||
if [ -n "${current##*-N mwan3_policy_$1$'\n'*}" ]; then
|
||||
mwan3_push_update -N "mwan3_policy_$1"
|
||||
fi
|
||||
|
||||
mwan3_push_update -F "mwan3_policy_$1"
|
||||
|
@ -915,14 +704,14 @@ mwan3_set_sticky_iptables()
|
|||
mwan3_get_iface_id id "$1"
|
||||
|
||||
[ -n "$id" ] || return 0
|
||||
if [ -z "${current##*-N mwan3_iface_in_$1*}" ]; then
|
||||
if [ -z "${current##*-N mwan3_iface_in_$1$'\n'*}" ]; then
|
||||
mwan3_push_update -I "mwan3_rule_$rule" \
|
||||
-m mark --mark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK \
|
||||
-m mark --mark "$(mwan3_id2mask id MMX_MASK)/$MMX_MASK" \
|
||||
-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" \
|
||||
-m mark --mark 0/$MMX_MASK \
|
||||
-j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
|
||||
-m mark --mark "0/$MMX_MASK" \
|
||||
-j MARK --set-xmark "$(mwan3_id2mask id MMX_MASK)/$MMX_MASK"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
@ -932,7 +721,7 @@ mwan3_set_user_iptables_rule()
|
|||
{
|
||||
local ipset family proto policy src_ip src_port src_iface src_dev
|
||||
local sticky dest_ip dest_port use_policy timeout policy
|
||||
local global_logging rule_logging loglevel rule_policy rule ipv
|
||||
local global_logging rule_logging loglevel rule_policy rule ipv
|
||||
|
||||
rule="$1"
|
||||
ipv="$2"
|
||||
|
@ -952,6 +741,18 @@ mwan3_set_user_iptables_rule()
|
|||
config_get global_logging globals logging 0
|
||||
config_get loglevel globals loglevel notice
|
||||
|
||||
[ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && return
|
||||
[ "$family" = "ipv4" ] && [ "$ipv" = "ipv6" ] && return
|
||||
[ "$family" = "ipv6" ] && [ "$ipv" = "ipv4" ] && return
|
||||
|
||||
for ipaddr in "$src_ip" "$dest_ip"; do
|
||||
if [ -n "$ipaddr" ] && { { [ "$ipv" = "ipv4" ] && echo "$ipaddr" | grep -qE "$IPv6_REGEX"; } ||
|
||||
{ [ "$ipv" = "ipv6" ] && echo "$ipaddr" | grep -qE $IPv4_REGEX; } }; then
|
||||
LOG warn "invalid $ipv address $ipaddr specified for rule $rule"
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$src_iface" ]; then
|
||||
network_get_device src_dev "$src_iface"
|
||||
if [ -z "$src_dev" ]; then
|
||||
|
@ -963,9 +764,9 @@ mwan3_set_user_iptables_rule()
|
|||
[ -z "$dest_ip" ] && unset dest_ip
|
||||
[ -z "$src_ip" ] && unset src_ip
|
||||
[ -z "$ipset" ] && unset ipset
|
||||
[ -z "$src_port" ] && unset src_port
|
||||
[ -z "$dest_port" ] && unset dest_port
|
||||
if [ "$proto" != 'tcp' ] && [ "$proto" != 'udp' ]; then
|
||||
[ -z "$src_port" ] && unset src_port
|
||||
[ -z "$dest_port" ] && unset dest_port
|
||||
if [ "$proto" != 'tcp' ] && [ "$proto" != 'udp' ]; then
|
||||
[ -n "$src_port" ] && {
|
||||
LOG warn "src_port set to '$src_port' but proto set to '$proto' not tcp or udp. src_port will be ignored"
|
||||
}
|
||||
|
@ -1013,16 +814,12 @@ mwan3_set_user_iptables_rule()
|
|||
fi
|
||||
fi
|
||||
|
||||
[ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && return
|
||||
[ "$family" = "ipv4" ] && [ "$ipv" = "ipv6" ] && return
|
||||
[ "$family" = "ipv6" ] && [ "$ipv" = "ipv4" ] && return
|
||||
|
||||
if [ $rule_policy -eq 1 ] && [ -n "${current##*-N $policy*}" ]; then
|
||||
if [ $rule_policy -eq 1 ] && [ -n "${current##*-N $policy$'\n'*}" ]; then
|
||||
mwan3_push_update -N "$policy"
|
||||
fi
|
||||
|
||||
if [ $rule_policy -eq 1 ] && [ "$sticky" -eq 1 ]; then
|
||||
if [ -n "${current##*-N mwan3_rule_$1*}" ]; then
|
||||
if [ -n "${current##*-N mwan3_rule_$1$'\n'*}" ]; then
|
||||
mwan3_push_update -N "mwan3_rule_$1"
|
||||
fi
|
||||
|
||||
|
@ -1117,7 +914,7 @@ mwan3_set_user_rules()
|
|||
fi
|
||||
[ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue
|
||||
update="*mangle"
|
||||
current="$($IPT -S)"
|
||||
current="$($IPT -S)"$'\n'
|
||||
|
||||
|
||||
if [ -n "${current##*-N mwan3_rules*}" ]; then
|
||||
|
@ -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() {
|
||||
local iface=$1
|
||||
local state=$2
|
||||
|
@ -1151,7 +1025,7 @@ mwan3_get_iface_hotplug_state() {
|
|||
|
||||
mwan3_report_iface_status()
|
||||
{
|
||||
local device result track_ips tracking IP IPT
|
||||
local device result tracking IP IPT
|
||||
|
||||
mwan3_get_iface_id id "$1"
|
||||
network_get_device device "$1"
|
||||
|
@ -1170,8 +1044,9 @@ mwan3_report_iface_status()
|
|||
|
||||
if [ -z "$id" ] || [ -z "$device" ]; then
|
||||
result="offline"
|
||||
elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" ] && \
|
||||
[ -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" ] && \
|
||||
elif [ -n "$($IP rule | awk '$1 == "'$((id+1000)):'"')" ] && \
|
||||
[ -n "$($IP rule | awk '$1 == "'$((id+2000)):'"')" ] && \
|
||||
[ -n "$($IP rule | awk '$1 == "'$((id+3000)):'"')" ] && \
|
||||
[ -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" ] && \
|
||||
[ -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
|
||||
json_init
|
||||
|
@ -1183,11 +1058,12 @@ mwan3_report_iface_status()
|
|||
json_get_vars online uptime
|
||||
json_select ..
|
||||
json_select ..
|
||||
online="$(printf '%02dh:%02dm:%02ds\n' $(($online/3600)) $(($online%3600/60)) $(($online%60)))"
|
||||
uptime="$(printf '%02dh:%02dm:%02ds\n' $(($uptime/3600)) $(($uptime%3600/60)) $(($uptime%60)))"
|
||||
online="$(printf '%02dh:%02dm:%02ds\n' $((online/3600)) $((online%3600/60)) $((online%60)))"
|
||||
uptime="$(printf '%02dh:%02dm:%02ds\n' $((uptime/3600)) $((uptime%3600/60)) $((uptime%60)))"
|
||||
result="$(mwan3_get_iface_hotplug_state $1) $online, uptime $uptime"
|
||||
elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" ] || \
|
||||
[ -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" ] || \
|
||||
elif [ -n "$($IP rule | awk '$1 == "'$((id+1000)):'"')" ] || \
|
||||
[ -n "$($IP rule | awk '$1 == "'$((id+2000)):'"')" ] || \
|
||||
[ -n "$($IP rule | awk '$1 == "'$((id+3000)):'"')" ] || \
|
||||
[ -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" ] || \
|
||||
[ -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
|
||||
result="error"
|
||||
|
@ -1197,22 +1073,7 @@ mwan3_report_iface_status()
|
|||
result="disabled"
|
||||
fi
|
||||
|
||||
mwan3_list_track_ips()
|
||||
{
|
||||
track_ips="$1 $track_ips"
|
||||
}
|
||||
config_list_foreach "$1" track_ip mwan3_list_track_ips
|
||||
|
||||
if [ -n "$track_ips" ]; then
|
||||
if [ -n "$(pgrep -f "mwan3track $1 $device")" ]; then
|
||||
tracking="active"
|
||||
else
|
||||
tracking="down"
|
||||
fi
|
||||
else
|
||||
tracking="not enabled"
|
||||
fi
|
||||
|
||||
tracking="$(mwan3_get_mwan3track_status $1)"
|
||||
echo " interface $1 is $result and tracking is $tracking"
|
||||
}
|
||||
|
||||
|
@ -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}')
|
||||
|
||||
if [ ! -z "${total_weight##*[!0-9]*}" ]; then
|
||||
if [ -n "${total_weight##*[!0-9]*}" ]; then
|
||||
for iface in $($ipt -S "$policy" | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | awk '{print $1}'); do
|
||||
weight=$($ipt -S "$policy" | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | awk '$1 == "'$iface'"' | awk '{print $2}')
|
||||
percent=$(($weight*100/$total_weight))
|
||||
percent=$((weight*100/total_weight))
|
||||
echo " $iface ($percent%)"
|
||||
done
|
||||
else
|
||||
|
@ -1306,6 +1167,6 @@ mwan3_flush_conntrack()
|
|||
|
||||
mwan3_track_clean()
|
||||
{
|
||||
rm -rf "$MWAN3_STATUS_DIR/${1}" &> /dev/null
|
||||
rm -rf "${MWAN3_STATUS_DIR:?}/${1}" &> /dev/null
|
||||
rmdir --ignore-fail-on-non-empty "$MWAN3_STATUS_DIR"
|
||||
}
|
||||
|
|
|
@ -77,16 +77,13 @@ get_mwan3_status() {
|
|||
local online=0
|
||||
local offline=0
|
||||
local up="0"
|
||||
local enabled pid device time_p time_n time_u time_d status
|
||||
local enabled device time_p time_n time_u time_d status track_status
|
||||
|
||||
network_get_device device $1
|
||||
|
||||
if [ "${iface}" = "${iface_select}" ] || [ "${iface_select}" = "" ]; then
|
||||
pid="$(pgrep -f "mwan3track $iface $device")"
|
||||
if [ "${pid}" != "" ]; then
|
||||
running="1"
|
||||
fi
|
||||
|
||||
track_status="$(mwan3_get_mwan3track_status "$1")"
|
||||
[ "$track_status" = "active" ] && running="1"
|
||||
time_p="$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/TIME")"
|
||||
[ -z "${time_p}" ] || {
|
||||
time_n="$(get_uptime)"
|
||||
|
|
|
@ -12,39 +12,37 @@ help()
|
|||
Syntax: mwan3 [command]
|
||||
|
||||
Available commands:
|
||||
start Load iptables rules, ip rules and ip routes
|
||||
stop Unload iptables rules, ip rules and ip routes
|
||||
restart Reload iptables rules, ip rules and ip routes
|
||||
ifup <iface> Load rules and routes for specific interface
|
||||
ifdown <iface> Unload rules and routes for specific interface
|
||||
interfaces Show interfaces status
|
||||
policies Show currently active policy
|
||||
connected Show directly connected networks
|
||||
rules Show active rules
|
||||
status Show all status
|
||||
|
||||
start Load iptables rules, ip rules and ip routes
|
||||
stop Unload iptables rules, ip rules and ip routes
|
||||
restart Reload iptables rules, ip rules and ip routes
|
||||
ifup <iface> Load rules and routes for specific interface
|
||||
ifdown <iface> Unload rules and routes for specific interface
|
||||
interfaces Show interfaces status
|
||||
policies Show currently active policy
|
||||
connected Show directly connected networks
|
||||
rules Show active rules
|
||||
status Show all status
|
||||
use <iface> <cmd> Run a command bound to <iface> and avoid mwan3 rules
|
||||
EOF
|
||||
}
|
||||
|
||||
ifdown()
|
||||
{
|
||||
|
||||
ifdown() {
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
ACTION=ifdown INTERFACE=$1 /sbin/hotplug-call iface
|
||||
|
||||
kill $(pgrep -f "mwan3track $1 ") &> /dev/null
|
||||
mwan3_track_clean $1
|
||||
mwan3_interface_hotplug_shutdown "$1" 1
|
||||
}
|
||||
|
||||
ifup()
|
||||
{
|
||||
local device enabled up l3_device status interface true_iface
|
||||
ifup() {
|
||||
. /etc/init.d/mwan3
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Expecting interface. Usage: mwan3 ifup <interface>"
|
||||
|
@ -56,46 +54,7 @@ ifup()
|
|||
exit 0
|
||||
fi
|
||||
|
||||
interface=$1
|
||||
|
||||
if [ "${MWAN3_STARTUP}" != 1 ]; then
|
||||
# It is not necessary to obtain a lock here, because it is obtained in the hotplug
|
||||
# script, but we still want to do the check to print a useful error message
|
||||
config_load mwan3
|
||||
config_get_bool enabled globals 'enabled' 0
|
||||
|
||||
[ ${enabled} -gt 0 ] || {
|
||||
echo "The service mwan3 is global disabled."
|
||||
echo "Please execute \"/etc/init.d/mwan3 start\" first."
|
||||
exit 1
|
||||
}
|
||||
else
|
||||
enabled=1
|
||||
fi
|
||||
mwan3_get_true_iface true_iface $interface
|
||||
status=$(ubus -S call network.interface.$true_iface status)
|
||||
|
||||
[ -n "$status" ] && {
|
||||
json_load "$status"
|
||||
json_get_vars up l3_device
|
||||
}
|
||||
hotplug_startup()
|
||||
{
|
||||
MWAN3_STARTUP=$MWAN3_STARTUP ACTION=ifup INTERFACE=$interface DEVICE=$l3_device TRUE_INTERFACE=$true_iface sh /etc/hotplug.d/iface/15-mwan3
|
||||
MWAN3_STARTUP=$MWAN3_STARTUP ACTION=ifup INTERFACE=$interface DEVICE=$l3_device TRUE_INTERFACE=$true_iface sh /etc/hotplug.d/iface/16-mwan3-user
|
||||
}
|
||||
|
||||
if [ "$up" != "1" ] || [ -z "$l3_device" ] || [ "$enabled" != "1" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "${MWAN3_STARTUP}" = 1 ]; then
|
||||
hotplug_startup &
|
||||
hotplug_pids="$hotplug_pids $!"
|
||||
else
|
||||
hotplug_startup
|
||||
fi
|
||||
|
||||
mwan3_ifup "$1"
|
||||
}
|
||||
|
||||
interfaces()
|
||||
|
@ -104,40 +63,40 @@ interfaces()
|
|||
|
||||
echo "Interface status:"
|
||||
config_foreach mwan3_report_iface_status interface
|
||||
echo -e
|
||||
echo
|
||||
}
|
||||
|
||||
policies()
|
||||
{
|
||||
echo "Current ipv4 policies:"
|
||||
mwan3_report_policies_v4
|
||||
echo -e
|
||||
echo
|
||||
[ $NO_IPV6 -ne 0 ] && return
|
||||
echo "Current ipv6 policies:"
|
||||
mwan3_report_policies_v6
|
||||
echo -e
|
||||
echo
|
||||
}
|
||||
|
||||
connected()
|
||||
{
|
||||
echo "Directly connected ipv4 networks:"
|
||||
mwan3_report_connected_v4
|
||||
echo -e
|
||||
echo
|
||||
[ $NO_IPV6 -ne 0 ] && return
|
||||
echo "Directly connected ipv6 networks:"
|
||||
mwan3_report_connected_v6
|
||||
echo -e
|
||||
echo
|
||||
}
|
||||
|
||||
rules()
|
||||
{
|
||||
echo "Active ipv4 user rules:"
|
||||
mwan3_report_rules_v4
|
||||
echo -e
|
||||
echo
|
||||
[ $NO_IPV6 -ne 0 ] && return
|
||||
echo "Active ipv6 user rules:"
|
||||
mwan3_report_rules_v6
|
||||
echo -e
|
||||
echo
|
||||
}
|
||||
|
||||
status()
|
||||
|
@ -148,113 +107,51 @@ status()
|
|||
rules
|
||||
}
|
||||
|
||||
start()
|
||||
{
|
||||
local enabled hotplug_pids MWAN3_STARTUP
|
||||
MWAN3_STARTUP=1
|
||||
mwan3_lock "command" "mwan3"
|
||||
uci_toggle_state mwan3 globals enabled "1"
|
||||
config_load mwan3
|
||||
|
||||
mwan3_update_iface_to_table
|
||||
mwan3_set_connected_iptables
|
||||
mwan3_set_custom_ipset
|
||||
mwan3_set_general_rules
|
||||
mwan3_set_general_iptables
|
||||
config_foreach ifup interface
|
||||
wait $hotplug_pids
|
||||
mwan3_add_all_nondefault_routes
|
||||
mwan3_set_policies_iptables
|
||||
mwan3_set_user_rules
|
||||
|
||||
|
||||
mwan3_unlock "command" "mwan3"
|
||||
mwan3_rtmon
|
||||
unset MWAN3_STARTUP
|
||||
start() {
|
||||
/etc/init.d/mwan3 enable
|
||||
/etc/init.d/mwan3 start
|
||||
}
|
||||
|
||||
stop()
|
||||
{
|
||||
local ipset rule IP IPTR IPT kill_pid family table tid
|
||||
|
||||
mwan3_lock "command" "mwan3"
|
||||
uci_toggle_state mwan3 globals enabled "0"
|
||||
|
||||
{
|
||||
kill -TERM $(pgrep -f "mwan3rtmon") > /dev/null 2>&1
|
||||
kill -TERM $(pgrep -f "mwan3track") > /dev/null 2>&1
|
||||
|
||||
sleep 1
|
||||
|
||||
kill -KILL $(pgrep -f "mwan3rtmon") > /dev/null 2>&1
|
||||
kill -KILL $(pgrep -f "mwan3track") > /dev/null 2>&1
|
||||
} &
|
||||
kill_pid=$!
|
||||
config_load mwan3
|
||||
config_foreach mwan3_track_clean interface
|
||||
|
||||
for family in ipv4 ipv6; do
|
||||
if [ "$family" = "ipv4" ]; then
|
||||
IPT="$IPT4"
|
||||
IPTR="$IPT4R"
|
||||
IP="$IP4"
|
||||
elif [ "$family" = "ipv6" ]; then
|
||||
[ $NO_IPV6 -ne 0 ] && continue
|
||||
IPT="$IPT6"
|
||||
IPTR="$IPT6R"
|
||||
IP="$IP6"
|
||||
fi
|
||||
|
||||
for tid in $(ip route list table all | sed -ne 's/.*table \([0-9]\+\).*/\1/p'|sort -u); do
|
||||
[ $tid -gt $MWAN3_INTERFACE_MAX ] && continue
|
||||
$IP route flush table $tid &> /dev/null
|
||||
done
|
||||
|
||||
for rule in $($IP rule list | 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"
|
||||
|
||||
stop() {
|
||||
/etc/init.d/mwan3 disable
|
||||
/etc/init.d/mwan3 stop
|
||||
}
|
||||
|
||||
restart() {
|
||||
stop
|
||||
start
|
||||
/etc/init.d/mwan3 enable
|
||||
/etc/init.d/mwan3 stop
|
||||
/etc/init.d/mwan3 start
|
||||
}
|
||||
|
||||
wrap() {
|
||||
# Run a command with the device, src_ip and fwmark set to avoid processing by mwan3
|
||||
# firewall rules
|
||||
|
||||
local interface device src_ip family
|
||||
mwan3_init
|
||||
config_load mwan3
|
||||
|
||||
interface=$1 ; shift
|
||||
[ -z "$*" ] && echo "no command specified for mwan3 wrap" && return
|
||||
network_get_device device $interface
|
||||
[ -z "$device" ] && echo "could not find device for $interface" && return
|
||||
|
||||
mwan3_get_src_ip src_ip $interface
|
||||
[ -z "$src_ip" ] && echo "could not find src_ip for $interface" && return
|
||||
|
||||
config_get family $interface family
|
||||
[ -z "$family" ] && echo "could not find family for $interface. Using ipv4." && family='ipv4'
|
||||
|
||||
echo "Running '$*' with DEVICE=$device SRCIP=$src_ip FWMARK=$MMX_DEFAULT FAMILY=$family"
|
||||
# shellcheck disable=SC2048
|
||||
FAMILY=$family DEVICE=$device SRCIP=$src_ip FWMARK=$MMX_DEFAULT LD_PRELOAD=/lib/mwan3/libwrap_mwan3_sockopt.so.1.0 $*
|
||||
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
ifup|ifdown|interfaces|policies|connected|rules|status|start|stop|restart)
|
||||
ifup|ifdown|interfaces|policies|connected|rules|status|start|stop|restart|use)
|
||||
mwan3_init
|
||||
# shellcheck disable=SC2048
|
||||
$*
|
||||
;;
|
||||
*)
|
||||
|
|
|
@ -5,82 +5,139 @@
|
|||
. /lib/mwan3/mwan3.sh
|
||||
. /lib/mwan3/common.sh
|
||||
|
||||
trap_with_arg()
|
||||
{
|
||||
func="$1" ; shift
|
||||
pid="$1" ; shift
|
||||
for sig ; do
|
||||
# shellcheck disable=SC2064
|
||||
trap "$func $sig $pid" "$sig"
|
||||
done
|
||||
}
|
||||
|
||||
func_trap()
|
||||
{
|
||||
kill -${1} ${2} 2>/dev/null
|
||||
}
|
||||
|
||||
mwan3_add_all_routes()
|
||||
{
|
||||
local tid IP IPT route_line family active_tbls tid initial_state
|
||||
local ipv=$1
|
||||
|
||||
add_active_tbls()
|
||||
{
|
||||
let tid++
|
||||
config_get family "$1" family ipv4
|
||||
config_get initial_state "$1" initial_state "online"
|
||||
[ "$family" != "$ipv" ] && return
|
||||
if $IPT -S "mwan3_iface_in_$1" &> /dev/null; then
|
||||
active_tbls="$active_tbls${tid} "
|
||||
fi
|
||||
}
|
||||
|
||||
add_route()
|
||||
{
|
||||
let tid++
|
||||
[ -n "${active_tbls##* $tid *}" ] && return
|
||||
$IP route add table $tid $route_line ||
|
||||
LOG warn "failed to add $route_line to table $tid"
|
||||
}
|
||||
|
||||
mwan3_update_dev_to_table
|
||||
[ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && return
|
||||
if [ "$ipv" = "ipv4" ]; then
|
||||
IP="$IP4"
|
||||
IPT="$IPT4"
|
||||
elif [ "$ipv" = "ipv6" ]; then
|
||||
IP="$IP6"
|
||||
IPT="$IPT6"
|
||||
fi
|
||||
tid=0
|
||||
active_tbls=" "
|
||||
config_foreach add_active_tbls interface
|
||||
[ $active_tbls = " " ] && return
|
||||
mwan3_get_routes | while read -r route_line; do
|
||||
mwan3_route_line_dev "tid" "$route_line" "$ipv"
|
||||
if [ -n "$tid" ] && [ -z "${active_tbls##* $tid *}" ]; then
|
||||
$IP route add table $tid $route_line
|
||||
elif [ -n "${route_line##default*}" ] && [ -n "${route_line##fe80::/64*}" ]; then
|
||||
config_foreach add_route interface
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
mwan3_rtmon_route_handle()
|
||||
{
|
||||
config_load mwan3
|
||||
local section action route_line family tbl device metric tos dst line
|
||||
local route_device tid
|
||||
local action route_line family tbl device line route_line_exp tid source_routing
|
||||
|
||||
route_line=${1##"Deleted "}
|
||||
route_family=$2
|
||||
|
||||
config_get_boolean source_routing globals source_routing 0
|
||||
[ $source_routing -eq 0 ] && unset source_routing
|
||||
|
||||
if [ "$route_line" = "$1" ]; then
|
||||
action="replace"
|
||||
route_line_exp="s/expires \([0-9]\+\)sec//;s/error [0-9]\+//; ${source_routing:+s/default\(.*\) from [^ ]*/default\1/}"
|
||||
$IPS -! add mwan3_connected_${route_family##ip} ${route_line%% *}
|
||||
else
|
||||
action="del"
|
||||
route_line_exp="s/expires [0-9]\+sec//;s/error [0-9]\+//; ${source_routing:+s/default\(.*\) from [^ ]*/default\1/}"
|
||||
mwan3_set_connected_${route_family}
|
||||
fi
|
||||
|
||||
if [ "$route_family" = "ipv4" ]; then
|
||||
IP="$IP4"
|
||||
elif [ "$route_family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
|
||||
IP="$IP6"
|
||||
route_line=$(echo "$route_line" | sed "$route_line_exp")
|
||||
else
|
||||
LOG warn "route update called with invalid family - $route_family"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "$route_line" == "$1" ]; then
|
||||
action="add"
|
||||
else
|
||||
action="del"
|
||||
# don't try to add routes when link has gone down
|
||||
if [ -z "${route_line##linkdown*}" ]; then
|
||||
LOG debug "not adding route due to linkdown - skipping $route_line"
|
||||
return
|
||||
fi
|
||||
|
||||
# never add default route lines, since this is handled elsewhere
|
||||
[ -z "${route_line##default*}" ] && return
|
||||
[ -z "${route_line##::/0*}" ] && return
|
||||
route_line=${route_line%% linkdown*}
|
||||
route_line=${route_line%% unreachable*}
|
||||
mwan3_update_dev_to_table
|
||||
mwan3_route_line_dev "tid" "$route_line" "$route_family"
|
||||
handle_route() {
|
||||
tbl=$($IP route list table $tid)
|
||||
if [ $action = "add" ]; then
|
||||
echo "$tbl" | grep -q "^default\|^::/0" || return
|
||||
else
|
||||
[ -z "$tbl" ] && return
|
||||
fi
|
||||
# check that action needs to be performed. May not need to take action if:
|
||||
# Got a route update on ipv6 where route is already in the table
|
||||
# Got a delete event, but table was already flushed
|
||||
local iface=$1
|
||||
tbl=$($IP route list table $tid 2>/dev/null)$'\n'
|
||||
|
||||
[ $action = "add" ] && [ -z "${tbl##*$route_line*}" ] && return
|
||||
[ $action = "del" ] && [ -n "${tbl##*$route_line*}" ] && return
|
||||
network_get_device device "$section"
|
||||
LOG debug "adjusting route $device: $IP route "$action" table $tid $route_line"
|
||||
if [ "$(cat /var/run/mwan3track/$iface/STATUS)" != "online" ]; then
|
||||
LOG debug "interface $iface is offline - skipping $route_line";
|
||||
return
|
||||
fi
|
||||
|
||||
# check that action needs to be performed. May not need to take action if we
|
||||
# got a delete event, but table was already flushed
|
||||
if [ $action = "del" ] && [ -n "${tbl##*$route_line$'\n'*}" ]; then
|
||||
LOG debug "skipping already deleted route table $tid - skipping $route_line"
|
||||
return
|
||||
fi
|
||||
|
||||
network_get_device device "$iface"
|
||||
LOG debug "adjusting route $device: $IP route $action table $tid $route_line"
|
||||
$IP route "$action" table $tid $route_line ||
|
||||
LOG warn "failed: $IP route $action table $tid $route_line"
|
||||
}
|
||||
handle_route_cb(){
|
||||
local iface=$1
|
||||
let tid++
|
||||
config_get family "$section" family ipv4
|
||||
config_get family "$iface" family ipv4
|
||||
[ "$family" != "$route_family" ] && return
|
||||
handle_route
|
||||
handle_route "$iface"
|
||||
}
|
||||
|
||||
if [ $action = "add" ]; then
|
||||
## handle old routes from 'change' or 'replace'
|
||||
metric=${route_line##*metric }
|
||||
[ "$metric" = "$route_line" ] && unset metric || metric=${metric%% *}
|
||||
|
||||
tos=${route_line##*tos }
|
||||
[ "$tos" = "$route_line" ] && unset tos || tos=${tos%% *}
|
||||
|
||||
dst=${route_line%% *}
|
||||
grep_line="$dst ${tos:+tos $tos}.*table [0-9].*${metric:+metric $metric}"
|
||||
$IP route list table all | grep "$grep_line" | while read line; do
|
||||
tbl=${line##*table }
|
||||
tbl=${tbl%% *}
|
||||
[ $tbl -gt $MWAN3_INTERFACE_MAX ] && continue
|
||||
LOG debug "removing route on ip route change/replace: $line"
|
||||
$IP route del $line
|
||||
done
|
||||
fi
|
||||
mwan3_update_dev_to_table
|
||||
mwan3_route_line_dev "tid" "$route_line" "$route_family"
|
||||
|
||||
if [ -n "$tid" ]; then
|
||||
handle_route
|
||||
else
|
||||
elif [ -n "${route_line##default*}" ] && [ -n "${route_line##fe80::/64*}" ]; then
|
||||
config_foreach handle_route_cb interface
|
||||
fi
|
||||
}
|
||||
|
@ -92,19 +149,35 @@ main()
|
|||
config_load mwan3
|
||||
family=$1
|
||||
[ -z $family ] && family=ipv4
|
||||
if [ "$family" = ipv6 ]; then
|
||||
if [ "$family" = "ipv6" ]; then
|
||||
if [ $NO_IPV6 -ne 0 ]; then
|
||||
LOG warn "mwan3rtmon started for ipv6, but ipv6 not enabled on system"
|
||||
exit 1
|
||||
fi
|
||||
IP="$IP6"
|
||||
else
|
||||
IP="$IP4"
|
||||
fi
|
||||
mwan3_init
|
||||
|
||||
$IP monitor route | while read line; do
|
||||
[ -z "${line##*table*}" ] && continue
|
||||
LOG debug "handling route update $family $line"
|
||||
mwan3_lock "service" "mwan3rtmon"
|
||||
mwan3_rtmon_route_handle "$line" "$family"
|
||||
mwan3_unlock "service" "mwan3rtmon"
|
||||
done
|
||||
mwan3_lock "mwan3rtmon" "start"
|
||||
sh -c "echo \$\$; exec $IP monitor route" | {
|
||||
read -r monitor_pid
|
||||
trap_with_arg func_trap "$monitor_pid" SIGINT SIGTERM SIGKILL
|
||||
while read -r line; do
|
||||
[ -z "${line##*table*}" ] && continue
|
||||
LOG debug "handling route update $family $line"
|
||||
mwan3_lock "service" "mwan3rtmon"
|
||||
mwan3_rtmon_route_handle "$line" "$family"
|
||||
mwan3_unlock "service" "mwan3rtmon"
|
||||
done
|
||||
} &
|
||||
child=$!
|
||||
kill -SIGSTOP $child
|
||||
trap_with_arg func_trap "$child" SIGINT SIGTERM SIGKILL
|
||||
mwan3_set_connected_${family}
|
||||
mwan3_add_all_routes ${family}
|
||||
mwan3_unlock "mwan3rtmon" "start"
|
||||
kill -SIGCONT $child
|
||||
wait $!
|
||||
}
|
||||
main "$@"
|
||||
|
|
|
@ -1,37 +1,64 @@
|
|||
#!/bin/sh
|
||||
|
||||
. /lib/functions.sh
|
||||
. /lib/functions/network.sh
|
||||
. /lib/mwan3/common.sh
|
||||
|
||||
INTERFACE=""
|
||||
DEVICE=""
|
||||
PING="/bin/ping"
|
||||
|
||||
IFDOWN_EVENT=0
|
||||
IFUP_EVENT=0
|
||||
TRACK_OUTPUT=$MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_OUTPUT
|
||||
|
||||
mwan3_init
|
||||
|
||||
stop_subprocs() {
|
||||
[ -n "$SLEEP_PID" ] && kill "$SLEEP_PID" && unset SLEEP_PID
|
||||
[ -n "$TRACK_PID" ] && kill "$TRACK_PID" && unset TRACK_PID
|
||||
}
|
||||
|
||||
WRAP() {
|
||||
# shellcheck disable=SC2048
|
||||
FAMILY=$FAMILY DEVICE=$DEVICE SRCIP=$SRC_IP FWMARK=$MMX_DEFAULT LD_PRELOAD=/lib/mwan3/libwrap_mwan3_sockopt.so.1.0 $*
|
||||
}
|
||||
|
||||
clean_up() {
|
||||
LOG notice "Stopping mwan3track for interface \"${INTERFACE}\""
|
||||
LOG notice "Stopping mwan3track for interface \"${INTERFACE}\". Status was \"${STATUS}\""
|
||||
stop_subprocs
|
||||
exit 0
|
||||
}
|
||||
|
||||
if_down() {
|
||||
LOG info "Detect ifdown event on interface ${INTERFACE} (${DEVICE})"
|
||||
IFDOWN_EVENT=1
|
||||
stop_subprocs
|
||||
}
|
||||
|
||||
if_up() {
|
||||
LOG info "Detect ifup event on interface ${INTERFACE} (${DEVICE})"
|
||||
IFDOWN_EVENT=0
|
||||
IFUP_EVENT=1
|
||||
STARTED=1
|
||||
stop_subprocs
|
||||
}
|
||||
|
||||
validate_track_method() {
|
||||
case "$1" in
|
||||
ping)
|
||||
[ -x "$PING" ] || {
|
||||
LOG warn "Missing ping. Please enable ping util and recompile busybox."
|
||||
if [ -x "/usr/bin/ping" ] && [ "$(/usr/bin/ping -V | grep -o '[0-9]*$')" -gt 20150519 ]; then
|
||||
# -4 option added in iputils c3e68ac6
|
||||
PING="/usr/bin/ping -${FAMILY#ipv}"
|
||||
elif [ "$FAMILY" = "ipv6" ] && [ -x "/usr/bin/ping6" ]; then
|
||||
PING="/usr/bin/ping6"
|
||||
elif [ "$FAMILY" = "ipv4" ] && [ -x "/usr/bin/ping" ]; then
|
||||
PING="/usr/bin/ping"
|
||||
elif [ -x "/bin/ping" ]; then
|
||||
PING="/bin/ping -${FAMILY#ipv}"
|
||||
else
|
||||
LOG warn "Missing ping. Please enable BUSYBOX_DEFAULT_PING and recompile busybox or install iputils-ping package."
|
||||
return 1
|
||||
}
|
||||
fi
|
||||
;;
|
||||
arping)
|
||||
command -v arping 1>/dev/null 2>&1 || {
|
||||
|
@ -44,10 +71,6 @@ validate_track_method() {
|
|||
LOG warn "Missing httping. Please install httping package."
|
||||
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-*)
|
||||
command -v nping 1>/dev/null 2>&1 || {
|
||||
|
@ -62,30 +85,63 @@ validate_track_method() {
|
|||
esac
|
||||
}
|
||||
|
||||
validate_wrap() {
|
||||
[ -x /lib/mwan3/libwrap_mwan3_sockopt.so.1.0 ] && return
|
||||
LOG error "Missing libwrap_mwan3_sockopt. Please reinstall mwan3." &&
|
||||
exit 1
|
||||
}
|
||||
|
||||
disconnected() {
|
||||
echo "offline" > /var/run/mwan3track/$INTERFACE/STATUS
|
||||
echo "$(get_uptime)" > /var/run/mwan3track/$INTERFACE/OFFLINE
|
||||
echo "0" > /var/run/mwan3track/$INTERFACE/ONLINE
|
||||
STATUS='offline'
|
||||
echo "offline" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS
|
||||
get_uptime > $MWAN3TRACK_STATUS_DIR/$INTERFACE/OFFLINE
|
||||
echo "0" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/ONLINE
|
||||
score=0
|
||||
[ "$1" == 1 ] && return
|
||||
[ "$1" = 1 ] && return
|
||||
LOG notice "Interface $INTERFACE ($DEVICE) is offline"
|
||||
env -i ACTION="disconnected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface
|
||||
}
|
||||
|
||||
connected() {
|
||||
echo "online" > /var/run/mwan3track/$INTERFACE/STATUS
|
||||
echo "0" > /var/run/mwan3track/$INTERFACE/OFFLINE
|
||||
echo "$(get_uptime)" > /var/run/mwan3track/$INTERFACE/ONLINE
|
||||
STATUS='online'
|
||||
echo "online" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS
|
||||
echo "0" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/OFFLINE
|
||||
get_uptime > $MWAN3TRACK_STATUS_DIR/$INTERFACE/ONLINE
|
||||
host_up_count=0
|
||||
lost=0
|
||||
turn=0
|
||||
loss=0
|
||||
[ "$1" == 1 ] && return
|
||||
LOG notice "Interface $INTERFACE ($DEVICE) is online"
|
||||
env -i ACTION="connected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface
|
||||
env -i FIRSTCONNECT=$1 ACTION="connected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface
|
||||
}
|
||||
|
||||
disabled() {
|
||||
STATUS='disabled'
|
||||
echo "disabled" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS
|
||||
STARTED=0
|
||||
}
|
||||
|
||||
firstconnect() {
|
||||
local true_iface
|
||||
network_flush_cache
|
||||
|
||||
mwan3_get_true_iface true_iface $INTERFACE
|
||||
network_get_device DEVICE $true_iface
|
||||
|
||||
if [ "$STATUS" != "online" ]; then
|
||||
config_get STATUS $INTERFACE initial_state "online"
|
||||
fi
|
||||
|
||||
if ! network_is_up $true_iface || [ -z "$DEVICE" ]; then
|
||||
disabled
|
||||
return
|
||||
fi
|
||||
|
||||
mwan3_get_src_ip SRC_IP $INTERFACE
|
||||
|
||||
LOG debug "firstconnect: called on $INTERFACE/$true_iface ($DEVICE). Status is $STATUS. SRC_IP is $SRC_IP"
|
||||
|
||||
STARTED=1
|
||||
if [ "$STATUS" = "offline" ]; then
|
||||
disconnected 1
|
||||
else
|
||||
|
@ -94,14 +150,12 @@ firstconnect() {
|
|||
}
|
||||
|
||||
update_status() {
|
||||
local status track_ip
|
||||
track_ip=$1
|
||||
status=$2
|
||||
local track_ip=$1
|
||||
|
||||
echo "$1" > /var/run/mwan3track/$INTERFACE/TRACK_${track_ip}
|
||||
echo "$2" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_${track_ip}
|
||||
[ -z "$3" ] && return
|
||||
echo "$3" > /var/run/mwan3track/$INTERFACE/LATENCY_${track_ip}
|
||||
echo "$4" > /var/run/mwan3track/$INTERFACE/LOSS_${track_ip}
|
||||
echo "$3" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/LATENCY_${track_ip}
|
||||
echo "$4" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/LOSS_${track_ip}
|
||||
}
|
||||
|
||||
main() {
|
||||
|
@ -109,23 +163,23 @@ main() {
|
|||
local recovery_interval down up size
|
||||
local keep_failure_interval check_quality failure_latency
|
||||
local recovery_latency failure_loss recovery_loss
|
||||
local max_ttl httping_ssl
|
||||
|
||||
[ -z "$5" ] && echo "Error: should not be started manually" && exit 0
|
||||
local max_ttl httping_ssl track_ips do_log
|
||||
|
||||
INTERFACE=$1
|
||||
DEVICE=$2
|
||||
STATUS=$3
|
||||
SRC_IP=$4
|
||||
mkdir -p /var/run/mwan3track/$INTERFACE
|
||||
STATUS=""
|
||||
STARTED=0
|
||||
mkdir -p $MWAN3TRACK_STATUS_DIR/$INTERFACE
|
||||
|
||||
trap clean_up TERM
|
||||
trap if_down USR1
|
||||
trap if_up USR2
|
||||
|
||||
config_load mwan3
|
||||
config_get FAMILY $INTERFACE family ipv4
|
||||
config_get track_method $INTERFACE track_method ping
|
||||
config_get_bool httping_ssl $INTERFACE httping_ssl 0
|
||||
validate_track_method $track_method $SRC_IP || {
|
||||
validate_track_method $track_method || {
|
||||
track_method=ping
|
||||
if validate_track_method $track_method; then
|
||||
LOG warn "Using ping to track interface $INTERFACE avaliability"
|
||||
|
@ -150,110 +204,102 @@ main() {
|
|||
config_get recovery_latency $INTERFACE recovery_latency 500
|
||||
config_get failure_loss $INTERFACE failure_loss 40
|
||||
config_get recovery_loss $INTERFACE recovery_loss 10
|
||||
local sleep_time result ping_status loss latency
|
||||
mwan3_list_track_ips()
|
||||
{
|
||||
track_ips="$track_ips $1"
|
||||
}
|
||||
config_list_foreach "$1" track_ip mwan3_list_track_ips
|
||||
|
||||
local score=$(($down+$up))
|
||||
local track_ips=$(echo $* | cut -d ' ' -f 5-99)
|
||||
local score=$((down+up))
|
||||
local host_up_count=0
|
||||
local lost=0
|
||||
local turn=0
|
||||
local ping_protocol=4
|
||||
local sleep_time result ping_result ping_result_raw ping_status loss latency
|
||||
|
||||
firstconnect
|
||||
while true; do
|
||||
|
||||
[ $STARTED -eq 0 ] && { sleep $MAX_SLEEP & SLEEP_PID=$!; wait; }
|
||||
unset SLEEP_PID
|
||||
sleep_time=$interval
|
||||
|
||||
for track_ip in $track_ips; do
|
||||
if [ $host_up_count -lt $reliability ]; then
|
||||
case "$track_method" in
|
||||
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
|
||||
$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=$?
|
||||
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_result=$(echo "$ping_result_raw" | tail -n2)
|
||||
loss="$(echo "$ping_result" | grep "packet loss" | cut -d "," -f3 | awk '{print $1}' | sed -e 's/%//')"
|
||||
loss="$(sed $TRACK_OUTPUT -ne 's/.*\([0-9]\+\)% packet loss.*/\1/p')"
|
||||
if [ "$ping_status" -ne 0 ] || [ "$loss" -eq 100 ]; then
|
||||
latency=999999
|
||||
loss=100
|
||||
else
|
||||
latency="$(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
|
||||
;;
|
||||
arping)
|
||||
arping -I $DEVICE -c $count -w $timeout -q $track_ip &> /dev/null
|
||||
WRAP arping -I $DEVICE -c $count -w $timeout -q $track_ip &> /dev/null &
|
||||
TRACK_PID=$!
|
||||
wait $TRACK_PID
|
||||
result=$?
|
||||
;;
|
||||
httping)
|
||||
if [ "$httping_ssl" -eq 1 ]; then
|
||||
httping -y $SRC_IP -c $count -t $timeout -q "https://$track_ip" &> /dev/null
|
||||
WRAP httping -c $count -t $timeout -q "https://$track_ip" &> /dev/null &
|
||||
else
|
||||
httping -y $SRC_IP -c $count -t $timeout -q "http://$track_ip" &> /dev/null
|
||||
WRAP httping -c $count -t $timeout -q "http://$track_ip" &> /dev/null &
|
||||
fi
|
||||
TRACK_PID=$!
|
||||
wait $TRACK_PID
|
||||
result=$?
|
||||
;;
|
||||
nping-tcp)
|
||||
result=$(nping -e $DEVICE -c $count $track_ip --tcp | grep Lost | awk '{print $12}')
|
||||
;;
|
||||
nping-udp)
|
||||
result=$(nping -e $DEVICE -c $count $track_ip --udp | grep Lost | awk '{print $12}')
|
||||
;;
|
||||
nping-icmp)
|
||||
result=$(nping -e $DEVICE -c $count $track_ip --icmp | grep Lost | awk '{print $12}')
|
||||
;;
|
||||
nping-arp)
|
||||
result=$(nping -e $DEVICE -c $count $track_ip --arp | grep Lost | awk '{print $12}')
|
||||
nping-*)
|
||||
WRAP nping -c $count $track_ip --${FAMILY#nping-} > $TRACK_OUTPUT &
|
||||
TRACK_PID=$!
|
||||
wait $TRACK_PID
|
||||
result=$(grep $TRACK_OUTPUT Lost | awk '{print $12}')
|
||||
;;
|
||||
esac
|
||||
do_log=""
|
||||
if [ $check_quality -eq 0 ]; then
|
||||
if [ $result -eq 0 ]; then
|
||||
let host_up_count++
|
||||
update_status "$track_ip" "up"
|
||||
|
||||
if [ $score -le $up ]; then
|
||||
LOG info "Check ($track_method) success for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
||||
fi
|
||||
[ $score -le $up ] && do_log="success"
|
||||
else
|
||||
let lost++
|
||||
update_status "$track_ip" "down"
|
||||
|
||||
if [ $score -gt $up ]; then
|
||||
LOG info "Check ($track_method) failed for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
||||
fi
|
||||
[ $score -gt $up ] && do_log="failed"
|
||||
fi
|
||||
[ -n "$do_log" ] && LOG info "Check ($track_method) ${do_log} for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
||||
|
||||
else
|
||||
if [ "$loss" -ge "$failure_loss" -o "$latency" -ge "$failure_latency" ]; then
|
||||
if [ "$loss" -ge "$failure_loss" ] || [ "$latency" -ge "$failure_latency" ]; then
|
||||
let lost++
|
||||
update_status "$track_ip" "down" $latency $loss
|
||||
|
||||
if [ $score -gt $up ]; then
|
||||
LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) failed for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
||||
fi
|
||||
elif [ "$loss" -le "$recovery_loss" -a "$latency" -le "$recovery_latency" ]; then
|
||||
[ $score -gt $up ] && do_log="failed"
|
||||
elif [ "$loss" -le "$recovery_loss" ] && [ "$latency" -le "$recovery_latency" ]; then
|
||||
let host_up_count++
|
||||
update_status "$track_ip" "up" $latency $loss
|
||||
|
||||
if [ $score -le $up ]; then
|
||||
LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) success for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
||||
fi
|
||||
[ $score -le $up ] && do_log="success"
|
||||
else
|
||||
echo "skipped" > /var/run/mwan3track/$INTERFACE/TRACK_${track_ip}
|
||||
echo "skipped" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_${track_ip}
|
||||
fi
|
||||
[ -n "$do_log" ] && LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) ${do_log} for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score"
|
||||
fi
|
||||
else
|
||||
echo "skipped" > /var/run/mwan3track/$INTERFACE/TRACK_${track_ip}
|
||||
echo "skipped" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_${track_ip}
|
||||
fi
|
||||
done
|
||||
|
||||
|
@ -262,9 +308,7 @@ main() {
|
|||
|
||||
if [ $score -lt $up ]; then
|
||||
score=0
|
||||
[ ${keep_failure_interval} -eq 1 ] && {
|
||||
sleep_time=$failure_interval
|
||||
}
|
||||
[ ${keep_failure_interval} -eq 1 ] && sleep_time=$failure_interval
|
||||
else
|
||||
sleep_time=$failure_interval
|
||||
fi
|
||||
|
@ -274,31 +318,31 @@ main() {
|
|||
score=0
|
||||
fi
|
||||
else
|
||||
if [ $score -lt $(($down+$up)) ] && [ $lost -gt 0 ]; then
|
||||
LOG info "Lost $(($lost*$count)) ping(s) on interface $INTERFACE ($DEVICE). Current score: $score"
|
||||
if [ $score -lt $((down+up)) ] && [ $lost -gt 0 ]; then
|
||||
LOG info "Lost $((lost*count)) ping(s) on interface $INTERFACE ($DEVICE). Current score: $score"
|
||||
fi
|
||||
|
||||
let score++
|
||||
lost=0
|
||||
|
||||
if [ $score -gt $up ]; then
|
||||
echo "online" > /var/run/mwan3track/$INTERFACE/STATUS
|
||||
score=$(($down+$up))
|
||||
echo "online" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS
|
||||
score=$((down+up))
|
||||
elif [ $score -le $up ]; then
|
||||
sleep_time=$recovery_interval
|
||||
fi
|
||||
|
||||
if [ $score -eq $up ]; then
|
||||
connected $INTERFACE $DEVICE
|
||||
connected
|
||||
fi
|
||||
fi
|
||||
|
||||
let turn++
|
||||
mkdir -p "/var/run/mwan3track/${1}"
|
||||
echo "${lost}" > /var/run/mwan3track/$INTERFACE/LOST
|
||||
echo "${score}" > /var/run/mwan3track/$INTERFACE/SCORE
|
||||
echo "${turn}" > /var/run/mwan3track/$INTERFACE/TURN
|
||||
echo "$(get_uptime)" > /var/run/mwan3track/$INTERFACE/TIME
|
||||
mkdir -p "$MWAN3TRACK_STATUS_DIR/${1}"
|
||||
echo "${lost}" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/LOST
|
||||
echo "${score}" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/SCORE
|
||||
echo "${turn}" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TURN
|
||||
get_uptime > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TIME
|
||||
|
||||
host_up_count=0
|
||||
sleep "${sleep_time}" &
|
||||
|
@ -306,7 +350,8 @@ main() {
|
|||
|
||||
if [ "${IFDOWN_EVENT}" -eq 1 ]; then
|
||||
LOG debug "Register ifdown event on interface ${INTERFACE} (${DEVICE})"
|
||||
disconnected 1
|
||||
disabled
|
||||
disconnected
|
||||
IFDOWN_EVENT=0
|
||||
fi
|
||||
if [ "${IFUP_EVENT}" -eq 1 ]; then
|
||||
|
|
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