update 2024-05-11 00:21:41

This commit is contained in:
kenzok8 2024-05-11 00:21:41 +08:00
parent 5ff6b359e9
commit 35a624a298
15 changed files with 1280 additions and 2171 deletions

View File

@ -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 <cnsztl@immortalwrt.org>
PKG_LICENSE:=GPL-3.0

View File

@ -8,12 +8,10 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=mwan3
PKG_VERSION:=2.11.7
PKG_RELEASE:=1
PKG_MAINTAINER:=Florian Eckert <fe@dev.tdt.de>, \
Aaron Goodman <aaronjg@alumni.stanford.edu>
PKG_VERSION:=2.8.8
PKG_RELEASE:=2
PKG_MAINTAINER:=Florian Eckert <fe@dev.tdt.de>
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))

View File

@ -1,6 +1,7 @@
config globals 'globals'
option mmx_mask '0x3F00'
option rtmon_interval '5'
config member 'wan_m1_w3'
option interface 'wan'

View File

@ -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

View File

@ -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

View File

@ -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

113
mwan3/files/etc/init.d/mwan3 Normal file → Executable file
View File

@ -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() {

View File

@ -8,13 +8,9 @@
# There are three main environment variables that are passed to this script.
#
# $ACTION
# <ifup> Is called by netifd and mwan3track.
# <ifdown> Is called by netifd and mwan3track.
# <connected> Is only called by mwan3track if tracking was successful.
# <disconnected> 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
# <ifup> Is called by netifd and mwan3track
# <ifdown> Is called by netifd and mwan3track
# <connected> Is only called by mwan3track if tracking was successful
# <disconnected> 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")

View File

@ -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<<bitcnt)-1))
MWAN3_INTERFACE_MAX=$((mmdefault-3))
uci_toggle_state mwan3 globals iface_max "$MWAN3_INTERFACE_MAX"
LOG debug "Max interface count is ${MWAN3_INTERFACE_MAX}"
fi
# remove "linkdown", expiry and source based routing modifiers from route lines
config_get_bool source_routing globals source_routing 0
[ $source_routing -eq 1 ] && unset source_routing
MWAN3_ROUTE_LINE_EXP="s/offload//; s/linkdown //; s/expires [0-9]\+sec//; s/error [0-9]\+//; ${source_routing:+s/default\(.*\) from [^ ]*/default\1/;} p"
# mark mask constants
bitcnt=$(mwan3_count_one_bits MMX_MASK)
mmdefault=$(((1<<bitcnt)-1))
MM_BLACKHOLE=$((mmdefault-2))
MM_UNREACHABLE=$((mmdefault-1))
# MMX_DEFAULT should equal MMX_MASK
MMX_DEFAULT=$(mwan3_id2mask mmdefault MMX_MASK)
MMX_BLACKHOLE=$(mwan3_id2mask MM_BLACKHOLE MMX_MASK)
MMX_UNREACHABLE=$(mwan3_id2mask MM_UNREACHABLE MMX_MASK)
}
# maps the 1st parameter so it only uses the bits allowed by the bitmask (2nd parameter)
# which means spreading the bits of the 1st parameter to only use the bits that are set to 1 in the 2nd parameter
# 0 0 0 0 0 1 0 1 (0x05) 1st parameter
# 1 0 1 0 1 0 1 0 (0xAA) 2nd parameter
# 1 0 1 result
mwan3_id2mask()
{
local bit_msk bit_val result
bit_val=0
result=0
for bit_msk in $(seq 0 31); do
if [ $((($2>>bit_msk)&1)) = "1" ]; then
if [ $((($1>>bit_val)&1)) = "1" ]; then
result=$((result|(1<<bit_msk)))
fi
bit_val=$((bit_val+1))
fi
done
printf "0x%x" $result
}
# counts how many bits are set to 1
# n&(n-1) clears the lowest bit set to 1
mwan3_count_one_bits()
{
local count n
count=0
n=$(($1))
while [ "$n" -gt "0" ]; do
n=$((n&(n-1)))
count=$((count+1))
done
echo $count
}
get_uptime() {
local uptime=$(cat /proc/uptime)
echo "${uptime%%.*}"
}
get_online_time() {
local time_n time_u iface
iface="$1"
time_u="$(cat "$MWAN3TRACK_STATUS_DIR/${iface}/ONLINE" 2>/dev/null)"
[ -z "${time_u}" ] || [ "${time_u}" = "0" ] || {
time_n="$(get_uptime)"
echo $((time_n-time_u))
}
}

