#!/bin/sh
#
# Copyright (C) 2018-2025 Ycarus (Yannick Chabanois) <ycarus@zugaina.org> for OpenMPTCProuter
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
# This script test global or interface speed
#

FORCEVPS=false
FASTTEST=false
INTERFACE=""
for arg in "$@"; do
	case "$arg" in
		forcevps)
			FORCEVPS=true
			;;
		fasttest)
			FASTTEST=true
			;;
		*)
			# Keep the last non-flag argument as interface name.
			INTERFACE="$arg"
			;;
	esac
done

IPV6=false
if [ "$(basename $0)" = "omr-test-speedv6" ]; then
	IPV6=true
fi

[ -n "$INTERFACE" ] && [ ! -d "/sys/class/net/$INTERFACE" ] && {
	echo "You must use a real interface. You wan find them using 'ip a' for example (not $INTERFACE)"
	exit 1
}

_DEFAULT_HOSTLST="http://scaleway.testdebit.info/10G.iso http://appliwave.testdebit.info/10G/10G.iso http://speedtest.frankfurt.linode.com/garbage.php?ckSize=10000 http://speedtest.tokyo2.linode.com/garbage.php?ckSize=10000 http://speedtest.singapore.linode.com/garbage.php?ckSize=10000 http://speedtest.newark.linode.com/garbage.php?ckSize=10000 http://speedtest.atlanta.linode.com/garbage.php?ckSize=10000 http://speedtest.dallas.linode.com/garbage.php?ckSize=10000 http://speedtest.fremont.linode.com/garbage.php?ckSize=10000 http://par.download.datapacket.com/10000mb.bin http://nyc.download.datapacket.com/10000mb.bin http://ams.download.datapacket.com/10000mb.bin http://fra.download.datapacket.com/10000mb.bin http://lon.download.datapacket.com/10000mb.bin http://mad.download.datapacket.com/10000mb.bin http://prg.download.datapacket.com/10000mb.bin http://sto.download.datapacket.com/10000mb.bin http://vie.download.datapacket.com/10000mb.bin http://war.download.datapacket.com/10000mb.bin http://atl.download.datapacket.com/10000mb.bin http://chi.download.datapacket.com/10000mb.bin http://lax.download.datapacket.com/10000mb.bin http://mia.download.datapacket.com/10000mb.bin http://nyc.download.datapacket.com/10000mb.bin http://speedtest.milkywan.fr/files/10G.iso https://rbx.proof.ovh.net/files/10Gb.dat https://gra.proof.ovh.net/files/10Gb.dat https://sbg.proof.ovh.net/files/10Gb.dat https://bhs.proof.ovh.ca/files/10Gb.dat https://vin.proof.ovh.us/files/10Gb.dat https://hil.proof.ovh.us/files/10Gb.dat http://speedtest.tele2.net/10GB.zip https://la.speedtest.clouvider.net/10g.bin https://atl.speedtest.clouvider.net/10g.bin https://nyc.speedtest.clouvider.net/10g.bin https://lon.speedtest.clouvider.net/10g.bin https://man.speedtest.clouvider.net/10g.bin https://ams.speedtest.clouvider.net/10g.bin https://fra.speedtest.clouvider.net/10g.bin https://dal.speedtest.clouvider.net/10g.bin https://ash.speedtest.clouvider.net/10g.bin https://phx.speedtest.clouvider.net/10g.bin https://chi.speedtest.clouvider.net/10g.bin https://akl.download.datapacket.com/10000mb.bin https://syd.download.datapacket.com/10000mb.bin http://speedtest.sydney.linode.com/garbage.php?ckSize=10000"
_DEFAULT_HOSTLST6="http://scaleway.testdebit.info/10G.iso http://appliwave.testdebit.info/10G/10G.iso http://speedtest.frankfurt.linode.com/garbage.php?ckSize=10000 http://speedtest.tokyo2.linode.com/garbage.php?ckSize=10000 http://speedtest.singapore.linode.com/garbage.php?ckSize=10000 http://speedtest.newark.linode.com/garbage.php?ckSize=10000 http://speedtest.atlanta.linode.com/garbage.php?ckSize=10000 http://speedtest.dallas.linode.com/garbage.php?ckSize=10000 http://speedtest.fremont.linode.com/garbage.php?ckSize=10000 http://par.download.datapacket.com/10000mb.bin http://nyc.download.datapacket.com/10000mb.bin http://ams.download.datapacket.com/10000mb.bin http://fra.download.datapacket.com/10000mb.bin http://lon.download.datapacket.com/10000mb.bin http://mad.download.datapacket.com/10000mb.bin http://prg.download.datapacket.com/10000mb.bin http://sto.download.datapacket.com/10000mb.bin http://vie.download.datapacket.com/10000mb.bin http://war.download.datapacket.com/10000mb.bin http://atl.download.datapacket.com/10000mb.bin http://chi.download.datapacket.com/10000mb.bin http://lax.download.datapacket.com/10000mb.bin http://mia.download.datapacket.com/10000mb.bin http://nyc.download.datapacket.com/10000mb.bin http://speedtest.milkywan.fr/files/10G.iso https://rbx.proof.ovh.net/files/10Gb.dat https://gra.proof.ovh.net/files/10Gb.dat https://sbg.proof.ovh.net/files/10Gb.dat https://bhs.proof.ovh.ca/files/10Gb.dat https://vin.proof.ovh.us/files/10Gb.dat https://hil.proof.ovh.us/files/10Gb.dat http://speedtest.tele2.net/10GB.zip https://la.speedtest.clouvider.net/10g.bin https://atl.speedtest.clouvider.net/10g.bin https://nyc.speedtest.clouvider.net/10g.bin https://lon.speedtest.clouvider.net/10g.bin https://man.speedtest.clouvider.net/10g.bin https://ams.speedtest.clouvider.net/10g.bin https://fra.speedtest.clouvider.net/10g.bin https://dal.speedtest.clouvider.net/10g.bin https://ash.speedtest.clouvider.net/10g.bin https://phx.speedtest.clouvider.net/10g.bin https://chi.speedtest.clouvider.net/10g.bin https://akl.download.datapacket.com/10000mb.bin https://syd.download.datapacket.com/10000mb.bin http://speedtest.sydney.linode.com/garbage.php?ckSize=10000"

