#!/bin/sh /etc/rc.common
# Copyright (C) 2018-2019 Ycarus (Yannick Chabanois) <ycarus@zugaina.org>
# Released under GPL 3. See LICENSE for the full terms.

START=99

USE_PROCD=1

EXTRA_COMMANDS="set_pihole backup_send backup_get backup_list set_vps_firewall"

_parse_result() {
	result=$("echo $1 | jsonfilter -q -e '@.result'")
	echo $result
}

_login() {
	local username password auth
	server="$(uci -q get openmptcprouter.${servername}.ip)"
	[ -z "$server" ] && server="$(uci -q get shadowsocks-libev.sss0.server)"
	username="$(uci -q get openmptcprouter.${servername}.username)"
	password="$(uci -q get openmptcprouter.${servername}.password)"
	serverport="$(uci -q get openmptcprouter.${servername}.port)"
	if [ -z "$token" ]; then
		#auth=`curl --max-time 10 -s -k -H "Content-Type: application/json" -X POST -d '{"username":"'$username'","password":"'$password'"}' https://$server:$serverport/login`
		auth=`curl --max-time 10 -s -k -H "accept: application/json" -H "Content-Type: application/x-www-form-urlencoded" -X POST -d 'username='$username'&password='$password https://$server:$serverport/token`
		[ -z "$auth" ] && return
		token="$(echo "$auth" | jsonfilter -q -e '@.access_token')"
		uci -q set openmptcprouter.${servername}.token="$token"
	fi
}

_ping_server() {
	server="$(uci -q get openmptcprouter.${servername}.ip)"
	[ -z "$server" ] && server="$(uci -q get shadowsocks-libev.sss0.server)"
	ret=$(ping -c 3 -w 3 -Q 184 $server) && echo "$ret" | grep -sq "bytes from" && return
	false
}

_get_json() {
	local route result
	route=$1
	[ -z "$token" ] && _login
	[ -n "$token" ] && {
		result=`curl --max-time 10 -s -k -H "accept: application/json" -H "Authorization: Bearer $token" https://$server:$serverport/$route`
		echo $result
	} || {
		echo ''
	}
}

_set_json() {
	local route result settings
	route=$1
	settings="$2"
	[ -z "$token" ] && _login
	[ -n "$token" ] && {
		result=`curl --max-time 10 -s -k -H "Authorization: Bearer $token" -H "Content-Type: application/json" -X POST -d "$settings" https://$server:$serverport/$route`
		echo $result
	} || {
		echo ''
	}
}

_set_glorytun_vps() {
	local enabled port key
	enabled="$(uci -q get glorytun.vpn.enable)"
	[ "$enabled" != "1" ] && echo "Glorytun disabled" && return
	port="$(uci -q get glorytun.vpn.port)"
	key="$(uci -q get glorytun.vpn.key)"
	chacha="$(uci -q get glorytun.vpn.chacha20)"
	if [ "$chacha" = "1" ]; then
		chacha="true"
	else
		chacha="false"
	fi
	[ -z "$key" ] && echo "Glorytun key not set" && return
	local current_port current_key current_chacha
	[ -z "$vps_config" ] && vps_config=$(_get_json "config")
	[ -z "$vps_config" ] && return
	current_port="$(echo "$vps_config" | jsonfilter -q -e '@.glorytun.port')"
	current_key="$(echo "$vps_config" | jsonfilter -q -e '@.glorytun.key')"
	current_chacha="$(echo "$vps_config" | jsonfilter -q -e '@.glorytun.chacha')"
	if [ "$current_port" != "$port" ] || [ "$current_key" != "$key" ] || [ "$current_chacha" != "$chacha" ]; then
		local settings
		settings='{"port": '$port',"key":"'$key'", "chacha": "'$chacha'"}'
		echo $(_set_json "glorytun" "$settings")
	else
		echo 1
	fi
}

_set_openvpn_vps() {
	local enabled port key
	enabled="$(uci -q get openvpn.omr.enable)"
	[ "$enabled" != "1" ] && echo "OpenVPN disabled" && return
	port="$(uci -q get openvpn.omr.port)"
	cipher="$(uci -q get openvpn.omr.cipher)"
	local current_port current_cipher
	[ -z "$vps_config" ] && vps_config=$(_get_json "config")
	[ -z "$vps_config" ] && return
	current_port="$(echo "$vps_config" | jsonfilter -q -e '@.openvpn.port')"
	current_cipher="$(echo "$vps_config" | jsonfilter -q -e '@.openvpn.cipher')"
	if [ "$current_port" != "$port" ] || [ "$current_cipher" != "$cipher" ]; then
		local settings
		settings='{"port": '$port', "cipher": "'$cipher'"}'
		echo $(_set_json "openvpn" "$settings")
	else
		echo 1
	fi
}

_get_ss_redir() {
	config_get cf_ebpf $1 ebpf
	[ "$cf_ebpf" = "1" ] && ebpf="true"
	config_get cf_fast_open $1 fast_open
	[ "$cf_fast_open" = "1" ] && fast_open="true"
	config_get cf_no_delay $1 no_delay
	[ "$cf_no_delay" = "1" ] && no_delay="true"
}

_get_ss_server() {
	config_get cf_obfs $1 obfs
	[ "$cf_obfs" = "1" ] && obfs="true"
	config_get obfs_plugin $1 obfs_plugin
	config_get obfs_type $1 obfs_type
}

_set_ss_server_vps() {
	local disabled port key method
	config_get disabled $1 disabled
	[ "$disabled" = "1" ] && return
	config_get port $1 server_port
	#config_get server $1 server
	config_get key $1 key
	key="$(echo $key | sed 's/+/-/g; s/\//_/g;')"
	[ -z "$key" ] && return
	config_get method $1 method
	local current_port current_key current_method
	[ -z "$vps_config" ] && vps_config=$(_get_json "config")
	[ -z "$vps_config" ] && return
	current_port="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.port')"
	current_key="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.key')"
	current_method="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.method')"
	current_ebpf="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.ebpf')"
	current_obfs="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.obfs')"
	current_obfs_plugin="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.obfs_plugin')"
	current_obfs_type="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.obfs_type')"
	current_fast_open="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.fast_open')"
	current_no_delay="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.no_delay')"
	
	ebpf="false"
	fast_open="false"
	no_delay="false"
	obfs="false"
	obfs_plugin="v2ray"
	obfs_type="http"
	config_load shadowsocks-libev
	config_foreach _get_ss_redir ss_redir
	config_foreach _get_ss_server server

	if [ "$current_obfs_plugin" != "$obfs_plugin" ] || [ "$current_obfs_type" != "$obfs_type" ] || [ "$current_port" != "$port" ] || [ "$current_method" != "$method" ] || [ "$current_key" != "$key" ] || [ "$current_ebpf" != "$ebpf" ] || [ "$current_obfs" != "$obfs" ] || [ "$current_fast_open" != "$fast_open" ] || [ "$current_no_delay" != "$no_delay" ]; then
		local settings
		settings='{"port": '$port',"method":"'$method'","fast_open":'$fast_open',"reuse_port":true,"no_delay":'$no_delay',"mptcp":true,"key":"'$key'","ebpf":'$ebpf',"obfs":'$obfs',"obfs_plugin":"'$obfs_plugin'","obfs_type":"'$obfs_type'"}'
		echo $(_set_json "shadowsocks" "$settings")
	fi
}