File diff suppressed because it is too large Load Diff

126
mwan3/files/usr/libexec/rpcd/mwan3 Normal file → Executable file
View File

@ -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 () {

270
mwan3/files/usr/sbin/mwan3 Normal file → Executable file
View File

@ -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 <<EOF
Syntax: mwan3 [command]
Available commands:
start Load iptables rules, ip rules and ip routes
stop Unload iptables rules, ip rules and ip routes
restart Reload iptables rules, ip rules and ip routes
ifup <iface> Load rules and routes for specific interface
ifdown <iface> Unload rules and routes for specific interface
interfaces Show interfaces status
policies Show currently active policy
connected Show directly connected networks
rules Show active rules
status Show all status
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 <iface>" "Load rules and routes for specific interface"
command_help "ifdown <iface>" "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 <ipv4|ipv6>" "Show internal configuration <default: ipv4>"
command_help "use <iface> <cmd>" "Run a command bound to <iface> and avoid mwan3 rules"
}
ifdown() {
ifdown()
{
if [ -z "$1" ]; then
echo "Error: Expecting interface. Usage: mwan3 ifdown <interface>"
exit 0
echo "Error: Expecting interface. Usage: mwan3 ifdown <interface>" && exit 0
fi
if [ -n "$2" ]; then
echo "Error: Too many arguments. Usage: mwan3 ifdown <interface>"
exit 0
echo "Error: Too many arguments. Usage: mwan3 ifdown <interface>" && exit 0
fi
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 <interface>"
exit 0
echo "Expecting interface. Usage: mwan3 ifup <interface>" && exit 0
fi
if [ -n "$2" ]; then
echo "Too many arguments. Usage: mwan3 ifup <interface>"
exit 0
echo "Too many arguments. Usage: mwan3 ifup <interface>" && 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
$*
;;
*)

192
mwan3/files/usr/sbin/mwan3rtmon Normal file → Executable file
View File

@ -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 "$@"

432
mwan3/files/usr/sbin/mwan3track Normal file → Executable file
View File

@ -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
}

View File

