diff options
-rw-r--r-- | etc/inc/openvpn.inc | 1291 | ||||
-rwxr-xr-x | usr/local/www/vpn_openvpn.php | 2 | ||||
-rwxr-xr-x | usr/local/www/vpn_openvpn_ccd.php | 192 | ||||
-rwxr-xr-x | usr/local/www/vpn_openvpn_ccd_edit.php | 420 | ||||
-rwxr-xr-x | usr/local/www/vpn_openvpn_cli.php | 50 | ||||
-rwxr-xr-x | usr/local/www/vpn_openvpn_cli_edit.php | 608 | ||||
-rwxr-xr-x | usr/local/www/vpn_openvpn_crl.php | 159 | ||||
-rwxr-xr-x | usr/local/www/vpn_openvpn_crl_edit.php | 241 | ||||
-rwxr-xr-x | usr/local/www/vpn_openvpn_srv.php | 187 | ||||
-rwxr-xr-x | usr/local/www/vpn_openvpn_srv_edit.php | 1167 |
10 files changed, 3831 insertions, 486 deletions
diff --git a/etc/inc/openvpn.inc b/etc/inc/openvpn.inc index 0953779..1036f31 100644 --- a/etc/inc/openvpn.inc +++ b/etc/inc/openvpn.inc @@ -3,6 +3,7 @@ openvpn.inc Copyright (C) 2004 Peter Curran (peter@closeconsultants.com). + Copyright (C) 2005 Peter Allgeyer (allgeyer@web.de). All rights reserved. Redistribution and use in source and binary forms, with or without @@ -35,6 +36,8 @@ 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(); @@ -50,13 +53,13 @@ function ovpn_link_tap() { mwexec("/sbin/kldload if_tap"); $fd = fopen($g['vardb_path'] ."/ovpn_tap_link", 'w'); } - else { - $fd = fopen($g['vardb_path'] ."/ovpn_tap_link", 'r+'); - $link_count = fread($fd); - $link_count ++; - } - fwrite($fd, $link_count); - fclose($fd); + //else { + // $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); return true; } @@ -68,8 +71,8 @@ function ovpn_unlink_tap() { return false; //no file, no links so why are we called? $fd = fopen($g['vardb_path'] ."/ovpn_tap_link", 'r+'); - $link_count = fread($fd); - $link_count --; + $link_count = fread($fd, filesize($g['vardb_path'] ."/ovpn_tap_link")); + $link_count--; fwrite($fd, $link_count); fclose($fd); @@ -82,146 +85,103 @@ function ovpn_unlink_tap() { /* Server related functions */ /*****************************/ -function getnxt_server_if($type) { - /* find the first available device of type $type */ - global $config; - $a_server = $config['ovpn']['server']['tunnel']; - $max = ($type == 'tun') ? 17 : 4; - for ($i = 0; $i < $max ; $i++) { - $hit = false; - foreach ($a_server as $server) { - if ($server['tun_iface'] == $type . $i) { - $hit = true; - break; - } - } - if (!$hit) - return $type . $i; - } - return false; -} - -function getnxt_server_port() { - /* Get first unused port */ - global $config; - $a_server = $config['ovpn']['server']['tunnel']; - $port = 1194; - while (true) { - $hit = false; - foreach ($a_server as $server) { - if ($server['port'] == $port) { - $hit = true; - break; - } - } - if (!$hit) - if (!ovpn_port_inuse_client($port)) - return $port; - $port++; - } - return false; /* should never get here */ -} - /* Configure the server */ function ovpn_config_server($reconfigure) { - global $config, $g; + global $config, $g, $d_ovpnsrvdirty_path; foreach ($config['ovpn']['server']['tunnel'] as $id => $server) { /* get tunnel interface */ $tun = $server['tun_iface']; - /* kill any running openvpn daemon */ - killbypid($g['varrun_path']."/ovpn_srv_{$tun}.pid"); - if (isset($server['enable'])) { - if ($g['booting']) + 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; } - /* 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}.pem"); - unlink_if_exists("{$g['varetc_path']}/ovpn_cli_up_{$tun}.pem"); - - /* Copy the TLS-Server certs & keys to disk */ - $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); - } + /* read dirtyfile */ + if (is_readable($d_ovpnsrvdirty_path)) + $lines = file($d_ovpnsrvdirty_path); + + /* reconfigure server */ + if (is_array($lines) && in_array($tun, $lines)) { + + /* kill running server */ + ovpn_server_kill($tun); + + /* remove old certs & keys */ + ovpn_server_certs_del($tun); - 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); + /* define configuration options */ + ovpn_srv_config_generate($id); } /* Start the openvpn daemon */ - mwexec("/usr/local/sbin/openvpn " . ovpn_srv_config_generate($id)); + if (!is_readable("{$g['varrun_path']}/ovpn_srv_{$tun}.pid")) + mwexec("/usr/local/sbin/openvpn {$g['varetc_path']}/ovpn_srv_{$tun}.conf"); - if ($g['booting']) - /* Send the boot message */ - echo "done\n"; + /* next server */ + continue; } - else { - if (!$g['booting']){ - /* stop any processes, unload the tap module */ - /* Remove old certs & keys */ - ovpn_server_kill($tun); - if ($server['type'] == "tap") - ovpn_unlink_tap(); - } + /* 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_kill($tun) { +function ovpn_server_certs_del($tun) { global $g; - killbypid("{$g['varrun_path']}/ovpn_srv_{$tun}.pid"); - /* 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; @@ -233,140 +193,253 @@ function ovpn_srv_config_generate($id) { /* 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 are a TLS Server (for authentication) - We will run without privilege */ - $ovpn_config = "--daemon --user nobody --group nobody --verb {$server['verb']} --persist-tun --persist-key --status /var/log/openvpn_{$tun}.log 60 "; - - /* pid file */ - $ovpn_config .= "--writepid {$g['varrun_path']}/ovpn_srv_{$tun}.pid "; - - /* interface */ - $ovpn_config .= "--dev {$server['tun_iface']} "; - - /* port */ - $ovpn_config .= "--port {$server['port']} "; + $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 "; - } - + if ($server['proto'] == "tcp") + $ovpn_config .= "proto tcp-server\n"; + /* Interface binding - 1 or all */ - if ($server['bind_iface'] != 'all') { + if ($server['bind_iface'] != 'all') if ($ipaddr = ovpn_get_ip($server['bind_iface'])) - $ovpn_config .= "--local $ipaddr "; - else - return "Interface bridged"; - } + $ovpn_config .= "local {$ipaddr}\n"; /* are we using dynamic ip addresses? */ if (isset($server['dynip'])) - $ovpn_config .= "--persist-remote-ip "; - + $ovpn_config .= "persist-remote-ip\n"; + /* Client to client routing (off by default) */ if (isset($server['cli2cli'])) - $ovpn_config .= "--client-to-client "; - - /* Set maximum simultaneous clients */ - $ovpn_config .= "--max-clients {$server['maxcli']} "; - - /* bridging enabled? */ - if (($ifname = $config['interfaces'][$iface]['bridge']) && $server['type'] == "tap") { - $gateway = $config['interfaces'][$ifname]['ipaddr']; - $netmask = gen_subnet_mask($config['interfaces'][$ifname]['subnet']); - $poolstart = $server['ipblock']; - $poolend = gen_subnet_max($server['ipblock'], $server['prefix']); + $ovpn_config .= "client-to-client\n"; - $ovpn_config .= "--server-bridge $gateway $netmask $poolstart $poolend "; + /* Limit server to a maximum of n concurrent clients. */ + if (!empty($server['maxcli'])) + $ovpn_config .= "max-clients {$server['maxcli']}\n"; - $lastdigits = substr($tun, 3) + 2; - $ovpn_srv_up = "/sbin/ifconfig " . $tun . " 127.0.0." . $lastdigits . "/32\n"; + /* Authentication method */ + if ($server['authentication_method'] != "pre_shared_key") { - $fd = fopen("{$g['varetc_path']}/ovpn_srv_up_{$tun}.sh", "w"); - if ($fd) { - fwrite($fd, $ovpn_srv_up); - fclose($fd); - chmod ("{$g['varetc_path']}/ovpn_srv_up_{$tun}.sh", 0755); - $ovpn_config .= "--up /var/etc/ovpn_srv_up_{$tun}.sh "; + $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"; + } else { - /* New --server macro simplifies config */ - $netmask = gen_subnet_mask($server['prefix']); + /* 'authentication_method' == "pre_shared_key" */ + $network = gen_subnet($server['lipaddr'], $server['netmask']); + $netmask = gen_subnet_mask($server['netmask']); - $ovpn_config .= "--server {$server['ipblock']} {$netmask} "; - } - - /* TLS-Server params */ - $ovpn_config .= "--ca {$g['vardb_path']}/ovpn_ca_cert_{$tun}.pem "; - $ovpn_config .= "--cert {$g['vardb_path']}/ovpn_srv_cert_{$tun}.pem "; - $ovpn_config .= "--key {$g['vardb_path']}/ovpn_srv_key_{$tun}.pem "; - $ovpn_config .= "--dh {$g['vardb_path']}/ovpn_dh_{$tun}.pem "; - - /* TLS auth */ - if (isset($server['tlsauth'])) - $ovpn_config .= "--tls-auth {$g['vardb_path']}/ovpn_srv_psk_{$tun}.pem 0 "; - - /* Data channel encryption cipher*/ - $ovpn_config .= "--cipher {$server['crypto']} "; + $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"; + } + + if (isset($server['client-to-client'])) + $ovpn_config .= "push \"route {$network} {$netmask}\"\n"; + else + $ovpn_config .= "push \"route {$server['lipaddr']}\"\n"; + + } /* end authentication_method */ + + $push_options = ""; - /* Duplicate CNs */ - if (isset($server['dupcn'])) - $ovpn_config .= "--duplicate-cn "; - /* Client push - redirect gateway */ - if (isset($server['psh_options']['redir'])){ + if (isset($server['psh_options']['redir'])) { if (isset($server['psh_options']['redir_loc'])) - $ovpn_config .= "--push \"redirect-gateway local\" "; + $push_config .= "push \"redirect-gateway local\"\n"; else - $ovpn_config .= "--push \"redirect-gateway\" "; + $push_config .= "push \"redirect-gateway\"\n"; + if ($server['method'] != "ovpn") + $push_config .= "push \"route-gateway {$server['ipblock']}\"\n"; } - + /* Client push - route delay */ if (isset($server['psh_options']['rte_delay'])) - $ovpn_config .= "--push \"route-delay {$server['psh_options']['rte_delay_int']}\" "; - + $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']} "; - $ovpn_config .= "--push \"ping {$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) . " "; - $ovpn_config .= "--push \"ping-restart $interval\" "; + $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']} "; - $ovpn_config .= "--push \"ping-exit {$server['psh_options']['pingexit_int']}\" "; + $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']} "; - $ovpn_config .= "--push \"inactive {$server['psh_options']['inact_int']}\" "; + $ovpn_config .= "inactive {$server['psh_options']['inact_int']}\n"; + $push_config .= "push \"inactive {$server['psh_options']['inact_int']}\"\n"; } - + + if (isset($push_config)) + $ovpn_config .= $push_config; + if (!isset($conflict)) - $ovpn_config .= "--keepalive 10 60 "; + $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); - return $ovpn_config; } /* 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'])) { @@ -382,17 +455,31 @@ function ovpn_server_iface(){ && ($config['interfaces'][$ifname]['ovpn'] == "server_{$tun}")) /* Already an interface defined - overwrite */ break; - } - else { + } 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($ifname); + $config['interfaces'][$ifname]['descr'] = strtoupper($server['tun_iface']); $config['interfaces'][$ifname]['if'] = $server['tun_iface']; - $config['interfaces'][$ifname]['ipaddr'] = long2ip( ip2long($server['ipblock']) + 1); + 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}"; @@ -400,6 +487,13 @@ function ovpn_server_iface(){ 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"; } @@ -416,7 +510,6 @@ function ovpn_server_iface_del($tun) { } } - /* shift down other OPTn interfaces to get rid of holes */ $i++; @@ -428,153 +521,339 @@ function ovpn_server_iface_del($tun) { unset($config['interfaces']['opt' . $i]); $i++; } + + /* reconfigure filter rules */ + interfaces_optional_configure(); } +/* Add client config file */ +function ovpn_server_ccd_add() { + global $config, $g; -/****************************/ -/* Client related functions */ -/****************************/ + if (is_array($config['ovpn']['server']['ccd'])) { + foreach ($config['ovpn']['server']['ccd'] as $id => $server) { + /* define configuration options */ + ovpn_server_ccd_generate($id); + } + } +} -function getnxt_client_if($type) { - /* find the first available device of type $type */ - global $config; - $max = ($type == 'tun') ? 17 : 4; - for ($i = 0; $i < $max; $i++) { - $hit = false; - foreach ($a_client as $client) { - if ($client['if'] == $type . $i) { - $hit = true; - break; - } + +/* 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); } - if (!$hit) - return $type . $i; } - return false; } -function getnxt_client_port() { - /* Get first unused port */ - global $config; - $a_client = $config['ovpn']['client']['tunnel']; - $port = 1194; - while (true) { - $hit = false; - foreach ($a_client as $client) { - if ($client['port'] == $port) { - $hit = true; - break; +/* 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, $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); } - if (!$hit) - if (!ovpn_port_inuse_server($port)) - return $port; - $port++; } - return false; /* should never get here */ + return 0; } -/* Port in use */ -function ovpn_port_inuse_client($port){ +/* 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; - $a_client = $config['ovpn']['client']['tunnel']; - foreach ($a_client as $client) { - if ($client['port'] == $port) { - return true; + + $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 false; + 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); + 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); + fclose($fd); + } +} + + +/****************************/ +/* Client related functions */ +/****************************/ + function ovpn_config_client() { /* Boot time configuration */ - global $config, $g; + global $config, $g, $d_ovpnclidirty_path;; foreach ($config['ovpn']['client']['tunnel'] as $id => $client) { /* get tunnel interface */ $tun = $client['if']; - /* kill any running openvpn daemon */ - killbypid($g['varrun_path']."/ovpn_cli_{$tun}.pid"); - if (isset($client['enable'])) { - - if ($g['booting']) + + if ($g['booting']) { echo "Starting OpenVPN client $id... "; - /* 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"); - - /* Copy the TLS-Client certs & keys to disk */ - $fd = fopen("{$g['vardb_path']}/ovpn_cli_ca_cert_{$tun}.pem", "w"); - if ($fd) { - fwrite($fd, base64_decode($client['ca_cert'])."\n"); - fclose($fd); - } - else - trigger_error("OVPN: No open for CA", E_USER_NOTICE); - $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); - } - 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); - } - - /* Start openvpn for this client */ - mwexec("/usr/local/sbin/openvpn " . ovpn_cli_config_generate($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"); - if ($g['booting']) /* Send the boot message */ echo "done\n"; - } - else { - if (!$g['booting']){ - /* stop any processes, unload the tap module */ - /* Remove old certs & keys */ + + /* 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, $lines)) { + + /* kill running client */ ovpn_client_kill($tun); - if ($client['type'] == "tap") - ovpn_unlink_tap(); + /* 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_kill($tun) { +function ovpn_client_certs_del($tun) { global $g; - killbypid("{$g['varrun_path']}/ovpn_cli_{$tun}.pid"); - /* 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 */ @@ -583,65 +862,151 @@ function ovpn_cli_config_generate($id) { /* get tunnel interface */ $tun = $client['if']; - + /* get optional interface name */ $iface = ovpn_get_opt_interface($tun); - /* Client support in 2.0 is very simple */ - $ovpn_config = "--client --daemon --verb 1 --status /var/log/openvpn_{$tun}.log 60 "; - - /* pid file */ - $ovpn_config .= "--writepid {$g['varrun_path']}/ovpn_cli_{$tun}.pid "; - - /* interface */ - $ovpn_config .= "--dev {$client['if']} "; - - /* protocol */ - /* Set protocol being used (p = udp (default), tcp-client) - if ($client['proto'] == 'tcp') { - $ovpn_config .= "--proto tcp-client "; + /* 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); + } } - - /* port */ - $ovpn_config .= "--lport {$client['port']} "; - - /* server location */ - $ovpn_config .= "--remote {$client['saddr']} {$client['sport']} "; - - /* bridging enabled? */ - if (($ifname = $config['interfaces'][$iface]['bridge']) && $client['type'] == "tap") { - $lastdigits = substr($tun, 3) + 2; - $ovpn_srv_up = "/sbin/ifconfig " . $tun . " 127.0.0." . $lastdigits . "/32\n"; - $fd = fopen("{$g['varetc_path']}/ovpn_cli_up_{$tun}.sh", "w"); + 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, $ovpn_cli_up); - fclose($fd); - chmod ("{$g['varetc_path']}/ovpn_cli_up_{$tun}.sh", 0755); - $ovpn_config .= "--up /var/etc/ovpn_cli_up_{$tun}.sh "; + 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 */ - $ovpn_config .= "--ca {$g['vardb_path']}/ovpn_cli_ca_cert_{$tun}.pem "; - $ovpn_config .= "--cert {$g['vardb_path']}/ovpn_cli_cert_{$tun}.pem "; - $ovpn_config .= "--key {$g['vardb_path']}/ovpn_cli_key_{$tun}.pem "; + 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 - /* TLS auth */ - if (isset($client['tlsauth'])) - $ovpn_config .= "--tls-auth {$g['vardb_path']}/ovpn_cli_psk_{$tun}.pem 1 "; +EOD; - /* Data channel encryption cipher*/ - $ovpn_config .= "--cipher {$client['crypto']} "; - - //trigger_error("OVPN: $ovpn_config", E_USER_NOTICE); - return $ovpn_config; + 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 */ + + /* 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'])) { @@ -656,23 +1021,41 @@ function ovpn_client_iface(){ && ($config['interfaces'][$ifname]['ovpn'] == "client_{$tun}")) /* Already an interface defined - overwrite */ break; - } - else { + } 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($ifname); + $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"; } @@ -689,7 +1072,6 @@ function ovpn_client_iface_del($tun) { } } - /* shift down other OPTn interfaces to get rid of holes */ $i++; @@ -701,15 +1083,165 @@ function ovpn_client_iface_del($tun) { 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); + 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); @@ -717,17 +1249,17 @@ function ovpn_calc_end($start, $prefix){ /* 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; - $a_server = $config['ovpn']['server']['tunnel']; - foreach ($a_server as $server) { - if ($server['port'] == $port) { - return true; + if ($a_server = $config['ovpn']['server']['tunnel']) { + foreach ($a_server as $server) { + if ($server['port'] == $port) { + return true; + } } } return false; @@ -824,6 +1356,83 @@ function ovpn_real_interface_list(){ 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 */ diff --git a/usr/local/www/vpn_openvpn.php b/usr/local/www/vpn_openvpn.php index 3388536..0f7175e 100755 --- a/usr/local/www/vpn_openvpn.php +++ b/usr/local/www/vpn_openvpn.php @@ -149,8 +149,8 @@ include("head.inc"); ?> -<body link="#0000CC" vlink="#0000CC" alink="#0000CC"> <?php include("fbegin.inc"); ?> +<body link="#0000CC" vlink="#0000CC" alink="#0000CC"> <p class="pgtitle"><?=$pgtitle?></p> <?php if ($input_errors) print_input_errors($input_errors); ?> diff --git a/usr/local/www/vpn_openvpn_ccd.php b/usr/local/www/vpn_openvpn_ccd.php new file mode 100755 index 0000000..8bf448e --- /dev/null +++ b/usr/local/www/vpn_openvpn_ccd.php @@ -0,0 +1,192 @@ +#!/usr/local/bin/php +<?php +/* + vpn_openvpn_ccd.php + + Copyright (C) 2005 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. +*/ + +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; + } +} + +$pgtitle = "VPN: OpenVPN"; +include("head.inc"); + +?> + +<?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> + <br> + </span></strong> + <table width="100%" border="0" cellpadding="0" cellspacing="0"> + <tr> + <td width="5%" class="list"> </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']);?> + <?=$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> + <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"> </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 --git a/usr/local/www/vpn_openvpn_ccd_edit.php b/usr/local/www/vpn_openvpn_ccd_edit.php new file mode 100755 index 0000000..850bc80 --- /dev/null +++ b/usr/local/www/vpn_openvpn_ccd_edit.php @@ -0,0 +1,420 @@ +#!/usr/local/bin/php +<?php +/* + vpn_openvpn_ccd_edit.php + + Copyright (C) 2005 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']; + } +} + +$pgtitle = "VPN: OpenVPN: Edit client-specific configuration"; +include("head.inc"); +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> <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> </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"> </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> </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> </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> </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> </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"> </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 --git a/usr/local/www/vpn_openvpn_cli.php b/usr/local/www/vpn_openvpn_cli.php index e7cc879..fe01ee0 100755 --- a/usr/local/www/vpn_openvpn_cli.php +++ b/usr/local/www/vpn_openvpn_cli.php @@ -28,7 +28,6 @@ POSSIBILITY OF SUCH DAMAGE. */ -$pgtitle = array("VPN", "OpenVPN"); require("guiconfig.inc"); require_once("openvpn.inc"); @@ -53,6 +52,7 @@ if ($_POST['apply']) { } else{ ovpn_lock(); + $retval = ovpn_client_iface(); $retval = ovpn_config_client(); ovpn_unlock(); } @@ -67,26 +67,27 @@ if ($_GET['act'] == "del") { unset($ovpncli[$id]); /* Kill running processes */ - /* Remove old certs & keys */ 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); + //touch($d_sysrebootreqd_path); header("Location: vpn_openvpn_cli.php"); exit; } } + $pgtitle = "VPN: OpenVPN"; include("head.inc"); ?> -<body link="#0000CC" vlink="#0000CC" alink="#0000CC"> <?php include("fbegin.inc"); ?> -<p class="pgtitle"><?=$pgtitle?></p> <?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"> @@ -97,30 +98,27 @@ include("head.inc"); <table width="100%" border="0" cellpadding="0" cellspacing="0"> <tr><td> -<?php - $tab_array = array(); - $tab_array[] = array("Server", false, "vpn_openvpn.php"); - $tab_array[] = array("Client", true, "vpn_openvpn.php"); - display_top_tabs($tab_array); -?> + <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> - <div id="mainarea"> - <table class="tabcont" width="100%" border="0" cellspacing="0" cellpadding="0"> - <tr> - <td colspan="6"> + <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> <br> </span></strong> + <table width="100%" border="0" cellpadding="0" cellspacing="0"> <tr> <td width="10%" class="listhdrr">Interface</td> - <td width="10%" class="listhdrr">Protocol</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="middle">Version</td> - <td width="35%" class="listhdr">Description</td> + <td width="5%" class="listhdrr" align="center">Version</td> + <td width="40%" class="listhdr">Description</td> <td width="10%" class="list"></td> </tr> @@ -135,13 +133,16 @@ include("head.inc"); <tr> <td class="listlr"><?=$spans;?> - <?= $client['if'];?> + <?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['port'];?> + <?= "0.0.0.0:" . $client['cport'];?> <?=$spane;?></td> <td class="listr"><?=$spans;?> <?= $client['saddr'].":".$client['sport'];?> @@ -152,16 +153,15 @@ include("head.inc"); <td class="listbg"><?=$spans;?> <?= htmlspecialchars($client['descr']);?> <?=$spane;?></td> - <td valign="middle" nowrap class="list"> <a href="vpn_openvpn_cli_edit.php?id=<?=$i;?>"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_e.gif" title="edit client configuration" width="17" height="17" border="0"></a> - <a href="vpn_openvpn_cli.php?act=del&id=<?=$i;?>" onclick="return confirm('Do you really want to delete this client configuration?')"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" title="delete client configuration" width="17" height="17" border="0"></a></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> + <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"> </td> - <td class="list"> <a href="vpn_openvpn_cli_edit.php"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_plus.gif" title="add client configuration" width="17" height="17" border="0"></a></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> - </div> </td> </tr> </table> diff --git a/usr/local/www/vpn_openvpn_cli_edit.php b/usr/local/www/vpn_openvpn_cli_edit.php index c4136e4..1f4fca3 100755 --- a/usr/local/www/vpn_openvpn_cli_edit.php +++ b/usr/local/www/vpn_openvpn_cli_edit.php @@ -28,7 +28,6 @@ POSSIBILITY OF SUCH DAMAGE. */ -$pgtitle = array("VPN", "OpenVPN", "Edit client"); require("guiconfig.inc"); require_once("openvpn.inc"); @@ -50,10 +49,18 @@ if (isset($id) && $ovpncli[$id]) { $pconfig = $config['ovpn']['client']['tunnel'][$id]; if (isset($ovpncli[$id]['pull'])) $pconfig['pull'] = true; -} -else { + 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'; @@ -63,13 +70,7 @@ else { $pconfig['enable'] = true; } -if (isset($_POST['pull'])) { - - $pconfig = $_POST; - - $pconfig['ca_cert'] = base64_encode($pconfig['ca_cert']); - $pconfig['cli_cert'] = base64_encode($pconfig['cli_cert']); - $pconfig['cli_key'] = base64_encode($pconfig['cli_key']); +if ($_POST) { /* Called from form */ unset($input_errors); @@ -78,77 +79,157 @@ if (isset($_POST['pull'])) { $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 (default 1194)."; + $input_errors[] = "The server's port must be an integer between 1 and 65535."; - if (is_null($_POST['ca_cert'])) - $input_errors[] = "You must provide a CA certificate file"; - elseif (!strstr($_POST['ca_cert'], "BEGIN CERTIFICATE") || !strstr($_POST['ca_cert'], "END CERTIFICATE")) - $input_errors[] = "The CA certificate does not appear to be valid."; - - if (is_null($_POST['cli_cert'])) - $input_errors[] = "You must provide a client certificate file"; - elseif (!strstr($_POST['cli_cert'], "BEGIN CERTIFICATE") || !strstr($_POST['cli_cert'], "END CERTIFICATE")) - $input_errors[] = "The client certificate does not appear to be valid."; - - if (is_null($_POST['cli_key'])) - $input_errors[] = "You must provide a client key file"; - elseif (!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 (!$input_errors) { - if (isset($id)) { - /* Editing an existing entry */ - $ovpnent = $ovpncli[$id]; + /* 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 ( $ovpncli[$id]['sport'] != $_POST['sport'] || - $ovpncli[$id]['proto'] != $_POST['proto'] ) { + if (isset($id) && $ovpncli[$id]) { + /* Editing an existing entry */ + $ovpnent = $ovpncli[$id]; - /* some entries changed */ - for ($i = 0; isset($config['ovpn']['client']['tunnel'][$i]); $i++) { - $current = &$config['ovpn']['client']['tunnel'][$i]; + if ($ovpncli[$id]['bridge'] != $_POST['bridge']) { + /* double bridging? */ + if ($_POST['bridge'] && + $_POST['type'] == "tap" && + $_POST['authentication_method'] == "rsasig") + $retval = check_bridging($_POST['bridge']); - 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"; - } - } + if (!empty($retval)) + $input_errors[] = $retval; + else + ovpn_cli_dirty($ovpnent['if']); + } - /* Test Server type hasn't changed */ - if ($ovpnent['type'] != $_POST['type']) { - $nxt_if = getnxt_client_if($_POST['type']); - if (!$nxt_if) - $input_errors[] = "Run out of devices for a tunnel of type {$_POST['type']}"; - else - $ovpnent['if'] = $nxt_if; - /* Need to reboot in order to create interfaces cleanly */ - touch($d_sysrebootreqd_path); - } - /* Has the enable/disable state changed? */ - if (isset($ovpnent['enable']) && isset($_POST['disabled'])) { - touch($d_ovpnclidirty_path); - } - if (!isset($ovpnent['enable']) && !isset($_POST['disabled'])) { - touch($d_ovpnclidirty_path); + 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"; } } - else { - /* Creating a new entry */ - $ovpnent = array(); - $nxt_if = getnxt_client_if($_POST['type']); - if (!$nxt_if) - $input_errors[] = "Run out of devices for a tunnel of type {$_POST['type']}"; + + /* 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']) ."."; + + /* Has the enable/disable state changed? */ + if (isset($ovpnent['enable']) && isset($_POST['disabled'])) { + ovpn_cli_dirty($ovpnent['if']); + } + 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(); + + ovpn_cli_dirty($ovpnent['if']); + } + } 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; else - $ovpnent['if'] = $nxt_if; - $ovpnent['port'] = getnxt_client_port(); - /* I think we have to reboot to have the interface created cleanly */ - touch($d_sysrebootreqd_path); + ovpn_cli_dirty($ovpnent['if']); } + } + 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']; @@ -158,10 +239,33 @@ if (isset($_POST['pull'])) { $ovpnent['cli_cert'] = $pconfig['cli_cert']; $ovpnent['cli_key'] = $pconfig['cli_key']; $ovpnent['crypto'] = $_POST['crypto']; - $ovpnent['pull'] = true; //This is a fixed config for this version - $ovpnent['enable'] = isset($_POST['disabled']) ? false : true; - - + $ovpnent['ns_cert_type'] = $_POST['ns_cert_type'] ? true : false; + $ovpnent['pull'] = $_POST['pull'] ? 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; } @@ -170,15 +274,157 @@ if (isset($_POST['pull'])) { } write_config(); - touch($d_ovpnclidirty_path); + 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']); } } + +$pgtitle = "VPN: OpenVPN: Edit client"; +include("head.inc"); + ?> + <?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.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"> @@ -186,7 +432,7 @@ if (isset($_POST['pull'])) { <tr> <td width="22%" valign="top" class="vncellreq">Disabled</td> <td width="78%" class="vtable"> - <input name="disabled" type="checkbox" id="disabled" value="yes" <?php if (!isset($pconfig['enable'])) echo "checked"; ?>> + <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> @@ -199,20 +445,14 @@ if (isset($_POST['pull'])) { <tr> <td colspan="2" valign="top" class="listtopic">Server information</td> </tr> - <tr> - <td valign="top" class="vncellreq">Tunnel type</td> - <td class="vtable"> - <input name="type" type="radio" class="formfld" value="tun" <?php if ($pconfig['type'] == 'tun') echo "checked"; ?>> TUN -<input name="type" type="radio" class="formfld" value="tap" <?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 -<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> + <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> @@ -222,14 +462,6 @@ if (isset($_POST['pull'])) { </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">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 @@ -249,24 +481,21 @@ if (isset($_POST['pull'])) { <td colspan="2" class="list" height="12"></td> </tr> - <tr> - <td colspan="2" valign="top" class="listtopic">Client configuration</td> + <tr> + <td colspan="2" valign="top" class="listtopic">Cryptographic options</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> + <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"> @@ -309,24 +538,165 @@ if (isset($_POST['pull'])) { 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 + <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 +<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: </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: </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> + <tr> - <td width="22%" valign="top" class="vncellreq">Options</td> + <td width="22%" valign="top" class="vncell">Options</td> <td width="78%" class="vtable"> <input type="checkbox" name="pull" value="yes" <?php if ($pconfig['pull']) echo "checked"; ?>> - Client-pull</td> + <strong>Client-pull</strong></td> </tr> - - <tr> - <td width="22%" valign="top"> </td> - <td width="78%"> - <input name="Submit" type="submit" class="formbtn" value="Save"> + + <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"> </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> + </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 --git a/usr/local/www/vpn_openvpn_crl.php b/usr/local/www/vpn_openvpn_crl.php new file mode 100755 index 0000000..cfafe89 --- /dev/null +++ b/usr/local/www/vpn_openvpn_crl.php @@ -0,0 +1,159 @@ +#!/usr/local/bin/php +<?php +/* + vpn_openvpn_crl.php + + Copyright (C) 2005 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. +*/ + +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; + } +} + +$pgtitle = "VPN: OpenVPN"; +include("head.inc"); + +?> + +<?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> + <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']);?> + <?=$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> + <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"> </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 --git a/usr/local/www/vpn_openvpn_crl_edit.php b/usr/local/www/vpn_openvpn_crl_edit.php new file mode 100755 index 0000000..7b5d463 --- /dev/null +++ b/usr/local/www/vpn_openvpn_crl_edit.php @@ -0,0 +1,241 @@ +#!/usr/local/bin/php +<?php +/* + vpn_openvpn_crl_edit.php + + Copyright (C) 2005 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. +*/ + +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']); + } +} + +$pgtitle = "VPN: OpenVPN: Edit client-specific configuration"; +include("head.inc"); + +?> + +<?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> <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"> </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 --git a/usr/local/www/vpn_openvpn_srv.php b/usr/local/www/vpn_openvpn_srv.php new file mode 100755 index 0000000..5cd6ff1 --- /dev/null +++ b/usr/local/www/vpn_openvpn_srv.php @@ -0,0 +1,187 @@ +#!/usr/local/bin/php +<?php +/* + vpn_openvpn_srv.php + + Copyright (C) 2004 Peter Curran (peter@closeconsultants.com). + Copyright (C) 2005 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. +*/ + +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; + } +} + +$pgtitle = "VPN: OpenVPN"; +include("head.inc"); + +?> + +<?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> + <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']);?> + <?=$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> + <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"> </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"); ?> diff --git a/usr/local/www/vpn_openvpn_srv_edit.php b/usr/local/www/vpn_openvpn_srv_edit.php new file mode 100755 index 0000000..e2ac9f1 --- /dev/null +++ b/usr/local/www/vpn_openvpn_srv_edit.php @@ -0,0 +1,1167 @@ +#!/usr/local/bin/php +<?php +/* + vpn_openvpn_srv_edit.php + + Copyright (C) 2004 Peter Curran (peter@closeconsultants.com). + Copyright (C) 2005 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. +*/ + +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); + unset($bridge_reset); + + /* 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 { + $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)."; + + if (!($_POST['type'] == "tap" && $_POST['authentication_method'] == "rsasig")) + $bridge_reset = 1; + } + } + + /* 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; + else + ovpn_srv_dirty($ovpnent['tun_iface']); + } + + /* 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']) ."."; + + } + + /* Has the enable/disable state changed? */ + if (isset($ovpnent['enable']) && isset($_POST['disabled'])) { + /* status changed to disabled */ + ovpn_srv_dirty($ovpnent['tun_iface']); + } + + /* 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."; + } + } + + ovpn_srv_dirty($ovpnent['tun_iface']); + } + + } 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; + else + ovpn_srv_dirty($ovpnent['tun_iface']); + } + } + + 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['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']; + } +} + +$pgtitle = "VPN: OpenVPN: Edit Server"; +include("head.inc"); + +?> + +<?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.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; + 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; + 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> <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 + <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 + <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> </td> + <td> </td> + </tr> + <tr> + <td>Maximum number of simultaneous clients: <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: </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: </td> + <td valign="top"><input name="range_from" type="text" class="formfld" size="20" value="<?=htmlspecialchars($pconfig['range_from']);?>"> + to <input name="range_to" type="text" class="formfld" size="20" value="<?=htmlspecialchars($pconfig['range_to']);?>"> + </td> + </tr> + + <tr> + <td>Gateway: </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"> </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: </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: </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">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> </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"> </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> </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> </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> </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> </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"> </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"); +?> |