_get_vps_config() {
	[ -z "$vps_config" ] && vps_config=$(_get_json "config")
	[ -z "$vps_config" ] && return
	vps_lastchange="$(echo "$vps_config" | jsonfilter -q -e '@.vps.lastchange')"
	if [ -n "$(uci -q get openmptcprouter.${servername}.lastchange)" ] && [ -n "$vps_lastchange" ] && [ "$vps_lastchange" -gt "$(uci -q get openmptcprouter.${servername}.lastchange)" ]; then
		_set_config_from_vps
	fi

	piholeomr="$(uci -q get openmptcprouter.${servername}.pihole)"
	pihole="$(echo "$vps_config" | jsonfilter -q -e '@.pihole.state')"
	if [ "$pihole" = "true" ] && [ "$piholeomr" != "1" ]; then
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.${servername}.pihole='1'
			commit openmptcprouter
		EOF
	elif [ "$pihole" = "false" ] && [ "$piholeomr" != "0" ]; then
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.${servername}.pihole='0'
			commit openmptcprouter
		EOF
	fi

	vpsinternet="$(echo "$vps_config" | jsonfilter -q -e '@.network.internet')"
	if [ "$vpsinternet" = "false" ] && [ "$(uci -q get openmptcprouter.settings.external_check)" != "0" ]; then
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.settings.external_check='0'
			commit openmptcprouter
		EOF
	fi

	vps_kernel="$(echo "$vps_config" | jsonfilter -q -e '@.vps.kernel')"
	vps_machine="$(echo "$vps_config" | jsonfilter -q -e '@.vps.machine')"
	vps_omr_version="$(echo "$vps_config" | jsonfilter -q -e '@.vps.omr_version')"
	uci -q batch <<-EOF >/dev/null
		set openmptcprouter.${servername}.kernel=$vps_kernel
		set openmptcprouter.${servername}.machine=$vps_machine
		set openmptcprouter.${servername}.omr_version=$vps_omr_version
	EOF
	vpn="$(uci -q get openmptcprouter.settings.vpn)"

	glorytun_state=0
	glorytun_change=0
	if [ "$vpn" = "glorytun_tcp" ]; then
		glorytun_state=1
		uci -q set glorytun.vpn.proto='tcp'
		client_ip="$(echo "$vps_config" | jsonfilter -q -e '@.glorytun.tcp.client_ip')"
		host_ip="$(echo "$vps_config" | jsonfilter -q -e '@.glorytun.tcp.host_ip')"
		port="$(echo "$vps_config" | jsonfilter -q -e '@.glorytun.port')"
		if [ "$(uci -q get glorytun.vpn.port)" != "$port" ]; then
			uci -q batch <<-EOF >/dev/null
				set glorytun.vpn.port=$port
			EOF
			glorytun_change=1
		fi
		if [ "$client_ip" != "dhcp" ] && [ -n "$client_ip" ]; then
			if [ "$host_ip" != "$(uci -q get glorytun.vpn.remoteip)" ] || [ "$client_ip" != "$(uci -q get glorytun.vpn.localip)" ]; then
				uci -q batch <<-EOF >/dev/null
					set glorytun.vpn.localip=$client_ip
					set glorytun.vpn.remoteip=$host_ip
				EOF
				glorytun_change=1
			fi
			if [ "$(uci -q get network.omrvpn.proto)" != 'none' ]; then
				uci -q batch <<-EOF >/dev/null
					set network.omrvpn.proto='none'
					commit network
				EOF
				glorytun_change=1
			fi
		else
			if [ "$(uci -q get glorytun.vpn.remoteip)" != "" ] || [ "$(uci -q get glorytun.vpn.localip)" != "" ]; then
				uci -q batch <<-EOF >/dev/null
					delete glorytun.vpn.localip
					delete glorytun.vpn.remoteip
				EOF
				glorytun_change=1
			fi
			if [ "$(uci -q get network.omrvpn.proto)" != 'dhcp' ]; then
				uci -q batch <<-EOF >/dev/null
					set network.omrvpn.proto='dhcp'
					commit network
				EOF
				glorytun_change=1
			fi
		fi
	fi
	if [ "$vpn" = "glorytun_udp" ]; then
		glorytun_state=1
		uci -q set glorytun.vpn.proto='udp'
		client_ip="$(echo "$vps_config" | jsonfilter -q -e '@.glorytun.udp.client_ip')"
		host_ip="$(echo "$vps_config" | jsonfilter -q -e '@.glorytun.udp.host_ip')"
		port="$(echo "$vps_config" | jsonfilter -q -e '@.glorytun.port')"
		if [ "$(uci -q get glorytun.vpn.port)" != "$port" ]; then
			uci -q batch <<-EOF >/dev/null
				set glorytun.vpn.port=$port
			EOF
		fi
		if [ "$client_ip" != "dhcp" ] && [ -n "$client_ip" ]; then
			if [ "$host_ip" != "$(uci -q get glorytun.vpn.remoteip)" ] || [ "$client_ip" != "$(uci -q get glorytun.vpn.localip)" ]; then
				uci -q batch <<-EOF >/dev/null
					set glorytun.vpn.localip=$client_ip
					set glorytun.vpn.remoteip=$host_ip
				EOF
				glorytun_change=1
			fi
			if [ "$(uci -q get network.omrvpn.proto)" = "dhcp" ]; then
				uci -q batch <<-EOF >/dev/null
					set network.omrvpn.proto='none'
					commit network
				EOF
				glorytun_change=1
			fi
		else
			if [ "$(uci -q get glorytun.vpn.remoteip)" != "" ] || [ "$(uci -q get glorytun.vpn.localip)" != "" ]; then
				uci -q batch <<-EOF >/dev/null
					delete glorytun.vpn.localip
					delete glorytun.vpn.remoteip
				EOF
				glorytun_change=1
			fi
			if [ "$(uci -q get network.omrvpn.proto)" != "dhcp" ]; then
				uci -q batch <<-EOF >/dev/null
					set network.omrvpn.proto='dhcp'
					commit network
				EOF
				glorytun_change=1
			fi
		fi
	fi
	vpsip="$(uci -q get openmptcprouter.${servername}.ip)"
	if [ "$(uci -q get shadowsocks-libev.sss0.server)" != "127.0.0.1" ] && [ "$(uci -q get shadowsocks-libev.sss0.server)" != "$vpsip" ] && [ "$(uci -q get openmptcprouter.settings.ha)" != "1" ]; then
		config_foreach _set_ss_server server "server" $vpsip
		uci -q batch <<-EOF >/dev/null
			commit shadowsocks-libev
		EOF
		if [ "$(uci -q get shadowsocks-libev.sss0.disabled)" = "0" ]; then
			logger -t "OMR-VPS" "Restart shadowsocks..."
			/etc/init.d/shadowsocks-libev restart
		fi
	fi
	if [ "$(uci -q get openvpn.omr.remote)" != "127.0.0.1" ] && [ "$(uci -q get openvpn.omr.remote)" != "$vpsip" ] && [ "$(uci -q get openmptcprouter.settings.ha)" != "1" ]; then
		uci -q batch <<-EOF >/dev/null
			set openvpn.omr.remote="$vpsip"
			commit openvpn
		EOF
		if [ "$(uci -q get openvpn.omr.enabled)" = "1" ]; then
			logger -t "OMR-VPS" "Restart OpenVPN..."
			/etc/init.d/openvpn restart
		fi
	fi
	port="$(echo "$vps_config" | jsonfilter -q -e '@.dsvpn.port')"
	localip="$(echo "$vps_config" | jsonfilter -q -e '@.dsvpn.client_ip')"
	remoteip="$(echo "$vps_config" | jsonfilter -q -e '@.dsvpn.host_ip')"
	if ([ "$(uci -q get dsvpn.vpn.host)" != "127.0.0.1" ] && [ "$(uci -q get dsvpn.vpn.host)" != "$vpsip" ] && [ "$(uci -q get openmptcprouter.settings.ha)" != "1" ]) || [ "$(uci -q get dsvpn.vpn.port)" != "$port" ] || [ "$(uci -q get dsvpn.vpn.localip)" != "$localip" ] || [ "$(uci -q get dsvpn.vpn.remoteip)" != "$remoteip" ]; then
		uci -q batch <<-EOF >/dev/null
			set dsvpn.vpn.port=$port
			set dsvpn.vpn.localip=$localip
			set dsvpn.vpn.remoteip=$remoteip
			set dsvpn.vpn.host="$vpsip"
			commit dsvpn
		EOF
		if [ "$(uci -q get dsvpn.vpn.enable)" = "1" ]; then
			logger -t "OMR-VPS" "Restart DSVPN..."
			/etc/init.d/dsvpn restart
		fi
	fi

	if [ "$(uci -q get mlvpn.general.host)" != "127.0.0.1" ] && [ "$(uci -q get mlvpn.general.host)" != "$vpsip" ] && [ "$(uci -q get openmptcprouter.settings.ha)" != "1" ] && [ -f /etc/init.d/mlvpn ]; then
		uci -q batch <<-EOF >/dev/null
			set mlvpn.general=mlvpn
			set mlvpn.general.host="$vpsip"
			commit mlvpn
		EOF
		if [ "$(uci -q get mlvpn.general.enable)" = "1" ]; then
			logger -t "OMR-VPS" "Restart MLVPN..."
			/etc/init.d/mlvpn restart
		fi
	fi
	if [ "$(uci -q get glorytun.vpn.host)" != "127.0.0.1" ] && [ "$(uci -q get glorytun.vpn.host)" != "$vpsip" ] && [ "$(uci -q get openmptcprouter.settings.ha)" != "1" ]; then
		uci -q batch <<-EOF >/dev/null
			set glorytun.vpn.host="$vpsip"
		EOF
		glorytun_change=1
	fi

	if [ "$glorytun_change" != "0" ]; then
		uci -q batch <<-EOF >/dev/null
			commit glorytun
		EOF
		if [ "$(uci -q get glorytun.vpn.enable)" = "1" ]; then
			logger -t "OMR-VPS" "Restart glorytun..."
			/etc/init.d/glorytun restart >/dev/null 2>&1
			/etc/init.d/glorytun-udp restart >/dev/null 2>&1
		fi
	fi
}