HOSTLST=$(uci -q get omr-speedtest.urls.download 2>/dev/null | tr '\n' ' ')
[ -z "$HOSTLST" ] && HOSTLST="$_DEFAULT_HOSTLST"
HOSTLST6=$(uci -q get omr-speedtest.urls.download6 2>/dev/null | tr '\n' ' ')
[ -z "$HOSTLST6" ] && HOSTLST6="$_DEFAULT_HOSTLST6"

select_server() {
	[ "$FASTTEST" = true ] || echo "Select best test server..."
	bestping="9999"
	HOST=""
	if [ "$IPV6" = true ]; then
		for pinghost in $HOSTLST6; do
			domain=$(echo $pinghost | awk -F/ '{print $3}')
			if [ -z "$INTERFACE" ] || [ "$FORCEVPS" = true ]; then
				ping=$(ping -6 -c1 -w2 $domain | cut -d "/" -s -f5 | cut -d "." -f1 | tr -d '\n')
			else
				ping=$(ping -6 -c1 -w2 -I $INTERFACE -B $domain | cut -d "/" -s -f5 | cut -d "." -f1 | tr -d '\n')
			fi
			[ "$FASTTEST" = true ] || echo "host: $domain - ping: $ping"
			if [ -n "$ping" ] && [ "$ping" -lt "$bestping" ]; then
				bestping=$ping
				HOST=$pinghost
			fi
		done
	else
		for pinghost in $HOSTLST; do
			domain=$(echo $pinghost | awk -F/ '{print $3}')
			if [ -z "$INTERFACE" ] || [ "$FORCEVPS" = true ]; then
				ping=$(ping -4 -c1 -w2 $domain | cut -d "/" -s -f5 | cut -d "." -f1 | tr -d '\n')
			else
				ping=$(ping -4 -c1 -w2 -I $INTERFACE -B $domain | cut -d "/" -s -f5 | cut -d "." -f1 | tr -d '\n')
			fi
			[ "$FASTTEST" = true ] || echo "host: $domain - ping: $ping"
			if [ -n "$ping" ] && [ "$ping" -lt "$bestping" ]; then
				bestping=$ping
				HOST=$pinghost
			fi
		done
	fi
}

get_speed_global() {
	HOST=$1
	if [ "$IPV6" = true ]; then
		curl -6 -o /dev/null $HOST || echo
	else
		curl -4 -o /dev/null $HOST || echo
	fi
}

get_speed_global_fast() {
	HOST=$1
	if [ "$IPV6" = true ]; then
		avg_speed=$(curl -6 --max-time 10 -o /dev/null -qfsS -w '%{speed_download}' $HOST 2>/dev/null)
	else
		avg_speed=$(curl -4 --max-time 10 -o /dev/null -qfsS -w '%{speed_download}' $HOST 2>/dev/null)
	fi
	echo "$avg_speed"
}

