From fb5e78635378145bc8ad432b0951f41bca3d2fe8 Mon Sep 17 00:00:00 2001 From: Franco Fichtner Date: Fri, 19 Aug 2016 18:44:02 +0200 Subject: [PATCH] ipsec: allow tunnel isolation compatibility mode At least FortiGate doesn't like meshing the phase 2 entries so instead isolete each phase 2 entry in its own tunnel. This is supposedly IKEv1 trickery, but it works... Also see: https://wiki.strongswan.org/projects/strongswan/wiki/FAQ#Multiple-subnets-per-SA Also see: https://lists.strongswan.org/pipermail/users/2013-March/004478.html --- src/etc/inc/ipsec.inc | 82 ++++++++++++++++++++++++------------ src/www/vpn_ipsec_phase1.php | 15 ++++++- 2 files changed, 68 insertions(+), 29 deletions(-) diff --git a/src/etc/inc/ipsec.inc b/src/etc/inc/ipsec.inc index 2750a57db..2b8db13c4 100644 --- a/src/etc/inc/ipsec.inc +++ b/src/etc/inc/ipsec.inc @@ -1115,7 +1115,6 @@ conn con<> installpolicy = yes {$tunneltype} {$dpdline} - auto = {$conn_auto} left = {$left_spec} right = {$right_spec} leftid = {$myid_data} @@ -1157,42 +1156,69 @@ EOD; if (!empty($ealgoAHsp2arr[$idx])) { $tmpconf .= "\tah = " . join(',', $ealgoAHsp2arr[$idx]) . "!\n"; } + $tmpconf .= "\tauto = {$conn_auto}"; $ipsecconf .= $tmpconf; } } else { // mobile and ikev2 - $tmpconf = str_replace('<>', "{$ph1ent['ikeid']}", $connEntry); - if (!empty($rightsubnet_spec)) { - $tmpconf .= "\trightsubnet = " . join(',', array_unique($rightsubnet_spec)) . "\n"; - } - if (!empty($leftsubnet_spec)) { - $tmpconf .= "\tleftsubnet = " . join(',', array_unique($leftsubnet_spec)) . "\n"; - } - // merge esp phase 2 arrays. - $esp_content = array(); - foreach ($ealgoESPsp2arr as $ealgoESPsp2arr_details) { - foreach ($ealgoESPsp2arr_details as $esp_item) { - if (!in_array($esp_item, $esp_content)) { - $esp_content[] = $esp_item; + if (isset($ph1ent['tunnel_isolation'])) { + $ipsecconf .= str_replace('<>', "{$ph1ent['ikeid']}-000", $connEntry); + for ($idx = 0; $idx < count($leftsubnet_spec); ++$idx) { + // requires leading empty line: + $tmpconf = array(''); + // fix for strongSwan to pick up the correct connection + // name from the first configured tunnel ($idx == 0): + $conn_suffix = $idx ? sprintf('-%03d', $idx) : ''; + $tmpconf[] = "conn con{$ph1ent['ikeid']}{$conn_suffix}"; + $tmpconf[] = "\trightsubnet = {$rightsubnet_spec[$idx]}"; + $tmpconf[] = "\tleftsubnet = {$leftsubnet_spec[$idx]}"; + if (!empty($ealgoESPsp2arr[$idx])) { + $tmpconf[] = "\tesp = " . join(',', $ealgoESPsp2arr[$idx]) . '!'; + } + if (!empty($ealgoAHsp2arr[$idx])) { + $tmpconf[] = "\tah = " . join(',', $ealgoAHsp2arr[$idx]) . '!'; + } + $tmpconf[] = "\talso = con{$ph1ent['ikeid']}-000"; + $tmpconf[] = "\tauto = {$conn_auto}"; + // requires trailing empty line: + $tmpconf[] = ''; + $ipsecconf .= join("\n", $tmpconf); + } + } else { + $tmpconf = str_replace('<>', "{$ph1ent['ikeid']}", $connEntry); + if (!empty($rightsubnet_spec)) { + $tmpconf .= "\trightsubnet = " . join(',', array_unique($rightsubnet_spec)) . "\n"; + } + if (!empty($leftsubnet_spec)) { + $tmpconf .= "\tleftsubnet = " . join(',', array_unique($leftsubnet_spec)) . "\n"; + } + // merge esp phase 2 arrays. + $esp_content = array(); + foreach ($ealgoESPsp2arr as $ealgoESPsp2arr_details) { + foreach ($ealgoESPsp2arr_details as $esp_item) { + if (!in_array($esp_item, $esp_content)) { + $esp_content[] = $esp_item; + } } } - } - // merge ah phase 2 arrays. - $ah_content = array(); - foreach ($ealgoAHsp2arr as $ealgoAHsp2arr_details) { - foreach ($ealgoAHsp2arr_details as $ah_item) { - if (!in_array($ah_item, $ah_content)) { - $ah_content[] = $ah_item; + // merge ah phase 2 arrays. + $ah_content = array(); + foreach ($ealgoAHsp2arr as $ealgoAHsp2arr_details) { + foreach ($ealgoAHsp2arr_details as $ah_item) { + if (!in_array($ah_item, $ah_content)) { + $ah_content[] = $ah_item; + } } } + if (!empty($esp_content)) { + $tmpconf .= "\tesp = " . join(',', $esp_content) . "!\n"; + } + if (!empty($ah_content)) { + $tmpconf .= "\tah = " . join(',', $ah_content) . "!\n"; + } + $tmpconf .= "\tauto = {$conn_auto}"; + $ipsecconf .= $tmpconf; } - if (!empty($esp_content)) { - $tmpconf .= "\tesp = " . join(',', $esp_content) . "!\n"; - } - if (!empty($ah_content)) { - $tmpconf .= "\tah = " . join(',', $ah_content) . "!\n"; - } - $ipsecconf .= $tmpconf; } } } diff --git a/src/www/vpn_ipsec_phase1.php b/src/www/vpn_ipsec_phase1.php index 4aa7cfaf6..2b88aa4cb 100644 --- a/src/www/vpn_ipsec_phase1.php +++ b/src/www/vpn_ipsec_phase1.php @@ -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) { @@ -359,6 +359,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']; @@ -920,6 +924,15 @@ endforeach; ?> + + + + /> + + +