diff -Nur rootfs-1.21/etc/inc/config.inc rootfs-1.21-ovpn1/etc/inc/config.inc
--- rootfs-1.21/etc/inc/config.inc	2006-01-01 12:53:09.000000000 +0100
+++ rootfs-1.21-ovpn1/etc/inc/config.inc	2006-01-14 11:48:36.000000000 +0100
@@ -521,36 +521,9 @@
 	
 	/* convert 1.5 -> 1.6 */
 	if ($config['version'] == "1.5") {
-	
-		/* Remove OpenVPN configuration */
-		unset($config['ovpn']);
-		
-		/* Remove OpenVPN interfaces */
-		for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
-			if (isset($config['interfaces']['opt' . $i]['ovpn'])) {
-			
-				unset($config['interfaces']['opt' . $i]);
-
-				/* shift down other OPTn interfaces to get rid of holes */
-				$j = $i + 1;
-				
-				/* look at the following OPTn ports */
-				while (is_array($config['interfaces']['opt' . $j])) {
-					$config['interfaces']['opt' . ($j - 1)] =
-						$config['interfaces']['opt' . $j];
-					
-					if ($config['interfaces']['opt' . ($j - 1)]['descr'] == "OPT" . $j)
-						$config['interfaces']['opt' . ($j - 1)]['descr'] = "OPT" . ($j - 1);
-					
-					unset($config['interfaces']['opt' . $j]);
-					$j++;
-				}
-			}
-		}
-
 		$config['version'] = "1.6";
 	}
-	
+
 	write_config();
 	
 	if ($g['booting'])
