diff --git a/brook/Makefile b/brook/Makefile index fbb5b287c..b46182e9f 100644 --- a/brook/Makefile +++ b/brook/Makefile @@ -5,12 +5,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=brook -PKG_VERSION:=20240404 +PKG_VERSION:=20240606 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/txthinking/brook/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=6eda9a348f9c3555a1c27711e81c0982ea9999bf2878e73cf2eaaee90e8cc2e7 +PKG_HASH:=eee1c6173daff3199c23396f4661d7f81d701dc0f4eb1662b39041a6ca10703b PKG_MAINTAINER:=Tianling Shen PKG_LICENSE:=GPL-3.0 diff --git a/mwan3/Makefile b/mwan3/Makefile index 99c01712d..f4d03e63d 100644 --- a/mwan3/Makefile +++ b/mwan3/Makefile @@ -8,12 +8,10 @@ include $(TOPDIR)/rules.mk PKG_NAME:=mwan3 -PKG_VERSION:=2.11.7 -PKG_RELEASE:=1 -PKG_MAINTAINER:=Florian Eckert , \ - Aaron Goodman +PKG_VERSION:=2.8.8 +PKG_RELEASE:=2 +PKG_MAINTAINER:=Florian Eckert PKG_LICENSE:=GPL-2.0 -PKG_CONFIG_DEPENDS:=CONFIG_IPV6 include $(INCLUDE_DIR)/package.mk @@ -25,7 +23,6 @@ define Package/mwan3 +ip \ +ipset \ +iptables \ - +IPV6:ip6tables \ +iptables-mod-conntrack-extra \ +iptables-mod-ipopt \ +jshn @@ -45,9 +42,12 @@ define Package/mwan3/conffiles /etc/mwan3.user endef +define Build/Compile +endef + define Package/mwan3/postinst #!/bin/sh -if [ -z "$${IPKG_INSTROOT}" ] && [ -x /etc/init.d/rpcd ]; then +if [ -z "$${IPKG_INSTROOT}" ]; then /etc/init.d/rpcd restart fi exit 0 @@ -55,63 +55,14 @@ endef define Package/mwan3/postrm #!/bin/sh -if [ -z "$${IPKG_INSTROOT}" ] && [ -x /etc/init.d/rpcd ]; then +if [ -z "$${IPKG_INSTROOT}" ]; then /etc/init.d/rpcd restart 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 - $(INSTALL_DIR) $(1)/etc/config - $(INSTALL_CONF) ./files/etc/config/mwan3 \ - $(1)/etc/config/ - - $(INSTALL_DIR) $(1)/etc/hotplug.d/iface - $(INSTALL_DATA) ./files/etc/hotplug.d/iface/15-mwan3 \ - $(1)/etc/hotplug.d/iface/ - $(INSTALL_DATA) ./files/etc/hotplug.d/iface/16-mwan3-user \ - $(1)/etc/hotplug.d/iface/ - - $(INSTALL_DIR) $(1)/etc/init.d - $(INSTALL_BIN) ./files/etc/init.d/mwan3 \ - $(1)/etc/init.d/ - - $(INSTALL_DIR) $(1)/lib/mwan3 - $(INSTALL_DATA) ./files/lib/mwan3/common.sh \ - $(1)/lib/mwan3/ - $(INSTALL_DATA) ./files/lib/mwan3/mwan3.sh \ - $(1)/lib/mwan3/ - - $(INSTALL_DIR) $(1)/usr/libexec/rpcd - $(INSTALL_BIN) ./files/usr/libexec/rpcd/mwan3 \ - $(1)/usr/libexec/rpcd/ - - $(INSTALL_DIR) $(1)/usr/sbin - $(INSTALL_BIN) ./files/usr/sbin/mwan3 \ - $(1)/usr/sbin/ - $(INSTALL_BIN) ./files/usr/sbin/mwan3rtmon \ - $(1)/usr/sbin/ - $(INSTALL_BIN) ./files/usr/sbin/mwan3track \ - $(1)/usr/sbin/ - - $(INSTALL_DIR) $(1)/etc - $(INSTALL_BIN) ./files/etc/mwan3.user \ - $(1)/etc/ - - $(CP) $(PKG_BUILD_DIR)/libwrap_mwan3_sockopt.so.1.0 $(1)/lib/mwan3/ - - $(INSTALL_DIR) $(1)/etc/uci-defaults - $(INSTALL_DATA) ./files/etc/uci-defaults/mwan3-migrate-flush_conntrack \ - $(1)/etc/uci-defaults/ +$(CP) ./files/* $(1) endef $(eval $(call BuildPackage,mwan3)) diff --git a/mwan3/files/etc/config/mwan3 b/mwan3/files/etc/config/mwan3 index 2e88c8ddb..22c9c6d80 100644 --- a/mwan3/files/etc/config/mwan3 +++ b/mwan3/files/etc/config/mwan3 @@ -1,6 +1,7 @@ config globals 'globals' option mmx_mask '0x3F00' + option rtmon_interval '5' config member 'wan_m1_w3' option interface 'wan' diff --git a/mwan3/files/etc/hotplug.d/iface/15-mwan3 b/mwan3/files/etc/hotplug.d/iface/15-mwan3 index 6eac6309a..5bfbd2462 100644 --- a/mwan3/files/etc/hotplug.d/iface/15-mwan3 +++ b/mwan3/files/etc/hotplug.d/iface/15-mwan3 @@ -3,87 +3,92 @@ . /lib/functions.sh . /lib/functions/network.sh . /lib/mwan3/mwan3.sh +. /usr/share/libubox/jshn.sh -initscript=/etc/init.d/mwan3 -. /lib/functions/procd.sh - - -SCRIPTNAME="mwan3-hotplug" -[ "$ACTION" = "ifup" ] || [ "$ACTION" = "ifdown" ] || [ "$ACTION" = "connected" ] || [ "$ACTION" = "disconnected" ] || exit 1 +[ "$ACTION" == "ifup" -o "$ACTION" == "ifdown" ] || exit 1 [ -n "$INTERFACE" ] || exit 2 -[ "$FIRSTCONNECT" = "1" ] || [ "$MWAN3_SHUTDOWN" = "1" ] && exit 0 -if { [ "$ACTION" = "ifup" ] || [ "$ACTION" = "connected" ] ; } && [ -z "$DEVICE" ]; then - LOG notice "$ACTION called on $INTERFACE with no device set" - exit 3 +if [ "$ACTION" == "ifup" ]; then + [ -n "$DEVICE" ] || exit 3 fi -[ "$MWAN3_STARTUP" = "init" ] || procd_lock +config_load mwan3 +config_get_bool enabled globals 'enabled' '0' +[ ${enabled} -gt 0 ] || exit 0 +mwan3_lock "$ACTION" "$INTERFACE" mwan3_init +mwan3_set_connected_iptables +mwan3_set_custom_ipset +mwan3_unlock "$ACTION" "$INTERFACE" -/etc/init.d/mwan3 running || { - [ "$MWAN3_STARTUP" = "init" ] || procd_lock - LOG notice "mwan3 hotplug $ACTION on $INTERFACE not called because globally disabled" - exit 0 -} +config_get enabled $INTERFACE enabled 0 +config_get initial_state $INTERFACE initial_state "online" +[ "$enabled" == "1" ] || exit 0 -$IPT4 -S mwan3_hook &>/dev/null || { - LOG warn "hotplug called on $INTERFACE before mwan3 has been set up" - exit 0 -} - -if [ "$MWAN3_STARTUP" != "init" ] && [ "$ACTION" = "ifup" ]; then - mwan3_set_user_iface_rules $INTERFACE $DEVICE +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_ipaddr src_ip ${INTERFACE}_4 + else + network_get_ipaddr src_ip ${INTERFACE} + fi + [ -n "$src_ip" ] || src_ip="0.0.0.0" + elif [ "$family" = "ipv6" ]; then + ubus call network.interface.${INTERFACE}_6 status &>/dev/null + if [ "$?" -eq "0" ]; then + network_get_ipaddr6 src_ip ${INTERFACE}_6 + else + network_get_ipaddr6 src_ip ${INTERFACE} + fi + [ -n "$src_ip" ] || src_ip="::" + fi fi -config_get_bool enabled $INTERFACE 'enabled' '0' -[ "${enabled}" -eq 1 ] || { - LOG notice "mwan3 hotplug on $INTERFACE not called because interface disabled" - exit 0 -} - -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 + json_load "$(ubus call mwan3 status '{"section":"interfaces"}')" + json_select "interfaces" + json_select "${INTERFACE}" + json_get_var running running + json_get_var status status else status=online + running=1 fi -LOG notice "Execute $ACTION event on interface $INTERFACE (${DEVICE:-unknown})" +mwan3_lock "$ACTION" "$INTERFACE" +$LOG notice "Execute "$ACTION" event on interface $INTERFACE (${DEVICE:-unknown})" case "$ACTION" in - connected) - mwan3_set_iface_hotplug_state $INTERFACE "online" - mwan3_set_policies_iptables - ;; ifup) + mwan3_set_general_rules + mwan3_set_general_iptables mwan3_create_iface_iptables $INTERFACE $DEVICE mwan3_create_iface_rules $INTERFACE $DEVICE - mwan3_set_iface_hotplug_state $INTERFACE "$status" - if [ "$MWAN3_STARTUP" != "init" ]; then - mwan3_create_iface_route $INTERFACE $DEVICE - mwan3_set_general_rules - [ "$status" = "online" ] && mwan3_set_policies_iptables + mwan3_create_iface_route $INTERFACE $DEVICE + if [ ${running} -eq 1 -a "${status}" = "online" ]; then + $LOG notice "Starting tracker on interface $INTERFACE (${DEVICE:-unknown})" + mwan3_set_iface_hotplug_state $INTERFACE "online" + mwan3_track $INTERFACE $DEVICE "online" "$src_ip" + else + $LOG notice "Starting tracker on interface $INTERFACE (${DEVICE:-unknown})" + mwan3_set_iface_hotplug_state $INTERFACE "offline" + mwan3_track $INTERFACE $DEVICE "offline" "$src_ip" fi - [ "$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 - ;; + mwan3_set_user_rules + ;; 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 - procd_running mwan3 "track_$INTERFACE" && procd_send_signal mwan3 "track_$INTERFACE" USR1 + mwan3_track_signal $INTERFACE $DEVICE mwan3_set_policies_iptables + mwan3_set_user_rules ;; esac -mwan3_flush_conntrack "$INTERFACE" "$ACTION" +mwan3_unlock "$ACTION" "$INTERFACE" exit 0 diff --git a/mwan3/files/etc/hotplug.d/iface/16-mwan3 b/mwan3/files/etc/hotplug.d/iface/16-mwan3 new file mode 100644 index 000000000..c243d55ff --- /dev/null +++ b/mwan3/files/etc/hotplug.d/iface/16-mwan3 @@ -0,0 +1,22 @@ +#!/bin/sh + +. /lib/functions.sh +. /lib/functions/network.sh +. /lib/mwan3/mwan3.sh + +config_load mwan3 +config_get_bool enabled globals 'enabled' '0' +[ ${enabled} -gt 0 ] || exit 0 + +if [ "$ACTION" == "ifup" ]; then + mwan3_lock "$ACTION" "mwan3rtmon" + mwan3_rtmon + mwan3_unlock "$ACTION" "mwan3rtmon" +fi + +config_get enabled $INTERFACE enabled 0 +[ "${enabled}" = "0" ] || { + mwan3_flush_conntrack "$INTERFACE" "$ACTION" +} + +exit 0 diff --git a/mwan3/files/etc/hotplug.d/iface/16-mwan3-user b/mwan3/files/etc/hotplug.d/iface/16-mwan3-user index 0960a2628..9372c736e 100644 --- a/mwan3/files/etc/hotplug.d/iface/16-mwan3-user +++ b/mwan3/files/etc/hotplug.d/iface/16-mwan3-user @@ -2,25 +2,15 @@ [ -f "/etc/mwan3.user" ] && { . /lib/functions.sh - . /lib/mwan3/mwan3.sh - initscript=/etc/init.d/mwan3 - . /lib/functions/procd.sh - - [ "$MWAN3_SHUTDOWN" != 1 ] && procd_lock - - [ "$MWAN3_SHUTDOWN" != 1 ] && ! /etc/init.d/mwan3 running && { - exit 0 - } config_load mwan3 + config_get_bool enabled globals 'enabled' '0' + [ ${enabled} -gt 0 ] || exit 0 - config_get_bool enabled "$INTERFACE" enabled 0 - [ "${enabled}" -eq 1 ] || { - exit 0 - } - - [ -x /etc/mwan3.user ] || chmod 755 /etc/mwan3.user - env -i ACTION="$ACTION" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /etc/mwan3.user + 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 diff --git a/mwan3/files/etc/init.d/mwan3 b/mwan3/files/etc/init.d/mwan3 old mode 100644 new mode 100755 index 33a1f46e5..af750e55e --- a/mwan3/files/etc/init.d/mwan3 +++ b/mwan3/files/etc/init.d/mwan3 @@ -1,109 +1,26 @@ #!/bin/sh /etc/rc.common -. "${IPKG_INSTROOT}/lib/functions/network.sh" -. "${IPKG_INSTROOT}/lib/mwan3/mwan3.sh" - START=19 USE_PROCD=1 -SCRIPTNAME="mwan3-init" - -service_running() { - [ -d "$MWAN3_STATUS_DIR" ] -} - -start_tracker() { - local enabled interface - interface=$1 - config_get_bool enabled $interface 'enabled' '0' - [ $enabled -eq 0 ] && return - [ -z "$(config_get $interface track_ip)" ] && return - - procd_open_instance "track_${1}" - procd_set_param command /usr/sbin/mwan3track $interface - procd_set_param respawn - procd_close_instance -} - -start_service() { - local enabled hotplug_pids - - mwan3_init - config_foreach start_tracker interface - - mwan3_update_iface_to_table - mwan3_set_dynamic_ipset - mwan3_set_connected_ipset - mwan3_set_custom_ipset - mwan3_set_general_rules - mwan3_set_general_iptables - config_foreach mwan3_ifup interface "init" - wait $hotplug_pids - mwan3_set_policies_iptables - mwan3_set_user_rules - - 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() { - local ipset rule IP IPTR IPT family table tid - - 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 - - # Needed for the firewall backend to release the ipsets reference - sleep 2 - for ipset in $($IPS -n list | grep mwan3_); do - $IPS -q destroy $ipset - done - - rm -rf $MWAN3_STATUS_DIR $MWAN3TRACK_STATUS_DIR +boot() { + . /lib/config/uci.sh + uci_toggle_state mwan3 globals enabled "1" + mwan3_boot=1 + rc_procd start_service } reload_service() { - stop - start + /usr/sbin/mwan3 restart +} + +start_service() { + [ -n "${mwan3_boot}" ] && return 0 + /usr/sbin/mwan3 start +} + +stop_service() { + /usr/sbin/mwan3 stop } service_triggers() { diff --git a/mwan3/files/etc/mwan3.user b/mwan3/files/etc/mwan3.user index 2e8e51748..39989ab9b 100644 --- a/mwan3/files/etc/mwan3.user +++ b/mwan3/files/etc/mwan3.user @@ -8,13 +8,9 @@ # There are three main environment variables that are passed to this script. # # $ACTION -# Is called by netifd and mwan3track. -# Is called by netifd and mwan3track. -# Is only called by mwan3track if tracking was successful. -# Is only called by mwan3track if tracking has failed. -# $INTERFACE Name of the interface an action relates to (e.g. "wan" or "wwan"). -# $DEVICE Physical device name of the interface the action relates to (e.g. "eth0" or "wwan0"). -# Note: On an ifdown event, $DEVICE is not available, use $INTERFACE instead. -# -# Further documentation can be found here: -# https://openwrt.org/docs/guide-user/network/wan/multiwan/mwan3#alertsnotifications +# Is called by netifd and mwan3track +# Is called by netifd and mwan3track +# Is only called by mwan3track if tracking was successful +# Is only called by mwan3track if tracking has failed +# $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") diff --git a/mwan3/files/lib/mwan3/common.sh b/mwan3/files/lib/mwan3/common.sh index 29ace6050..1af129919 100644 --- a/mwan3/files/lib/mwan3/common.sh +++ b/mwan3/files/lib/mwan3/common.sh @@ -1,205 +1,6 @@ #!/bin/sh -IP4="ip -4" -IP6="ip -6" -SCRIPTNAME="$(basename "$0")" - -MWAN3_STATUS_DIR="/var/run/mwan3" -MWAN3_STATUS_IPTABLES_LOG_DIR="${MWAN3_STATUS_DIR}/iptables_log" -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)) - -command -v ip6tables > /dev/null -NO_IPV6=$? - -IPS="ipset" -IPT4="iptables -t mangle -w" -IPT6="ip6tables -t mangle -w" -IPT4R="iptables-restore -T mangle -w -n" -IPT6R="ip6tables-restore -T mangle -w -n" - -LOG() -{ - local facility=$1; shift - # in development, we want to show 'debug' level logs - # when this release is out of beta, the comment in the line below - # should be removed - [ "$facility" = "debug" ] && return - logger -t "${SCRIPTNAME}[$$]" -p $facility "$*" -} - -mwan3_get_true_iface() -{ - local family V - _true_iface=$2 - config_get family "$2" family ipv4 - if [ "$family" = "ipv4" ]; then - V=4 - elif [ "$family" = "ipv6" ]; then - V=6 - fi - ubus call "network.interface.${2}_${V}" status &>/dev/null && _true_iface="${2}_${V}" - export "$1=$_true_iface" -} - -mwan3_get_src_ip() -{ - local family _src_ip 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 mmdefault source_routing - - config_load mwan3 - - [ -d $MWAN3_STATUS_DIR ] || mkdir -p $MWAN3_STATUS_DIR/iface_state - [ -d "$MWAN3_STATUS_IPTABLES_LOG_DIR" ] || mkdir -p "$MWAN3_STATUS_IPTABLES_LOG_DIR" - - # 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_get MMX_MASK globals mmx_mask '0x3F00' - echo "$MMX_MASK"| tr 'A-F' 'a-f' > "${MWAN3_STATUS_DIR}/mmx_mask" - LOG debug "Using firewall mask ${MMX_MASK}" - - bitcnt=$(mwan3_count_one_bits MMX_MASK) - mmdefault=$(((1<>bit_msk)&1)) = "1" ]; then - if [ $((($1>>bit_val)&1)) = "1" ]; then - result=$((result|(1</dev/null)" - [ -z "${time_u}" ] || [ "${time_u}" = "0" ] || { - time_n="$(get_uptime)" - echo $((time_n-time_u)) - } -} diff --git a/mwan3/files/lib/mwan3/mwan3.sh b/mwan3/files/lib/mwan3/mwan3.sh index a3e7c0098..64b07d658 100644 --- a/mwan3/files/lib/mwan3/mwan3.sh +++ b/mwan3/files/lib/mwan3/mwan3.sh @@ -1,8 +1,11 @@ #!/bin/sh -. "${IPKG_INSTROOT}/usr/share/libubox/jshn.sh" -. "${IPKG_INSTROOT}/lib/mwan3/common.sh" - +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" IPv6_REGEX="([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" IPv6_REGEX="${IPv6_REGEX}([0-9a-fA-F]{1,4}:){1,7}:|" @@ -16,73 +19,83 @@ 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="" -mwan3_push_update() +MMX_UNREACHABLE="" +MM_UNREACHABLE="" + +# return true(=0) if has any mwan3 interface enabled +# otherwise return false +mwan3_rtmon_ipv4() { - # 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"$'\n'"$*"; -} - -mwan3_update_dev_to_table() -{ - local _tid - # shellcheck disable=SC2034 - mwan3_dev_tbl_ipv4=" " - # shellcheck disable=SC2034 - mwan3_dev_tbl_ipv6=" " - - update_table() - { - local family curr_table device enabled - let _tid++ - config_get family "$1" family ipv4 - network_get_device device "$1" - [ -z "$device" ] && return - config_get enabled "$1" enabled - [ "$enabled" -eq 0 ] && return - curr_table=$(eval "echo \"\$mwan3_dev_tbl_${family}\"") - export "mwan3_dev_tbl_$family=${curr_table}${device}=$_tid " - } - network_flush_cache - config_foreach update_table interface -} - -mwan3_update_iface_to_table() -{ - local _tid - mwan3_iface_tbl=" " - update_table() - { - let _tid++ - export mwan3_iface_tbl="${mwan3_iface_tbl}${1}=$_tid " - } - config_foreach update_table interface -} - -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 - route_line=$2 - route_family=$3 - route_device=$(echo "$route_line" | sed -ne "s/.*dev \([^ ]*\).*/\1/p") - unset "$1" - [ -z "$route_device" ] && return - - curr_table=$(eval "echo \"\$mwan3_dev_tbl_${route_family}\"") - for entry in $curr_table; do - if [ "${entry%%=*}" = "$route_device" ]; then - _tid=${entry##*=} - export "$1=$_tid" - return + local tid=1 + local idx=0 + local ret=1 + local tbl="" + mkdir -p /tmp/mwan3rtmon + ($IP4 route list table main | grep -v "^default\|linkdown" | sort -n; echo empty fixup) >/tmp/mwan3rtmon/ipv4.main + while uci get mwan3.@interface[$idx] >/dev/null 2>&1 ; do + idx=$((idx+1)) + tid=$idx + [ "$(uci get mwan3.@interface[$((idx-1))].family)" = "ipv4" ] && { + tbl=$($IP4 route list table $tid) + if echo "$tbl" | grep -q ^default; then + (echo "$tbl" | grep -v "^default\|linkdown" | sort -n; echo empty fixup) >/tmp/mwan3rtmon/ipv4.$tid + cat /tmp/mwan3rtmon/ipv4.$tid | grep -v -x -F -f /tmp/mwan3rtmon/ipv4.main | while read line; do + $IP4 route del table $tid $line + done + cat /tmp/mwan3rtmon/ipv4.main | grep -v -x -F -f /tmp/mwan3rtmon/ipv4.$tid | while read line; do + $IP4 route add table $tid $line + done + fi + } + if [ "$(uci get mwan3.@interface[$((idx-1))].enabled)" = "1" ]; then + ret=0 fi done + rm -f /tmp/mwan3rtmon/ipv4.* + return $ret +} + +# return true(=0) if has any mwan3 interface enabled +# otherwise return false +mwan3_rtmon_ipv6() +{ + local tid=1 + local idx=0 + local ret=1 + local tbl="" + mkdir -p /tmp/mwan3rtmon + ($IP6 route list table main | grep -v "^default\|^::/0\|^fe80::/64\|^unreachable" | sort -n; echo empty fixup) >/tmp/mwan3rtmon/ipv6.main + while uci get mwan3.@interface[$idx] >/dev/null 2>&1 ; do + idx=$((idx+1)) + tid=$idx + [ "$(uci get mwan3.@interface[$((idx-1))].family)" = "ipv6" ] && { + tbl=$($IP6 route list table $tid) + if echo "$tbl" | grep -q "^default\|^::/0"; then + (echo "$tbl" | grep -v "^default\|^::/0\|^unreachable" | sort -n; echo empty fixup) >/tmp/mwan3rtmon/ipv6.$tid + cat /tmp/mwan3rtmon/ipv6.$tid | grep -v -x -F -f /tmp/mwan3rtmon/ipv6.main | while read line; do + $IP6 route del table $tid $line + done + cat /tmp/mwan3rtmon/ipv6.main | grep -v -x -F -f /tmp/mwan3rtmon/ipv6.$tid | while read line; do + $IP6 route add table $tid $line + done + fi + } + if [ "$(uci get mwan3.@interface[$((idx-1))].enabled)" = "1" ]; then + ret=0 + fi + done + rm -f /tmp/mwan3rtmon/ipv6.* + return $ret } # counts how many bits are set to 1 @@ -99,12 +112,89 @@ mwan3_count_one_bits() echo $count } +# maps the 1st parameter so it only uses the bits allowed by the bitmask (2nd parameter) +# which means spreading the bits of the 1st parameter to only use the bits that are set to 1 in the 2nd parameter +# 0 0 0 0 0 1 0 1 (0x05) 1st parameter +# 1 0 1 0 1 0 1 0 (0xAA) 2nd parameter +# 1 0 1 result +mwan3_id2mask() +{ + local bit_msk bit_val result + bit_val=0 + result=0 + for bit_msk in $(seq 0 31); do + if [ $((($2>>bit_msk)&1)) = "1" ]; then + if [ $((($1>>bit_val)&1)) = "1" ]; then + result=$((result|(1< "${MWAN3_STATUS_DIR}/mmx_mask" + $LOG notice "Using firewall mask ${MMX_MASK}" + + bitcnt=$(mwan3_count_one_bits MMX_MASK) + mmdefault=$(((1< "${MWAN3_STATUS_IPTABLES_LOG_DIR}/ipset-set_custom_ipset.dump" - error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_custom_ipset: $error" + $IPS -! create mwan3_custom_v6 hash:net family inet6 + $IPS create mwan3_custom_v6_temp hash:net family inet6 + config_list_foreach "globals" "rt_table_lookup" mwan3_set_custom_ipset_v6 + $IPS swap mwan3_custom_v6_temp mwan3_custom_v6 + $IPS destroy mwan3_custom_v6_temp + + $IPS -! create mwan3_connected list:set + $IPS -! add mwan3_connected mwan3_custom_v4 + $IPS -! add mwan3_connected mwan3_custom_v6 } - -mwan3_set_connected_ipv4() +mwan3_set_connected_iptables() { - local connected_network_v4 error - local candidate_list cidr_list - local update="" + local connected_network_v4 connected_network_v6 source_network_v6 - mwan3_push_update -! create mwan3_connected_ipv4 hash:net - mwan3_push_update flush mwan3_connected_ipv4 + $IPS -! create mwan3_connected_v4 hash:net + $IPS create mwan3_connected_v4_temp hash:net - candidate_list="" - cidr_list="" - route_lists() - { - $IP4 route | awk '{print $1}' - $IP4 route list table 0 | awk '{print $2}' - } - 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 - candidate_list="$candidate_list $connected_network_v4" - fi + for connected_network_v4 in $($IP4 route | awk '{print $1}' | egrep '[0-9]{1,3}(\.[0-9]{1,3}){3}'); do + $IPS -! add mwan3_connected_v4_temp $connected_network_v4 done - for connected_network_v4 in $cidr_list; do - mwan3_push_update -! add mwan3_connected_ipv4 "$connected_network_v4" - done - for connected_network_v4 in $candidate_list; do - mwan3_push_update -! add mwan3_connected_ipv4 "$connected_network_v4" + for connected_network_v4 in $($IP4 route list table 0 | awk '{print $2}' | egrep '[0-9]{1,3}(\.[0-9]{1,3}){3}'); do + $IPS -! add mwan3_connected_v4_temp $connected_network_v4 done - mwan3_push_update add mwan3_connected_ipv4 224.0.0.0/3 + $IPS add mwan3_connected_v4_temp 224.0.0.0/3 - echo "$update" > "${MWAN3_STATUS_IPTABLES_LOG_DIR}/ipset-set_connected_ipv4.dump" - error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_connected_ipv4: $error" -} + $IPS swap mwan3_connected_v4_temp mwan3_connected_v4 + $IPS destroy mwan3_connected_v4_temp -mwan3_set_connected_ipv6() -{ - local connected_network_v6 error - local update="" - [ $NO_IPV6 -eq 0 ] || return + $IPS -! create mwan3_connected_v6 hash:net family inet6 + $IPS create mwan3_connected_v6_temp hash:net family inet6 - mwan3_push_update -! create mwan3_connected_ipv6 hash:net family inet6 - mwan3_push_update flush mwan3_connected_ipv6 - - for connected_network_v6 in $($IP6 route | awk '{print $1}' | grep -E "$IPv6_REGEX"); do - mwan3_push_update -! add mwan3_connected_ipv6 "$connected_network_v6" + for connected_network_v6 in $($IP6 route | awk '{print $1}' | egrep "$IPv6_REGEX"); do + $IPS -! add mwan3_connected_v6_temp $connected_network_v6 done - echo "$update" > "${MWAN3_STATUS_IPTABLES_LOG_DIR}/ipset-set_connected_ipv6.dump" - error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_connected_ipv6: $error" -} + $IPS swap mwan3_connected_v6_temp mwan3_connected_v6 + $IPS destroy mwan3_connected_v6_temp -mwan3_set_connected_ipset() -{ - local error - local update="" + $IPS -! create mwan3_connected list:set + $IPS -! add mwan3_connected mwan3_connected_v4 + $IPS -! add mwan3_connected mwan3_connected_v6 - mwan3_push_update -! create mwan3_connected_ipv4 hash:net - mwan3_push_update flush mwan3_connected_ipv4 + $IPS -! create mwan3_source_v6 hash:net family inet6 + $IPS create mwan3_source_v6_temp hash:net family inet6 + for source_network_v6 in $($IP6 addr ls | sed -ne 's/ *inet6 \([^ \/]*\).* scope global.*/\1/p'); do + $IPS -! add mwan3_source_v6_temp $source_network_v6 + done + $IPS swap mwan3_source_v6_temp mwan3_source_v6 + $IPS destroy mwan3_source_v6_temp - if [ $NO_IPV6 -eq 0 ]; then - mwan3_push_update -! create mwan3_connected_ipv6 hash:net family inet6 - mwan3_push_update flush mwan3_connected_ipv6 - fi + $IPS -! create mwan3_dynamic_v4 hash:net + $IPS -! add mwan3_connected mwan3_dynamic_v4 - echo "$update" > "${MWAN3_STATUS_IPTABLES_LOG_DIR}/ipset-set_connected_ipset.dump" - error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_connected_ipset: $error" -} - -mwan3_set_dynamic_ipset() -{ - local error - local update="" - - mwan3_push_update -! create mwan3_dynamic_ipv4 list:set - mwan3_push_update flush mwan3_dynamic_ipv4 - - if [ $NO_IPV6 -eq 0 ]; then - mwan3_push_update -! create mwan3_dynamic_ipv6 hash:net family inet6 - mwan3_push_update flush mwan3_dynamic_ipv6 - fi - - echo "$update" > "${MWAN3_STATUS_IPTABLES_LOG_DIR}/ipset-set_dynamic_ipset.dump" - error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_dynamic_ipset: $error" + $IPS -! create mwan3_dynamic_v6 hash:net family inet6 + $IPS -! add mwan3_connected mwan3_dynamic_v6 } mwan3_set_general_rules() @@ -240,13 +292,13 @@ mwan3_set_general_rules() local IP 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 @@ -255,468 +307,535 @@ mwan3_set_general_rules() mwan3_set_general_iptables() { - local IPT current update error family + local IPT for IPT in "$IPT4" "$IPT6"; do - [ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue - current="$($IPT -S)"$'\n' - update="*mangle" - if [ -n "${current##*-N mwan3_ifaces_in*}" ]; then - mwan3_push_update -N mwan3_ifaces_in + + if ! $IPT -S mwan3_ifaces_in &> /dev/null; then + $IPT -N mwan3_ifaces_in fi - if [ "$IPT" = "$IPT6" ]; then - family="ipv6" - else - family="ipv4" + if ! $IPT -S mwan3_connected &> /dev/null; then + $IPT -N mwan3_connected + $IPS -! create mwan3_connected list:set + $IPT -A mwan3_connected \ + -m set --match-set mwan3_connected dst \ + -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK fi - for chain in custom connected dynamic; do - echo "${current}" | grep -q "\-N mwan3_${chain}_${family}$" - local ret="$?" - if [ "$ret" = 1 ]; then - mwan3_push_update -N mwan3_${chain}_${family} - mwan3_push_update -A mwan3_${chain}_${family} \ - -m set --match-set mwan3_${chain}_${family} dst \ - -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK - fi - done - - if [ -n "${current##*-N mwan3_rules*}" ]; then - mwan3_push_update -N mwan3_rules + if ! $IPT -S mwan3_rules &> /dev/null; then + $IPT -N mwan3_rules fi - if [ -n "${current##*-N mwan3_hook*}" ]; then - mwan3_push_update -N mwan3_hook + if ! $IPT -S mwan3_hook &> /dev/null; then + $IPT -N mwan3_hook # do not mangle ipv6 ra service if [ "$IPT" = "$IPT6" ]; then - mwan3_push_update -A mwan3_hook \ - -p ipv6-icmp \ - -m icmp6 --icmpv6-type 133 \ - -j RETURN - mwan3_push_update -A mwan3_hook \ - -p ipv6-icmp \ - -m icmp6 --icmpv6-type 134 \ - -j RETURN - mwan3_push_update -A mwan3_hook \ - -p ipv6-icmp \ - -m icmp6 --icmpv6-type 135 \ - -j RETURN - mwan3_push_update -A mwan3_hook \ - -p ipv6-icmp \ - -m icmp6 --icmpv6-type 136 \ - -j RETURN - mwan3_push_update -A mwan3_hook \ - -p ipv6-icmp \ - -m icmp6 --icmpv6-type 137 \ - -j RETURN + $IPT6 -A mwan3_hook \ + -p ipv6-icmp \ + -m icmp6 --icmpv6-type 133 \ + -j RETURN + $IPT6 -A mwan3_hook \ + -p ipv6-icmp \ + -m icmp6 --icmpv6-type 134 \ + -j RETURN + $IPT6 -A mwan3_hook \ + -p ipv6-icmp \ + -m icmp6 --icmpv6-type 135 \ + -j RETURN + $IPT6 -A mwan3_hook \ + -p ipv6-icmp \ + -m icmp6 --icmpv6-type 136 \ + -j RETURN + $IPT6 -A mwan3_hook \ + -p ipv6-icmp \ + -m icmp6 --icmpv6-type 137 \ + -j RETURN + # do not mangle outgoing echo request + $IPT6 -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 \ - -j mwan3_ifaces_in - - for chain in custom connected dynamic; do - mwan3_push_update -A mwan3_hook \ - -m mark --mark 0x0/$MMX_MASK \ - -j mwan3_${chain}_${family} - done - - mwan3_push_update -A mwan3_hook \ - -m mark --mark 0x0/$MMX_MASK \ - -j mwan3_rules - mwan3_push_update -A mwan3_hook \ - -j CONNMARK --save-mark --nfmask "$MMX_MASK" --ctmask "$MMX_MASK" - - for chain in custom connected dynamic; do - mwan3_push_update -A mwan3_hook \ - -m mark ! --mark $MMX_DEFAULT/$MMX_MASK \ - -j mwan3_${chain}_${family} - done + $IPT -A mwan3_hook \ + -j CONNMARK --restore-mark --nfmask $MMX_MASK --ctmask $MMX_MASK + $IPT -A mwan3_hook \ + -m mark --mark 0x0/$MMX_MASK \ + -j mwan3_ifaces_in + $IPT -A mwan3_hook \ + -m mark --mark 0x0/$MMX_MASK \ + -j mwan3_connected + $IPT -A mwan3_hook \ + -m mark --mark 0x0/$MMX_MASK \ + -j mwan3_rules + $IPT -A mwan3_hook \ + -j CONNMARK --save-mark --nfmask $MMX_MASK --ctmask $MMX_MASK + $IPT -A mwan3_hook \ + -m mark ! --mark $MMX_DEFAULT/$MMX_MASK \ + -j mwan3_connected fi - if [ -n "${current##*-A PREROUTING -j mwan3_hook*}" ]; then - mwan3_push_update -A PREROUTING -j mwan3_hook + if ! $IPT -S PREROUTING | grep mwan3_hook &> /dev/null; then + $IPT -A PREROUTING -j mwan3_hook fi - if [ -n "${current##*-A OUTPUT -j mwan3_hook*}" ]; then - mwan3_push_update -A OUTPUT -j mwan3_hook - fi - mwan3_push_update COMMIT - mwan3_push_update "" - echo "$update" > "${MWAN3_STATUS_IPTABLES_LOG_DIR}/iptables-set_general_iptables-${family}.dump" - if [ "$IPT" = "$IPT4" ]; then - error=$(echo "$update" | $IPT4R 2>&1) || LOG error "set_general_iptables (${family}): $error" - else - error=$(echo "$update" | $IPT6R 2>&1) || LOG error "set_general_iptables (${family}): $error" + if ! $IPT -S OUTPUT | grep mwan3_hook &> /dev/null; then + $IPT -A OUTPUT -j mwan3_hook fi done } mwan3_create_iface_iptables() { - local id family IPT IPTR current update error + local id family - config_get family "$1" family ipv4 - mwan3_get_iface_id id "$1" + config_get family $1 family ipv4 + mwan3_get_iface_id id $1 [ -n "$id" ] || return 0 - if [ "$family" = "ipv4" ]; then - IPT="$IPT4" - IPTR="$IPT4R" - elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then - IPT="$IPT6" - IPTR="$IPT6R" - else - return - fi + if [ "$family" == "ipv4" ]; then + $IPS -! create mwan3_connected list:set - current="$($IPT -S)"$'\n' - update="*mangle" - if [ -n "${current##*-N mwan3_ifaces_in*}" ]; then - mwan3_push_update -N mwan3_ifaces_in - fi + if ! $IPT4 -S mwan3_ifaces_in &> /dev/null; then + $IPT4 -N mwan3_ifaces_in + fi - 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" - fi + if ! $IPT4 -S mwan3_iface_in_$1 &> /dev/null; then + $IPT4 -N mwan3_iface_in_$1 + fi - for chain in custom connected dynamic; do - mwan3_push_update -A "mwan3_iface_in_$1" \ - -i "$2" \ - -m set --match-set mwan3_${chain}_${family} src \ - -m mark --mark "0x0/$MMX_MASK" \ + $IPT4 -F mwan3_iface_in_$1 + $IPT4 -A mwan3_iface_in_$1 \ + -i $2 \ + -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" - done - mwan3_push_update -A "mwan3_iface_in_$1" \ - -i "$2" \ - -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 $MMX_DEFAULT/$MMX_MASK + $IPT4 -A mwan3_iface_in_$1 \ + -i $2 \ + -m mark --mark 0x0/$MMX_MASK \ + -m comment --comment "$1" \ + -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK - if [ -n "${current##*-A mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_${1}$'\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" - else - LOG debug "create_iface_iptables: mwan3_iface_in_$1 already in iptables, skip" + $IPT4 -D mwan3_ifaces_in \ + -m mark --mark 0x0/$MMX_MASK \ + -j mwan3_iface_in_$1 &> /dev/null + $IPT4 -A mwan3_ifaces_in \ + -m mark --mark 0x0/$MMX_MASK \ + -j mwan3_iface_in_$1 fi - mwan3_push_update COMMIT - mwan3_push_update "" + if [ "$family" == "ipv6" ]; then + $IPS -! create mwan3_connected_v6 hash:net family inet6 - echo "$update" > "${MWAN3_STATUS_IPTABLES_LOG_DIR}/iptables-create_iface_iptables-${1}.dump" - error=$(echo "$update" | $IPTR 2>&1) || LOG error "create_iface_iptables (${1}): $error" + if ! $IPT6 -S mwan3_ifaces_in &> /dev/null; then + $IPT6 -N mwan3_ifaces_in + fi + + if ! $IPT6 -S mwan3_iface_in_$1 &> /dev/null; then + $IPT6 -N mwan3_iface_in_$1 + fi + + $IPT6 -F mwan3_iface_in_$1 + $IPT6 -A mwan3_iface_in_$1 -i $2 \ + -m set --match-set mwan3_connected_v6 src \ + -m mark --mark 0x0/$MMX_MASK \ + -m comment --comment "default" \ + -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK + $IPT6 -A mwan3_iface_in_$1 -i $2 -m mark --mark 0x0/$MMX_MASK \ + -m comment --comment "$1" \ + -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK + + $IPT6 -D mwan3_ifaces_in \ + -m mark --mark 0x0/$MMX_MASK \ + -j mwan3_iface_in_$1 &> /dev/null + $IPT6 -A mwan3_ifaces_in \ + -m mark --mark 0x0/$MMX_MASK \ + -j mwan3_iface_in_$1 + fi } mwan3_delete_iface_iptables() { - local IPT update - config_get family "$1" family ipv4 + config_get family $1 family ipv4 - if [ "$family" = "ipv4" ]; then - IPT="$IPT4" + if [ "$family" == "ipv4" ]; then + + $IPT4 -D mwan3_ifaces_in \ + -m mark --mark 0x0/$MMX_MASK \ + -j mwan3_iface_in_$1 &> /dev/null + $IPT4 -F mwan3_iface_in_$1 &> /dev/null + $IPT4 -X mwan3_iface_in_$1 &> /dev/null fi - if [ "$family" = "ipv6" ]; then - [ $NO_IPV6 -ne 0 ] && return - IPT="$IPT6" + if [ "$family" == "ipv6" ]; then + + $IPT6 -D mwan3_ifaces_in \ + -m mark --mark 0x0/$MMX_MASK \ + -j mwan3_iface_in_$1 &> /dev/null + $IPT6 -F mwan3_iface_in_$1 &> /dev/null + $IPT6 -X mwan3_iface_in_$1 &> /dev/null fi - - update="*mangle" - - mwan3_push_update -D mwan3_ifaces_in \ - -m mark --mark 0x0/$MMX_MASK \ - -j "mwan3_iface_in_$1" &> /dev/null - mwan3_push_update -F "mwan3_iface_in_$1" &> /dev/null - mwan3_push_update -X "mwan3_iface_in_$1" &> /dev/null - - mwan3_push_update COMMIT - mwan3_push_update "" - - echo "$update" > "${MWAN3_STATUS_IPTABLES_LOG_DIR}/iptables-delete_iface_iptables-${1}.dump" - error=$(echo "$update" | $IPTR 2>&1) || LOG error "delete_iface_iptables (${1}): $error" -} - -mwan3_extra_tables_routes() -{ - $IP route list table "$1" -} - -mwan3_get_routes() -{ - { - $IP route list table main - config_list_foreach "globals" "rt_table_lookup" mwan3_extra_tables_routes - } | sed -ne "$MWAN3_ROUTE_LINE_EXP" | sort -u } mwan3_create_iface_route() { - local tid route_line family IP id tbl - config_get family "$1" family ipv4 - mwan3_get_iface_id id "$1" + local id route_args metric + + config_get family $1 family ipv4 + mwan3_get_iface_id id $1 [ -n "$id" ] || return 0 - if [ "$family" = "ipv4" ]; then - IP="$IP4" - elif [ "$family" = "ipv6" ]; then - IP="$IP6" - fi - - tbl=$($IP route list table $id 2>/dev/null)$'\n' - mwan3_update_dev_to_table - 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 debug "Route '$route_line' already added to table $id" + if [ "$family" == "ipv4" ]; then + if ubus call network.interface.${1}_4 status &>/dev/null; then + network_get_gateway route_args ${1}_4 + else + network_get_gateway route_args $1 fi - done + if [ -n "$route_args" -a "$route_args" != "0.0.0.0" ]; then + route_args="via $route_args" + else + route_args="" + fi + + network_get_metric metric $1 + if [ -n "$metric" -a "$metric" != "0" ]; then + route_args="$route_args metric $metric" + fi + + $IP4 route flush table $id + $IP4 route add table $id default $route_args dev $2 + mwan3_rtmon_ipv4 + fi + + if [ "$family" == "ipv6" ]; then + if ubus call network.interface.${1}_6 status &>/dev/null; then + network_get_gateway6 route_args ${1}_6 + else + network_get_gateway6 route_args $1 + fi + + if [ -n "$route_args" -a "$route_args" != "::" ]; then + route_args="via $route_args" + else + route_args="" + fi + + network_get_metric metric $1 + if [ -n "$metric" -a "$metric" != "0" ]; then + route_args="$route_args metric $metric" + fi + + $IP6 route flush table $id + $IP6 route add table $id default $route_args dev $2 + mwan3_rtmon_ipv6 + fi } mwan3_delete_iface_route() { - local id family + local id - config_get family "$1" family ipv4 - mwan3_get_iface_id id "$1" + config_get family $1 family ipv4 + mwan3_get_iface_id id $1 - if [ -z "$id" ]; then - LOG warn "delete_iface_route: could not find table id for interface $1" - return 0 + [ -n "$id" ] || return 0 + + if [ "$family" == "ipv4" ]; then + $IP4 route flush table $id fi - if [ "$family" = "ipv4" ]; then - $IP4 route flush table "$id" - elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then - $IP6 route flush table "$id" + if [ "$family" == "ipv6" ]; then + $IP6 route flush table $id fi } mwan3_create_iface_rules() { - local id family IP + local id family - config_get family "$1" family ipv4 - mwan3_get_iface_id id "$1" + config_get family $1 family ipv4 + mwan3_get_iface_id id $1 [ -n "$id" ] || return 0 - if [ "$family" = "ipv4" ]; then - IP="$IP4" - elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then - IP="$IP6" - else - return + if [ "$family" == "ipv4" ]; then + + while [ -n "$($IP4 rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do + $IP4 rule del pref $(($id+1000)) + done + + while [ -n "$($IP4 rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do + $IP4 rule del pref $(($id+2000)) + done + + $IP4 rule add pref $(($id+1000)) iif $2 lookup $id + $IP4 rule add pref $(($id+2000)) fwmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK lookup $id fi - mwan3_delete_iface_rules "$1" + if [ "$family" == "ipv6" ]; then - $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 + while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do + $IP6 rule del pref $(($id+1000)) + done + + while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do + $IP6 rule del pref $(($id+2000)) + done + + $IP6 rule add pref $(($id+1000)) iif $2 lookup $id + $IP6 rule add pref $(($id+2000)) fwmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK lookup $id + fi } mwan3_delete_iface_rules() { - local id family IP rule_id + local id family - config_get family "$1" family ipv4 - mwan3_get_iface_id id "$1" + config_get family $1 family ipv4 + mwan3_get_iface_id id $1 [ -n "$id" ] || return 0 - if [ "$family" = "ipv4" ]; then - IP="$IP4" - elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then - IP="$IP6" - else - return + if [ "$family" == "ipv4" ]; then + + while [ -n "$($IP4 rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do + $IP4 rule del pref $(($id+1000)) + done + + while [ -n "$($IP4 rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do + $IP4 rule del pref $(($id+2000)) + done fi - 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 + if [ "$family" == "ipv6" ]; then + + while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do + $IP6 rule del pref $(($id+1000)) + done + + while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do + $IP6 rule del pref $(($id+2000)) + done + fi } mwan3_delete_iface_ipset_entries() { local id setname entry - mwan3_get_iface_id id "$1" + mwan3_get_iface_id id $1 [ -n "$id" ] || return 0 - for setname in $(ipset -n list | grep ^mwan3_rule_); do - for entry in $(ipset list "$setname" | grep "$(mwan3_id2mask id MMX_MASK | awk '{ printf "0x%08x", $1; }')" | cut -d ' ' -f 1); do - $IPS del "$setname" $entry || - LOG notice "failed to delete $entry from $setname" + for setname in $(ipset -n list | grep ^mwan3_sticky_); do + for entry in $(ipset list $setname | grep "$(echo $(mwan3_id2mask id MMX_MASK) | awk '{ printf "0x%08x", $1; }')" | cut -d ' ' -f 1); do + $IPS del $setname $entry done done } +mwan3_rtmon() +{ + pid="$(pgrep -f mwan3rtmon)" + if [ "${pid}" != "" ]; then + kill -USR1 "${pid}" + else + [ -x /usr/sbin/mwan3rtmon ] && /usr/sbin/mwan3rtmon & + fi +} + +mwan3_track() +{ + local track_ip track_ips pid + + mwan3_list_track_ips() + { + track_ips="$track_ips $1" + } + config_list_foreach $1 track_ip mwan3_list_track_ips + + for pid in $(pgrep -f "mwan3track $1 $2"); do + kill -TERM "$pid" > /dev/null 2>&1 + sleep 1 + kill -KILL "$pid" > /dev/null 2>&1 + done + if [ -n "$track_ips" ]; then + [ -x /usr/sbin/mwan3track ] && /usr/sbin/mwan3track "$1" "$2" "$3" "$4" $track_ips & + fi +} + +mwan3_track_signal() +{ + local pid + + pid="$(pgrep -f "mwan3track $1 $2")" + [ "${pid}" != "" ] && { + kill -USR1 "${pid}" + } +} mwan3_set_policy() { - local id iface family metric probability weight device is_lowest is_offline IPT IPTR total_weight current update error + local iface_count id iface family metric probability weight device - is_lowest=0 - config_get iface "$1" interface - config_get metric "$1" metric 1 - config_get weight "$1" weight 1 + config_get iface $1 interface + config_get metric $1 metric 1 + config_get weight $1 weight 1 [ -n "$iface" ] || return 0 - network_get_device device "$iface" - [ "$metric" -gt $DEFAULT_LOWEST_METRIC ] && LOG warn "Member interface $iface has >$DEFAULT_LOWEST_METRIC metric. Not appending to policy" && return 0 + network_get_device device $iface + [ "$metric" -gt $DEFAULT_LOWEST_METRIC ] && $LOG warn "Member interface $iface has >$DEFAULT_LOWEST_METRIC metric. Not appending to policy" && return 0 - mwan3_get_iface_id id "$iface" + mwan3_get_iface_id id $iface [ -n "$id" ] || return 0 - [ "$(mwan3_get_iface_hotplug_state "$iface")" = "online" ] - is_offline=$? + config_get family $iface family ipv4 - config_get family "$iface" family ipv4 + if [ "$family" == "ipv4" ]; then - if [ "$family" = "ipv4" ]; then - IPT="$IPT4" - IPTR="$IPT4R" - elif [ "$family" = "ipv6" ]; then - IPT="$IPT6" - IPTR="$IPT6R" - fi - current="$($IPT -S)"$'\n' - update="*mangle" + if [ "$(mwan3_get_iface_hotplug_state $iface)" = "online" ]; then + if [ "$metric" -lt "$lowest_metric_v4" ]; then - if [ "$family" = "ipv4" ] && [ $is_offline -eq 0 ]; then - if [ "$metric" -lt "$lowest_metric_v4" ]; then - is_lowest=1 - total_weight_v4=$weight - lowest_metric_v4=$metric - elif [ "$metric" -eq "$lowest_metric_v4" ]; then - total_weight_v4=$((total_weight_v4+weight)) - total_weight=$total_weight_v4 + total_weight_v4=$weight + $IPT4 -F mwan3_policy_$policy + $IPT4 -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 + + lowest_metric_v4=$metric + + elif [ "$metric" -eq "$lowest_metric_v4" ]; then + + total_weight_v4=$(($total_weight_v4+$weight)) + probability=$(($weight*1000/$total_weight_v4)) + + if [ "$probability" -lt 10 ]; then + probability="0.00$probability" + elif [ $probability -lt 100 ]; then + probability="0.0$probability" + elif [ $probability -lt 1000 ]; then + probability="0.$probability" + else + probability="1" + fi + + probability="-m statistic --mode random --probability $probability" + + $IPT4 -I mwan3_policy_$policy \ + -m mark --mark 0x0/$MMX_MASK $probability \ + -m comment --comment "$iface $weight $total_weight_v4" \ + -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK + fi else - return - fi - elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ] && [ $is_offline -eq 0 ]; then - if [ "$metric" -lt "$lowest_metric_v6" ]; then - is_lowest=1 - total_weight_v6=$weight - lowest_metric_v6=$metric - elif [ "$metric" -eq "$lowest_metric_v6" ]; then - total_weight_v6=$((total_weight_v6+weight)) - total_weight=$total_weight_v6 - else - return + [ -n "$device" ] && { + $IPT4 -S mwan3_policy_$policy | grep -q '.*--comment ".* [0-9]* [0-9]*"' || \ + $IPT4 -I mwan3_policy_$policy \ + -o $device \ + -m mark --mark 0x0/$MMX_MASK \ + -m comment --comment "out $iface $device" \ + -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK + } fi fi - if [ $is_lowest -eq 1 ]; then - mwan3_push_update -F "mwan3_policy_$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" - elif [ $is_offline -eq 0 ]; then - probability=$((weight*1000/total_weight)) - if [ "$probability" -lt 10 ]; then - probability="0.00$probability" - elif [ $probability -lt 100 ]; then - probability="0.0$probability" - elif [ $probability -lt 1000 ]; then - probability="0.$probability" + + if [ "$family" == "ipv6" ]; then + + if [ "$(mwan3_get_iface_hotplug_state $iface)" = "online" ]; then + if [ "$metric" -lt "$lowest_metric_v6" ]; then + + total_weight_v6=$weight + $IPT6 -F mwan3_policy_$policy + $IPT6 -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 + + lowest_metric_v6=$metric + + elif [ "$metric" -eq "$lowest_metric_v6" ]; then + + total_weight_v6=$(($total_weight_v6+$weight)) + probability=$(($weight*1000/$total_weight_v6)) + + if [ "$probability" -lt 10 ]; then + probability="0.00$probability" + elif [ $probability -lt 100 ]; then + probability="0.0$probability" + elif [ $probability -lt 1000 ]; then + probability="0.$probability" + else + probability="1" + fi + + probability="-m statistic --mode random --probability $probability" + + $IPT6 -I mwan3_policy_$policy \ + -m mark --mark 0x0/$MMX_MASK \ + $probability \ + -m comment --comment "$iface $weight $total_weight_v6" \ + -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK + fi else - probability="1" + [ -n "$device" ] && { + $IPT6 -S mwan3_policy_$policy | grep -q '.*--comment ".* [0-9]* [0-9]*"' || \ + $IPT6 -I mwan3_policy_$policy \ + -o $device \ + -m mark --mark 0x0/$MMX_MASK \ + -m comment --comment "out $iface $device" \ + -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK + } fi - - mwan3_push_update -I "mwan3_policy_$policy" \ - -m mark --mark 0x0/$MMX_MASK \ - -m statistic \ - --mode random \ - --probability "$probability" \ - -m comment --comment \"$iface $weight $total_weight\" \ - -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" \ - -o "$device" \ - -m mark --mark 0x0/$MMX_MASK \ - -m comment --comment \"out $iface $device\" \ - -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK fi - mwan3_push_update COMMIT - mwan3_push_update "" - - echo "$update" > "${MWAN3_STATUS_IPTABLES_LOG_DIR}/iptables-set_policy-${1}.dump" - error=$(echo "$update" | $IPTR 2>&1) || LOG error "set_policy ($1): $error" } mwan3_create_policies_iptables() { - local last_resort lowest_metric_v4 lowest_metric_v6 total_weight_v4 total_weight_v6 policy IPT current update error + local last_resort lowest_metric_v4 lowest_metric_v6 total_weight_v4 total_weight_v6 policy IPT policy="$1" - config_get last_resort "$1" last_resort unreachable + config_get last_resort $1 last_resort unreachable - if [ "$1" != "$(echo "$1" | cut -c1-15)" ]; then - LOG warn "Policy $1 exceeds max of 15 chars. Not setting policy" && return 0 + if [ "$1" != $(echo "$1" | cut -c1-15) ]; then + $LOG warn "Policy $1 exceeds max of 15 chars. Not setting policy" && return 0 fi for IPT in "$IPT4" "$IPT6"; do - [ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue - current="$($IPT -S)"$'\n' - update="*mangle" - if [ -n "${current##*-N mwan3_policy_$1$'\n'*}" ]; then - mwan3_push_update -N "mwan3_policy_$1" + + if ! $IPT -S mwan3_policy_$1 &> /dev/null; then + $IPT -N mwan3_policy_$1 fi - mwan3_push_update -F "mwan3_policy_$1" + $IPT -F mwan3_policy_$1 case "$last_resort" in blackhole) - mwan3_push_update -A "mwan3_policy_$1" \ - -m mark --mark 0x0/$MMX_MASK \ - -m comment --comment "blackhole" \ - -j MARK --set-xmark $MMX_BLACKHOLE/$MMX_MASK - ;; + $IPT -A mwan3_policy_$1 \ + -m mark --mark 0x0/$MMX_MASK \ + -m comment --comment "blackhole" \ + -j MARK --set-xmark $MMX_BLACKHOLE/$MMX_MASK + ;; default) - mwan3_push_update -A "mwan3_policy_$1" \ - -m mark --mark 0x0/$MMX_MASK \ - -m comment --comment "default" \ - -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK - ;; + $IPT -A mwan3_policy_$1 \ + -m mark --mark 0x0/$MMX_MASK \ + -m comment --comment "default" \ + -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK + ;; *) - mwan3_push_update -A "mwan3_policy_$1" \ - -m mark --mark 0x0/$MMX_MASK \ - -m comment --comment "unreachable" \ - -j MARK --set-xmark $MMX_UNREACHABLE/$MMX_MASK - ;; + $IPT -A mwan3_policy_$1 \ + -m mark --mark 0x0/$MMX_MASK \ + -m comment --comment "unreachable" \ + -j MARK --set-xmark $MMX_UNREACHABLE/$MMX_MASK + ;; esac - mwan3_push_update COMMIT - mwan3_push_update "" - - echo "$update" > "${MWAN3_STATUS_IPTABLES_LOG_DIR}/iptables-create_policies_iptables-${1}.dump" - if [ "$IPT" = "$IPT4" ]; then - error=$(echo "$update" | $IPT4R 2>&1) || LOG error "create_policies_iptables ($1): $error" - else - error=$(echo "$update" | $IPT6R 2>&1) || LOG error "create_policies_iptables ($1): $error" - fi done lowest_metric_v4=$DEFAULT_LOWEST_METRIC @@ -725,7 +844,7 @@ mwan3_create_policies_iptables() lowest_metric_v6=$DEFAULT_LOWEST_METRIC total_weight_v6=0 - config_list_foreach "$1" use_member mwan3_set_policy + config_list_foreach $1 use_member mwan3_set_policy } mwan3_set_policies_iptables() @@ -735,403 +854,253 @@ mwan3_set_policies_iptables() mwan3_set_sticky_iptables() { - local interface="${1}" - local rule="${2}" - local ipv="${3}" - local policy="${4}" - local id iface - for iface in $(echo "$current" | grep "^-A $policy" | cut -s -d'"' -f2 | awk '{print $1}'); do - if [ "$iface" = "$interface" ]; then - mwan3_get_iface_id id "$iface" + for iface in $($IPT4 -S $policy | cut -s -d'"' -f2 | awk '{print $1}'); do + + if [ "$iface" == "$1" ]; then + + mwan3_get_iface_id id $1 [ -n "$id" ] || return 0 - if [ -z "${current##*-N mwan3_iface_in_${iface}$'\n'*}" ]; then - mwan3_push_update -I "mwan3_rule_$rule" \ - -m mark --mark "$(mwan3_id2mask id MMX_MASK)/$MMX_MASK" \ - -m set ! --match-set "mwan3_rule_${ipv}_${rule}" src,src \ - -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" - fi + + for IPT in "$IPT4" "$IPT6"; do + if [ -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" ]; then + $IPT -I mwan3_rule_$rule \ + -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 + $IPT -I mwan3_rule_$rule \ + -m mark --mark 0/$MMX_MASK \ + -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK + fi + done fi done } -mwan3_set_sticky_ipset() -{ - local rule="$1" - local mmx="$2" - local timeout="$3" - - local error - local update="" - - mwan3_push_update -! create "mwan3_rule_ipv4_$rule" \ - hash:ip,mark markmask "$mmx" \ - timeout "$timeout" - - [ $NO_IPV6 -eq 0 ] && - mwan3_push_update -! create "mwan3_rule_ipv6_$rule" \ - hash:ip,mark markmask "$mmx" \ - timeout "$timeout" family inet6 - - echo "$update" > "${MWAN3_STATUS_IPTABLES_LOG_DIR}/ipset-set_sticky_ipset-${rule}.dump" - error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_sticky_ipset (${rule}): $error" -} - 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 sticky dest_ip dest_port use_policy timeout rule policy IPT + local global_logging rule_logging loglevel rule="$1" - ipv="$2" - rule_policy=0 - config_get sticky "$1" sticky 0 - config_get timeout "$1" timeout 600 - config_get ipset "$1" ipset - config_get proto "$1" proto all - config_get src_ip "$1" src_ip - config_get src_iface "$1" src_iface - config_get src_port "$1" src_port - config_get dest_ip "$1" dest_ip - config_get dest_port "$1" dest_port - config_get use_policy "$1" use_policy - config_get family "$1" family any - config_get rule_logging "$1" logging 0 - 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 - LOG notice "could not find device corresponding to src_iface $src_iface for rule $1" - return - fi - fi + config_get sticky $1 sticky 0 + config_get timeout $1 timeout 600 + config_get ipset $1 ipset + config_get proto $1 proto all + config_get src_ip $1 src_ip + config_get src_iface $1 src_iface + network_get_device src_dev $src_iface + config_get src_port $1 src_port + config_get dest_ip $1 dest_ip + config_get dest_port $1 dest_port + config_get use_policy $1 use_policy + config_get family $1 family any [ -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 + [ "$proto" != 'tcp' ] && [ "$proto" != 'udp' ] && { [ -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" + $LOG warn "src_port set to '$src_port' but proto set to '$proto' not tcp or udp. src_port will be ignored" } - [ -n "$dest_port" ] && { - LOG warn "dest_port set to '$dest_port' but proto set to '$proto' not tcp or udp. dest_port will be ignored" + $LOG warn "dest_port set to '$dest_port' but proto set to '$proto' not tcp or udp. dest_port will be ignored" } unset src_port unset dest_port - fi + } - if [ "$1" != "$(echo "$1" | cut -c1-15)" ]; then - LOG warn "Rule $1 exceeds max of 15 chars. Not setting rule" && return 0 + config_get rule_logging $1 logging 0 + config_get global_logging globals logging 0 + config_get loglevel globals loglevel notice + + if [ "$1" != $(echo "$1" | cut -c1-15) ]; then + $LOG warn "Rule $1 exceeds max of 15 chars. Not setting rule" && return 0 fi if [ -n "$ipset" ]; then ipset="-m set --match-set $ipset dst" fi - if [ -z "$use_policy" ]; then - return - fi + if [ -n "$use_policy" ]; then + if [ "$use_policy" == "default" ]; then + policy="MARK --set-xmark $MMX_DEFAULT/$MMX_MASK" + elif [ "$use_policy" == "unreachable" ]; then + policy="MARK --set-xmark $MMX_UNREACHABLE/$MMX_MASK" + elif [ "$use_policy" == "blackhole" ]; then + policy="MARK --set-xmark $MMX_BLACKHOLE/$MMX_MASK" + else + if [ "$sticky" -eq 1 ]; then - if [ "$use_policy" = "default" ]; then - policy="MARK --set-xmark $MMX_DEFAULT/$MMX_MASK" - elif [ "$use_policy" = "unreachable" ]; then - policy="MARK --set-xmark $MMX_UNREACHABLE/$MMX_MASK" - elif [ "$use_policy" = "blackhole" ]; then - policy="MARK --set-xmark $MMX_BLACKHOLE/$MMX_MASK" - else - rule_policy=1 - policy="mwan3_policy_$use_policy" - if [ "$sticky" -eq 1 ]; then - mwan3_set_sticky_ipset "$rule" "$MMX_MASK" "$timeout" + policy="mwan3_policy_$use_policy" + + for IPT in "$IPT4" "$IPT6"; do + if ! $IPT -S $policy &> /dev/null; then + $IPT -N $policy + fi + + if ! $IPT -S mwan3_rule_$1 &> /dev/null; then + $IPT -N mwan3_rule_$1 + fi + + $IPT -F mwan3_rule_$1 + done + + $IPS -! create mwan3_sticky_v4_$rule \ + hash:ip,mark markmask $MMX_MASK \ + timeout $timeout + $IPS -! create mwan3_sticky_v6_$rule \ + hash:ip,mark markmask $MMX_MASK \ + timeout $timeout family inet6 + $IPS -! create mwan3_sticky_$rule list:set + $IPS -! add mwan3_sticky_$rule mwan3_sticky_v4_$rule + $IPS -! add mwan3_sticky_$rule mwan3_sticky_v6_$rule + + config_foreach mwan3_set_sticky_iptables interface + + for IPT in "$IPT4" "$IPT6"; do + $IPT -A mwan3_rule_$1 \ + -m mark --mark 0/$MMX_MASK \ + -j $policy + $IPT -A mwan3_rule_$1 \ + -m mark ! --mark 0xfc00/0xfc00 \ + -j SET --del-set mwan3_sticky_$rule src,src + $IPT -A mwan3_rule_$1 \ + -m mark ! --mark 0xfc00/0xfc00 \ + -j SET --add-set mwan3_sticky_$rule src,src + done + + policy="mwan3_rule_$1" + else + policy="mwan3_policy_$use_policy" + + for IPT in "$IPT4" "$IPT6"; do + if ! $IPT -S $policy &> /dev/null; then + $IPT -N $policy + fi + done + + fi fi + for IPT in "$IPT4" "$IPT6"; do + [ "$family" == "ipv4" ] && [ "$IPT" == "$IPT6" ] && continue + [ "$family" == "ipv6" ] && [ "$IPT" == "$IPT4" ] && continue + [ "$global_logging" = "1" ] && [ "$rule_logging" = "1" ] && { + $IPT -A mwan3_rules \ + -p $proto \ + ${src_ip:+-s} $src_ip \ + ${src_dev:+-i} $src_dev \ + ${dest_ip:+-d} $dest_ip\ + $ipset \ + ${src_port:+-m} ${src_port:+multiport} ${src_port:+--sports} $src_port \ + ${dest_port:+-m} ${dest_port:+multiport} ${dest_port:+--dports} $dest_port \ + -m mark --mark 0/$MMX_MASK \ + -m comment --comment "$1" \ + -j LOG --log-level "$loglevel" --log-prefix "MWAN3($1)" &> /dev/null + } + + $IPT -A mwan3_rules \ + -p $proto \ + ${src_ip:+-s} $src_ip \ + ${src_dev:+-i} $src_dev \ + ${dest_ip:+-d} $dest_ip\ + $ipset \ + ${src_port:+-m} ${src_port:+multiport} ${src_port:+--sports} $src_port \ + ${dest_port:+-m} ${dest_port:+multiport} ${dest_port:+--dports} $dest_port \ + -m mark --mark 0/$MMX_MASK \ + -j $policy &> /dev/null + done fi - - 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$'\n'*}" ]; then - mwan3_push_update -N "mwan3_rule_$1" - fi - - mwan3_push_update -F "mwan3_rule_$1" - config_foreach mwan3_set_sticky_iptables interface "$rule" "$ipv" "$policy" - - - mwan3_push_update -A "mwan3_rule_$1" \ - -m mark --mark 0/$MMX_MASK \ - -j "$policy" - mwan3_push_update -A "mwan3_rule_$1" \ - -m mark ! --mark 0xfc00/0xfc00 \ - -j SET --del-set "mwan3_rule_${ipv}_${rule}" src,src - mwan3_push_update -A "mwan3_rule_$1" \ - -m mark ! --mark 0xfc00/0xfc00 \ - -j SET --add-set "mwan3_rule_${ipv}_${rule}" src,src - policy="mwan3_rule_$1" - fi - if [ "$global_logging" = "1" ] && [ "$rule_logging" = "1" ]; then - mwan3_push_update -A mwan3_rules \ - -p "$proto" \ - ${src_ip:+-s} $src_ip \ - ${src_dev:+-i} $src_dev \ - ${dest_ip:+-d} $dest_ip \ - $ipset \ - ${src_port:+-m} ${src_port:+multiport} ${src_port:+--sports} $src_port \ - ${dest_port:+-m} ${dest_port:+multiport} ${dest_port:+--dports} $dest_port \ - -m mark --mark 0/$MMX_MASK \ - -m comment --comment "$1" \ - -j LOG --log-level "$loglevel" --log-prefix "MWAN3($1)" - fi - - mwan3_push_update -A mwan3_rules \ - -p "$proto" \ - ${src_ip:+-s} $src_ip \ - ${src_dev:+-i} $src_dev \ - ${dest_ip:+-d} $dest_ip \ - $ipset \ - ${src_port:+-m} ${src_port:+multiport} ${src_port:+--sports} $src_port \ - ${dest_port:+-m} ${dest_port:+multiport} ${dest_port:+--dports} $dest_port \ - -m mark --mark 0/$MMX_MASK \ - -j $policy - -} - -mwan3_set_user_iface_rules() -{ - local current iface update family error device is_src_iface - iface=$1 - device=$2 - - if [ -z "$device" ]; then - LOG notice "set_user_iface_rules: could not find device corresponding to iface $iface" - return - fi - - config_get family "$iface" family ipv4 - - if [ "$family" = "ipv4" ]; then - IPT="$IPT4" - IPTR="$IPT4R" - elif [ "$family" = "ipv6" ]; then - IPT="$IPT6" - IPTR="$IPT6R" - fi - $IPT -S | grep -q "^-A mwan3_rules.*-i $device" && return - - is_src_iface=0 - - iface_rule() - { - local src_iface - config_get src_iface "$1" src_iface - [ "$src_iface" = "$iface" ] && is_src_iface=1 - } - config_foreach iface_rule rule - [ $is_src_iface -eq 1 ] && mwan3_set_user_rules } mwan3_set_user_rules() { - local IPT IPTR ipv - local current update error + local IPT - for ipv in ipv4 ipv6; do - if [ "$ipv" = "ipv4" ]; then - IPT="$IPT4" - IPTR="$IPT4R" - elif [ "$ipv" = "ipv6" ]; then - IPT="$IPT6" - IPTR="$IPT6R" - fi - [ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue - update="*mangle" - current="$($IPT -S)"$'\n' + for IPT in "$IPT4" "$IPT6"; do - - if [ -n "${current##*-N mwan3_rules*}" ]; then - mwan3_push_update -N "mwan3_rules" + if ! $IPT -S mwan3_rules &> /dev/null; then + $IPT -N mwan3_rules fi - mwan3_push_update -F mwan3_rules - - config_foreach mwan3_set_user_iptables_rule rule "$ipv" - - mwan3_push_update COMMIT - mwan3_push_update "" - - echo "$update" > "${MWAN3_STATUS_IPTABLES_LOG_DIR}/iptables-set_user_rules-${ipv}.dump" - error=$(echo "$update" | $IPTR 2>&1) || LOG error "set_user_rules (${ipv}): $error" + $IPT -F mwan3_rules done - -} - -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 interface=$1 - local caller=$2 - - local up l3_device status true_iface - - if [ "${caller}" = "cmd" ]; 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=$caller ACTION=ifup \ - INTERFACE=$interface DEVICE=$l3_device \ - sh /etc/hotplug.d/iface/15-mwan3 - } - - if [ "$up" != "1" ] || [ -z "$l3_device" ]; then - return - fi - - if [ "${caller}" = "init" ]; then - hotplug_startup & - hotplug_pids="$hotplug_pids $!" - else - hotplug_startup - fi - + config_foreach mwan3_set_user_iptables_rule rule } mwan3_set_iface_hotplug_state() { local iface=$1 local state=$2 - echo "$state" > "$MWAN3_STATUS_DIR/iface_state/$iface" + echo -n $state > $MWAN3_STATUS_DIR/iface_state/$iface } mwan3_get_iface_hotplug_state() { local iface=$1 - cat "$MWAN3_STATUS_DIR/iface_state/$iface" 2>/dev/null || echo "offline" + cat $MWAN3_STATUS_DIR/iface_state/$iface 2>/dev/null || echo "offline" } mwan3_report_iface_status() { - local device result tracking IP IPT error + local device result track_ips tracking IP IPT - mwan3_get_iface_id id "$1" - network_get_device device "$1" + mwan3_get_iface_id id $1 + network_get_device device $1 config_get enabled "$1" enabled 0 config_get family "$1" family ipv4 - if [ "$family" = "ipv4" ]; then + if [ "$family" == "ipv4" ]; then IP="$IP4" IPT="$IPT4" fi - if [ "$family" = "ipv6" ]; then + if [ "$family" == "ipv6" ]; then IP="$IP6" IPT="$IPT6" fi - if [ -z "$id" ] || [ -z "$device" ]; then + if [ -z "$id" -o -z "$device" ]; then result="offline" - else - error=0 - [ -n "$($IP rule | awk '$1 == "'$((id+1000)):'"')" ] || - error=$((error+1)) - [ -n "$($IP rule | awk '$1 == "'$((id+2000)):'"')" ] || - error=$((error+2)) - [ -n "$($IP rule | awk '$1 == "'$((id+3000)):'"')" ] || - error=$((error+4)) - [ -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" ] || - error=$((error+8)) - [ -n "$($IP route list table $id default dev $device 2> /dev/null)" ] || - error=$((error+16)) - fi - - if [ "$result" = "offline" ]; then - : - elif [ $error -eq 0 ]; then - online=$(get_online_time "$1") - network_get_uptime uptime "$1" - 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 [ $error -gt 0 ] && [ $error -ne 31 ]; then - result="error (${error})" - elif [ "$enabled" = "1" ]; then + elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" ] && \ + [ -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" ] && \ + [ -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" ] && \ + [ -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then + result="$(mwan3_get_iface_hotplug_state $1)" + elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" ] || \ + [ -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" ] || \ + [ -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" + elif [ "$enabled" == "1" ]; then result="offline" else result="disabled" fi - tracking="$(mwan3_get_mwan3track_status $1)" + 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 + echo " interface $1 is $result and tracking is $tracking" } @@ -1142,16 +1111,16 @@ mwan3_report_policies() local percent total_weight weight iface - total_weight=$($ipt -S "$policy" | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | head -1 | awk '{print $3}') + total_weight=$($ipt -S $policy | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | head -1 | awk '{print $3}') - if [ -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)) + if [ ! -z "${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)) echo " $iface ($percent%)" done else - echo " $($ipt -S "$policy" | grep -v '.*--comment "out .*" .*$' | sed '/.*--comment \([^ ]*\) .*$/!d;s//\1/;q')" + echo " $($ipt -S $policy | grep -v '.*--comment "out .*" .*$' | sed '/.*--comment \([^ ]*\) .*$/!d;s//\1/;q')" fi } @@ -1177,15 +1146,19 @@ mwan3_report_policies_v6() mwan3_report_connected_v4() { - if [ -n "$($IPT4 -S mwan3_connected_ipv4 2> /dev/null)" ]; then - $IPS -o save list mwan3_connected_ipv4 | grep add | cut -d " " -f 3 + local address + + if [ -n "$($IPT4 -S mwan3_connected 2> /dev/null)" ]; then + $IPS -o save list mwan3_connected_v4 | grep add | cut -d " " -f 3 fi } mwan3_report_connected_v6() { - if [ -n "$($IPT6 -S mwan3_connected_ipv6 2> /dev/null)" ]; then - $IPS -o save list mwan3_connected_ipv6 | grep add | cut -d " " -f 3 + local address + + if [ -n "$($IPT6 -S mwan3_connected 2> /dev/null)" ]; then + $IPS -o save list mwan3_connected_v6 | grep add | cut -d " " -f 3 fi } @@ -1214,7 +1187,7 @@ mwan3_flush_conntrack() if [ "$action" = "$flush_conntrack" ]; then echo f > ${CONNTRACK_FILE} - LOG info "Connection tracking flushed for interface '$interface' on action '$action'" + $LOG info "Connection tracking flushed for interface '$interface' on action '$action'" fi } @@ -1225,6 +1198,10 @@ mwan3_flush_conntrack() mwan3_track_clean() { - rm -rf "${MWAN3_STATUS_DIR:?}/${1}" &> /dev/null - rmdir --ignore-fail-on-non-empty "$MWAN3_STATUS_DIR" + rm -rf "$MWAN3_STATUS_DIR/${1}" &> /dev/null + [ -d "$MWAN3_STATUS_DIR" ] && { + if [ -z "$(ls -A "$MWAN3_STATUS_DIR")" ]; then + rm -rf "$MWAN3_STATUS_DIR" + fi + } } diff --git a/mwan3/files/usr/libexec/rpcd/mwan3 b/mwan3/files/usr/libexec/rpcd/mwan3 old mode 100644 new mode 100755 index 8b336a450..33e3e0284 --- a/mwan3/files/usr/libexec/rpcd/mwan3 +++ b/mwan3/files/usr/libexec/rpcd/mwan3 @@ -5,6 +5,12 @@ . /usr/share/libubox/jshn.sh . /lib/mwan3/common.sh +MWAN3TRACK_STATUS_DIR="/var/run/mwan3track" + +IPS="ipset" +IPT4="iptables -t mangle -w" +IPT6="ip6tables -t mangle -w" + report_connected_v4() { local address @@ -16,7 +22,6 @@ report_connected_v4() { } report_connected_v6() { - [ $NO_IPV6 -ne 0 ] && return local address if [ -n "$($IPT6 -S mwan3_connected 2> /dev/null)" ]; then @@ -55,7 +60,6 @@ report_policies_v4() { } report_policies_v6() { - [ $NO_IPV6 -ne 0 ] && return local policy for policy in $($IPT6 -S | awk '{print $2}' | grep mwan3_policy_ | sort -u); do @@ -65,26 +69,6 @@ report_policies_v6() { done } -get_age() { - local time_p time_u - iface="$1" - time_p="$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/TIME")" - [ -z "${time_p}" ] || { - time_n="$(get_uptime)" - echo $((time_n-time_p)) - } -} - -get_offline_time() { - local time_n time_d iface - iface="$1" - time_d="$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/OFFLINE")" - [ -z "${time_d}" ] || [ "${time_d}" = "0" ] || { - time_n="$(get_uptime)" - echo $((time_n-time_d)) - } -} - get_mwan3_status() { local iface="${1}" local iface_select="${2}" @@ -92,60 +76,74 @@ get_mwan3_status() { local age=0 local online=0 local offline=0 - local enabled time_p time_n time_u time_d status track_status up uptime + local up="0" + local enabled pid device time_p time_n time_u time_d status - if [ "${iface}" != "${iface_select}" ] && [ "${iface_select}" != "" ]; then - return - fi + network_get_device device $1 - track_status="$(mwan3_get_mwan3track_status "$1")" - [ "$track_status" = "active" ] && running="1" - age=$(get_age "$iface") - online=$(get_online_time "$iface") - offline=$(get_offline_time "$iface") + if [ "${iface}" = "${iface_select}" ] || [ "${iface_select}" = "" ]; then + pid="$(pgrep -f "mwan3track $iface $device")" + if [ "${pid}" != "" ]; then + running="1" + fi - config_get enabled "$iface" enabled 0 + time_p="$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/TIME")" + [ -z "${time_p}" ] || { + time_n="$(get_uptime)" + let age=time_n-time_p + } - if [ -d "${MWAN3_STATUS_DIR}" ]; then + time_u="$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/ONLINE")" + [ -z "${time_u}" ] || [ "${time_u}" = "0" ] || { + time_n="$(get_uptime)" + let online=time_n-time_u + } + + time_d="$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/OFFLINE")" + [ -z "${time_d}" ] || [ "${time_d}" = "0" ] || { + time_n="$(get_uptime)" + let offline=time_n-time_d + } + + local uptime="0" + + config_get enabled "$iface" enabled 0 network_get_uptime uptime "$iface" network_is_up "$iface" && up="1" + if [ -f "$MWAN3TRACK_STATUS_DIR/${iface}/STATUS" ]; then status="$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/STATUS")" else - status="notracking" + status="unknown" fi - else - uptime=0 - up=0 - status="unknown" - fi - json_add_object "${iface}" - json_add_int age "$age" - json_add_int online "${online}" - json_add_int offline "${offline}" - json_add_int uptime "${uptime}" - json_add_int "score" "$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/SCORE")" - json_add_int "lost" "$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/LOST")" - json_add_int "turn" "$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/TURN")" - json_add_string "status" "${status}" - json_add_boolean "enabled" "${enabled}" - json_add_boolean "running" "${running}" - json_add_boolean "up" "${up}" - json_add_array "track_ip" - for file in $MWAN3TRACK_STATUS_DIR/${iface}/TRACK_*; do - [ -z "${file#*/TRACK_OUTPUT}" ] && continue - [ -z "${file#*/TRACK_\*}" ] && continue - track="${file#*/TRACK_}" - json_add_object - json_add_string ip "${track}" - json_add_string status "$(cat "${file}")" - json_add_int latency "$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/LATENCY_${track}")" - json_add_int packetloss "$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/LOSS_${track}")" + json_add_object "${iface}" + json_add_int age "$age" + json_add_int online "${online}" + json_add_int offline "${offline}" + json_add_int uptime "${uptime}" + json_add_int "score" "$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/SCORE")" + json_add_int "lost" "$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/LOST")" + json_add_int "turn" "$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/TURN")" + json_add_string "status" "${status}" + json_add_boolean "enabled" "${enabled}" + json_add_boolean "running" "${running}" + json_add_boolean "up" "${up}" + json_add_array "track_ip" + for file in $MWAN3TRACK_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_add_int latency "$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/LATENCY_${track}")" + json_add_int packetloss "$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/LOSS_${track}")" + json_close_object + fi + done + json_close_array json_close_object - done - json_close_array - json_close_object + fi } main () { diff --git a/mwan3/files/usr/sbin/mwan3 b/mwan3/files/usr/sbin/mwan3 old mode 100644 new mode 100755 index ea3d4c6a7..a854dfda2 --- a/mwan3/files/usr/sbin/mwan3 +++ b/mwan3/files/usr/sbin/mwan3 @@ -5,62 +5,75 @@ . /lib/functions/network.sh . /lib/mwan3/mwan3.sh -command_help() { - local cmd="$1" - local help="$2" - - echo "$(printf "%-25s%s" "${cmd}" "${help}")" -} - help() { cat < Load rules and routes for specific interface + ifdown Unload rules and routes for specific interface + interfaces Show interfaces status + policies Show currently active policy + connected Show directly connected networks + rules Show active rules + status Show all status + EOF - command_help "start" "Load iptables rules, ip rules and ip routes" - command_help "stop" "Unload iptables rules, ip rules and ip routes" - command_help "restart" "Reload iptables rules, ip rules and ip routes" - command_help "ifup " "Load rules and routes for specific interface" - command_help "ifdown " "Unload rules and routes for specific interface" - command_help "interfaces" "Show interfaces status" - command_help "policies" "Show currently active policy" - command_help "connected" "Show directly connected networks" - command_help "rules" "Show active rules" - command_help "status" "Show all status" - command_help "internal " "Show internal configuration " - command_help "use " "Run a command bound to and avoid mwan3 rules" } -ifdown() { +ifdown() +{ if [ -z "$1" ]; then - echo "Error: Expecting interface. Usage: mwan3 ifdown " - exit 0 + echo "Error: Expecting interface. Usage: mwan3 ifdown " && exit 0 fi if [ -n "$2" ]; then - echo "Error: Too many arguments. Usage: mwan3 ifdown " - exit 0 + echo "Error: Too many arguments. Usage: mwan3 ifdown " && exit 0 fi - mwan3_interface_hotplug_shutdown "$1" 1 + ACTION=ifdown INTERFACE=$1 /sbin/hotplug-call iface + + kill $(pgrep -f "mwan3track $1 $2") &> /dev/null + mwan3_track_clean $1 } -ifup() { - . /etc/init.d/mwan3 +ifup() +{ + local device enabled up l3_device status + + 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 + } if [ -z "$1" ]; then - echo "Expecting interface. Usage: mwan3 ifup " - exit 0 + echo "Expecting interface. Usage: mwan3 ifup " && exit 0 fi if [ -n "$2" ]; then - echo "Too many arguments. Usage: mwan3 ifup " - exit 0 + echo "Too many arguments. Usage: mwan3 ifup " && exit 0 fi - mwan3_ifup "$1" "cmd" + status=$(ubus -S call network.interface.$1 status) + [ -n "$status" ] && { + json_load "$status" + json_get_vars up l3_device + } + + config_get enabled "$1" enabled 0 + + if [ "$up" = "1" ] \ + && [ -n "$l3_device" ] \ + && [ "$enabled" = "1" ]; then + ACTION=ifup INTERFACE=$1 DEVICE=$l3_device /sbin/hotplug-call iface + fi } interfaces() @@ -69,40 +82,37 @@ interfaces() echo "Interface status:" config_foreach mwan3_report_iface_status interface - echo + echo -e } policies() { echo "Current ipv4 policies:" mwan3_report_policies_v4 - echo - [ $NO_IPV6 -ne 0 ] && return + echo -e echo "Current ipv6 policies:" mwan3_report_policies_v6 - echo + echo -e } connected() { echo "Directly connected ipv4 networks:" mwan3_report_connected_v4 - echo - [ $NO_IPV6 -ne 0 ] && return + echo -e echo "Directly connected ipv6 networks:" mwan3_report_connected_v6 - echo + echo -e } rules() { echo "Active ipv4 user rules:" mwan3_report_rules_v4 - echo - [ $NO_IPV6 -ne 0 ] && return + echo -e echo "Active ipv6 user rules:" mwan3_report_rules_v6 - echo + echo -e } status() @@ -113,136 +123,86 @@ status() rules } -internal() +start() { - local family="$1" - local dash="-------------------------------------------------" + local enabled - if [ -f "/etc/openwrt_release" ]; then - . /etc/openwrt_release - fi + uci_toggle_state mwan3 globals enabled "1" - local ipt ip output + config_load mwan3 + config_foreach ifup interface +} - if [ "$family" = "ipv6" ]; then - ipt="$IPT6" - ip="$IP6" - else - ipt="$IPT4" - ip="$IP4" - fi +stop() +{ + local ipset route rule table IP IPT pid - echo "Software-Version" - echo "$dash" + mwan3_lock "command" "mwan3" - if [ "$DISTRIB_RELEASE" != "" ]; then - echo "OpenWrt - $DISTRIB_RELEASE" - else - echo "OpenWrt - unknown" - fi - - echo "" - echo "Output of \"$ip a show\"" - echo "$dash" - output="$($ip a show)" - if [ "$output" != "" ]; then - echo "$output" - else - echo "No data found" - fi - - echo "" - echo "Output of \"$ip route show\"" - echo "$dash" - output="$($ip route show)" - if [ "$output" != "" ]; then - echo "$output" - else - echo "No data found" - fi - - echo "" - echo "Output of \"$ip rule show\"" - echo "$dash" - output="$($ip rule show)" - if [ "$output" != "" ]; then - echo "$output" - else - echo "No data found" - fi - - echo "" - echo "Output of \"$ip route list table 1-250\"" - echo "$dash" - local dump=0 - for i in $(seq 1 250); do - output=$($ip route list table $i 2>/dev/null) - if [ "$output" != "" ];then - dump=1 - echo "Routing table $i:" - echo "$output" - echo "" - fi + for pid in $(pgrep -f "mwan3rtmon"); do + kill -TERM "$pid" > /dev/null 2>&1 + sleep 1 + kill -KILL "$pid" > /dev/null 2>&1 done - if [ "$dump" = "0" ]; then - echo "No data found" - echo "" - fi - echo "Output of \"$ipt -L -v -n\"" - echo "$dash" - output="$($ipt -L -v -n)" - if [ "$output" != "" ]; then - echo "$output" - else - echo "No data found" - fi -} + for pid in $(pgrep -f "mwan3track"); do + kill -TERM "$pid" > /dev/null 2>&1 + sleep 1 + kill -KILL "$pid" > /dev/null 2>&1 + done -start() { - /etc/init.d/mwan3 enable - /etc/init.d/mwan3 start -} + config_load mwan3 + config_foreach mwan3_track_clean interface -stop() { - /etc/init.d/mwan3 disable - /etc/init.d/mwan3 stop + for IP in "$IP4" "$IP6"; do + + for route in $(seq 1 $MWAN3_INTERFACE_MAX); do + $IP route flush table $route &> /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 + done + + for IPT in "$IPT4" "$IPT6"; do + + $IPT -D PREROUTING -j mwan3_hook &> /dev/null + $IPT -D OUTPUT -j mwan3_hook &> /dev/null + + for table in $($IPT -S | awk '{print $2}' | grep mwan3 | sort -u); do + $IPT -F $table &> /dev/null + done + + for table in $($IPT -S | awk '{print $2}' | grep mwan3 | sort -u); do + $IPT -X $table &> /dev/null + done + 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 + + mwan3_unlock "command" "mwan3" + + mwan3_lock_clean + rm -rf $MWAN3_STATUS_DIR $MWAN3TRACK_STATUS_DIR + + uci_toggle_state mwan3 globals enabled "0" } restart() { - /etc/init.d/mwan3 enable - /etc/init.d/mwan3 stop - /etc/init.d/mwan3 start -} - -use() { - # 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 - - interface=$1 ; shift - [ -z "$*" ] && echo "no command specified for mwan3 use" && 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 $* - + stop + start } case "$1" in - ifup|ifdown|interfaces|policies|connected|rules|status|start|stop|restart|use|internal) + ifup|ifdown|interfaces|policies|connected|rules|status|start|stop|restart) mwan3_init - # shellcheck disable=SC2048 $* ;; *) diff --git a/mwan3/files/usr/sbin/mwan3rtmon b/mwan3/files/usr/sbin/mwan3rtmon old mode 100644 new mode 100755 index d8ccffeb0..9165de554 --- a/mwan3/files/usr/sbin/mwan3rtmon +++ b/mwan3/files/usr/sbin/mwan3rtmon @@ -1,172 +1,38 @@ #!/bin/sh . /lib/functions.sh -. /lib/functions/network.sh . /lib/mwan3/mwan3.sh -trap_with_arg() -{ - func="$1" ; shift - pid="$1" ; shift - for sig ; do - # shellcheck disable=SC2064 - trap "$func $sig $pid" "$sig" +LOG="logger -t $(basename "$0")[$$] -p" + +clean_up() { + $LOG notice "Stopping mwan3rtmon..." + exit 0 +} + +rtchange() { + $LOG info "Detect rtchange event." +} + +main() { + local rtmon_interval + trap clean_up TERM + trap rtchange USR1 + + config_load mwan3 + config_get rtmon_interval globals rtmon_interval '5' + + sleep 3 + while true; do + mwan3_lock "service" "mwan3rtmon" + mwan3_rtmon_ipv4 || mwan3_rtmon_ipv6 + ret=$? + mwan3_unlock "service" "mwan3rtmon" + [ "$ret" = "0" ] || break + [ "$rtmon_interval" = "0" ] && break + sleep "$rtmon_interval" & + wait 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 error - 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 - error=$($IP route add table $tid $route_line 2>&1) || - LOG warn "failed to add $route_line to table $tid - error: $error" - } - - 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() -{ - local action route_line family tbl device line tid - - route_line=${1##"Deleted "} - route_family=$2 - - if [ "$route_line" = "$1" ]; then - action="replace" - $IPS -! add mwan3_connected_${route_family} ${route_line%% *} - else - action="del" - mwan3_set_connected_${route_family} - fi - - if [ -z "${route_line##*linkdown*}" ]; then - LOG debug "attempting to add link on down interface - $route_line" - fi - - if [ "$route_family" = "ipv4" ]; then - IP="$IP4" - elif [ "$route_family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then - IP="$IP6" - else - LOG warn "route update called with invalid family - $route_family" - return - fi - route_line=$(echo "$route_line" | sed -ne "$MWAN3_ROUTE_LINE_EXP") - - handle_route() { - local error - local iface=$1 - tbl=$($IP route list table $tid 2>/dev/null)$'\n' - - if [ -n "$iface" ] && [ "$(mwan3_get_mwan3track_status $iface)" != "active" ]; then - LOG debug "interface $iface is disabled - 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'" - error=$($IP route "$action" table $tid $route_line 2>&1)|| - LOG warn "failed: '$IP route $action table $tid $route_line' - error: $error" - } - handle_route_cb(){ - local iface=$1 - let tid++ - config_get family "$iface" family ipv4 - [ "$family" != "$route_family" ] && return - handle_route "$iface" - } - - mwan3_update_dev_to_table - mwan3_route_line_dev "tid" "$route_line" "$route_family" - - if [ -n "$tid" ]; then - handle_route - elif [ -n "${route_line##default*}" ] && [ -n "${route_line##fe80::/64*}" ]; then - config_foreach handle_route_cb interface - fi -} - -main() -{ - local IP family - - mwan3_init - - family=$1 - [ -z $family ] && family=ipv4 - 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 - sh -c "echo \$\$; exec $IP monitor route" | { - read -r monitor_pid - trap_with_arg func_trap "$monitor_pid" SIGINT SIGTERM SIGKILL - KILL -SIGSTOP $$ - while IFS='' read -r line; do - [ -z "${line##*table*}" ] && continue - LOG debug "handling route update $family '$line'" - mwan3_rtmon_route_handle "$line" "$family" - done - } & - child=$! - trap_with_arg func_trap "$child" SIGINT SIGTERM SIGKILL - mwan3_set_connected_${family} - mwan3_add_all_routes ${family} - kill -SIGCONT $child - wait $child -} main "$@" diff --git a/mwan3/files/usr/sbin/mwan3track b/mwan3/files/usr/sbin/mwan3track old mode 100644 new mode 100755 index 162bdbb7d..e112475ce --- a/mwan3/files/usr/sbin/mwan3track +++ b/mwan3/files/usr/sbin/mwan3track @@ -1,348 +1,229 @@ #!/bin/sh . /lib/functions.sh -. /lib/functions/network.sh . /lib/mwan3/common.sh +LOG="logger -t $(basename "$0")[$$] -p" INTERFACE="" DEVICE="" +PING="/bin/ping" IFDOWN_EVENT=0 -IFUP_EVENT=0 - -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}\". Status was \"${STATUS}\"" - stop_subprocs + $LOG notice "Stopping mwan3track for interface \"${INTERFACE}\"" exit 0 } if_down() { - LOG info "Detect ifdown event on interface ${INTERFACE} (${DEVICE})" + $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 -} - -ping_test_host() { - if [ "$FAMILY" = "ipv6" ]; then - echo "::1" - else - echo "127.0.0.1" - fi -} - -get_ping_command() { - if [ -x "/usr/bin/ping" ] && /usr/bin/ping -${FAMILY#ipv} -c1 -q $(ping_test_host) &>/dev/null; then - # -4 option added in iputils c3e68ac6 so need to check if we can use it - # or if we must use ping and ping6 - echo "/usr/bin/ping -${FAMILY#ipv}" - elif [ "$FAMILY" = "ipv6" ] && [ -x "/usr/bin/ping6" ]; then - echo "/usr/bin/ping6" - elif [ "$FAMILY" = "ipv4" ] && [ -x "/usr/bin/ping" ]; then - echo "/usr/bin/ping" - elif [ -x "/bin/ping" ]; then - echo "/bin/ping -${FAMILY#ipv}" - else - return 1 - fi } validate_track_method() { case "$1" in ping) - PING=$(get_ping_command) - if [ $? -ne 0 ]; then - LOG warn "Missing ping. Please enable BUSYBOX_DEFAULT_PING and recompile busybox or install iputils-ping package." + which ping 1>/dev/null 2>&1 || { + $LOG warn "Missing ping. Please install iputils-ping package or enable ping util and recompile busybox." return 1 - fi + } ;; arping) - command -v arping 1>/dev/null 2>&1 || { - LOG warn "Missing arping. Please install iputils-arping package." + which arping 1>/dev/null 2>&1 || { + $LOG warn "Missing arping. Please install iputils-arping package." return 1 } ;; httping) - command -v httping 1>/dev/null 2>&1 || { - LOG warn "Missing httping. Please install httping package." + which httping 1>/dev/null 2>&1 || { + $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 || { - LOG warn "Missing nping. Please install nping package." + which nping 1>/dev/null 2>&1 || { + $LOG warn "Missing nping. Please install nping package." return 1 } ;; *) - LOG warn "Unsupported tracking method: $track_method" + $LOG warn "Unsupported tracking method: $track_method" return 2 ;; 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() { - local status="$(cat ${MWAN3TRACK_STATUS_DIR}/${INTERFACE}/STATUS)" - - 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 - - # Only execute disconnectd action if status was online or disconnecting - if [ "$status" = "online" ] || [ "$status" = "disconnecting" ]; then - LOG notice "Interface $INTERFACE ($DEVICE) is offline" - env -i ACTION="disconnected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface - else - LOG notice "Skip disconnected event for $INTERFACE ($DEVICE)" - fi -} - -connected() { - STATUS='online' - echo "online" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS - echo "0" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/OFFLINE - get_uptime > $MWAN3TRACK_STATUS_DIR/$INTERFACE/ONLINE - score=$((down+up)) - host_up_count=0 - lost=0 - turn=0 - loss=0 - LOG notice "Interface $INTERFACE ($DEVICE) is online" - env -i FIRSTCONNECT=$1 ACTION="connected" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface -} - -disconnecting() { - if [ "$STATUS" != "disconnecting" ] ; then - STATUS="disconnecting" - echo "disconnecting" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS - LOG notice "Interface $INTERFACE ($DEVICE) is disconnecting" - env -i ACTION="disconnecting" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface - fi -} - -connecting() { - if [ "$STATUS" != "connecting" ] ; then - STATUS="connecting" - echo "connecting" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS - LOG notice "Interface $INTERFACE ($DEVICE) is connecting" - env -i ACTION="connecting" INTERFACE="$INTERFACE" DEVICE="$DEVICE" /sbin/hotplug-call iface - fi -} - -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 - connected 1 - fi -} - -update_status() { - local track_ip=$1 - - echo "$2" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_${track_ip} - [ -z "$3" ] && return - echo "$3" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/LATENCY_${track_ip} - echo "$4" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/LOSS_${track_ip} -} - main() { local reliability count timeout interval failure_interval 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 - local max_ttl httping_ssl track_ips do_log + [ -z "$5" ] && echo "Error: should not be started manually" && exit 0 INTERFACE=$1 - STATUS="" - STARTED=0 - TRACK_OUTPUT=$MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_OUTPUT - - mwan3_init - - mkdir -p $MWAN3TRACK_STATUS_DIR/$INTERFACE - + DEVICE=$2 + STATUS=$3 + SRC_IP=$4 + mkdir -p /var/run/mwan3track/$1 trap clean_up TERM trap if_down USR1 - trap if_up USR2 - 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 || { + config_load mwan3 + config_get track_method $1 track_method ping + config_get_bool httping_ssl $1 httping_ssl 0 + validate_track_method $track_method $SRC_IP || { track_method=ping if validate_track_method $track_method; then - LOG warn "Using ping to track interface $INTERFACE avaliability" + $LOG warn "Using ping to track interface $INTERFACE avaliability" else - LOG err "No track method avaliable" + $LOG err "No track method avaliable" exit 1 fi } - config_get reliability $INTERFACE reliability 1 - config_get count $INTERFACE count 1 - config_get timeout $INTERFACE timeout 4 - config_get interval $INTERFACE interval 10 - config_get down $INTERFACE down 5 - config_get up $INTERFACE up 5 - config_get size $INTERFACE size 56 - config_get max_ttl $INTERFACE max_ttl 60 - config_get failure_interval $INTERFACE failure_interval $interval - config_get_bool keep_failure_interval $INTERFACE keep_failure_interval 0 - config_get recovery_interval $INTERFACE recovery_interval $interval - config_get_bool check_quality $INTERFACE check_quality 0 - config_get failure_latency $INTERFACE failure_latency 1000 - 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 + 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 max_ttl $1 max_ttl 60 + config_get failure_interval $1 failure_interval $interval + config_get_bool keep_failure_interval $1 keep_failure_interval 0 + config_get recovery_interval $1 recovery_interval $interval + config_get_bool check_quality $1 check_quality 0 + config_get failure_latency $1 failure_latency 1000 + config_get recovery_latency $1 recovery_latency 500 + config_get failure_loss $1 failure_loss 40 + config_get recovery_loss $1 recovery_loss 10 - local score=$((down+up)) + local score=$(($down+$up)) + local track_ips=$(echo $* | cut -d ' ' -f 5-99) local host_up_count=0 local lost=0 + local sleep_time=0 local turn=0 + local result + local ping_protocol=4 + local ping_result + local ping_result_raw + local ping_status + local loss=0 + local latency=0 - firstconnect + if [ "$STATUS" = "offline" ]; then + echo "offline" > /var/run/mwan3track/$1/STATUS + echo "0" > /var/run/mwan3track/$1/ONLINE + echo "$(get_uptime)" > /var/run/mwan3track/$1/OFFLINE + score=0 + else + echo "online" > /var/run/mwan3track/$1/STATUS + echo "0" > /var/run/mwan3track/$1/OFFLINE + echo "$(get_uptime)" > /var/run/mwan3track/$1/ONLINE + env -i ACTION="connected" INTERFACE="$1" DEVICE="$2" /sbin/hotplug-call iface + fi 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 echo $track_ip | grep -q ':'; then + ADDR=$(ip -6 addr ls dev "$DEVICE" | sed -ne '/\/128/d' -e 's/ *inet6 \([^ \/]*\).* scope global.*/\1/p' | head -n1) + [ -z "$ADDR" ] && ADDR=$(ip -6 addr ls dev "$DEVICE" | sed -ne 's/ *inet6 \([^ \/]*\).* scope global.*/\1/p') + ping_protocol=6 + fi if [ $check_quality -eq 0 ]; then - WRAP $PING -n -c $count -W $timeout -s $size -t $max_ttl -q $track_ip &> /dev/null & - TRACK_PID=$! - wait $TRACK_PID + $PING -$ping_protocol -I ${ADDR:-$DEVICE} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip &> /dev/null result=$? else - WRAP $PING -n -c $count -W $timeout -s $size -t $max_ttl -q $track_ip 2>/dev/null > $TRACK_OUTPUT & - TRACK_PID=$! - wait $TRACK_PID + ping_result_raw="$($PING -$ping_protocol -I ${ADDR:-$DEVICE} -c $count -W $timeout -s $size -t $max_ttl -q $track_ip 2>/dev/null)" ping_status=$? - loss="$(sed $TRACK_OUTPUT -ne 's/.*\([0-9]\+\)% packet loss.*/\1/p')" + ping_result=$(echo "$ping_result_raw" | tail -n2) + loss="$(echo "$ping_result" | grep "packet loss" | cut -d "," -f3 | awk '{print $1}' | sed -e 's/%//')" if [ "$ping_status" -ne 0 ] || [ "$loss" -eq 100 ]; then latency=999999 loss=100 else - latency="$(sed $TRACK_OUTPUT -ne 's%\(rtt\|round-trip\).* = [^/]*/\([0-9]\+\).*%\2%p')" + latency="$(echo "$ping_result" | grep -E 'rtt|round-trip' | cut -d "=" -f2 | cut -d "/" -f2 | cut -d "." -f1)" fi fi ;; arping) - WRAP arping -I $DEVICE -c $count -w $timeout -q $track_ip &> /dev/null & - TRACK_PID=$! - wait $TRACK_PID + arping -I $DEVICE -c $count -w $timeout -q $track_ip &> /dev/null result=$? ;; httping) if [ "$httping_ssl" -eq 1 ]; then - WRAP httping -c $count -t $timeout -q "https://$track_ip" &> /dev/null & + httping -y $SRC_IP -c $count -t $timeout -q "https://$track_ip" &> /dev/null else - WRAP httping -c $count -t $timeout -q "http://$track_ip" &> /dev/null & + httping -y $SRC_IP -c $count -t $timeout -q "http://$track_ip" &> /dev/null fi - TRACK_PID=$! - wait $TRACK_PID result=$? ;; - nping-*) - WRAP nping -c $count $track_ip --${FAMILY#nping-} > $TRACK_OUTPUT & - TRACK_PID=$! - wait $TRACK_PID - result=$(grep $TRACK_OUTPUT Lost | awk '{print $12}') + 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}') ;; esac - do_log="" if [ $check_quality -eq 0 ]; then if [ $result -eq 0 ]; then let host_up_count++ - update_status "$track_ip" "up" - - [ $score -le $up ] && do_log="success" + echo "up" > /var/run/mwan3track/$1/TRACK_${track_ip} + if [ $score -le $up ]; then + $LOG info "Check ($track_method) success for target \"$track_ip\" on interface $1 ($2)" + fi else let lost++ - update_status "$track_ip" "down" - - [ $score -gt $up ] && do_log="failed" + echo "down" > /var/run/mwan3track/$1/TRACK_${track_ip} + if [ $score -gt $up ]; then + $LOG info "Check ($track_method) failed for target \"$track_ip\" on interface $1 ($2)" + fi fi - [ -n "$do_log" ] && LOG info "Check ($track_method) ${do_log} for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score" - else - if [ "$loss" -ge "$failure_loss" ] || [ "$latency" -ge "$failure_latency" ]; then + if [ "$loss" -ge "$failure_loss" -o "$latency" -ge "$failure_latency" ]; then let lost++ - update_status "$track_ip" "down" $latency $loss + echo "down" > /var/run/mwan3track/$1/TRACK_${track_ip} + echo "$latency" > /var/run/mwan3track/$1/LATENCY_${track_ip} + echo "$loss" > /var/run/mwan3track/$1/LOSS_${track_ip} - [ $score -gt $up ] && do_log="failed" - elif [ "$loss" -le "$recovery_loss" ] && [ "$latency" -le "$recovery_latency" ]; then + if [ $score -gt $up ]; then + $LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) failed for target \"$track_ip\" on interface $1 ($2)" + fi + elif [ "$loss" -le "$recovery_loss" -a "$latency" -le "$recovery_latency" ]; then let host_up_count++ - update_status "$track_ip" "up" $latency $loss + echo "up" > /var/run/mwan3track/$1/TRACK_${track_ip} + echo "$latency" > /var/run/mwan3track/$1/LATENCY_${track_ip} + echo "$loss" > /var/run/mwan3track/$1/LOSS_${track_ip} - [ $score -le $up ] && do_log="success" + if [ $score -le $up ]; then + $LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) success for target \"$track_ip\" on interface $1 ($2)" + fi else - echo "skipped" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_${track_ip} + echo "skipped" > /var/run/mwan3track/$1/TRACK_${track_ip} fi - [ -n "$do_log" ] && LOG info "Check (${track_method}: latency=${latency}ms loss=${loss}%) ${do_log} for target \"$track_ip\" on interface $INTERFACE ($DEVICE). Current score: $score" fi else - echo "skipped" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/TRACK_${track_ip} + echo "skipped" > /var/run/mwan3track/$1/TRACK_${track_ip} fi done @@ -351,62 +232,61 @@ main() { if [ $score -lt $up ]; then score=0 - [ ${keep_failure_interval} -eq 1 ] && sleep_time=$failure_interval - elif [ $score -eq $up ]; then - disconnecting - sleep_time=$failure_interval - disconnected - elif [ $score -gt $up ]; then - disconnecting + [ ${keep_failure_interval} -eq 1 ] && { + sleep_time=$failure_interval + } + else sleep_time=$failure_interval fi + + if [ $score -eq $up ]; then + echo "offline" > /var/run/mwan3track/$1/STATUS + env -i ACTION=ifdown INTERFACE=$1 DEVICE=$2 /sbin/hotplug-call iface + 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 $1 ($2)" fi let score++ lost=0 - if [ $score -lt $up ]; then - connecting + if [ $score -gt $up ]; then + echo "online" > /var/run/mwan3track/$1/STATUS + score=$(($down+$up)) + elif [ $score -le $up ]; then sleep_time=$recovery_interval - elif [ $score -eq $up ]; then - connecting - sleep_time=$recovery_interval - connected - elif [ $score -gt $up ]; then - echo "online" > $MWAN3TRACK_STATUS_DIR/$INTERFACE/STATUS - score=$((down+up)) + fi + + if [ $score -eq $up ]; then + $LOG notice "Interface $1 ($2) is online" + echo "online" > /var/run/mwan3track/$1/STATUS + env -i ACTION=ifup INTERFACE=$1 DEVICE=$2 /sbin/hotplug-call iface + exit 0 fi fi let turn++ - 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 + 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 + echo "$(get_uptime)" > /var/run/mwan3track/$1/TIME host_up_count=0 - if [ "${IFDOWN_EVENT}" -eq 0 ] && [ "${IFUP_EVENT}" -eq 0 ]; then - sleep "${sleep_time}" & - SLEEP_PID=$! - wait - unset SLEEP_PID - fi + sleep "${sleep_time}" & + wait if [ "${IFDOWN_EVENT}" -eq 1 ]; then - LOG debug "Register ifdown event on interface ${INTERFACE} (${DEVICE})" - disconnected - disabled + echo "offline" > /var/run/mwan3track/$1/STATUS + echo "$(get_uptime)" > /var/run/mwan3track/$1/OFFLINE + echo "0" > /var/run/mwan3track/$1/ONLINE + $LOG notice "Interface $1 ($2) is offline" + env -i ACTION="disconnected" INTERFACE="$1" DEVICE="$2" /sbin/hotplug-call iface + score=0 IFDOWN_EVENT=0 fi - if [ "${IFUP_EVENT}" -eq 1 ]; then - LOG debug "Register ifup event on interface ${INTERFACE} (${DEVICE})" - firstconnect - IFUP_EVENT=0 - fi done } diff --git a/mwan3/src/sockopt_wrap.c b/mwan3/src/sockopt_wrap.c deleted file mode 100644 index 695e57502..000000000 --- a/mwan3/src/sockopt_wrap.c +++ /dev/null @@ -1,255 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2020 Aaron Goodman . All Rights Reserved. - */ - -/* - * sockopt_wrap.c provides a shared library that intercepts syscalls to various - * networking functions to bind the sockets a source IP address and network device - * and to set the firewall mark on otugoing packets. Parameters are set using the - * DEVICE, SRCIP, FWMARK environment variables. - * - * Additionally the FAMILY environment variable can be set to either 'ipv4' or - * 'ipv6' to cause sockets opened with ipv6 or ipv4 to fail, respectively. - * - * Each environment variable is optional, and if not set, the library will not - * enforce the particular parameter. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include - -static int (*next_socket)(int domain, int type, int protocol); -static int (*next_setsockopt)(int sockfd, int level, int optname, - const void *optval, socklen_t optlen); -static int (*next_bind)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); -static int (*next_close)(int fd); -static ssize_t (*next_send)(int sockfd, const void *buf, size_t len, int flags); -static ssize_t (*next_sendto)(int sockfd, const void *buf, size_t len, int flags, - const struct sockaddr *dest_addr, socklen_t addrlen); -static ssize_t (*next_sendmsg)(int sockfd, const struct msghdr *msg, int flags); -static int (*next_connect)(int sockfd, const struct sockaddr *addr, - socklen_t addrlen); -static int device=0; -static struct sockaddr_in source4 = {0}; -#ifdef CONFIG_IPV6 -static struct sockaddr_in6 source6 = {0}; -#endif -static struct sockaddr * source = 0; -static int sockaddr_size = 0; -static int is_bound [1024] = {0}; - -#define next_func(x)\ -void set_next_##x(){\ - if (next_##x) return;\ - next_##x = dlsym(RTLD_NEXT, #x);\ - dlerror_handle();\ - return;\ -} - -void dlerror_handle() -{ - char *msg; - if ((msg = dlerror()) != NULL) { - fprintf(stderr, "socket: dlopen failed : %s\n", msg); - fflush(stderr); - exit(EXIT_FAILURE); - } -} - -next_func(bind); -next_func(close); -next_func(setsockopt); -next_func(socket); -next_func(send); -next_func(sendto); -next_func(sendmsg); -next_func(connect); - -void dobind(int sockfd) -{ - if (source && sockfd < 1024 && !is_bound[sockfd]) { - set_next_bind(); - if (next_bind(sockfd, source, sockaddr_size)) { - perror("failed to bind to ip address"); - next_close(sockfd); - exit(EXIT_FAILURE); - } - is_bound[sockfd] = 1; - } -} - -int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) -{ - set_next_connect(); - dobind(sockfd); - return next_connect(sockfd, addr, addrlen); -} - -ssize_t send(int sockfd, const void *buf, size_t len, int flags) -{ - set_next_send(); - dobind(sockfd); - return next_send(sockfd, buf, len, flags); -} - -ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, - const struct sockaddr *dest_addr, socklen_t addrlen) -{ - set_next_sendto(); - dobind(sockfd); - return next_sendto(sockfd, buf, len, flags, dest_addr, addrlen); -} - -ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags) -{ - set_next_sendmsg(); - dobind(sockfd); - return next_sendmsg(sockfd, msg, flags); -} - -int bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen) -{ - set_next_bind(); - if (device && addr->sa_family == AF_PACKET) { - ((struct sockaddr_ll*)addr)->sll_ifindex=device; - } - else if (source && addr->sa_family == AF_INET) { - ((struct sockaddr_in*)addr)->sin_addr = source4.sin_addr; - } -#ifdef CONFIG_IPV6 - else if (source && addr->sa_family == AF_INET6) { - ((struct sockaddr_in6*)addr)->sin6_addr = source6.sin6_addr; - } -#endif - if (sockfd < 1024) - is_bound[sockfd] = 1; - return next_bind(sockfd, addr, addrlen); -} - -int close (int sockfd) -{ - set_next_close(); - if (sockfd < 1024) - is_bound[sockfd]=0; - return next_close(sockfd); -} - -int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) -{ - set_next_setsockopt(); - if (level == SOL_SOCKET && (optname == SO_MARK || optname == SO_BINDTODEVICE)) - return 0; - return next_setsockopt(sockfd, level, optname, optval, optlen); -} - -int socket(int domain, int type, int protocol) -{ - int handle; - - const char *socket_str = getenv("DEVICE"); - const char *srcip_str = getenv("SRCIP"); - const char *fwmark_str = getenv("FWMARK"); - const char *family_str = getenv("FAMILY"); - const int iface_len = socket_str ? strnlen(socket_str, IFNAMSIZ) : 0; - int has_family = family_str && *family_str != 0; - int has_srcip = srcip_str && *srcip_str != 0; - const int fwmark = fwmark_str ? (int)strtol(fwmark_str, NULL, 0) : 0; - - set_next_close(); - set_next_socket(); - set_next_send(); - set_next_setsockopt(); - set_next_sendmsg(); - set_next_sendto(); - set_next_connect(); - if(has_family) { -#ifdef CONFIG_IPV6 - if(domain == AF_INET && strncmp(family_str,"ipv6",4) == 0) - return -1; -#endif - if(domain == AF_INET6 && strncmp(family_str,"ipv4",4) == 0) - return -1; - } - - if (domain != AF_INET -#ifdef CONFIG_IPV6 - && domain != AF_INET6 -#endif - ) { - return next_socket(domain, type, protocol); - } - - - if (iface_len > 0) { - if (iface_len == IFNAMSIZ) { - fprintf(stderr,"socket: Too long iface name\n"); - fflush(stderr); - exit(EXIT_FAILURE); - } - } - - if (has_srcip) { - int s; - void * addr_buf; - if (domain == AF_INET) { - addr_buf = &source4.sin_addr; - sockaddr_size=sizeof source4; - memset(&source4, 0, sockaddr_size); - source4.sin_family = domain; - source = (struct sockaddr*)&source4; - } -#ifdef CONFIG_IPV6 - else { - addr_buf = &source6.sin6_addr; - sockaddr_size=sizeof source6; - memset(&source6, 0, sockaddr_size); - source6.sin6_family=domain; - source = (struct sockaddr*)&source6; - } -#endif - s = inet_pton(domain, srcip_str, addr_buf); - if (s == 0) { - fprintf(stderr, "socket: ip address invalid format for family %s\n", - domain == AF_INET ? "AF_INET" : domain == AF_INET6 ? - "AF_INET6" : "unknown"); - return -1; - } - if (s < 0) { - perror("inet_pton"); - exit(EXIT_FAILURE); - } - } - - handle = next_socket(domain, type, protocol); - if (handle == -1 ) { - return handle; - } - - if (iface_len > 0) { - device=if_nametoindex(socket_str); - if (next_setsockopt(handle, SOL_SOCKET, SO_BINDTODEVICE, - socket_str, iface_len + 1)) { - perror("socket: setting interface name failed with error"); - next_close(handle); - exit(EXIT_FAILURE); - } - } - - if (fwmark > 0) { - if (next_setsockopt(handle, SOL_SOCKET, SO_MARK, - &fwmark, sizeof fwmark)) { - perror("failed setting mark for socket"); - next_close(handle); - exit(EXIT_FAILURE); - } - } - return handle; -}