_get_gre_tunnel() {
	[ -z "$vps_config" ] && vps_config=$(_get_json "config")
	[ -z "$vps_config" ] && return
	gre_tunnel_state="$(echo "$vps_config" | jsonfilter -q -e '@.gre_tunnel.enabled')"
	if [ "$gre_tunnel_state" = "true" ]; then
		i=0
		echo "$vps_config" | jsonfilter -q -e '@.gre_tunnel.config[*]' |
		while IFS= read -r tunnel; do
			peeraddr="$(echo $tunnel | jsonfilter -q -e '@.remote_ip')"
			ipaddr="$(echo $tunnel | jsonfilter -q -e '@.local_ip')"
			publicaddr="$(echo $tunnel | jsonfilter -q -e '@.public_ip')"
			uci -q batch <<-EOF >/dev/null
				set network.omrip${i}=interface
				set network.omrip${i}.label="Tunnel for $publicaddr"
				set network.omrip${i}.proto=gre
				set network.omrip${i}.nohostroute='1'
				set network.omrip${i}.ipv6='0'
				set network.omrip${i}.defaultroute='0'
				set network.omrip${i}.multipath='off'
				set network.omrip${i}.peerdns='0'
				set network.omrip${i}.ip4table='vpn'
				set network.omrip${i}.peeraddr="$peeraddr"
				set network.omrip${i}.ipaddr="$ipaddr"
				commit network
				add_list firewall.zone_vpn.network="omrip${i}"
				commit firewall
			EOF
			
			ssport="$(echo $tunnel | jsonfilter -q -e '@.shadowsocks_port')"
			uci -q batch <<-EOF >/dev/null
				set shadowsocks-libev.omrip${i}server=server
				set shadowsocks-libev.omrip${i}server.label="Server with public IP $publicaddr"
				set shadowsocks-libev.omrip${i}server.server_port="$ssport"
				set shadowsocks-libev.omrip${i}server.method="$(uci -q get shadowsocks-libev.sss0.method)"
				set shadowsocks-libev.omrip${i}server.key="$(uci -q get shadowsocks-libev.sss0.key)"
				set shadowsocks-libev.omrip${i}=ss_redir
				set shadowsocks-libev.omrip${i}.label="ss-redir for public IP $publicaddr"
				set shadowsocks-libev.omrip${i}.server="omrip${i}server"
				set shadowsocks-libev.omrip${i}.local_port="230$i"
				set shadowsocks-libev.omrip${i}.mode='tcp_and_udp'
				set shadowsocks-libev.omrip${i}.reuse_port='1'
				set shadowsocks-libev.omrip${i}.mptcp='1'
				set shadowsocks-libev.omrip${i}.ipv6_first='1'
				set shadowsocks-libev.omrip${i}.timeout="$(uci -q get shadowsocks-libev.omrip${i}.timeout)"
				set shadowsocks-libev.omrip${i}.fast_open="$(uci -q get shadowsocks-libev.omrip${i}.fast_open)"
				set shadowsocks-libev.omrip${i}.no_delay="$(uci -q get shadowsocks-libev.omrip${i}.no_delay)"
				set shadowsocks-libev.omrip${i}_rule=ss_rules
				set shadowsocks-libev.omrip${i}_rule.label="Rules for public IP $publicaddr"
				set shadowsocks-libev.omrip${i}_rule.server="omrip${i}server"
				set shadowsocks-libev.omrip${i}_rule.disabled='1'
				set shadowsocks-libev.omrip${i}_rule.src_default='forward'
				set shadowsocks-libev.omrip${i}_rule.dst_default='forward'
				set shadowsocks-libev.omrip${i}_rule.local_default='forward'
				set shadowsocks-libev.omrip${i}_rule.redir_tcp="omrip${i}"
				commit shadowsocks-libev
			EOF
			if [ "$(uci -q get shadowsocks-libev.omrip${i}server.disabled)" = "" ]; then
				uci -q set shadowsocks-libev.omrip${i}server.disabled='1'
			fi
			if [ "$(uci -q get shadowsocks-libev.omrip${i}.local_address)" = "" ]; then
				uci -q set shadowsocks-libev.omrip${i}.local_address='::'
			fi
			i=$((i+1))
		done
	fi
}

_get_pihole() {
	[ -z "$vps_config" ] && vps_config=$(_get_json "config")
	[ -z "$vps_config" ] && return
	vpn="$(uci -q get openmptcprouter.settings.vpn)"
	piholeomr="$(uci -q get openmptcprouter.${servername}.pihole)"
	pihole="$(echo "$vps_config" | jsonfilter -q -e '@.pihole.state')"
	if [ "$pihole" = "true" ] && [ "$piholeomr" != "1" ]; then
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.${servername}.pihole='1'
			commit openmptcprouter
		EOF
	elif [ "$pihole" = "false" ] && [ "$piholeomr" != "0" ]; then
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.${servername}.pihole='0'
			commit openmptcprouter
		EOF
	fi

	if [ "$vpn" = "glorytun_tcp" ]; then
		host_ip="$(echo "$vps_config" | jsonfilter -q -e '@.glorytun.tcp.host_ip')"
		if [ "$pihole" = "true" ] && [ "$(uci -q get dhcp.@dnsmasq[0].server)" != "$host_ip#53" ]; then
			uci -q batch <<-EOF >/dev/null
				delete dhcp.@dnsmasq[0].server
				add_list dhcp.@dnsmasq[0].server="$host_ip#53"
				set dhcp.@dnsmasq[0].rebind_protection='0'
				commit dhcp
			EOF
			logger -t "OMR-VPS" "Restart dnsmasq..."
			/etc/init.d/dnsmasq restart >/dev/null 2>&1
		fi
	fi
	if [ "$vpn" = "glorytun_udp" ]; then
		host_ip="$(echo "$vps_config" | jsonfilter -q -e '@.glorytun.udp.host_ip')"
		if [ "$pihole" = "true" ] && [ "$(uci -q get dhcp.@dnsmasq[0].server)" != "$host_ip#53" ]; then
			uci -q batch <<-EOF >/dev/null
				delete dhcp.@dnsmasq[0].server
				add_list dhcp.@dnsmasq[0].server="$host_ip#53"
				set dhcp.@dnsmasq[0].rebind_protection='0'
				commit dhcp
			EOF
			logger -t "OMR-VPS" "Restart dnsmasq..."
			/etc/init.d/dnsmasq restart >/dev/null 2>&1
		fi
	fi
	if [ "$vpn" = "openvpn" ]; then
		host_ip="$(echo "$vps_config" | jsonfilter -q -e '@.openvpn.host_ip')"
		if [ "$pihole" = "true" ] && [ "$(uci -q get dhcp.@dnsmasq[0].server)" != "$host_ip#53" ]; then
			uci -q batch <<-EOF >/dev/null
				delete dhcp.@dnsmasq[0].server
				add_list dhcp.@dnsmasq[0].server="$host_ip#53"
				set dhcp.@dnsmasq[0].rebind_protection='0'
				commit dhcp
			EOF
			logger -t "OMR-VPS" "Restart dnsmasq..."
			/etc/init.d/dnsmasq restart >/dev/null 2>&1
		fi
	fi
	if [ "$vpn" = "mlvpn" ]; then
		host_ip="$(echo "$vps_config" | jsonfilter -q -e '@.mlvpn.host_ip')"
		if [ "$pihole" = "true" ] && [ "$(uci -q get dhcp.@dnsmasq[0].server)" != "$host_ip#53" ]; then
			uci -q batch <<-EOF >/dev/null
				delete dhcp.@dnsmasq[0].server
				add_list dhcp.@dnsmasq[0].server="$host_ip#53"
				set dhcp.@dnsmasq[0].rebind_protection='0'
				commit dhcp
			EOF
			logger -t "OMR-VPS" "Restart dnsmasq..."
			/etc/init.d/dnsmasq restart >/dev/null 2>&1
		fi
	fi
	if [ "$vpn" = "dsvpn" ]; then
		host_ip="$(echo "$vps_config" | jsonfilter -q -e '@.dsvpn.host_ip')"
		if [ "$pihole" = "true" ] && [ "$(uci -q get dhcp.@dnsmasq[0].server)" != "$host_ip#53" ]; then
			uci -q batch <<-EOF >/dev/null
				delete dhcp.@dnsmasq[0].server
				add_list dhcp.@dnsmasq[0].server="$host_ip#53"
				set dhcp.@dnsmasq[0].rebind_protection='0'
				commit dhcp
			EOF
			logger -t "OMR-VPS" "Restart dnsmasq..."
			/etc/init.d/dnsmasq restart >/dev/null 2>&1
		fi
	fi
}

_set_redirect_ports_from_vps() {
	redirect_ports=$1
	[ -z "$vps_config" ] && vps_config=$(_get_json "config")
	[ -z "$vps_config" ] && return
	redirect_ports_current="$(echo "$vps_config" | jsonfilter -q -e '@.shorewall.redirect_ports')"
	[ "$redirect_ports" = "1" ] && redirect_ports_request="enable"
	[ "$redirect_ports" = "0" ] && redirect_ports_request="disable"
	if [ "$redirect_ports_request" != "$redirect_ports_current" ]; then
		settings='{"redirect_ports": "'$redirect_ports_request'"}'
		echo $(_set_json "shorewall" "$settings")
	else
		echo 1
	fi

}