@ -1,255 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 Aaron Goodman <aaronjg@alumni.stanford.edu>. All Rights Reserved.
*/
/*
* sockopt_wrap.c provides a shared library that intercepts syscalls to various
* networking functions to bind the sockets a source IP address and network device
* and to set the firewall mark on otugoing packets. Parameters are set using the
* DEVICE, SRCIP, FWMARK environment variables.
*
* Additionally the FAMILY environment variable can be set to either 'ipv4' or
* 'ipv6' to cause sockets opened with ipv6 or ipv4 to fail, respectively.
*
* Each environment variable is optional, and if not set, the library will not
* enforce the particular parameter.
*/
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/ethernet.h>
#include <linux/if_packet.h>
#include <net/if.h>
static int (*next_socket)(int domain, int type, int protocol);
static int (*next_setsockopt)(int sockfd, int level, int optname,
const void *optval, socklen_t optlen);
static int (*next_bind)(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
static int (*next_close)(int fd);
static ssize_t (*next_send)(int sockfd, const void *buf, size_t len, int flags);
static ssize_t (*next_sendto)(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
static ssize_t (*next_sendmsg)(int sockfd, const struct msghdr *msg, int flags);
static int (*next_connect)(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
static int device=0;
static struct sockaddr_in source4 = {0};
#ifdef CONFIG_IPV6
static struct sockaddr_in6 source6 = {0};
#endif
static struct sockaddr * source = 0;
static int sockaddr_size = 0;
static int is_bound [1024] = {0};
#define next_func(x)\
void set_next_##x(){\
if (next_##x) return;\
next_##x = dlsym(RTLD_NEXT, #x);\
dlerror_handle();\
return;\
}
void dlerror_handle()
{
char *msg;
if ((msg = dlerror()) != NULL) {
fprintf(stderr, "socket: dlopen failed : %s\n", msg);
fflush(stderr);
exit(EXIT_FAILURE);
}
}
next_func(bind);
next_func(close);
next_func(setsockopt);
next_func(socket);
next_func(send);
next_func(sendto);
next_func(sendmsg);
next_func(connect);
void dobind(int sockfd)
{
if (source && sockfd < 1024 && !is_bound[sockfd]) {
set_next_bind();
if (next_bind(sockfd, source, sockaddr_size)) {
perror("failed to bind to ip address");
next_close(sockfd);
exit(EXIT_FAILURE);
}
is_bound[sockfd] = 1;
}
}
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
set_next_connect();
dobind(sockfd);
return next_connect(sockfd, addr, addrlen);
}
ssize_t send(int sockfd, const void *buf, size_t len, int flags)
{
set_next_send();
dobind(sockfd);
return next_send(sockfd, buf, len, flags);
}
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
set_next_sendto();
dobind(sockfd);
return next_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
}
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
{
set_next_sendmsg();
dobind(sockfd);
return next_sendmsg(sockfd, msg, flags);
}
int bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
set_next_bind();
if (device && addr->sa_family == AF_PACKET) {
((struct sockaddr_ll*)addr)->sll_ifindex=device;
}
else if (source && addr->sa_family == AF_INET) {
((struct sockaddr_in*)addr)->sin_addr = source4.sin_addr;
}
#ifdef CONFIG_IPV6
else if (source && addr->sa_family == AF_INET6) {
((struct sockaddr_in6*)addr)->sin6_addr = source6.sin6_addr;
}
#endif
if (sockfd < 1024)
is_bound[sockfd] = 1;
return next_bind(sockfd, addr, addrlen);
}
int close (int sockfd)
{
set_next_close();
if (sockfd < 1024)
is_bound[sockfd]=0;
return next_close(sockfd);
}
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen)
{
set_next_setsockopt();
if (level == SOL_SOCKET && (optname == SO_MARK || optname == SO_BINDTODEVICE))
return 0;
return next_setsockopt(sockfd, level, optname, optval, optlen);
}
int socket(int domain, int type, int protocol)
{
int handle;
const char *socket_str = getenv("DEVICE");
const char *srcip_str = getenv("SRCIP");
const char *fwmark_str = getenv("FWMARK");
const char *family_str = getenv("FAMILY");
const int iface_len = socket_str ? strnlen(socket_str, IFNAMSIZ) : 0;
int has_family = family_str && *family_str != 0;
int has_srcip = srcip_str && *srcip_str != 0;
const int fwmark = fwmark_str ? (int)strtol(fwmark_str, NULL, 0) : 0;
set_next_close();
set_next_socket();
set_next_send();
set_next_setsockopt();
set_next_sendmsg();
set_next_sendto();
set_next_connect();
if(has_family) {
#ifdef CONFIG_IPV6
if(domain == AF_INET && strncmp(family_str,"ipv6",4) == 0)
return -1;
#endif
if(domain == AF_INET6 && strncmp(family_str,"ipv4",4) == 0)
return -1;
}
if (domain != AF_INET
#ifdef CONFIG_IPV6
&& domain != AF_INET6
#endif
) {
return next_socket(domain, type, protocol);
}
if (iface_len > 0) {
if (iface_len == IFNAMSIZ) {
fprintf(stderr,"socket: Too long iface name\n");
fflush(stderr);
exit(EXIT_FAILURE);
}
}
if (has_srcip) {
int s;
void * addr_buf;
if (domain == AF_INET) {
addr_buf = &source4.sin_addr;
sockaddr_size=sizeof source4;
memset(&source4, 0, sockaddr_size);
source4.sin_family = domain;
source = (struct sockaddr*)&source4;
}
#ifdef CONFIG_IPV6
else {
addr_buf = &source6.sin6_addr;
sockaddr_size=sizeof source6;
memset(&source6, 0, sockaddr_size);
source6.sin6_family=domain;
source = (struct sockaddr*)&source6;
}
#endif
s = inet_pton(domain, srcip_str, addr_buf);
if (s == 0) {
fprintf(stderr, "socket: ip address invalid format for family %s\n",
domain == AF_INET ? "AF_INET" : domain == AF_INET6 ?
"AF_INET6" : "unknown");
return -1;
}
if (s < 0) {
perror("inet_pton");
exit(EXIT_FAILURE);
}
}
handle = next_socket(domain, type, protocol);
if (handle == -1 ) {
return handle;
}
if (iface_len > 0) {
device=if_nametoindex(socket_str);
if (next_setsockopt(handle, SOL_SOCKET, SO_BINDTODEVICE,
socket_str, iface_len + 1)) {
perror("socket: setting interface name failed with error");
next_close(handle);
exit(EXIT_FAILURE);
}
}
if (fwmark > 0) {
if (next_setsockopt(handle, SOL_SOCKET, SO_MARK,
&fwmark, sizeof fwmark)) {
perror("failed setting mark for socket");
next_close(handle);
exit(EXIT_FAILURE);
}
}
return handle;
}