include $(TOPDIR)/rules.mk
PKG_NAME:=mwan3
-PKG_VERSION:=2.0
-PKG_RELEASE:=3
-PKG_MAINTAINER:=Jeroen Louwes <jeroen.louwes@gmail.com>
+PKG_VERSION:=2.5.2
+PKG_RELEASE:=5
+PKG_MAINTAINER:=Florian Eckert <fe@dev.tdt.de>
PKG_LICENSE:=GPLv2
include $(INCLUDE_DIR)/package.mk
SUBMENU:=Routing and Redirection
DEPENDS:=+ip +ipset +iptables +iptables-mod-conntrack-extra +iptables-mod-ipopt
TITLE:=Multiwan hotplug script with connection tracking support
- MAINTAINER:=Jeroen Louwes <jeroen.louwes@gmail.com>
+ MAINTAINER:=Florian Eckert <fe@dev.tdt.de>
PKGARCH:=all
endef
define Package/mwan3/conffiles
/etc/config/mwan3
+/etc/mwan3.user
endef
define Build/Compile
. /lib/functions/network.sh
. /lib/mwan3/mwan3.sh
-config_load mwan3
-
-config_get enabled $INTERFACE enabled 0
-[ "$enabled" == "1" ] || exit 0
-
[ "$ACTION" == "ifup" -o "$ACTION" == "ifdown" ] || exit 1
[ -n "$INTERFACE" ] || exit 2
[ -n "$DEVICE" ] || exit 3
fi
-[ -x /usr/bin/ip ] || exit 4
-[ -x /usr/sbin/ipset ] || exit 5
-[ -x /usr/sbin/iptables ] || exit 6
-[ -x /usr/sbin/ip6tables ] || exit 7
-[ -x /usr/bin/logger ] || exit 8
+mwan3_set_connected_iptables
+
+config_load mwan3
+config_get enabled $INTERFACE enabled 0
+[ "$enabled" == "1" ] || exit 0
-config_get family $INTERFACE family ipv4
+if [ "$ACTION" == "ifup" ]; then
+ config_get family $INTERFACE family ipv4
+ if [ "$family" = "ipv4" ]; then
+ ubus call network.interface.${INTERFACE}_4 status &>/dev/null
+ if [ "$?" -eq "0" ]; then
+ network_get_gateway gateway ${INTERFACE}_4
+ else
+ network_get_gateway gateway $INTERFACE
+ fi
+ elif [ "$family" = "ipv6" ]; then
+ ubus call network.interface.${INTERFACE}_6 status &>/dev/null
+ if [ "$?" -eq "0" ]; then
+ network_get_gateway6 gateway ${INTERFACE}_6
+ else
+ network_get_gateway6 gateway ${INTERFACE}
+ fi
+ fi
-if [ "$family" == "ipv4" ]; then
- network_get_gateway gateway $INTERFACE
-elif [ "$family" == "ipv6" ]; then
- network_get_gateway6 gateway $INTERFACE
+ [ -n "$gateway" ] || exit 9
fi
-[ -n "$gateway" ] || exit 9
-
$LOG notice "$ACTION interface $INTERFACE (${DEVICE:-unknown})"
-mwan3_set_connected_iptables
-
case "$ACTION" in
ifup)
mwan3_set_general_rules
mwan3_track $INTERFACE $DEVICE
mwan3_set_policies_iptables
mwan3_set_user_rules
+ mwan3_flush_conntrack $INTERFACE $DEVICE "ifup"
;;
ifdown)
mwan3_delete_iface_rules $INTERFACE
mwan3_delete_iface_iptables $INTERFACE
mwan3_delete_iface_route $INTERFACE
mwan3_delete_iface_ipset_entries $INTERFACE
+ mwan3_track_signal $INTERFACE $DEVICE
mwan3_set_policies_iptables
mwan3_set_user_rules
+ mwan3_flush_conntrack $INTERFACE $DEVICE "ifdown"
;;
esac
--- /dev/null
+#!/bin/sh
+
+[ -f "/etc/mwan3.user" ] && {
+ . /lib/functions.sh
+
+ config_load mwan3
+ config_get enabled "$INTERFACE" enabled 0
+ [ "${enabled}" = "1" ] || exit 0
+ env -i ACTION="$ACTION" INTERFACE="$INTERFACE" DEVICE="$DEVICE" \
+ /bin/sh /etc/mwan3.user
+}
+
+exit 0
--- /dev/null
+#!/bin/sh
+#
+# This file is interpreted as shell script.
+# Put your custom mwan3 action here, they will
+# be executed with each netifd hotplug interface event
+# on interfaces for which mwan3 is enabled.
+#
+# There are three main environment variables that are passed to this script.
+#
+# $ACTION Either "ifup" or "ifdown"
+# $INTERFACE Name of the interface which went up or down (e.g. "wan" or "wwan")
+# $DEVICE Physical device name which interface went up or down (e.g. "eth0" or "wwan0")
#!/bin/sh
-IP4="/usr/bin/ip -4"
-IP6="/usr/bin/ip -6"
-IPS="/usr/sbin/ipset"
-IPT4="/usr/sbin/iptables -t mangle -w"
-IPT6="/usr/sbin/ip6tables -t mangle -w"
-LOG="/usr/bin/logger -t mwan3 -p"
+IP4="ip -4"
+IP6="ip -6"
+IPS="ipset"
+IPT4="iptables -t mangle -w"
+IPT6="ip6tables -t mangle -w"
+LOG="logger -t mwan3 -p"
+CONNTRACK_FILE="/proc/net/nf_conntrack"
mwan3_get_iface_id()
{
if [ "$family" == "ipv4" ]; then
- network_get_ipaddr src_ip $1
+ ubus call network.interface.${1}_4 status &>/dev/null
+ if [ "$?" -eq "0" ]; then
+ network_get_ipaddr src_ip ${1}_4
+ else
+ network_get_ipaddr src_ip $1
+ fi
$IPS -! create mwan3_connected list:set
if [ "$family" == "ipv6" ]; then
- network_get_ipaddr6 src_ipv6 $1
+ ubus call network.interface.${1}_6 status &>/dev/null
+ if [ "$?" -eq "0" ]; then
+ network_get_ipaddr6 src_ipv6 ${1}_6
+ else
+ network_get_ipaddr6 src_ipv6 $1
+ fi
$IPS -! create mwan3_connected_v6 hash:net family inet6
[ -n "$id" ] || return 0
if [ "$family" == "ipv4" ]; then
+ ubus call network.interface.${1}_4 status &>/dev/null
+ if [ "$?" -eq "0" ]; then
+ network_get_gateway route_args ${1}_4
+ else
+ network_get_gateway route_args $1
+ fi
- network_get_gateway route_args $1
route_args="via $route_args dev $2"
$IP4 route flush table $id
if [ "$family" == "ipv6" ]; then
- network_get_gateway6 route_args $1
+ ubus call network.interface.${1}_6 status &>/dev/null
+ if [ "$?" -eq "0" ]; then
+ network_get_gateway6 route_args ${1}_6
+ else
+ network_get_gateway6 route_args $1
+ fi
+
route_args="via $route_args dev $2"
$IP6 route flush table $id
mwan3_track()
{
- local track_ip track_ips reliability count timeout interval down up
+ local track_ip track_ips
mwan3_list_track_ips()
{
}
config_list_foreach $1 track_ip mwan3_list_track_ips
- if [ -e /var/run/mwan3track-$1.pid ] ; then
- kill $(cat /var/run/mwan3track-$1.pid) &> /dev/null
- rm /var/run/mwan3track-$1.pid &> /dev/null
+ kill $(pgrep -f "mwan3track $1") &> /dev/null
+ if [ -n "$track_ips" ]; then
+ [ -x /usr/sbin/mwan3track ] && /usr/sbin/mwan3track $1 $2 $track_ips &
fi
+}
- if [ -n "$track_ips" ]; then
- config_get reliability $1 reliability 1
- config_get count $1 count 1
- config_get timeout $1 timeout 4
- config_get interval $1 interval 10
- config_get down $1 down 5
- config_get up $1 up 5
-
- [ -x /usr/sbin/mwan3track ] && /usr/sbin/mwan3track $1 $2 $reliability $count $timeout $interval $down $up $track_ips &
+mwan3_track_signal()
+{
+ local pid
+
+ pid="$(pgrep -f "mwan3track $1")"
+ if [ "${pid}" != "" ]; then
+ kill -USR1 "${pid}"
+ else
+ $LOG warn "Unable to send signal USR1 to mwan3track on interface $1 with pid ${pid}"
fi
}
$IPT6 -L mwan3_rules -n -v 2> /dev/null | tail -n+3 | sed 's/mark.*//' | sed 's/mwan3_policy_/- /' | sed 's/mwan3_rule_/S /'
fi
}
+
+mwan3_flush_conntrack()
+{
+ local flush_conntrack
+
+ config_get flush_conntrack $1 flush_conntrack never
+
+ if [ -e "$CONNTRACK_FILE" ]; then
+ case $flush_conntrack in
+ ifup)
+ [ "$3" = "ifup" ] && {
+ echo f > ${CONNTRACK_FILE}
+ $LOG info "connection tracking flushed on interface $1 ($2) $3"
+ }
+ ;;
+ ifdown)
+ [ "$3" = "ifdown" ] && {
+ echo f > ${CONNTRACK_FILE}
+ $LOG info "connection tracking flushed on interface $1 ($2) $3"
+ }
+ ;;
+ always)
+ echo f > ${CONNTRACK_FILE}
+ $LOG info "connection tracking flushed on interface $1 ($2) $3"
+ ;;
+ never)
+ $LOG info "connection tracking not flushed on interface $1 ($2) $3"
+ ;;
+ esac
+ else
+ $LOG warning "connection tracking not enabled"
+ fi
+}
--- /dev/null
+#!/bin/sh
+
+. /lib/functions.sh
+. /usr/share/libubox/jshn.sh
+
+MWAN3_STATUS_DIR="/var/run/mwan3track"
+MWAN3_PID_FILE="/var/run/mwan3track"
+
+IPS="ipset"
+IPT4="iptables -t mangle -w"
+IPT6="ip6tables -t mangle -w"
+
+report_connected_v4() {
+ local address
+
+ if [ -n "$($IPT4 -S mwan3_connected 2> /dev/null)" ]; then
+ for address in $($IPS list mwan3_connected_v4 | tail -n +8); do
+ json_add_string "" "${address}"
+ done
+ fi
+}
+
+report_connected_v6() {
+ local address
+
+ if [ -n "$($IPT6 -S mwan3_connected 2> /dev/null)" ]; then
+ for address in $($IPS list mwan3_connected_v6 | tail -n +8); do
+ json_add_string "" "${address}"
+ done
+ fi
+}
+
+get_mwan3_status() {
+ local iface="${1}"
+ local iface_select="${2}"
+ local running="0"
+ local pid
+
+ if [ "${iface}" = "${iface_select}" ] || [ "${iface_select}" = "" ]; then
+ pid="$(pgrep -f "mwan3track $iface_selected")"
+ if [ "${pid}" != "" ]; then
+ running="1"
+ fi
+
+ json_add_object "${iface}"
+ json_add_string "score" "$(cat "$MWAN3_STATUS_DIR/${iface}/SCORE")"
+ json_add_string "lost" "$(cat "$MWAN3_STATUS_DIR/${iface}/LOST")"
+ json_add_string "turn" "$(cat "$MWAN3_STATUS_DIR/${iface}/TURN")"
+ json_add_string "status" "$(cat "$MWAN3_STATUS_DIR/${iface}/STATUS")"
+ json_add_boolean "running" "${running}"
+ json_add_array "track_ip"
+ for file in $MWAN3_STATUS_DIR/${iface}/*; do
+ track="${file#*/TRACK_}"
+ if [ "${track}" != "${file}" ]; then
+ json_add_object
+ json_add_string ip "${track}"
+ json_add_string status "$(cat "${file}")"
+ json_close_object
+ fi
+ done
+ json_close_array
+ json_close_object
+ fi
+}
+
+case "$1" in
+ list)
+ json_init
+ json_add_object "status"
+ json_add_string "section" "x"
+ json_add_string "interface" "x"
+ json_close_object
+ json_dump
+ ;;
+ call)
+ case "$2" in
+ status)
+ local section iface
+ read input;
+ json_load "$input"
+ json_get_var section section
+ json_get_var iface interface
+
+ config_load mwan3
+ json_init
+ case "$section" in
+ interfaces)
+ json_add_object interfaces
+ config_foreach get_mwan3_status interface "${iface}"
+ json_close_object
+ ;;
+ connected)
+ json_add_object connected
+ json_add_array ipv4
+ report_connected_v4
+ json_close_array
+ json_add_array ipv6
+ report_connected_v6
+ json_close_array
+ json_close_object
+ ;;
+ *)
+ # interfaces
+ json_add_object interfaces
+ config_foreach get_mwan3_status interface
+ json_close_object
+ # connected
+ json_add_object connected
+ json_add_array ipv4
+ report_connected_v4
+ json_close_array
+ json_add_array ipv6
+ report_connected_v6
+ json_close_array
+ json_close_object
+ ;;
+ esac
+ json_dump
+ ;;
+ esac
+ ;;
+esac
#!/bin/sh
-[ -x /usr/bin/ip ] || exit 4
-[ -x /usr/sbin/ipset ] || exit 5
-[ -x /usr/sbin/iptables ] || exit 6
-[ -x /usr/sbin/ip6tables ] || exit 7
-[ -x /usr/bin/logger ] || exit 8
-
. /lib/functions.sh
. /lib/functions/network.sh
. /lib/mwan3/mwan3.sh
ACTION=ifdown INTERFACE=$1 /sbin/hotplug-call iface
- if [ -e /var/run/mwan3track-$1.pid ] ; then
- kill $(cat /var/run/mwan3track-$1.pid)
- rm /var/run/mwan3track-$1.pid
- fi
+ kill $(pgrep -f "mwan3track $1") &> /dev/null
}
ifup()
local ipset route rule table IP IPT
killall mwan3track &> /dev/null
- rm /var/run/mwan3track-* &> /dev/null
for IP in "$IP4" "$IP6"; do
#!/bin/sh
-[ -z "$9" ] && echo "Error: should not be started manually" && exit 0
+. /lib/functions.sh
-if [ -e /var/run/mwan3track-$1.pid ] ; then
- kill $(cat /var/run/mwan3track-$1.pid) &> /dev/null
- rm /var/run/mwan3track-$1.pid &> /dev/null
-fi
+LOG="logger -t $(basename "$0")[$$] -p"
+INTERFACE=""
+DEVICE=""
-echo "$$" > /var/run/mwan3track-$1.pid
+IFDOWN_EVENT=0
-score=$(($7+$8))
-track_ips=$(echo $* | cut -d ' ' -f 9-99)
-host_up_count=0
-lost=0
-
-while true; do
-
- for track_ip in $track_ips; do
- ping -I $2 -c $4 -W $5 -q $track_ip &> /dev/null
- if [ $? -eq 0 ]; then
- let host_up_count++
+clean_up() {
+ $LOG notice "Stopping mwan3track for interface \"${INTERFACE}\""
+ if [ "$(pgrep -f "mwan3track ${INTERFACE}")" = "" ]; then
+ rm -rf "/var/run/mwan3track/${INTERFACE}" &> /dev/null
+ fi
+ if [ -z "$(ls -A "/var/run/mwan3track")" ]; then
+ rm -rf "/var/run/mwan3track"
+ fi
+ exit 0
+}
+
+if_down() {
+ $LOG info "Detect ifdown event on interface ${INTERFACE} (${DEVICE})"
+ IFDOWN_EVENT=1
+}
+
+main() {
+ local reliability count timeout interval failure_interval
+ local recovery_interval down up size
+
+ [ -z "$3" ] && echo "Error: should not be started manually" && exit 0
+
+ INTERFACE=$1
+ DEVICE=$2
+ mkdir -p /var/run/mwan3track/$1
+ trap clean_up SIGINT SIGTERM
+ trap if_down SIGUSR1
+
+ config_load mwan3
+ config_get reliability $1 reliability 1
+ config_get count $1 count 1
+ config_get timeout $1 timeout 4
+ config_get interval $1 interval 10
+ config_get down $1 down 5
+ config_get up $1 up 5
+ config_get size $1 size 56
+ config_get failure_interval $1 failure_interval $interval
+ config_get recovery_interval $1 recovery_interval $interval
+
+ local score=$(($down+$up))
+ local track_ips=$(echo $* | cut -d ' ' -f 3-99)
+ local host_up_count=0
+ local lost=0
+ local sleep_time=0
+ local turn=0
+
+ echo "offline" > /var/run/mwan3track/$1/STATUS
+ while true; do
+
+ sleep_time=$interval
+
+ for track_ip in $track_ips; do
+ ping -I $2 -c $count -W $timeout -s $size -q $track_ip &> /dev/null
+ if [ $? -eq 0 ]; then
+ let host_up_count++
+ echo "up" > /var/run/mwan3track/$1/TRACK_${track_ip}
+ else
+ let lost++
+ echo "down" > /var/run/mwan3track/$1/TRACK_${track_ip}
+ fi
+ done
+
+ if [ $host_up_count -lt $reliability ]; then
+ let score--
+
+ if [ $score -lt $up ]; then
+ score=0
+ else
+ sleep_time=$failure_interval
+ fi
+
+ if [ $score -eq $up ]; then
+ echo "offline" > /var/run/mwan3track/$1/STATUS
+ $LOG notice "Interface $1 ($2) is offline"
+ env -i ACTION=ifdown INTERFACE=$1 DEVICE=$2 /sbin/hotplug-call iface
+ score=0
+ fi
else
- let lost++
+ if [ $score -lt $(($down+$up)) ] && [ $lost -gt 0 ]; then
+ $LOG info "Lost $(($lost*$count)) ping(s) on interface $1 ($2)"
+ fi
+
+ let score++
+ lost=0
+
+ if [ $score -gt $up ]; then
+ echo "online" > /var/run/mwan3track/$1/STATUS
+ score=$(($down+$up))
+ elif [ $score -le $up ]; then
+ sleep_time=$recovery_interval
+ fi
+
+ if [ $score -eq $up ]; then
+ $LOG notice "Interface $1 ($2) is online"
+ env -i ACTION=ifup INTERFACE=$1 DEVICE=$2 /sbin/hotplug-call iface
+ rm -rf "/var/run/mwan3track/${1}" &> /dev/null
+ exit 0
+ fi
fi
- done
- if [ $host_up_count -lt $3 ]; then
- let score--
+ let turn++
+ mkdir -p "/var/run/mwan3track/${1}"
+ echo "${lost}" > /var/run/mwan3track/$1/LOST
+ echo "${score}" > /var/run/mwan3track/$1/SCORE
+ echo "${turn}" > /var/run/mwan3track/$1/TURN
- if [ $score -lt $8 ]; then score=0 ; fi
- if [ $score -eq $8 ]; then
+ host_up_count=0
+ sleep "${sleep_time}" &
+ wait
- logger -t mwan3track -p notice "Interface $1 ($2) is offline"
- env -i ACTION=ifdown INTERFACE=$1 DEVICE=$2 /sbin/hotplug-call iface
+ if [ "${IFDOWN_EVENT}" -eq 1 ]; then
score=0
-
- fi
-
- else
-
- if [ $score -lt $(($7+$8)) ] && [ $lost -gt 0 ]; then
-
- logger -t mwan3track -p info "Lost $(($lost*$4)) ping(s) on interface $1 ($2)"
-
+ echo "offline" > /var/run/mwan3track/$1/STATUS
+ IFDOWN_EVENT=0
fi
+ done
+}
- let score++
- lost=0
-
- if [ $score -gt $8 ]; then score=$(($7+$8)); fi
- if [ $score -eq $8 ]; then
-
- logger -t mwan3track -p notice "Interface $1 ($2) is online"
- env -i ACTION=ifup INTERFACE=$1 DEVICE=$2 /sbin/hotplug-call iface
- rm /var/run/mwan3track-$1.pid
- exit 0
- fi
- fi
-
- host_up_count=0
- sleep $6
-done
-
-exit 1
+main "$@"