_set_mptcp_vps() {
	local settings
	[ -z "$vps_config" ] && vps_config=$(_get_json "config")
	[ -z "$vps_config" ] && return
	mptcp_enabled_current="$(echo "$vps_config" | jsonfilter -q -e '@.mptcp.enabled')"
	checksum_current="$(echo "$vps_config" | jsonfilter -q -e '@.mptcp.checksum')"
	path_manager_current="$(echo "$vps_config" | jsonfilter -q -e '@.mptcp.path_manager')"
	scheduler_current="$(echo "$vps_config" | jsonfilter -q -e '@.mptcp.scheduler')"
	syn_retries_current="$(echo "$vps_config" | jsonfilter -q -e '@.mptcp.syn_retries')"
	congestion_control_current="$(echo "$vps_config" | jsonfilter -q -e '@.network.congestion_control')"
	mptcp_enabled="$(uci -q get network.globals.multipath)"
	if [ "$mptcp_enabled" = "disable" ]; then
		mptcp_enabled="0"
	else
		mptcp_enabled="1"
	fi
	checksum="$(uci -q get network.globals.mptcp_checksum)"
	path_manager="$(uci -q get network.globals.mptcp_path_manager)"
	scheduler="$(uci -q get network.globals.mptcp_scheduler)"
	syn_retries="$(uci -q get network.globals.mptcp_syn_retries)"
	congestion="$(uci -q get network.globals.congestion)"
	[ -z "$congestion" ] && congestion="bbr"
	if [ "$mptcp_enabled_current" != "$mptcp_enabled" ] || [ "$checksum_current" != "$checksum" ] || [ "$path_manager_current" != "$path_manager" ] || [ "$scheduler_current" != "$scheduler" ] || [ "$syn_retries_current" != "$syn_retries" ] || [ "$congestion_control_current" != "$congestion" ]; then
		settings='{"enabled" : "'$mptcp_enabled'", "checksum": "'$checksum'","path_manager": "'$path_manager'","scheduler": "'$scheduler'","syn_retries": "'$syn_retries'","congestion_control": "'$congestion'"}'
		echo $(_set_json "mptcp" "$settings")
	else
		echo 1
	fi
}

_set_vpn_vps() {
	local settings
	[ -z "$vps_config" ] && vps_config=$(_get_json "config")
	[ -z "$vps_config" ] && return
	vpn_current="$(echo "$vps_config" | jsonfilter -q -e '@.vps.current')"
	vpn="$(uci -q get openmptcprouter.settings.vpn)"
	if [ "$vpn_current" != "$vpn" ]; then
		settings='{"vpn" : "'$vpn'"}'
		echo $(_set_json "vpn" "$settings")
	else
		echo 1
	fi
}

_get_local_wan_ip() {
	wanip="$(uci -q get openmptcprouter.$1.publicip)"
	[ -n "$wanip" ] && {
		[ -z "$wanips" ] && wanips=$wanip || wanips="$wanips"'\n'"$wanip"
	}
}

_set_wan_ip() {
	local settings
	[ -z "$vps_config" ] && vps_config=$(_get_json "config")
	[ -z "$vps_config" ] && return
	wanip_current="$(echo "$vps_config" | jsonfilter -q -e '@.wan.ips')"
	if [ -n "$wanips" ] && [ "$wanip_current" != "$wanips" ]; then
		settings='{"ips" : "'$wanips'"}'
		result=$(_set_json "wan" "$settings")
		#echo $(_set_json "wan" "$settings")
	#else
	#	echo 1
	fi
}

_set_lan_ip() {
	local settings
	[ -z "$vps_config" ] && vps_config=$(_get_json "config")
	[ -z "$vps_config" ] && return
	lanip_current="$(echo "$vps_config" | jsonfilter -q -e '@.lan.ips')"
	lanips="$(uci -q get network.lan.ipaddr)/$(uci -q get network.lan.netmask)"
	if [ "$lanips" != "/" ] && [ "$lanip_current" != "$lanips" ]; then
		settings='{"lanips" : ["'$lanips'"]}'
		result=$(_set_json "lan" "$settings")
	fi
}

_set_vpn_ip() {
	local settings
	[ -z "$vps_config" ] && vps_config=$(_get_json "config")
	[ -z "$vps_config" ] && return
	vpnifname="$(uci -q get network.omrvpn.ifname)"
	vpnip_local_current="$(echo "$vps_config" | jsonfilter -q -e '@.vpn.remoteip')"
	vpnip_local=$(ip -4 -br addr ls dev ${vpnifname} | awk -F'[ /]+' '{print $3}')
	vpnip_remote_current="$(echo "$vps_config" | jsonfilter -q -e '@.vpn.localip')"
	vpnip_remote=$(ip -4 r list dev ${vpnifname} | grep via | grep -v default | grep -v / | grep -v metric | awk '{print $1}' | tr -d "\n")
	[ -z "$vpnip_remote" ] && vpnip_remote=$(ip -4 r list dev ${vpnifname} | grep kernel | awk '{print $1}' | tr -d "\n")
	[ -z "$vpnip_remote" ] && vpnip_remote=$(ip -4 r list dev ${vpnifname} | grep "proto static src" | awk '{print $3}' | tr -d "\n")
	ula="$(uci -q get network.globals.ula_prefix)"
	ula_current="$(echo "$vps_config" | jsonfilter -q -e '@.ip6in4.ula')"
	if [ "$vpnip_remote" != "" ] && [ "$vpnip_local" != "" ] && ([ "$vpnip_remote" != "$vpnip_remote_current" ] || [ "$vpnip_local" != "$vpnip_local_current" ] || [ "$ula" != "$ula_current" ]); then
		settings='{"remoteip" : "'$vpnip_local'","localip" : "'$vpnip_remote'","ula" : "'$ula'"}'
		result=$(_set_json "vpnips" "$settings")
	fi
}

_delete_client2client() {
	if [ -n "$(echo $1 | grep omr_client2client)" ]; then
		uci -q delete network.$1
	fi
}

_set_client2client() {
	local c2cid=0
	[ -z "$vps_config" ] && vps_config=$(_get_json "config")
	[ -z "$vps_config" ] && return
	c2cips="$(echo "$vps_config" | jsonfilter -q -e '@.client2client.lanips[0]')"
	vpnifname="$(uci -q get network.omrvpn.ifname)"
	vpnip_local=$(ip -4 -br addr ls dev ${vpnifname} | awk -F'[ /]+' '{print $3}' | tr -d "\n")
	vpnip_remote=$(ip -4 r list dev ${vpnifname} | grep via | grep -v default | grep -v / | grep -v metric | awk '{print $1}' | tr -d "\n")
	for lanip in $c2cips; do
		c2cid=$((c2cid+1))
		targetip=$(echo $lanip | awk -F '/' '{print $1}' | tr -d "\n")
		netmask=$(echo $lanip | awk -F '/' '{print $2}' | tr -d "\n")
		target=$(ipcalc.sh $targetip $netmask | grep NETWORK | awk -F '=' '{print $2}' | tr -d "\n")
		uci -q batch <<-EOF >/dev/null
			set network.omr_client2client_${c2cid}=route
			set network.omr_client2client_${c2cid}.interface=omrvpn
			set network.omr_client2client_${c2cid}.target="${target}"
			set network.omr_client2client_${c2cid}.netmask="${netmask}"
			set network.omr_client2client_${c2cid}.gateway="${vpnip_remote}"
		EOF
	done
	uci -q commit network
}

