#!/bin/sh /etc/rc.common
# Copyright (C) 2023-2025 muink
#
# depends rgmac

. "${IPKG_INSTROOT}/lib/functions/network.sh"

START=99
USE_PROCD=1
# alwaysonline
[ -x "$(command -v nft)" ] && FW='fw4' || FW='fw3'
PROG='/usr/sbin/alwaysonline'
HOSTFILE='/var/hosts/alwaysonline'
USERNAME=alwaysonline
# uci
CONFIG_NAME='alwaysonline'
TYPEDSECTION='alwaysonline'
DOMAINS='domain'

config_load "$CONFIG_NAME"


find_op_ifnames() {
	local ifnames ifname iface _c

	ifnames="lo $($FW -q zone $($FW -q device "br-lan"))"
	for _c in network_find_wan network_find_wan6; do
		$_c iface 1
		ifname=$($FW -q zone $($FW -q network "$iface"))
		ifnames="${ifnames:+$ifnames }$ifname"
	done
	echo $ifnames | sed 's|\s|\n|g' | sort -u
}

gen_uhttpd_listen_ips() {
	local regexp

	regexp=$(find_op_ifnames | tr '\n' '|' | sed 's,^|*,,;s,|*$,,')
	ip -o addr | grep -v "\bscope link\b" | sed -En -e "/^[0-9]+:\s*($regexp)\s/{s|^.*\binet6?\s+([^/]+)/.*|\1|p}" | sed '/:/{s|^|\[|;s|$|\]|}'
}

validate_section_domain() {
	uci_load_validate $CONFIG_NAME $DOMAINS "$1" "$2" \
		'enabled:bool:0' \
		'name:hostname' \
		'group:string' \
		'family:or("4", "6", "both"):both' \
		'overwrite:ipaddr'
}

init_hosts() {
	mkdir -p "${HOSTFILE%/*}" 2>/dev/null
	echo "# auto-generated config file from /etc/config/alwaysonline" > "${HOSTFILE}"
}

gen_hosts() {
	[ "$2" == "0" ] || { >&2 echo "section $1 validation failed"; return 1; }
	[ "$enabled" == "0" ] && return 0

	local _addr4="${tun_addr4%/*}"
	local _addr6="${tun_addr6%/*}"

	local familys
	[ "$family" == "both" ] && familys="4 6" || familys="$family"

	for v in $familys; do
		eval "domain_list=\"\${domain_list}\${overwrite:-\$_addr$v} \${name}\n\""
	done
}

gen_eui64() {
	local mac=$(rgmac)
	local head=${mac:0:2}
	if [ "$(( 0x$head & 2 ))" = "0" ]; then
		printf "fe80::%x%s" $(( 0x$head | 2 )) "${mac:2:2}:${mac:4:2}ff:fe${mac:6:2}:${mac:8}"
	else
		printf "fe80::%x%s" $(( 0x$head & 0xfd )) "${mac:2:2}:${mac:4:2}ff:fe${mac:6:2}:${mac:8}"
	fi
}

# set_uhttpd [host:port list]
set_uhttpd() {
	local listen_http="${1:-0.0.0.0:80 [::]:80}" _v

	uci -q delete uhttpd.main.listen_http
	for _v in $listen_http; do
		uci add_list uhttpd.main.listen_http="$_v"
	done
	uci commit uhttpd
}

start_instance() {
	# TUN
	ip tuntap add mode tun user "$USERNAME" name "$tun_name"
	sleep 1s
	ip link set "$tun_name" up

	ip addr add "${tun_addr4}" dev "$tun_name"
	ip addr add "${tun_addr6}" dev "$tun_name"
	ip addr add "$(gen_eui64)/64" scope link dev "$tun_name"

	procd_open_instance "$CONFIG_NAME"
	procd_set_param command "$PROG" -port 80
	procd_append_param command --disable-dns-server
	procd_append_param command -ipv4 "${tun_addr4%/*}" -ipv6 "${tun_addr6%/*}"
	procd_append_param netdev "br-lan"
	procd_append_param netdev "$tun_name"
	procd_set_param respawn
	procd_set_param user root
	procd_set_param stderr 1
	procd_close_instance
}

start_service() {
	local enabled tun_name tun_addr4 tun_addr6

	config_get enabled global enabled 0
	[ "$enabled" == "0" ] && return 1
	config_get tun_name  global tun_name  'awoltun0'
	config_get tun_addr4 global tun_addr4 '172.25.26.1/30'
	config_get tun_addr6 global tun_addr6 'fdfe:aead:2526::1/126'
	config_get port global port '8083'

	# DNS
	init_hosts
	local domain_list
	config_foreach validate_section_domain "$DOMAINS" gen_hosts || return $?
	sed -Ei "1a$domain_list" "$HOSTFILE"

	# HTTP
	/etc/init.d/uhttpd stop
	set_uhttpd "$(gen_uhttpd_listen_ips | sed 's|$|:80|')"
	start_instance
}

service_triggers() {
	procd_add_reload_trigger "$CONFIG_NAME" 'network'

	local iface=$(uci show network|grep "device='br-lan'"|cut -f2 -d'.'|head -n1)
	[ -n "$iface" ] && procd_add_reload_interface_trigger "$iface"
}

reload_service() {
	stop
	start
}

service_started() {
	# DNS
	/etc/init.d/dnsmasq reload

	# HTTP
	/etc/init.d/uhttpd start
}

service_stopped() {
	# DNS
	init_hosts
	/etc/init.d/dnsmasq reload

	# HTTP
	set_uhttpd
	/etc/init.d/uhttpd restart

	# TUN
	local tun_name
	config_get tun_name global tun_name 'awoltun0'

	ip link set "$tun_name" down 2>/dev/null
	ip tuntap del mode tun name "$tun_name" 2>/dev/null
}
