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

START=99

CONFIG="luci-app-ipsec-server"
IPSEC_SECRETS_FILE=/etc/ipsec.secrets
IPSEC_CONN_FILE=/etc/ipsec.conf
CHAP_SECRETS=/etc/ppp/chap-secrets
L2TP_PATH=/var/etc/xl2tpd
L2TP_CONTROL_FILE=${L2TP_PATH}/control
L2TP_CONFIG_FILE=${L2TP_PATH}/xl2tpd.conf
L2TP_OPTIONS_FILE=${L2TP_PATH}/options.xl2tpd
L2TP_LOG_FILE=${L2TP_PATH}/xl2tpd.log

ipt_comment="IPSec VPN Server"

init_config() {
	vt_type=$(uci -q get ${CONFIG}.@service[0].type)
	vt_clientip=$(uci -q get ${CONFIG}.@service[0].clientip)
	l2tp_localip=$(uci -q get ${CONFIG}.@service[0].l2tp_localip)
}

get_enabled_anonymous_secs() {
	uci -q show "${CONFIG}" | grep "${1}\[.*\.enabled='1'" | cut -d '.' -sf2
}

ipt_rule() {
	if [ "$1" = "add" ]; then
		iptables -w -t mangle -I OUTPUT -p udp -m multiport --sports 500,4500 -m comment --comment "${ipt_comment}" -j RETURN 2>/dev/null
		iptables -w -I input_rule -p udp -m multiport --dports 500,4500 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
		iptables -w -I forwarding_rule -m policy --dir in --pol ipsec --proto esp -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
		iptables -w -I forwarding_rule -m policy --dir out --pol ipsec --proto esp -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null

		ip6tables -w -t mangle -I OUTPUT -p udp -m multiport --sports 500,4500 -m comment --comment "${ipt_comment}" -j RETURN 2>/dev/null
		ip6tables -w -I input_rule -p udp -m multiport --dports 500,4500 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
		ip6tables -w -I forwarding_rule -m policy --dir in --pol ipsec --proto esp -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
		ip6tables -w -I forwarding_rule -m policy --dir out --pol ipsec --proto esp -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null

		if [ "${vt_type}" = "L2TP" ]; then
			iptables -w -t mangle -I OUTPUT -p udp --sport 1701 -m comment --comment "${ipt_comment}" -j RETURN 2>/dev/null
			iptables -w -I input_rule -p udp --dport 1701 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
			iptables -w -I input_rule -s ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
			iptables -w -I input_rule -d ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
			iptables -w -I forwarding_rule -s ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
			iptables -w -I forwarding_rule -d ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
			iptables -w -I output_rule -s ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
			iptables -w -I output_rule -d ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
			iptables -w -t nat -I postrouting_rule -s ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j FULLCONENAT 2>/dev/null
			[ "$?" != "0" ] && iptables -w -t nat -I postrouting_rule -s ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j MASQUERADE 2>/dev/null
			iptables -w -t nat -I postrouting_rule -d ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j FULLCONENAT 2>/dev/null
			[ "$?" != "0" ] && iptables -w -t nat -I postrouting_rule -d ${l2tp_localip%.*}.0/24 -m comment --comment "${ipt_comment}" -j MASQUERADE 2>/dev/null
		else
			iptables -w -I input_rule -s ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
			iptables -w -I input_rule -d ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
			iptables -w -I forwarding_rule -s ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
			iptables -w -I forwarding_rule -d ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
			iptables -w -I output_rule -s ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
			iptables -w -I output_rule -d ${vt_clientip} -m comment --comment "${ipt_comment}" -j ACCEPT 2>/dev/null
			iptables -w -t nat -I postrouting_rule -s ${vt_clientip} -m comment --comment "${ipt_comment}" -j FULLCONENAT 2>/dev/null
			[ "$?" != "0" ] && iptables -w -t nat -I postrouting_rule -s ${vt_clientip} -m comment --comment "${ipt_comment}" -j MASQUERADE 2>/dev/null
			iptables -w -t nat -I postrouting_rule -d ${vt_clientip} -m comment --comment "${ipt_comment}" -j FULLCONENAT 2>/dev/null
			[ "$?" != "0" ] && iptables -w -t nat -I postrouting_rule -d ${vt_clientip} -m comment --comment "${ipt_comment}" -j MASQUERADE 2>/dev/null
			

			uci -q batch <<-EOF >/dev/null
				delete network.ipsec_server
				set network.ipsec_server=interface
				set network.ipsec_server.ifname="ipsec0"
				set network.ipsec_server.device="ipsec0"
				set network.ipsec_server.proto="static"
				set network.ipsec_server.ipaddr="${vt_clientip%.*}.1"
				set network.ipsec_server.netmask="255.255.255.0"
				commit network
			EOF
		fi
	else
		ipt_del() {
			for i in $(seq 1 $($1 -nL $2 | grep -c "${ipt_comment}")); do
				local index=$($1 --line-number -nL $2 | grep "${ipt_comment}" | head -1 | awk '{print $1}')
				$1 -w -D $2 $index 2>/dev/null
			done
		}
		ipt_del "iptables -w" "input_rule"
		ipt_del "iptables -w" "forwarding_rule"
		ipt_del "iptables -w" "output_rule"
		ipt_del "iptables -w -t nat" "postrouting_rule"
		ipt_del "iptables -w -t mangle" "OUTPUT"
		ipt_del "ip6tables -w" "input_rule"
		ipt_del "ip6tables -w" "forwarding_rule"
		ipt_del "ip6tables -w -t mangle" "OUTPUT"
		uci -q batch <<-EOF >/dev/null
			delete network.ipsec_server
			commit network
		EOF
		ifup ipsec_server > /dev/null 2>&1
	fi
}