_vps_firewall_redirect_port() {
	local src proto src_dport
	config_get src $1 src
	config_get proto $1 proto "tcp udp"
	config_get src_dport $1 src_dport
	config_get family $1 family "ipv4"
	config_get enabled $1 enabled "1"
	config_get src_dip $1 src_dip
	[ "$(echo $src_dport | cut -d'-' -f2)" -ge "65000" ] && {
		logger -t "OMR-VPS" "You can't redirect ports >= 65000, they are needed by OpenMPTCProuter Server part"
		uci -q delete firewall.$1
		return
	}
	[ "$src" = "vpn" ] && [ -n "$proto" ] && [ -n "$src_dport" ] && [ "$enabled" != "0" ] && {
		if [ "$proto" = "tcp udp" ]; then
			checkfw=""
			if [ "$family" = "ipv4" ]; then
				if [ "$src_dip" = "" ]; then
					checkfw=$(echo "$vpsfwlist" | grep "$src_dport	# OMR $username redirect router $src_dport port tcp")
				else
					checkfw=$(echo "$vpsfwlist" | grep "# OMR $username redirect router $src_dport port tcp to $src_dip")
				fi
			else
				if [ "$src_dip" = "" ]; then
					checkfw=$(echo "$vpsfw6list" | grep "$src_dport	# OMR $username redirect router $src_dport port tcp")
				else
					checkfw=$(echo "$vpsfw6list" | grep "# OMR $username redirect router $src_dport port tcp to $src_dip")
				fi
			fi
			if [ "$checkfw" = "" ]; then
				settings='{"name" : "router '$src_dport'","port" : "'$src_dport'","source_dip" : "'$src_dip'","proto" : "tcp","fwtype" : "DNAT","ipproto" : "'$family'"}'
				_set_json "shorewallopen" "$settings"
			fi
			if [ "$family" = "ipv4" ]; then
				if [ "$src_dip" = "" ]; then
					vpsfwlist=$(echo "$vpsfwlist" | grep -v "# OMR $username redirect router $src_dport port tcp")
					[ "$username" = "openmptcprouter" ] && vpsfwlist=$(echo "$vpsfwlist" | grep -v "# OMR redirect router $src_dport port tcp")
				else
					vpsfwlist=$(echo "$vpsfwlist" | grep -v "# OMR $username redirect router $src_dport port tcp to $src_dip")
					[ "$username" = "openmptcprouter" ] && vpsfwlist=$(echo "$vpsfwlist" | grep -v "# OMR redirect router $src_dport port tcp to $src_dip")
				fi
			else
				if [ "$src_dip" = "" ]; then
					vpsfw6list=$(echo "$vpsfw6list" | grep -v "# OMR $username redirect router $src_dport port tcp")
					[ "$username" = "openmptcprouter" ] && vpsfw6list=$(echo "$vpsfw6list" | grep -v "# OMR redirect router $src_dport port tcp")
				else
					vpsfw6list=$(echo "$vpsfw6list" | grep -v "# OMR $username redirect router $src_dport port tcp to $src_dip")
					[ "$username" = "openmptcprouter" ] && vpsfw6list=$(echo "$vpsfw6list" | grep -v "# OMR redirect router $src_dport port tcp to $src_dip")
				fi
			fi

			checkfw=""
			if [ "$family" = "ipv4" ]; then
				if [ "$src_dip" = "" ]; then
					checkfw=$(echo "$vpsfwlist" | grep "$src_dport	# OMR $username redirect router $src_dport port udp")
				else
					checkfw=$(echo "$vpsfwlist" | grep "# OMR $username redirect router $src_dport port udp to $src_dip")
				fi
			else
				if [ "$src_dip" = "" ]; then
					checkfw=$(echo "$vpsfw6list" | grep "$src_dport	# OMR $username redirect router $src_dport port udp")
				else
					checkfw=$(echo "$vpsfw6list" | grep "# OMR $username redirect router $src_dport port udp to $src_dip")
				fi
			fi
			if [ "$checkfw" = "" ]; then
				settings='{"name" : "router '$src_dport'","port" : "'$src_dport'","source_dip" : "'$src_dip'","proto" : "udp","fwtype" : "DNAT","ipproto" : "'$family'"}'
				_set_json "shorewallopen" "$settings"
			fi
			if [ "$family" = "ipv4" ]; then
				if [ "$src_dip" = "" ]; then
					vpsfwlist=$(echo "$vpsfwlist" | grep -v "$src_dport	# OMR $username redirect router $src_dport port udp")
					[ "$username" = "openmptcprouter" ] && vpsfwlist=$(echo "$vpsfwlist" | grep -v "$src_dport	# OMR redirect router $src_dport port udp")
				else
					vpsfwlist=$(echo "$vpsfwlist" | grep -v "# OMR $username redirect router $src_dport port udp to $src_dip")
					[ "$username" = "openmptcprouter" ] && vpsfwlist=$(echo "$vpsfwlist" | grep -v "# OMR redirect router $src_dport port udp to $src_dip")
				fi
			else
				if [ "$src_dip" = "" ]; then
					vpsfw6list=$(echo "$vpsfw6list" | grep -v "$src_dport	# OMR $username redirect router $src_dport port udp")
					[ "$username" = "openmptcprouter" ] && vpsfw6list=$(echo "$vpsfw6list" | grep -v "$src_dport	# OMR redirect router $src_dport port udp")
				else
					vpsfw6list=$(echo "$vpsfw6list" | grep -v "# OMR $username redirect router $src_dport port udp to $src_dip")
					[ "$username" = "openmptcprouter" ] && vpsfw6list=$(echo "$vpsfw6list" | grep -v "# OMR redirect router $src_dport port udp to $src_dip")
				fi
			fi
		else
			checkfw=""
			if [ "$family" = "ipv4" ]; then
				if [ "$src_dip" = "" ]; then
					checkfw=$(echo "$vpsfwlist" | grep "$src_dport	# OMR $username redirect router $src_dport port $proto")
				else
					checkfw=$(echo "$vpsfwlist" | grep "# OMR $username redirect router $src_dport port $proto to $src_dip")
				fi
			else
				if [ "$src_dip" = "" ]; then
					checkfw=$(echo "$vpsfw6list" | grep "$src_dport	# OMR $username redirect router $src_dport port $proto")
				else
					checkfw=$(echo "$vpsfw6list" | grep "# OMR $username redirect router $src_dport port $proto to $src_dip")
				fi
			fi
			if [ "$checkfw" = "" ]; then
				settings='{"name" : "router '$src_dport'","port" : "'$src_dport'","source_dip" : "'$src_dip'","proto" : "'$proto'","fwtype" : "DNAT","ipproto" : "'$family'"}'
				_set_json "shorewallopen" "$settings"
			fi
			if [ "$family" = "ipv4" ]; then
				if [ "$src_dip" = "" ]; then
					vpsfwlist=$(echo "$vpsfwlist" | grep -v "$src_dport	# OMR $username redirect router $src_dport port $proto")
					[ "$username" = "openmptcprouter" ] && vpsfwlist=$(echo "$vpsfwlist" | grep -v "$src_dport	# OMR redirect router $src_dport port $proto")
				else
					vpsfwlist=$(echo "$vpsfwlist" | grep -v "# OMR $username redirect router $src_dport port $proto to $src_dip")
					[ "$username" = "openmptcprouter" ] && vpsfwlist=$(echo "$vpsfwlist" | grep -v "# OMR redirect router $src_dport port $proto to $src_dip")
				fi
			else
				if [ "$src_dip" = "" ]; then
					vpsfw6list=$(echo "$vpsfw6list" | grep -v "$src_dport	# OMR $username redirect router $src_dport port $proto")
					[ "$username" = "openmptcprouter" ] && vpsfw6list=$(echo "$vpsfw6list" | grep -v "$src_dport	# OMR redirect router $src_dport port $proto")
				else
					vpsfw6list=$(echo "$vpsfw6list" | grep -v "# OMR $username redirect router $src_dport port $proto to $src_dip")
					[ "$username" = "openmptcprouter" ] && vpsfw6list=$(echo "$vpsfw6list" | grep -v "# OMR redirect router $src_dport port $proto to $src_dip")
				fi
			fi
		fi
	}
}

_vps_firewall_close_port() {
	[ -n "$vpsfwlist" ] && {
		echo "$vpsfwlist" | while read -r line; do
			[ -n "$line" ] && {
				proto=$(echo $line | awk '{print $4}')
				src_dport=$(echo $line | awk '{print $5}')
				settings='{"name" : "router '$src_dport'","port" : "'$src_dport'","proto" : "'$proto'","fwtype" : "DNAT"}'
				_set_json "shorewallclose" "$settings"
			}
		done
	}
	[ -n "$vpsfw6list" ] && {
		echo "$vpsfw6list" | while read -r line; do
			[ -n "$line" ] && {
				proto=$(echo $line | awk '{print $4}')
				src_dport=$(echo $line | awk '{print $5}')
				settings='{"name" : "router '$src_dport'","port" : "'$src_dport'","proto" : "'$proto'","fwtype" : "DNAT","ipproto" : "ipv6"}'
				_set_json "shorewallclose" "$settings"
			}
		done
	}
}

_set_vps_firewall() {
	fwservername=$1
	[ -z "$servername" ] && servername=$fwservername
	[ -z "$fwservername" ] && fwservername=$servername
	[ "$(uci -q get openmptcprouter.${fwservername}.nofwredirect)" = "1" ] && return
	[ -z "$(uci -q get openmptcprouter.${fwservername}.username)" ] && return
	[ -z "$(uci -q get openmptcprouter.${fwservername}.password)" ] && return
	[ -z "$(uci -q get openmptcprouter.${fwservername}.port)" ] && return
	token=""
	vps_config=""
	_login
	[ -z "$token" ] && {
		logger -t "OMR-VPS" "Can't get token, try later"
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.${fwservername}.admin_error=1
		EOF
		return
	}
	username="$(uci -q get openmptcprouter.${fwservername}.username)"
	settings='{"name" : "redirect router"}'
	fw_list=$(_set_json "shorewalllist" "$settings")
	vpsfwlist=$(echo $fw_list | jsonfilter -q -e '@.list[*]' | sed '/^[[:space:]]*$/d')
	settings='{"name" : "redirect router","ipproto" : "ipv6"}'
	fw6_list=$(_set_json "shorewalllist" "$settings")
	vpsfw6list=$(echo $fw6_list | jsonfilter -q -e '@.list[*]' | sed '/^[[:space:]]*$/d')
	config_load firewall
	config_foreach _vps_firewall_redirect_port redirect
	[ -n "$vpsfwlist" ] || [ -n "$vpsfw6list" ] && {
		logger -t "OMR-VPS" "Remove old firewall rules"
		_vps_firewall_close_port
	}
}

set_vps_firewall() {
	fw3 -q print | grep 'vpn.* -d' |
	while IFS=$"\n" read -r c; do
		eval $(echo $c | sed 's/-A/-D/')
		newrule=$(echo $c | sed -E -e 's/ -d ([^ ])*//' -e 's/ -s ([^ ])*//')
		eval $(echo $newrule | sed 's/-A/-C/') || eval $newrule
	done
	#'
	config_load openmptcprouter
	config_foreach _set_vps_firewall server
}

_set_ss_redir() {
	local option=$2
	local value=$3
	if [ "$value" = "true" ]; then
		value=1
	elif [ "$value" = "false" ]; then
		value=0
	fi
	uci -q set shadowsocks-libev.$1.$option=$value
}

