#!/bin/sh /etc/rc.common
# Copyright (C) 2020 Lienol <lawlienol@gmail.com>
# Copyright (C) 2026 sbwml <admin@cooluc.com>

USE_PROCD=1
START=99
STOP=10

CONFIG="socat"
CONFIG_PATH="/var/etc/${CONFIG}"

firewall_add_rule() {
	local ports="$1"

	[ -z "$ports" ] && return 1

	uci -q delete firewall.socat
	uci set firewall.socat=rule
	uci set firewall.socat.name="socat"
	uci set firewall.socat.target="ACCEPT"
	uci set firewall.socat.src="wan"
	uci set firewall.socat.dest_port="$ports"
	uci set firewall.socat.enabled="1"
	uci commit firewall
	/etc/init.d/firewall reload >/dev/null 2>&1
}

firewall_del_rule() {
	uci -q delete firewall.socat
	uci commit firewall 2>/dev/null
	/etc/init.d/firewall reload >/dev/null 2>&1
}

start_instance() {
	local cfg="$1"
	local enable remarks protocol family proto listen_port reuseaddr
	local dest_proto dest_ip dest_port firewall_accept listen socat_opts

	config_get_bool enable "$cfg" "enable" 0
	[ "$enable" -eq 0 ] && return 0

	config_get remarks "$cfg" "remarks" ""
	config_get protocol "$cfg" "protocol" ""
	config_get family "$cfg" "family" ""
	config_get proto "$cfg" "proto" ""
	config_get listen_port "$cfg" "listen_port" ""
	config_get_bool reuseaddr "$cfg" "reuseaddr" 0
	config_get dest_proto "$cfg" "dest_proto" ""
	config_get dest_ip "$cfg" "dest_ip" ""
	config_get dest_port "$cfg" "dest_port" ""
	config_get_bool firewall_accept "$cfg" "firewall_accept" 0

	if [ -z "$listen_port" ] || [ -z "$dest_ip" ] || [ -z "$dest_port" ]; then
		return 1
	fi

	ln -sf /usr/bin/socat "${CONFIG_PATH}/${cfg}"

	socat_opts=""
	[ "$reuseaddr" -eq 1 ] && socat_opts="${socat_opts},reuseaddr"
	[ "$family" = "6" ] && socat_opts="${socat_opts},ipv6-v6only"
	socat_opts="${socat_opts},fork"

	if [ "$protocol" = "port_forwards" ]; then
		listen="${proto}${family}"
		[ -z "$family" ] && listen="${proto}6"

		procd_open_instance "$cfg"
		procd_set_param command "${CONFIG_PATH}/${cfg}"
		procd_append_param command "${listen}-listen:${listen_port}${socat_opts}"
		procd_append_param command "${dest_proto}:${dest_ip}:${dest_port}"
		procd_set_param respawn 3600 5 3
		procd_set_param stdout 0
		procd_set_param stderr 0
		procd_close_instance

		if [ "$firewall_accept" -eq 1 ]; then
			echo "$listen_port" >> "/var/etc/${CONFIG}.port"
		fi
	fi
}

start_service() {
	local global_enable accept_ports

	config_load "luci_socat"
	config_get_bool global_enable "global" "enable" 0

	if [ "$global_enable" -eq 0 ]; then
		return 0
	fi

	mkdir -p "$CONFIG_PATH"
	rm -f "/var/etc/${CONFIG}.port"

	config_foreach start_instance "config"

	accept_ports=$(cat "/var/etc/${CONFIG}.port" 2>/dev/null | tr '\n' ' ')

	if [ -n "$accept_ports" ]; then
		firewall_add_rule "$accept_ports"
	fi
}

stop_service() {
	firewall_del_rule
	rm -rf "$CONFIG_PATH" "/var/etc/${CONFIG}.port"
}

service_triggers() {
	procd_add_reload_trigger "luci_socat"
}

reload_service() {
	stop
	sleep 1
	start
}
