%PDF- %PDF-
Direktori : /backups/router/usr/local/www/ |
Current File : //backups/router/usr/local/www/vpn_openvpn_server.php |
<?php /* * Copyright (C) 2014-2022 Deciso B.V. * Copyright (C) 2008 Shrew Soft Inc. <mgrooms@shrew.net> * 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_once("guiconfig.inc"); require_once("interfaces.inc"); require_once("plugins.inc.d/openvpn.inc"); $a_server = &config_read_array('openvpn', 'openvpn-server'); $act = null; if ($_SERVER['REQUEST_METHOD'] === 'GET') { // fetch id if provided if (isset($_GET['dup']) && isset($a_server[$_GET['dup']])) { $configId = $_GET['dup']; } elseif (isset($_GET['id']) && is_numericint($_GET['id'])) { $id = $_GET['id']; $configId = $id; } if (isset($_GET['act'])) { $act = $_GET['act']; } $pconfig = array(); // defaults $vpnid = 0; $pconfig['verbosity_level'] = 1; $pconfig['digest'] = "SHA1"; // OpenVPN Defaults to SHA1 if unset $pconfig['crypto'] = ""; $pconfig['tlsmode'] = "auth"; $pconfig['autokey_enable'] = "yes"; $pconfig['autotls_enable'] = "yes"; if (isset($configId) && isset($a_server[$configId])) { if ($a_server[$configId]['mode'] != "p2p_shared_key") { $pconfig['cert_depth'] = 1; } // 1 on 1 copy of config attributes $copy_fields = "mode,protocol,authmode,dev_mode,interface,local_port ,description,custom_options,crypto,tunnel_network ,tunnel_networkv6,remote_network,remote_networkv6,gwredir,local_network ,local_networkv6,maxclients,compression,passtos,client2client ,dynamic_ip,topology_subnet,serverbridge_dhcp ,serverbridge_interface,serverbridge_dhcp_start,serverbridge_dhcp_end ,dns_server1,dns_server2,dns_server3,dns_server4,ntp_server1 ,ntp_server2,netbios_enable,netbios_ntype,netbios_scope,wins_server1 ,wins_server2,push_register_dns,push_block_outside_dns,dns_domain,dns_domain_search,local_group ,client_mgmt_port,verbosity_level,tlsmode,caref,crlref,certref ,cert_depth,strictusercn,digest,disable,duplicate_cn,vpnid,reneg-sec,use-common-name,cso_login_matching"; foreach (explode(",", $copy_fields) as $fieldname) { $fieldname = trim($fieldname); if (isset($a_server[$configId][$fieldname])) { $pconfig[$fieldname] = $a_server[$configId][$fieldname]; } elseif (!isset($pconfig[$fieldname])) { // initialize element $pconfig[$fieldname] = null; } } // load / convert if (!empty($a_server[$configId]['ipaddr'])) { $pconfig['interface'] = $pconfig['interface'] . '|' . $a_server[$configId]['ipaddr']; } if (!empty($a_server[$configId]['shared_key'])) { $pconfig['shared_key'] = base64_decode($a_server[$configId]['shared_key']); } else { $pconfig['shared_key'] = null; } if (!empty($a_server[$configId]['tls'])) { $pconfig['tls'] = base64_decode($a_server[$configId]['tls']); } else { $pconfig['tls'] = null; $pconfig['tlsmode'] = null; } } elseif ($act == "new") { $pconfig['dev_mode'] = "tun"; $pconfig['interface'] = 'any'; $pconfig['protocol'] = 'UDP'; $pconfig['local_port'] = openvpn_port_next($pconfig['protocol']); $pconfig['cert_depth'] = 1; // init all fields used in the form $init_fields = "mode,protocol,authmode,dev_mode,interface,local_port ,description,custom_options,crypto,tunnel_network ,tunnel_networkv6,remote_network,remote_networkv6,gwredir,local_network ,local_networkv6,maxclients,compression,passtos,client2client ,dynamic_ip,topology_subnet,serverbridge_dhcp ,serverbridge_interface,serverbridge_dhcp_start,serverbridge_dhcp_end ,dns_server1,dns_server2,dns_server3,dns_server4,ntp_server1 ,ntp_server2,netbios_enable,netbios_ntype,netbios_scope,wins_server1 ,wins_server2,push_register_dns,push_block_outside_dns,dns_domain,dns_domain_search ,client_mgmt_port,verbosity_level,tlsmode,caref,crlref,certref ,cert_depth,strictusercn,digest,disable,duplicate_cn,vpnid,shared_key,tls,reneg-sec,use-common-name ,cso_login_matching"; foreach (explode(",", $init_fields) as $fieldname) { $fieldname = trim($fieldname); if (!isset($pconfig[$fieldname])) { $pconfig[$fieldname] = null; } } } } elseif ($_SERVER['REQUEST_METHOD'] === 'POST') { if (isset($_POST['id']) && isset($a_server[$_POST['id']])) { $id = $_POST['id']; } if (isset($_POST['act'])) { $act = $_POST['act']; } if ($act == "del") { // action delete $vpn_id = !empty($a_server[$id]) ? $a_server[$id]['vpnid'] : null; if ($vpn_id !== null && is_interface_assigned("ovpns{$vpn_id}")) { $response = [ "status" => "failed", "message" => gettext("This tunnel cannot be deleted because it is still being used as an interface.") ]; } elseif ($vpn_id !== null) { openvpn_delete('server', $a_server[$id]); unset($a_server[$id]); write_config(); $response = ["status" => "ok"]; } echo json_encode($response); exit; } elseif ($act == "toggle") { if (isset($id)) { if (isset($a_server[$id]['disable'])) { unset($a_server[$id]['disable']); } else { $a_server[$id]['disable'] = true; } write_config(); openvpn_configure_single($a_server[$id]['vpnid']); } header(url_safe('Location: /vpn_openvpn_server.php')); exit; } else { // action add/update $input_errors = array(); $pconfig = $_POST; $vpnid = (isset($id) && $a_server[$id]) ? $a_server[$id]['vpnid'] : 0; $tls_mode = ($pconfig['mode'] != "p2p_shared_key"); if (!empty($pconfig['autokey_enable'])) { $pconfig['shared_key'] = openvpn_create_key(); } // all input validators if (strpos($pconfig['interface'], '|') !== false) { list($iv_iface, $iv_ip) = explode("|", $pconfig['interface']); } else { $iv_iface = $pconfig['interface']; $iv_ip = null; } if (is_ipaddrv4($iv_ip) && (stristr($pconfig['protocol'], "6") !== false)) { $input_errors[] = gettext("Protocol and IP address families do not match. You cannot select an IPv6 protocol and an IPv4 IP address."); } elseif (is_ipaddrv6($iv_ip) && (stristr($pconfig['protocol'], "6") === false)) { $input_errors[] = gettext("Protocol and IP address families do not match. You cannot select an IPv4 protocol and an IPv6 IP address."); } elseif ((stristr($pconfig['protocol'], "6") === false) && !get_interface_ip($iv_iface) && ($pconfig['interface'] != "any")) { $input_errors[] = gettext("An IPv4 protocol was selected, but the selected interface has no IPv4 address."); } elseif ((stristr($pconfig['protocol'], "6") !== false) && !get_interface_ipv6($iv_iface) && ($pconfig['interface'] != "any")) { $input_errors[] = gettext("An IPv6 protocol was selected, but the selected interface has no IPv6 address."); } if (empty($pconfig['authmode']) && (($pconfig['mode'] == "server_user") || ($pconfig['mode'] == "server_tls_user"))) { $input_errors[] = gettext("You must select a Backend for Authentication if the server mode requires User Auth."); } if ($result = openvpn_validate_port($pconfig['local_port'], gettext('Local port'))) { $input_errors[] = $result; } if ($result = openvpn_validate_cidr($pconfig['tunnel_network'], gettext('IPv4 Tunnel Network'), false, 'ipv4')) { $input_errors[] = $result; } elseif (!empty($pconfig['tunnel_network']) && (strpos($pconfig['mode'], "p2p_") === false)) { // Check IPv4 tunnel_network pool size for Remote Access modes list($ipv4tunnel_base, $ipv4tunnel_prefix) = explode('/',trim($pconfig['tunnel_network'])); if ($pconfig['dev_mode'] == "tun") { if ($ipv4tunnel_prefix > 28 && empty($pconfig['topology_subnet'])) { $input_errors[] = gettext('A prefix longer than 28 cannot be used with a net30 topology.'); } elseif ($ipv4tunnel_prefix > 29 && !empty($pconfig['topology_subnet'])) { $input_errors[] = gettext('A prefix longer than 29 cannot be used for tunnel network.'); } } elseif ($pconfig['dev_mode'] == "tap" && $ipv4tunnel_prefix > 29) { $input_errors[] = gettext('A prefix longer than 29 cannot be used for tunnel network.'); } } if ($result = openvpn_validate_cidr($pconfig['tunnel_networkv6'], gettext('IPv6 Tunnel Network'), false, 'ipv6')) { $input_errors[] = $result; } if ($result = openvpn_validate_cidr($pconfig['remote_network'], gettext('IPv4 Remote Network'), true, 'ipv4')) { $input_errors[] = $result; } if ($result = openvpn_validate_cidr($pconfig['remote_networkv6'], gettext('IPv6 Remote Network'), true, 'ipv6')) { $input_errors[] = $result; } if ($result = openvpn_validate_cidr($pconfig['local_network'], gettext('IPv4 Local Network'), true, 'ipv4')) { $input_errors[] = $result; } if ($result = openvpn_validate_cidr($pconfig['local_networkv6'], gettext('IPv6 Local Network'), true, 'ipv6')) { $input_errors[] = $result; } if (!empty($pconfig['local_port'])) { $portused = openvpn_port_used($pconfig['protocol'], $pconfig['interface'], $pconfig['local_port'], $vpnid); if ($portused) { $input_errors[] = gettext("The specified 'Local port' is in use. Please select another value"); } } if (!$tls_mode && empty($pconfig['autokey_enable'])) { if (!strstr($pconfig['shared_key'], "-----BEGIN OpenVPN Static key V1-----") || !strstr($pconfig['shared_key'], "-----END OpenVPN Static key V1-----")) { $input_errors[] = gettext("The field 'Shared Key' does not appear to be valid"); } } if ($tls_mode && !empty($pconfig['tlsmode']) && empty($pconfig['autotls_enable'])) { if (!strstr($pconfig['tls'], "-----BEGIN OpenVPN Static key V1-----") || !strstr($pconfig['tls'], "-----END OpenVPN Static key V1-----")) { $input_errors[] = gettext("The field 'TLS Shared Key' does not appear to be valid"); } } if (!empty($pconfig['dns_domain_search'])) { $tmp_ok_domain = 0; $tmp_nok_domain = 0; foreach (explode(",", $pconfig['dns_domain_search'] ?? "") as $domain) { if (is_domain($domain)) { $tmp_ok_domain++; } else { $tmp_nok_domain++; } } if ($tmp_nok_domain > 0) { $input_errors[] = gettext("The field 'DNS Domain search list' must contain valid domain names"); } elseif ($tmp_ok_domain > 10) { $input_errors[] = gettext("The field 'DNS Domain search list' may contain max 10 entries"); } } if (!empty($pconfig['dns_server1']) && !is_ipaddr(trim($pconfig['dns_server1']))) { $input_errors[] = gettext("The field 'DNS Server #1' must contain a valid IP address"); } if (!empty($pconfig['dns_server2']) && !is_ipaddr(trim($pconfig['dns_server2']))) { $input_errors[] = gettext("The field 'DNS Server #2' must contain a valid IP address"); } if (!empty($pconfig['dns_server3']) && !is_ipaddr(trim($pconfig['dns_server3']))) { $input_errors[] = gettext("The field 'DNS Server #3' must contain a valid IP address"); } if (!empty($pconfig['dns_server4']) && !is_ipaddr(trim($pconfig['dns_server4']))) { $input_errors[] = gettext("The field 'DNS Server #4' must contain a valid IP address"); } if (!empty($pconfig['ntp_server1']) && !is_ipaddr(trim($pconfig['ntp_server1']))) { $input_errors[] = gettext("The field 'NTP Server #1' must contain a valid IP address"); } if (!empty($pconfig['ntp_server2']) && !is_ipaddr(trim($pconfig['ntp_server2']))) { $input_errors[] = gettext("The field 'NTP Server #2' must contain a valid IP address"); } if (!empty($pconfig['wins_server_enable'])) { if (!empty($pconfig['wins_server1']) && !is_ipaddr(trim($pconfig['wins_server1']))) { $input_errors[] = gettext("The field 'WINS Server #1' must contain a valid IP address"); } if (!empty($pconfig['wins_server2']) && !is_ipaddr(trim($pconfig['wins_server2']))) { $input_errors[] = gettext("The field 'WINS Server #2' must contain a valid IP address"); } } if (!empty($pconfig['client_mgmt_port_enable'])) { if ($result = openvpn_validate_port($pconfig['client_mgmt_port'], gettext('Client management port'))) { $input_errors[] = $result; } } if (!empty($pconfig['maxclients']) && !is_numeric($pconfig['maxclients'])) { $input_errors[] = gettext("The field 'Concurrent connections' must be numeric."); } /* If we are not in shared key mode, then we need the CA/Cert. */ if (isset($pconfig['mode']) && $pconfig['mode'] != "p2p_shared_key") { $reqdfields = explode(" ", "caref certref"); $reqdfieldsn = array(gettext("Certificate Authority"),gettext("Certificate")); } elseif (empty($pconfig['autokey_enable'])) { /* We only need the shared key filled in if we are in shared key mode and autokey is not selected. */ $reqdfields = array('shared_key'); $reqdfieldsn = array(gettext('Shared key')); } $reqdfields[] = 'local_port'; $reqdfieldsn[] = gettext('Local port'); if ($pconfig['dev_mode'] != "tap") { $reqdfields[] = 'tunnel_network,tunnel_networkv6'; $reqdfieldsn[] = gettext('Tunnel Network'); } else { if ($pconfig['serverbridge_dhcp'] && ($pconfig['tunnel_network'] || $pconfig['tunnel_networkv6'])) { $input_errors[] = gettext("Using a tunnel network and server bridge settings together is not allowed."); } if (($pconfig['serverbridge_dhcp_start'] && !$pconfig['serverbridge_dhcp_end']) || (!$pconfig['serverbridge_dhcp_start'] && $pconfig['serverbridge_dhcp_end'])) { $input_errors[] = gettext("Server Bridge DHCP Start and End must both be empty, or defined."); } if (($pconfig['serverbridge_dhcp_start'] && !is_ipaddrv4($pconfig['serverbridge_dhcp_start']))) { $input_errors[] = gettext("Server Bridge DHCP Start must be an IPv4 address."); } if (($pconfig['serverbridge_dhcp_end'] && !is_ipaddrv4($pconfig['serverbridge_dhcp_end']))) { $input_errors[] = gettext("Server Bridge DHCP End must be an IPv4 address."); } if (ip2ulong($pconfig['serverbridge_dhcp_start']) > ip2ulong($pconfig['serverbridge_dhcp_end'])) { $input_errors[] = gettext("The Server Bridge DHCP range is invalid (start higher than end)."); } } if (isset($pconfig['reneg-sec']) && $pconfig['reneg-sec'] != "" && (string)((int)$pconfig['reneg-sec']) != $pconfig['reneg-sec']) { $input_errors[] = gettext("Renegotiate time should contain a valid number of seconds."); } if (!empty($pconfig['certref'])) { foreach ($config['cert'] as $cert) { if ($cert['refid'] == $pconfig['certref']) { if (cert_get_purpose($cert['crt'])['id-kp-serverAuth'] == 'No') { $input_errors[] = gettext( sprintf('Certificate %s is not intended for server use.', $cert['descr']) ); } } } } $prev_opt = (isset($id) && !empty($a_server[$id])) ? $a_server[$id]['custom_options'] : ""; if ($prev_opt != str_replace("\r\n", "\n", $pconfig['custom_options']) && !userIsAdmin($_SESSION['Username'])) { $input_errors[] = gettext('Advanced options may only be edited by system administrators due to the increased possibility of privilege escalation.'); } do_input_validation($pconfig, $reqdfields, $reqdfieldsn, $input_errors); if (count($input_errors) == 0) { // validation correct, save data $server = array(); // delete(rename) old interface so a new TUN or TAP interface can be created. if (isset($id) && $pconfig['dev_mode'] != $a_server[$id]['dev_mode']) { openvpn_delete('server', $a_server[$id]); } // 1 on 1 copy of config attributes $copy_fields = "mode,protocol,dev_mode,local_port,description,crypto,digest ,tunnel_network,tunnel_networkv6,remote_network,remote_networkv6 ,gwredir,local_network,local_networkv6,maxclients,compression ,passtos,client2client,dynamic_ip,topology_subnet,local_group ,serverbridge_dhcp,serverbridge_interface,serverbridge_dhcp_start ,serverbridge_dhcp_end,dns_domain,dns_domain_search,dns_server1,dns_server2,dns_server3 ,dns_server4,push_register_dns,push_block_outside_dns,ntp_server1,ntp_server2,netbios_enable ,netbios_ntype,netbios_scope,verbosity_level,wins_server1,tlsmode ,wins_server2,client_mgmt_port,strictusercn,reneg-sec,use-common-name,cso_login_matching"; foreach (explode(",", $copy_fields) as $fieldname) { $fieldname = trim($fieldname); if (!empty($pconfig[$fieldname]) || $pconfig[$fieldname] == '0') { $server[$fieldname] = $pconfig[$fieldname]; } } // attributes containing some kind of logic if ($vpnid != 0) { $server['vpnid'] = $vpnid; } else { $server['vpnid'] = openvpn_vpnid_next(); } if ($pconfig['disable'] == "yes") { $server['disable'] = true; } if (!empty($pconfig['authmode'])) { $server['authmode'] = implode(",", $pconfig['authmode']); } if (strpos($pconfig['interface'], "|") !== false) { list($server['interface'], $server['ipaddr']) = explode("|", $pconfig['interface']); } else { $server['interface'] = $pconfig['interface']; } $server['custom_options'] = str_replace("\r\n", "\n", $pconfig['custom_options']); if ($tls_mode) { if ($pconfig['tlsmode']) { if (!empty($pconfig['autotls_enable'])) { $pconfig['tls'] = openvpn_create_key(); } $server['tls'] = base64_encode($pconfig['tls']); } foreach (['caref', 'crlref', 'certref', 'cert_depth'] as $cpKey) { if (isset($pconfig[$cpKey])) { $server[$cpKey] = $pconfig[$cpKey]; } } if (isset($pconfig['mode']) && $pconfig['mode'] == "server_tls_user" && isset($server['strictusercn'])) { $server['strictusercn'] = $pconfig['strictusercn']; } } else { $server['shared_key'] = base64_encode($pconfig['shared_key']); } if (isset($_POST['duplicate_cn']) && $_POST['duplicate_cn'] == "yes") { $server['duplicate_cn'] = true; } // update or add to config if (isset($id) && $a_server[$id]) { $a_server[$id] = $server; } else { $a_server[] = $server; } write_config(); openvpn_configure_single($server['vpnid']); header(url_safe('Location: /vpn_openvpn_server.php')); exit; } elseif (!empty($pconfig['authmode'])) { $pconfig['authmode'] = implode(",", $pconfig['authmode']); } } } include("head.inc"); legacy_html_escape_form_data($pconfig); ?> <body> <?php include("fbegin.inc"); ?> <script> $( document ).ready(function() { // watch scroll position and set to last known on page load watchScrollPosition(); // link delete buttons $(".act_delete").click(function(){ var id = $(this).attr("id").split('_').pop(-1); BootstrapDialog.show({ type:BootstrapDialog.TYPE_DANGER, title: "<?= gettext("OpenVPN");?>", message: "<?= gettext("Do you really want to delete this server?"); ?>", buttons: [{ label: "<?= gettext("No");?>", action: function(dialogRef) { dialogRef.close(); }}, { label: "<?= gettext("Yes");?>", action: function(dialogRef) { $.post(window.location, {act: 'del', id:id}, function(data) { if (data.status == 'failed' && data.message !== undefined) { dialogRef.close(); BootstrapDialog.show({ type:BootstrapDialog.TYPE_DANGER, title: "<?= gettext("OpenVPN");?>", message: data.message, buttons: [ { label: "<?= gettext("Close");?>", action: function(dialogRef) { dialogRef.close(); } } ] }); return; } else { location.reload(); } }, 'json'); dialogRef.close(); } }] }); }); // link toggle buttons $(".act_toggle").click(function(event){ event.preventDefault(); $.post(window.location, {act: 'toggle', id:$(this).data("id")}, function(data) { location.reload(); }); }); // input form events if ($("#iform").length) { $("#mode,#gwredir").change(function(){ $(".opt_mode").hide(); $(".opt_mode :input").prop( "disabled", true ); $(".opt_mode_"+$("#mode").val()).show(); $(".opt_mode_"+$("#mode").val()+" :input").prop( "disabled", false ); if ($("#gwredir").is(":checked")) { $(".opt_gwredir").hide(); } $("#dev_mode").change(); $('.selectpicker').selectpicker('refresh'); $(window).resize(); }); $("#mode").change(); $("#dev_mode,#serverbridge_dhcp").change(function(){ $(".dev_mode").hide(); $(".dev_mode_"+$("#dev_mode").val()).show(); if ($("#mode").val().indexOf('p2p_tls') == 0) { $("#serverbridge_dhcp").prop('disabled', true); } else { $("#serverbridge_dhcp").prop('disabled', false); } if ($("#mode").val().indexOf('p2p_tls') == 0 || $("#serverbridge_dhcp").is(':checked') == false) { $("#serverbridge_interface").prop('disabled', true); $("#serverbridge_dhcp_start").prop('disabled', true); $("#serverbridge_dhcp_end").prop('disabled', true); } else { $("#serverbridge_interface").prop('disabled', false); $("#serverbridge_dhcp_start").prop('disabled', false); $("#serverbridge_dhcp_end").prop('disabled', false); } $('.selectpicker').selectpicker('refresh'); }); $("#dev_mode").change(); $("#autokey_enable").change(function(){ if ($("#autokey_enable").is(':checked')) { $("#autokey_opts").hide(); } else { $("#autokey_opts").show(); } }); $("#autokey_enable").change(); $("#autotls_enable,#tlsmode").change(function(){ if ($("#autotls_enable").length !== 0 && $("#autotls_enable").is(":checked")) { $("#autotls_opts").hide(); } else { $("#autotls_opts").show(); } if ($("#tlsmode").val() === "") { $(".tls_input_field").prop("disabled", true); } else { $(".tls_input_field").prop("disabled", false); } }); $("#autotls_enable").change(); $("#dns_domain_enable").change(function(){ if ($("#dns_domain_enable").is(':checked')) { $("#dns_domain_data").show(); } else { $("#dns_domain_data").hide(); } }); $("#dns_domain_enable").change(); $("#dns_domain_search_enable").change(function(){ if ($("#dns_domain_search_enable").is(':checked')) { $("#dns_domain_search_data").show(); } else { $("#dns_domain_search_data").hide(); } }); $("#dns_domain_search_enable").change(); $("#dns_server_enable").change(function(){ if ($("#dns_server_enable").is(':checked')) { $("#dns_server_data").show(); } else { $("#dns_server_data").hide(); } }); $("#dns_server_enable").change(); $("#wins_server_enable").change(function(){ if ($("#wins_server_enable").is(':checked')) { $("#wins_server_data").show(); } else { $("#wins_server_data").hide(); } }); $("#wins_server_enable").change(); $("#netbios_enable").change(function(){ if ($("#netbios_enable").is(':checked')) { $("#wins_opts").show(); $("#netbios_data").show(); } else { $("#wins_opts").hide(); $("#netbios_data").hide(); } }); $("#netbios_enable").change(); $("#ntp_server_enable").change(function(){ if ($("#ntp_server_enable").is(':checked')) { $("#ntp_server_data").show(); } else { $("#ntp_server_data").hide(); } }); $("#ntp_server_enable").change(); $("#client_mgmt_port_enable").change(function(){ if ($("#client_mgmt_port_enable").is(':checked')) { $("#client_mgmt_port_data").show(); } else { $("#client_mgmt_port_data").hide(); } }); $("#client_mgmt_port_enable").change(); $(window).resize(); } }); </script> <section class="page-content-main"> <div class="container-fluid"> <div class="row"> <?php if (isset($input_errors) && count($input_errors) > 0) { print_input_errors($input_errors); } if (isset($savemsg)) { print_info_box($savemsg); }?> <?php if ($act=="new" || $act=="edit") :?> <form method="post" name="iform" id="iform"> <section class="col-xs-12"> <div class="tab-content content-box col-xs-12"> <div class="table-responsive"> <table class="table table-striped opnsense_standard_table_form"> <tr> <td style="width:22%"><strong><?=gettext("General information"); ?></strong></td> <td style="width:78%; text-align:right"> <small><?=gettext("full help"); ?> </small> <i class="fa fa-toggle-off text-danger" style="cursor: pointer;" id="show_all_help_page"></i> </td> </tr> <tr> <td> <a id="help_for_disable" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Disabled"); ?> </td> <td> <div> <input name="disable" type="checkbox" value="yes" <?= !empty($pconfig['disable']) ? "checked=\"checked\"" : "";?> /> </div> <div class="hidden" data-for="help_for_disable"> <?=gettext("Set this option to disable this server without removing it from the list"); ?>. </div> </td> </tr> <tr> <td style="width:22%"><a id="help_for_description" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Description"); ?></td> <td> <input name="description" type="text" class="form-control unknown" size="30" value="<?=htmlspecialchars($pconfig['description']);?>" /> <div class="hidden" data-for="help_for_description"> <?=gettext("You may enter a description here for your reference (not parsed)."); ?> </div> </td> </tr> <tr> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Server Mode");?></td> <td> <select name='mode' id="mode" class="selectpicker"> <?php $openvpn_server_modes = array( 'p2p_tls' => gettext("Peer to Peer ( SSL/TLS )"), 'p2p_shared_key' => gettext("Peer to Peer ( Shared Key )"), 'server_tls' => gettext("Remote Access ( SSL/TLS )"), 'server_user' => gettext("Remote Access ( User Auth )"), 'server_tls_user' => gettext("Remote Access ( SSL/TLS + User Auth )")); foreach ($openvpn_server_modes as $name => $desc) : $selected = ""; if ($pconfig['mode'] == $name) { $selected = "selected=\"selected\""; }?> <option value="<?=$name;?>" <?=$selected;?>><?=$desc;?></option> <?php endforeach; ?> </select> </td> </tr> <tr class="opt_mode opt_mode_server_user opt_mode_server_tls_user" style="display:none"> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Backend for authentication");?></td> <td> <select name='authmode[]' id='authmode' class="selectpicker" multiple="multiple" size="5"> <?php if (isset($pconfig['authmode'])) { $authmodes = explode(",", $pconfig['authmode']); } else { $authmodes = array(); } $auth_servers = auth_get_authserver_list(); foreach ($auth_servers as $auth_key => $auth_server) : $selected = ""; if (in_array($auth_key, $authmodes)) { $selected = "selected=\"selected\""; }?> <option value="<?=htmlspecialchars($auth_key); ?>" <?=$selected; ?>><?=htmlspecialchars($auth_server['name']);?></option> <?php endforeach; ?> </select> </td> </tr> <tr class="opt_mode opt_mode_server_user opt_mode_server_tls_user" style="display:none"> <td><a id="help_for_local_group" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?= gettext('Enforce local group') ?></td> <td> <select name='local_group' id="local_group" class="selectpicker"> <option value="" <?= empty($pconfig['local_group']) ? 'selected="selected"' : '' ?>>(<?= gettext('none') ?>)</option> <?php foreach (config_read_array('system', 'group') as $group): $selected = $pconfig['local_group'] == $group['name'] ? 'selected="selected"' : ''; ?> <option value="<?= $group['name'] ?>" <?= $selected ?>><?= $group['name'] ?></option> <?php endforeach; ?> </select> <div class="hidden" data-for="help_for_local_group"> <?= gettext('Restrict access to users in the selected local group. Please be aware ' . 'that other authentication backends will refuse to authenticate when using this option.') ?> </div> </td> </tr> <tr> <td><a id="help_for_protocol" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Protocol");?></td> <td> <select name='protocol' class="selectpicker"> <?php foreach (openvpn_get_protocols() as $prot): $selected = ""; if ($pconfig['protocol'] == $prot) { $selected = "selected=\"selected\""; }?> <option value="<?=$prot;?>" <?=$selected;?>><?=$prot;?></option> <?php endforeach; ?> </select> <div class="hidden" data-for="help_for_protocol"> <?= gettext('Select the protocol family to be used. Note that using both families with UDP/TCP ' . 'does not work with an explicit interface as OpenVPN does not support listening to more ' . 'than one specified IP address. In this case IPv4 is currently assumed.') ?> </div> </td> </tr> <tr> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Device Mode"); ?></td> <td> <select name="dev_mode" id="dev_mode" class="selectpicker"> <?php foreach (array("tun", "tap") as $device) : $selected = ""; if (! empty($pconfig['dev_mode'])) { if ($pconfig['dev_mode'] == $device) { $selected = "selected=\"selected\""; } } else { if ($device == "tun") { $selected = "selected=\"selected\""; } }?> <option value="<?=$device;?>" <?=$selected;?>><?=$device;?></option> <?php endforeach; ?> </select> </td> </tr> <tr> <td><a id="help_for_interface" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Interface"); ?></td> <td> <select name="interface" class="selectpicker" data-size="5" data-live-search="true"> <?php $interfaces = get_configured_interface_with_descr(); foreach (get_configured_carp_interface_list() as $cif => $carpip) { $interfaces[$cif.'|'.$carpip] = $carpip." (".get_vip_descr($carpip).")"; } foreach (get_configured_ip_aliases_list() as $aliasip => $aliasif) { $interfaces[$aliasif.'|'.$aliasip] = $aliasip." (".get_vip_descr($aliasip).")"; } $interfaces['lo0'] = "Localhost"; $interfaces['any'] = "any"; foreach ($interfaces as $iface => $ifacename) :?> <option value="<?=$iface; ?>"<?=$iface == $pconfig['interface'] ? ' selected="selected"' : '';?>> <?=htmlspecialchars($ifacename);?> </option> <?php endforeach; ?> </select> <div class="hidden" data-for="help_for_interface"> <?=gettext( "When selecting any in combination with UDP, we will assume the server is used multi-homed. ". "This has some small performance implications to assure proper return address lookup." ); ?> </div> </td> </tr> <tr> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Local port");?></td> <td> <input name="local_port" type="text" class="form-control unknown" size="5" value="<?=$pconfig['local_port'];?>" /> </td> </tr> </table> </div> </div> </section> <section class="col-xs-12"> <div class="tab-content content-box col-xs-12"> <div class="table-responsive"> <table class="table table-striped opnsense_standard_table_form"> <tr> <td colspan="2"><strong><?=gettext("Cryptographic Settings"); ?></strong></td> </tr> <tr class="opt_mode opt_mode_p2p_tls opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user"> <td style="width:22%"><i class="fa fa-info-circle text-muted"></i> <?=gettext("TLS Authentication"); ?></td> <td style="width:78%"> <select name='tlsmode' id='tlsmode' class="selectpicker"> <option value="" <?= empty($pconfig['tlsmode']) ? "selected=\"selected\"" : "";?>> <?=gettext("Disabled");?> </option> <option value="auth" <?= $pconfig['tlsmode'] === "auth" ? "selected=\"selected\"" : "";?>> <?=gettext("Enabled - Authentication only");?> </option> <option value="crypt" <?= $pconfig['tlsmode'] === "crypt" ? "selected=\"selected\"" : "";?>> <?=gettext("Enabled - Authentication & encryption");?> </option> </select> </td> </tr> <tr class="opt_mode opt_mode_p2p_tls opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user"> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("TLS Shared Key"); ?></td> <td> <?php if (!$pconfig['tls']) :?> <input name="autotls_enable" id="autotls_enable" class="tls_input_field" type="checkbox" value="yes" <?=!empty($pconfig['autotls_enable']) ? "checked=\"checked\"" : "" ;?> /> <?=gettext("Automatically generate a shared TLS authentication key"); ?>. <?php endif; ?> <div id="autotls_opts"> <textarea id="tls" name="tls" cols="65" rows="7" class="tls_input_field formpre"><?=$pconfig['tls'];?></textarea> <p class="text-muted"><em><small><?=gettext("Paste your shared key here"); ?>.</small></em></p> </div> </td> </tr> <tr class="opt_mode opt_mode_p2p_tls opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user"> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Peer Certificate Authority"); ?></td> <td> <?php if (isset($config['ca'])) :?> <select name='caref' class="selectpicker" data-size="5" data-live-search="true"> <?php foreach ($config['ca'] as $ca) : $selected = ""; if ($pconfig['caref'] == $ca['refid']) { $selected = "selected=\"selected\""; } ?> <option value="<?=htmlspecialchars($ca['refid']);?>" <?=$selected;?>> <?=htmlspecialchars($ca['descr']);?> </option> <?php endforeach; ?> </select> <?php else :?> <b><?=gettext("No Certificate Authorities defined.");?></b> <br /><?=gettext("Create one under")?> <a href="system_camanager.php"> <?=gettext("System: Certificates");?></a>. <?php endif; ?> </td> </tr> <tr class="opt_mode opt_mode_p2p_tls opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user"> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Peer Certificate Revocation List"); ?></td> <td> <?php if (isset($config['crl'])) :?> <select name='crlref' class="selectpicker" data-size="5" data-live-search="true"> <option value="">None</option> <?php foreach ($config['crl'] as $crl) : if (!isset($crl['refid'])) { continue; } $ca = lookup_ca($crl['caref']); if ($ca) { $selected = $pconfig['crlref'] == $crl['refid'] ? 'selected="selected"' : ''; ?> <option value="<?=htmlspecialchars($crl['refid']);?>" <?=$selected;?>><?=htmlspecialchars("{$crl['descr']} ({$ca['descr']})");?></option> <?php } endforeach; ?> </select> <?php else :?> <b><?=gettext("No Certificate Revocation Lists (CRLs) defined.");?></b> <br /><?=gettext("Create one under");?> <a href="system_crlmanager.php"><?=gettext("System: Certificates");?></a>. <?php endif; ?> </td> </tr> <tr class="opt_mode opt_mode_p2p_tls opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user"> <td><i class="fa fa-info-circle text-muted"></i> <?=gettext("Server Certificate"); ?></td> <td> <?php if (isset($config['cert'])) :?> <select name='certref' class="selectpicker" data-size="5" data-live-search="true"> <?php foreach ($config['cert'] as $cert) : $selected = ""; $caname = ""; $inuse = ""; $revoked = ""; if (!isset($cert['prv'])) { continue; } if (isset($cert['caref'])) { $ca = lookup_ca($cert['caref']); if (!empty($ca)) { $caname = " ({$ca['descr']})"; } } if ($pconfig['certref'] == $cert['refid']) { $selected = "selected=\"selected\""; } if (cert_in_use($cert['refid'])) { $inuse = " *In Use"; } if (is_cert_revoked($cert)) { $revoked = " *Revoked"; } ?> <option value="<?=htmlspecialchars($cert['refid']);?>" <?=$selected;?>> <?=htmlspecialchars($cert['descr'] . $caname . $inuse . $revoked);?> </option> <?php endforeach; ?> </select> <?php else :?> <b><?=gettext("No Certificates defined.");?></b> <br /><?=gettext("Create one under");?> <a href="system_certmanager.php"><?=gettext("System: Certificates");?></a>. <?php endif; ?> </td> </tr> <tr class="opt_mode opt_mode_p2p_shared_key"> <td style="width:22%"><i class="fa fa-info-circle text-muted"></i> <?=gettext("Shared Key"); ?></td> <td> <?php if (empty($pconfig['shared_key'])) :?> <div> <input name="autokey_enable" id="autokey_enable" type="checkbox" value="yes" <?=!empty($pconfig['autokey_enable']) ? "checked=\"checked\"" : "" ;?> /> <?=gettext("Automatically generate a shared key"); ?>. </div> <?php endif; ?> <div id="autokey_opts"> <textarea name="shared_key" cols="65" rows="7"><?=$pconfig['shared_key'];?></textarea> <?=gettext("Paste your shared key here"); ?>. </div> </td> </tr> <tr> <td><a id="help_for_crypto" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Encryption algorithm (deprecated)"); ?></td> <td> <select name="crypto" class="selectpicker"> <?php foreach (openvpn_get_cipherlist() as $name => $desc) : $selected = $name == $pconfig['crypto'] ? " selected=\"selected\"" : "";?> <option value="<?=$name;?>"<?=$selected?>> <?=htmlspecialchars($desc);?> </option> <?php endforeach; ?> </select> <div class="hidden" data-for="help_for_crypto"> <?= gettext('Cipher selection for older clients. Only preserved for backwards compatibility reasons.') ?> </div> </td> </tr> <tr> <td><a id="help_for_digest" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Auth Digest Algorithm"); ?></td> <td> <select name="digest" class="selectpicker" data-size="5" data-live-search="true"> <?php $digestlist = openvpn_get_digestlist(); foreach ($digestlist as $name => $desc) : $selected = ""; if ($name == $pconfig['digest']) { $selected = " selected=\"selected\""; } ?> <option value="<?=$name;?>"<?=$selected?>> <?=htmlspecialchars($desc);?> </option> <?php endforeach; ?> </select> <div class="hidden" data-for="help_for_digest"> <?= gettext('Leave this set to SHA1 unless all clients are set to match. SHA1 is the default for OpenVPN.') ?> </div> </td> </tr> <tr class="opt_mode opt_mode_p2p_tls opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user"> <td style="width:22%"><a id="help_for_cert_depth" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Certificate Depth"); ?></td> <td> <table> <tr><td> <select name="cert_depth" class="selectpicker"> <option value=""><?=gettext('Do Not Check') ?></option> <?php $openvpn_cert_depths = array( 1 => gettext('One (Client+Server)'), 2 => gettext('Two (Client+Intermediate+Server)'), 3 => gettext('Three (Client+2xIntermediate+Server)'), 4 => gettext('Four (Client+3xIntermediate+Server)'), 5 => gettext('Five (Client+4xIntermediate+Server)') ); foreach ($openvpn_cert_depths as $depth => $depthdesc) : $selected = ""; if ($depth == $pconfig['cert_depth']) { $selected = " selected=\"selected\""; } ?> <option value="<?= $depth ?>" <?= $selected ?>><?= $depthdesc ?></option> <?php endforeach; ?> </select> </td> </tr> <tr> <td> <div class="hidden" data-for="help_for_cert_depth"> <span> <?=gettext("When a certificate-based client logs in, do not accept certificates below this depth. Useful for denying certificates made with intermediate CAs generated from the same CA as the server."); ?> </span> </div> </td></tr> </table> </td> </tr> <tr class="opt_mode opt_mode_server_tls_user"> <td style="width:22%"><a id="help_for_strictusercn" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Strict User/CN Matching"); ?></td> <td> <input name="strictusercn" type="checkbox" value="yes" <?=!empty($pconfig['strictusercn']) ? "checked=\"checked\"" : "" ;?> /> <div class="hidden" data-for="help_for_strictusercn"> <span> <?=gettext("When authenticating users, enforce a match between the Common Name of the client certificate and the username given at login."); ?> </span> </div> </td> </tr> </table> </div> </div> </section> <section class="col-xs-12"> <div class="tab-content content-box col-xs-12"> <div class="table-responsive"> <table class="table table-striped opnsense_standard_table_form"> <tr> <td colspan="2"><strong><?=gettext("Tunnel Settings"); ?></strong></td> </tr> <tr> <td style="width:22%" id="ipv4_tunnel_network"><a id="help_for_tunnel_network" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("IPv4 Tunnel Network"); ?></td> <td style="width:78%"> <input name="tunnel_network" type="text" class="form-control unknown" size="20" value="<?=$pconfig['tunnel_network'];?>" /> <div class="hidden" data-for="help_for_tunnel_network"> <?=gettext("This is the IPv4 virtual network used for private " . "communications between this server and client " . "hosts expressed using CIDR (eg. 10.0.8.0/24). " . "The first network address will be assigned to " . "the server virtual interface. The remaining " . "network addresses can optionally be assigned " . "to connecting clients. (see Address Pool)"); ?> </div> </td> </tr> <tr> <td style="width:22%"><a id="help_for_tunnel_networkv6" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("IPv6 Tunnel Network"); ?></td> <td> <input name="tunnel_networkv6" type="text" class="form-control unknown" size="20" value="<?=$pconfig['tunnel_networkv6'];?>" /> <div class="hidden" data-for="help_for_tunnel_networkv6"> <?=gettext("This is the IPv6 virtual network used for private " . "communications between this server and client " . "hosts expressed using CIDR (eg. fe80::/64). " . "The first network address will be assigned to " . "the server virtual interface. The remaining " . "network addresses can optionally be assigned " . "to connecting clients. (see Address Pool)"); ?> </div> </td> </tr> <tr class="dev_mode dev_mode_tap"> <td style="width:22%"><a id="help_for_serverbridge_dhcp" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Bridge DHCP"); ?></td> <td> <input id="serverbridge_dhcp" name="serverbridge_dhcp" type="checkbox" value="yes" <?=!empty($pconfig['serverbridge_dhcp']) ? "checked=\"checked\"" : "" ;?>/> <div class="hidden" data-for="help_for_serverbridge_dhcp"> <span> <?=gettext("Allow clients on the bridge to obtain DHCP."); ?><br /> </span> </div> </td> </tr> <tr class="dev_mode dev_mode_tap"> <td style="width:22%"><a id="help_for_serverbridge_interface" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Bridge Interface"); ?></td> <td> <select id="serverbridge_interface" name="serverbridge_interface" class="selectpicker" data-size="5" data-live-search="true"> <?php $serverbridge_interface['none'] = "none"; $serverbridge_interface = array_merge($serverbridge_interface, get_configured_interface_with_descr()); foreach (get_configured_carp_interface_list() as $cif => $carpip) { $serverbridge_interface[$cif.'|'.$carpip] = $carpip." (".get_vip_descr($carpip).")"; } foreach (get_configured_ip_aliases_list() as $aliasip => $aliasif) { $serverbridge_interface[$aliasif.'|'.$aliasip] = $aliasip." (".get_vip_descr($aliasip).")"; } foreach ($serverbridge_interface as $iface => $ifacename) : $selected = ""; if ($iface == $pconfig['serverbridge_interface']) { $selected = "selected=\"selected\""; } ?> <option value="<?=$iface;?>" <?=$selected;?>> <?=htmlspecialchars($ifacename);?> </option> <?php endforeach; ?> </select> <div class="hidden" data-for="help_for_serverbridge_interface"> <?=gettext("The interface to which this tap instance will be " . "bridged. This is not done automatically. You must assign this " . "interface and create the bridge separately. " . "This setting controls which existing IP address and subnet " . "mask are used by OpenVPN for the bridge. Setting this to " . "'none' will cause the Server Bridge DHCP settings below to be ignored."); ?> </div> </td> </tr> <tr class="dev_mode dev_mode_tap"> <td style="width:22%"><a id="help_for_serverbridge_dhcp_start" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Server Bridge DHCP Start"); ?></td> <td> <input id="serverbridge_dhcp_start" name="serverbridge_dhcp_start" type="text" class="form-control unknown" size="20" value="<?=$pconfig['serverbridge_dhcp_start'];?>" /> <div class="hidden" data-for="help_for_serverbridge_dhcp_start"> <?=gettext("When using tap mode as a multi-point server, " . "you may optionally supply a DHCP range to use on the " . "interface to which this tap instance is bridged. " . "If these settings are left blank, DHCP will be passed " . "through to the LAN, and the interface setting above " . "will be ignored."); ?> </div> </td> </tr> <tr class="dev_mode dev_mode_tap"> <td style="width:22%"><i class="fa fa-info-circle text-muted"></i> <?=gettext("Server Bridge DHCP End"); ?></td> <td> <input id="serverbridge_dhcp_end" name="serverbridge_dhcp_end" type="text" class="form-control unknown" size="20" value="<?=$pconfig['serverbridge_dhcp_end'];?>" /> </td> </tr> <tr class="opt_mode opt_mode_p2p_tls opt_mode_p2p_shared_key opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user"> <td style="width:22%"><a id="help_for_gwredir" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Redirect Gateway"); ?></td> <td> <input name="gwredir" id="gwredir" type="checkbox" value="yes" <?=!empty($pconfig['gwredir']) ? "checked=\"checked\"" : "" ;?> /> <div class="hidden" data-for="help_for_gwredir"> <span> <?= gettext('Force all client generated traffic through the tunnel.') ?> </span> </div> </td> </tr> <tr class="opt_mode opt_mode_p2p_tls opt_mode_p2p_shared_key opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user opt_gwredir"> <td style="width:22%"><a id="help_local_network" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("IPv4 Local Network"); ?></td> <td> <input name="local_network" type="text" class="form-control unknown" size="40" value="<?=$pconfig['local_network'];?>" /> <div class="hidden" data-for="help_local_network"> <?=gettext("These are the IPv4 networks that will be accessible " . "from the remote endpoint. Expressed as a comma-separated list of one or more CIDR ranges. " . "You may leave this blank if you don't " . "want to add a route to the local network " . "through this tunnel on the remote machine. " . "This is generally set to your LAN network"); ?>. </div> </td> </tr> <tr class="opt_mode opt_mode_p2p_tls opt_mode_p2p_shared_key opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user opt_gwredir"> <td style="width:22%"><a id="help_for_local_networkv6" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("IPv6 Local Network"); ?></td> <td> <input name="local_networkv6" type="text" class="form-control unknown" size="40" value="<?=$pconfig['local_networkv6'];?>" /> <div class="hidden" data-for="help_for_local_networkv6"> <?=gettext("These are the IPv6 networks that will be accessible " . "from the remote endpoint. Expressed as a comma-separated list of one or more IP/PREFIX. " . "You may leave this blank if you don't " . "want to add a route to the local network " . "through this tunnel on the remote machine. " . "This is generally set to your LAN network"); ?>. </div> </td> </tr> <tr class="opt_mode opt_mode_p2p_tls opt_mode_p2p_shared_key opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user"> <td style="width:22%"><a id="help_for_remote_network" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("IPv4 Remote Network"); ?></td> <td> <input name="remote_network" type="text" class="form-control unknown" size="40" value="<?=$pconfig['remote_network'];?>" /> <div class="hidden" data-for="help_for_remote_network"> <?=gettext("These are the IPv4 networks that will be routed through " . "the tunnel, so that a site-to-site VPN can be " . "established without manually changing the routing tables. " . "Expressed as a comma-separated list of one or more CIDR ranges. " . "If this is a site-to-site VPN, enter the " . "remote LAN/s here. You may leave this blank if " . "you don't want a site-to-site VPN"); ?>. </div> </td> </tr> <tr class="opt_mode opt_mode_p2p_tls opt_mode_p2p_shared_key opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user"> <td style="width:22%"><a id="help_for_remote_networkv6" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("IPv6 Remote Network"); ?></td> <td> <input name="remote_networkv6" type="text" class="form-control unknown" size="40" value="<?=$pconfig['remote_networkv6'];?>" /> <div class="hidden" data-for="help_for_remote_networkv6"> <?=gettext("These are the IPv6 networks that will be routed through " . "the tunnel, so that a site-to-site VPN can be " . "established without manually changing the routing tables. " . "Expressed as a comma-separated list of one or more IP/PREFIX. " . "If this is a site-to-site VPN, enter the " . "remote LAN/s here. You may leave this blank if " . "you don't want a site-to-site VPN"); ?>. </div> </td> </tr> <tr> <td style="width:22%"><a id="help_for_maxclients" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Concurrent connections");?></td> <td> <input name="maxclients" type="text" class="form-control unknown" size="5" value="<?=$pconfig['maxclients'];?>" /> <div class="hidden" data-for="help_for_maxclients"> <?=gettext("Specify the maximum number of clients allowed to concurrently connect to this server"); ?>. </div> </td> </tr> <tr> <td style="width:22%"><a id="help_for_compression" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Compression"); ?></td> <td> <select name="compression" class="selectpicker"> <?php foreach (openvpn_compression_modes() as $cmode => $cmodedesc): $selected = ""; if ($cmode == $pconfig['compression']) { $selected = " selected=\"selected\""; } ?> <option value="<?= $cmode ?>" <?= $selected ?>><?= $cmodedesc ?></option> <?php endforeach; ?> </select> <div class="hidden" data-for="help_for_compression"> <?=gettext("Compress tunnel packets using the LZ4/LZO algorithm. The LZ4 generally offers the best performance with least CPU usage. For backwards compatibility use the LZO (which is identical to the older option --comp-lzo yes). In the partial mode (the option --compress with an empty algorithm) compression is turned off, but the packet framing for compression is still enabled, allowing a different setting to be pushed later. The legacy LZO algorithm with adaptive compression mode will dynamically disable compression for a period of time if OpenVPN detects that the data in the packets is not being compressed efficiently."); ?> </div> </td> </tr> <tr> <td style="width:22%"><a id="help_for_passtos" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Type-of-Service"); ?></td> <td> <input name="passtos" type="checkbox" value="yes" <?=!empty($pconfig['passtos']) ? "checked=\"checked\"" : "" ;?> /> <div class="hidden" data-for="help_for_passtos"> <span> <?=gettext("Set the TOS IP header value of tunnel packets to match the encapsulated packet value"); ?>. </span> </div> </td> </tr> <tr class="opt_mode opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user"> <td style="width:22%"><a id="help_for_client2client" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Inter-client communication"); ?></td> <td> <input name="client2client" type="checkbox" value="yes" <?=!empty($pconfig['client2client']) ? "checked=\"checked\"" : "" ;?> /> <div class="hidden" data-for="help_for_client2client"> <span> <?=gettext("Allow communication between clients connected to this server"); ?> </span> </div> </td> </tr> <tr id="duplicate_cn"> <td style="width:22%"><a id="help_for_duplicate_cn" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Duplicate Connections"); ?></td> <td> <input name="duplicate_cn" type="checkbox" value="yes" <?=!empty($pconfig['duplicate_cn']) ? "checked=\"checked\"" : "" ;?> /> <div class="hidden" data-for="help_for_duplicate_cn"> <span> <?=gettext("Allow multiple concurrent connections from clients using the same Common Name.<br />NOTE: This is not generally recommended, but may be needed for some scenarios."); ?> </span> </div> </td> </tr> </table> </div> </div> </section> <section class="col-xs-12"> <div class="tab-content content-box col-xs-12"> <div class="table-responsive"> <table class="table table-striped opnsense_standard_table_form"> <tr> <td colspan="2"><strong><?=gettext("Client Settings"); ?></strong></td> </tr> <tr> <td style="width:22%"><a id="help_for_dynamic_ip" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Dynamic IP"); ?></td> <td style="width:78%"> <input name="dynamic_ip" type="checkbox" id="dynamic_ip" value="yes" <?=!empty($pconfig['dynamic_ip']) ? "checked=\"checked\"" : "" ;?> /> <div class="hidden" data-for="help_for_dynamic_ip"> <span> <?=gettext("Allow connected clients to retain their connections if their IP address changes"); ?>.<br /> </span> </div> </td> </tr> <tr class="dev_mode dev_mode_tun" id="topology_subnet_opt"> <td style="width:22%"><a id="help_for_topology_subnet" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Topology"); ?></td> <td> <input name="topology_subnet" type="checkbox" id="topology_subnet" value="yes" <?=!empty($pconfig['topology_subnet']) ? "checked=\"checked\"" : "" ;?> /> <div class="hidden" data-for="help_for_topology_subnet"> <span> <?=gettext("Allocate only one IP per client (topology subnet), rather than an isolated subnet per client (topology net30)."); ?><br /> <?=gettext("Relevant when supplying a virtual adapter IP address to clients when using tun mode on IPv4."); ?><br /> <?=gettext("Some clients may require this even for IPv6, such as OpenVPN Connect (iOS/Android). Others may break if it is present, such as older versions of OpenVPN or clients such as Yealink phones."); ?><br /> </span> </div> </td> </tr> <tr class="opt_mode opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user" style="display:none"> <td style="width:22%"><a id="help_for_dns_domain" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("DNS Default Domain"); ?></td> <td> <input name="dns_domain_enable" type="checkbox" id="dns_domain_enable" value="yes" <?=!empty($pconfig['dns_domain']) ? "checked=\"checked\"" : "" ;?> /> <div id="dns_domain_data"> <input name="dns_domain" type="text" class="form-control unknown" id="dns_domain" size="30" value="<?=htmlspecialchars($pconfig['dns_domain']);?>" /> </div> <div class="hidden" data-for="help_for_dns_domain"> <span> <?=gettext("Provide a default domain name to clients"); ?><br /> </span> </div> </td> </tr> <tr class="opt_mode opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user" style="display:none"> <td style="width:22%"><a id="help_for_dns_domain_search" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("DNS Domain search list"); ?></td> <td> <input name="dns_domain_search_enable" type="checkbox" id="dns_domain_search_enable" value="yes" <?=!empty($pconfig['dns_domain_search']) ? "checked=\"checked\"" : "" ;?> /> <div id="dns_domain_search_data"> <input name="dns_domain_search" type="text" class="form-control unknown" value="<?=htmlspecialchars($pconfig['dns_domain_search']);?>" /> </div> <div class="hidden" data-for="help_for_dns_domain_search"> <span> <?=gettext("Add name to the domain search list. Repeat this option to add more entries. Expressed as a comma-separated list up to 10 domains are supported."); ?><br /> </span> </div> </td> </tr> <tr class="opt_mode opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user" style="display:none"> <td style="width:22%"><a id="help_for_dns_server" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("DNS Servers"); ?></td> <td> <input name="dns_server_enable" type="checkbox" id="dns_server_enable" value="yes" <?=!empty($pconfig['dns_server1']) || !empty($pconfig['dns_server2']) || !empty($pconfig['dns_server3']) || !empty($pconfig['dns_server4']) ? "checked=\"checked\"" : "" ;?> /> <div id="dns_server_data"> <span> <?=gettext("Server #1:"); ?> </span> <input name="dns_server1" type="text" class="form-control unknown" id="dns_server1" size="20" value="<?=$pconfig['dns_server1'];?>" /> <span> <?=gettext("Server #2:"); ?> </span> <input name="dns_server2" type="text" class="form-control unknown" id="dns_server2" size="20" value="<?=$pconfig['dns_server2'];?>" /> <span> <?=gettext("Server #3:"); ?> </span> <input name="dns_server3" type="text" class="form-control unknown" id="dns_server3" size="20" value="<?=$pconfig['dns_server3'];?>" /> <span> <?=gettext("Server #4:"); ?> </span> <input name="dns_server4" type="text" class="form-control unknown" id="dns_server4" size="20" value="<?=$pconfig['dns_server4'];?>" /> </div> <div class="hidden" data-for="help_for_dns_server"> <span> <?=gettext("Provide a DNS server list to clients"); ?><br /> </span> </div> </td> </tr> <tr id="chkboxPushRegisterDNS" class="opt_mode opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user" style="display:none"> <td style="width:22%"><a id="help_for_push_register_dns" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Force DNS cache update"); ?></td> <td> <input name="push_register_dns" type="checkbox" value="yes" <?=!empty($pconfig['push_register_dns']) ? "checked=\"checked\"" : "" ;?> /> <div class="hidden" data-for="help_for_push_register_dns"> <span> <?=gettext("Run ''net stop dnscache'', ''net start dnscache'', ''ipconfig /flushdns'' and ''ipconfig /registerdns'' on connection initiation. This is known to kick Windows into recognizing pushed DNS servers."); ?><br /> </span> </div> </td> </tr> <tr id="chkboxBlockOutsideDNS" class="opt_mode opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user" style="display:none"> <td style="width:22%"><a id="help_for_push_block_outside_dns" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Prevent DNS leaks"); ?></td> <td> <input name="push_block_outside_dns" type="checkbox" value="yes" <?=!empty($pconfig['push_block_outside_dns']) ? "checked=\"checked\"" : "" ;?> /> <div class="hidden" data-for="help_for_push_block_outside_dns"> <span> <?=gettext("Block DNS servers on other network adapters to prevent DNS leaks. Compatible with Windows clients only."); ?><br /> </span> </div> </td> </tr> <tr class="opt_mode opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user" style="display:none"> <td style="width:22%"><a id="help_for_ntp_server_enable" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("NTP Servers"); ?></td> <td> <input name="ntp_server_enable" type="checkbox" id="ntp_server_enable" value="yes" <?=!empty($pconfig['ntp_server1']) || !empty($pconfig['ntp_server2']) ? "checked=\"checked\"" : "" ;?> /> <div id="ntp_server_data"> <span> <?=gettext("Server #1:"); ?> </span> <input name="ntp_server1" type="text" class="form-control unknown" id="ntp_server1" size="20" value="<?=$pconfig['ntp_server1'];?>" /> <span> <?=gettext("Server #2:"); ?> </span> <input name="ntp_server2" type="text" class="form-control unknown" id="ntp_server2" size="20" value="<?=$pconfig['ntp_server2'];?>" /> </div> <div class="hidden" data-for="help_for_ntp_server_enable"> <span> <?=gettext("Provide a NTP server list to clients"); ?><br /> </span> </div> </td> </tr> <tr class="opt_mode opt_mode_server_tls opt_mode_server_user opt_mode_server_tls_user" style="display:none"> <td style="width:22%"><a id="help_for_netbios_enable" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("NetBIOS Options"); ?></td> <td> <input name="netbios_enable" type="checkbox" id="netbios_enable" value="yes" <?=!empty($pconfig['netbios_enable']) ? "checked=\"checked\"" : "" ;?> /> <div class="hidden" data-for="help_for_netbios_enable"> <span> <?=gettext("Enable NetBIOS over TCP/IP"); ?><br /> <?=gettext("If this option is not set, all NetBIOS-over-TCP/IP options (including WINS) will be disabled"); ?>. </span> </div> <div id="netbios_data"> <span> <?=gettext("Node Type"); ?>: </span><br> <select name='netbios_ntype' class="selectpicker"> <?php foreach ($netbios_nodetypes as $type => $name) : $selected = ""; if ($pconfig['netbios_ntype'] == $type) { $selected = "selected=\"selected\""; } ?> <option value="<?=$type;?>" <?=$selected;?>><?=$name;?></option> <?php endforeach; ?> </select> <div class="hidden" data-for="help_for_netbios_enable"> <?=gettext("Possible options: b-node (broadcasts), p-node " . "(point-to-point name queries to a WINS server), " . "m-node (broadcast then query name server), and " . "h-node (query name server, then broadcast)."); ?> </div><br> <span> <?=gettext("Scope ID"); ?>: </span> <input name="netbios_scope" type="text" class="form-control unknown" id="netbios_scope" size="30" value="<?=$pconfig['netbios_scope'];?>" /> <div class="hidden" data-for="help_for_netbios_enable"> <?=gettext("A NetBIOS Scope ID provides an extended naming " . "service for NetBIOS over TCP/IP. The NetBIOS " . "Scope ID isolates NetBIOS traffic on a single " . "network to only those nodes with the same " . "NetBIOS Scope ID."); ?> </div> </div> </td> </tr> <tr id="wins_opts"> <td style="width:22%"><a id="help_for_wins_server" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("WINS Servers"); ?></td> <td> <input name="wins_server_enable" type="checkbox" id="wins_server_enable" value="yes" <?=!empty($pconfig['wins_server1']) || !empty($pconfig['wins_server2']) ? "checked=\"checked\"" : "" ;?> /> <div class="hidden" data-for="help_for_wins_server"> <span> <?=gettext("Provide a WINS server list to clients"); ?><br /> </span> </div> <div id="wins_server_data"> <span> <?=gettext("Server #1:"); ?> </span> <input name="wins_server1" type="text" class="form-control unknown" id="wins_server1" size="20" value="<?=$pconfig['wins_server1'];?>" /> <span> <?=gettext("Server #2:"); ?> </span> <input name="wins_server2" type="text" class="form-control unknown" id="wins_server2" size="20" value="<?=$pconfig['wins_server2'];?>" /> </div> </td> </tr> <tr> <td style="width:22%"><a id="help_for_client_mgmt_port" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Client Management Port"); ?></td> <td> <input name="client_mgmt_port_enable" type="checkbox" id="client_mgmt_port_enable" value="yes" <?=!empty($pconfig['client_mgmt_port']) ? "checked=\"checked\"" : "" ;?> /> <div id="client_mgmt_port_data"> <input name="client_mgmt_port" type="text" class="form-control unknown" id="client_mgmt_port" size="30" value="<?=htmlspecialchars($pconfig['client_mgmt_port']);?>" /> </div> <div class="hidden" data-for="help_for_client_mgmt_port"> <span> <?=gettext("Use a different management port on clients. The default port is 166. Specify a different port if the client machines need to select from multiple OpenVPN links."); ?><br /> </span> </div> </td> </tr> <tr class="opt_mode opt_mode_server_tls_user"> <td style="width:22%"><a id="help_for_use-common-name" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Use common name"); ?></td> <td> <input name="use-common-name" type="checkbox" value="1" <?=!empty($pconfig['use-common-name']) ? "checked=\"checked\"" : "" ;?> /> <div class="hidden" data-for="help_for_use-common-name"> <span> <?=gettext("When using a client certificate, use certificate common name for indexing purposes instead of username"); ?><br /> </span> </div> </td> </tr> </table> </div> </div> </section> <section class="col-xs-12"> <div class="tab-content content-box col-xs-12"> <div class="table-responsive"> <table class="table table-striped opnsense_standard_table_form"> <tr> <td colspan="2"><strong><?=gettext("Advanced configuration"); ?></strong></td> </tr> <tr> <td style="width:22%"><a id="help_for_custom_options" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Advanced"); ?></td> <td> <textarea rows="6" cols="78" name="custom_options" id="custom_options"><?=$pconfig['custom_options'];?></textarea> <?=gettext("This option will be removed in the future due to being insecure by nature. In the mean time only full administrators are allowed to change this setting.");?> <div class="hidden" data-for="help_for_custom_options"> <?=gettext("Enter any additional options you would like to add to the configuration file here."); ?> </div> </td> </tr> <tr id="comboboxVerbosityLevel"> <td style="width:22%"><a id="help_for_verbosity_level" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Verbosity level");?></td> <td> <select name="verbosity_level" class="selectpicker"> <?php foreach (openvpn_verbosity_level() as $verb_value => $verb_desc): $selected = ''; if ($pconfig['verbosity_level'] == $verb_value) { $selected = 'selected="selected"'; } ?> <option value="<?=$verb_value; ?>" <?=$selected; ?>><?=$verb_desc;?></option> <?php endforeach; ?> </select> <div class="hidden" data-for="help_for_verbosity_level"> <?=gettext("Each level shows all info from the previous levels. Level 3 is recommended if you want a good summary of what's happening without being swamped by output."); ?><br /> <br /> <?=sprintf(gettext("%s0%s -- No output except fatal errors."),'<strong>','</strong>') ?> <br /> <?=sprintf(gettext("%s1%s -- startup info + connection initiated messages + non-fatal encryption & net errors."),'<strong>','</strong>') ?> <br /> <?=sprintf(gettext("%s2,3%s -- show TLS negotiations & route info."),'<strong>','</strong>') ?> <br /> <?=sprintf(gettext("%s4%s -- Normal usage range."),'<strong>','</strong>') ?> <br /> <?=sprintf(gettext("%s5%s -- Output R and W characters to the console for each packet read and write, uppercase is used for TCP/UDP packets and lowercase is used for TUN/TAP packets."),'<strong>','</strong>') ?> <br /> <?=sprintf(gettext("%s6%s-%s11%s -- Debug info range."),'<strong>','</strong>','<strong>','</strong>') ?> </div> </td> </tr> <tr class="opt_mode opt_mode_server_tls_user opt_mode_server_user"> <td><a id="help_for_reneg-sec" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Renegotiate time"); ?></td> <td> <input type="text" name="reneg-sec" value="<?=$pconfig['reneg-sec'];?>"> <div class="hidden" data-for="help_for_reneg-sec"> <?=sprintf( gettext('Renegotiate data channel key after n seconds (default=3600).%s' . 'When using a one time password, be advised that your connection will automatically drop because your password is not valid anymore.%sSet to 0 to disable, remember to change your client as well.'), '<br/>','<br/>');?> </div> </td> </tr> <tr id="chkboxLoginMatching"> <td style="width:22%"><a id="help_for_cso_login_matching" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Force CSO Login Matching"); ?></td> <td> <input name="cso_login_matching" type="checkbox" value="yes" <?=!empty($pconfig['cso_login_matching']) ? "checked=\"checked\"" : "" ;?> /> <div class="hidden" data-for="help_for_cso_login_matching"> <span> <?=gettext("Use username instead of common name to match client specific override."); ?><br /> </span> </div> </td> </tr> <tr> <td style="width:22%"> </td> <td style="width:78%"> <input name="save" type="submit" class="btn btn-primary" value="<?=html_safe(gettext('Save')); ?>" /> <input name="act" type="hidden" value="<?=$act;?>" /> <?php if (isset($id) && $a_server[$id]) :?> <input name="id" type="hidden" value="<?=htmlspecialchars($id);?>" /> <?php endif; ?> </td> </tr> </table> </div> </div> </section> </form> <?php else :?> <section class="col-xs-12"> <div class="tab-content content-box col-xs-12"> <table class="table table-striped"> <thead> <tr> <td></td> <td><?=gettext("Protocol / Port"); ?></td> <td><?=gettext("Tunnel Network"); ?></td> <td><?=gettext("Description"); ?></td> <td class="text-nowrap"> <a href="vpn_openvpn_server.php?act=new" class="btn btn-primary btn-xs" data-toggle="tooltip" title="<?= html_safe(gettext('Add')) ?>"> <i class="fa fa-plus fa-fw"></i> </a> <a href="wizard.php?xml=openvpn" class="btn btn-defaultu btn-xs" data-toggle="tooltip" title="<?= html_safe(gettext('Use a wizard to setup a new server')) ?>"> <i class="fa fa-magic fa-fw"></i> </a> </td> </tr> </thead> <tbody> <?php $i = 0; foreach ($a_server as $server) :?> <tr> <td> <a href="#" class="act_toggle" data-id="<?=$i;?>" data-toggle="tooltip" title="<?=(empty($server['disable'])) ? gettext("Disable") : gettext("Enable");?>"> <span class="fa fa-play <?=(empty($server['disable'])) ? "text-success" : "text-muted";?>"></span> </a> </td> <td> <?=htmlspecialchars($server['protocol']);?> / <?=htmlspecialchars($server['local_port']);?> </td> <td> <?= htmlspecialchars($server['tunnel_network']) ?> <?= !empty($server['tunnel_networkv6']) && !empty($server['tunnel_network']) ? ',' : '' ?> <?= htmlspecialchars($server['tunnel_networkv6']) ?> </td> <td> <?=htmlspecialchars($server['description']);?> </td> <td class="text-nowrap"> <a href="vpn_openvpn_server.php?act=edit&id=<?=$i;?>" title="<?= html_safe(gettext('Edit')) ?>" data-toggle="tooltip" class="btn btn-default btn-xs"><i class="fa fa-pencil fa-fw"></i></a> <a id="del_<?=$i;?>" title="<?= html_safe(gettext('Delete')) ?>" data-toggle="tooltip" class="act_delete btn btn-default btn-xs"><i class="fa fa-trash fa-fw"></i></a> <a href="vpn_openvpn_server.php?act=new&dup=<?=$i;?>" class="btn btn-default btn-xs" data-toggle="tooltip" title="<?= html_safe(gettext('Clone')) ?>"> <span class="fa fa-clone fa-fw"></span> </a> </td> </tr> <?php $i++; endforeach;?> </tbody> </table> </div> </section> <?php endif; ?> </div> </div> </section> <?php include("foot.inc"); ?>