_set_ss_server() {
	local option=$2
	local value=$3
	if [ "$value" = "true" ]; then
		value=1
	elif [ "$value" = "false" ]; then
		value=0
	fi
	[ "$(echo $1 | grep omr)" != "" ] && uci -q set shadowsocks-libev.$1.$option=$value
}

_set_config_from_vps() {
	local shadowsocks_disabled vpn glorytun_state redirect shorewall_redirect mlvpn_key openvpn_key dsvpn_key
	[ -z "$vps_config" ] && vps_config=$(_get_json "config")
	[ -z "$vps_config" ] && return

	logger -t "OMR-VPS" "Get config from VPS..."
	noerror=1
	# get VPS ip
	vpsip="$(uci -q get openmptcprouter.${servername}.ip)"
	vps_lastchange="$(echo "$vps_config" | jsonfilter -q -e '@.vps.lastchange')"
	user_permission="$(echo "$vps_config" | jsonfilter -q -e '@.user.permission')"
	[ -z "$user_permission" ] && user_permission="rw"

	vpsinternet="$(echo "$vps_config" | jsonfilter -q -e '@.network.internet')"
	if [ "$vpsinternet" = "false" ] && [ "$(uci -q get openmptcprouter.settings.external_check)" != "0" ]; then
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.settings.external_check='0'
		EOF
		logger -t "OMR-VPS" "OMR-Tracker restart..."
		/etc/init.d/omr-tracker restart
	fi

	ula="$(echo "$vps_config" | jsonfilter -q -e '@.ip6in4.ula')"
	if [ -n "$ula" ] && [[ "$ula" != *" "* ]]; then
		uci -q batch <<-EOF >/dev/null
		set network.globals.ula_prefix=$ula
		EOF
	fi

	# Set current VPN
	current_vpn="$(uci -q get openmptcprouter.settings.vpn)"
	if [ -z "$current_vpn" ] || [ -n "$vps_lastchange" ] || [ "$user_permission" = "ro" ]; then
		current_vpn="$(echo "$vps_config" | jsonfilter -q -e '@.vpn.current')"
		if [ -n "$current_vpn" ]; then
			uci -q batch <<-EOF >/dev/null
			set openmptcprouter.settings.vpn=${current_vpn}
			commit openmptcprouter
			EOF
		fi
	fi

	# Shadowsocks settings
	shadowsocks_disabled="$(uci -q get openmptcprouter.settings.shadowsocks_disable)"
	[ -z "$shadowsocks_disabled" ] && shadowsocks_disabled=0
	ss_key="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.key')"
	ss_key="$(echo $ss_key | sed 's/-/+/g; s/_/\//g;')"
	if [ -n "$ss_key" ] && [ "$ss_key" != "$(uci -q get shadowsocks-libev.sss0.key)" ]; then
		ss_method="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.method')"
		ss_port="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.port')"
		ss_ebpf="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.ebpf')"
		if [ "$ss_ebpf" = "true" ] && [ "$ss_method" = "none" ]; then
			ss_ebpf=1
		else
			ss_ebpf=0
		fi
		[ -z "$ss_port" ] && ss_port=65101
		ss_no_delay="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.no_delay')"
		ss_fast_open="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.fast_open')"
		ss_obfs="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.obfs')"
		if [ "$ss_obfs" = "true" ]; then
			ss_obfs=1
		else
			ss_obfs=0
		fi
		ss_obfs_plugin="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.obfs_plugin')"
		ss_obfs_type="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.obfs_type')"
		ss_obfs_host="$(echo "$vps_config" | jsonfilter -q -e '@.network.domain')"
		#ss_reuse_port="$(echo "$vps_config" | jsonfilter -q -e '@.shadowsocks.reuse_port')"
		config_load shadowsocks-libev
		config_foreach _set_ss_redir ss_redir "no_delay" $ss_no_delay
		config_foreach _set_ss_redir ss_redir "fast_open" $ss_fast_open
		config_foreach _set_ss_redir ss_redir "ebpf" $ss_ebpf
		config_foreach _set_ss_redir ss_local "no_delay" $ss_no_delay
		config_foreach _set_ss_redir ss_local "fast_open" $ss_fast_open
		config_foreach _set_ss_redir ss_local "ebpf" $ss_ebpf
		uci -q batch <<-EOF >/dev/null
			set shadowsocks-libev.sss0.key=$ss_key
			set shadowsocks-libev.sss0.server_port=$ss_port
			set shadowsocks-libev.sss0.method=$ss_method
			set shadowsocks-libev.sss0.disabled=$shadowsocks_disabled
			set shadowsocks-libev.sss0.obfs=$ss_obfs
			set shadowsocks-libev.sss0.obfs_plugin=$ss_obfs_plugin
			set shadowsocks-libev.sss0.obfs_type=$ss_obfs_type
			set shadowsocks-libev.sss0.obfs_host=$ss_obfs_host
		EOF
		config_foreach _set_ss_server server "key" $ss_key
		config_foreach _set_ss_server server "method" $ss_method
		config_foreach _set_ss_server server "obfs" $ss_obfs
		config_foreach _set_ss_server server "obfs_plugin" $ss_obfs_plugin
		config_foreach _set_ss_server server "obfs_type" $ss_obfs_type
		config_foreach _set_ss_server server "obfs_host" $ss_obfs_host
		if [ "$(uci -q get shadowsocks-libev.sss0.server)" != "127.0.0.1" ]; then
			config_foreach _set_ss_server server "server" $vpsip
		fi
		uci -q commit shadowsocks-libev
		logger -t "OMR-VPS" "Shadowsocks restart..."
		/etc/init.d/shadowsocks-libev restart >/dev/null 2>&1
	fi

	# Glorytun settings
	glorytun_key="$(echo "$vps_config" | jsonfilter -q -e '@.glorytun.key')"
	glorytun_port="$(echo "$vps_config" | jsonfilter -q -e '@.glorytun.port')"
	if ([ -n "$glorytun_key" ] && [ "$glorytun_key" != "$(uci -q get glorytun.vpn.key)" ]) || ([ -n "$glorytun_port" ] || [ "$glorytun_port" != "$(uci -q get glorytun.vpn.port)" ]); then
		vpn="$(uci -q get openmptcprouter.settings.vpn)"
		glorytun_state=0
		if [ "$vpn" = "glorytun_tcp" ]; then
			glorytun_state=1
		fi
		if [ "$vpn" = "glorytun_udp" ]; then
			glorytun_state=1
		fi
		[ -z "$glorytun_port" ] && glorytun_port="65001"
		glorytun_chacha="$(echo "$vps_config" | jsonfilter -q -e '@.glorytun.chacha')"
		[ -z "$glorytun_chacha" ] || [ "$glorytun_chacha" = "true" ] && glorytun_chacha=1
		[ "$glorytun_chacha" = "false" ] && glorytun_chacha=0
		uci -q batch <<-EOF >/dev/null
			set glorytun.vpn.port=$glorytun_port
			set glorytun.vpn.key=$glorytun_key
			set glorytun.vpn.enable=$glorytun_state
			set glorytun.vpn.chacha20=$glorytun_chacha
		EOF
		if [ "$(uci -q get glorytun.vpn.host)" != "127.0.0.1" ]; then
			uci -q set glorytun.vpn.host="$vpsip"
		fi
		uci -q commit glorytun
		logger -t "OMR-VPS" "Glorytun restart..."
		/etc/init.d/glorytun restart >/dev/null 2>&1
		/etc/init.d/glorytun-udp restart >/dev/null 2>&1
	fi

	# OpenVPN settings
	openvpn_key="$(echo "$vps_config" | jsonfilter -q -e '@.openvpn.key')"
	[ -n "$openvpn_key" ] && {
		echo $openvpn_key | base64 -d > /etc/luci-uploads/openvpn.key
		openvpn_port="$(echo "$vps_config" | jsonfilter -q -e '@.openvpn.port')"
		[ -z "$openvpn_port" ] && openvpn_port="65001"
		vpn="$(uci -q get openmptcprouter.settings.vpn)"
		openvpn_state=0
		if [ "$vpn" = "openvpn" ]; then
			openvpn_state=1
		fi
		uci -q batch <<-EOF >/dev/null
			set openvpn.omr.port=$openvpn_port
			set openvpn.omr.secret="/etc/luci-uploads/openvpn.key"
			set openvpn.omr.enabled=$openvpn_state
		EOF
		if [ "$(uci -q get openvpn.omr.remote)" != "127.0.0.1" ]; then
			uci -q set openvpn.omr.remote="$vpsip"
		fi
		uci -q commit openvpn
		logger -t "OMR-VPS" "OpenVPN restart..."
		/etc/init.d/openvpn restart
	}
	openvpn_client_key="$(echo "$vps_config" | jsonfilter -q -e '@.openvpn.client_key')"
	[ -n "$openvpn_client_key" ] && {
		echo $openvpn_client_key | base64 -d > /etc/luci-uploads/client.key
	}
	openvpn_client_crt="$(echo "$vps_config" | jsonfilter -q -e '@.openvpn.client_crt')"
	[ -n "$openvpn_client_crt" ] && {
		echo $openvpn_client_crt | base64 -d > /etc/luci-uploads/client.crt
	}
	openvpn_client_ca="$(echo "$vps_config" | jsonfilter -q -e '@.openvpn.client_ca')"
	[ -n "$openvpn_client_ca" ] && {
		echo $openvpn_client_ca | base64 -d > /etc/luci-uploads/ca.crt
	}
	[ -n "$openvpn_client_key" ] && [ -n "$openvpn_client_crt" ] && [ -n "$openvpn_client_ca" ] && {
		openvpn_port="$(echo "$vps_config" | jsonfilter -q -e '@.openvpn.port')"
		[ -z "$openvpn_port" ] && openvpn_port="65001"
		vpn="$(uci -q get openmptcprouter.settings.vpn)"
		openvpn_state=0
		if [ "$vpn" = "openvpn" ]; then
			openvpn_state=1
		fi
		uci -q batch <<-EOF >/dev/null
			set openvpn.omr.port=$openvpn_port
			set openvpn.omr.key="/etc/luci-uploads/client.key"
			set openvpn.omr.cert="/etc/luci-uploads/client.crt"
			set openvpn.omr.ca="/etc/luci-uploads/ca.crt"
			set openvpn.omr.enabled=$openvpn_state
			set openvpn.omr.tls_client=1
			set openvpn.omr.client=1
			set openvpn.omr.allow_recursive_routing=1
		EOF
		if [ "$(uci -q get openvpn.omr.remote)" != "127.0.0.1" ]; then
			uci -q set openvpn.omr.remote="$vpsip"
		fi
		uci -q commit openvpn
		logger -t "OMR-VPS" "OpenVPN restart..."
		/etc/init.d/openvpn restart
	}

	# MLVPN settings
	mlvpn_key="$(echo "$vps_config" | jsonfilter -q -e '@.mlvpn.key')"
	if [ -n "$mlvpn_key" ] && [ "$mlvpn_key" != "$(uci -q get mlvpn.general.password)" ] && [ -f /etc/init.d/mlvpn ]; then
		vpn="$(uci -q get openmptcprouter.settings.vpn)"
		mlvpn_state=0
		if [ "$vpn" = "mlvpn" ]; then
			mlvpn_state=1
		fi
		uci -q batch <<-EOF >/dev/null
			set mlvpn.general.password=$mlvpn_key
			set mlvpn.general.enable=$mlvpn_state
			commit mlvpn
		EOF
		if [ "$(uci -q get mlvpn.general.host)" != "127.0.0.1" ]; then
			uci -q set mlvpn.general.host="$vpsip"
		fi
		uci -q commit mlvpn
		logger -t "OMR-VPS" "MLVPN restart..."
		/etc/init.d/mlvpn restart
	fi

	# DSVPN settings
	dsvpn_key="$(echo "$vps_config" | jsonfilter -q -e '@.dsvpn.key')"
	dsvpn_port="$(echo "$vps_config" | jsonfilter -q -e '@.dsvpn.port')"
	if ([ -n "$dsvpn_key" ] && [ "$dsvpn_key" != "$(uci -q get dsvpn.vpn.key)" ]) || ([ -n "$dsvpn_port" ] && [ "$dsvpn_port" != "$(uci -q get dsvpn.vpn.port)" ]); then
		dsvpn_state=0
		if [ "$vpn" = "dsvpn" ]; then
			dsvpn_state=1
		fi
		uci -q batch <<-EOF >/dev/null
			set dsvpn.vpn.key=$dsvpn_key
			set dsvpn.vpn.enable=$dsvpn_state
			set dsvpn.vpn.port=$dsvpn_port
			commit dsvpn
		EOF
		if [ "$(uci -q get dsvpn.vpn.host)" != "127.0.0.1" ]; then
			uci -q set dsvpn.vpn.host="$vpsip"
		fi
		uci -q commit dsvpn
		logger -t "OMR-VPS" "DSVPN restart..."
		/etc/init.d/dsvpn restart
	fi

	# Shorewall settings
	shorewall_redirect="$(echo "$vps_config" | jsonfilter -q -e '@.shorewall.redirect_ports')"
	[ "$shorewall_redirect" = "enable" ] && redirect="1"
	[ "$shorewall_redirect" = "disable" ] && redirect="0"
	uci -q batch <<-EOF >/dev/null
		set openmptcprouter.${servername}.redirect_ports=$redirect
	EOF

	# MPTCP settings
	mptcp_path_manager="$(echo "$vps_config" | jsonfilter -q -e '@.mptcp.path_manager')"
	mptcp_scheduler="$(echo "$vps_config" | jsonfilter -q -e '@.mptcp.scheduler')"
	mptcp_checksum="$(echo "$vps_config" | jsonfilter -q -e '@.mptcp.checksum')"
	mptcp_syn_retries="$(echo "$vps_config" | jsonfilter -q -e '@.mptcp.syn_retries')"
	mptcp_enabled="$(echo "$vps_config" | jsonfilter -q -e '@.mptcp.enabled')"
	if [ "$mptcp_enabled" = "0" ]; then
		mptcp_enabled="disable"
	else
		mptcp_enabled="enable"
	fi
	congestion="$(echo "$vps_config" | jsonfilter -q -e '@.network.congestion_control')"
	uci -q batch <<-EOF >/dev/null
		set network.globals.multipath=$mptcp_enabled
		set network.globals.mptcp_path_manager=$mptcp_path_manager
		set network.globals.mptcp_scheduler=$mptcp_scheduler
		set network.globals.mptcp_checksum=$mptcp_checksum
		set network.globals.mptcp_syn_retries=$mptcp_syn_retries
		set network.globals.congestion=$congestion
		commit network
	EOF

	# Check if server get an IPv6, if not disable IPv6 on OMR
	vps_ipv6_addr="$(echo "$vps_config" | jsonfilter -q -e '@.network.ipv6')"
	if [ -z "$vps_ipv6_addr" ]; then
		if [ "$(uci -q get openmptcprouter.settings.disable_ipv6)" = "0" ]; then
			logger -t "OMR-VPS" "No IPv6 support on VPS side. IPv6 disabled."
		fi
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.settings.disable_ipv6=1
		EOF
		sysctl -qw net.ipv6.conf.all.disable_ipv6=1
	else
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.${servername}.ipv6=$vps_ipv6_addr
		EOF
	fi

	omr6in4_vps_localip="$(echo "$vps_config" | jsonfilter -q -e '@.ip6in4.localip')"
	omr6in4_vps_remoteip="$(echo "$vps_config" | jsonfilter -q -e '@.ip6in4.remoteip')"
	if ([ -n "$omr6in4_vps_localip" ] && [ "$omr6in4_vps_localip" != "$(uci -q get network.omr6in4.gateway)" ]) || ([ -n "$omr6in4_vps_remoteip" ] && [ "$omr6in4_vps_remoteip" != "$(uci -q get network.omr6in4.ip6addr)" ]); then
		logger -t "OMR-VPS" "Set omr6in4 ip address and gateway"
		uci -q batch <<-EOF >/dev/null
			set network.omr6in4.ip6addr="$omr6in4_vps_remoteip"
			set network.omr6in4.gateway="$omr6in4_vps_localip"
			commit network
		EOF
		/etc/init.d/network restart
		sleep 6
	fi

	# Get VPS iperf config
	iperf_user="$(echo "$vps_config" | jsonfilter -q -e '@.iperf.user')"
	iperf_pass="$(echo "$vps_config" | jsonfilter -q -e '@.iperf.password')"
	iperf_key="$(echo "$vps_config" | jsonfilter -q -e '@.iperf.key')"
	uci -q batch <<-EOF >/dev/null
		del iperf.${servername}
		set iperf.${servername}=server
		set iperf.${servername}.host=$server
		set iperf.${servername}.ports=65400
		set iperf.${servername}.ipv4=1
		set iperf.${servername}.ipv6=0
		set iperf.${servername}.speed=1000
		set iperf.${servername}.tcp=1
		set iperf.${servername}.udp=1
		set iperf.${servername}.user=$iperf_user
		set iperf.${servername}.password=$iperf_pass
		set iperf.${servername}.key="$iperf_key"
		commit iperf
	EOF

	# Get available server
	available_vpn="$(echo "$vps_config" | jsonfilter -q -e '@.vpn.available' | sed -e 's/\[ //' -e 's/ \]//' -e 's/,//g')"
	uci -q batch <<-EOF >/dev/null
		del openmptcprouter.${servername}.available_vpn
	EOF

	if [ "$user_permission" = "ro" ]; then
		current_vpn="$(echo "$vps_config" | jsonfilter -q -e '@.vpn.current')"
		if [ -n "$current_vpn" ]; then
			uci -q batch <<-EOF >/dev/null
				set openmptcprouter.${servername}.available_vpn=${current_vpn}
			EOF
		fi
	
	else
		if [ -n "$available_vpn" ]; then
			for vpn in $available_vpn; do
				uci -q batch <<-EOF >/dev/null
					add_list openmptcprouter.${servername}.available_vpn=$vpn
				EOF
			done
		fi
	fi
	if [ "$noerror" = "1" ]; then
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.${servername}.get_config=0
			commit openmptcprouter
		EOF
	fi
}