gen_include() {
	echo '#!/bin/sh' > /var/etc/ipsecvpn.include
	extract_rules() {
		echo "*$1"
		iptables-save -t $1 | grep "${ipt_comment}" | \
		sed -e "s/^-A \(INPUT\)/-I \1 1/"
		echo 'COMMIT'
	}
	extract_rules6() {
		echo "*$1"
		ip6tables-save -t $1 | grep "${ipt_comment}" | \
		sed -e "s/^-A \(INPUT\)/-I \1 1/"
		echo 'COMMIT'
	}
	cat <<-EOF >> /var/etc/ipsecvpn.include
		iptables-save -c | grep -v "${ipt_comment}" | iptables-restore -c
		iptables-restore -n <<-EOT
		$(extract_rules filter)
		$(extract_rules nat)
		$(extract_rules mangle)
		EOT
		
		ip6tables-save -c | grep -v "${ipt_comment}" | ip6tables-restore -c
		ip6tables-restore -n <<-EOT
		$(extract_rules6 filter)
		$(extract_rules6 mangle)
		EOT
	EOF
	return 0
}

start() {
	init_config
	local vt_enabled=$(uci -q get ${CONFIG}.@service[0].enabled)
	[ "$vt_enabled" = 0 ] && return 1

	cat > ${IPSEC_CONN_FILE} <<-EOF
		# ipsec.conf - strongSwan IPsec configuration file

		config setup
		  uniqueids=no
		  charondebug="cfg 2, dmn 2, ike 2, net 0"

		conn %default
		  dpdaction=clear
		  dpddelay=300s
		  rekey=no
		  left=%any
		  leftfirewall=yes
		  right=%any
		  ikelifetime=60m
		  keylife=20m
		  rekeymargin=3m
		  keyingtries=1
		  auto=add
		  ike=aes128-sha1-modp2048,aes128-sha1-modp1024,3des-sha1-modp1024,3des-sha1-modp1536
		  esp=aes128-sha1,aes256-sha256,3des-sha1

	EOF
	
	cat > ${IPSEC_SECRETS_FILE} <<-EOF
		# /etc/ipsec.secrets - strongSwan IPsec secrets file
	EOF

	([ "${vt_type}" = "IKEv1" ] || [ "${vt_type}" = "IKEv2" ]) && {
		local vt_gateway="${vt_clientip%.*}.1"
		cat >> ${IPSEC_CONN_FILE} <<-EOF
			conn conn-ipsec
			  leftsubnet=0.0.0.0/0
			  rightsubnet=${vt_clientip}
			  rightsourceip=${vt_clientip}
			  rightdns=${vt_gateway}

		EOF
	}

	[ "${vt_type}" = "IKEv2" ] && {
		cat >> ${IPSEC_CONN_FILE} <<-EOF
			conn IKEv2-PSK-XAuth
			  also=conn-ipsec
			  keyexchange=ikev2
			  leftauth=psk
			  rightauth=psk

		EOF
		local ikev2_users=$(get_enabled_anonymous_secs "@ikev2_users")
		[ -n "${ikev2_users}" ] && {
			for _user in ${ikev2_users}; do
				local u_enabled=$(uci -q get ${CONFIG}.${_user}.enabled)
				[ "${u_enabled}" -eq 1 ] || continue

				local u_identifier=$(uci -q get ${CONFIG}.${_user}.identifier)
				[ -n "${u_identifier}" ] || continue

				local u_secret=$(uci -q get ${CONFIG}.${_user}.secret)
				[ -n "${u_secret}" ] || continue

				echo "${u_identifier} : PSK '${u_secret}'" >> ${IPSEC_SECRETS_FILE}
			done
		}
	}

	([ "${vt_type}" = "IKEv1" ] || [ "${vt_type}" = "L2TP" ]) && {
		cat >> ${IPSEC_CONN_FILE} <<-EOF
			conn IKEv1-PSK-XAuth
			  keyexchange=ikev1
		EOF
		local vt_secret=$(uci -q get ${CONFIG}.@service[0].secret)
		cat >> ${IPSEC_SECRETS_FILE} <<-EOF
			: PSK "$vt_secret"
		EOF
	}

	[ "${vt_type}" = "IKEv1" ] && {
		cat >> ${IPSEC_CONN_FILE} <<-EOF
			  also=conn-ipsec
			  leftauth=psk
			  rightauth=psk
			  rightauth2=xauth
		EOF
		local ipsec_users=$(get_enabled_anonymous_secs "@ipsec_users")
		[ -n "${ipsec_users}" ] && {
			for _user in ${ipsec_users}; do
				local u_enabled=$(uci -q get ${CONFIG}.${_user}.enabled)
				[ "${u_enabled}" -eq 1 ] || continue

				local u_username=$(uci -q get ${CONFIG}.${_user}.username)
				[ -n "${u_username}" ] || continue

				local u_password=$(uci -q get ${CONFIG}.${_user}.password)
				[ -n "${u_password}" ] || continue

				echo "${u_username} : XAUTH '${u_password}'" >> ${IPSEC_SECRETS_FILE}
			done
		}
	}

	[ "${vt_type}" = "L2TP" ] && {
		cat >> ${IPSEC_CONN_FILE} <<-EOF

			conn L2TP-IKEv1-PSK
			  type=transport
			  keyexchange=ikev1
			  authby=secret
			  leftprotoport=udp/1701
			  left=%any
			  right=%any
			  rekey=no
			  forceencaps=yes

		EOF

		mkdir -p ${L2TP_PATH}
		cat > ${L2TP_OPTIONS_FILE} <<-EOF
			name "l2tp-server"
			ipcp-accept-local
			ipcp-accept-remote
			ms-dns ${l2tp_localip}
			noccp
			auth
			idle 1800
			mtu 1400
			mru 1400
			lcp-echo-failure 10
			lcp-echo-interval 60
			connect-delay 5000
		EOF
		local l2tp_remoteip=$(uci -q get ${CONFIG}.@service[0].l2tp_remoteip)
		cat > ${L2TP_CONFIG_FILE} <<-EOF
			[global]
			port = 1701
			;debug avp = yes
			;debug network = yes
			;debug state = yes
			;debug tunnel = yes
			[lns default]
			ip range = ${l2tp_remoteip}
			local ip = ${l2tp_localip}
			require chap = yes
			refuse pap = yes
			require authentication = no
			name = l2tp-server
			;ppp debug = yes
			pppoptfile = ${L2TP_OPTIONS_FILE}
			length bit = yes
		EOF

		touch ${CHAP_SECRETS}
		local l2tp_users=$(get_enabled_anonymous_secs "@l2tp_users")
		[ -n "${l2tp_users}" ] && {
			for _user in ${l2tp_users}; do
				local u_enabled=$(uci -q get ${CONFIG}.${_user}.enabled)
				[ "${u_enabled}" -eq 1 ] || continue

				local u_username=$(uci -q get ${CONFIG}.${_user}.username)
				[ -n "${u_username}" ] || continue

				local u_password=$(uci -q get ${CONFIG}.${_user}.password)
				[ -n "${u_password}" ] || continue

				local u_ipaddress=$(uci -q get ${CONFIG}.${_user}.ipaddress)
				[ -n "${u_ipaddress}" ] || u_ipaddress="*"

				echo "${u_username} l2tp-server ${u_password} ${u_ipaddress}" >> ${CHAP_SECRETS}
			done
		}

		echo "ip-up-script /usr/share/xl2tpd/ip-up" >> ${L2TP_OPTIONS_FILE}
		echo "ip-down-script /usr/share/xl2tpd/ip-down" >> ${L2TP_OPTIONS_FILE}

		xl2tpd -c ${L2TP_CONFIG_FILE} -C ${L2TP_CONTROL_FILE} -D >${L2TP_LOG_FILE} 2>&1 &
		rm -f "/usr/lib/ipsec/libipsec.so.0"
	}

	ipt_rule add

	/usr/lib/ipsec/starter --daemon charon --nofork > /dev/null 2>&1 &
	gen_include
	ifup ipsec_server > /dev/null 2>&1
}

stop() {
	init_config
	ifdown ipsec_server > /dev/null 2>&1
	sed -i '/l2tp-server/d' ${CHAP_SECRETS} 2>/dev/null
	top -bn1 | grep "${L2TP_PATH}" | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
	rm -rf ${L2TP_PATH}
	busybox ps -w | grep "/usr/lib/ipsec" | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
	ipt_rule del
	rm -rf /var/etc/ipsecvpn.include
	ln -s "libipsec.so.0.0.0" "/usr/lib/ipsec/libipsec.so.0" >/dev/null 2>&1
}