diff -Nur rootfs-1.21/etc/inc/filter.inc rootfs-1.21-ovpn1/etc/inc/filter.inc
--- rootfs-1.21/etc/inc/filter.inc	2006-01-01 12:53:09.000000000 +0100
+++ rootfs-1.21-ovpn1/etc/inc/filter.inc	2006-01-14 11:48:36.000000000 +0100
@@ -300,6 +300,7 @@
 		if (isset($oc['enable']) && $oc['if']) {
 			$oic = array();
 			$oic['if'] = $oc['if'];
+			$oic['ovpn'] = $oc['ovpn'];
 			
 			if ($oc['bridge']) {
 				if (!strstr($oc['bridge'], "opt") || 
@@ -412,6 +413,11 @@
 EOD;
 
 	foreach ($optcfg as $oc) {
+		if (isset($oc['ovpn'])) {
+			/* exclude OpenVPN tunneling interfaces */
+			/* $ovpnclient = true; */
+			continue;
+		}
 		if (!$oc['bridge'])
 			$ipfrules .= "block in $log quick on $wanif from {$oc['sa']}/{$oc['sn']} to any\n";
 	}
@@ -456,8 +462,11 @@
 
 	/* OPT spoof check */
 	foreach ($optcfg as $on => $oc) {
+		/* omit for openvpn interfaces */
 		/* omit for bridged interfaces when the filtering bridge is on */
-		if ($oc['ip'] && (!$oc['bridge'] || !isset($config['bridge']['filteringbridge'])))
+		if (!isset($oc['ovpn']) &&
+		              $oc['ip'] &&
+		   (!$oc['bridge'] || !isset($config['bridge']['filteringbridge'])) && $oc['sa'] != "0.0.0.0")
 			$ipfrules .= filter_rules_spoofcheck_generate($on, $oc['if'], $oc['sa'], $oc['sn'], $log);
 	}
 	
diff -Nur rootfs-1.21/etc/inc/functions.inc rootfs-1.21-ovpn1/etc/inc/functions.inc
--- rootfs-1.21/etc/inc/functions.inc	2006-01-01 12:53:09.000000000 +0100
+++ rootfs-1.21-ovpn1/etc/inc/functions.inc	2006-01-14 11:48:36.000000000 +0100
@@ -37,6 +37,7 @@
 require_once("filter.inc");
 require_once("shaper.inc");
 require_once("vpn.inc");
+require_once("openvpn.inc");
 require_once("captiveportal.inc");
 require_once("util.inc");
 
diff -Nur rootfs-1.21/etc/inc/interfaces.inc rootfs-1.21-ovpn1/etc/inc/interfaces.inc
--- rootfs-1.21/etc/inc/interfaces.inc	2006-01-01 12:53:09.000000000 +0100
+++ rootfs-1.21-ovpn1/etc/inc/interfaces.inc	2006-01-14 11:48:36.000000000 +0100
@@ -216,6 +216,12 @@
 		echo "Configuring OPT{$opti}{$optdescr} interface... ";
 	}
 	
+	/* OpenVPN configuration? */
+ 	if (isset($optcfg['ovpn'])) {
+ 		if (strstr($optcfg['if'], "tap"))
+ 			ovpn_link_tap();
+ 	}
+	
 	if (isset($optcfg['enable'])) {
 		/* wireless configuration? */
 		if (is_array($optcfg['wireless']))
@@ -235,7 +241,7 @@
 				$cmd .= " mediaopt " . escapeshellarg($optcfg['mediaopt']);
 			mwexec($cmd);
 		}
-	
+		
 		$addflags = "";
 		if (strpos($optcfg['if'], "fxp") !== false)
 			$addflags .= " link0";
@@ -251,7 +257,7 @@
 			$bridgeconfig .= $optcfg['if'] . ":" . $opti . "," .
 				$config['interfaces'][$optcfg['bridge']]['if'] .
 				":" . $opti;
-		} else {
+		} else if (!$optcfg['ovpn']) {
 			mwexec("/sbin/ifconfig " . escapeshellarg($optcfg['if']) . " " . 
 				escapeshellarg($optcfg['ipaddr'] . "/" . $optcfg['subnet']) . $addflags);
 		}
diff -Nur rootfs-1.21/etc/inc/openvpn.inc rootfs-1.21-ovpn1/etc/inc/openvpn.inc
--- rootfs-1.21/etc/inc/openvpn.inc	1970-01-01 01:00:00.000000000 +0100
+++ rootfs-1.21-ovpn1/etc/inc/openvpn.inc	2006-01-14 11:48:36.000000000 +0100
@@ -0,0 +1,1486 @@
+<?php
+/*
+	openvpn.inc
+	
+	Copyright (C) 2004 Peter Curran (peter@closeconsultants.com).
+	Copyright (C) 2005-2006 Peter Allgeyer (allgeyer@web.de).
+	All rights reserved.
+	
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions are met:
+	
+	1. Redistributions of source code must retain the above copyright notice,
+	   this list of conditions and the following disclaimer.
+	
+	2. Redistributions in binary form must reproduce the above copyright
+	   notice, this list of conditions and the following disclaimer in the
+	   documentation and/or other materials provided with the distribution.
+	
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	POSSIBILITY OF SUCH DAMAGE.
+*/
+	
+/* include all configuration functions */
+require_once("globals.inc");
+require_once("config.inc");
+require_once("functions.inc");
+
+function ovpn_configure($reconfigure) {
+	global $config;
+	if (is_array($config['ovpn']['server']))
+		ovpn_server_crl_add();
+		ovpn_server_ccd_add();
+		ovpn_config_server($reconfigure);
+	if (is_array($config['ovpn']['client']))
+		ovpn_config_client();
+	return;
+}
+
+function ovpn_link_tap() {
+	/* Add a reference to the tap KLM.  If ref count = 1, load it */
+	global $g;
+	
+	if (!is_file($g['vardb_path'] ."/ovpn_tap_link")){
+		$link_count = 1;
+		mwexec("/sbin/kldload if_tap");
+		$fd = fopen($g['vardb_path'] ."/ovpn_tap_link", 'w');
+	}
+	return true;
+}
+
+function ovpn_unlink_tap() {
+	/* Remove a reference to the tap KLM.  If ref count = 0, unload it */
+	global $g;
+	
+	if (!is_file($g['vardb_path'] ."/ovpn_tap_link"))
+		return false;  //no file, no links so why are we called?
+		
+	$fd = fopen($g['vardb_path'] ."/ovpn_tap_link", 'r+');
+	$link_count = fread($fd, filesize($g['vardb_path'] ."/ovpn_tap_link"));
+	$link_count--;
+	fwrite($fd, $link_count);
+	fclose($fd);
+		
+	if ($link_count == 0)
+		mwexec("/sbin/kldunload if_tap");
+	return true;
+}
+
+/*****************************/	
+/*  Server related functions */
+/*****************************/
+
+/* Configure the server */
+function ovpn_config_server($reconfigure) {
+	global $config, $g, $d_ovpnsrvdirty_path;
+
+	foreach ($config['ovpn']['server']['tunnel'] as $id => $server) {
+		/* get tunnel interface */
+		$tun = $server['tun_iface'];
+			
+		if (isset($server['enable'])) {
+
+			if ($g['booting']) {
+				echo "Starting OpenVPN server $id... ";
+
+				/* define configuration options */
+				ovpn_srv_config_generate($id);
+
+				/* Start the openvpn daemon */
+				mwexec("/usr/local/sbin/openvpn {$g['varetc_path']}/ovpn_srv_{$tun}.conf");
+
+				/* Send the boot message */
+				echo "done\n";
+
+				/* next server */
+				continue;
+			}
+
+			/* send SIGUSR1 to running openvpn daemon */
+			if ( $reconfigure == "true" && isset($server['dynip'])) {
+				sigkillbypid($g['varrun_path']."/ovpn_srv_{$tun}.pid", "SIGUSR1");
+				continue;
+			}
+
+			/* read dirtyfile */
+			if (is_readable($d_ovpnsrvdirty_path))
+				$lines = file($d_ovpnsrvdirty_path);
+
+			/* reconfigure server */
+			if (is_array($lines) && in_array($tun . "\n", $lines)) {
+
+				/* kill running server */
+				ovpn_server_kill($tun);
+
+				/* remove old certs & keys */
+				ovpn_server_certs_del($tun);
+
+				/* define configuration options */
+				ovpn_srv_config_generate($id);
+			}
+
+			/* Start the openvpn daemon */
+			if (!is_readable("{$g['varrun_path']}/ovpn_srv_{$tun}.pid"))
+				mwexec("/usr/local/sbin/openvpn {$g['varetc_path']}/ovpn_srv_{$tun}.conf");
+
+			/* next server */
+			continue;
+		}
+
+		/* server disabled */
+		if (!$g['booting']) {
+			/* kill running server */
+			ovpn_server_kill($tun);
+
+			/* Remove old certs & keys */
+			ovpn_server_certs_del($tun);
+
+			/* stop any processes, unload the tap module */
+			//if ($server['type'] == "tap")
+			//	ovpn_unlink_tap();
+		}
+	}
+	return 0;
+}
+
+/* Kill off a running server process */
+function ovpn_server_certs_del($tun) {
+	global $g;
+	
+	/* Remove old certs & keys */
+	unlink_if_exists("{$g['vardb_path']}/ovpn_ca_cert_{$tun}.pem");
+	unlink_if_exists("{$g['vardb_path']}/ovpn_srv_cert_{$tun}.pem");
+	unlink_if_exists("{$g['vardb_path']}/ovpn_srv_key_{$tun}.pem");
+	unlink_if_exists("{$g['vardb_path']}/ovpn_dh_{$tun}.pem");
+	unlink_if_exists("{$g['vardb_path']}/ovpn_srv_psk_{$tun}.pem");
+	unlink_if_exists("{$g['varetc_path']}/ovpn_srv_up_{$tun}.sh");
+	unlink_if_exists("{$g['varetc_path']}/ovpn_srv_{$tun}.conf");
+
+	return 0;
+}
+
+/* Kill off a running server process */
+function ovpn_server_kill($tun) {
+	global $g;
+
+	/* kill running server */
+	killbypid("{$g['varrun_path']}/ovpn_srv_{$tun}.pid");
+}
+
+/* Generate the config for a OpenVPN server */
+function ovpn_srv_config_generate($id) {
+	global $config, $g;
+	$server = $config['ovpn']['server']['tunnel'][$id];
+
+	/* get tunnel interface */
+	$tun = $server['tun_iface'];
+
+	/* get optional interface name */
+	$iface = ovpn_get_opt_interface($tun);
+
+	/* Copy the TLS-Server certs & keys to disk */
+	if ($server['authentication_method'] != "pre_shared_key" ) {
+
+		$fd = fopen("{$g['vardb_path']}/ovpn_ca_cert_{$tun}.pem", "w");
+		if ($fd) {
+			fwrite($fd, base64_decode($server['ca_cert'])."\n");
+			fclose($fd);	
+		}
+
+		$fd = fopen("{$g['vardb_path']}/ovpn_srv_cert_{$tun}.pem", "w");
+		if ($fd) {
+			fwrite($fd, base64_decode($server['srv_cert'])."\n");
+			fclose($fd);	
+		}
+
+		touch ("{$g['vardb_path']}/ovpn_srv_key_{$tun}.pem");
+		chmod ("{$g['vardb_path']}/ovpn_srv_key_{$tun}.pem", 0600);
+		$fd = fopen("{$g['vardb_path']}/ovpn_srv_key_{$tun}.pem", "w");
+		if ($fd) {
+			fwrite($fd, base64_decode($server['srv_key'])."\n");
+			fclose($fd);	
+		}
+
+		$fd = fopen("{$g['vardb_path']}/ovpn_dh_{$tun}.pem", "w");
+		if ($fd) {
+			fwrite($fd, base64_decode($server['dh_param'])."\n");
+			fclose($fd);	
+		}
+	}
+
+	if ($server['authentication_method'] == "pre_shared_key" || isset($server['tlsauth'])) {
+		touch ("{$g['vardb_path']}/ovpn_srv_psk_{$tun}.pem");
+		chmod ("{$g['vardb_path']}/ovpn_srv_psk_{$tun}.pem", 0600);
+		$fd = fopen("{$g['vardb_path']}/ovpn_srv_psk_{$tun}.pem", "w");
+		if ($fd) {
+			fwrite($fd, base64_decode($server['pre-shared-key'])."\n");
+			fclose($fd);	
+		}
+	}
+
+	$fd = fopen("{$g['varetc_path']}/ovpn_srv_{$tun}.conf", "w");
+	if (!$fd) {
+		printf("Error: cannot open ovpn_srv_{$tun}.conf in ovpn_srv_config_generate($id).\n");
+		return 1;
+	}
+
+	/* First the generic stuff:
+		- We are a server
+		- We will run without privilege
+	*/
+	$ovpn_config = "";
+	$ovpn_config .= <<<EOD
+daemon
+user nobody
+group nobody
+verb {$server['verb']}
+persist-tun
+persist-key
+status /var/log/openvpn_{$tun}.log 60
+writepid {$g['varrun_path']}/ovpn_srv_{$tun}.pid
+dev {$server['tun_iface']}
+port {$server['port']}
+cipher {$server['crypto']}
+
+EOD;
+
+	/* Set protocol being used (p = udp (default), tcp-server) */
+	if ($server['proto'] == "tcp")
+		$ovpn_config .= "proto tcp-server\n";
+
+	/* Interface binding - 1 or all */
+	if ($server['bind_iface'] != 'all')
+		if ($ipaddr = ovpn_get_ip($server['bind_iface']))
+			$ovpn_config .= "local {$ipaddr}\n";
+
+	/* are we using dynamic ip addresses? */
+	if (isset($server['dynip']))
+		$ovpn_config .= "persist-remote-ip\n";
+
+	/* LZO compression (off by default) */
+	if (isset($server['comp_method'])) {
+		switch ($server['comp_method']) {
+
+			case 'lzo':
+				$ovpn_config .= "comp-lzo\n";
+				break;
+			case 'noadapt':
+				$ovpn_config .= "comp-lzo\n" . "comp-noadapt\n";
+				break;
+		}
+	}
+
+	/* Client to client routing (off by default) */
+	if (isset($server['cli2cli']))
+		$ovpn_config .= "client-to-client\n";
+
+	/* Limit server to a maximum of n concurrent clients. */
+	if (!empty($server['maxcli']))
+		$ovpn_config .= "max-clients {$server['maxcli']}\n";
+
+	/* Authentication method */
+	if ($server['authentication_method'] != "pre_shared_key") {
+
+		$ovpn_config .= <<<EOD
+client-config-dir {$g['vardb_path']}/ccd
+ca {$g['vardb_path']}/ovpn_ca_cert_{$tun}.pem
+cert {$g['vardb_path']}/ovpn_srv_cert_{$tun}.pem
+key {$g['vardb_path']}/ovpn_srv_key_{$tun}.pem
+dh {$g['vardb_path']}/ovpn_dh_{$tun}.pem
+
+EOD;
+
+		/* CRL list */
+		if (isset($server['crlname']) &&
+		    is_readable("{$g['vardb_path']}/{$server['crlname']}.crl.pem")) {
+			$ovpn_config .= "crl-verify {$g['vardb_path']}/{$server['crlname']}.crl.pem\n";
+		}
+
+		/* TLS auth */
+		if (isset($server['tlsauth']))
+			$ovpn_config .= "tls-auth {$g['vardb_path']}/ovpn_srv_psk_{$tun}.pem 0\n";
+
+		/* bridging enabled? */
+		if ($server['bridge'] && $server['type'] == "tap") {
+			if ($server['method'] == "ovpn") {
+				$netmask = gen_subnet_mask($config['interfaces'][$server['bridge']]['subnet']);
+				$ovpn_config .= "server-bridge {$server['gateway']} {$netmask} {$server['range_from']} {$server['range_to']}\n";
+			} else {
+				$ovpn_config .= <<<EOD
+mode server
+tls-server
+
+EOD;
+			}
+
+			$lastdigits = substr($tun, 3) + 2;
+			$ovpn_srv_up = "/sbin/ifconfig " . $tun . " 127.0.0." . $lastdigits . "/32\n";
+
+			$fdo = fopen("{$g['varetc_path']}/ovpn_srv_up_{$tun}.sh", "w");
+			if ($fdo) {
+				fwrite($fdo, $ovpn_srv_up);
+				fclose($fdo);	
+				chmod ("{$g['varetc_path']}/ovpn_srv_up_{$tun}.sh", 0755);
+				$ovpn_config .= "up /var/etc/ovpn_srv_up_{$tun}.sh\n";
+			}
+
+		} else {
+			/* Not bridged, can be tun or tap, doesn't matter */
+			$netmask = gen_subnet_mask($server['prefix']);
+
+			if ($server['method'] == "ovpn") {
+				/* new --server macro simplifies config */
+				$ovpn_config .= "server {$server['ipblock']} {$netmask}\n";
+			} else {
+				$ovpn_config .= <<<EOD
+mode server
+tls-server
+ifconfig {$server['ipblock']} {$netmask}
+
+EOD;
+			}
+		} /* end bridging */
+
+		/* Duplicate CNs */
+		if (isset($server['dupcn']))
+			$ovpn_config .= "duplicate-cn\n";
+
+		$push_options = "";
+	
+		/* Client push - redirect gateway */
+		if (isset($server['psh_options']['redir']))  {
+			if (isset($server['psh_options']['redir_loc']))
+				$push_config .= "push \"redirect-gateway local\"\n";
+			else
+				$push_config .= "push \"redirect-gateway\"\n";
+		}
+
+		/* Client push - route delay */
+		if (isset($server['psh_options']['rte_delay']))
+			$push_config .= "push \"route-delay {$server['psh_options']['rte_delay_int']}\"\n";
+
+		/* Client push - ping (note we set both server and client) */
+		if (isset ($server['psh_options']['ping'])){
+			$conflict = true;
+			$interval = $server['psh_options']['ping_int'];
+			$ovpn_config .= "ping {$server['psh_options']['ping_int']}\n ";
+			$push_config .= "push \"ping {$server['psh_options']['ping_int']}\"\n";
+		}
+
+		/* Client push - ping-restart (note server uses 2 x client interval) */
+		if (isset ($server['psh_options']['pingrst'])){
+			$conflict = true;
+			$interval = $server['psh_options']['pingrst_int'];
+			$ovpn_config .= "ping-restart " . ($interval * 2) . "\n";
+			$push_config .= "push \"ping-restart $interval\"\n";
+		}
+	
+		/* Client push - ping-exit (set on client) */
+		if (isset ($server['psh_options']['pingexit'])){
+			$conflict = true;
+			$ovpn_config .= "ping-exit {$server['psh_options']['pingexit_int']}\n";
+			$push_config .= "push \"ping-exit {$server['psh_options']['pingexit_int']}\"\n";
+		}
+
+		/* Client push - inactive (set on client) */
+		if (isset ($server['psh_options']['inact'])){
+			$ovpn_config .= "inactive {$server['psh_options']['inact_int']}\n";
+			$push_config .= "push \"inactive {$server['psh_options']['inact_int']}\"\n";
+		}
+
+		if (isset($server['client-to-client']))
+			$push_config .= "push \"route {$network} {$netmask}\"\n";
+
+		if (isset($push_config))
+			$ovpn_config .= $push_config;
+
+	} else {
+		/* 'authentication_method' == "pre_shared_key" */
+		$network = gen_subnet($server['lipaddr'], $server['netmask']);
+		$netmask = gen_subnet_mask($server['netmask']);
+
+		$ovpn_config .= "secret {$g['vardb_path']}/ovpn_srv_psk_{$tun}.pem 0\n";
+
+		if (strstr($server['type'], "tun")) {
+			$ovpn_config .= "ifconfig {$server['lipaddr']} {$server['ripaddr']}\n";
+			$ovpn_config .= "route {$network} {$netmask}\n";
+		} else {
+			$ovpn_config .= "ifconfig {$server['lipaddr']} {$netmask}\n";
+		}
+
+	} /* end authentication_method */
+
+	if (!isset($conflict))
+		$ovpn_config .= "keepalive 10 60\n";
+
+	/* Expert mode paramters */
+	if (isset($server['expertmode_enabled']) && is_array($server['expertmode'])) {
+		$ovpn_config .= ";begin expertmode\n";
+		foreach ($server['expertmode']['option'] as $option) {
+			$ovpn_config .= "{$option}\n";
+		}
+		$ovpn_config .= ";end expertmode\n";
+	}
+
+	fwrite($fd, $ovpn_config);
+	fclose($fd);
+
+	//trigger_error("OVPN: $ovpn_config", E_USER_NOTICE);
+}
+
+/* Define an OVPN Server tunnel interface in the interfaces array and assign a name */
+function ovpn_server_iface(){
+	global $config, $g;
+
+	unset($filter_configure);
+	unset($bridge_configure);
+	
+	foreach ($config['ovpn']['server']['tunnel'] as $id => $server) {
+		if (isset($server['enable'])) {
+
+			/* get tunnel interface */
+			$tun = $server['tun_iface'];
+			
+			$i = 1;
+			while (true) {
+				$ifname = 'opt' . $i;
+				if (is_array($config['interfaces'][$ifname])) {
+					if ((isset($config['interfaces'][$ifname]['ovpn']))
+					     && ($config['interfaces'][$ifname]['ovpn'] == "server_{$tun}"))
+						/* Already an interface defined - overwrite */
+						break;
+				} else {
+
+					/* No existing entry, this is first unused */
+					$config['interfaces'][$ifname] = array();
+
+					/* add new filter rules */
+					$filter_configure = true;
+					break;
+				}
+				$i++;
+			}
+			$config['interfaces'][$ifname]['descr'] = strtoupper($server['tun_iface']);
+			$config['interfaces'][$ifname]['if'] = $server['tun_iface'];
+			if ($server['method'] == "ovpn")
+				$config['interfaces'][$ifname]['ipaddr'] = long2ip( ip2long($server['ipblock']) + 1);
+			else
+				$config['interfaces'][$ifname]['ipaddr'] = $server['ipblock'];
+			if (isset($server['bridge'])) {
+				$config['interfaces'][$ifname]['bridge'] = $server['bridge'];
+				$bridge_configure = true;
+			} else if (isset($config['interfaces'][$ifname]['bridge'])) {
+				/* bridge config removed */
+				unset ($config['interfaces'][$ifname]['bridge']);
+				$bridge_configure = true;
+			}
+			$config['interfaces'][$ifname]['subnet'] = $server['prefix'];
+			$config['interfaces'][$ifname]['enable'] = isset($server['enable']) ? true : false;
+			$config['interfaces'][$ifname]['ovpn'] = "server_{$tun}";
+
+			write_config();
+		}
+	}
+
+	/* do we have to reconfigure filter rules? */
+	if (isset($bridge_configure))
+		interfaces_optional_configure();
+	else if (isset($filter_configure))
+		filter_configure();
+
+	return "OpenVPN server interface defined";
+}
+
+/* Delete a server interface definition */
+function ovpn_server_iface_del($tun) {
+	global $config;
+
+	for ($i = 1; is_array($config['interfaces']['opt' . $i]); $i++) {
+		$ifname = 'opt' . $i;
+		if ((isset($config['interfaces'][$ifname]['ovpn']))
+		     && ($config['interfaces'][$ifname]['if'] == "$tun")) {
+			unset($config['interfaces'][$ifname]);
+			break;
+		}
+	}
+
+	/* shift down other OPTn interfaces to get rid of holes */
+	$i++;
+
+	/* look at the following OPTn ports */
+	while (is_array($config['interfaces']['opt' . $i])) {
+		$config['interfaces']['opt' . ($i - 1)] =
+			$config['interfaces']['opt' . $i];
+
+		unset($config['interfaces']['opt' . $i]);
+		$i++;
+	}
+
+	/* reconfigure filter rules */
+	interfaces_optional_configure();
+}
+
+/* Add client config file */
+function ovpn_server_ccd_add() {
+	global $config, $g;
+
+	if (is_array($config['ovpn']['server']['ccd'])) {
+		foreach ($config['ovpn']['server']['ccd'] as $id => $server) {
+			/* define configuration options */
+			ovpn_server_ccd_generate($id);
+		}
+	}
+}
+
+
+/* Construct client config file */
+function ovpn_server_ccd_generate($id) {
+	global $config, $g;
+	$ovpnccd = $config['ovpn']['server']['ccd'][$id];
+
+	$cn = $ovpnccd['cn'];
+	$ccd_config = "";
+        $push_options = "";
+        
+	/* Push reset */
+	if (!isset($ovpnccd['disable']) && isset($ovpnccd['psh_reset']))  {
+		$ccd_config .= "push-reset\n";
+
+		/* Client push - redirect gateway */
+		if (isset($ovpnccd['psh_options']['redir']))  {
+			if (isset($ovpnccd['psh_options']['redir_loc']))
+				$push_config .= "push \"redirect-gateway local\"\n";
+			else
+				$push_config .= "push \"redirect-gateway\"\n";
+		}
+
+		/* Client push - route delay */
+		if (isset($ovpnccd['psh_options']['rte_delay']))
+			$push_config .= "push \"route-delay {$ovpnccd['psh_options']['rte_delay_int']}\"\n";
+
+		/* Client push - ping (note we set both server and client) */
+		if (isset ($ovpnccd['psh_options']['ping'])){
+			$ccd_config .= "ping {$server['psh_options']['ping_int']}\n ";
+			$push_config .= "push \"ping {$ovpnccd['psh_options']['ping_int']}\"\n";
+		}
+
+		/* Client push - ping-restart (note server uses 2 x client interval) */
+		if (isset ($ovpnccd['psh_options']['pingrst'])){
+			$interval = $ovpnccd['psh_options']['pingrst_int'];
+			$ccd_config .= "ping-restart " . ($interval * 2) . "\n";
+			$push_config .= "push \"ping-restart $interval\"\n";
+		}
+
+		/* Client push - ping-exit (set on client) */
+		if (isset ($ovpnccd['psh_options']['pingexit'])){
+			$ccd_config .= "ping-exit {$ovpnccd['psh_options']['pingexit_int']}\n";
+			$push_config .= "push \"ping-exit {$ovpnccd['psh_options']['pingexit_int']}\"\n";
+		}
+
+		/* Client push - inactive (set on client) */
+		if (isset ($ovpnccd['psh_options']['inact'])){
+			$ccd_config .= "inactive {$ovpnccd['psh_options']['inact_int']}\n";
+			$push_config .= "push \"inactive {$ovpnccd['psh_options']['inact_int']}\"\n";
+		}
+
+		if (isset($push_config))
+			$ccd_config .= $push_config;
+	}
+
+        if (!isset($ovpnccd['disable']) && is_array($ovpnccd['options'])) {
+                foreach ($ovpnccd['options']['option'] as $option) {
+                        $ccd_config .= "{$option}\n";
+                }
+        }
+
+	/* Disable client from connecting */
+	if (isset($ovpnccd['disable']))
+		$ccd_config = "disable\n";
+
+	unlink_if_exists("{$g['vardb_path']}/ccd/{$cn}");
+
+	if (isset($ccd_config) && isset($ovpnccd['enable'])) {
+		$fd = fopen("{$g['vardb_path']}/ccd/{$cn}", "w");
+		if ($fd) {
+			fwrite($fd, $ccd_config."\n");
+			fclose($fd);    
+		}
+	}
+}
+
+/* Delete client config file */
+function ovpn_server_ccd_del($cn) {
+	global $g;
+	
+	unlink_if_exists("{$g['vardb_path']}/ccd/{$cn}");
+	return 0;
+}
+
+/* Add CRL file */
+function ovpn_server_crl_add() {
+	global $config, $g, $d_ovpncrldirty_path;
+
+	if (is_array($config['ovpn']['server']['crl'])) {
+		foreach ($config['ovpn']['server']['crl'] as $id => $crlent) {
+			/* get crl file name */
+			$name = $crlent['crlname'];
+
+			if (isset($crlent['enable'])) {
+			
+				/* add file */
+				ovpn_server_crl_generate($id);
+
+				if ($g['booting']) {
+					/* next crl file */
+					continue;
+				}
+				
+				/* read dirtyfile */
+				if (is_readable($d_ovpncrldirty_path))
+					$lines = file($d_ovpncrldirty_path);
+
+				/* reconfigure crl file */
+				if (is_array($lines) && in_array($name . "\n", $lines)) {
+
+					/* restart running openvpn daemon */
+					foreach ($config['ovpn']['server']['tunnel'] as $id => $server) {
+						$tun = $server['tun_iface'];
+
+						if ($server['enable'] &&
+						    isset($server['crlname']) && $server['crlname'] == $name)
+							/* kill running server */
+							ovpn_server_kill($tun);
+
+							/* Start the openvpn daemon */
+							mwexec("/usr/local/sbin/openvpn {$g['varetc_path']}/ovpn_srv_{$tun}.conf");
+					}
+
+				}
+			
+				/* next crl file */
+				continue;
+			}
+			
+			/* crl file disabled: remove file */
+			ovpn_server_crl_del($name);
+		}
+	}
+	return 0;
+}
+
+/* Write CRL to file */
+function ovpn_server_crl_generate($id) {
+	global $config, $g;
+
+	$ovpncrl = $config['ovpn']['server']['crl'][$id];
+
+	$fd = fopen("{$g['vardb_path']}/{$ovpncrl['crlname']}.crl.pem", "w");
+	if ($fd) {
+		fwrite($fd, base64_decode($ovpncrl['crl_list'])."\n");
+		fclose($fd);
+	}
+}
+
+/* Delete CRL file */
+function ovpn_server_crl_del($name) {
+	global $config, $g;
+
+	/* have to wipe out the crl from the server config */
+	foreach ($config['ovpn']['server']['tunnel'] as $id => $server) {
+		if (isset($server['crlname']) && $server['crlname'] == $name) {
+
+			/* get tunnel interface */
+			$tun = $server['tun_iface'];
+
+			/* remove crl file entry */
+			unset($config['ovpn']['server']['tunnel'][$id]['crlname']);
+			write_config();
+			
+			/* kill running server */
+			ovpn_server_kill($tun);
+
+			/* remove old certs & keys */
+			ovpn_server_certs_del($tun);
+			
+			/* reconfigure daemon */
+			ovpn_srv_config_generate($id);
+
+			/* Start the openvpn daemon */
+			mwexec("/usr/local/sbin/openvpn {$g['varetc_path']}/ovpn_srv_{$tun}.conf");
+		}
+	}
+
+	unlink_if_exists("{$g['vardb_path']}/{$name}.crl.pem");
+	return 0;
+}
+
+
+/* Get a list of crl files */
+function ovpn_get_crl_list() {
+	global $config;
+
+	$crl_list = array();
+
+	if (is_array($config['ovpn']['server']['crl'])) {
+		foreach ($config['ovpn']['server']['crl'] as $crlent) {
+			if (isset($crlent['enable']))
+				$crl_list[] = $crlent['crlname'];
+		}
+	}
+	return $crl_list;
+}
+
+/* append interface to $_ovpnsrvdirty_path */
+function ovpn_srv_dirty($tun) {
+	global $d_ovpnsrvdirty_path;
+	
+	$fd = fopen($d_ovpnsrvdirty_path, 'a');
+	if ($fd) {
+		fwrite($fd, $tun ."\n");
+		fclose($fd);
+	}
+}
+
+/* append file name to $_ovpncrldirty_path */
+function ovpn_crl_dirty($name) {
+	global $d_ovpncrldirty_path;
+	
+	$fd = fopen($d_ovpncrldirty_path, 'a');
+	if ($fd) {
+		fwrite($fd, $name ."\n");
+		fclose($fd);
+	}
+}
+
+
+/****************************/
+/* Client related functions */
+/****************************/
+
+function ovpn_config_client() {
+	/* Boot time configuration */
+	global $config, $g, $d_ovpnclidirty_path;;
+	
+	foreach ($config['ovpn']['client']['tunnel'] as $id => $client) {
+
+		/* get tunnel interface */
+		$tun = $client['if'];
+
+		if (isset($client['enable'])) {
+
+			if ($g['booting']) {
+				echo "Starting OpenVPN client $id... ";
+		
+				/* define configuration options */
+				ovpn_cli_config_generate($id);
+
+				/* Start openvpn for this client */
+				mwexec("/usr/local/sbin/openvpn {$g['varetc_path']}/ovpn_cli_{$tun}.conf");
+		
+				/* Send the boot message */
+				echo "done\n";
+
+				/* next client */
+				continue;
+			}
+
+			/* read dirtyfile */
+			if (is_readable($d_ovpnclidirty_path))
+				$lines = file($d_ovpnclidirty_path);
+
+			/* reconfigure client */
+			if (is_array($lines) && in_array($tun . "\n", $lines)) {
+
+				/* kill running client */
+				ovpn_client_kill($tun);
+
+				/* remove old certs & keys */
+				ovpn_client_certs_del($tun);
+
+				/* define configuration options */
+				ovpn_cli_config_generate($id);
+			}
+
+			/* Start the openvpn daemon */
+			if (!is_readable("{$g['varrun_path']}/ovpn_cli_{$tun}.pid"))
+				mwexec("/usr/local/sbin/openvpn {$g['varetc_path']}/ovpn_cli_{$tun}.conf");
+
+			/* next client */
+			continue;
+		}
+
+		/* client disabled */
+		if (!$g['booting']) {
+			/* kill running client */
+			ovpn_client_kill($tun);
+			
+			/* remove old certs & keys */
+			ovpn_client_certs_del($tun);
+
+			/* stop any processes, unload the tap module */
+			//if ($client['type'] == "tap")
+			//	ovpn_unlink_tap();
+		}
+	}
+	return 0;
+}
+
+/* Kill off a running client process */
+function ovpn_client_certs_del($tun) {
+	global $g;
+	
+	/* Remove old certs & keys */
+	unlink_if_exists("{$g['vardb_path']}/ovpn_cli_ca_cert_{$tun}.pem");
+	unlink_if_exists("{$g['vardb_path']}/ovpn_cli_cert_{$tun}.pem");
+	unlink_if_exists("{$g['vardb_path']}/ovpn_cli_key_{$tun}.pem");
+	unlink_if_exists("{$g['vardb_path']}/ovpn_cli_psk_{$tun}.pem");
+	unlink_if_exists("{$g['varetc_path']}/ovpn_cli_up_{$tun}.pem");
+	unlink_if_exists("{$g['varetc_path']}/ovpn_cli_{$tun}.conf");
+
+	return 0;
+}
+
+/* Kill off a running client process */
+function ovpn_client_kill($tun) {
+	global $g;
+
+	/* kill running client */
+	killbypid("{$g['varrun_path']}/ovpn_cli_{$tun}.pid");
+}
+
+/* Generate the config for a OpenVPN client */
+function ovpn_cli_config_generate($id) {
+	/* configure the named client */
+	global $config, $g;
+	$client = $config['ovpn']['client']['tunnel'][$id];
+
+	/* get tunnel interface */
+	$tun = $client['if'];
+
+	/* get optional interface name */
+	$iface = ovpn_get_opt_interface($tun);
+
+	/* Copy the TLS-Client certs & keys to disk */
+	if ($client['authentication_method'] != "pre_shared_key" ) {
+
+		$fd = fopen("{$g['vardb_path']}/ovpn_cli_ca_cert_{$tun}.pem", "w");
+		if ($fd) {
+			fwrite($fd, base64_decode($client['ca_cert'])."\n");
+			fclose($fd);	
+		}
+
+		$fd = fopen("{$g['vardb_path']}/ovpn_cli_cert_{$tun}.pem", "w");
+		if ($fd) {
+			fwrite($fd, base64_decode($client['cli_cert'])."\n");
+			fclose($fd);	
+		}
+
+		touch ("{$g['vardb_path']}/ovpn_cli_key_{$tun}.pem");
+		chmod ("{$g['vardb_path']}/ovpn_cli_key_{$tun}.pem", 0600);
+		$fd = fopen("{$g['vardb_path']}/ovpn_cli_key_{$tun}.pem", "w");
+		if ($fd) {
+			fwrite($fd, base64_decode($client['cli_key'])."\n");
+			fclose($fd);	
+		}
+	}
+
+	if ($client['authentication_method'] == "pre_shared_key" || isset($client['tlsauth'])) {
+		touch ("{$g['vardb_path']}/ovpn_cli_psk_{$tun}.pem");
+		chmod ("{$g['vardb_path']}/ovpn_cli_psk_{$tun}.pem", 0600);
+		$fd = fopen("{$g['vardb_path']}/ovpn_cli_psk_{$tun}.pem", "w");
+		if ($fd) {
+			fwrite($fd, base64_decode($client['pre-shared-key'])."\n");
+			fclose($fd);	
+		}
+	}
+
+	$fd = fopen("{$g['varetc_path']}/ovpn_cli_{$tun}.conf", "w");
+	if (!$fd) {
+		printf("Error: cannot open ovpn_cli_{$tun}.conf in ovpn_cli_config_generate($id).\n");
+		return 1;
+	}
+
+	/* Client support in 2.0 is very simple */
+	$ovpn_config = "";
+	$ovpn_config .= <<<EOD
+daemon
+verb 1
+status /var/log/openvpn_{$tun}.log 60
+writepid {$g['varrun_path']}/ovpn_cli_{$tun}.pid
+dev {$client['if']}
+lport {$client['cport']}
+remote {$client['saddr']} {$client['sport']}
+cipher {$client['crypto']}
+
+EOD;
+
+	/* Version 1.0 compatibility; http://openvpn.net/compat.html */
+	if ($client['ver'] != "2") {
+		$ovpn_config .= <<<EOD
+key-method 1
+tun-mtu 1500
+tun-mtu-extra 32
+mssfix 1450
+
+EOD;
+	}
+
+	/* Set protocol being used (p = udp (default), tcp-client) */
+	if ($client['proto'] == "tcp")
+		$ovpn_config .= "proto tcp-client\n";
+
+	/* TLS-Client params */
+	if ($client['authentication_method'] != "pre_shared_key") {
+		$ovpn_config .= <<<EOD
+ca {$g['vardb_path']}/ovpn_cli_ca_cert_{$tun}.pem
+cert {$g['vardb_path']}/ovpn_cli_cert_{$tun}.pem
+key {$g['vardb_path']}/ovpn_cli_key_{$tun}.pem
+
+EOD;
+
+		if (isset($client['pull']))
+			$ovpn_config .= "client\n";
+		else
+			$ovpn_config .= "tls-client\n";
+
+		/* TLS auth */
+		if (isset($client['ns_cert_type']))
+			$ovpn_config .= "ns-cert-type server\n";
+
+		/* TLS auth */
+		if (isset($client['tlsauth']))
+			$ovpn_config .= "tls-auth {$g['vardb_path']}/ovpn_cli_psk_{$tun}.pem 1\n";
+
+		/* bridging enabled? */
+		if ($client['bridge'] && $client['type'] == "tap") {
+			$lastdigits = substr($tun, 3) + 2;
+			$ovpn_cli_up = "/sbin/ifconfig " . $tun . " 127.0.0." . $lastdigits . "/32\n";
+
+			$fdo = fopen("{$g['varetc_path']}/ovpn_cli_up_{$tun}.sh", "w");
+			if ($fdo) {
+				fwrite($fdo, $ovpn_cli_up);
+				fclose($fdo);   
+				chmod ("{$g['varetc_path']}/ovpn_cli_up_{$tun}.sh", 0755);
+				$ovpn_config .= "up /var/etc/ovpn_cli_up_{$tun}.sh\n";
+			}
+		}
+
+	} else {
+		/* 'authentication_method' == "pre_shared_key" */
+		$ovpn_config .= "secret {$g['vardb_path']}/ovpn_cli_psk_{$tun}.pem 0\n";
+
+		$network = gen_subnet($client['lipaddr'], $client['netmask']);
+		$netmask = gen_subnet_mask($client['netmask']);
+
+		if (strstr($client['type'], "tap"))
+			$ovpn_config .= "ifconfig {$client['lipaddr']} {$netmask}\n";
+		else
+			$ovpn_config .= "ifconfig {$client['lipaddr']} {$client['ripaddr']}\n";
+
+	} /* end authentication_method */
+
+	/* LZO compression (off by default) */
+	if (isset($client['comp_method'])) {
+		switch ($client['comp_method']) {
+
+			case 'lzo':
+				$ovpn_config .= "comp-lzo\n";
+				break;
+			case 'noadapt':
+				$ovpn_config .= "comp-lzo\n" . "comp-noadapt\n";
+				break;
+		}
+	}
+
+	/* Expert mode paramters */
+	if (isset($client['expertmode_enabled']) && is_array($client['expertmode'])) {
+		$ovpn_config .= ";begin expertmode\n";
+		foreach ($client['expertmode']['option'] as $option) {
+			$ovpn_config .= "{$option}\n";
+		}
+		$ovpn_config .= ";end expertmode\n";
+	}
+
+	fwrite($fd, $ovpn_config);
+	fclose($fd);
+
+	/* trigger_error("OVPN: $ovpn_config", E_USER_NOTICE); */
+}
+
+/* Define an OVPN tunnel interface in the interfaces array for each client */
+function ovpn_client_iface(){
+	global $config;
+		
+	unset($filter_configure);
+	unset($bridge_configure);
+
+	foreach ($config['ovpn']['client']['tunnel'] as $id => $client) {
+		if (isset($client['enable'])) {
+
+			/* get tunnel interface */
+			$tun = $client['if'];
+
+			$i = 1;
+			while (true) {
+				$ifname = 'opt' . $i;
+				if (is_array($config['interfaces'][$ifname])) {
+					if ((isset($config['interfaces'][$ifname]['ovpn']))
+			     		     && ($config['interfaces'][$ifname]['ovpn'] == "client_{$tun}"))
+						/* Already an interface defined - overwrite */
+						break;
+				} else {
+
+					/* No existing entry, this is first unused */
+					$config['interfaces'][$ifname] = array();
+
+					/* add new filter rules */
+					$filter_configure = true;
+					break;
+				}
+				$i++;
+			}
+			$config['interfaces'][$ifname]['descr'] = strtoupper($client['if']);
+			$config['interfaces'][$ifname]['if'] = $client['if'];
+			$config['interfaces'][$ifname]['ipaddr'] = "0.0.0.0";
+			$config['interfaces'][$ifname]['subnet'] = "0";
+			if (isset($client['bridge'])) {
+				$config['interfaces'][$ifname]['bridge'] = $client['bridge'];
+				$bridge_configure = true;
+			} else if (isset($config['interfaces'][$ifname]['bridge'])) {
+				/* bridge config removed */
+				unset ($config['interfaces'][$ifname]['bridge']);
+				$bridge_configure = true;
+			}
+			$config['interfaces'][$ifname]['enable'] = isset($client['enable']) ? true : false;
+			$config['interfaces'][$ifname]['ovpn'] = "client_{$tun}";
+			write_config();
+		}
+	}
+
+	/* do we have to reconfigure filter rules? */
+	if (isset($bridge_configure))
+		interfaces_optional_configure();
+	else if (isset($filter_configure))
+		filter_configure();
+
+	return "OpenVPN client interfaces defined";
+}
+
+/* Delete a client interface definition */
+function ovpn_client_iface_del($tun) {
+	global $config;
+
+	for ($i = 1; is_array($config['interfaces']['opt' . $i]); $i++) {
+		$ifname = 'opt' . $i;
+		if ((isset($config['interfaces'][$ifname]['ovpn']))
+		     && ($config['interfaces'][$ifname]['if'] == "$tun")) {
+			unset($config['interfaces'][$ifname]);
+			break;
+		}
+	}
+
+	/* shift down other OPTn interfaces to get rid of holes */
+	$i++;
+
+	/* look at the following OPTn ports */
+	while (is_array($config['interfaces']['opt' . $i])) {
+		$config['interfaces']['opt' . ($i - 1)] =
+			$config['interfaces']['opt' . $i];
+
+		unset($config['interfaces']['opt' . $i]);
+		$i++;
+	}
+
+	/* reconfigure filter rules */
+	interfaces_optional_configure();
+}
+
+/* append interface to ovpndirty_path */
+function ovpn_cli_dirty($tun) {
+	global $d_ovpnclidirty_path;
+	
+	$fd = fopen($d_ovpnclidirty_path, 'a');
+	if ($fd) {
+		fwrite($fd, $tun . "\n");
+		fclose($fd);
+	}
+}
+
+
+/******************/
+/* Misc functions */
+/******************/
+
+/* find the first available device of type $type */
+function getnxt_if($type) {
+	global $config;
+
+	/* initialize variables */
+	$iface_list	= array();
+	$max		= ($type == 'tun') ? 17 : 4;
+
+	/* construct list of valid interfaces */
+	for ($i = 0; $i < $max ; $i++)
+		array_push($iface_list, $type . $i);
+	
+	/* delete interface in use from the list */
+	if ($a_server = $config['ovpn']['server']['tunnel']) {
+		foreach ($a_server as $server) {
+			$entry = array();
+			array_push($entry, $server['tun_iface']);
+			$iface_list = array_diff($iface_list, $entry);
+		}
+	}
+
+	/* same for list of client tunnels  */
+	if ($a_client = $config['ovpn']['client']['tunnel']) {
+		foreach ($a_client as $client) {
+			$entry = array();
+			array_push($entry, $client['if']);
+			$iface_list = array_diff($iface_list, $entry);
+		}
+	}
+			
+	/* return first element of list, if list of interfaces isn't empty */
+	if (count($iface_list))
+		return array_shift($iface_list);
+	else
+		return false;
+}
+
+/* find the next best available port */
+function getnxt_port() {
+
+	/* construct list of valid ports */
+	$port_list = free_port_list();
+
+        /* return first element of list, if list of ports isn't empty */
+        if (count($port_list))
+                return array_shift($port_list);
+        else
+                return false;
+}
+
+/* construct list of free ports */
+function free_port_list() {
+	global $config;
+
+	/* initialize variables */
+	$port_list	= array();
+	$first_port 	= 1194;
+	$max		= $first_port + 21;
+
+	for ($i = $first_port; $i < $max; $i++)
+		array_push($port_list, $i);
+        
+        /* delete port in use from the list */
+        if ($a_server = $config['ovpn']['server']['tunnel']) {
+                foreach ($a_server as $server) {
+                        $entry = array();
+                        array_push($entry, $server['port']);
+                        $port_list = array_diff($port_list, $entry);
+                }
+        }
+
+        /* same for list of client tunnels  */
+        if ($a_client = $config['ovpn']['client']['tunnel']) {
+                foreach ($a_client as $client) {
+                        $entry = array();
+                        array_push($entry, $client['cport']);
+                        $port_list = array_diff($port_list, $entry);
+                }
+        }
+
+	return $port_list;
+}
+
+/* construct list of used ports */
+function used_port_list() {
+	global $config;
+
+	/* initialize variables */
+	$port_list	= array();
+
+        /* add used ports to the list */
+        if ($a_server = $config['ovpn']['server']['tunnel']) {
+                foreach ($a_server as $server) {
+                        if (isset($server['enable']))
+				array_push($port_list, $server['port']);
+                }
+        }
+
+        /* same for list of client tunnels  */
+        if ($a_client = $config['ovpn']['client']['tunnel']) {
+                foreach ($a_client as $client) {
+                        if (isset($client['enable']))
+                        	array_push($port_list, $client['cport']);
+                }
+        }
+
+	return $port_list;
+}
+
+/* construct list of bindings used for a specified port */
+function used_bind_list($port) {
+	global $config;
+
+	/* initialize variables */
+	$bind_list	= array();
+
+        /* add used bindings to the list */
+        if ($a_server = $config['ovpn']['server']['tunnel']) {
+                foreach ($a_server as $server) {
+                        if (isset($server['enable']) && $server['port'] == $port)
+				array_push($bind_list, $server['bind_iface']);
+                }
+        }
+
+	/* client daemon always binds to 0.0.0.0 */
+	if ($a_client = $config['ovpn']['client']['tunnel']) {
+		foreach ($a_client as $client) {
+			if (isset($client['enable']) && $client['cport'] == $port)
+				array_push($bind_list, "all");
+		}
+	}
+
+	/* return list of bindings */
+	return $bind_list;
+}
+
+/* Calculate the last address in a range given the start and /prefix */
+function ovpn_calc_end($start, $prefix){
+	$first = ip2long($start);
+	$last = pow(2,(32 - $prefix)) - 1 + $first;
+	return long2ip($last);
+}
+
+/* Calculate a mask given a /prefix */
+function ovpn_calc_mask($prefix){
+	return long2ip(ip2long("255.255.255.255") - (pow( 2, (32 - $prefix)) - 1));
+}
+
+/* Port in use */
+function ovpn_port_inuse_server($port){
+	global $config;
+	if ($a_server = $config['ovpn']['server']['tunnel']) {
+		foreach ($a_server as $server) {
+			if ($server['port'] == $port) {
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+/* Read in a file from the $_FILES array */
+function ovpn_get_file($file){
+	global $g;
+	
+	if (!is_uploaded_file($_FILES[$file]['tmp_name'])){
+		trigger_error("Bad file upload".$_FILES[$file]['error'], E_USER_NOTICE);
+		return NULL;
+	}
+	$contents = file_get_contents($_FILES[$file]['tmp_name']);
+	return $contents;
+}
+
+
+/* Get the IP address of a specified interface */
+function ovpn_get_ip($iface){
+	global $config;
+	
+	if ($iface == 'wan')
+		return get_current_wan_address();
+		
+	if ($config['interfaces'][$iface]['bridge'])
+		/* No bridging (yet) */
+		return false;
+	return $config['interfaces'][$iface]['ipaddr'];
+}
+	
+	
+/* Get a list of the cipher options supported by OpenVPN */
+function ovpn_get_cipher_list(){
+	
+/*	exec("/usr/local/sbin/openvpn --show-ciphers", $raw);
+	print_r ($raw);
+	
+	$ciphers = preg_grep('/ bit default key /', $raw);
+	
+	for($i = 0; $i <count($ciphers); $i++){
+		$tmp = explode(' ',$ciphers[$i]);
+		$cipher_list["$tmp[0]"] = "{$tmp[0]} ({$tmp[1]} {$tmp[2]})";
+	}
+*/
+	$cipher_list = array('DES-CBC' => 'DES-CBC (64 bit)',
+			     'RC2-CBC' => 'RC2-CBC (128 bit)',
+			     'DES-EDE-CBC' => 'DES-EDE-CBC (128 bit)',
+			     'DES-EDE3-CBC' => 'DES-EDE3-CBC (192 bit)',
+			     'DESX-CBC' => 'DESX-CBC (192 bit)',
+			     'BF-CBC' => 'BF-CBC (128 bit)',
+			     'RC2-40-CBC' => 'RC2-40-CBC (40 bit)',
+			     'CAST5-CBC' => 'CAST5-CBC (128 bit)',
+			     'RC5-CBC' => 'RC5-CBC (128 bit)',
+			     'RC2-64-CBC' => 'RC2-64-CBC (64 bit)',
+			     'AES-128-CBC' => 'AES-128-CBC (128 bit)',
+			     'AES-192-CBC' => 'AES-192-CBC (192 bit)',
+			     'AES-256-CBC' => 'AES-256-CBC (256 bit)');
+	return $cipher_list;
+}
+		
+	
+/* Get optional interface */
+/* needs tunneling interface (tun0, tun1, tap0, ...) */
+/* returns optional interface name (opt2, opt3, ...) */
+function ovpn_get_opt_interface($tun){
+	global $config;
+
+	for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
+		$ifname = 'opt' . $i;
+
+		if (isset($config['interfaces']['opt' . $i]['ovpn']))
+			if ($config['interfaces'][$ifname]['if'] == "$tun")
+				 return $ifname;
+	}
+	/* not found? */
+	return false;
+}
+
+/* Build a list of the current real interfaces */
+function ovpn_real_interface_list(){
+	global $config;
+	
+	$interfaces = array('all' => 'ALL',
+			    'lan' => 'LAN',
+			    'wan' => 'WAN');
+	for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
+		if (isset($config['interfaces']['opt' . $i]['ovpn']))
+			/* Hide our own interface */
+			break;
+		if (isset($config['interfaces']['opt' . $i]['enable']))
+			$interfaces['opt' . $i] = $config['interfaces']['opt' . $i]['descr'];
+	}
+	return $interfaces;
+}
+
+/* called by interfaces_opt.php */
+function ovpn_ccd_sort() {
+	global $g, $config;
+
+	function ccdcmp($a, $b) {
+		return strcmp($a['cn'][0], $b['cn'][0]);
+	}
+
+	usort($config['ovpn']['server']['ccd'], "ccdcmp");
+
+}
+
+/* called by interfaces_opt.php */
+function ovpn_config_post() {
+	global $_POST, $optcfg, $pconfig;
+	
+	unset($input_errors);
+
+	/* bridge check */
+	if ($_POST['bridge'] && strstr($optcfg['if'], "tun"))
+		$input_errors[] = "Bridging a tun interface isn't possible.";
+
+	if (($_POST['enable'] && !isset($optcfg['enable'])) || (!$_POST['enable'] && isset($optcfg['enable'])))
+		$input_errors[] = "Enabling or disabling a tunneling interface isn't supported on this page.";
+
+	if ($_POST['ipaddr'] != $optcfg['ipaddr']) 
+		$input_errors[] = "Changing the IP address of a tunneling interfaces isn't supported on this page.";
+
+	if ($_POST['subnet'] != $optcfg['subnet']) 
+		$input_errors[] = "Changing the subnet mask of a tunneling interfaces isn't supported on this page.";
+
+	if ($input_errors) {
+		$pconfig['ipaddr'] = $optcfg['ipaddr'];
+		$pconfig['subnet'] = $optcfg['subnet'];
+		$pconfig['bridge'] = $optcfg['bridge'];
+		$pconfig['enable'] = isset($optcfg['enable']);
+	}
+
+	return $input_errors;
+}
+
+function check_bridging($bridge) {
+	global $config;
+	unset($input_errors);
+
+	/* double bridging? */
+	for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) { 
+		if ($i != $index) {
+			if ($config['interfaces']['opt' . $i]['bridge'] == $bridge) {
+				$input_errors = "Optional interface {$i} " . 
+				  "({$config['interfaces']['opt' . $i]['descr']}) is already bridged to " .
+				  "the specified interface.";
+			} else if ($config['interfaces']['opt' . $i]['bridge'] == "opt{$index}") {
+				$input_errors = "Optional interface {$i} " . 
+				  "({$config['interfaces']['opt' . $i]['descr']}) is already bridged to " .
+				  "this interface.";
+			}
+		}
+	}
+
+	if ($config['interfaces'][$bridge]['bridge'])
+		$input_errors = "The specified interface is already bridged to another interface.";
+
+	return $input_errors;
+}
+
+/*
+function is_specialnet($net) {
+	$specialsrcdst = explode(" ", "lan");
+	        
+	if (in_array($net, $specialsrcdst))
+		return true;
+	else
+		return false;
+}
+*/
+
+	
+/* lock openvpn information, decide that the lock file is stale after
+   10 seconds */
+function ovpn_lock() {
+	
+	global $g;
+	
+	$lockfile = "{$g['varrun_path']}/ovpn.lock";
+	
+	$n = 0;
+	while ($n < 10) {
+		/* open the lock file in append mode to avoid race condition */
+		if ($fd = fopen($lockfile, "x")) {
+			/* succeeded */
+			fclose($fd);
+			return;
+		} else {
+			/* file locked, wait and try again */
+			sleep(1);
+			$n++;
+		}
+	}
+}
+
+/* unlock configuration file */
+function ovpn_unlock() {
+	
+	global $g;
+	
+	$lockfile = "{$g['varrun_path']}/ovpn.lock";
+	
+	if (file_exists($lockfile))
+		unlink($lockfile);
+}
+
+?>
diff -Nur rootfs-1.21/etc/inc/util.inc rootfs-1.21-ovpn1/etc/inc/util.inc
--- rootfs-1.21/etc/inc/util.inc	2006-01-01 12:53:09.000000000 +0100
+++ rootfs-1.21-ovpn1/etc/inc/util.inc	2006-01-14 11:48:36.000000000 +0100
@@ -239,7 +239,7 @@
 		if (substr($ifname, -1) == "*")
 			$ifname = substr($ifname, 0, strlen($ifname) - 1);
 		
-		if (!preg_match("/^(ppp|sl|gif|faith|lo|ng|vlan|tun)/", $ifname)) {
+		if (!preg_match("/^(ppp|sl|gif|faith|lo|ng|vlan)/", $ifname)) {
 			$iflist[$ifname] = array();
 			
 			$iflist[$ifname]['mac'] = chop($alink[3]);
diff -Nur rootfs-1.21/etc/inc/xmlparse.inc rootfs-1.21-ovpn1/etc/inc/xmlparse.inc
--- rootfs-1.21/etc/inc/xmlparse.inc	2006-01-01 12:53:09.000000000 +0100
+++ rootfs-1.21-ovpn1/etc/inc/xmlparse.inc	2006-01-14 11:48:36.000000000 +0100
@@ -30,7 +30,7 @@
 */
 
 /* tags that are always to be handled as lists */
-$listtags = explode(" ", "rule user key dnsserver winsserver " .
+$listtags = explode(" ", "rule user key dnsserver winsserver option ccd crl " .
 	"encryption-algorithm-option hash-algorithm-option hosts tunnel onetoone " .
 	"staticmap route alias pipe queue shellcmd cacert earlyshellcmd mobilekey " .
 	"servernat proxyarpnet passthrumac allowedip wolentry vlan domainoverrides element");
diff -Nur rootfs-1.21/etc/rc rootfs-1.21-ovpn1/etc/rc
--- rootfs-1.21/etc/rc	2005-05-10 14:14:04.000000000 +0200
+++ rootfs-1.21-ovpn1/etc/rc	2006-01-14 11:48:24.000000000 +0100
@@ -19,7 +19,7 @@
 trap "echo 'Reboot interrupted'; exit 1" 3
 
 # make some directories in /var
-mkdir /var/run /var/log /var/etc /var/db
+mkdir /var/run /var/log /var/etc /var/db /var/db/ccd
 
 # generate circular logfiles
 clog -i -s 262144 /var/log/system.log
diff -Nur rootfs-1.21/etc/rc.bootup rootfs-1.21-ovpn1/etc/rc.bootup
--- rootfs-1.21/etc/rc.bootup	2006-01-01 12:53:09.000000000 +0100
+++ rootfs-1.21-ovpn1/etc/rc.bootup	2006-01-14 11:48:24.000000000 +0100
@@ -87,6 +87,9 @@
 	
 	/* set up Optional interfaces */
 	interfaces_optional_configure();
+		
+	/* start OpenVPN server & clients */
+	ovpn_configure(false);
 	
 	/* resync ipfilter */
 	filter_resync();
diff -Nur rootfs-1.21/etc/rc.newwanip rootfs-1.21-ovpn1/etc/rc.newwanip
--- rootfs-1.21/etc/rc.newwanip	2006-01-01 12:53:09.000000000 +0100
+++ rootfs-1.21-ovpn1/etc/rc.newwanip	2006-01-14 11:48:24.000000000 +0100
@@ -62,6 +62,9 @@
 	
 	/* reconfigure IPsec tunnels */
 	vpn_ipsec_configure(true);
+ 	
+	/* reconfigure OpenVPN tunnels */
+	ovpn_configure(true);
 	
 	/* regenerate resolv.conf if DNS overrides are allowed or the BigPond
 	   client is enabled */
diff -Nur rootfs-1.21/etc/version rootfs-1.21-ovpn1/etc/version
--- rootfs-1.21/etc/version	2006-01-01 12:53:09.000000000 +0100
+++ rootfs-1.21-ovpn1/etc/version	2006-01-14 11:48:24.000000000 +0100
@@ -1 +1 @@
-1.21
+1.21-ovpn1
diff -Nur rootfs-1.21/etc/version.buildtime rootfs-1.21-ovpn1/etc/version.buildtime
--- rootfs-1.21/etc/version.buildtime	2006-01-01 12:53:30.000000000 +0100
+++ rootfs-1.21-ovpn1/etc/version.buildtime	2006-01-14 11:59:35.000000000 +0100
@@ -1 +1 @@
-Sun Jan  1 12:53:30 CET 2006
+Sat Jan 14 11:59:35 CET 2006
diff -Nur rootfs-1.21/usr/local/www/fbegin.inc rootfs-1.21-ovpn1/usr/local/www/fbegin.inc
--- rootfs-1.21/usr/local/www/fbegin.inc	2006-01-01 12:53:09.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/fbegin.inc	2006-01-14 11:49:22.000000000 +0100
@@ -49,6 +49,7 @@
 		triel.src = "/tri_c.gif";
 	}
 }
+
 -->
 </script>
 <table width="750" border="0" cellspacing="0" cellpadding="2">
@@ -92,7 +93,7 @@
               shaper</a> <br>
               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="/firewall_aliases.php" class="navlnk">Aliases</a><br>
               <strong>Services</strong><br>
-			  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="/services_dnsmasq.php" class="navlnk">DNS forwarder</a><br>
+              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="/services_dnsmasq.php" class="navlnk">DNS forwarder</a><br>
               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="/services_dyndns.php" class="navlnk">Dynamic 
               DNS</a><br>
               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="/services_dhcp.php" class="navlnk">DHCP server</a><br>
@@ -104,9 +105,13 @@
               <strong>VPN</strong><br>
               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="/vpn_ipsec.php" class="navlnk">IPsec</a><br>
               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="/vpn_pptp.php" class="navlnk">PPTP</a><br>
+              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="/vpn_openvpn_srv.php" class="navlnk">OpenVPN</a><br>
               <strong>Status</strong><br>
               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="/index.php" class="navlnk">System</a><br>
               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="/status_interfaces.php" class="navlnk">Interfaces</a><br>
+			<?php if (count($config['ovpn']['server']['tunnel'])): ?>
+              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="/status_ovpn.php" class="navlnk">OpenVPN</a><br>
+			<?php endif; ?>
               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="/status_graph.php" class="navlnk">Traffic graph</a><br>
               &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="/status_wireless.php" class="navlnk">Wireless</a><br>
 			  <?php if (isset($config['captiveportal']['enable'])): ?>
diff -Nur rootfs-1.21/usr/local/www/guiconfig.inc rootfs-1.21-ovpn1/usr/local/www/guiconfig.inc
--- rootfs-1.21/usr/local/www/guiconfig.inc	2006-01-01 12:53:09.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/guiconfig.inc	2006-01-14 11:49:22.000000000 +0100
@@ -56,6 +56,10 @@
 $d_sysrebootreqd_path = $g['varrun_path'] . "/sysreboot.reqd";
 $d_passthrumacsdirty_path = $g['varrun_path'] . "/passthrumacs.dirty";
 $d_allowedipsdirty_path = $g['varrun_path'] . "/allowedips.dirty";
+$d_ovpnsrvdirty_path = $g['varrun_path'] . "/ovpnserver.dirty";
+$d_ovpnclidirty_path = $g['varrun_path'] . "/ovpnclient.dirty";
+$d_ovpnccddirty_path = $g['varrun_path'] . "/ovpnccd.dirty";
+$d_ovpncrldirty_path = $g['varrun_path'] . "/ovpncrl.dirty";
 
 if (file_exists($d_firmwarelock_path)) {
 	if (!$d_isfwfile) {
diff -Nur rootfs-1.21/usr/local/www/interfaces_assign.php rootfs-1.21-ovpn1/usr/local/www/interfaces_assign.php
--- rootfs-1.21/usr/local/www/interfaces_assign.php	2006-01-01 12:53:09.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/interfaces_assign.php	2006-01-14 11:49:22.000000000 +0100
@@ -51,6 +51,26 @@
 	}
 }
 
+/* add server tun/tap interfaces */
+if (is_array($config['ovpn']['server']['tunnel']) && count($config['ovpn']['server']['tunnel'])) {
+	$i = 0;
+	foreach ($config['ovpn']['server']['tunnel'] as $tunnel) {
+		$portlist['tun' . $i] = $tunnel;
+		$portlist['tun' . $i]['istun'] = true;
+		$i++;
+	}
+}
+
+/* add client tun/tap interfaces */
+if (is_array($config['ovpn']['client']['tunnel']) && count($config['ovpn']['client']['tunnel'])) {
+	$i = 0;
+	foreach ($config['ovpn']['client']['tunnel'] as $tunnel) {
+		$portlist['tun' . $i] = $tunnel;
+		$portlist['tun' . $i]['istun'] = true;
+		$i++;
+	}
+}
+
 if ($_POST) {
 
 	unset($input_errors);
@@ -118,29 +138,30 @@
 
 if ($_GET['act'] == "del") {
 	$id = $_GET['id'];
-	
-	unset($config['interfaces'][$id]);	/* delete the specified OPTn */
 
-	/* shift down other OPTn interfaces to get rid of holes */
-	$i = substr($id, 3); /* the number of the OPTn port being deleted */
-	$i++;
-	
-	/* look at the following OPTn ports */
-	while (is_array($config['interfaces']['opt' . $i])) {
-		$config['interfaces']['opt' . ($i - 1)] =
-			$config['interfaces']['opt' . $i];
-		
-		if ($config['interfaces']['opt' . ($i - 1)]['descr'] == "OPT" . $i)
-			$config['interfaces']['opt' . ($i - 1)]['descr'] = "OPT" . ($i - 1);
-		
-		unset($config['interfaces']['opt' . $i]);
+	if (!$input_errors) {
+
+		/* shift down other OPTn interfaces to get rid of holes */
+		$i = substr($id, 3); /* the number of the OPTn port being deleted */
 		$i++;
-	}
 
-	write_config();
-	touch($d_sysrebootreqd_path);
-	header("Location: interfaces_assign.php");
-	exit;
+		/* look at the following OPTn ports */
+		while (is_array($config['interfaces']['opt' . $i])) {
+			$config['interfaces']['opt' . ($i - 1)] =
+				$config['interfaces']['opt' . $i];
+			
+			if ($config['interfaces']['opt' . ($i - 1)]['descr'] == "OPT" . $i)
+				$config['interfaces']['opt' . ($i - 1)]['descr'] = "OPT" . ($i - 1);
+			
+			unset($config['interfaces']['opt' . $i]);
+			$i++;
+		}
+
+		write_config();
+		touch($d_sysrebootreqd_path);
+		header("Location: interfaces_assign.php");
+		exit;
+	}
 }
 
 if ($_GET['act'] == "add") {
@@ -178,8 +199,10 @@
 
 ?>
 <?php include("fbegin.inc"); ?>
-<?php if ($input_errors) print_input_errors($input_errors); ?>
-<?php if (file_exists($d_sysrebootreqd_path)) print_info_box(get_std_save_message(0)); ?>
+<?php if ($input_errors)
+	print_input_errors($input_errors);
+      else if (file_exists($d_sysrebootreqd_path)) print_info_box(get_std_save_message(0));
+?>
 <form action="interfaces_assign.php" method="post" name="iform" id="iform">
 <table width="100%" border="0" cellpadding="0" cellspacing="0">
   <tr><td class="tabnavtbl">
@@ -197,6 +220,10 @@
 	<td class="list">&nbsp;</td>
   </tr>
   <?php foreach ($config['interfaces'] as $ifname => $iface):
+  	/* we don't want to see the OpenVPN tun interfaces */
+	if (isset($iface['ovpn']))
+		continue;
+
 	if ($iface['descr'])
 		$ifdescr = $iface['descr'];
 	else
@@ -207,6 +234,7 @@
 	  <td valign="middle" class="listr">
 		<select name="<?=$ifname;?>" class="formfld" id="<?=$ifname;?>">
 		  <?php foreach ($portlist as $portname => $portinfo): ?>
+		  <?php   if ($portinfo['istun']) continue; ?>
 		  <option value="<?=$portname;?>" <?php if ($portname == $iface['if']) echo "selected";?>> 
 		  <?php if ($portinfo['isvlan']) {
 		  			$descr = "VLAN {$portinfo['tag']} on {$portinfo['if']}";
diff -Nur rootfs-1.21/usr/local/www/interfaces_opt.php rootfs-1.21-ovpn1/usr/local/www/interfaces_opt.php
--- rootfs-1.21/usr/local/www/interfaces_opt.php	2006-01-01 12:53:09.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/interfaces_opt.php	2006-01-14 11:49:22.000000000 +0100
@@ -53,6 +53,16 @@
 	wireless_config_init();
 }
 
+/* OpenVPN tunnel interface? */
+if (isset($optcfg['ovpn'])) {
+	if (strstr($optcfg['ovpn'], "tun")) {
+		$ovpn_tun = "yes";
+	} else if (strstr($optcfg['ovpn'], "tap")) {
+		$ovpn_tap = "yes";
+	}
+}
+	
+
 if ($_POST) {
 
 	unset($input_errors);
@@ -116,13 +126,21 @@
 		}
 	}
 	
+	/* TUN/TAP interface? */
+	if (isset($optcfg['ovpn'])) {
+		$ovpn_input_errors = ovpn_config_post();
+		if ($ovpn_input_errors) {
+			$input_errors = array_merge($input_errors, $ovpn_input_errors);
+		}
+	}
+	
 	if (!$input_errors) {
 		$optcfg['descr'] = $_POST['descr'];
 		$optcfg['ipaddr'] = $_POST['ipaddr'];
 		$optcfg['subnet'] = $_POST['subnet'];
 		$optcfg['bridge'] = $_POST['bridge'];
 		$optcfg['enable'] = $_POST['enable'] ? true : false;
-
+			
 		write_config();
 		
 		$retval = 0;
@@ -156,23 +174,29 @@
 	document.iform.bridge.disabled = endis;
 
 	if (document.iform.mode) {
-		 document.iform.mode.disabled = endis;
-		 document.iform.ssid.disabled = endis;
-		 document.iform.channel.disabled = endis;
-		 document.iform.stationname.disabled = endis;
-		 document.iform.wep_enable.disabled = endis;
-		 document.iform.key1.disabled = endis;
-		 document.iform.key2.disabled = endis;
-		 document.iform.key3.disabled = endis;
-		 document.iform.key4.disabled = endis;
+		document.iform.mode.disabled = endis;
+		document.iform.ssid.disabled = endis;
+		document.iform.channel.disabled = endis;
+		document.iform.stationname.disabled = endis;
+		document.iform.wep_enable.disabled = endis;
+		document.iform.key1.disabled = endis;
+		document.iform.key2.disabled = endis;
+		document.iform.key3.disabled = endis;
+		document.iform.key4.disabled = endis;
 	}
 }
 function bridge_change(enable_over) {
 	var endis;
 
-	if (document.iform.enable.checked || enable_over) {
+	if (document.iform.enable.checked || enable_over)
 		endis = !((document.iform.bridge.selectedIndex == 0) || enable_over);
-	} else {
+	else
+		endis = true;
+
+	if (document.iform.ovpntun.checked && !enable_over) {
+		endis = true;
+		document.iform.bridge.disabled = endis;
+	} else if (document.iform.ovpntap.checked && !enable_over) {
 		endis = true;
 	}
 
@@ -210,7 +234,7 @@
                 <tr> 
                   <td width="22%" valign="top" class="vtable">&nbsp;</td>
                   <td width="78%" class="vtable">
-<input name="enable" type="checkbox" value="yes" <?php if ($pconfig['enable']) echo "checked"; ?> onClick="enable_change(false);bridge_change(false)">
+<input name="enable" type="checkbox" value="yes" <?php if ($pconfig['enable']) echo "checked"; ?> onChange="enable_change(false);bridge_change(false)">
                     <strong>Enable Optional <?=$index;?> interface</strong></td>
 				</tr>
                 <tr> 
@@ -243,26 +267,28 @@
                       </option>
                       <?php endforeach; ?>
                     </select> </td>
-				</tr>
-                <tr> 
-                  <td width="22%" valign="top" class="vncellreq">IP address</td>
-                  <td width="78%" class="vtable"> 
-                    <?=$mandfldhtml;?><input name="ipaddr" type="text" class="formfld" id="ipaddr" size="20" value="<?=htmlspecialchars($pconfig['ipaddr']);?>" onchange="ipaddr_change()">
-                    /
-                	<select name="subnet" class="formfld" id="subnet">
-					<?php for ($i = 31; $i > 0; $i--): ?>
-					<option value="<?=$i;?>" <?php if ($i == $pconfig['subnet']) echo "selected"; ?>><?=$i;?></option>
-					<?php endfor; ?>
-                    </select>
-				 </td>
-				</tr>
-				<?php /* Wireless interface? */
-				if (isset($optcfg['wireless']))
-					wireless_config_print();
-				?>
+		</tr>
+		<tr>
+		  <td width="22%" valign="top" class="vncellreq">IP address</td>
+		  <td width="78%" class="vtable">
+		    <?=$mandfldhtml;?><input name="ipaddr" type="text" class="formfld" id="ipaddr" size="20" value="<?=htmlspecialchars($pconfig['ipaddr']);?>" onchange="ipaddr_change()">
+		    /
+		    <select name="subnet" class="formfld" id="subnet">
+			<?php for ($i = 31; $i >= 0; $i--): ?>
+			  <option value="<?=$i;?>" <?php if ($i == $pconfig['subnet']) echo "selected";?>><?=$i;?></option>
+			<?php endfor; ?>
+		    </select>
+		  </td>
+		</tr>
+			<?php /* Wireless interface? */
+			if (isset($optcfg['wireless']))
+				wireless_config_print();
+			?>
                 <tr> 
                   <td width="22%" valign="top">&nbsp;</td>
                   <td width="78%"> 
+                    <input name="ovpntun" type="hidden" id="ovpntun" value="<?=$ovpn_tun;?>" <?php if ($ovpn_tun) echo "checked"; ?>> 
+                    <input name="ovpntap" type="hidden" id="ovpntap" value="<?=$ovpn_tap;?>" <?php if ($ovpn_tap) echo "checked"; ?>> 
                     <input name="index" type="hidden" value="<?=$index;?>"> 
 				  <input name="Submit" type="submit" class="formbtn" value="Save" onclick="enable_change(true);bridge_change(true)"> 
                   </td>
diff -Nur rootfs-1.21/usr/local/www/license.php rootfs-1.21-ovpn1/usr/local/www/license.php
--- rootfs-1.21/usr/local/www/license.php	2006-01-01 12:53:08.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/license.php	2006-01-14 11:49:22.000000000 +0100
@@ -79,8 +79,9 @@
               &nbsp;&nbsp;&nbsp;&nbsp;<em><font color="#666666">DHCP lease list page</font></em><br>
               <br>
               Peter Allgeyer (<a href="mailto:allgeyer@web.de">allgeyer@web.de</a>)<br>
-              &nbsp;&nbsp;&nbsp;&nbsp;<em><font color="#666666">&quot;reject&quot; type filter rules; dial-on-demand; WAN connect/disconnect; auto-add proxy ARP </font></em><br>
-              &nbsp;&nbsp;&nbsp;&nbsp;<em><font color="#666666">firewall log filtering; DynDNS server/port; Diag: ARP improvements</font></em><br>
+              &nbsp;&nbsp;&nbsp;&nbsp;<em><font color="#666666">&quot;reject&quot; type filter rules; dial-on-demand; WAN connect/disconnect; auto-add proxy ARP; </font></em><br>
+              &nbsp;&nbsp;&nbsp;&nbsp;<em><font color="#666666">firewall log filtering; DynDNS server/port; Diag: ARP improvements;</font></em><br>
+	      &nbsp;&nbsp;&nbsp;&nbsp;<em><font color="#666666">OpenVPN support enhancements</font></em><br>
               <br>
               Thierry Lechat (<a href="mailto:dev@lechat.org">dev@lechat.org</a>)<br>
               &nbsp;&nbsp;&nbsp;&nbsp;<em><font color="#666666">SVG-based traffic grapher</font></em><br>
@@ -110,6 +111,9 @@
               Audun Larsen (<a href="mailto:larsen@xqus.com">larsen@xqus.com</a>)<br>
               &nbsp;&nbsp;&nbsp;&nbsp;<em><font color="#666666">CPU/memory usage display</font></em><br>
 			  <br>
+              Peter Curran (<a href="mailto:peter@closeconsultants.com">peter@closeconsultants.com</a>)<br>
+              &nbsp;&nbsp;&nbsp;&nbsp;<em><font color="#666666">OpenVPN support</font></em><br>
+			  <br>
               Pavel A. Grodek (<a href="mailto:pg@abletools.com">pg@abletools.com</a>)<br>
               &nbsp;&nbsp;&nbsp;&nbsp;<em><font color="#666666">Traffic shaper packet loss rate/queue size</font></em><br>
 			  <br>
diff -Nur rootfs-1.21/usr/local/www/services_dhcp.php rootfs-1.21-ovpn1/usr/local/www/services_dhcp.php
--- rootfs-1.21/usr/local/www/services_dhcp.php	2006-01-01 12:53:08.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/services_dhcp.php	2006-01-14 11:49:22.000000000 +0100
@@ -41,7 +41,7 @@
 for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
 	$oc = $config['interfaces']['opt' . $i];
 	
-	if (isset($oc['enable']) && $oc['if'] && (!$oc['bridge'])) {
+	if (isset($oc['enable']) && $oc['if'] && (!$oc['bridge']) && (!strstr($oc['if'], "tun"))) {
 		$iflist['opt' . $i] = $oc['descr'];
 	}
 }
diff -Nur rootfs-1.21/usr/local/www/services_dhcp_relay.php rootfs-1.21-ovpn1/usr/local/www/services_dhcp_relay.php
--- rootfs-1.21/usr/local/www/services_dhcp_relay.php	2006-01-01 12:53:08.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/services_dhcp_relay.php	2006-01-14 11:49:22.000000000 +0100
@@ -62,7 +62,7 @@
 for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
 	$oc = $config['interfaces']['opt' . $i];
 	
-	if (isset($oc['enable']) && $oc['if'] && (!$oc['bridge'])) {
+	if (isset($oc['enable']) && $oc['if'] && (!$oc['bridge']) && (!strstr($oc['if'], "tun"))) {
 		$iflist['opt' . $i] = $oc['descr'];
 	}
 }
diff -Nur rootfs-1.21/usr/local/www/services_proxyarp_edit.php rootfs-1.21-ovpn1/usr/local/www/services_proxyarp_edit.php
--- rootfs-1.21/usr/local/www/services_proxyarp_edit.php	2006-01-01 12:53:08.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/services_proxyarp_edit.php	2006-01-14 11:49:22.000000000 +0100
@@ -168,6 +168,7 @@
 					<select name="interface" class="formfld">
                       <?php $interfaces = array('wan' => 'WAN', 'lan' => 'LAN');
 					  for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
+					  	if (!strstr($config['interfaces']['opt' . $i]['if'], "tun"))
 							$interfaces['opt' . $i] = $config['interfaces']['opt' . $i]['descr'];
 					  }
 					  foreach ($interfaces as $iface => $ifacename): ?>
diff -Nur rootfs-1.21/usr/local/www/services_wol_edit.php rootfs-1.21-ovpn1/usr/local/www/services_wol_edit.php
--- rootfs-1.21/usr/local/www/services_wol_edit.php	2006-01-01 12:53:08.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/services_wol_edit.php	2006-01-14 11:49:22.000000000 +0100
@@ -94,7 +94,8 @@
                       <?php $interfaces = array('lan' => 'LAN');
 					  for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
 					    if (isset($config['interfaces']['opt' . $i]['enable']) &&
-							!$config['interfaces']['opt' . $i]['bridge'])
+							!$config['interfaces']['opt' . $i]['bridge'] &&
+							!$config['interfaces']['opt' . $i]['ovpn'])
 					  		$interfaces['opt' . $i] = $config['interfaces']['opt' . $i]['descr'];
 					  }
 					  foreach ($interfaces as $iface => $ifacename): ?>
diff -Nur rootfs-1.21/usr/local/www/services_wol.php rootfs-1.21-ovpn1/usr/local/www/services_wol.php
--- rootfs-1.21/usr/local/www/services_wol.php	2006-01-01 12:53:08.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/services_wol.php	2006-01-14 11:49:22.000000000 +0100
@@ -88,7 +88,8 @@
                       <?php $interfaces = array('lan' => 'LAN');
 					  for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
 					    if (isset($config['interfaces']['opt' . $i]['enable']) &&
-							!$config['interfaces']['opt' . $i]['bridge'])
+							!$config['interfaces']['opt' . $i]['bridge'] &&
+							!$config['interfaces']['opt' . $i]['ovpn'])
 					  		$interfaces['opt' . $i] = $config['interfaces']['opt' . $i]['descr'];
 					  }
 					  foreach ($interfaces as $iface => $ifacename): ?>
diff -Nur rootfs-1.21/usr/local/www/status_ovpn.php rootfs-1.21-ovpn1/usr/local/www/status_ovpn.php
--- rootfs-1.21/usr/local/www/status_ovpn.php	1970-01-01 01:00:00.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/status_ovpn.php	2006-01-14 11:49:22.000000000 +0100
@@ -0,0 +1,120 @@
+#!/usr/local/bin/php
+<?php 
+/*
+	status_ovpn.php
+	part of m0n0wall (http://m0n0.ch/wall)
+	
+	Copyright (C) 2003-2005 Manuel Kasper <mk@neon1.net>.
+	Copyright (C) 2005-2006 Peter Allgeyer <allgeyer@web.de>.
+	All rights reserved.
+	
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions are met:
+	
+	1. Redistributions of source code must retain the above copyright notice,
+	   this list of conditions and the following disclaimer.
+	
+	2. Redistributions in binary form must reproduce the above copyright
+	   notice, this list of conditions and the following disclaimer in the
+	   documentation and/or other materials provided with the distribution.
+	
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	POSSIBILITY OF SUCH DAMAGE.
+*/
+
+$pgtitle = array("Status", "OpenVPN");
+require("guiconfig.inc");
+
+$client_list = array();
+$virtip_list = array();
+
+function dump_log($type) {
+	global $g, $config;
+
+	unset($client_list);
+	$client_list = array();
+
+	unset($virtip_list);
+	$virtip_list = array();
+			
+	$max = ($type == 'tun') ? 17 : 4;
+	for ($i = 0; $i < $max; $i++) {
+		if (file_exists("/var/log/openvpn_{$type}{$i}.log")) {
+
+			unset($string);
+			unset($logarr);
+			
+			exec("/bin/cat /var/log/openvpn_{$type}{$i}.log", $logarr);
+	
+			foreach ($logarr as $logent) {
+				$logent = preg_split("/,/", $logent, 5);
+				$string = preg_split("/:/", $logent[1]);
+
+				/* search for ip address in second column */
+				if (isset($string[0]) && is_ipaddr($string[0]))
+					array_push($client_list, $logent);
+				
+				/* search for ip address in first column */
+				else if (is_ipaddr($logent[0]))
+					array_push($virtip_list, $logent);
+			}
+		}
+	}
+
+	if (count($client_list > 1)) {
+		foreach ($client_list as $cent) {
+			echo "<tr>\n";
+			echo "<td class=\"listlr\" nowrap>" . htmlspecialchars($cent[0]) . "</td>\n";
+			echo "<td class=\"listr\">" . htmlspecialchars($cent[1]) . "</td>\n";
+
+			unset($found);
+			if (isset($virtip_list)) {
+				foreach ($virtip_list as $vent) {
+					if ($cent[1] == $vent[2]) {
+						$found = 1;
+						echo "<td class=\"listr\">" . htmlspecialchars($vent[0]) . "&nbsp;</td>\n";
+					}
+				}
+			}
+			if (!isset($found))
+				echo "<td class=\"listr\" align=\"center\">--</td>\n";
+				
+			$date = preg_split("/\s+/", $cent[4]);
+			echo "<td nowrap class=\"listr\">" . htmlspecialchars($date[1]) . " " . htmlspecialchars($date[2]) . " " . htmlspecialchars($date[3]) . "</td>\n";
+			echo "<td class=\"listr\">" . htmlspecialchars($cent[2]) . "</td>\n";
+			echo "<td class=\"listr\">" . htmlspecialchars($cent[3]) . "</td>\n";
+			echo "</tr>\n";
+		}
+	}
+}
+
+?>
+<?php include("fbegin.inc"); ?>
+<table width="100%" border="0" cellpadding="0" cellspacing="0"><tr>
+  <td colspan="6" class="listtopic"> 
+	    OpenVPN server status entries</td>
+	</tr>
+	 <tr>
+	  <td class="listhdrr">Common Name</td>
+	  <td class="listhdrr">Real Address</td>
+	  <td class="listhdrr">Virtual Address</td>
+	  <td class="listhdrr">Connected Since</td>
+	  <td class="listhdrr">Bytes Received</td>
+	  <td class="listhdr">Bytes Sent</td>
+	</tr>
+	<?php dump_log(tun); ?>
+	<?php dump_log(tap); ?>
+</table>
+<br>
+<strong class="red">Note:<br>
+</strong>Please note that status entries are updated once every minute only.
+So don't bother about entries on this page being possibly too old!
+<?php include("fend.inc"); ?>
diff -Nur rootfs-1.21/usr/local/www/status.php rootfs-1.21-ovpn1/usr/local/www/status.php
--- rootfs-1.21/usr/local/www/status.php	2006-01-01 12:53:08.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/status.php	2006-01-14 11:49:22.000000000 +0100
@@ -30,6 +30,8 @@
 					/* remove password tag contents */
 					$line = preg_replace("/<password>.*?<\\/password>/", "<password>xxxxx</password>", $line);
 					$line = preg_replace("/<pre-shared-key>.*?<\\/pre-shared-key>/", "<pre-shared-key>xxxxx</pre-shared-key>", $line);
+					$line = preg_replace("/<srv_key>.*?<\\/srv_key>/", "<srv_key>xxxxx</srv_key>", $line);
+					$line = preg_replace("/<cli_key>.*?<\\/cli_key>/", "<cli_key>xxxxx</cli_key>", $line);
 					$line = str_replace("\t", "    ", $line);
 					echo htmlspecialchars($line,ENT_NOQUOTES);
 				}
