#!/bin/bash
#
# /etc/openvpn/makeconf.sh
#
# ::copy::
# ::maintainer::
#
CMD=$(basename $0)
CMDVER="2.4"
CMDSTR="$CMD v$CMDVER (2026-07-26)"

config=./config
remotes=remotes

firewall_dir="/etc/kufirewall"
firewall_tmp="25auto-vpn-accept.sh"
firewall_out="$firewall_dir/rules.d/$firewall_tmp"

TAG="!!AUTO-GENERATED-FILE!!"
HEADER="# $TAG
# DO NOT EDIT! THIS FILE WILL BE OVERWRITTEN ON NEXT UPDATE
#"

cleanup()
{
	rm -f $firewall_tmp nodes.tmp
}

makeroute()
{
	name=$1
	route=$2
	interface=$3

	set `echo $route | tr '/' ' '`
	ip=$1
	case "$2" in
		*.*.*.*) mask=$2 ;;
		"") mask=255.255.255.0 ;;
		*)  mask=`ipcalc -n -b $1 $2 | grep 'Netmask: ' | sed \
			-e 's/Netmask: *//' -e 's/ *=.*//'`
			;;
	esac
	echo -e "\nroute $ip $mask vpn_gateway"
}


checknode()
{
	grep "^$1$" nodes.tmp && {
		echo "error: node $1 used twice"
		exit 1
	}
	echo "$1" >> nodes.tmp
}


add_firewall_port()
{
	local port=$1
	local use_tcp=$2
	if $use_tcp
	then
		echo "IT -A vpn_check -p tcp --destination-port $port -j ACCEPT"
	else
		echo "IT -A vpn_check -p udp --destination-port $port -j ACCEPT"
	fi >> $firewall_tmp
}

install_firewall_rules()
{
	[ -d $firewall_dir ] || return 0	# silently ignore

	[ -f $firewall_out ] && {
		cmp $firewall_tmp $firewall_out >/dev/null && return 0
	}
	echo -e "\n  installing firewall rules in $firewall_out"
	mv $firewall_tmp $firewall_out || {
		cleanup
		exit 1
	}
	(cd $firewall_dir ; rm -f _lastrun; make)
}




# (MAIN)


# config files checks
#
[ -s $config ] || {
	echo "error: config file '$config' not found" >&2
	exit 1
}
[ -s $remotes ] || {
	echo "error: remote nodes list file '$remotes' not found" >&2
	exit 1
}

. $config




# config sanity checks
#
[ -z "$MYNODE" ] && {
	echo "error: MYNODE not defined in '$config'"
	exit 1
}
[ -z "$BASEPORT" ] && {
	echo "error: BASEPORT not defined in '$config'"
	exit 1
}
[ -z "$NETBASE" ] && {
	echo "error: NETBASE not defined in '$config'"
	exit 1
}

rm -f `fgrep -l "$TAG" *.conf`

echo $MYNODE > nodes.tmp

echo "# check valid openvpn listening ports
#
$HEADER

IT -N vpn_check
IT -A INPUT -i \$EXTERNAL_IFACE -j vpn_check
" >$firewall_tmp

trap "echo '*INTR*'; cleanup; exit 255" 1 2 3
trap "cleanup" EXIT


sed -e 's/#.*//g' -e '/^ *$/d' $remotes | \
    while read number name remote key opts
do
	checknode $number || {
		cleanup
		exit 1
	}

	out=$name.conf
	lport=
	rport=
	laddr=
	raddr=
	more_options=
	cipher="$CIPHER"
	netbase=$NETBASE

	is_server=true
	ipv6=false
	use_tcp=true
	use_tun=true
	ssec=1

	for opt in `echo $opts`
	do
		set `echo $opt | tr ',' ' '`
		opt=$1
		parm=$2

		case "$opt" in
		    route)	more_options="$more_options\n`makeroute $name $parm tun$number`" ;;
		    frag)	more_options="$more_options\nmssfix\nfragment 1400" ;;
		    log)	more_options="$more_options\nlog-append /var/log/openvpn/$name.log" ;;
		    up)		more_options="$more_options\nup $parm" ; ssec=3 ;;
		    down)	more_options="$more_options\ndown $parm" ; ssec=3 ;;
		    ipchange)	more_options="$more_options\nipchange $parm" ; ssec=2 ;;
		    cipher)	cipher="$parm" ;;
		    udp)	use_tcp=false ;;
		    tun)	use_tun=false ;;
		    ipv6)	use_tcp=false ; use_tun=false ; ssec=3 ; ipv6=true ;;
		    base)	netbase=$parm ;;
		    *)		echo "unknown opt '$opt'" >&2 ; cleanup; exit 1 ;;
		esac
	done

	$use_tun		&& device="tun$number"	|| device="tap"
	[ X"$remote" == X- ]	&& is_server=true	|| is_server=false

	echo -e "# /etc/openvpn/$out (`uname -n`)" >$out
	echo -e "$HEADER"		>>$out
	echo "dev $device"		>>$out
	echo "secret $key"		>>$out
	echo "script-security $ssec"	>>$out

	printf " %-8s %-12s " "$device" "$name"

	$use_tun && {
		lport=`expr $BASEPORT + $number`
		rport=`expr $BASEPORT + $MYNODE`
		laddr=$NETBASE.$MYNODE.$number
		raddr=$netbase.$number.$MYNODE
	}

	if $is_server
	then
		if $use_tun
		then
			printf " %-20s %-20s listen $lport\n" "-" "$laddr"
			echo "lport $lport" >>$out
			add_firewall_port $lport $use_tcp
		else
			printf " %-20s %-20s (listening)\n" "-" "-"
		fi
	else
       		echo "remote $remote" >>$out

		if $use_tun
		then
			printf " %-20s %-20s -> $raddr:$rport\n" "$remote" "$laddr"
			echo "rport $rport" >>$out
		else
			printf " %-20s %-20s\n" "$remote"
		fi
	fi

	$ipv6			&& echo "up /etc/openvpn/ipv6bind.sh"	>>$out
	$use_tun		&& echo "ifconfig $laddr $raddr"	>>$out
	[ X"$cipher" != X ]	&& echo "cipher $cipher"		>>$out
	[ "$COMP" == "yes" ]	&& echo "comp-lzo"			>>$out

	if $use_tcp
	then
		if $is_server
		then
			echo "proto tcp-server" >>$out
		else
			echo "proto tcp-client" >>$out
		fi
	else
		$ipv6 && echo "proto udp6" >>$out
	fi

	$is_server ||	echo "ping-timer-rem"		>>$out

	echo "ping 30"			>>$out
	echo "ping-restart 60"		>>$out

	echo "tun-mtu 1500"		>>$out
	echo "tun-mtu-extra 64"		>>$out
	echo "float"			>>$out

	echo "persist-tun"		>>$out
	echo "persist-key"		>>$out
	echo "persist-local-ip"		>>$out
	echo -e "$more_options"		>>$out
done

install_firewall_rules

cleanup
exit 0
