#!/bin/sh /etc/rc.common

. /usr/share/libubox/jshn.sh

START=90
USE_PROCD=1

PROG="/usr/bin/zerotier-one"
[ -x "$PROG" ] || PROG="/usr/local$PROG"
CONFIG_PATH=/var/run/zerotier/lib/zerotier-one

EXTRA_COMMANDS="get_ifname"
EXTRA_HELP="
	get_ifname        calculates interface name from a given network ID
"

get_ifname() {
	ucode -e '
		let nwid = 0x'"$1"';
		let nwid40 = (nwid ^ (nwid >> 24));
		let tmp2 = [
			(nwid40 >> 32) & 0xff,
			(nwid40 >> 24) & 0xff,
			(nwid40 >> 16) & 0xff,
			(nwid40 >> 8) & 0xff,
			nwid40 & 0xff
		];
		let base32_chars = "abcdefghijklmnopqrstuvwxyz234567";

		function base32_5_to_8(bytes) {
			let value = (bytes[0] << 32) | (bytes[1] << 24) | (bytes[2] << 16) | (bytes[3] << 8) | bytes[4];
			let result = "";

			for (let i = 0; i < 8; i++) {
				let shift = 35 - (i * 5);
				let index = (value >> shift) & 31;
				result += substr(base32_chars, index, 1);
			}
			return result;
		}

		let tmp3 = "zt" + base32_5_to_8(tmp2);
		print(tmp3 + "\n");
	'
}

setup_network() {
	local cfg="$1"
	local secret="$2"
	local node_id="$3"
	local args=""
	local network_id allow_global allow_managed allow_default custom_planet_file
	local user="zerotier:zerotier"

	config_get enabled "$1" 'enabled' 0
	config_get network_id $cfg 'network_id'
	config_get port $cfg 'port' '9993'
	config_get allow_global $cfg 'allow_global'
	config_get allow_managed $cfg 'allow_managed' '1'
	config_get allow_default $cfg 'allow_default'
	config_get bridge_to $cfg 'bridge_to'
	config_get custom_planet_file "$cfg" "custom_planet_file"

	[ "$enabled" -eq 0 ] && return 1


	args="$args -p${port}"
	path="${CONFIG_PATH}_${node_id}_${cfg}"
	mkdir -p "$path/networks.d"

	# link latest default config path to latest config path
	rm -f "$CONFIG_PATH"
	ln -s "$path" $CONFIG_PATH

	if [ -n "$secret" ]; then
		echo "$secret" > "$path/identity.secret"
		rm -f "$path/identity.public"
	fi

	# an (empty) config file will cause ZT to join a network
	touch "${path}/networks.d/${network_id}.conf"
	touch "${path}/networks.d/${network_id}.local.conf"
	[ -e "$custom_planet_file" ] && cp "$custom_planet_file" "${path}/planet"

	[ "$allow_default" = "1" ] && {
		sysctl -w "net.ipv4.conf.all.rp_filter=2" >/dev/null
		echo "allowDefault=1" >> "${path}/networks.d/${network_id}.local.conf"
        }

	[ "$allow_global" = "1" ] && echo "allowGlobal=1" >> "${path}/networks.d/${network_id}.local.conf"
	[ "$allow_managed" = "1" ] && echo "allowManaged=1" >> "${path}/networks.d/${network_id}.local.conf"
	[ "$allow_managed" = "0" ] && echo "allowManaged=0" >> "${path}/networks.d/${network_id}.local.conf"

	if [ -n "$bridge_to" ]; then
		json_init
		json_add_object "settings"
		json_add_array "interfacePrefixBlacklist"
		json_add_string "" "br-${bridge_to}"
		json_close_object
		json_dump > "${path}/local.conf"
	fi

	args="$args -U" # Skip privilege check and do not attempt to drop privileges
	chown -R "zerotier:zerotier" "$path"
	procd_open_instance
	procd_set_param command $PROG $args $path
	procd_set_param stderr 1
	procd_set_param respawn
	procd_set_param user "zerotier"
	procd_close_instance
}

setup_instance() {
	local enabled port secret node_id

	config_get enabled "$1" 'enabled' 0
	[ "$enabled" -eq 0 ] && return 1

	config_get secret "$1" 'secret'
	config_get node_id "$1" 'node_id'

	if [ -z "$secret" ]; then
		echo "Generating a secret..."
		local sf="/tmp/zt.globals.secret"

		zerotier-idtool generate "$sf" > /dev/null || {
			echo "Failed to generate a secret!"
			return 1
		}

		secret=$(cat "$sf")
		node_id=${secret:0:10}
		uci_set zerotier "$1" "secret" "$secret"
		uci_set zerotier "$1" "node_id" "$node_id"
		rm "$sf"

		uci_commit zerotier
	fi

	config_foreach setup_network "network_${1}" "$secret" "$node_id"
}

start_service() {
	[ -e "/etc/hotplug.d/net/97-zerotier" ] || ln -s /usr/local/usr/share/zerotier/97-zerotier /etc/hotplug.d/net/97-zerotier
	config_load "zerotier"
	config_foreach setup_instance "instance"
	if [ "$(/etc/init.d/mwan3 status)" = "running" ]; then
		/etc/init.d/mwan3 reload
	fi
}

stop_service() {
	[ -d "${CONFIG_PATH}/" ] && find ${CONFIG_PATH}/ ! -name "peers.d" -maxdepth 1 -mindepth 1 -exec rm -rf {} +
}

reload_service() {
	stop
	start
}

service_triggers() {
	procd_add_reload_trigger 'zerotier'
}