diff -Nur rootfs-1.21/usr/local/www/vpn_ipsec_edit.php rootfs-1.21-ovpn1/usr/local/www/vpn_ipsec_edit.php
--- rootfs-1.21/usr/local/www/vpn_ipsec_edit.php	2006-01-01 12:53:08.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/vpn_ipsec_edit.php	2006-01-14 11:49:22.000000000 +0100
@@ -328,6 +328,7 @@
                   <td width="78%" class="vtable"><select name="interface" class="formfld">
                       <?php $interfaces = array('wan' => 'WAN', 'lan' => 'LAN');
 					  for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
+					  	if (!$config['interfaces']['opt' . $i]['ovpn'])
 							$interfaces['opt' . $i] = $config['interfaces']['opt' . $i]['descr'];
 					  }
 					  foreach ($interfaces as $iface => $ifacename): ?>
diff -Nur rootfs-1.21/usr/local/www/vpn_openvpn_ccd_edit.php rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_ccd_edit.php
--- rootfs-1.21/usr/local/www/vpn_openvpn_ccd_edit.php	1970-01-01 01:00:00.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_ccd_edit.php	2006-01-14 11:49:22.000000000 +0100
@@ -0,0 +1,418 @@
+#!/usr/local/bin/php
+<?php 
+/*
+	vpn_openvpn_ccd_edit.php
+
+	Copyright (C) 2005-2006 Peter Allgeyer (allgeyer@web.de).
+	All rights reserved.
+	
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions are met:
+	
+	1. Redistributions of source code must retain the above copyright notice,
+	   this list of conditions and the following disclaimer.
+	
+	2. Redistributions in binary form must reproduce the above copyright
+	   notice, this list of conditions and the following disclaimer in the
+	   documentation and/or other materials provided with the distribution.
+	
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	POSSIBILITY OF SUCH DAMAGE.
+*/
+
+$pgtitle = array("VPN", "OpenVPN", "Edit client-specific configuration");
+require("guiconfig.inc");
+require_once("openvpn.inc");
+
+if (!is_array($config['ovpn']))
+	$config['ovpn'] = array();
+if (!is_array($config['ovpn']['server']))
+	$config['ovpn']['server'] = array();
+if (!is_array($config['ovpn']['server']['ccd']))
+	$config['ovpn']['server']['ccd'] = array();
+
+$ovpnccd =& $config['ovpn']['server']['ccd'];
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+	$id = $_POST['id'];
+
+if (isset($id) && $ovpnccd[$id]) {
+
+	$pconfig = $config['ovpn']['server']['ccd'][$id];
+
+	if (isset($ovpnccd[$id]['enable']))
+		$pconfig['enable'] = true;
+
+	if (is_array($config['ovpn']['server']['ccd'][$id]['options'])) {
+		$pconfig['options'] = "";
+		foreach ($ovpnccd[$id]['options']['option'] as $optent) {
+			$pconfig['options'] .= $optent . "\n";
+		}
+		$pconfig['options'] = rtrim($pconfig['options']);
+	}
+
+} else {
+	/* creating - set defaults */
+	$pconfig = array();
+	$pconfig['enable'] = true;
+}
+
+if ($_POST) {
+
+	unset($input_errors);
+	$pconfig = $_POST;
+
+	/* input validation */
+	$reqdfields = explode(" ", "cn");
+	$reqdfieldsn = explode(",", "Common name");
+
+	do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors);
+
+	if (preg_match("/[^a-zA-Z0-9\.\-_\:\/\@]/", $_POST['cn']))
+		$input_errors[] = "The common name contains invalid characters.";
+
+	if ($_POST['psh_pingrst'] && $_POST['psh_pingexit'])
+		$input_errors[] = "Ping-restart and Ping-exit are mutually exclusive and cannot be used together";
+
+	if ($_POST['psh_rtedelay'] && !is_numeric($_POST['psh_rtedelay_int']))
+		$input_errors[] = "Route-delay needs a numerical interval setting.";
+
+	if ($_POST['psh_inact'] && !is_numeric($_POST['psh_inact_int']))
+		$input_errors[] = "Inactive needs a numerical interval setting.";
+
+	if ($_POST['psh_ping'] && !is_numeric($_POST['psh_ping_int']))
+		$input_errors[] = "Ping needs a numerical interval setting.";
+			
+	if ($_POST['psh_pingexit'] && !is_numeric($_POST['psh_pingexit_int']))
+		$input_errors[] = "Ping-exit needs a numerical interval setting.";
+
+	if ($_POST['psh_pingrst'] && !is_numeric($_POST['psh_pingrst_int']))
+		$input_errors[] = "Ping-restart needs a numerical interval setting.";
+
+	/* Editing an existing entry? */
+	if (!$input_errors && !(isset($id) && $ovpnccd[$id])) {
+		/* make sure there are no dupes */
+		foreach ($ovpnccd as $ccdent) {
+			if ($ccdent['cn'] == $_POST['cn']) {
+				$input_errors[] = "Another entry with the same common name already exists.";
+				break;
+			}
+		}
+	}
+
+	if (isset($id) && $ovpnccd[$id]) {
+		$ccdent = $ovpnccd[$id];
+
+		/* Has the enable/disable state changed? */
+		if (isset($ccdent['enable']) && isset($_POST['disabled'])) {
+			/* status changed to disabled */
+			touch($d_ovpnccddirty_path);
+		}
+
+		/* status changed to enable */
+		if (!isset($ccdent['enable']) && !isset($_POST['disabled'])) {
+			/* touch($d_sysrebootreqd_path); */
+			touch($d_ovpnccddirty_path);
+		}
+	}
+
+	if (!$input_errors) {
+        
+		$ccdent = array();
+
+		if (isset($id) && $ovpnccd[$id])
+			$ccdent = $ovpnccd[$id];
+        
+                $ccdent['cn'] = $_POST['cn'];
+		$ccdent['descr'] = $_POST['descr'];
+		$ccdent['enable'] = $_POST['disabled'] ? false : true;
+		$ccdent['disable'] = $_POST['disable'] ? true : false;
+
+
+                if (!is_array($options))
+                        $options = array();
+                if (!is_array($ccdent['options']))
+                        $ccdent['options'] = array();
+
+		$options['option'] = array_map('trim', explode("\n", trim($_POST['options'])));
+		$ccdent['options'] = $options;
+
+		$ccdent['psh_reset'] = $_POST['psh_reset'] ? true : false;
+		$ccdent['psh_options']['redir'] = $_POST['psh_redir'] ? true : false;
+		$ccdent['psh_options']['redir_loc'] = $_POST['psh_redir_loc'] ? true : false;
+		$ccdent['psh_options']['rtedelay'] = $_POST['psh_rtedelay'] ? true : false;
+		$ccdent['psh_options']['inact'] = $_POST['psh_inact'] ? true : false;
+		$ccdent['psh_options']['ping'] = $_POST['psh_ping'] ? true : false;
+		$ccdent['psh_options']['pingrst'] = $_POST['psh_pingrst'] ? true : false;
+		$ccdent['psh_options']['pingexit'] = $_POST['psh_pingexit'] ? true : false;
+
+		unset($ccdent['psh_options']['rtedelay_int']);
+		unset($ccdent['psh_options']['inact_int']);
+		unset($ccdent['psh_options']['ping_int']);
+		unset($ccdent['psh_options']['pingrst_int']);
+		unset($ccdent['psh_options']['pingexit_int']);
+
+		if ($_POST['psh_rtedelay_int'])
+			$ccdent['psh_options']['rtedelay_int'] = $_POST['psh_rtedelay_int'];
+		if ($_POST['psh_inact_int'])
+			$ccdent['psh_options']['inact_int'] = $_POST['psh_inact_int'];
+		if ($_POST['psh_ping_int'])
+			$ccdent['psh_options']['ping_int'] = $_POST['psh_ping_int'];
+		if ($_POST['psh_pingrst_int'])
+			$ccdent['psh_options']['pingrst_int'] = $_POST['psh_pingrst_int'];
+		if ($_POST['psh_pingexit_int'])
+			$ccdent['psh_options']['pingexit_int'] = $_POST['psh_pingexit_int'];
+
+                if (isset($id) && $ovpnccd[$id])
+                        $ovpnccd[$id] = $ccdent;
+                else
+                        $ovpnccd[] = $ccdent;
+                
+                write_config();
+                touch($d_ovpnccddirty_path);
+                
+                header("Location: vpn_openvpn_ccd.php");
+                exit;
+
+	} else {
+
+		$pconfig = $_POST;
+
+		$pconfig['enable'] = "true";
+		if (isset($_POST['disabled']))
+			unset($pconfig['enable']);
+
+		$pconfig['psh_reset'] = $_POST['psh_reset'];
+		$pconfig['psh_options']['redir'] = $_POST['psh_redir'];
+		$pconfig['psh_options']['redir_loc'] = $_POST['psh_redir_loc'];
+		$pconfig['psh_options']['rtedelay'] = $_POST['psh_rtedelay'];
+		$pconfig['psh_options']['inact'] = $_POST['psh_inact'];
+		$pconfig['psh_options']['ping'] = $_POST['psh_ping'];
+		$pconfig['psh_options']['pingrst'] = $_POST['psh_pingrst'];
+		$pconfig['psh_options']['pingexit'] = $_POST['psh_pingexit'];
+
+		$pconfig['psh_options']['rtedelay_int'] = $_POST['psh_rtedelay_int'];
+		$pconfig['psh_options']['inact_int'] = $_POST['psh_inact_int'];
+		$pconfig['psh_options']['ping_int'] = $_POST['psh_ping_int'];
+		$pconfig['psh_options']['pingrst_int'] = $_POST['psh_pingrst_int'];
+		$pconfig['psh_options']['pingexit_int'] = $_POST['psh_pingexit_int'];
+	}
+}
+?>
+
+<?php include("fbegin.inc"); ?>
+<script language="JavaScript">
+function enable_change(enable_over) {
+	var endis;
+	endis = !(!document.iform.disabled.checked || enable_over);
+        
+	document.iform.cn.disabled = endis;
+	document.iform.disable.disabled = endis;
+	document.iform.descr.disabled = endis;
+	document.iform.psh_reset.disabled = endis;
+	document.iform.psh_redir.disabled = endis;
+	document.iform.psh_redir_loc.disabled = endis;
+	document.iform.psh_rtedelay.disabled = endis;
+	document.iform.psh_rtedelay_int.disabled = endis;
+	document.iform.psh_inact.disabled = endis;
+	document.iform.psh_inact_int.disabled = endis;
+	document.iform.psh_ping.disabled = endis;
+	document.iform.psh_ping_int.disabled = endis;
+	document.iform.psh_pingexit.disabled = endis;
+	document.iform.psh_pingexit_int.disabled = endis;
+	document.iform.psh_pingrst.disabled = endis;
+	document.iform.psh_pingrst_int.disabled = endis;
+	document.iform.options.disabled = endis;
+
+	if (!document.iform.disabled.checked) {
+		push_change(false);
+		disable_change(false);
+	}
+
+}
+
+function disable_change(enable_over) {
+	var endis;
+	endis = !(!document.iform.disable.checked || enable_over);
+        
+	document.iform.psh_reset.disabled = endis;
+	document.iform.psh_redir.disabled = endis;
+	document.iform.psh_redir_loc.disabled = endis;
+	document.iform.psh_rtedelay.disabled = endis;
+	document.iform.psh_rtedelay_int.disabled = endis;
+	document.iform.psh_inact.disabled = endis;
+	document.iform.psh_inact_int.disabled = endis;
+	document.iform.psh_ping.disabled = endis;
+	document.iform.psh_ping_int.disabled = endis;
+	document.iform.psh_pingexit.disabled = endis;
+	document.iform.psh_pingexit_int.disabled = endis;
+	document.iform.psh_pingrst.disabled = endis;
+	document.iform.psh_pingrst_int.disabled = endis;
+	document.iform.options.disabled = endis;
+
+	if (!document.iform.disable.checked) {
+		push_change(enable_over);
+	}
+
+}
+
+function push_change(enable_over) {
+	var endis;
+	endis = !(document.iform.psh_reset.checked || enable_over);
+        
+	document.iform.psh_redir.disabled = endis;
+	document.iform.psh_redir_loc.disabled = endis;
+	document.iform.psh_rtedelay.disabled = endis;
+	document.iform.psh_rtedelay_int.disabled = endis;
+	document.iform.psh_inact.disabled = endis;
+	document.iform.psh_inact_int.disabled = endis;
+	document.iform.psh_ping.disabled = endis;
+	document.iform.psh_ping_int.disabled = endis;
+	document.iform.psh_pingexit.disabled = endis;
+	document.iform.psh_pingexit_int.disabled = endis;
+	document.iform.psh_pingrst.disabled = endis;
+	document.iform.psh_pingrst_int.disabled = endis;
+}
+
+//-->
+</script>
+
+<?php if ($input_errors) print_input_errors($input_errors);?>
+<form action="vpn_openvpn_ccd_edit.php" method="post" enctype="multipart/form-data" name="iform" id="iform">
+<strong><span class="red">WARNING: This feature is experimental and modifies your optional interface configuration.
+  Backup your configuration before using OpenVPN, and restore it before upgrading.<br>&nbsp;<br>
+</span></strong>
+<table width="100%" border="0" cellpadding="6" cellspacing="0">
+    <tr>
+     <td width="22%" valign="top" class="vncellreq">Disabled</td>
+     <td width="78%" class="vtable">
+	<input name="disabled" type="checkbox" value="yes" onclick="enable_change(false)" <?php if (!isset($pconfig['enable'])) echo "checked"; ?>>
+	<strong>Disable this entry</strong><br>
+	<span class="vexpl">Set this option to disable this client-specific configuration
+	without removing it from the list.</span></td>
+      </td>
+    </tr>
+   
+    <tr> 
+      <td width="22%" valign="top" class="vncellreq">Common Name</td>
+      <td width="78%" class="vtable"> 
+        <input name="cn" type="text" class="formfld" id="cn" size="40" value="<?=htmlspecialchars($pconfig['cn']);?>"> 
+        <br><span class="vexpl">Enter client's X.509 common name here.</span></td>
+    </tr>
+
+    <tr> 
+      <td width="22%" valign="top" class="vncell">Description</td>
+      <td width="78%" class="vtable"> 
+        <input name="descr" type="text" class="formfld" id="descr" size="40" value="<?=htmlspecialchars($pconfig['descr']);?>"> 
+        <br><span class="vexpl">You may enter a description here for your reference (not parsed).</span></td>
+    </tr>
+
+    <tr>
+     <td width="22%" valign="top" class="vncell">Block client</td>
+     <td width="78%" class="vtable">
+	<input name="disable" type="checkbox" value="yes" onclick="disable_change(false)" <?php if (isset($pconfig['disable'])) echo "checked"; ?>>
+	<strong>Disable this client from connecting</strong><br>
+	<span class="vexpl">Disable a particular client (based on the common name) from connecting.
+	Don't use this option to disable a client due to key
+	or password compromise. Use a CRL (certificate revocation list)
+	instead.</span></td>
+      </td>
+    </tr>
+   
+    <tr> 
+    <tr> 
+      <td colspan="2" valign="top" height="16"></td>
+    </tr>
+    <tr>
+      <td colspan="2" valign="top" class="listtopic">Push options</td>
+    </tr>
+	 
+    <tr>
+      <td width="22%" valign="top" class="vncell">Client-Push Inheritation</td>
+      <td width="78%" class="vtable">
+	<input type="checkbox" name="psh_reset" value="yes" onchange="push_change(false)" <?php if (isset($pconfig['psh_reset'])) echo "checked"; ?>>Push reset
+	<br><span class="vexpl">Set this option to on, if you don't want to inherit
+	the global push list for this client from the server page.</span>
+      </td>
+    </tr>
+    <tr>
+      <td width="22%" valign="top" class="vncell">Client-push options</td>
+      <td width="78%" class="vtable">
+	<table border="0" cellspacing="0" cellpadding="0">
+	  <tr>
+            <td><input type="checkbox" name="psh_redir" value="yes" <?php if (isset($pconfig['psh_options']['redir'])) echo "checked"; ?>>
+            Redirect-gateway</td>
+            <td>&nbsp;</td>
+            <td><input type="checkbox" name="psh_redir_loc" value="yes" <?php if (isset($pconfig['psh_options']['redir_loc'])) echo "checked"; ?>>
+              Local</td>
+	  </tr>
+          <tr>
+            <td><input type="checkbox" name="psh_rtedelay" value="yes" <?php if (isset($pconfig['psh_options']['rtedelay'])) echo "checked"; ?>> Route-delay</td>
+            <td width="16">&nbsp;</td>
+            <td><input type="text" name="psh_rtedelay_int" class="formfld" size="4" value="<?= $pconfig['psh_options']['rtedelay_int']?>"> seconds</td>
+          </tr>
+          <tr>
+            <td><input type="checkbox" name="psh_inact" value="yes" <?php if (isset($pconfig['psh_options']['inact'])) echo "checked"; ?>>
+    Inactive</td>
+            <td>&nbsp;</td>
+            <td><input type="text" name="psh_inact_int" class="formfld" size="4" value="<?= $pconfig['psh_options']['inact_int']?>">
+    seconds</td>
+          </tr>
+          <tr>
+            <td><input type="checkbox" name="psh_ping" value="yes" <?php if (isset($pconfig['psh_options']['ping'])) echo "checked"; ?>> Ping</td>
+            <td>&nbsp;</td>
+            <td>Interval: <input type="text" name="psh_ping_int" class="formfld" size="4" value="<?= $pconfig['psh_options']['ping_int']?>"> seconds</td>
+          </tr>
+          <tr>
+            <td><input type="checkbox" name="psh_pingexit" value="yes" <?php if (isset($pconfig['psh_options']['pingexit'])) echo "checked"; ?>> Ping-exit</td>
+            <td>&nbsp;</td>
+            <td>Interval: <input type="text" name="psh_pingexit_int" class="formfld" size="4" value="<?= $pconfig['psh_options']['pingexit_int']?>"> seconds</td>
+          </tr>
+          <tr>
+            <td><input type="checkbox" name="psh_pingrst" value="yes" <?php if (isset($pconfig['psh_options']['pingrst'])) echo "checked"; ?>> Ping-restart</td>
+            <td>&nbsp;</td>
+            <td>Interval: <input type="text" name="psh_pingrst_int" class="formfld" size="4" value="<?= $pconfig['psh_options']['pingrst_int']?>"> seconds</td>
+          </tr>
+        </table></td>
+    </tr>
+
+     <tr>
+      <td width="22%" valign="top" class="vncell">Custom client options</td>
+      <td width="78%" class="vtable">
+	<span>The following options are legal in a client-specific  context:<br>
+	push, push-reset, iroute, ifconfig-push and config.</span><br>
+        <textarea name="options" id="options" cols="65" rows="4" class="formpre"><?=htmlspecialchars($pconfig['options']);?></textarea>
+	<strong><span class="red">Note:</span></strong><br>
+	Commands in here aren't supported.</span></strong>
+        </td>
+    </tr>
+
+    <tr>
+      <td width="22%" valign="top">&nbsp;</td>
+      <td width="78%">
+        <input name="Submit" type="submit" class="formbtn" value="Save" onclick="enable_change(true);disable_change(true)">
+        <?php if (isset($id)): ?>
+        <input name="id" type="hidden" value="<?=$id;?>"> 
+        <?php endif; ?>
+      </td>
+    </tr>
+</table>
+</form>
+<script language="JavaScript">
+<!--
+disable_change(false);
+push_change(false);
+enable_change(false);
+//-->
+</script>
+<?php include("fend.inc");
+?>
diff -Nur rootfs-1.21/usr/local/www/vpn_openvpn_ccd.php rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_ccd.php
--- rootfs-1.21/usr/local/www/vpn_openvpn_ccd.php	1970-01-01 01:00:00.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_ccd.php	2006-01-14 11:49:22.000000000 +0100
@@ -0,0 +1,191 @@
+#!/usr/local/bin/php
+<?php 
+/*
+	vpn_openvpn_ccd.php
+
+	Copyright (C) 2005-2006 Peter Allgeyer (allgeyer@web.de).
+	All rights reserved.
+	
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions are met:
+	
+	1. Redistributions of source code must retain the above copyright notice,
+	   this list of conditions and the following disclaimer.
+	
+	2. Redistributions in binary form must reproduce the above copyright
+	   notice, this list of conditions and the following disclaimer in the
+	   documentation and/or other materials provided with the distribution.
+	
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	POSSIBILITY OF SUCH DAMAGE.
+*/
+
+$pgtitle = array("VPN", "OpenVPN");
+require("guiconfig.inc");
+require_once("openvpn.inc");
+
+if (!is_array($config['ovpn']))
+	$config['ovpn'] = array();
+if (!is_array($config['ovpn']['server'])){
+	$config['ovpn']['server'] =  array();
+	$config['ovpn']['server']['tunnel'] =  array();
+}
+if (!is_array($config['ovpn']['server']['ccd']))
+	$config['ovpn']['server']['ccd'] =  array();
+
+$ovpnccd = &$config['ovpn']['server']['ccd'];
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+        $id = $_POST['id'];
+
+
+if ($_POST['apply']) {
+	$retval = 0;
+
+	$retval = ovpn_server_ccd_add();
+
+#
+#	/* should we send a SIGUSR1 to openvpn daemon? */
+#	foreach ($config['ovpn']['server']['tunnel'] as $id => $server) {
+#		/* get tunnel interface */
+#		$tun = $server['tun_iface'];
+#
+#		/* send SIGUSR1 to running openvpn daemon */
+#		if (isset($server['enable']))
+#			sigkillbypid($g['varrun_path']."/ovpn_srv_{$tun}.pid", "SIGUSR1");
+#	}
+#
+
+	/* remove dirty flag */
+	unlink_if_exists($d_ovpnccddirty_path);
+
+	$savemsg = get_std_save_message($retval);	
+}
+
+if ($_GET['act'] == "del") {
+	if ($ovpnccd[$id]) {
+		$ovpnent = $ovpnccd[$id];
+
+		unset($ovpnccd[$id]);
+		write_config();
+
+		/* Remove config files */
+		ovpn_server_ccd_del($ovpnent['cn']);
+
+		header("Location: vpn_openvpn_ccd.php");
+		exit;
+	}
+
+} else if ($_GET['act'] == "toggle") {
+	if ($ovpnccd[$_GET['id']]) {
+		$ovpnccd[$_GET['id']]['enable'] = !isset($ovpnccd[$_GET['id']]['enable']);
+		write_config();
+		touch($d_ovpnccddirty_path);
+		header("Location: vpn_openvpn_ccd.php");
+		exit;
+	}
+}
+
+
+?>
+
+<?php include("fbegin.inc"); ?>
+<?php if ($input_errors) print_input_errors($input_errors); ?>
+<?php if (file_exists($d_sysrebootreqd_path) && !file_exists($d_ovpnccddirty_path)) print_info_box(get_std_save_message(0)); ?>
+<form action="vpn_openvpn_ccd.php" method="post" enctype="multipart/form-data" name="iform" id="iform">
+<?php if (file_exists($d_ovpnccddirty_path)): ?><p>
+<?php print_info_box_np("OpenVPN client-specific configuration options have been changed.<br>You must apply the changes in order for them to take effect.");?><br>
+<input name="apply" type="submit" class="formbtn" id="apply" value="Apply changes"></p>
+<?php endif; ?>
+
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+  <tr><td>
+  <ul id="tabnav">	        
+	<li class="tabinact"><a href="vpn_openvpn_srv.php">Server</a></li>
+	<li class="tabinact"><a href="vpn_openvpn_cli.php">Client</a></li>
+	<li class="tabact">Client-specific Configuration</li>
+	<li class="tabinact"><a href="vpn_openvpn_crl.php">CRL</a></li>
+  </ul>
+  </td></tr>
+  <tr>
+  <td class="tabcont">
+  <strong><span class="red">WARNING: This feature is experimental and modifies your optional interface configuration.
+  Backup your configuration before using OpenVPN, and restore it before upgrading.<br>
+&nbsp;  <br>
+    </span></strong>
+    <table width="100%" border="0" cellpadding="0" cellspacing="0">
+	<tr>
+	  <td width="5%" class="list">&nbsp;</td>
+	  <td width="38%" class="listhdrr">Common Name</td>
+	  <td width="47%" class="listhdr">Description</td>
+	  <td width="10%" class="list"></td>
+	</tr>
+	<?php $i = 0; foreach ($ovpnccd as $ccd):
+
+		if (isset($ccd['disable']))
+			$iconfn = "block";
+		else
+			$iconfn = "pass";
+
+		if (!isset($ccd['enable'])) {
+			$spans = "<span class=\"gray\">";
+			$spane = "</span>";
+			$iconfn .= "_d";
+		} else {
+			$spans = $spane = "";
+		}
+	?>
+	
+	<tr>
+	  <td class="listt" align="center">
+	  	<a href="?act=toggle&id=<?=$i;?>"><img src="<?=$iconfn;?>.gif"
+		width="11" height="11" border="0" title="click to toggle enabled/disabled status"></a>
+	  </td>
+	  <td class="listlr"><?=$spans;?>
+		<?= $ccd['cn'];?>
+	  <?=$spane;?></td>
+	  <td class="listbg"><?=$spans;?>
+		<?= htmlspecialchars($ccd['descr']);?>&nbsp;
+	  <?=$spane;?></td>
+	  <td valign="middle" nowrap class="list"><a href="vpn_openvpn_ccd_edit.php?id=<?=$i;?>"><img src="e.gif" title="edit client-specific configuration" width="17" height="17" border="0"></a>
+		&nbsp;<a href="vpn_openvpn_ccd.php?act=del&id=<?=$i;?>" onclick="return confirm('Do you really want to delete this client-specific configuration?')"><img src="x.gif" title="delete client-specific configuration" width="17" height="17" border="0"></a></td>
+	</tr>
+  	<?php $i++; endforeach; ?>
+	<tr> 
+	  <td class="list" colspan="3">&nbsp;</td>
+	  <td class="list"><a href="vpn_openvpn_ccd_edit.php"><img src="plus.gif" title="add client-specific configuration" width="17" height="17" border="0"></a></td>
+	</tr>
+    </table>
+    <table border="0" cellspacing="0" cellpadding="0">
+      <tr> 
+	<td width="16"><img src="pass.gif" width="11" height="11"></td>
+	  <td>pass</td>
+	  <td width="14"></td>
+	  <td width="16"><img src="block.gif" width="11" height="11"></td>
+	  <td>block</td>
+	</tr>
+	<tr>
+	  <td colspan="5" height="4"></td>
+	</tr>
+	<tr> 
+	  <td><img src="pass_d.gif" width="11" height="11"></td>
+	  <td>pass (disabled)</td>
+	  <td></td>
+	  <td><img src="block_d.gif" width="11" height="11"></td>
+	  <td>block (disabled)</td>
+	</tr>
+    </table>
+  </td>
+</tr>
+</table>
+</form>
+<?php include("fend.inc"); ?>
diff -Nur rootfs-1.21/usr/local/www/vpn_openvpn_cli_edit.php rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_cli_edit.php
--- rootfs-1.21/usr/local/www/vpn_openvpn_cli_edit.php	1970-01-01 01:00:00.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_cli_edit.php	2006-01-14 11:49:22.000000000 +0100
@@ -0,0 +1,722 @@
+#!/usr/local/bin/php
+<?php 
+/*
+	vpn_openvpn_cli_edit.php
+
+	Copyright (C) 2004 Peter Curran (peter@closeconsultants.com).
+	Copyright (C) 2005-2006 Peter  Allgeyer (allgeyer@web.de).
+	All rights reserved.
+	
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions are met:
+	
+	1. Redistributions of source code must retain the above copyright notice,
+	   this list of conditions and the following disclaimer.
+	
+	2. Redistributions in binary form must reproduce the above copyright
+	   notice, this list of conditions and the following disclaimer in the
+	   documentation and/or other materials provided with the distribution.
+	
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	POSSIBILITY OF SUCH DAMAGE.
+*/
+
+$pgtitle = array("VPN", "OpenVPN", "Edit client");
+require("guiconfig.inc");
+require_once("openvpn.inc");
+
+if (!is_array($config['ovpn']))
+	$config['ovpn'] = array();
+if (!is_array($config['ovpn']['client'])){
+	$config['ovpn']['client'] =  array();
+	$config['ovpn']['client']['tunnel'] = array();
+}
+
+
+$ovpncli =& $config['ovpn']['client']['tunnel'];
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+	$id = $_POST['id'];
+
+if (isset($id) && $ovpncli[$id]) {
+	$pconfig = $config['ovpn']['client']['tunnel'][$id];
+	if (isset($ovpncli[$id]['pull']))
+		$pconfig['pull'] = true;
+	if (is_array($ovpncli[$id]['expertmode'])) {
+		$pconfig['expertmode_options'] = "";
+		foreach ($ovpncli[$id]['expertmode']['option'] as $optent) {
+			$pconfig['expertmode_options'] .= $optent . "\n"; 
+		}
+		$pconfig['expertmode_options'] = rtrim($pconfig['expertmode_options']); 
+	}
+
+} else {
+	/* creating - set defaults */
+	$pconfig = array();
+	$pconfig['authentication_method'] = "rsasig";
+	$pconfig['type'] = 'tun';
+	$pconfig['proto'] = 'udp';
+	$pconfig['sport'] = '1194';
+	$pconfig['ver'] = '2';
+	$pconfig['crypto'] = 'BF-CBC';
+	$pconfig['pull'] = true;
+	$pconfig['enable'] = true;
+}
+
+if ($_POST) {
+
+	/* Called from form */
+	unset($input_errors);
+
+	/* input validation */
+	$reqdfields = explode(" ", "type saddr sport");
+	$reqdfieldsn = explode(",", "Tunnel type,Address,Port");
+
+	if ($_POST['authentication_method'] == "pre_shared_key") {
+		$reqdfields  = array_merge($reqdfields, explode(" ", "lipaddr pre-shared-key"));
+		$reqdfieldsn = array_merge($reqdfieldsn, explode(",", "Local IP address,Pre-shared secret"));
+
+		if ($_POST['type'] == "tun") {
+			/* tun */
+			$reqdfields  = array_merge($reqdfields, explode(" ", "ripaddr"));
+			$reqdfieldsn = array_merge($reqdfieldsn, explode(",", "Remote IP address"));
+
+			/* subnet or ip address */
+			if ($_POST['ripaddr']) {
+				if (!is_ipaddr($_POST['ripaddr']))
+					$input_errors[] = "A valid static remote IP address must be specified.";
+				else if (ip2long($_POST['lipaddr']) == ip2long($_POST['ripaddr']))
+					$input_errors[] = "Local IP address and remote IP address are the same.";
+			}
+			if ($_POST['lipaddr'])
+				if (!is_ipaddr($_POST['lipaddr']))
+					$input_errors[] = "A valid static local IP address must be specified.";
+
+		} else {
+			/* tap */
+			if ($_POST['lipaddr']) {
+				if (!is_ipaddr($_POST['lipaddr']))
+					$input_errors[] = "A valid static local IP address must be specified.";
+				else if (gen_subnet($_POST['lipaddr'], $_POST['netmask']) == $_POST['lipaddr']) 
+					$input_errors[] = "Local IP address is subnet address.";
+				else if (gen_subnet_max($_POST['lipaddr'], $_POST['netmask']) == $_POST['lipaddr']) 
+					$input_errors[] = "Local IP address is broadcast address.";
+			}
+		}
+
+		if (!empty($_POST['pre-shared-key']) &&
+		   (!strstr($_POST['pre-shared-key'], "BEGIN OpenVPN Static key") ||
+		    !strstr($_POST['pre-shared-key'], "END OpenVPN Static key")))
+			$input_errors[] = "Pre-shared secret does not appear to be valid.";
+
+	} else {
+		/* rsa */
+		$reqdfields  = array_merge($reqdfields, explode(" ", "ca_cert cli_cert cli_key"));
+		$reqdfieldsn = array_merge($reqdfieldsn, explode(",", "CA certificate,Client certificate,Client key"));
+
+		if (!empty($_POST['ca_cert']) &&
+		   (!strstr($_POST['ca_cert'], "BEGIN CERTIFICATE") ||
+		    !strstr($_POST['ca_cert'], "END CERTIFICATE")))
+			$input_errors[] = "The CA certificate does not appear to be valid.";
+		
+		if (!empty($_POST['cli_cert']) &&
+		   (!strstr($_POST['cli_cert'], "BEGIN CERTIFICATE") ||
+		    !strstr($_POST['cli_cert'], "END CERTIFICATE")))
+			$input_errors[] = "The client certificate does not appear to be valid.";
+		
+		if (!empty($_POST['cli_key']) &&
+		   (!strstr($_POST['cli_key'], "BEGIN RSA PRIVATE KEY") ||
+		    !strstr($_POST['cli_key'], "END RSA PRIVATE KEY")))
+			$input_errors[] = "The client key does not appear to be valid.";
+
+		if (!empty($_POST['pre-shared-key']) &&
+		   (!strstr($_POST['pre-shared-key'], "BEGIN OpenVPN Static key") ||
+		    !strstr($_POST['pre-shared-key'], "END OpenVPN Static key")))
+			$input_errors[] = "Pre-shared secret does not appear to be valid.";
+
+		if (isset($_POST['tlsauth']) && empty($_POST['pre-shared-key'])) {
+			$reqdfields  = array_merge($reqdfields, explode(" ", "pre-shared-key"));
+			$reqdfieldsn = array_merge($reqdfieldsn, explode(",", "Pre-shared secret"));
+		}
+	}
+
+	do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors);
+ 
+	/* valid Port */
+	if (($_POST['sport'] && !is_port($_POST['sport'])))
+		$input_errors[] = "The server's port must be an integer between 1 and 65535.";
+
+	/* valid FQDN or IP address */
+	if (($_POST['saddr'] && !is_ipaddr($_POST['saddr']) && !is_domain($_POST['saddr'])))
+		$input_errors[] = "The server name contains invalid characters.";
+
+	if (isset($id) && $ovpncli[$id]) {
+		/* Editing an existing entry */
+		$ovpnent = $ovpncli[$id];
+
+		if ($ovpncli[$id]['bridge'] != $_POST['bridge']) {
+			/* double bridging? */
+			if ($_POST['bridge'] &&
+			    $_POST['type'] == "tap" &&
+			    $_POST['authentication_method'] == "rsasig")
+				$retval = check_bridging($_POST['bridge']);
+
+			if (!empty($retval))
+				$input_errors[] = $retval;
+		}
+
+		if ( $ovpncli[$id]['sport'] != $_POST['sport'] ||
+			$ovpncli[$id]['proto'] != $_POST['proto'] ) {
+
+			/* some entries changed */
+			for ($i = 0; isset($config['ovpn']['client']['tunnel'][$i]); $i++) {
+				$current = &$config['ovpn']['client']['tunnel'][$i];
+
+				if ($current['sport'] == $_POST['sport'])
+					if ($current['proto'] == $_POST['proto'])
+						$input_errors[] = "You already have this combination for port and protocol settings. You can't use it twice";
+			}
+		}
+
+		/* Test Server type hasn't changed */
+		if ($ovpnent['type'] != $_POST['type'])
+			$input_errors[] = "Delete this interface first before changing the type of the tunnel to "
+			                . strtoupper($_POST['type']) .".";
+
+		if (!isset($ovpnent['enable']) && !isset($_POST['disabled'])) {
+
+			/* check if port number is free, else choose another one */
+			if (in_array($ovpnent['cport'], used_port_list()))
+				$ovpnent['cport'] = getnxt_port();
+		}
+	} else {
+		/* Creating a new entry */
+		$ovpnent = array();
+		if (!($ovpnent['if'] = getnxt_if($_POST['type'])))
+			$input_errors[] = "Run out of devices for a tunnel of type {$_POST['type']}";
+
+		$ovpnent['cport'] = getnxt_port();
+
+		/* double bridging? */
+		if ($_POST['bridge'] &&
+		    $_POST['type'] == "tap" &&
+		    $_POST['authentication_method'] == "rsasig") {
+			$retval = check_bridging($_POST['bridge']);
+
+			if (!empty($retval))
+				$input_errors[] = $retval;
+		}
+	}
+
+	if (!$input_errors) {
+
+		$ovpnent['enable'] = isset($_POST['disabled']) ? false : true;
+		$ovpnent['type'] = $_POST['type'];
+		$ovpnent['authentication_method'] = $_POST['authentication_method'];
+		$ovpnent['proto'] = $_POST['proto'];
+		$ovpnent['sport'] = $_POST['sport'];
+		$ovpnent['ver'] = $_POST['ver'];
+		$ovpnent['saddr'] = $_POST['saddr'];
+		$ovpnent['descr'] = $_POST['descr'];
+		$ovpnent['ca_cert'] = $pconfig['ca_cert'];
+		$ovpnent['cli_cert'] = $pconfig['cli_cert'];
+		$ovpnent['cli_key'] = $pconfig['cli_key'];
+		$ovpnent['crypto'] = $_POST['crypto'];
+		$ovpnent['comp_method'] = $_POST['comp_method'];
+		$ovpnent['ns_cert_type'] = $_POST['ns_cert_type'] ? true : false;
+		$ovpnent['pull'] = $_POST['pull'] ? true : false;
+		$ovpnent['dupcn'] = $_POST['dupcn'] ? true : false;
+		$ovpnent['tlsauth'] = $_POST['tlsauth'] ? true : false;
+		$ovpnent['bridge'] = $_POST['bridge'];
+		$ovpnent['lipaddr'] = $_POST['lipaddr'];
+		$ovpnent['ripaddr'] = $_POST['ripaddr'];
+		$ovpnent['netmask'] = $_POST['netmask'];
+
+		unset($ovpnent['pre-shared-key']);
+		if ($_POST['pre-shared-key'])
+			$ovpnent['pre-shared-key'] = base64_encode($_POST['pre-shared-key']);   
+
+		$ovpnent['ca_cert'] = base64_encode($_POST['ca_cert']);
+		$ovpnent['cli_cert'] = base64_encode($_POST['cli_cert']);
+		$ovpnent['cli_key'] = base64_encode($_POST['cli_key']);
+
+		/* expertmode params */
+		$ovpnent['expertmode_enabled'] = $_POST['expertmode_enabled'] ? true : false;
+
+		if (!is_array($options))
+			$options = array();
+		if (!is_array($ovpnent['expertmode']))
+			$ovpnent['expertmode'] = array();
+
+		$options['option'] = array_map('trim', explode("\n", trim($_POST['expertmode_options'])));
+		$ovpnent['expertmode'] = $options;
+
+		if (isset($id) && $ovpncli[$id]){
+			$ovpncli[$id] = $ovpnent;
+		}
+		else{
+			$ovpncli[] = $ovpnent;
+		}
+		
+		write_config();
+		ovpn_cli_dirty($ovpnent['if']);
+
+		header("Location: vpn_openvpn_cli.php");
+		exit;
+	} else {
+		$pconfig = $_POST;
+
+		$pconfig['enable'] = "true";
+		if (isset($_POST['disabled']))
+			unset($pconfig['enable']);
+
+		$pconfig['pre-shared-key'] = base64_encode($_POST['pre-shared-key']); 
+		$pconfig['ca_cert'] = base64_encode($_POST['ca_cert']);
+		$pconfig['cli_cert'] = base64_encode($_POST['cli_cert']);
+		$pconfig['cli_key'] = base64_encode($_POST['cli_key']);
+	}
+}
+
+?>
+<?php include("fbegin.inc"); ?>
+<script language="JavaScript">
+function enable_change(enable_over) {
+	var endis;
+	endis = !(!document.iform.disabled.checked || enable_over);
+
+	document.iform.type[0].disabled = endis;
+	document.iform.type[1].disabled = endis;
+	document.iform.proto[0].disabled = endis;
+	document.iform.proto[1].disabled = endis;
+	document.iform.sport.disabled = endis;
+	document.iform.saddr.disabled = endis;
+	document.iform.ver[0].disabled = endis;
+	document.iform.ver[1].disabled = endis;
+	document.iform.descr.disabled = endis;
+	document.iform.authentication_method.disabled = endis;
+	document.iform.ca_cert.disabled = endis;
+	document.iform.cli_cert.disabled = endis;
+	document.iform.cli_key.disabled = endis;
+	document.iform.crypto.disabled = endis;
+	document.iform.comp_method.disabled = endis;
+	document.iform.ns_cert_type.disabled = endis;
+	document.iform.pull.disabled = endis;
+	document.iform.tlsauth.disabled = endis;
+	document.iform.lipaddr.disabled = endis;
+	document.iform.ripaddr.disabled = endis;
+	document.iform.netmask.disabled = endis;
+	document.iform.psk.disabled = endis;
+	document.iform.expertmode_enabled.disabled = endis;
+	document.iform.expertmode_options.disabled = endis;
+
+	if (!document.iform.disabled.checked) {
+		tls_change(enable_over);
+		expertmode_change(enable_over);
+		methodsel_change(enable_over);
+	}
+}
+
+function expertmode_change(enable_over) {
+	var endis;
+	endis = !(document.iform.expertmode_enabled.checked || enable_over);
+
+	document.iform.expertmode_options.disabled = endis;
+}
+
+function tls_change(enable_over) {
+	var endis;
+	endis = !(document.iform.tlsauth.checked || enable_over);
+
+	document.iform.psk.disabled = endis;
+}
+
+function methodsel_change(enable_over) {
+	var endis;
+
+	switch (document.iform.authentication_method.selectedIndex) {
+		case 1: /* rsa */
+			if (get_radio_value(document.iform.type) == "tap") {
+				/* tap */
+				document.iform.bridge.disabled = 0;
+			} else {
+				/* tun */
+				document.iform.bridge.disabled = 1;
+				document.iform.bridge.selectedIndex = 0;
+			}
+
+			document.iform.psk.disabled = 1;
+			document.iform.ca_cert.disabled = 0;
+			document.iform.cli_cert.disabled = 0;
+			document.iform.cli_key.disabled = 0;
+			document.iform.ns_cert_type.disabled = 0;
+			document.iform.tlsauth.disabled = 0;
+			document.iform.lipaddr.disabled = 1;
+			document.iform.ripaddr.disabled = 1;
+			document.iform.netmask.disabled = 1;
+			document.iform.pull.disabled = 0;
+			tls_change();
+			break;
+		default: /* pre-shared */
+			if (get_radio_value(document.iform.type) == "tap") {
+				/* tap */
+				document.iform.ripaddr.disabled = 1;
+				document.iform.netmask.disabled = 0;
+			} else {
+				/* tun */
+				document.iform.ripaddr.disabled = 0;
+				document.iform.netmask.disabled = 1;
+			}
+
+			document.iform.lipaddr.disabled = 0;
+			document.iform.psk.disabled = 0;
+			document.iform.ca_cert.disabled = 1;
+			document.iform.cli_cert.disabled = 1;
+			document.iform.cli_key.disabled = 1;
+			document.iform.ns_cert_type.disabled = 1;
+			document.iform.tlsauth.disabled = 1;
+			document.iform.bridge.disabled = 1;
+			document.iform.bridge.selectedIndex = 0;
+			document.iform.pull.disabled = 1;
+			break;
+	}
+
+	if (enable_over) {
+		document.iform.psk.disabled = 0;
+		document.iform.ca_cert.disabled = 0;
+		document.iform.cli_cert.disabled = 0;
+		document.iform.cli_key.disabled = 0;
+		document.iform.tlsauth.disabled = 0;
+		document.iform.bridge.disabled = 0;
+		document.iform.lipaddr.disabled = 0;
+		document.iform.ripaddr.disabled = 0;
+		document.iform.netmask.disabled = 0;
+		document.iform.pull.disabled = 0;
+	}
+}
+
+function get_radio_value(obj) {
+	for (i = 0; i < obj.length; i++) {
+		if (obj[i].checked)
+		return obj[i].value;
+	}
+	return null;
+}
+
+//-->
+</script>
+
+<?php if ($input_errors) print_input_errors($input_errors); ?>
+
+<form action="vpn_openvpn_cli_edit.php" method="post" enctype="multipart/form-data" name="iform" id="iform">
+  <table width="100%" border="0" cellpadding="6" cellspacing="0">
+    <tr>
+      <td width="22%" valign="top" class="vncellreq">Disabled</td>
+      <td width="78%" class="vtable"> 
+        <input name="disabled" type="checkbox" id="disabled" value="yes" onclick="enable_change(false)" <?php if (!isset($pconfig['enable'])) echo "checked"; ?>>
+        <strong>Disable this client</strong><br>
+        <span class="vexpl">Set this option to disable this client without removing it from the list.</span>
+      </td>
+    </tr>
+	
+    <tr> 
+      <td colspan="2" class="list" height="12"></td>
+    </tr>
+    
+    <tr>
+      <td colspan="2" valign="top" class="listtopic">Server information</td>
+    </tr>
+    
+    <tr>
+      <td width="22%" valign="top" class="vncellreq">Address</td>
+      <td width="78%" class="vtable"> 
+	<input name="saddr" type="text" class="formfld" size="20" maxlength="255" value="<?=htmlspecialchars($pconfig['saddr']);?>">
+	<br>
+	Enter the server's IP address or FQDN.</td>
+    </tr>
+    
+    <tr>
+      <td width="22%" valign="top" class="vncellreq">Port</td>
+      <td width="78%" class="vtable">
+        <input name="sport" type="text" class="formfld" size="5" maxlength="5" value="<?=htmlspecialchars($pconfig['sport']);?>"><br>
+        Enter the server's port number (default is 1194).</td>
+    </tr>
+    
+    <tr>
+      <td width="22%" valign="top" class="vncellreq">Version</td>
+      <td width="78%" class="vtable"> 
+        <input name="ver" type="radio" class="formfld" value="2" <?php if ($pconfig['ver'] == '2') echo "checked"; ?>> 2.0&nbsp;
+	<input name="ver" type="radio" class="formfld" value="1" <?php if ($pconfig['ver'] == '1') echo "checked"; ?>> 1.x
+	<br>
+	Specify which version of the OpenVPN protocol the server runs.</td>
+    </tr>
+    
+    <tr> 
+      <td width="22%" valign="top" class="vncell">Description</td>
+      <td width="78%" class="vtable"> 
+        <input name="descr" type="text" class="formfld" id="descr" size="40" value="<?=htmlspecialchars($pconfig['descr']);?>"> 
+        <br> <span class="vexpl">You may enter a description here for your reference (not parsed).</span></td>
+    </tr>
+    
+    <tr> 
+      <td colspan="2" class="list" height="12"></td>
+    </tr>
+    
+    <tr>
+      <td colspan="2" valign="top" class="listtopic">Cryptographic options</td>
+    </tr>
+    <tr> 
+      <td width="22%" valign="top" class="vncellreq">Authentication method</td>
+      <td width="78%" class="vtable"> 
+        <select name="authentication_method" class="formfld" onchange="methodsel_change(false)">
+          <?php foreach ($p1_authentication_methods as $method => $methodname): ?>
+            <option value="<?=$method;?>" <?php if ($method == $pconfig['authentication_method']) echo "selected"; ?>>
+                <?=htmlspecialchars($methodname);?>
+            </option>
+          <?php endforeach; ?>
+        </select> <br> <span class="vexpl">Must match the setting chosen on the remote side.</span></td>
+    </tr>
+
+    <tr> 
+      <td width="22%" valign="top" class="vncellreq">CA certificate</td>
+      <td width="78%" class="vtable"> 
+      <textarea name="ca_cert" cols="65" rows="4" class="formpre"><?=htmlspecialchars(base64_decode($pconfig['ca_cert']));?></textarea>
+      <br>      
+      Paste a CA certificate in X.509 PEM format here.</td>
+    </tr>
+		
+    <tr> 
+      <td width="22%" valign="top" class="vncellreq">Client certificate</td>
+      <td width="78%" class="vtable">
+        <textarea name="cli_cert" cols="65" rows="4" class="formpre"><?=htmlspecialchars(base64_decode($pconfig['cli_cert']));?></textarea>
+        <br>
+        Paste a client certificate in X.509 PEM format here.</td>
+     </tr>
+     
+     <tr> 
+       <td width="22%" valign="top" class="vncellreq">Client key</td>
+       <td width="78%" class="vtable"> 
+         <textarea name="cli_key" cols="65" rows="4" class="formpre"><?=htmlspecialchars(base64_decode($pconfig['cli_key']));?></textarea>
+         <br>Paste the client RSA private key here.</td>
+     </tr>
+     
+        
+      <tr>
+        <td width="22%" valign="top" class="vncell">Crypto</td>
+        <td width="78%" class="vtable">
+          <select name="crypto" class="formfld">
+	    <?php $cipher_list = ovpn_get_cipher_list();
+	    foreach($cipher_list as $key => $value){
+	    ?>
+	      <option value="<?= $key ?>" <?php if ($pconfig['crypto'] == $key) echo "selected"; ?>>
+	        <?= $value ?>
+	      </option>
+	    <?php
+	    }
+	    ?>
+	  </select>
+	  <br>
+	  Select the data channel encryption cipher.  This must match the setting on the server.
+	</td>
+      </tr>
+
+      <tr>
+        <td width="22%" valign="top" class="vncell">nsCertType</td>
+        <td width="78%" class="vtable">
+	  <input name="ns_cert_type" type="checkbox" value="yes" <?php if (isset($pconfig['ns_cert_type'])) echo "checked";?>>
+	  <strong>nsCertType</strong><br>
+	  Require  that  peer  certificate  was  signed  with  an explicit
+	  nsCertType designation of "server".
+	  This is a useful security option for clients, to ensure that the
+	  host they connect with is a designated server.
+      </tr>
+
+      <tr>
+        <td width="22%" valign="top" class="vncell">TLS auth</td>
+        <td width="78%" class="vtable">
+	  <input name="tlsauth" type="checkbox" value="yes" onclick="tls_change(false)" <?php if (isset($pconfig['tlsauth'])) echo "checked";?>>
+	  <strong>TLS auth</strong><br>
+          The tls-auth directive adds an additional HMAC signature to all SSL/TLS handshake packets for integrity verification.</td>
+      </tr>
+
+      <tr> 
+	<td width="22%" valign="top" class="vncell">Pre-shared secret</td>
+	<td width="78%" class="vtable">
+	  <textarea name="pre-shared-key" id="psk" cols="65" rows="4" class="formpre"><?=htmlspecialchars(base64_decode($pconfig['pre-shared-key']));?></textarea>
+	  <br>
+	  Paste your own pre-shared secret here.</td>
+      </tr>
+
+    <tr> 
+      <td colspan="2" class="list" height="12"></td>
+    </tr>
+    
+    <tr> 
+      <td colspan="2" valign="top" class="listtopic">Client configuration</td>
+    </tr>
+    
+    <tr>
+      <td valign="top" class="vncellreq">Tunnel type</td>
+      <td class="vtable">
+	<input name="type" type="radio" class="formfld" value="tun" onclick="methodsel_change(false)" <?php if ($pconfig['type'] == 'tun') echo "checked"; ?>> TUN&nbsp;
+	<input name="type" type="radio" class="formfld" value="tap" onclick="methodsel_change(false)" <?php if ($pconfig['type'] == 'tap') echo "checked"; ?>> TAP</td>
+    </tr> 
+    
+    <tr>
+      <td width="22%" valign="top" class="vncellreq">Tunnel protocol</td>
+      <td width="78%" class="vtable">
+<input name="proto" type="radio" class="formfld" value="udp" <?php if ($pconfig['proto'] == 'udp') echo "checked"; ?>> UDP&nbsp;
+<input name="proto" type="radio" class="formfld" value="tcp" <?php if ($pconfig['proto'] == 'tcp') echo "checked"; ?>> TCP<br>
+       <span class="vexpl">Important: These settings must match the server's configuration.</span></td>
+     </tr>
+
+    <tr> 
+      <td width="22%" valign="top" class="vncell">Interface</td>
+      <td width="78%" class="vtable">
+        <strong>Auto</strong>
+      </td>
+    </tr>
+    
+    <tr>
+      <td width="22%" valign="top" class="vncell">Port</td>
+      <td width="78%" class="vtable">
+	<strong>Auto</strong>
+      </td>
+    </tr>
+
+    <tr> 
+      <td width="22%" valign="top" class="vncell">Bridge with</td>
+      <td width="78%" class="vtable">
+	<select name="bridge" class="formfld" id="bridge" onchange="methodsel_change(false)">
+	<option <?php if (!$pconfig['bridge']) echo "selected";?> value="">none</option>
+	<?php $opts = array('lan' => "LAN", 'wan' => "WAN");
+	for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
+		if ($i != $index && !($config['interfaces']['opt' . $i]['ovpn']))
+			$opts['opt' . $i] = "Optional " . $i . " (" . $config['interfaces']['opt' . $i]['descr'] . ")";
+	}
+	foreach ($opts as $opt => $optname): ?>
+		<option <?php if ($opt == $pconfig['bridge']) echo "selected";?> value="<?=htmlspecialchars($opt);?>"> 
+		<?=htmlspecialchars($optname);?>
+		</option>
+	<?php endforeach; ?>
+	</select> <br> <span class="vexpl">Only supported with authentication method set to RSA signature.</span>
+      </td>
+    </tr>
+
+    <tr> 
+      <td width="22%" valign="top" class="vncell">OpenVPN address assignment</td>
+      <td width="78%" class="vtable"> 
+        When using pre-shared keys, enter the IP address and subnet mask
+        of the local and remote VPN endpoint here. For TAP devices, only the
+	IP address of the local VPN endpoint is needed. The netmask is the subnet mask
+        of the virtual ethernet segment which is being created or connected to.<br>
+        <br>
+        <table cellpadding="0" cellspacing="0">
+          <tr>
+            <td>Local IP address:&nbsp;&nbsp;</td>
+            <td valign="top"><input name="lipaddr" id="lipaddr" type="text" class="formfld" size="20" value="<?=htmlspecialchars($pconfig['lipaddr']);?>">
+                / 
+                <select name="netmask" id="netmask" class="formfld">
+                <?php for ($i = 30; $i > 19; $i--): ?>
+                  <option value="<?=$i;?>" <?php if ($i == $pconfig['netmask']) echo "selected"; ?>>
+                    <?=$i;?>
+                  </option>
+                <?php endfor; ?>
+                </select>
+            </td>
+          </tr>
+          <tr>
+            <td>Remote IP address:&nbsp;&nbsp;</td>
+            <td valign="top"><input name="ripaddr" id="ripaddr" type="text" class="formfld" size="20" value="<?=htmlspecialchars($pconfig['ripaddr']);?>">
+            </td>
+          </tr>
+        </table>
+      </td>
+    </tr>
+     
+    <tr> 
+      <td colspan="2" valign="top" height="12"></td>
+    </tr>
+    <tr>
+      <td colspan="2" valign="top" class="listtopic">Client Options</td>
+    </tr>
+
+    <tr>
+      <td width="22%" valign="top" class="vncell">Pull Options</td>
+      <td width="78%" class="vtable">
+        <input type="checkbox" name="pull" value="yes" <?php if ($pconfig['pull']) echo "checked"; ?>> 
+        <strong>Client-pull</strong><br>
+	This  option  must  be used on a client which is connecting to a
+	multi-client server.  It indicates to OpenVPN that it should
+	accept options pushed by the server, provided they are part of the
+	legal set of pushable options.
+	</td>
+    </tr>
+
+    <tr>
+      <td width="22%" valign="top" class="vncell">Compression method</td>
+      <td width="78%" class="vtable">
+	<select name="comp_method" class="formfld" id="comp_method">
+	<option <?php if (!$pconfig['comp_method']) echo "selected";?> value="">none</option>
+	<?php $compression_method = array('lzo' => 'LZO', 'noadapt' => 'LZO (no adaptive)');
+	    foreach($compression_method as $comp_method => $comp_methodname): ?>
+		<option value="<?=$comp_method;?>"
+		<?php if ($comp_method == $pconfig['comp_method']) echo "selected";?>>
+		  <?=htmlspecialchars($comp_methodname);?>
+		</option>
+	<?php endforeach; ?>
+	</select>
+	<br>
+	Choose which compression method to use.<br>
+	<br>
+	LZO compression generally improves performance on slow links,
+	but may add up to 1 byte per packet for incompressible data.<br>
+	<br>
+	With adaptive compression, OpenVPN will periodically sample the
+	compression process to measure its efficiency. If the data being
+	sent over the tunnel is already compressed, the compression
+	efficiency will be very low. Choose 'LZO (no adaptive)'
+	to disable OpenVPN's adaptive compression algorithm.
+	</td>
+     </tr>
+
+     <tr>
+      <td width="22%" valign="top" class="vncell">Expert mode</td>
+      <td width="78%" class="vtable">
+        <input name="expertmode_enabled" type="checkbox" value="yes" onclick="expertmode_change(false)" <?php if (isset($pconfig['expertmode_enabled'])) echo "checked"; ?>>
+        <strong>Enable expert OpenVPN mode</strong><br>
+        If this option is on, you can specify your own extra commands for the OpenVPN server.<br/>
+        <textarea name="expertmode_options" id="expertmode_options" cols="65" rows="4" class="formpre"><?=htmlspecialchars($pconfig['expertmode_options']);?></textarea>
+        <strong><span class="red">Note:</span></strong><br>
+	Commands in expert mode aren't supported.
+      </td>
+    </tr>
+
+    <tr> 
+      <td width="22%" valign="top">&nbsp;</td>
+      <td width="78%"> 
+         <input name="Submit" type="submit" class="formbtn" value="Save" onclick="methodsel_change(true);tls_change(true);expertmode_change(true);enable_change(true)">
+         <?php if (isset($id)): ?>
+         <input name="id" type="hidden" value="<?=$id;?>"> 
+         <?php endif; ?>
+      </td>
+    </tr>
+  </table>
+</form>
+<script language="JavaScript">
+<!--
+tls_change(false);
+methodsel_change(false);
+expertmode_change(false);
+enable_change(false);
+//-->
+</script>
+<?php include("fend.inc"); ?>
diff -Nur rootfs-1.21/usr/local/www/vpn_openvpn_cli.php rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_cli.php
--- rootfs-1.21/usr/local/www/vpn_openvpn_cli.php	1970-01-01 01:00:00.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_cli.php	2006-01-14 11:49:22.000000000 +0100
@@ -0,0 +1,166 @@
+#!/usr/local/bin/php
+<?php 
+/*
+	vpn_openvpn_cli.php
+
+	Copyright (C) 2004 Peter Curran (peter@closeconsultants.com).
+	Copyright (C) 2005-2006 Peter Allgeyer (allgeyer@web.de).
+	All rights reserved.
+	
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions are met:
+	
+	1. Redistributions of source code must retain the above copyright notice,
+	   this list of conditions and the following disclaimer.
+	
+	2. Redistributions in binary form must reproduce the above copyright
+	   notice, this list of conditions and the following disclaimer in the
+	   documentation and/or other materials provided with the distribution.
+	
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	POSSIBILITY OF SUCH DAMAGE.
+*/
+
+$pgtitle = array("VPN", "OpenVPN");
+require("guiconfig.inc");
+require_once("openvpn.inc");
+
+if (!is_array($config['ovpn']))
+	$config['ovpn'] = array();
+if (!is_array($config['ovpn']['client'])){
+	$config['ovpn']['client'] =  array();
+	$config['ovpn']['client']['tunnel'] =  array();
+}
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+	$id = $_POST['id'];
+
+$ovpncli =& $config['ovpn']['client']['tunnel'];
+
+if ($_POST['apply']) {
+		$retval = 0;
+		if (file_exists($d_sysrebootreqd_path)) {
+			/* Rewrite interface definitions */
+			$retval = ovpn_client_iface();
+		}
+		else{
+			ovpn_lock();
+			$retval = ovpn_client_iface();
+			$retval = ovpn_config_client();
+			ovpn_unlock();
+		}
+		if (file_exists($d_ovpnclidirty_path))
+			unlink($d_ovpnclidirty_path);
+		$savemsg = get_std_save_message($retval);	
+}
+
+if ($_GET['act'] == "del") {
+	if ($ovpncli[$id]) {
+		$ovpnent = $ovpncli[$id];
+		unset($ovpncli[$id]);
+
+		/* Kill running processes */
+		ovpn_client_kill($ovpnent['if']);
+
+		/* Remove old certs & keys */
+		ovpn_client_certs_del($ovpnent['if']);
+
+		/* Remove interface from list of optional interfaces */
+		ovpn_client_iface_del($ovpnent['if']);
+
+		write_config();
+		//touch($d_sysrebootreqd_path);
+		header("Location: vpn_openvpn_cli.php");
+		exit;
+	}
+}
+?>
+<?php include("fbegin.inc"); ?>
+<?php if ($input_errors) print_input_errors($input_errors); ?>
+<?php if (file_exists($d_sysrebootreqd_path) && !file_exists($d_ovpnclidirty_path)) print_info_box(get_std_save_message(0)); ?>
+<form action="vpn_openvpn_cli.php" method="post" enctype="multipart/form-data" name="iform" id="iform">
+<?php if (file_exists($d_ovpnclidirty_path)): ?><p>
+<?php print_info_box_np("The OpenVPN client configuration has been changed.<br>You must apply the changes in order for them to take effect.");?><br>
+<input name="apply" type="submit" class="formbtn" id="apply" value="Apply changes"></p>
+<?php endif; ?>
+
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+  <tr><td>
+  <ul id="tabnav">	        
+	<li class="tabinact1"><a href="vpn_openvpn_srv.php">Server</a></li>
+	<li class="tabact">Client</li>
+	<li class="tabinact"><a href="vpn_openvpn_ccd.php">Client-specific Configuration</a></li>
+	<li class="tabinact"><a href="vpn_openvpn_crl.php">CRL</a></li>
+  </ul>
+  </td></tr>
+  <tr>
+  <td class="tabcont">
+  <strong><span class="red">WARNING: This feature is experimental and modifies your optional interface configuration.
+  Backup your configuration before using OpenVPN, and restore it before upgrading.<br>
+&nbsp;  <br>
+    </span></strong>
+    <table width="100%" border="0" cellpadding="0" cellspacing="0">
+	<tr>
+	  <td width="10%" class="listhdrr">Interface</td>
+	  <td width="5%" class="listhdrr">Protocol</td>
+	  <td width="15%" class="listhdrr">Socket</td>
+	  <td width="15%" class="listhdrr">Server address</td>
+	  <td width="5%" class="listhdrr" align="center">Version</td>
+	  <td width="40%" class="listhdr">Description</td>
+	  <td width="10%" class="list"></td>
+	</tr>
+	
+	<?php $i = 0; foreach ($ovpncli as $client):
+					if (!isset($client['enable'])) {
+						$spans = "<span class=\"gray\">";
+						$spane = "</span>";
+					} else {
+						$spans = $spane = "";
+					}
+	?>
+	
+	<tr>
+	  <td class="listlr"><?=$spans;?>
+		<?php	if ($interface = ovpn_get_opt_interface($client['if']))
+				$iface = $config['interfaces'][$interface]['descr'];
+			else $iface = strtoupper($client['if']);?>
+		<?= $iface;?>
+	  <?=$spane;?></td>
+	  <td class="listr"><?=$spans;?>
+		<?= strtoupper($client['proto']);?>     
+          <?=$spane;?></td>
+	  <td class="listr"><?=$spans;?>
+		<?= "0.0.0.0:" . $client['cport'];?>	
+	  <?=$spane;?></td>
+	  <td class="listr"><?=$spans;?>
+		<?= $client['saddr'].":".$client['sport'];?>
+	  <?=$spane;?></td>
+	  <td align="middle" class="listr"><?=$spans;?>
+	  	<?= $client['ver'];?>
+	  <?=$spane;?></td>
+	   <td class="listbg"><?=$spans;?>
+	  	<?= htmlspecialchars($client['descr']);?>&nbsp;
+	  <?=$spane;?></td>
+	  <td valign="middle" nowrap class="list"> <a href="vpn_openvpn_cli_edit.php?id=<?=$i;?>"><img src="e.gif" title="edit client configuration" width="17" height="17" border="0"></a>
+		 &nbsp;<a href="vpn_openvpn_cli.php?act=del&id=<?=$i;?>" onclick="return confirm('Do you really want to delete this client configuration?')"><img src="x.gif" title="delete client configuration" width="17" height="17" border="0"></a></td>
+	</tr>
+  	<?php $i++; endforeach; ?>
+	<tr> 
+	  <td class="list" colspan="6">&nbsp;</td>
+	  <td class="list"> <a href="vpn_openvpn_cli_edit.php"><img src="plus.gif" title="add client configuration" width="17" height="17" border="0"></a></td>
+	</tr>
+    </table>
+  </td>
+</tr>
+</table>
+</form>
+<?php include("fend.inc"); ?>
diff -Nur rootfs-1.21/usr/local/www/vpn_openvpn_crl_edit.php rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_crl_edit.php
--- rootfs-1.21/usr/local/www/vpn_openvpn_crl_edit.php	1970-01-01 01:00:00.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_crl_edit.php	2006-01-14 11:49:22.000000000 +0100
@@ -0,0 +1,238 @@
+#!/usr/local/bin/php
+<?php 
+/*
+	vpn_openvpn_crl_edit.php
+
+	Copyright (C) 2005-2006 Peter Allgeyer (allgeyer@web.de).
+	All rights reserved.
+	
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions are met:
+	
+	1. Redistributions of source code must retain the above copyright notice,
+	   this list of conditions and the following disclaimer.
+	
+	2. Redistributions in binary form must reproduce the above copyright
+	   notice, this list of conditions and the following disclaimer in the
+	   documentation and/or other materials provided with the distribution.
+	
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	POSSIBILITY OF SUCH DAMAGE.
+*/
+
+$pgtitle = array("VPN", "OpenVPN", "Edit client-specific configuration");
+require("guiconfig.inc");
+require_once("openvpn.inc");
+
+if (!is_array($config['ovpn']))
+	$config['ovpn'] = array();
+if (!is_array($config['ovpn']['server']))
+	$config['ovpn']['server'] = array();
+if (!is_array($config['ovpn']['server']['crl']))
+	$config['ovpn']['server']['crl'] = array();
+
+$ovpncrl =& $config['ovpn']['server']['crl'];
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+	$id = $_POST['id'];
+
+if (isset($id) && $ovpncrl[$id]) {
+
+	$pconfig = $config['ovpn']['server']['crl'][$id];
+
+	if (isset($ovpncrl[$id]['enable']))
+		$pconfig['enable'] = true;
+
+} else {
+	/* creating - set defaults */
+	$pconfig = array();
+	$pconfig['enable'] = true;
+}
+
+if ($_POST) {
+
+	unset($input_errors);
+	$pconfig = $_POST;
+
+	/* input validation */
+	$reqdfields = explode(" ", "crlname");
+	$reqdfieldsn = explode(",", "Name");
+
+	do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors);
+
+	if (preg_match("/[^a-zA-Z0-9\.\-_]/", $_POST['crlname']))
+		$input_errors[] = "The name contains invalid characters.";
+
+	/* Editing an existing entry? */
+	if (!$input_errors && !(isset($id) && $ovpncrl[$id])) {
+		/* make sure there are no dupes */
+		foreach ($ovpncrl as $crlent) {
+			if ($crlent['crlname'] == $_POST['crlname']) {
+				$input_errors[] = "Another entry with the same name already exists.";
+				break;
+			}
+		}
+	}
+
+	/* check if a crl was given */
+	if (is_uploaded_file($_FILES['filename']['tmp_name']) && !empty($_FILES['filename']['size'])) {
+		$content = file_get_contents($_FILES['filename']['tmp_name']);
+	} else if (!empty($_POST['crl_list'])) {
+		$content = $_POST['crl_list'];
+	} else {
+		$content = "";
+		$input_errors[] = "A valid X.509 CRL is required.";
+	}
+
+	/* check if crl is valid */
+	if (!empty($content) &&
+	   (!strstr($content, "BEGIN X509 CRL") ||
+	    !strstr($content, "END X509 CRL")))
+		$input_errors[] = "The X.509 CRL file content does not appear to be valid.";
+
+	if (isset($id) && $ovpncrl[$id]) {
+		$crlent = $ovpncrl[$id];
+
+		/* Has the enable/disable state changed? */
+		if (isset($crlent['enable']) && isset($_POST['disabled'])) {
+			/* status changed to disabled */
+			ovpn_crl_dirty($ovpncrl['crlname']);
+		} else if (!isset($crlent['enable']) && !isset($_POST['disabled'])) {
+			/* status changed to enable */
+			ovpn_crl_dirty($ovpncrl['crlname']);
+		}
+	}
+
+	if (!$input_errors) {
+        
+		$crlent = array();
+
+		if (isset($id) && $ovpncrl[$id])
+			$crlent = $ovpncrl[$id];
+        
+                $crlent['crlname'] = $_POST['crlname'];
+		$crlent['descr'] = $_POST['descr'];
+		$crlent['enable'] = $_POST['disabled'] ? false : true;
+
+		/* file upload? */
+		if ($_POST['crlname'] && is_uploaded_file($_FILES['filename']['tmp_name']))
+			$crlent['crl_list'] = base64_encode(file_get_contents($_FILES['filename']['tmp_name']));
+		else if (!empty($_POST['crl_list']))
+			$crlent['crl_list'] = base64_encode($_POST['crl_list']);
+
+                if (isset($id) && $ovpncrl[$id])
+                        $ovpncrl[$id] = $crlent;
+                else
+                        $ovpncrl[] = $crlent;
+                
+                write_config();
+		ovpn_crl_dirty($ovpncrl['crlname']);
+                
+                header("Location: vpn_openvpn_crl.php");
+                exit;
+
+	} else {
+
+		$pconfig = $_POST;
+
+		$pconfig['enable'] = "true";
+		if (isset($_POST['disabled']))
+			unset($pconfig['enable']);
+
+		$pconfig['crl_list'] = base64_encode($_POST['crl_list']);
+	}
+}
+?>
+
+<?php include("fbegin.inc"); ?>
+<script language="JavaScript">
+function enable_change(enable_over) {
+	var endis;
+	endis = !(!document.iform.disabled.checked || enable_over);
+        
+	document.iform.crlname.disabled = endis;
+	document.iform.descr.disabled = endis;
+	document.iform.crl_list.disabled = endis;
+	document.iform.filename.disabled = endis;
+
+}
+
+//-->
+</script>
+
+<?php if ($input_errors) print_input_errors($input_errors);?>
+<form action="vpn_openvpn_crl_edit.php" method="post" enctype="multipart/form-data" name="iform" id="iform">
+<strong><span class="red">WARNING: This feature is experimental and modifies your optional interface configuration.
+  Backup your configuration before using OpenVPN, and restore it before upgrading.<br>&nbsp;<br>
+</span></strong>
+<table width="100%" border="0" cellpadding="6" cellspacing="0">
+    <tr>
+     <td width="22%" valign="top" class="vncellreq">Disabled</td>
+     <td width="78%" class="vtable">
+	<input name="disabled" type="checkbox" value="yes" onclick="enable_change(false)" <?php if (!isset($pconfig['enable'])) echo "checked"; ?>>
+	<strong>Disable this X.509 CRL list</strong><br>
+	<span class="vexpl">Set this option to on to disable this X.509 CRL file
+	without removing it from the list.</span></td>
+      </td>
+    </tr>
+   
+    <tr> 
+      <td width="22%" valign="top" class="vncellreq">Name</td>
+      <td width="78%" class="vtable"> 
+        <input name="crlname" type="text" class="formfld" id="crlname" size="40" value="<?=htmlspecialchars($pconfig['crlname']);?>"> 
+        <br><span class="vexpl">Enter a unique name here, to describe the X.509 CRL list.</span></td>
+    </tr>
+
+    <tr> 
+      <td width="22%" valign="top" class="vncell">Description</td>
+      <td width="78%" class="vtable"> 
+        <input name="descr" type="text" class="formfld" id="descr" size="40" value="<?=htmlspecialchars($pconfig['descr']);?>"> 
+        <br><span class="vexpl">You may enter a description here for your reference (not parsed).</span></td>
+    </tr>
+
+    <tr>
+      <td valign="top" class="vncellreq">X.509 CRL file content</td>
+      <td class="vtable">
+        <textarea name="crl_list" cols="65" rows="4" class="formpre"><?=htmlspecialchars(base64_decode($pconfig['crl_list']));?></textarea>
+        <br>
+	Paste the contents of a X.509 CRL file in PEM format here.</td>
+    </tr>
+
+    <tr>
+      <td width="22%" valign="top" class="vncell">X.509 CRL file</td>
+      <td class="vtable">
+	<input name="filename" type="file" class="formfld" id="filename"><br>
+	Instead of pasting the contents of a X.509 CRL file above,
+	you can upload a X.509 CRL file in PEM format here. It will
+	overwrite the values entered in the "X.509 CRL file content"
+	field.
+      </td>
+    </tr>
+
+    <tr>
+      <td width="22%" valign="top">&nbsp;</td>
+      <td width="78%">
+        <input name="Submit" type="submit" class="formbtn" value="Save" onclick="enable_change(true)">
+        <?php if (isset($id)): ?>
+        <input name="id" type="hidden" value="<?=$id;?>"> 
+        <?php endif; ?>
+      </td>
+    </tr>
+</table>
+</form>
+<script language="JavaScript">
+<!--
+enable_change(false);
+//-->
+</script>
+<?php include("fend.inc");
+?>
diff -Nur rootfs-1.21/usr/local/www/vpn_openvpn_crl.php rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_crl.php
--- rootfs-1.21/usr/local/www/vpn_openvpn_crl.php	1970-01-01 01:00:00.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_crl.php	2006-01-14 11:49:22.000000000 +0100
@@ -0,0 +1,156 @@
+#!/usr/local/bin/php
+<?php 
+/*
+	vpn_openvpn_crl.php
+
+	Copyright (C) 2005-2006 Peter Allgeyer (allgeyer@web.de).
+	All rights reserved.
+	
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions are met:
+	
+	1. Redistributions of source code must retain the above copyright notice,
+	   this list of conditions and the following disclaimer.
+	
+	2. Redistributions in binary form must reproduce the above copyright
+	   notice, this list of conditions and the following disclaimer in the
+	   documentation and/or other materials provided with the distribution.
+	
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	POSSIBILITY OF SUCH DAMAGE.
+*/
+
+$pgtitle = array("VPN", "OpenVPN");
+require("guiconfig.inc");
+require_once("openvpn.inc");
+
+if (!is_array($config['ovpn']))
+	$config['ovpn'] = array();
+if (!is_array($config['ovpn']['server'])){
+	$config['ovpn']['server'] =  array();
+	$config['ovpn']['server']['tunnel'] =  array();
+}
+if (!is_array($config['ovpn']['server']['crl']))
+	$config['ovpn']['server']['crl'] =  array();
+
+$ovpncrl = &$config['ovpn']['server']['crl'];
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+        $id = $_POST['id'];
+
+
+if ($_POST['apply']) {
+	$retval = 0;
+	$retval = ovpn_server_crl_add();
+
+	/* remove dirty flag */
+	unlink_if_exists($d_ovpncrldirty_path);
+
+	$savemsg = get_std_save_message($retval);	
+}
+
+if ($_GET['act'] == "del") {
+	if ($ovpncrl[$id]) {
+		$ovpnent = $ovpncrl[$id];
+
+		unset($ovpncrl[$id]);
+		write_config();
+
+		/* Remove crl file */
+		ovpn_server_crl_del($ovpnent['crlname']);
+
+		/* we should send a SIGUSR1 to openvpn daemon */
+		touch($d_ovpncrldirty_path);
+
+		header("Location: vpn_openvpn_crl.php");
+		exit;
+	}
+}
+?>
+
+<?php include("fbegin.inc"); ?>
+<?php if ($input_errors) print_input_errors($input_errors); ?>
+<?php if (file_exists($d_sysrebootreqd_path) && !file_exists($d_ovpncrldirty_path)) print_info_box(get_std_save_message(0)); ?>
+<form action="vpn_openvpn_crl.php" method="post" enctype="multipart/form-data" name="iform" id="iform">
+<?php if (file_exists($d_ovpncrldirty_path)): ?><p>
+<?php print_info_box_np("OpenVPN CRL files have been changed.<br>You must apply the changes in order for them to take effect.");?><br>
+<input name="apply" type="submit" class="formbtn" id="apply" value="Apply changes"></p>
+<?php endif; ?>
+
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+  <tr><td>
+  <ul id="tabnav">	        
+	<li class="tabinact"><a href="vpn_openvpn_srv.php">Server</a></li>
+	<li class="tabinact"><a href="vpn_openvpn_cli.php">Client</a></li>
+	<li class="tabinact"><a href="vpn_openvpn_ccd.php">Client-specific Configuration</a></li>
+	<li class="tabact">CRL</li>
+  </ul>
+  </td></tr>
+  <tr>
+  <td class="tabcont">
+  <strong><span class="red">WARNING: This feature is experimental and modifies your optional interface configuration.
+  Backup your configuration before using OpenVPN, and restore it before upgrading.<br>
+  &nbsp;<br>
+  </span></strong>
+    <table width="100%" border="0" cellpadding="0" cellspacing="0">
+	<tr>
+	  <td width="40%" class="listhdrr">CRL name</td>
+	  <td width="50%" class="listhdr">Description</td>
+	  <td width="10%" class="list"></td>
+	</tr>
+	<?php $i = 0; foreach ($ovpncrl as $crl):
+
+		if (!isset($crl['enable'])) {
+			$spans = "<span class=\"gray\">";
+			$spane = "</span>";
+		} else {
+			$spans = $spane = "";
+		}
+	?>
+	
+	<tr>
+	  <td class="listlr"><?=$spans;?>
+		<?= $crl['crlname'];?>
+	  <?=$spane;?></td>
+	  <td class="listbg"><?=$spans;?>
+		<?= htmlspecialchars($crl['descr']);?>&nbsp;
+	  <?=$spane;?></td>
+	  <td valign="middle" nowrap class="list"><a href="vpn_openvpn_crl_edit.php?id=<?=$i;?>"><img src="e.gif" title="edit CRL file" width="17" height="17" border="0"></a>
+		&nbsp;<a href="vpn_openvpn_crl.php?act=del&id=<?=$i;?>" onclick="return confirm('Do you really want to delete this CRL file?')"><img src="x.gif" title="delete CRL file" width="17" height="17" border="0"></a></td>
+	</tr>
+  	<?php $i++; endforeach; ?>
+	<tr> 
+	  <td class="list" colspan="2">&nbsp;</td>
+	  <td class="list"><a href="vpn_openvpn_crl_edit.php"><img src="plus.gif" title="add CRL file" width="17" height="17" border="0"></a></td>
+	</tr>
+    </table><br>
+    <span class="vexpl">
+      <span class="red"><strong>Note:</strong></span><br>
+	A  CRL  (certificate  revocation list) is used when a particular
+	key is compromised but when the overall PKI is still intact.<br>
+	<br>
+	Suppose you had a PKI consisting of a CA, root certificate,  and
+	a number of client certificates.  Suppose a laptop computer
+	containing a client key and certificate was stolen.  By adding  the
+	stolen certificate to the CRL file, you could reject any connection
+	which attempts to use it, while preserving the overall
+	integrity of the PKI.<br>
+	<br>
+	The  only  time when it would be necessary to rebuild the entire
+	PKI from scratch would be if the root certificate key itself was
+	compromised.
+    </span>
+  </td>
+</tr>
+</table>
+</form>
+<?php include("fend.inc"); ?>
diff -Nur rootfs-1.21/usr/local/www/vpn_openvpn_srv_edit.php rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_srv_edit.php
--- rootfs-1.21/usr/local/www/vpn_openvpn_srv_edit.php	1970-01-01 01:00:00.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_srv_edit.php	2006-01-14 11:49:22.000000000 +0100
@@ -0,0 +1,1204 @@
+#!/usr/local/bin/php
+<?php 
+/*
+	vpn_openvpn_srv_edit.php
+
+	Copyright (C) 2004 Peter Curran (peter@closeconsultants.com).
+	Copyright (C) 2005-2006 Peter Allgeyer (allgeyer@web.de).
+	All rights reserved.
+	
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions are met:
+	
+	1. Redistributions of source code must retain the above copyright notice,
+	   this list of conditions and the following disclaimer.
+	
+	2. Redistributions in binary form must reproduce the above copyright
+	   notice, this list of conditions and the following disclaimer in the
+	   documentation and/or other materials provided with the distribution.
+	
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	POSSIBILITY OF SUCH DAMAGE.
+*/
+
+$pgtitle = array("VPN", "OpenVPN", "Edit server");
+require("guiconfig.inc");
+require_once("openvpn.inc");
+
+if (!is_array($config['ovpn']))
+	$config['ovpn'] = array();
+if (!is_array($config['ovpn']['server'])){
+	$config['ovpn']['server'] = array();
+	$config['ovpn']['server']['tunnel'] = array();
+}
+
+$ovpnsrv =& $config['ovpn']['server']['tunnel'];
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+	$id = $_POST['id'];
+
+if (isset($id) && $ovpnsrv[$id]) {
+	$pconfig = $config['ovpn']['server']['tunnel'][$id];
+	if (isset($ovpnsrv[$id]['enable']))
+		$pconfig['enable'] = true;
+	if (!isset($ovpnsrv[$id]['method']))
+		$pconfig['method'] = "ovpn";
+	if (is_array($ovpnsrv[$id]['expertmode'])) {
+		$pconfig['expertmode_options'] = "";
+		foreach ($ovpnsrv[$id]['expertmode']['option'] as $optent) {
+			$pconfig['expertmode_options'] .= $optent . "\n"; 
+		}
+		$pconfig['expertmode_options'] = rtrim($pconfig['expertmode_options']); 
+	}
+
+} else {
+	/* creating - set defaults */
+	$pconfig = array();
+	$pconfig['type'] = "tun";
+	$pconfig['psh_options'] = array();
+	/* Initialise with some sensible defaults */
+	$pconfig['authentication_method'] = "rsasig";
+	$pconfig['port'] = getnxt_port();
+	$pconfig['proto'] = 'udp';
+	$pconfig['method'] = 'ovpn';
+	$pconfig['maxcli'] = '';
+	$pconfig['crypto'] = 'BF-CBC';
+	$pconfig['dupcn'] = false;
+	$pconfig['verb'] = 1;
+	$pconfig['enable'] = true;
+}
+
+if ($_POST) {
+
+	unset($input_errors);
+	unset($check_ipblock);
+
+	/* input validation */
+	$reqdfields = explode(" ", "type bind_iface");
+	$reqdfieldsn = explode(",", "Tunnel type,Interface binding");
+
+	if ($_POST['authentication_method'] == "pre_shared_key") {
+		$reqdfields  = array_merge($reqdfields, explode(" ", "lipaddr pre-shared-key"));
+		$reqdfieldsn = array_merge($reqdfieldsn, explode(",", "Local IP address,Pre-shared secret"));
+
+		if ($_POST['type'] == "tun") {
+			/* tun */
+			$reqdfields  = array_merge($reqdfields, explode(" ", "ripaddr"));
+			$reqdfieldsn = array_merge($reqdfieldsn, explode(",", "Remote IP address"));
+
+			/* subnet or ip address */
+			if ($_POST['ripaddr']) {
+				if (!is_ipaddr($_POST['ripaddr']))
+					$input_errors[] = "A valid static remote IP address must be specified.";
+				else if (ip2long($_POST['lipaddr']) == ip2long($_POST['ripaddr']))
+					$input_errors[] = "Local IP address and remote IP address are the same.";
+			}
+			if ($_POST['lipaddr'])
+				if (!is_ipaddr($_POST['lipaddr'])) 
+					$input_errors[] = "A valid local static IP address must be specified.";
+
+		} else {
+			 /* tap */
+			if ($_POST['lipaddr']) {
+				if (!is_ipaddr($_POST['lipaddr'])) 
+					$input_errors[] = "A valid local static IP address must be specified.";
+				if (gen_subnet($_POST['lipaddr'], $_POST['netmask']) == $_POST['lipaddr'])
+					$input_errors[] = "Local IP address is subnet address.";
+				if (gen_subnet_max($_POST['lipaddr'], $_POST['netmask']) == $_POST['lipaddr'])
+					$input_errors[] = "Local IP address is broadcast address.";
+			}
+		}
+
+		if (intval($_POST['maxcli']) > 1)
+			$input_errors[] = "Maximum number of simultaneous clients should not be greater than \"1\".";
+
+		/* checked also by javascript */
+		if ($_POST['method'] != "static")
+			$input_errors[] = "Only static address assignment is supported.";
+
+	} else {
+		/* rsa */
+		$reqdfields  = array_merge($reqdfields, explode(" ", "ca_cert srv_cert srv_key dh_param"));
+		$reqdfieldsn = array_merge($reqdfieldsn, explode(",", "CA certificate,Server certificate,Server key,DH parameters"));
+
+		if ($_POST['type'] == "tap") {
+			/* tap*/
+			if (!$_POST['bridge']) {
+				if ($_POST['method'] == "ovpn") {
+					$reqdfields  = array_merge($reqdfields, "ipblock");
+					$reqdfieldsn = array_merge($reqdfieldsn, "IP address block");
+					
+					$check_ipblock = 1;
+				} else {
+					$input_errors[] = "Only supported address assignment is \"Managed by OpenVPN\".";
+				}
+			} else {
+				if ($_POST['method'] == "ovpn") {
+					$reqdfields  = array_merge($reqdfields, explode(" ", "range_from range_to gateway"));
+					$reqdfieldsn = array_merge($reqdfieldsn, explode(",", "Range begin,Range end,Gateway"));
+					if (intval($_POST['maxcli']) > (ip2long($_POST['range_to']) - ip2long($_POST['range_from']) + 1))
+						$input_errors[] = "IP range to small for maximum number of simultaneous clients.";
+
+				} else if ($_POST['method'] != "dhcp") {
+					$input_errors[] = "Wrong or emtpy OpenVPN address assignment.";
+				}
+			}
+
+		} else {
+			/* tun*/
+			$reqdfields  = array_merge($reqdfields, "ipblock");
+			$reqdfieldsn = array_merge($reqdfieldsn, "IP address block");
+
+			/* checked also by javascript */
+			if ($_POST['method'] != "ovpn")
+				$input_errors[] = "Only supported address assignment is \"Managed by OpenVPN\".";
+
+			$check_ipblock = 1;
+		}
+
+
+		/* valid IP */
+		if ($_POST['ipblock'] && $check_ipblock) {
+			if (!is_ipaddr($_POST['ipblock'])) {
+				$input_errors[] = "A valid IP netblock must be specified.";
+			} else if ($_POST['type'] == "tun" && intval($_POST['prefix']) > 29) {
+				$input_errors[] = "Network mask too high for tun-style tunnels.";
+			} else {
+				$network = ip2long(gen_subnet($_POST['ipblock'], $_POST['prefix']));
+				$broadcast = ip2long(gen_subnet_max($_POST['ipblock'], $_POST['prefix']));
+
+				if ($_POST['maxcli']) {
+					if ($_POST['type'] == "tap") {
+						if (intval($_POST['maxcli']) > ($broadcast - $network - 3))
+							$input_errors[] = "Maximum number of simultaneous clients too high";
+					} else {
+						if (intval($_POST['maxcli']) > floor(($broadcast - $network) / 4))
+							$input_errors[] = "Maximum number of simultaneous clients too high";
+					}
+				}
+			}
+		}
+
+		/* Sort out the cert+key files */
+		if (!empty($_POST['ca_cert']) &&
+		   (!strstr($_POST['ca_cert'], "BEGIN CERTIFICATE") ||
+		    !strstr($_POST['ca_cert'], "END CERTIFICATE")))
+			$input_errors[] = "The CA certificate does not appear to be valid.";
+
+		if (!empty($_POST['srv_cert']) &&
+		   (!strstr($_POST['srv_cert'], "BEGIN CERTIFICATE") ||
+		    !strstr($_POST['srv_cert'], "END CERTIFICATE")))
+			$input_errors[] = "The server certificate does not appear to be valid.";
+
+		if (!empty($_POST['srv_key']) &&
+		   (!strstr($_POST['srv_key'], "BEGIN RSA PRIVATE KEY") ||
+		    !strstr($_POST['srv_key'], "END RSA PRIVATE KEY")))
+			$input_errors[] = "The server key does not appear to be valid.";
+
+		if (!empty($_POST['dh_param']) &&
+		   (!strstr($_POST['dh_param'], "BEGIN DH PARAMETERS") ||
+		    !strstr($_POST['dh_param'], "END DH PARAMETERS")))
+			$input_errors[] = "The DH parameters do not appear to be valid.";
+
+		if (isset($_POST['tlsauth']) && empty($_POST['pre-shared-key']))
+			$input_errors[] = "The field 'Pre-shared secret' is required.";
+	}
+	
+	do_input_validation($_POST, $reqdfields, $reqdfieldsn, &$input_errors);
+
+	if (($_POST['range_from'] && !is_ipaddr($_POST['range_from'])))
+		$input_errors[] = "A valid range must be specified.";
+
+	if (($_POST['range_to'] && !is_ipaddr($_POST['range_to'])))
+		$input_errors[] = "A valid range must be specified.";
+
+	if ($_POST['gateway'] && !is_ipaddr($_POST['gateway']))
+		$input_errors[] = "A valid gateway IP address must be specified.";
+
+	/* make sure the range lies within the bridged subnet */
+	if ($_POST['bridge']) {
+		if ($_POST['method'] == "ovpn") {
+
+			$ipaddr = $config['interfaces'][$_POST['bridge']]['ipaddr'];
+			$subnet = $config['interfaces'][$_POST['bridge']]['subnet'];
+
+			$subnet_start = (ip2long($ipaddr) & gen_subnet_mask_long($subnet));
+			$subnet_end = (ip2long($ipaddr) | (~gen_subnet_mask_long($subnet)));
+
+			if (!ip_in_subnet($_POST['gateway'], gen_subnet($ipaddr, $subnet) . "/" . $subnet))
+				$input_errors[] = "The specified gateway lies outside of the bridged subnet.";
+
+			if ((ip2long($_POST['range_from']) < $subnet_start) || (ip2long($_POST['range_from']) > $subnet_end) ||
+			    (ip2long($_POST['range_to']) < $subnet_start) || (ip2long($_POST['range_to']) > $subnet_end)) {
+				$input_errors[] = "The specified range lies outside of the bridged subnet.";
+			}
+
+			if (ip2long($_POST['range_from']) > ip2long($_POST['range_to']))
+				$input_errors[] = "The range is invalid (first element higher than second element).";
+		}
+	}
+
+	/* valid Port */
+	if (empty($_POST['port']))
+		$input_errors[] = "You must provide a server in between 1 and 65535.";
+	else if (!is_port($_POST['port']))
+		$input_errors[] = "The server port must be an integer between 1 and 65535.";
+	
+	/* check if dynip is set correctly */
+	if ($_POST['dynip'] && $_POST['bind_iface'] != 'all')
+		$input_errors[] = "Dynamic IP address can only be set with interface binding set to ALL.";
+
+	if (!empty($_POST['pre-shared-key']))
+		if (!strstr($_POST['pre-shared-key'], "BEGIN OpenVPN Static key") ||
+		    !strstr($_POST['pre-shared-key'], "END OpenVPN Static key"))
+			$input_errors[] = "Pre-shared secret does not appear to be valid.";
+				
+	if ($_POST['psh_pingrst'] && $_POST['psh_pingexit'])
+		$input_errors[] = "Ping-restart and Ping-exit are mutually exclusive and cannot be used together";
+
+	if ($_POST['psh_rtedelay'] && !is_numeric($_POST['psh_rtedelay_int']))
+		$input_errors[] = "Route-delay needs a numerical interval setting.";
+
+	if ($_POST['psh_inact'] && !is_numeric($_POST['psh_inact_int']))
+		$input_errors[] = "Inactive needs a numerical interval setting.";
+
+	if ($_POST['psh_ping'] && !is_numeric($_POST['psh_ping_int']))
+		$input_errors[] = "Ping needs a numerical interval setting.";
+			
+	if ($_POST['psh_pingexit'] && !is_numeric($_POST['psh_pingexit_int']))
+		$input_errors[] = "Ping-exit needs a numerical interval setting.";
+
+	if ($_POST['psh_pingrst'] && !is_numeric($_POST['psh_pingrst_int']))
+		$input_errors[] = "Ping-restart needs a numerical interval setting.";
+
+	/* Editing an existing entry? */
+	if (isset($id) && $ovpnsrv[$id]) {
+		$ovpnent = $ovpnsrv[$id];
+
+		/* bridging changed */
+		if ($ovpnent['bridge'] != $_POST['bridge']) {
+			/* double bridging? */
+			if ($_POST['bridge'] &&
+			    $_POST['type'] == "tap" &&
+			    $_POST['authentication_method'] == "rsasig")
+				$retval = check_bridging($_POST['bridge']);
+
+			if (!empty($retval))
+				$input_errors[] = $retval;
+		}
+
+		/* port number syntactically valid, so lets check, if it is free */
+		if (isset($ovpnent['enable']) &&
+		   !isset($_POST['disabled']) &&
+		   $ovpnent['port'] != $_POST['port']) {
+			/* port number has changed */
+
+			if (in_array($_POST['port'], used_port_list())) {
+				/* port in use, check binding */
+
+				/* return interfaces bind to this port */
+				$bind_list = used_bind_list($_POST['port']);
+
+				/* check if binding is in use */
+				if (($_POST['bind_iface'] == "all") ||
+				    in_array("all", $bind_list) ||
+				    in_array($_POST['bind_iface'], $bind_list) ) {
+					$input_errors[] = "OpenVPN binding already in use by another OpenVPN daemon.";
+				}
+			}
+		}
+
+		/* binding free? */
+		if (isset($ovpnent['enable']) &&
+		   !isset($_POST['disabled']) &&
+		   $ovpnent['bind_iface'] != $_POST['bind_iface']) {
+			/* binding has changed, remove existing old entry from list */
+			$entry = array();
+			array_push($entry, $ovpnent['bind_iface']);
+			$bind_list = array_diff(used_bind_list($_POST['port']), $entry);
+
+			if (count($bind_list)) {
+				if ($_POST['bind_iface'] == "all")
+					$input_errors[] = "Interface binding is already in use.";
+				else if (in_array("all", $bind_list) ||
+				         in_array($_POST['bind_iface'], $bind_list))
+					$input_errors[] = "Interface binding is already in use.";
+			}
+		}
+
+		/* Test Server type hasn't changed */
+		if ($ovpnent['type'] != $_POST['type']) {
+			$input_errors[] = "Delete this interface first before changing the type of the tunnel to " . strtoupper($_POST['type']) .".";
+
+		}
+
+		/* status changed to enable */
+		if (!isset($ovpnent['enable']) && !isset($_POST['disabled'])) {
+
+			/* check if port number is free */
+			if (in_array($_POST['port'], used_port_list())) {
+				/* port in use, check binding */
+
+				/* return interfaces bind to this port */
+				$bind_list = used_bind_list($_POST['port']);
+
+				if (($_POST['bind_iface'] == "all") ||
+				    in_array("all", $bind_list ) ||
+				    in_array($_POST['bind_iface'], $bind_list) ) {
+					/* binding in use */
+					$input_errors[] = "OpenVPN binding already in use by another OpenVPN daemon.";
+				}
+			}
+		}
+
+	} else {
+		/* Creating a new entry */
+		$ovpnent = array();
+
+		/* port number syntactically valid, so lets check, if it is free */
+		if ($_POST['port']) {
+			/* new port number */
+			$bind_list = used_bind_list($_POST['port']);
+
+			if (in_array($_POST['port'], used_port_list())) {
+				/* port in use, check binding */
+				if (($_POST['bind_iface'] == "all") ||
+				    in_array("all", $bind_list ) ||
+				    in_array($_POST['bind_iface'], $bind_list) ) {
+					/* binding in use */
+					$input_errors[] = "Port {$_POST['port']} is already used for another interface.";
+				}
+			}
+		}
+
+		if (!($ovpnent['tun_iface'] = getnxt_if($_POST['type'])))
+			$input_errors[] = "Run out of devices for a tunnel of type {$_POST['type']}";
+
+		/* double bridging? */
+		if ($ovpnent['bridge'] != $_POST['bridge']) {
+			/* double bridging? */
+			if ($_POST['bridge'] &&
+			    $_POST['type'] == "tap" &&
+			    $_POST['authentication_method'] == "rsasig")
+				$retval = check_bridging($_POST['bridge']);
+
+			if (!empty($retval))
+				$input_errors[] = $retval;
+		}
+	}
+
+	if (!$input_errors) {
+
+		$ovpnent['enable'] = isset($_POST['disabled']) ? false : true;
+		$ovpnent['bind_iface'] = $_POST['bind_iface'];
+		$ovpnent['port'] = $_POST['port'];
+		$ovpnent['proto'] = $_POST['proto'];
+		$ovpnent['type'] = $_POST['type'];
+		$ovpnent['method'] = $_POST['method'];
+		$ovpnent['authentication_method'] = $_POST['authentication_method'];
+		
+		/* convert IP address block to a correct network IP address */
+		$ovpnent['ipblock'] = gen_subnet($_POST['ipblock'], $_POST['prefix']);
+		$ovpnent['prefix'] = $_POST['prefix'];
+		$ovpnent['lipaddr'] = $_POST['lipaddr'];
+		$ovpnent['ripaddr'] = $_POST['ripaddr'];
+		$ovpnent['netmask'] = $_POST['netmask'];
+		$ovpnent['range_from'] = $_POST['range_from'];
+		$ovpnent['range_to'] = $_POST['range_to'];
+		$ovpnent['gateway'] = $_POST['gateway'];
+		$ovpnent['bridge'] = $_POST['bridge'];
+
+		$ovpnent['descr'] = $_POST['descr'];
+		$ovpnent['verb'] = $_POST['verb'];
+		$ovpnent['maxcli'] = $_POST['maxcli'];
+		$ovpnent['crypto'] = $_POST['crypto'];
+		$ovpnent['comp_method'] = $_POST['comp_method'];
+		$ovpnent['cli2cli'] = $_POST['cli2cli'] ? true : false;
+		$ovpnent['dupcn'] = $_POST['dupcn'] ? true : false;
+		$ovpnent['dynip'] = $_POST['dynip'] ? true : false;
+		$ovpnent['tlsauth'] = $_POST['tlsauth'] ? true : false;
+		$ovpnent['crlname'] = $_POST['crlname'];
+
+		unset($ovpnent['pre-shared-key']);
+		if ($_POST['pre-shared-key'])
+			$ovpnent['pre-shared-key'] = base64_encode($_POST['pre-shared-key']);	
+
+		$ovpnent['psh_options']['redir'] = $_POST['psh_redir'] ? true : false;
+		$ovpnent['psh_options']['redir_loc'] = $_POST['psh_redir_loc'] ? true : false;
+		$ovpnent['psh_options']['rtedelay'] = $_POST['psh_rtedelay'] ? true : false;
+		$ovpnent['psh_options']['inact'] = $_POST['psh_inact'] ? true : false;
+		$ovpnent['psh_options']['ping'] = $_POST['psh_ping'] ? true : false;
+		$ovpnent['psh_options']['pingrst'] = $_POST['psh_pingrst'] ? true : false;
+		$ovpnent['psh_options']['pingexit'] = $_POST['psh_pingexit'] ? true : false;
+
+		unset($ovpnent['psh_options']['rtedelay_int']);
+		unset($ovpnent['psh_options']['inact_int']);
+		unset($ovpnent['psh_options']['ping_int']);
+		unset($ovpnent['psh_options']['pingrst_int']);
+		unset($ovpnent['psh_options']['pingexit_int']);
+
+		if ($_POST['psh_rtedelay_int'])
+			$ovpnent['psh_options']['rtedelay_int'] = $_POST['psh_rtedelay_int'];
+		if ($_POST['psh_inact_int'])
+			$ovpnent['psh_options']['inact_int'] = $_POST['psh_inact_int'];
+		if ($_POST['psh_ping_int'])
+			$ovpnent['psh_options']['ping_int'] = $_POST['psh_ping_int'];
+		if ($_POST['psh_pingrst_int'])
+			$ovpnent['psh_options']['pingrst_int'] = $_POST['psh_pingrst_int'];
+		if ($_POST['psh_pingexit_int'])
+			$ovpnent['psh_options']['pingexit_int'] = $_POST['psh_pingexit_int'];
+		
+		$ovpnent['ca_cert'] = base64_encode($_POST['ca_cert']);
+		$ovpnent['srv_cert'] = base64_encode($_POST['srv_cert']);
+		$ovpnent['srv_key'] = base64_encode($_POST['srv_key']);
+		$ovpnent['dh_param'] = base64_encode($_POST['dh_param']);	
+
+		/* expertmode params */
+		$ovpnent['expertmode_enabled'] = $_POST['expertmode_enabled'] ? true : false;
+		
+		if (!is_array($options))
+			$options = array();
+		if (!is_array($ovpnent['expertmode']))
+			$ovpnent['expertmode'] = array();
+
+		$options['option'] = array_map('trim', explode("\n", trim($_POST['expertmode_options'])));
+		$ovpnent['expertmode'] = $options;
+
+		if (isset($id) && $ovpnsrv[$id])
+			$ovpnsrv[$id] = $ovpnent;
+		else
+			$ovpnsrv[] = $ovpnent;
+
+		write_config();
+		ovpn_srv_dirty($ovpnent['tun_iface']);
+
+		header("Location: vpn_openvpn_srv.php");
+		exit;
+	} else {
+
+		$pconfig = $_POST;
+
+		$pconfig['enable'] = "true";
+		if (isset($_POST['disabled']))
+			unset($pconfig['enable']);
+
+		$pconfig['pre-shared-key'] = base64_encode($_POST['pre-shared-key']);	
+		$pconfig['ca_cert'] = base64_encode($_POST['ca_cert']);
+		$pconfig['srv_cert'] = base64_encode($_POST['srv_cert']);
+		$pconfig['srv_key'] = base64_encode($_POST['srv_key']);
+		$pconfig['dh_param'] = base64_encode($_POST['dh_param']);
+
+		$pconfig['psh_options']['redir'] = $_POST['psh_redir'];
+		$pconfig['psh_options']['redir_loc'] = $_POST['psh_redir_loc'];
+		$pconfig['psh_options']['rtedelay'] = $_POST['psh_rtedelay'];
+		$pconfig['psh_options']['inact'] = $_POST['psh_inact'];
+		$pconfig['psh_options']['ping'] = $_POST['psh_ping'];
+		$pconfig['psh_options']['pingrst'] = $_POST['psh_pingrst'];
+		$pconfig['psh_options']['pingexit'] = $_POST['psh_pingexit'];
+
+		$pconfig['psh_options']['rtedelay_int'] = $_POST['psh_rtedelay_int'];
+		$pconfig['psh_options']['inact_int'] = $_POST['psh_inact_int'];
+		$pconfig['psh_options']['ping_int'] = $_POST['psh_ping_int'];
+		$pconfig['psh_options']['pingrst_int'] = $_POST['psh_pingrst_int'];
+		$pconfig['psh_options']['pingexit_int'] = $_POST['psh_pingexit_int'];
+	}
+}
+
+
+?>
+<?php include("fbegin.inc"); ?>
+<script language="JavaScript">
+function enable_change(enable_over) {
+	var endis;
+	endis = !(!document.iform.disabled.checked || enable_over);
+        
+        document.iform.proto[0].disabled = endis;
+        document.iform.proto[1].disabled = endis;
+	document.iform.port.disabled = endis;
+        document.iform.bind_iface.disabled = endis;
+        document.iform.dynip.disabled = endis;
+        document.iform.descr.disabled = endis;
+        document.iform.authentication_method.disabled = endis;
+        document.iform.ca_cert.disabled = endis;
+        document.iform.srv_cert.disabled = endis;
+        document.iform.srv_key.disabled = endis;
+        document.iform.dh_param.disabled = endis;
+        document.iform.crypto.disabled = endis;
+        document.iform.tlsauth.disabled = endis;
+        document.iform.crlname.disabled = endis;
+        document.iform.psk.disabled = endis;
+        document.iform.type[0].disabled = endis;
+        document.iform.type[1].disabled = endis;
+	document.iform.bridge.disabled = endis;
+	document.iform.method[0].disabled = endis;
+	document.iform.method[1].disabled = endis;
+	document.iform.method[2].disabled = endis;
+	document.iform.maxcli.disabled = endis;
+	document.iform.ipblock.disabled = endis;
+	document.iform.prefix.disabled = endis;
+	document.iform.range_from.disabled = endis;
+	document.iform.range_to.disabled = endis;
+	document.iform.gateway.disabled = endis;
+	document.iform.lipaddr.disabled = endis;
+	document.iform.ripaddr.disabled = endis;
+	document.iform.netmask.disabled = endis;
+	document.iform.cli2cli.disabled = endis;
+	document.iform.dupcn.disabled = endis;
+	document.iform.comp_method.disabled = endis;
+	document.iform.psh_redir.disabled = endis;
+	document.iform.psh_redir_loc.disabled = endis;
+	document.iform.psh_rtedelay.disabled = endis;
+	document.iform.psh_rtedelay_int.disabled = endis;
+	document.iform.psh_inact.disabled = endis;
+	document.iform.psh_inact_int.disabled = endis;
+	document.iform.psh_ping.disabled = endis;
+	document.iform.psh_ping_int.disabled = endis;
+	document.iform.psh_pingexit.disabled = endis;
+	document.iform.psh_pingexit_int.disabled = endis;
+	document.iform.psh_pingrst.disabled = endis;
+	document.iform.psh_pingrst_int.disabled = endis;
+	document.iform.expertmode_enabled.disabled = endis;
+	document.iform.expertmode_options.disabled = endis;
+
+	if (!document.iform.disabled.checked) {
+		type_change();
+		tls_change(enable_over);
+		expertmode_change(enable_over);
+		methodsel_change(enable_over);
+	}
+}
+
+function type_change() {
+	switch (document.iform.bind_iface.selectedIndex) {
+		/* ALL */
+		case 0:
+			document.iform.dynip.disabled = 0;
+			break;
+		default:
+			document.iform.dynip.disabled = 1;
+	}
+}
+
+function tls_change(enable_over) {
+	var endis;
+	endis = !(document.iform.tlsauth.checked || enable_over);
+        
+        document.iform.psk.disabled = endis;
+}
+
+function expertmode_change(enable_over) {
+	var endis;
+	endis = !(document.iform.expertmode_enabled.checked || enable_over);
+
+	document.iform.expertmode_options.disabled = endis;
+}
+
+function methodsel_change(enable_over) {
+	var endis;
+
+	switch (document.iform.authentication_method.selectedIndex) {
+		case 1: /* rsa */
+			if (get_radio_value(document.iform.type) == "tap") {
+				/* tap */
+
+				endis = !((document.iform.bridge.selectedIndex == 0) || enable_over);
+
+				if (document.iform.bridge.selectedIndex == 0)
+					document.iform.method[0].checked = 1;
+
+				document.iform.method[0].disabled = 0;
+				document.iform.method[1].disabled = !endis;
+				document.iform.method[2].disabled = 1;
+				document.iform.method[2].checked = 0;
+				document.iform.bridge.disabled = 0;
+
+				if (get_radio_value(document.iform.method) == "ovpn") {
+					document.iform.ipblock.disabled = endis;
+					document.iform.prefix.disabled = endis;
+					document.iform.range_from.disabled = !endis;
+					document.iform.range_to.disabled = !endis;
+					document.iform.gateway.disabled = !endis;
+				} else if (get_radio_value(document.iform.method) == "dhcp") {
+					document.iform.ipblock.disabled = 1;
+					document.iform.prefix.disabled = 1;
+					document.iform.range_from.disabled = 1;
+					document.iform.range_to.disabled = 1;
+					document.iform.gateway.disabled = 1;
+				}
+			} else {
+				/* tun */
+				document.iform.method[0].disabled = 0;
+				document.iform.method[0].checked = 1;
+				document.iform.method[1].disabled = 1;
+				document.iform.method[2].disabled = 1;
+				document.iform.bridge.disabled = 1;
+				document.iform.bridge.selectedIndex = 0;
+				document.iform.ipblock.disabled = 0;
+				document.iform.prefix.disabled = 0;
+				document.iform.range_from.disabled = 1;
+				document.iform.range_to.disabled = 1;
+				document.iform.gateway.disabled = 1;
+			}
+
+			document.iform.psk.disabled = 1;
+			document.iform.ca_cert.disabled = 0;
+			document.iform.srv_cert.disabled = 0;
+			document.iform.srv_key.disabled = 0;
+			document.iform.dh_param.disabled = 0;
+			document.iform.tlsauth.disabled = 0;
+			document.iform.crlname.disabled = 0;
+			document.iform.maxcli.disabled = 0;
+			document.iform.dupcn.disabled = 0;
+			document.iform.lipaddr.disabled = 1;
+			document.iform.ripaddr.disabled = 1;
+			document.iform.netmask.disabled = 1;
+			document.iform.cli2cli.disabled = 0;
+			document.iform.psh_redir.disabled = 0;
+			document.iform.psh_redir_loc.disabled = 0;
+			document.iform.psh_rtedelay.disabled = 0;
+			document.iform.psh_rtedelay_int.disabled = 0;
+			document.iform.psh_inact.disabled = 0;
+			document.iform.psh_inact_int.disabled = 0;
+			document.iform.psh_ping.disabled = 0;
+			document.iform.psh_ping_int.disabled = 0;
+			document.iform.psh_pingexit.disabled = 0;
+			document.iform.psh_pingexit_int.disabled = 0;
+			document.iform.psh_pingrst.disabled = 0;
+			document.iform.psh_pingrst_int.disabled = 0;
+			tls_change();
+			break;
+		default: /* pre-shared */
+			if (get_radio_value(document.iform.type) == "tap") {
+				/* tap */
+				document.iform.ripaddr.disabled = 1;
+				document.iform.netmask.disabled = 0;
+			} else {
+				/* tun */
+				document.iform.ripaddr.disabled = 0;
+				document.iform.netmask.disabled = 1;
+			}
+
+			document.iform.psk.disabled = 0;
+			document.iform.ca_cert.disabled = 1;
+			document.iform.srv_cert.disabled = 1;
+			document.iform.srv_key.disabled = 1;
+			document.iform.dh_param.disabled = 1;
+			document.iform.tlsauth.disabled = 1;
+			document.iform.crlname.disabled = 1;
+		
+			document.iform.method[0].disabled = 1;
+			document.iform.method[1].disabled = 1;
+			document.iform.method[2].disabled = 0;
+			document.iform.method[2].checked = 1;
+			document.iform.bridge.disabled = 1;
+			document.iform.bridge.selectedIndex = 0;
+			document.iform.ipblock.disabled = 1;
+			document.iform.prefix.disabled = 1;
+			document.iform.range_from.disabled = 1;
+			document.iform.range_to.disabled = 1;
+			document.iform.gateway.disabled = 1;
+			document.iform.lipaddr.disabled = 0;
+			document.iform.maxcli.disabled = 1;
+			document.iform.maxcli.value = "";
+			document.iform.dupcn.disabled = 1;
+			document.iform.dupcn.checked = 0;
+			document.iform.cli2cli.disabled = 1;
+			document.iform.cli2cli.checked = 0;
+			document.iform.psh_redir.disabled = 1;
+			document.iform.psh_redir_loc.disabled = 1;
+			document.iform.psh_rtedelay.disabled = 1;
+			document.iform.psh_rtedelay_int.disabled = 1;
+			document.iform.psh_inact.disabled = 1;
+			document.iform.psh_inact_int.disabled = 1;
+			document.iform.psh_ping.disabled = 1;
+			document.iform.psh_ping_int.disabled = 1;
+			document.iform.psh_pingexit.disabled = 1;
+			document.iform.psh_pingexit_int.disabled = 1;
+			document.iform.psh_pingrst.disabled = 1;
+			document.iform.psh_pingrst_int.disabled = 1;
+			break;
+	}
+
+	if (enable_over) {
+		document.iform.psk.disabled = 0;
+		document.iform.ca_cert.disabled = 0;
+		document.iform.srv_cert.disabled = 0;
+		document.iform.srv_key.disabled = 0;
+		document.iform.dh_param.disabled = 0;
+		document.iform.tlsauth.disabled = 0;
+		document.iform.crlname.disabled = 0;
+		document.iform.bridge.disabled = 0;
+		document.iform.ipblock.disabled = 0;
+		document.iform.prefix.disabled = 0;
+		document.iform.range_from.disabled = 0;
+		document.iform.range_to.disabled = 0;
+		document.iform.gateway.disabled = 0;
+		document.iform.lipaddr.disabled = 0;
+		document.iform.ripaddr.disabled = 0;
+		document.iform.netmask.disabled = 0;
+		document.iform.maxcli.disabled = 0;
+		document.iform.method[0].disabled = 0;
+		document.iform.method[1].disabled = 0;
+		document.iform.method[2].disabled = 0;
+	}
+}
+
+function get_radio_value(obj) {
+	for (i = 0; i < obj.length; i++) {
+		if (obj[i].checked)
+		return obj[i].value;
+	}
+	return null;
+}
+
+//-->
+</script>
+<?php if ($input_errors) print_input_errors($input_errors);?>
+<form action="vpn_openvpn_srv_edit.php" method="post" enctype="multipart/form-data" name="iform" id="iform">
+<strong><span class="red">WARNING: This feature is experimental and modifies your optional interface configuration.
+  Backup your configuration before using OpenVPN, and restore it before upgrading.<br>&nbsp;<br>
+</span></strong>
+<table width="100%" border="0" cellpadding="6" cellspacing="0">
+  <tr>
+    <td width="22%" valign="top" class="vncellreq">Disabled</td>
+    <td width="78%" class="vtable">
+      <input name="disabled" type="checkbox" value="yes" onclick="enable_change(false)" <?php if (!isset($pconfig['enable'])) echo "checked"; ?>>
+      <strong>Disable this server</strong><br>
+        <span class="vexpl">Set this option to disable this server without removing it from the list.</span>
+    </td>
+   </tr>
+   
+    <tr>
+      <td width="22%" valign="top" class="vncell">OpenVPN protocol/port</td>
+      <td width="78%" class="vtable">
+	<input type="radio" name="proto" class="formfld" value="udp" <?php if ($pconfig['proto'] == 'udp') echo "checked"; ?>>
+           UDP&nbsp;
+        <input type="radio" name="proto" class="formfld" value="tcp" <?php if ($pconfig['proto'] == 'tcp') echo "checked"; ?>>
+           TCP<br><br>
+        Port: 
+        <input name="port" type="text" class="formfld" size="5" maxlength="5" value="<?= $pconfig['port']; ?>"><br>
+        Enter the port number to use for the server (default is 1194).</td>
+    </tr>
+    
+    <tr>
+      <td width="22%" valign="top" class="vncellreq">Interface binding</td>
+      <td width="78%" class="vtable">
+	<select name="bind_iface" class="formfld" onchange="type_change()">
+        <?php 
+	$interfaces = ovpn_real_interface_list();
+	foreach ($interfaces as $key => $iface):
+        ?>
+	<option value="<?=$key;?>" <?php if ($key == $pconfig['bind_iface']) echo "selected"; ?>> <?= $iface;?>
+        </option>
+        <?php endforeach;?>
+        </select>
+        <span class="vexpl"><br>
+        Choose an interface for the OpenVPN server to listen on.</span></td>
+    </tr>
+		
+    <tr>
+      <td width="22%" valign="top" class="vncell">Dynamic IP address</td>
+      <td width="78%" class="vtable">
+	<input name="dynip" type="checkbox" value="yes" <?php if (isset($pconfig['dynip'])) echo "checked"; ?>>
+	<strong>Dynamic IP address</strong><br>
+	Set this option to on, if your IP addresses are being assigned dynamically. Can only be used with interface binding set to ALL.</td>
+    </tr>
+
+    <tr> 
+      <td width="22%" valign="top" class="vncell">Description</td>
+      <td width="78%" class="vtable"> 
+        <input name="descr" type="text" class="formfld" id="descr" size="40" value="<?=htmlspecialchars($pconfig['descr']);?>"> 
+        <br> <span class="vexpl">You may enter a description here for your reference (not parsed).</span></td>
+    </tr>
+
+    <tr> 
+      <td colspan="2" valign="top" height="12"></td>
+    </tr>
+    <tr>
+      <td colspan="2" valign="top" class="listtopic">Cryptographic options</td>
+    </tr>
+    <tr> 
+      <td width="22%" valign="top" class="vncellreq">Authentication method</td>
+      <td width="78%" class="vtable"> 
+	<select name="authentication_method" class="formfld" onChange="methodsel_change(false)">
+	  <?php foreach ($p1_authentication_methods as $method => $methodname): ?>
+	    <option value="<?=$method;?>" <?php if ($method == $pconfig['authentication_method']) echo "selected"; ?>>
+		<?=htmlspecialchars($methodname);?>
+	    </option>
+	  <?php endforeach; ?>
+	</select> <br> <span class="vexpl">Must match the setting chosen on the remote side.</span></td>
+    </tr>
+    
+    <tr> 
+      <td width="22%" valign="top" class="vncellreq">CA certificate</td>
+      <td width="78%" class="vtable"> 
+      <textarea name="ca_cert" cols="65" rows="4" class="formpre"><?=htmlspecialchars(base64_decode($pconfig['ca_cert']));?></textarea>
+      <br>
+      Paste a CA certificate in X.509 PEM format here.</td>
+    </tr>
+		
+    <tr> 
+      <td width="22%" valign="top" class="vncellreq">Server certificate</td>
+      <td width="78%" class="vtable">
+        <textarea name="srv_cert" cols="65" rows="4" class="formpre"><?=htmlspecialchars(base64_decode($pconfig['srv_cert']));?></textarea>
+        <br>
+        Paste a server certificate in X.509 PEM format here.</td>
+    </tr>
+     
+    <tr> 
+      <td width="22%" valign="top" class="vncellreq">Server key</td>
+      <td width="78%" class="vtable"> 
+        <textarea name="srv_key" cols="65" rows="4" class="formpre"><?=htmlspecialchars(base64_decode($pconfig['srv_key']));?></textarea>
+        <br>Paste the server RSA private key here.</td>
+    </tr>
+      
+    <tr> 
+      <td width="22%" valign="top" class="vncellreq">DH parameters</td>
+      <td width="78%" class="vtable"> 
+	<textarea name="dh_param" cols="65" rows="4" class="formpre"><?=htmlspecialchars(base64_decode($pconfig['dh_param']));?></textarea>
+	<br>          
+	  Paste the Diffie-Hellman parameters in PEM format here.</td>
+    </tr>
+      
+    <tr>
+      <td width="22%" valign="top" class="vncell">Crypto</td>
+      <td width="78%" class="vtable">
+	<select name="crypto" class="formfld">
+	  <?php $cipher_list = ovpn_get_cipher_list();
+		foreach($cipher_list as $key => $value){
+	  ?>
+		<option value="<?= $key ?>" <?php if ($pconfig['crypto'] == $key) echo "selected"; ?>>
+		<?= $value ?>
+		</option>
+	  <?php
+	    }
+	  ?>
+	  </select>
+	  <br>
+	Select a data channel encryption cipher.</td>
+    </tr>
+      
+    <tr>
+      <td width="22%" valign="top" class="vncell">TLS auth</td>
+      <td width="78%" class="vtable">
+	<input name="tlsauth" type="checkbox" value="yes" <?php if (isset($pconfig['tlsauth'])) echo "checked";?> onclick="tls_change(false)">
+	<strong>TLS auth</strong><br>
+	The tls-auth directive adds an additional HMAC signature to all SSL/TLS handshake packets for integrity verification.</td>
+    </tr>
+
+    <tr> 
+      <td width="22%" valign="top" class="vncellreq">Pre-shared secret</td>
+      <td width="78%" class="vtable">
+	<textarea name="pre-shared-key" id="psk" cols="65" rows="4" class="formpre"><?=htmlspecialchars(base64_decode($pconfig['pre-shared-key']));?></textarea>
+	<br>
+	Paste your own pre-shared secret here.</td>
+    </tr>
+
+    <tr>
+      <td width="22%" valign="top" class="vncell">CRL</td>
+      <td width="78%" class="vtable">
+	<select name="crlname" class="formfld" id="crlname">
+	<option <?php if (!$pconfig['crlname']) echo "selected";?> value="">none</option>
+	<?php $crl_list = ovpn_get_crl_list();
+	    foreach($crl_list as $crlname): ?>
+		<option value="<?=$crlname;?>" <?php if ($crlname == $pconfig['crlname']) echo "selected";?>>
+		  <?=htmlspecialchars($crlname);?>
+		</option>
+	<?php endforeach; ?>
+	</select> 
+	<br> <span class="vexpl">
+	You can choose a CRL (certificate revocation list) file in PEM format here.
+	Each peer certificate is checked against this file.</span></td>
+    </tr>
+
+    <tr> 
+      <td colspan="2" valign="top" height="12"></td>
+    </tr>
+    <tr>
+      <td colspan="2" valign="top" class="listtopic">IP configuration</td>
+    </tr>
+   <tr>
+     <td width="22%" valign="top" class="vncellreq">Tunnel type</td>
+     <td width="78%" class="vtable">
+       <input type="radio" name="type" class="formfld" value="tun" onclick="methodsel_change(false)" <?php if ($pconfig['type'] == 'tun') echo "checked"; ?>>
+          TUN&nbsp;
+       <input type="radio" name="type" class="formfld" value="tap" onclick="methodsel_change(false)" <?php if ($pconfig['type'] == 'tap') echo "checked"; ?>>
+          TAP
+      </td>
+    </tr>
+
+    <tr> 
+      <td width="22%" valign="top" class="vncellreq">Bridge with</td>
+      <td width="78%" class="vtable">
+	<select name="bridge" class="formfld" id="bridge" onChange="methodsel_change(false)">
+	<option <?php if (!$pconfig['bridge']) echo "selected";?> value="">none</option>
+	<?php $opts = array('lan' => "LAN", 'wan' => "WAN");
+	for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
+		if ($i != $index && !($config['interfaces']['opt' . $i]['ovpn']))
+			$opts['opt' . $i] = "Optional " . $i . " (" . $config['interfaces']['opt' . $i]['descr'] . ")";
+	}
+	foreach ($opts as $opt => $optname): ?>
+		<option <?php if ($opt == $pconfig['bridge']) echo "selected";?> value="<?=htmlspecialchars($opt);?>"> 
+			<?=htmlspecialchars($optname);?>
+		</option>
+	<?php endforeach; ?>
+	</select> <br> <span class="vexpl">Only supported with authentication method set to RSA signature.</span>
+      </td>
+    </tr>
+	 
+    <tr> 
+      <td width="22%" valign="top" class="vncellreq">OpenVPN address assignment</td>
+      <td width="78%" class="vtable"> 
+	<table cellpadding="0" cellspacing="0">
+	  <tr>
+	    <td colspan="2"><input name="method" type="radio" id="method" value="ovpn" onclick="methodsel_change(false)" <?php if($pconfig['method'] == "ovpn" || $pconfig['type'] == "tun") echo "checked"; ?>>
+	    Managed by OpenVPN
+	    </td>
+	  </tr>
+	  <tr>
+	    <td colspan="2"><input name="method" type="radio" id="method" value="dhcp" onclick="methodsel_change(false)" <?php if($pconfig['method'] == "dhcp") echo "checked"; ?>>
+	    Configure manually or by DHCP Server
+	    </td>
+	  </tr>
+	  <tr>
+	    <td colspan="2"><input name="method" type="radio" id="method" value="static" onclick="methodsel_change(false)" <?php if($pconfig['method'] == "static") echo "checked"; ?>>
+	    Static assignment
+	    </td>
+	  </tr>
+	  <tr>
+	    <td>&nbsp;</td>
+	    <td>&nbsp;</td>
+	  </tr>
+	  <tr>
+	    <td>Maximum number of simultaneous clients:&nbsp;&nbsp;<br>(leave blank to disable)</td>
+	    <td valign="top">
+		<input name="maxcli" type="text" class="formfld" size="3" maxlength="3" value="<?=htmlspecialchars($pconfig['maxcli']);?>">
+	    </td>
+	  </tr>
+	</table>
+      </td>
+    </tr>
+
+    <tr> 
+      <td width="22%" valign="top" class="vncell"></td>
+      <td width="78%" class="vtable"> 
+	When using OpenVPN for address assignment, set aside a pool of subnets to be
+	dynamically allocated to connecting  clients, similar to a DHCP server.<br>
+	<br>
+	For tun-style tunnels, each client will be given a /30 subnet
+	(for interoperability  with  Windows  clients).<br>
+	For tap-style tunnels, individual addresses will be allocated, and the optional
+	netmask parameter will also be pushed to clients.<br>
+	<br>
+
+	<table cellpadding="0" cellspacing="0">
+	  <tr>
+	    <td>IP address block:&nbsp;&nbsp;</td>
+	    <td valign="top"><input name="ipblock" type="text" class="formfld" size="20" value="<?=htmlspecialchars($pconfig['ipblock']);?>">
+		/ 
+		<select name="prefix" class="formfld">
+		<?php for ($i = 30; $i > 19; $i--): ?>
+		  <option value="<?=$i;?>" <?php if ($i == $pconfig['prefix']) echo "selected"; ?>>
+		    <?=$i;?>
+		  </option>
+		<?php endfor; ?>
+		</select>
+	    </td>
+	  </tr>
+	</table>
+      </td>
+    </tr>
+
+    <tr> 
+      <td width="22%" valign="top" class="vncell"></td>
+      <td width="78%" class="vtable"> 
+	For bridges interfaces OpenVPN will allocate
+	an IP range in the bridged subnet to connecting clients.<br><br>
+	The gateway and netmask parameters
+	can be set to either the IP of the bridge interface, or to
+	the IP of the default gateway/router on the bridged subnet.<br>
+	<br>
+
+	<table cellpadding="0" cellspacing="0">
+	  <tr>
+	    <td>Range:&nbsp;&nbsp;</td>
+	    <td valign="top"><input name="range_from" type="text" class="formfld" size="20" value="<?=htmlspecialchars($pconfig['range_from']);?>">
+		&nbsp;to&nbsp;<input name="range_to" type="text" class="formfld" size="20" value="<?=htmlspecialchars($pconfig['range_to']);?>">
+	    </td>
+	  </tr>
+
+	  <tr>
+	    <td>Gateway:&nbsp;&nbsp;</td>
+	    <td valign="top"><input name="gateway" type="text" class="formfld" size="20" value="<?=htmlspecialchars($pconfig['gateway']);?>">
+	    </td>
+	  </tr>
+	</table>
+      </td>
+    </tr>
+
+    <tr> 
+      <td width="22%" valign="top" class="vncell">&nbsp;</td>
+      <td width="78%" class="vtable"> 
+        When using pre-shared keys, enter the IP address and subnet mask
+        of the local and remote VPN endpoint here. For TAP devices, only the
+        IP address of the local VPN endpoint is needed. The netmask is the subnet mask
+        of the virtual ethernet segment which is being created or connected to.<br>
+	<br>
+	<table cellpadding="0" cellspacing="0">
+	  <tr>
+	    <td>Local IP address:&nbsp;&nbsp;</td>
+	    <td valign="top"><input name="lipaddr" id="lipaddr" type="text" class="formfld" size="20" value="<?=htmlspecialchars($pconfig['lipaddr']);?>">
+		/ 
+		<select name="netmask" id="netmask" class="formfld">
+		<?php for ($i = 30; $i > 19; $i--): ?>
+		  <option value="<?=$i;?>" <?php if ($i == $pconfig['netmask']) echo "selected"; ?>>
+		    <?=$i;?>
+		  </option>
+		<?php endfor; ?>
+		</select>
+	    </td>
+	  </tr>
+
+	  <tr>
+	    <td>Remote IP address:&nbsp;&nbsp;</td>
+	    <td valign="top"><input name="ripaddr" id="ripaddr" type="text" class="formfld" size="20" value="<?=htmlspecialchars($pconfig['ripaddr']);?>">
+	    </td>
+	  </tr>
+	</table>
+      </td>
+    </tr>
+
+    <tr> 
+      <td colspan="2" valign="top" height="12"></td>
+    </tr>
+    <tr>
+      <td colspan="2" valign="top" class="listtopic">Server Options</td>
+    </tr>
+    <tr>
+      <td width="22%" valign="top" class="vncell">Internal routing mode</td>
+      <td width="78%" class="vtable">
+	<input name="cli2cli" type="checkbox" value="yes" <?php if (isset($pconfig['cli2cli'])) echo "checked"; ?>>
+	<strong>Enable client-to-client routing</strong><br>
+	If this option is on, clients are allowed to talk to each other.</td>
+    </tr>
+      
+    <tr>
+      <td width="22%" valign="top" class="vncell">Client authentication</td>
+      <td width="78%" class="vtable">
+	<input name="dupcn" type="checkbox" value="yes" <?php if (isset($pconfig['dupcn'])) echo "checked"; ?>>
+        <strong>Permit duplicate client certificates</strong><br>
+	If this option is on, clients with duplicate certificates will not be disconnected.</td>
+    </tr>
+	 
+    <tr>
+      <td width="22%" valign="top" class="vncell">Compression method</td>
+      <td width="78%" class="vtable">
+        <select name="comp_method" class="formfld" id="comp_method">
+        <option <?php if (!$pconfig['comp_method']) echo "selected";?> value="">none</option>
+        <?php $compression_method = array('lzo' => 'LZO', 'noadapt' => 'LZO (no adaptive)');
+            foreach($compression_method as $comp_method => $comp_methodname): ?>
+                <option value="<?=$comp_method;?>"
+		<?php if ($comp_method == $pconfig['comp_method']) echo "selected";?>>
+                  <?=htmlspecialchars($comp_methodname);?>
+                </option>
+        <?php endforeach; ?>
+        </select> 
+	<br>
+	Choose which compression method to use.<br>
+	<br>
+	LZO compression generally improves performance on slow links,
+	but may add up to 1 byte per packet for incompressible data.<br>
+	<br>
+	With adaptive compression, OpenVPN will periodically sample the
+	compression process to measure its efficiency. If the data being
+	sent over the tunnel is already compressed, the compression
+	efficiency will be very low. Choose 'LZO (no adaptive)'
+	to disable OpenVPN's adaptive compression algorithm.
+	</td>
+    </tr>
+	 
+    <tr>
+      <td width="22%" valign="top" class="vncell">Client-push options</td>
+      <td width="78%" class="vtable">
+	    <table border="0" cellspacing="0" cellpadding="0">
+	      <tr>
+            <td><input type="checkbox" name="psh_redir" value="yes" <?php if (isset($pconfig['psh_options']['redir'])) echo "checked"; ?>>
+            Redirect-gateway</td>
+            <td>&nbsp;</td>
+            <td><input type="checkbox" name="psh_redir_loc" value="yes" <?php if (isset($pconfig['psh_options']['redir_loc'])) echo "checked"; ?>>
+              Local</td>
+	        </tr>
+          <tr>
+            <td><input type="checkbox" name="psh_rtedelay" value="yes" <?php if (isset($pconfig['psh_options']['rtedelay'])) echo "checked"; ?>> Route-delay</td>
+            <td width="16">&nbsp;</td>
+            <td><input type="text" name="psh_rtedelay_int" class="formfld" size="4" value="<?= $pconfig['psh_options']['rtedelay_int']?>"> seconds</td>
+          </tr>
+          <tr>
+            <td><input type="checkbox" name="psh_inact" value="yes" <?php if (isset($pconfig['psh_options']['inact'])) echo "checked"; ?>>
+    Inactive</td>
+            <td>&nbsp;</td>
+            <td><input type="text" name="psh_inact_int" class="formfld" size="4" value="<?= $pconfig['psh_options']['inact_int']?>">
+    seconds</td>
+          </tr>
+          <tr>
+            <td><input type="checkbox" name="psh_ping" value="yes" <?php if (isset($pconfig['psh_options']['ping'])) echo "checked"; ?>> Ping</td>
+            <td>&nbsp;</td>
+            <td>Interval: <input type="text" name="psh_ping_int" class="formfld" size="4" value="<?= $pconfig['psh_options']['ping_int']?>"> seconds</td>
+          </tr>
+          <tr>
+            <td><input type="checkbox" name="psh_pingexit" value="yes" <?php if (isset($pconfig['psh_options']['pingexit'])) echo "checked"; ?>> Ping-exit</td>
+            <td>&nbsp;</td>
+            <td>Interval: <input type="text" name="psh_pingexit_int" class="formfld" size="4" value="<?= $pconfig['psh_options']['pingexit_int']?>"> seconds</td>
+          </tr>
+          <tr>
+            <td><input type="checkbox" name="psh_pingrst" value="yes" <?php if (isset($pconfig['psh_options']['pingrst'])) echo "checked"; ?>> Ping-restart</td>
+            <td>&nbsp;</td>
+            <td>Interval: <input type="text" name="psh_pingrst_int" class="formfld" size="4" value="<?= $pconfig['psh_options']['pingrst_int']?>"> seconds</td>
+          </tr>
+        </table></td>
+    </tr>
+
+     <tr>
+      <td width="22%" valign="top" class="vncell">Expert mode</td>
+      <td width="78%" class="vtable">
+        <input name="expertmode_enabled" type="checkbox" value="yes" onclick="expertmode_change(false);" <?php if (isset($pconfig['expertmode_enabled'])) echo "checked"; ?>>
+        <strong>Enable expert OpenVPN mode</strong><br>
+        If this option is on, you can specify your own extra commands for the OpenVPN server.<br/>
+        <textarea name="expertmode_options" id="expertmode_options" cols="65" rows="4" class="formpre"><?=htmlspecialchars($pconfig['expertmode_options']);?></textarea>
+	<strong><span class="red">Note:</span></strong><br>
+	Commands in expert mode aren't supported.
+      </td>
+    </tr>
+
+    <tr>
+      <td width="22%" valign="top">&nbsp;</td>
+      <td width="78%">
+        <input name="Submit" type="submit" class="formbtn" value="Save" onclick="methodsel_change(true);tls_change(true);expertmode_change(true);enable_change(true)">
+        <input name="verb" type="hidden" value="<?=$pconfig['verb'];?>"> 
+        <?php if (isset($id)): ?>
+        <input name="id" type="hidden" value="<?=$id;?>"> 
+        <?php endif; ?>
+      </td>
+    </tr>
+</table>
+</form>
+<script language="JavaScript">
+<!--
+type_change();
+tls_change(false);
+methodsel_change(false);
+expertmode_change(false);
+enable_change(false);
+//-->
+</script>
+<?php include("fend.inc");
+?>
diff -Nur rootfs-1.21/usr/local/www/vpn_openvpn_srv.php rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_srv.php
--- rootfs-1.21/usr/local/www/vpn_openvpn_srv.php	1970-01-01 01:00:00.000000000 +0100
+++ rootfs-1.21-ovpn1/usr/local/www/vpn_openvpn_srv.php	2006-01-14 11:49:22.000000000 +0100
@@ -0,0 +1,183 @@
+#!/usr/local/bin/php
+<?php 
+/*
+	vpn_openvpn_srv.php
+
+	Copyright (C) 2004 Peter Curran (peter@closeconsultants.com).
+	Copyright (C) 2005-2006 Peter Allgeyer (allgeyer@web.de).
+	All rights reserved.
+	
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions are met:
+	
+	1. Redistributions of source code must retain the above copyright notice,
+	   this list of conditions and the following disclaimer.
+	
+	2. Redistributions in binary form must reproduce the above copyright
+	   notice, this list of conditions and the following disclaimer in the
+	   documentation and/or other materials provided with the distribution.
+	
+	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	POSSIBILITY OF SUCH DAMAGE.
+*/
+
+$pgtitle = array("VPN", "OpenVPN");
+require("guiconfig.inc");
+require_once("openvpn.inc");
+
+if (!is_array($config['ovpn']))
+	$config['ovpn'] = array();
+if (!is_array($config['ovpn']['server'])){
+	$config['ovpn']['server'] =  array();
+	$config['ovpn']['server']['tunnel'] =  array();
+}
+
+$ovpnsrv = &$config['ovpn']['server']['tunnel'];
+
+$id = $_GET['id'];
+if (isset($_POST['id']))
+        $id = $_POST['id'];
+
+
+if ($_POST['apply']) {
+		$retval = 0;
+		if (file_exists($d_sysrebootreqd_path)) {
+			/* Rewrite interface definitions */
+			$retval = ovpn_server_iface();
+		} else {
+			ovpn_lock();
+			$retval = ovpn_server_iface();
+			$retval = ovpn_config_server(false);
+			ovpn_unlock();
+		}
+		if (file_exists($d_ovpnsrvdirty_path))
+			unlink($d_ovpnsrvdirty_path);
+		$savemsg = get_std_save_message($retval);	
+}
+
+if ($_GET['act'] == "del") {
+	if ($ovpnsrv[$id]) {
+		$ovpnent = $ovpnsrv[$id];
+		unset($ovpnsrv[$id]);
+									      
+		/* Kill running processes */
+		ovpn_server_kill($ovpnent['tun_iface']);
+
+		/* Remove old certs & keys */
+		ovpn_server_certs_del($ovpnent['tun_iface']);
+
+		/* Remove interface from list of optional interfaces */
+		ovpn_server_iface_del($ovpnent['tun_iface']);
+
+		write_config();
+		//touch($d_sysrebootreqd_path);
+		header("Location: vpn_openvpn_srv.php");
+		exit;
+	}
+}
+?>
+<?php include("fbegin.inc"); ?>
+<?php if ($input_errors) print_input_errors($input_errors); ?>
+<?php if (file_exists($d_sysrebootreqd_path) && !file_exists($d_ovpnsrvdirty_path)) print_info_box(get_std_save_message(0)); ?>
+<form action="vpn_openvpn_srv.php" method="post" enctype="multipart/form-data" name="iform" id="iform">
+<?php if (file_exists($d_ovpnsrvdirty_path)): ?><p>
+<?php print_info_box_np("The OpenVPN server configuration has been changed.<br>You must apply the changes in order for them to take effect.");?><br>
+<input name="apply" type="submit" class="formbtn" id="apply" value="Apply changes"></p>
+<?php endif; ?>
+
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+  <tr><td>
+  <ul id="tabnav">	        
+	<li class="tabact">Server</li>
+	<li class="tabinact"><a href="vpn_openvpn_cli.php">Client</a></li>
+	<li class="tabinact"><a href="vpn_openvpn_ccd.php">Client-specific Configuration</a></li>
+	<li class="tabinact"><a href="vpn_openvpn_crl.php">CRL</a></li>
+  </ul>
+  </td></tr>
+  <tr>
+  <td class="tabcont">
+  <strong><span class="red">WARNING: This feature is experimental and modifies your optional interface configuration.
+  Backup your configuration before using OpenVPN, and restore it before upgrading.<br>
+&nbsp;  <br>
+    </span></strong>
+    <table width="100%" border="0" cellpadding="0" cellspacing="0">
+	<tr>
+	  <td width="5%" class="listhdrr">Interface</td>
+	  <td width="5%" class="listhdrr">Protocol</td>
+	  <td width="5%" class="listhdrr">Socket</td>
+	  <td width="25%" class="listhdrr">IP Block</td>
+	  <td width="15%" class="listhdrr">Crypto</td>
+	  <td width="35%" class="listhdr">Description</td>
+	  <td width="10%" class="list"></td>
+	</tr>
+	
+	<?php $i = 0; foreach ($ovpnsrv as $server):
+					if (!isset($server['enable'])) {
+						$spans = "<span class=\"gray\">";
+						$spane = "</span>";
+					} else {
+						$spans = $spane = "";
+					}
+					
+		if ($server['bind_iface'] == 'all')
+			$ipaddr = "0.0.0.0";
+		else
+			$ipaddr = ovpn_get_ip($server['bind_iface']);
+	?>
+	
+	<tr>
+	  <td class="listlr"><?=$spans;?>
+		<?php	if ($interface = ovpn_get_opt_interface($server['tun_iface']))
+				$iface = $config['interfaces'][$interface]['descr'];
+			else $iface = strtoupper($server['tun_iface']);?>
+		<?= $iface;?>
+	  <?=$spane;?></td>
+	  <td class="listr"><?=$spans;?>
+		<?= strtoupper($server['proto']);?>	
+	  <?=$spane;?></td>
+	  <td class="listr"><?=$spans;?>
+		<?= $ipaddr.":".$server['port'];?>
+	  <?=$spane;?></td>
+	  <td nowrap class="listr"><?=$spans;?>
+		<?php	if ($server['authentication_method'] == "pre_shared_key") {
+				if ($server['type'] == "tun") {
+					$ipblock = $server['lipaddr'] . " / " . $server['ripaddr'];
+				} else {
+					$ipblock = $server['lipaddr'] . "/" . $server['netmask'];
+				}
+			} else if (!$server['bridge'])
+				$ipblock = $server['ipblock'] . "/" . $server['prefix'];
+			else if ($server['range_from'])
+				$ipblock = $server['range_from'] . " - " . $server['range_to'];
+			else
+				$ipblock = "--";?>
+		<?= $ipblock;?>	
+	  <?=$spane;?></td>
+	  <td class="listr"><?=$spans;?>
+		<?= $server['crypto'];?>	
+	  <?=$spane;?></td>
+	   <td class="listbg"><?=$spans;?>
+	  	<?= htmlspecialchars($server['descr']);?>&nbsp;
+	  <?=$spane;?></td>
+	  <td valign="middle" nowrap class="list"> <a href="vpn_openvpn_srv_edit.php?id=<?=$i;?>"><img src="e.gif" title="edit server configuration" width="17" height="17" border="0"></a>
+		 &nbsp;<a href="vpn_openvpn_srv.php?act=del&id=<?=$i;?>" onclick="return confirm('Do you really want to delete this server configuration?')"><img src="x.gif" title="delete server configuration" width="17" height="17" border="0"></a></td>
+	</tr>
+  	<?php $i++; endforeach; ?>
+	<tr> 
+	  <td class="list" colspan="6">&nbsp;</td>
+	  <td class="list"> <a href="vpn_openvpn_srv_edit.php"><img src="plus.gif" title="add server configuration" width="17" height="17" border="0"></a></td>
+	</tr>
+    </table>
+  </td>
+</tr>
+</table>
+</form>
+<?php include("fend.inc"); ?>