_backup_send() {
	servername=$1
	[ -z "$(uci -q get openmptcprouter.${servername}.username)" ] && return
	[ -z "$(uci -q get openmptcprouter.${servername}.password)" ] && return
	[ -z "$(uci -q get openmptcprouter.${servername}.port)" ] && return
	token=""
	vps_config=""
	_login
	[ -z "$token" ] && {
		logger -t "OMR-VPS" "Can't get token, try later"
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.${servername}.admin_error=1
		EOF
		return
	}
	sysupgrade -b /tmp/backup.tar.gz
	backup_data="$(cat /tmp/backup.tar.gz | base64 | tr -d '\n')"
	backup_sha256sum="$(sha256sum /tmp/backup.tar.gz | awk '{print $1}')"
	[ -n "$backup_data" ] && {
		logger -t "OMR-VPS" "Send backup file to server"
		local backupjson
		backupjson='{"data": "'$backup_data'","sha256sum": "'$backup_sha256sum'"}'
		_set_json "backuppost" "$backupjson"
	}
}

backup_send() {
	config_load openmptcprouter
	config_foreach _backup_send server
}


_backup_get() {
	servername=$1
	[ -z "$(uci -q get openmptcprouter.${servername}.username)" ] && return
	[ -z "$(uci -q get openmptcprouter.${servername}.password)" ] && return
	[ -z "$(uci -q get openmptcprouter.${servername}.port)" ] && return
	[ -z "$lastbackup" ] || [ "$lastbackup" -lt "$(uci -q get openmptcprouter.$servername.lastbackup)" ] && {
		lastbackup="$(uci -q get openmptcprouter.$servername.lastbackup)"
		serverbackup="$servername"
	}
}

