diff --git a/etc/inc/openvpn.inc b/etc/inc/openvpn.inc index 0953779494..1036f31a10 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"); + /* read dirtyfile */ + if (is_readable($d_ovpnsrvdirty_path)) + $lines = file($d_ovpnsrvdirty_path); - /* 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); - } + /* reconfigure server */ + if (is_array($lines) && in_array($tun, $lines)) { - 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); + /* kill running server */ + ovpn_server_kill($tun); + + /* remove old certs & keys */ + ovpn_server_certs_del($tun); + + /* define configuration options */ + ovpn_srv_config_generate($id); } /* Start the openvpn daemon */ - 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 "; + $ovpn_config = ""; + $ovpn_config .= << $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,6 +521,241 @@ 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; + + if (is_array($config['ovpn']['server']['ccd'])) { + foreach ($config['ovpn']['server']['ccd'] as $id => $server) { + /* define configuration options */ + ovpn_server_ccd_generate($id); + } + } +} + + +/* Construct client config file */ +function ovpn_server_ccd_generate($id) { + global $config, $g; + $ovpnccd = $config['ovpn']['server']['ccd'][$id]; + + $cn = $ovpnccd['cn']; + $ccd_config = ""; + $push_options = ""; + + /* Push reset */ + if (!isset($ovpnccd['disable']) && isset($ovpnccd['psh_reset'])) { + $ccd_config .= "push-reset\n"; + + /* Client push - redirect gateway */ + if (isset($ovpnccd['psh_options']['redir'])) { + if (isset($ovpnccd['psh_options']['redir_loc'])) + $push_config .= "push \"redirect-gateway local\"\n"; + else + $push_config .= "push \"redirect-gateway\"\n"; + } + + /* Client push - route delay */ + if (isset($ovpnccd['psh_options']['rte_delay'])) + $push_config .= "push \"route-delay {$ovpnccd['psh_options']['rte_delay_int']}\"\n"; + + /* Client push - ping (note we set both server and client) */ + if (isset ($ovpnccd['psh_options']['ping'])){ + $ccd_config .= "ping {$server['psh_options']['ping_int']}\n "; + $push_config .= "push \"ping {$ovpnccd['psh_options']['ping_int']}\"\n"; + } + + /* Client push - ping-restart (note server uses 2 x client interval) */ + if (isset ($ovpnccd['psh_options']['pingrst'])){ + $interval = $ovpnccd['psh_options']['pingrst_int']; + $ccd_config .= "ping-restart " . ($interval * 2) . "\n"; + $push_config .= "push \"ping-restart $interval\"\n"; + } + + /* Client push - ping-exit (set on client) */ + if (isset ($ovpnccd['psh_options']['pingexit'])){ + $ccd_config .= "ping-exit {$ovpnccd['psh_options']['pingexit_int']}\n"; + $push_config .= "push \"ping-exit {$ovpnccd['psh_options']['pingexit_int']}\"\n"; + } + + /* Client push - inactive (set on client) */ + if (isset ($ovpnccd['psh_options']['inact'])){ + $ccd_config .= "inactive {$ovpnccd['psh_options']['inact_int']}\n"; + $push_config .= "push \"inactive {$ovpnccd['psh_options']['inact_int']}\"\n"; + } + + if (isset($push_config)) + $ccd_config .= $push_config; + } + + if (!isset($ovpnccd['disable']) && is_array($ovpnccd['options'])) { + foreach ($ovpnccd['options']['option'] as $option) { + $ccd_config .= "{$option}\n"; + } + } + + /* Disable client from connecting */ + if (isset($ovpnccd['disable'])) + $ccd_config = "disable\n"; + + unlink_if_exists("{$g['vardb_path']}/ccd/{$cn}"); + + if (isset($ccd_config) && isset($ovpnccd['enable'])) { + $fd = fopen("{$g['vardb_path']}/ccd/{$cn}", "w"); + if ($fd) { + fwrite($fd, $ccd_config."\n"); + fclose($fd); + } + } +} + +/* Delete client config file */ +function ovpn_server_ccd_del($cn) { + global $g; + + unlink_if_exists("{$g['vardb_path']}/ccd/{$cn}"); + return 0; +} + +/* Add CRL file */ +function ovpn_server_crl_add() { + global $config, $g, $d_ovpncrldirty_path; + + if (is_array($config['ovpn']['server']['crl'])) { + foreach ($config['ovpn']['server']['crl'] as $id => $crlent) { + /* get crl file name */ + $name = $crlent['crlname']; + + if (isset($crlent['enable'])) { + + /* add file */ + ovpn_server_crl_generate($id); + + if ($g['booting']) { + /* next crl file */ + continue; + } + + /* read dirtyfile */ + if (is_readable($d_ovpncrldirty_path)) + $lines = file($d_ovpncrldirty_path); + + /* reconfigure crl file */ + if (is_array($lines) && in_array($name, $lines)) { + + /* restart running openvpn daemon */ + foreach ($config['ovpn']['server']['tunnel'] as $id => $server) { + $tun = $server['tun_iface']; + + if ($server['enable'] && + isset($server['crlname']) && $server['crlname'] == $name) + /* kill running server */ + ovpn_server_kill($tun); + + /* Start the openvpn daemon */ + mwexec("/usr/local/sbin/openvpn {$g['varetc_path']}/ovpn_srv_{$tun}.conf"); + } + + } + + /* next crl file */ + continue; + } + + /* crl file disabled: remove file */ + ovpn_server_crl_del($name); + } + } + return 0; +} + +/* Write CRL to file */ +function ovpn_server_crl_generate($id) { + global $config, $g; + + $ovpncrl = $config['ovpn']['server']['crl'][$id]; + + $fd = fopen("{$g['vardb_path']}/{$ovpncrl['crlname']}.crl.pem", "w"); + if ($fd) { + fwrite($fd, base64_decode($ovpncrl['crl_list'])."\n"); + fclose($fd); + } +} + +/* Delete CRL file */ +function ovpn_server_crl_del($name) { + global $config, $g; + + /* have to wipe out the crl from the server config */ + foreach ($config['ovpn']['server']['tunnel'] as $id => $server) { + if (isset($server['crlname']) && $server['crlname'] == $name) { + + /* get tunnel interface */ + $tun = $server['tun_iface']; + + /* remove crl file entry */ + unset($config['ovpn']['server']['tunnel'][$id]['crlname']); + write_config(); + + /* kill running server */ + ovpn_server_kill($tun); + + /* remove old certs & keys */ + ovpn_server_certs_del($tun); + + /* reconfigure daemon */ + ovpn_srv_config_generate($id); + + /* Start the openvpn daemon */ + mwexec("/usr/local/sbin/openvpn {$g['varetc_path']}/ovpn_srv_{$tun}.conf"); + } + } + + unlink_if_exists("{$g['vardb_path']}/{$name}.crl.pem"); + return 0; +} + + +/* Get a list of crl files */ +function ovpn_get_crl_list() { + global $config; + + $crl_list = array(); + + if (is_array($config['ovpn']['server']['crl'])) { + foreach ($config['ovpn']['server']['crl'] as $crlent) { + if (isset($crlent['enable'])) + $crl_list[] = $crlent['crlname']; + } + } + return $crl_list; +} + +/* append interface to $_ovpnsrvdirty_path */ +function ovpn_srv_dirty($tun) { + global $d_ovpnsrvdirty_path; + + $fd = fopen($d_ovpnsrvdirty_path, 'a'); + if ($fd) { + fwrite($fd, $tun); + 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); + } } @@ -435,146 +763,97 @@ function ovpn_server_iface_del($tun) { /* Client related functions */ /****************************/ -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; - } - } - 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; - } - } - if (!$hit) - if (!ovpn_port_inuse_server($port)) - return $port; - $port++; - } - return false; /* should never get here */ -} - -/* Port in use */ -function ovpn_port_inuse_client($port){ - global $config; - $a_client = $config['ovpn']['client']['tunnel']; - foreach ($a_client as $client) { - if ($client['port'] == $port) { - return true; - } - } - return false; -} - 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"); + /* 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"); - /* 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)); - - 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 "; - } - - /* 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"; + /* Copy the TLS-Client certs & keys to disk */ + if ($client['authentication_method'] != "pre_shared_key" ) { - $fd = fopen("{$g['varetc_path']}/ovpn_cli_up_{$tun}.sh", "w"); + $fd = fopen("{$g['vardb_path']}/ovpn_cli_ca_cert_{$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['ca_cert'])."\n"); + fclose($fd); + } + + $fd = fopen("{$g['vardb_path']}/ovpn_cli_cert_{$tun}.pem", "w"); + if ($fd) { + fwrite($fd, base64_decode($client['cli_cert'])."\n"); + fclose($fd); + } + + touch ("{$g['vardb_path']}/ovpn_cli_key_{$tun}.pem"); + chmod ("{$g['vardb_path']}/ovpn_cli_key_{$tun}.pem", 0600); + $fd = fopen("{$g['vardb_path']}/ovpn_cli_key_{$tun}.pem", "w"); + if ($fd) { + fwrite($fd, base64_decode($client['cli_key'])."\n"); + fclose($fd); } } + if ($client['authentication_method'] == "pre_shared_key" || isset($client['tlsauth'])) { + touch ("{$g['vardb_path']}/ovpn_cli_psk_{$tun}.pem"); + chmod ("{$g['vardb_path']}/ovpn_cli_psk_{$tun}.pem", 0600); + $fd = fopen("{$g['vardb_path']}/ovpn_cli_psk_{$tun}.pem", "w"); + if ($fd) { + fwrite($fd, base64_decode($client['pre-shared-key'])."\n"); + fclose($fd); + } + } + + $fd = fopen("{$g['varetc_path']}/ovpn_cli_{$tun}.conf", "w"); + if (!$fd) { + printf("Error: cannot open ovpn_cli_{$tun}.conf in ovpn_cli_config_generate($id).\n"); + return 1; + } + + /* Client support in 2.0 is very simple */ + $ovpn_config = ""; + $ovpn_config .= << $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 3388536d3d..0f7175eed4 100755 --- a/usr/local/www/vpn_openvpn.php +++ b/usr/local/www/vpn_openvpn.php @@ -149,8 +149,8 @@ include("head.inc"); ?> - +

diff --git a/usr/local/www/vpn_openvpn_ccd.php b/usr/local/www/vpn_openvpn_ccd.php new file mode 100755 index 0000000000..8bf448e79c --- /dev/null +++ b/usr/local/www/vpn_openvpn_ccd.php @@ -0,0 +1,192 @@ +#!/usr/local/bin/php + $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"); + +?> + + + + +
+

+You must apply the changes in order for them to take effect.");?>
+

+ + + + + + + +
+ +
+ WARNING: This feature is experimental and modifies your optional interface configuration. + Backup your configuration before using OpenVPN, and restore it before upgrading.

+
+ + + + + + + + "; + $spane = ""; + $iconfn .= "_d"; + } else { + $spans = $spane = ""; + } + ?> + + + + + + + + + + + + +
 Common NameDescription
+ + + + +   + +  
 
+ + + + + + + + + + + + + + + + + + +
passblock
pass (disabled)block (disabled)
+
+
+ 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 0000000000..850bc8069d --- /dev/null +++ b/usr/local/www/vpn_openvpn_ccd_edit.php @@ -0,0 +1,420 @@ +#!/usr/local/bin/php + + + + +
+WARNING: This feature is experimental and modifies your optional interface configuration. + Backup your configuration before using OpenVPN, and restore it before upgrading.
 
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Disabled + > + Disable this entry
+ Set this option to disable this client-specific configuration + without removing it from the list.
Common Name + +
Enter client's X.509 common name here.
Description + +
You may enter a description here for your reference (not parsed).
Block client + > + Disable this client from connecting
+ 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.
Push options
Client-Push Inheritation + >Push reset +
Set this option to on, if you don't want to inherit + the global push list for this client from the server page. +
Client-push options + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
> + Redirect-gateway > + Local
> Route-delay  seconds
> + Inactive  + seconds
> Ping Interval: seconds
> Ping-exit Interval: seconds
> Ping-restart Interval: seconds
Custom client options + The following options are legal in a client-specific context:
+ push, push-reset, iroute, ifconfig-push and config.

+ + Note:
+ Commands in here aren't supported. +
  + + + + +
+
+ + diff --git a/usr/local/www/vpn_openvpn_cli.php b/usr/local/www/vpn_openvpn_cli.php index e7cc879ad9..fe01ee0ae2 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"); ?> - -

@@ -97,30 +98,27 @@ include("head.inc"); - @@ -199,27 +445,6 @@ if (isset($_POST['pull'])) { - - - - - - - - - - - - - - @@ -229,6 +454,13 @@ if (isset($_POST['pull'])) { Enter the server's IP address or FQDN. + + + + + - - - - - - - - - - - + - + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + Client-pull - - - - + + + + + + + - -
- +
-
- - -
+ WARNING: This feature is experimental and modifies your optional interface configuration. Backup your configuration before using OpenVPN, and restore it before upgrading.
 
+ - + - - + + @@ -135,13 +133,16 @@ include("head.inc"); - + - +
InterfaceProtocolProtocol Socket Server addressVersionDescriptionVersionDescription
- + + - + @@ -152,16 +153,15 @@ include("head.inc");   -   +  
 
-
diff --git a/usr/local/www/vpn_openvpn_cli_edit.php b/usr/local/www/vpn_openvpn_cli_edit.php index c4136e434f..1f4fca3c51 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"); + ?> + + + @@ -186,7 +432,7 @@ if (isset($_POST['pull'])) {
Disabled - > + > Disable this client
Set this option to disable this client without removing it from the list.
Server information
Tunnel type - > TUN  -> TAP
Tunnel protocol -> UDP  -> TCP
- Important: These settings must match the server's configuration.
Port -
- Enter the server's port number (default is 1194).
Address
Port +
+ Enter the server's port number (default is 1194).
Version @@ -249,24 +481,21 @@ if (isset($_POST['pull'])) {
Client configuration
Interface - Auto -
Port - Auto - Cryptographic options
Authentication method +
Must match the setting chosen on the remote side.
CA certificate @@ -309,24 +538,165 @@ if (isset($_POST['pull'])) { Select the data channel encryption cipher. This must match the setting on the server.
nsCertType + > + nsCertType
+ 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. +
TLS auth + > + TLS auth
+ The tls-auth directive adds an additional HMAC signature to all SSL/TLS handshake packets for integrity verification.
Pre-shared secret + +
+ Paste your own pre-shared secret here.
Client configuration
Tunnel type + > TUN  + > TAP
Tunnel protocol +> UDP  +> TCP
+ Important: These settings must match the server's configuration.
Interface + Auto +
Port + Auto +
Bridge with +
Only supported with authentication method set to RSA signature. +
OpenVPN address assignment + 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.
+
+ + + + + + + + + +
Local IP address:   + / + +
Remote IP address:   +
+
Client Options
OptionsOptions > - Client-pull
  - + +
Expert mode + > + Enable expert OpenVPN mode
+ If this option is on, you can specify your own extra commands for the OpenVPN server.
+ + Note:
+ Commands in expert mode aren't supported. +
  + -
+ + +
- + diff --git a/usr/local/www/vpn_openvpn_crl.php b/usr/local/www/vpn_openvpn_crl.php new file mode 100755 index 0000000000..cfafe89a49 --- /dev/null +++ b/usr/local/www/vpn_openvpn_crl.php @@ -0,0 +1,159 @@ +#!/usr/local/bin/php + + + + + +
+

+You must apply the changes in order for them to take effect.");?>
+

+ + + + + + + +
+ +
+ WARNING: This feature is experimental and modifies your optional interface configuration. + Backup your configuration before using OpenVPN, and restore it before upgrading.
+  
+
+ + + + + + + "; + $spane = ""; + } else { + $spans = $spane = ""; + } + ?> + + + + + + + + + + + +
CRL nameDescription
+ + +   + +  
 

+ + Note:
+ A CRL (certificate revocation list) is used when a particular + key is compromised but when the overall PKI is still intact.
+
+ 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.
+
+ 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. +
+
+
+ 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 0000000000..7b5d463c1d --- /dev/null +++ b/usr/local/www/vpn_openvpn_crl_edit.php @@ -0,0 +1,241 @@ +#!/usr/local/bin/php + + + + + + +
+WARNING: This feature is experimental and modifies your optional interface configuration. + Backup your configuration before using OpenVPN, and restore it before upgrading.
 
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Disabled + > + Disable this X.509 CRL list
+ Set this option to on to disable this X.509 CRL file + without removing it from the list.
Name + +
Enter a unique name here, to describe the X.509 CRL list.
Description + +
You may enter a description here for your reference (not parsed).
X.509 CRL file content + +
+ Paste the contents of a X.509 CRL file in PEM format here.
X.509 CRL file +
+ 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. +
  + + + + +
+
+ + diff --git a/usr/local/www/vpn_openvpn_srv.php b/usr/local/www/vpn_openvpn_srv.php new file mode 100755 index 0000000000..5cd6ff13ef --- /dev/null +++ b/usr/local/www/vpn_openvpn_srv.php @@ -0,0 +1,187 @@ +#!/usr/local/bin/php + + + + + +
+

+You must apply the changes in order for them to take effect.");?>
+

+ + + + + + + +
+ +
+ WARNING: This feature is experimental and modifies your optional interface configuration. + Backup your configuration before using OpenVPN, and restore it before upgrading.

+
+ + + + + + + + + + + + "; + $spane = ""; + } else { + $spans = $spane = ""; + } + + if ($server['bind_iface'] == 'all') + $ipaddr = "0.0.0.0"; + else + $ipaddr = ovpn_get_ip($server['bind_iface']); + ?> + + + + + + + + + + + + + + + +
InterfaceProtocolSocketIP BlockCryptoDescription
+ + + + + + + + + + + + +   + +  
 
+
+
+ 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 0000000000..e2ac9f1995 --- /dev/null +++ b/usr/local/www/vpn_openvpn_srv_edit.php @@ -0,0 +1,1167 @@ +#!/usr/local/bin/php + 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"); + +?> + + + + +
+WARNING: This feature is experimental and modifies your optional interface configuration. + Backup your configuration before using OpenVPN, and restore it before upgrading.
 
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Disabled + > + Disable this server
+ Set this option to disable this server without removing it from the list. +
OpenVPN protocol/port + > + UDP  + > + TCP

+ Port: +
+ Enter the port number to use for the server (default is 1194).
Interface binding + +
+ Choose an interface for the OpenVPN server to listen on.
Dynamic IP address + > + Dynamic IP address
+ Set this option to on, if your IP addresses are being assigned dynamically. Can only be used with interface binding set to ALL.
Description + +
You may enter a description here for your reference (not parsed).
Cryptographic options
Authentication method +
Must match the setting chosen on the remote side.
CA certificate + +
+ Paste a CA certificate in X.509 PEM format here.
Server certificate + +
+ Paste a server certificate in X.509 PEM format here.
Server key + +
Paste the server RSA private key here.
DH parameters + +
+ Paste the Diffie-Hellman parameters in PEM format here.
Crypto + +
+ Select a data channel encryption cipher.
TLS auth + onclick="tls_change(false)"> + TLS auth
+ The tls-auth directive adds an additional HMAC signature to all SSL/TLS handshake packets for integrity verification.
Pre-shared secret + +
+ Paste your own pre-shared secret here.
CRL + +
+ You can choose a CRL (certificate revocation list) file in PEM format here. + Each peer certificate is checked against this file.
IP configuration
Tunnel type + > + TUN  + > + TAP +
Bridge with +
Only supported with authentication method set to RSA signature. +
OpenVPN address assignment + + + + + + + + + + + + + + + + + + +
> + Managed by OpenVPN +
> + Configure manually or by DHCP Server +
> + Static assignment +
  
Maximum number of simultaneous clients:  
(leave blank to disable)
+ +
+
+ When using OpenVPN for address assignment, set aside a pool of subnets to be + dynamically allocated to connecting clients, similar to a DHCP server.
+
+ For tun-style tunnels, each client will be given a /30 subnet + (for interoperability with Windows clients).
+ For tap-style tunnels, individual addresses will be allocated, and the optional + netmask parameter will also be pushed to clients.
+
+ + + + + + +
IP address block:   + / + +
+
+ For bridges interfaces OpenVPN will allocate + an IP range in the bridged subnet to connecting clients.

+ 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.
+
+ + + + + + + + + + + +
Range:   +  to  +
Gateway:   +
+
  + 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.
+
+ + + + + + + + + + +
Local IP address:   + / + +
Remote IP address:   +
+
Server Options
Internal routing mode + > + Enable client-to-client routing
+ If this option is on, clients are allowed to talk to each other.
Client authentication + > + Permit duplicate client certificates
+ If this option is on, clients with duplicate certificates will not be disconnected.
Client-push options + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
> + Redirect-gateway > + Local
> Route-delay  seconds
> + Inactive  + seconds
> Ping Interval: seconds
> Ping-exit Interval: seconds
> Ping-restart Interval: seconds
Expert mode + > + Enable expert OpenVPN mode
+ If this option is on, you can specify your own extra commands for the OpenVPN server.
+ + Note:
+ Commands in expert mode aren't supported. +
  + + + + + +
+
+ +