bypass_host_enable() {
	INTERFACE=$1
	HOST=$2
	SQM_STOPPED=false
	if tc qdisc show dev "$INTERFACE" | grep -q ingress; then
		/etc/init.d/sqm stop "$INTERFACE"
		SQM_STOPPED=true
	fi
	domain=$(echo $HOST | awk -F/ '{print $3}')
	if [ "$IPV6" = true ]; then
		hostip=$(dig +nocmd +noall +answer AAAA $domain | grep -v CNAME | awk '{print $5}' | tr '\n' ' ')
		if [ -n "$(ipset list 2>/dev/null | grep ss_rules6)" ]; then
			for ip in $hostip; do
				ipset add ss_rules6_dst_bypass_all $ip
			done
		fi
		if [ -n "$(nft list set inet fw4 omr_dst_bypass_all_6 2>/dev/null)" ]; then
			for ip in $hostip; do
				nft add element inet fw4 omr_dst_bypass_all_6 { $ip } >/dev/null 2>&1
			done
		fi
	else
		hostip=$(dig +nocmd +noall +answer A $domain | grep -v CNAME | awk '{print $5}' | tr '\n' ' ')
		if [ -n "$(ipset list 2>/dev/null | grep ss_rules)" ]; then
			for ip in $hostip; do
				ipset add ss_rules_dst_bypass_all $ip
			done
		fi
		if [ -n "$(nft list set inet fw4 omr_dst_bypass_all_4 2>/dev/null)" ]; then
			for ip in $hostip; do
				nft add element inet fw4 omr_dst_bypass_all_4 { $ip } >/dev/null 2>&1
			done
		fi
	fi
}


bypass_host_disable() {
	INTERFACE=$1
	HOST=$2
	domain=$(echo $HOST | awk -F/ '{print $3}')
	if [ "$IPV6" = true ]; then
		hostip=$(dig +nocmd +noall +answer AAAA $domain | grep -v CNAME | awk '{print $5}' | tr '\n' ' ')
		if [ -n "$(ipset list 2>/dev/null | grep ss_rules6)" ]; then
			for ip in $hostip; do
				ipset del ss_rules6_dst_bypass_all $ip
			done
		fi
		if [ -n "$(nft list set inet fw4 omr_dst_bypass_all_6 2>/dev/null)" ]; then
			for ip in $hostip; do
				nft delete element inet fw4 omr_dst_bypass_all_6 { $ip } >/dev/null 2>&1
			done
		fi
	else
		hostip=$(dig +nocmd +noall +answer A $domain | grep -v CNAME | awk '{print $5}' | tr '\n' ' ')
		if [ -n "$(ipset list 2>/dev/null | grep ss_rules)" ]; then
			for ip in $hostip; do
				ipset del ss_rules_dst_bypass_all $ip
			done
		fi
		if [ -n "$(nft list set inet fw4 omr_dst_bypass_all_4 2>/dev/null)" ]; then
			for ip in $hostip; do
				nft delete element inet fw4 omr_dst_bypass_all_4 { $ip } >/dev/null 2>&1
			done
		fi
	fi
	[ "$SQM_STOPPED" = true ] && /etc/init.d/sqm start "$INTERFACE"
}

get_speed_interface() {
	INTERFACE=$1
	HOST=$2
	bypass_host_enable $INTERFACE $HOST
	if [ "$IPV6" = true ]; then
		curl -6 -o /dev/null --interface $INTERFACE $HOST || echo
	else
		curl -4 -o /dev/null --interface $INTERFACE $HOST || echo
	fi
	bypass_host_disable $INTERFACE $HOST
}

get_speed_interface_fast() {
	INTERFACE=$1
	HOST=$2
	bypass_host_enable $INTERFACE $HOST
	if [ "$IPV6" = true ]; then
		avg_speed=$(curl -6 --max-time 10 -o /dev/null -qfsS -w '%{speed_download}' --interface $INTERFACE $HOST 2>/dev/null)
	else
		avg_speed=$(curl -4 --max-time 10 -o /dev/null -qfsS -w '%{speed_download}' --interface $INTERFACE $HOST 2>/dev/null)
	fi
	echo "$avg_speed"
	bypass_host_disable $INTERFACE $HOST
}

response="000"
try=0
while [ "$response" = "000" ] && [ "$try" -le 3 ]; do
	select_server
	if [ "$IPV6" = true ]; then
		response=$(curl -6 --write-out '%{http_code}' --silent --head --insecure -IL  --connect-timeout 5 --output /dev/null $HOST)
		[ -n "$HOST" ] && HOSTLST6=$(echo $HOSTLST6 | tr ' ' '\n' | grep -v "$HOST" | xargs)
	else
		response=$(curl -4 --write-out '%{http_code}' --silent --head --insecure -IL  --connect-timeout 5 --output /dev/null $HOST)
		[ -n "$HOST" ] && HOSTLST=$(echo $HOSTLST | tr ' ' '\n' | grep -v "$HOST" | xargs)
	fi
	try=$((try+1))
	if [ "$response" = "000" ] && [ "$FASTTEST" != true ]; then
		echo "No answer from $HOST, retry..."
	fi
done

[ -z "$HOST" ] && HOST="http://speedtest.milkywan.fr/files/10G.iso"

[ "$FASTTEST" = true ] || echo "Best server is $HOST, running test:"
trap : HUP INT TERM
if [ -z "$INTERFACE" ]; then
	if [ "$FASTTEST" = true ]; then 
		get_speed_global_fast $HOST
	else
		get_speed_global $HOST
	fi
else
	if [ "$FASTTEST" = true ]; then 
		get_speed_interface_fast $INTERFACE $HOST
	else
		get_speed_interface $INTERFACE $HOST
	fi
fi