_backup_get_and_apply() {
	servername=$1
	token=""
	vps_config=""
	_login
	[ -z "$token" ] && {
		logger -t "OMR-VPS" "Can't get token, try later"
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.${servername}.admin_error=1
		EOF
		return
	}
	vps_backup=$(_get_json "backupget")
	[ -z "$vps_backup" ] && return
	backup_data="$(echo "$vps_backup" | jsonfilter -q -e '@.data')"
	backup_sha256sum="$(echo "$vps_backup" | jsonfilter -q -e '@.sha256sum')"
	[ -n "$backup_data" ] && {
		echo $backup_data | base64 -d > /tmp/backup.tar.gz
		sysupgrade -t /tmp/backup.tar.gz
	}
}

backup_get() {
	lastbackup=""
	serverbackup=""
	config_load openmptcprouter
	config_foreach _backup_get server
	[ -n "$serverbackup" ] && _backup_get_and_apply $serverbackup
}

_backup_list() {
	bservername=$1
	[ -z "$servername" ] && servername=$bservername
	[ -z "$(uci -q get openmptcprouter.${servername}.username)" ] && return
	[ -z "$(uci -q get openmptcprouter.${servername}.password)" ] && return
	[ -z "$(uci -q get openmptcprouter.${servername}.port)" ] && return
	token=""
	vps_config=""
	_login
	[ -z "$token" ] && {
		logger -t "OMR-VPS" "Can't get token, try later"
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.${servername}.admin_error=1
		EOF
		return
	}
	vps_backup=$(_get_json "backuplist")
	[ -z "$vps_backup" ] && return
	backup_lastmodif="$(echo "$vps_backup" | jsonfilter -q -e '@.modif')"
	[ -n "$backup_lastmodif" ] && {
		uci -q set openmptcprouter.$servername.lastbackup=$backup_lastmodif
	}
}



backup_list() {
	config_load openmptcprouter
	config_foreach _backup_list server
	uci -q commit openmptcprouter
}


_count_server() {
	local servername=$1
	[ -z "$(uci -q get openmptcprouter.${servername}.username)" ] && return
	[ -z "$(uci -q get openmptcprouter.${servername}.password)" ] && return
	[ -z "$(uci -q get openmptcprouter.${servername}.port)" ] && return
	serversnb=$((serversnb+1))
}

_config_service() {
	servername=$1
	[ -z "$(uci -q get openmptcprouter.${servername}.username)" ] && return
	[ -z "$(uci -q get openmptcprouter.${servername}.password)" ] && return
	[ -z "$(uci -q get openmptcprouter.${servername}.port)" ] && return
	[ -z "$(uci -q get openmptcprouter.${servername}.ip)" ] && return
	token=""
	vps_config=""
	_login
	[ -z "$token" ] && {
		reason=""
		_ping_server
		status=$?
		if $(exit $status); then
			reason="can ping server"
		else
			reason="can't ping server"
		fi
		port="$(uci -q get openmptcprouter.${servername}.port)"
		server="$(uci -q get openmptcprouter.${servername}.ip)"
		if [ "$(curl -k -m 3 https://${server}:${port}/)" = "" ]; then
			reason="$reason, no server API answer"
		else
			reason="$reason, server API answer"
		fi
		if [ "$(uci -q get openmptcprouter.${servername}.username)" != "openmptcprouter" ]; then
			reason="$reason, custom username"
		fi
		logger -t "OMR-VPS" "Can't get token, try later ($reason)"
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.${servername}.admin_error=1
		EOF
		return
	}
	error=0
	[ "$(uci -q get openmptcprouter.${servername}.get_config)" = "1" ] && {
		_set_config_from_vps
		_get_gre_tunnel
	}

	_get_vps_config
	[ -z "$vps_config" ] && vps_config=$(_get_json "config")
	user_permission="$(echo "$vps_config" | jsonfilter -q -e '@.user.permission')"

	if [ "$(uci -q get openmptcprouter.settings.firstboot)" != "0" ]; then
		[ -n "$vps_config" ] && [ -n "$(cat /proc/cpuinfo | grep aes)" ] && {
			vps_aes="$(echo "$vps_config" | jsonfilter -q -e '@.vps.aes')"
			if [ "$vps_aes" != "false" ] && [ "$user_permission" != "ro" ]; then
				logger -t "OMR-VPS" "CPU support AES, set it by default"
				uci -q batch <<-EOF >/dev/null
					set glorytun.vpn.chacha20="0"
					commit glorytun
				EOF
				config_foreach _set_ss_server server "method" "aes-256-gcm"
				uci -q commit shadowsocks-libev
			fi
		}
		[ -n "$vps_config" ] && uci -q set openmptcprouter.settings.firstboot=0
	fi
	if [ "$user_permission" != "ro" ]; then
		config_load shadowsocks-libev
		config_foreach _set_ss_server_vps server
		[ -z "$(_set_glorytun_vps)" ] && error=1
		[ -z "$(_set_openvpn_vps)" ] && error=1
		_set_vps_firewall
	fi
	_backup_list
	redirect_port="0"
	if [ "$(uci -q get openmptcprouter.${servername}.redirect_ports)" = "1" ] || [ "$(uci -q get upnpd.config.enabled)" = "1" ]; then
		redirect_port="1"
	fi
	if [ "$user_permission" != "ro" ]; then
		[ -z "$(_set_redirect_ports_from_vps $redirect_port)" ] && error=1
		[ -z "$(_set_mptcp_vps)" ] && error=1
		[ -z "$(_set_vpn_vps)" ] && error=1
	fi
	[ "$(uci -q get shadowsocks-libev.sss0.key)" = "" ] && uci -q set openmptcprouter.${servername}.get_config=1
	
	#_set_pihole
	[ -n "$wanips" ] && _set_wan_ip
	_set_lan_ip
	_set_vpn_ip
	config_load network
	config_foreach _delete_client2client route
	if [ "$(uci -q get openmptcprouter.settings.vpn)" != "openvpn" ] && [ "$(echo "$vps_config" | jsonfilter -q -e '@.client2client.enabled')" == "true" ]; then
		_set_client2client
	fi
	[ "$error" = 0 ] && {
		#logger -t "OMR-VPS" "No errors"
		uci -q set openmptcprouter.${servername}.lastchange=$(date "+%s")
	}
	#[ "$error" != 0 ] && logger -t "OMR-VPS" "Error !"
	uci -q batch <<-EOF >/dev/null
		set openmptcprouter.${servername}.admin_error=$error
		commit openmptcprouter
	EOF
}

_set_pihole_server() {
	pservername=$1
	[ -z "$servername" ] && servername=$pservername
	[ -z "$(uci -q get openmptcprouter.${pservername}.username)" ] && return
	[ -z "$(uci -q get openmptcprouter.${pservername}.password)" ] && return
	[ -z "$(uci -q get openmptcprouter.${pservername}.port)" ] && return
	token=""
	vps_config=""
	_login
	[ -z "$token" ] && {
		logger -t "OMR-VPS" "Can't get token, try later"
		uci -q batch <<-EOF >/dev/null
			set openmptcprouter.${pservername}.admin_error=1
		EOF
		return
	}
	_get_pihole $pservername
}

set_pihole() {
	config_load openmptcprouter
	config_foreach _set_pihole_server server
}

start_service() {
	serversnb=0
	wanips=""
	config_load openmptcprouter
	config_foreach _count_server server
	config_foreach _get_local_wan_ip interface
	config_foreach _config_service server

	uci -q batch <<-EOF >/dev/null
		commit openmptcprouter
	EOF
}

service_triggers() {
	procd_add_reload_trigger openmptcprouter shadowsocks-libev glorytun mlvpn openvpn network upnpd dsvpn
	#procd_add_reload_trigger openmptcprouter shadowsocks-libev network upnpd
}