#!/bin/sh
#
# Copyright (C) 2026 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 manages mqvpn paths when an interface goes up or down

. "${OMR_LIB_DIR:-/usr/share/omr/lib}/omr-state.sh"

if [ "$(uci -q get mqvpn.settings.enable)" != "1" ]; then
	exit 0
fi

if [ -z "$OMR_TRACKER_DEVICE" ] || [ -z "$OMR_TRACKER_INTERFACE" ]; then
	exit 0
fi

# Don't manage VPN interfaces
if [ "$(uci -q get openmptcprouter.$OMR_TRACKER_INTERFACE.vpn)" = "1" ]; then
	exit 0
fi

if [ "$(pgrep -f mqvpn)" = "" ]; then
	exit 0
fi

mqvpn_path_exists() {
	mqvpn-path list 2>/dev/null | grep -q "\"$OMR_TRACKER_DEVICE\""
}
if [ "$(uci -q get mqvpn.interface.route_via_server)" = "1" ]; then
	if ip route show 0.0.0.0/1 dev tun0 2>/dev/null | grep -q .; then
		ip route del 0.0.0.0/1 dev tun0 2>/dev/null
	fi
fi
if [ "$OMR_TRACKER_STATUS" = "ERROR" ]; then
	[ "$OMR_TRACKER_PREV_STATUS" = "$OMR_TRACKER_STATUS" ] && exit 0
	# Monitor only: the path stays in use
	[ "$OMR_TRACKER_MONITOR_ONLY" = "1" ] && exit 0
	if mqvpn_path_exists; then
		_log "mqvpn: remove path $OMR_TRACKER_DEVICE ($OMR_TRACKER_INTERFACE)"
		mqvpn-path remove "$OMR_TRACKER_DEVICE" >/dev/null
		# Force 006-mqvpn-weight and 007-mqvpn-dscp to re-apply the weight
		# and the DSCP mask next time this path comes back up, since mqvpn
		# drops any per-path state on remove. Their caches are runtime
		# state (/var/state), nothing to commit.
		omr_state_del openmptcprouter "$OMR_TRACKER_INTERFACE" mqvpn_weight
		omr_state_del openmptcprouter "$OMR_TRACKER_INTERFACE" mqvpn_dscp_mask
	fi
	exit 0
fi

# Only act on status transitions to avoid spamming the API on every poll
[ "$OMR_TRACKER_PREV_STATUS" = "$OMR_TRACKER_STATUS" ] && exit 0

multipath_config=$(uci -q get "openmptcprouter.$OMR_TRACKER_INTERFACE.multipath")
[ -z "$multipath_config" ] && multipath_config=$(uci -q get "network.$OMR_TRACKER_INTERFACE.multipath" || echo "off")

if [ "$multipath_config" != "on" ] && [ "$multipath_config" != "master" ] && [ "$multipath_config" != "backup" ]; then
	exit 0
fi

# The other trackers run this too: a WAN added through the API while mqvpn
# restarts below is lost, so serialize. BusyBox flock has no timeout: past
# 30s go ahead unlocked.
lock_dir="${OMR_TRACKER_LOCK_DIR:-/var/run/omr-tracker}"
mkdir -p "$lock_dir" >/dev/null 2>&1
# a failed exec redirection ends a POSIX shell: check first
if [ -w "$lock_dir" ] && command -v flock >/dev/null 2>&1; then
	exec 7>"$lock_dir/mqvpn-path.lock"
	tries=0
	until flock -n 7 2>/dev/null; do
		tries=$((tries + 1))
		[ "$tries" -ge 30 ] && break
		sleep 1
	done
fi

# mqvpn started while no multipath WAN device existed, or all were down, has
# no Path line: it then opens one path bound to no device, which follows
# the route to the VPS. Paths added through the API come on top of it, so
# the WAN routing the VPS carries two paths, and when that WAN fails upstream
# the unbound one keeps sending into it until the route moves: the tunnel
# stays degraded for the whole outage. Restart mqvpn so that its
# configuration names the WANs up now, this one included (003-up set it up).
# A backup path does not replace that implicit primary path.
mqvpn_conf="${OMR_MQVPN_CONF:-/var/run/mqvpn.conf}"
case "$(uci -q get mqvpn.multipath.auto_wan)" in
	0|false|off|no|disabled) auto_wan=0 ;;
	*) auto_wan=1 ;;
esac
if [ "$multipath_config" != "backup" ] && [ "$auto_wan" = "1" ] && \
	[ -f "$mqvpn_conf" ] && ! grep -q '^Path = ' "$mqvpn_conf"; then
	_log "mqvpn: no WAN path in its configuration, restart it for $OMR_TRACKER_DEVICE ($OMR_TRACKER_INTERFACE)"
	# 002-error's watchdog cooldown
	date +%s > /tmp/omr-mqvpn-last-restart
	/etc/init.d/mqvpn restart >/dev/null 2>&1
	# Keep the lock until the control API answers, for the next WAN's add
	tries=0
	until mqvpn-path list >/dev/null 2>&1; do
		tries=$((tries + 1))
		[ "$tries" -ge 10 ] && break
		sleep 1
	done
	exit 0
fi

if ! mqvpn_path_exists; then
	if [ "$multipath_config" = "backup" ]; then
		_log "mqvpn: add backup path $OMR_TRACKER_DEVICE ($OMR_TRACKER_INTERFACE)"
		mqvpn-path add "$OMR_TRACKER_DEVICE" backup >/dev/null
	else
		_log "mqvpn: add path $OMR_TRACKER_DEVICE ($OMR_TRACKER_INTERFACE)"
		mqvpn-path add "$OMR_TRACKER_DEVICE" >/dev/null
	fi
fi

exit 0
