Commit cee1af97 authored by Franco Fichtner's avatar Franco Fichtner

vpn: merge nine IPsec changes from master

Same same, but different. (See previous commit for details.)

o Human-readable format of authentication method in overview
o Refine behaviour of enable / apply on main IPsec page
o Dedup leftsubnet/rightsubnet for meshed IKEv2
o More elegant interface and service plugging
o Tunnel isolation mode for IKEv2 (unmashed)
o Cleanup pass over backend code
o Allow Camellia for IKEv2
o Allow %any in phase 1
o Allow EAP-MSCHAPV2
parent efb06220
......@@ -1552,7 +1552,7 @@ function filter_nat_rules_generate(&$FilterIflist)
}
/* ipsec nat */
if (isset($config['ipsec']) && is_array($config['ipsec']) && isset($config['ipsec']['enable'])) {
if (isset($config['ipsec']['enable'])) {
if (isset($config['ipsec']['phase2'])) {
foreach ($config['ipsec']['phase2'] as $ph2ent) {
if ($ph2ent['mode'] != 'transport' && !empty($ph2ent['natlocalid']) && !isset($ph2ent['disabled'])) {
......@@ -2784,6 +2784,7 @@ pass in {$log['pass']} on \$loopback inet all label "pass IPv4 loopback"
pass out {$log['pass']} on \$loopback inet all label "pass IPv4 loopback"
pass in {$log['pass']} on \$loopback inet6 all label "pass IPv6 loopback"
pass out {$log['pass']} on \$loopback inet6 all label "pass IPv6 loopback"
# let out anything from the firewall host itself and decrypted IPsec traffic
pass out {$log['pass']} inet all keep state allow-opts label "let out anything IPv4 from firewall host itself"
pass out {$log['pass']} inet6 all keep state allow-opts label "let out anything IPv6 from firewall host itself"
......@@ -2821,10 +2822,9 @@ EOD;
}
}
/* add ipsec interfaces */
if (isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable'])) {
$ipfrules .= "pass out {$log['pass']} on \$IPsec all keep state label \"IPsec internal host to host\"\n";
if (!empty($FilterIflist['enc0']['descr'])) {
$ipfrules .= "pass out {$log['pass']} on \${$FilterIflist['enc0']['descr']} all keep state label \"IPsec internal host to host\"\n";
}
if (is_array($config['system']['webgui']) && !isset($config['system']['webgui']['noantilockout'])) {
......@@ -2836,6 +2836,7 @@ EOD;
*/
$lanif = $FilterIflist['lan']['if'];
$ipfrules .= <<<EOD
# make sure the user cannot lock himself out of the webConfigurator or SSH
pass in {$log['pass']} quick on {$lanif} proto tcp from any to ({$lanif}) port { {$alports} } keep state label "anti-lockout rule"
......@@ -2844,6 +2845,7 @@ EOD;
/* single-interface deployment, add to WAN */
$wanif = $FilterIflist["wan"]['if'];
$ipfrules .= <<<EOD
# make sure the user cannot lock himself out of the webConfigurator or SSH
pass in {$log['pass']} quick on {$wanif} proto tcp from any to ({$wanif}) port { {$alports} } keep state label "anti-lockout rule"
......@@ -3189,10 +3191,8 @@ function filter_generate_ipsec_rules(&$FilterIflist, $log = array())
return "\n# VPN Rules not added disabled in System->Advanced.\n";
}
$ipfrules = "\n# VPN Rules\n";
if (isset($config['ipsec']['enable']) &&
is_array($config['ipsec']['phase1'])) {
if (isset($config['ipsec']['enable']) && isset($config['ipsec']['phase1'])) {
/* step through all phase1 entries */
foreach ($config['ipsec']['phase1'] as $ph1ent) {
if (isset ($ph1ent['disabled'])) {
......
This diff is collapsed.
......@@ -44,7 +44,7 @@ function if_ipsec_services()
$services = array();
if (isset($config['ipsec']['enable'])) {
if (isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable'])) {
$pconfig = array();
$pconfig['name'] = 'ipsec';
$pconfig['description'] = gettext('IPsec VPN');
......@@ -64,15 +64,33 @@ function if_ipsec_interfaces()
$interfaces = array();
/* add ipsec interfaces */
if (isset($config['ipsec']['enable']) || isset($config['ipsec']['client']['enable'])) {
$oic = array("enable" => true);
$oic['if'] = 'enc0';
$oic['descr'] = 'IPsec';
$oic['type'] = "none";
$oic['virtual'] = true;
$oic['networks'] = array();
$interfaces['enc0'] = $oic;
if (isset($config['ipsec']['phase1']) && isset($config['ipsec']['phase2'])) {
foreach ($config['ipsec']['phase1'] as $ph1ent) {
if (isset($ph1ent['disabled'])) {
continue;
}
foreach ($config['ipsec']['phase2'] as $ph2ent) {
if (isset($ph2ent['disabled']) || $ph1ent['ikeid'] != $ph2ent['ikeid']) {
continue;
}
if ((isset($ph2ent['mobile']) && !isset($config['ipsec']['client']['enable'])) ||
!isset($config['ipsec']['enable'])) {
continue;
}
$oic = array('enable' => true);
$oic['if'] = 'enc0';
$oic['descr'] = 'IPsec';
$oic['type'] = 'none';
$oic['virtual'] = true;
$oic['networks'] = array();
$interfaces['enc0'] = $oic;
break 2;
}
}
}
return $interfaces;
......
......@@ -79,14 +79,19 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$a_phase2 = &$config['ipsec']['phase2'];
if (isset($_POST['apply'])) {
ipsec_configure();
/* reload the filter in the background */
filter_configure();
$savemsg = get_std_save_message();
clear_subsystem_dirty('ipsec');
} elseif (isset($_POST['save'])) {
$config['ipsec']['enable'] = !empty($_POST['enable']) ? true : false;
if (!empty($_POST['enable'])) {
$config['ipsec']['enable'] = true;
} elseif (isset($config['ipsec']['enable'])) {
unset($config['ipsec']['enable']);
}
write_config();
ipsec_configure();
filter_configure();
clear_subsystem_dirty('ipsec');
header("Location: vpn_ipsec.php");
exit;
} elseif (!empty($_POST['act']) && $_POST['act'] == "delphase1" ) {
......@@ -311,7 +316,7 @@ $( document ).ready(function() {
if (isset($savemsg)) {
print_info_box($savemsg);
}
if ($pconfig['enable'] && is_subsystem_dirty('ipsec')) {
if (is_subsystem_dirty('ipsec')) {
print_info_box_apply(gettext("The IPsec tunnel configuration has been changed.") . "<br />" . gettext("You must apply the changes in order for them to take effect."));
}?>
<section class="col-xs-12">
......@@ -423,7 +428,7 @@ $( document ).ready(function() {
<?=gettext("DH Group"); ?>&nbsp;<?=$p1_dhgroups[$ph1ent['dhgroup']];?>
</td>
<td class="hidden-xs">
<?=str_replace('_', ' ', $ph1ent['authentication_method']);?>
<?= html_safe($p1_authentication_methods[$ph1ent['authentication_method']]['name']) ?>
</td>
<td>
<?=$ph1ent['descr'];?>&nbsp;
......
......@@ -132,14 +132,13 @@ if (is_subsystem_dirty('ipsec')) {
foreach ($config['system']['user'] as $id => $user) {
if (!empty($user['ipsecpsk'])) {
$userkeys[] = array('ident' => $user['name'], 'pre-shared-key' => $user['ipsecpsk'], 'id' => $id);
;
}
}
foreach ($userkeys as $secretent) :
?>
<tr>
<td>
<?=$secretent['ident'] == 'allusers' ? gettext("ANY USER") : htmlspecialchars($secretent['ident']) ;?>
<?=htmlspecialchars($secretent['ident']) ;?>
</td>
<td>
<?=htmlspecialchars($secretent['pre-shared-key']);?>
......
......@@ -172,7 +172,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
write_config();
mark_subsystem_dirty('ipsec');
header(url_safe('Location: vpn_ipsec_mobile.php'));
exit;
}
......
......@@ -87,7 +87,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$phase1_fields = "mode,protocol,myid_type,myid_data,peerid_type,peerid_data
,encryption-algorithm,hash-algorithm,dhgroup,lifetime,authentication_method,descr,nat_traversal
,interface,iketype,dpd_delay,dpd_maxfail,remote-gateway,pre-shared-key,certref
,caref,reauth_enable,rekey_enable, auto";
,caref,reauth_enable,rekey_enable,auto,tunnel_isolation";
if (isset($p1index) && isset($config['ipsec']['phase1'][$p1index])) {
// 1-on-1 copy
foreach (explode(",", $phase1_fields) as $fieldname) {
......@@ -178,6 +178,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
// For RSA methods, require the CA/Cert.
switch ($method) {
case "eap-tls":
case "eap-mschapv2":
if ($pconfig['iketype'] != 'ikev2') {
$input_errors[] = sprintf(gettext("%s can only be used with IKEv2 type VPNs."), strtoupper($method));
}
......@@ -199,6 +200,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$reqdfieldsn = array(gettext("Certificate Authority"),gettext("Certificate"));
break;
}
if (empty($pconfig['mobile'])) {
$reqdfields[] = "remote-gateway";
$reqdfieldsn[] = gettext("Remote gateway");
......@@ -247,48 +249,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
}
}
if ($pconfig['myid_type'] == "address" and $pconfig['myid_data'] == "") {
if ($pconfig['interface'] == 'any' && $pconfig['myid_type'] == "myaddress") {
$input_errors[] = gettext("Please select an identifier (My Identifier) other then 'any' when selecting 'Any' interface");
} elseif ($pconfig['myid_type'] == "address" && $pconfig['myid_data'] == "") {
$input_errors[] = gettext("Please enter an address for 'My Identifier'");
}
if ($pconfig['myid_type'] == "keyid tag" and $pconfig['myid_data'] == "") {
} elseif ($pconfig['myid_type'] == "keyid tag" && $pconfig['myid_data'] == "") {
$input_errors[] = gettext("Please enter a keyid tag for 'My Identifier'");
}
if ($pconfig['myid_type'] == "fqdn" and $pconfig['myid_data'] == "") {
} elseif ($pconfig['myid_type'] == "fqdn" && $pconfig['myid_data'] == "") {
$input_errors[] = gettext("Please enter a fully qualified domain name for 'My Identifier'");
}
if ($pconfig['myid_type'] == "user_fqdn" and $pconfig['myid_data'] == "") {
} elseif ($pconfig['myid_type'] == "user_fqdn" && $pconfig['myid_data'] == "") {
$input_errors[] = gettext("Please enter a user and fully qualified domain name for 'My Identifier'");
}
if ($pconfig['myid_type'] == "dyn_dns" and $pconfig['myid_data'] == "") {
} elseif ($pconfig['myid_type'] == "dyn_dns" && $pconfig['myid_data'] == "") {
$input_errors[] = gettext("Please enter a dynamic domain name for 'My Identifier'");
}
if ((($pconfig['myid_type'] == "address") && !is_ipaddr($pconfig['myid_data']))) {
} elseif ((($pconfig['myid_type'] == "address") && !is_ipaddr($pconfig['myid_data']))) {
$input_errors[] = gettext("A valid IP address for 'My identifier' must be specified.");
}
if ((($pconfig['myid_type'] == "fqdn") && !is_domain($pconfig['myid_data']))) {
} elseif ((($pconfig['myid_type'] == "fqdn") && !is_domain($pconfig['myid_data']))) {
$input_errors[] = gettext("A valid domain name for 'My identifier' must be specified.");
}
if ($pconfig['myid_type'] == "fqdn") {
if (is_domain($pconfig['myid_data']) == false) {
$input_errors[] = gettext("A valid FQDN for 'My identifier' must be specified.");
}
}
if ($pconfig['myid_type'] == "user_fqdn") {
} elseif ($pconfig['myid_type'] == "fqdn" && !is_domain($pconfig['myid_data'])) {
$input_errors[] = gettext("A valid FQDN for 'My identifier' must be specified.");
} elseif ($pconfig['myid_type'] == "user_fqdn") {
$user_fqdn = explode("@", $pconfig['myid_data']);
if (is_domain($user_fqdn[1]) == false) {
$input_errors[] = gettext("A valid User FQDN in the form of user@my.domain.com for 'My identifier' must be specified.");
}
}
if ($pconfig['myid_type'] == "dyn_dns") {
} elseif ($pconfig['myid_type'] == "dyn_dns") {
if (is_domain($pconfig['myid_data']) == false) {
$input_errors[] = gettext("A valid Dynamic DNS address for 'My identifier' must be specified.");
}
......@@ -349,6 +333,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$pconfig['encryption-algorithm']['keylen'] = $pconfig['ealgo_keylen'];
}
foreach ($p1_ealgos as $algo => $algodata) {
if (!empty($pconfig['iketype']) && !empty($pconfig['encryption-algorithm']['name']) && !empty($algodata['iketype'])
&& $pconfig['iketype'] != $algodata['iketype'] && $pconfig['encryption-algorithm']['name'] == $algo) {
$input_errors[] = sprintf(gettext("%s can only be used with IKEv2 type VPNs."), $algodata['name']);
}
}
if (count($input_errors) == 0) {
$copy_fields = "ikeid,iketype,interface,mode,protocol,myid_type,myid_data
,peerid_type,peerid_data,encryption-algorithm,hash-algorithm,dhgroup
......@@ -376,6 +367,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$ph1ent['rekey_enable'] = true;
}
if (isset($pconfig['tunnel_isolation'])) {
$ph1ent['tunnel_isolation'] = true;
}
if (isset($pconfig['dpd_enable'])) {
$ph1ent['dpd_delay'] = $pconfig['dpd_delay'];
$ph1ent['dpd_maxfail'] = $pconfig['dpd_maxfail'];
......@@ -402,7 +397,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
write_config();
mark_subsystem_dirty('ipsec');
header("Location: vpn_ipsec.php");
exit;
}
......@@ -448,6 +442,7 @@ include("head.inc");
case 'hybrid_rsa_server':
case 'xauth_rsa_server':
case 'rsasig':
case 'eap-mschapv2':
$(".auth_eap_tls").show();
$(".auth_eap_tls :input").prop( "disabled", false );
$(".auth_eap_tls_caref").show();
......@@ -620,6 +615,9 @@ include("head.inc");
</option>
<?php endforeach;
?>
<option value="any" <?= $pconfig['interface'] == "any" ? "selected=\"selected\"" : "" ?>>
<?=gettext("Any");?>
</option>
</select>
<div class="hidden" for="help_for_interface">
<?=gettext("Select the interface for the local endpoint of this phase1 entry."); ?>
......@@ -661,13 +659,6 @@ include("head.inc");
<td>
<select name="authentication_method" id="authentication_method" class="formselect">
<?php
$p1_authentication_methods = array(
'hybrid_rsa_server' => array( 'name' => 'Hybrid RSA + Xauth', 'mobile' => true ),
'xauth_rsa_server' => array( 'name' => 'Mutual RSA + Xauth', 'mobile' => true ),
'xauth_psk_server' => array( 'name' => 'Mutual PSK + Xauth', 'mobile' => true ),
'eap-tls' => array( 'name' => 'EAP-TLS', 'mobile' => true),
'rsasig' => array( 'name' => 'Mutual RSA', 'mobile' => false ),
'pre_shared_key' => array( 'name' => 'Mutual PSK', 'mobile' => false ) );
foreach ($p1_authentication_methods as $method_type => $method_params) :
if (empty($pconfig['mobile']) && $method_params['mobile']) {
continue;
......@@ -731,6 +722,8 @@ endforeach; ?>
</div>
</td>
</tr>
<?php
if (empty($pconfig['mobile'])):?>
<tr class="auth_opt auth_eap_tls auth_psk">
<td ><i class="fa fa-info-circle text-muted"></i> <?=gettext("Peer identifier"); ?></td>
<td>
......@@ -762,6 +755,8 @@ endforeach; ?>
} ?>
</td>
</tr>
<?php
endif;?>
<tr class="auth_opt auth_psk">
<td ><a id="help_for_psk" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Pre-Shared Key"); ?></td>
<td>
......@@ -928,6 +923,15 @@ endforeach; ?>
</div>
</td>
</tr>
<tr>
<td><a id="help_for_tunnel_isolation" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext('Tunnel Isolation') ?></td>
<td>
<input name="tunnel_isolation" type="checkbox" id="tunnel_isolation" value="yes" <?= !empty($pconfig['tunnel_isolation']) ? 'checked="checked"' : '' ?>/>
<div class="hidden" for="help_for_tunnel_isolation">
<?= gettext('This option will create a tunnel for each phase 2 entry for IKEv2 interoperability with e.g. FortiGate devices.') ?>
</div>
</td>
</tr>
<tr>
<td><a id="help_for_nat_traversal" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("NAT Traversal"); ?></td>
<td>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment