VPN: IPsec: Advanced Settings - mvc conversion, for https://github.com/opnsense/core/issues/7648

move legacy settings to mvc including conversion, also expose some of our staticly configured strongswan.conf settings into the form for clarity.
This commit is contained in:
Ad Schellevis 2024-07-25 21:31:19 +02:00
parent 287c13beb8
commit 7a7e81c777
14 changed files with 588 additions and 287 deletions

6
plist
View File

@ -344,6 +344,7 @@
/usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/SadController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/ServiceController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/SessionsController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/SettingsController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/SpdController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/TunnelController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/VtiController.php
@ -365,6 +366,7 @@
/usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogRemote.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogSPD.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogVTI.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/settings.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/GifSettingsController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/GreSettingsController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Interfaces/Api/LaggSettingsController.php
@ -699,6 +701,7 @@
/usr/local/opnsense/mvc/app/models/OPNsense/IDS/Migrations/M1_0_6.php
/usr/local/opnsense/mvc/app/models/OPNsense/IDS/Migrations/M1_0_7.php
/usr/local/opnsense/mvc/app/models/OPNsense/IPsec/ACL/ACL.xml
/usr/local/opnsense/mvc/app/models/OPNsense/IPsec/FieldTypes/CharonLogLevelField.php
/usr/local/opnsense/mvc/app/models/OPNsense/IPsec/FieldTypes/ConnnectionField.php
/usr/local/opnsense/mvc/app/models/OPNsense/IPsec/FieldTypes/IKEAdressField.php
/usr/local/opnsense/mvc/app/models/OPNsense/IPsec/FieldTypes/IPsecProposalField.php
@ -710,6 +713,7 @@
/usr/local/opnsense/mvc/app/models/OPNsense/IPsec/Menu/Menu.xml
/usr/local/opnsense/mvc/app/models/OPNsense/IPsec/Migrations/M1_0_0.php
/usr/local/opnsense/mvc/app/models/OPNsense/IPsec/Migrations/M1_0_1.php
/usr/local/opnsense/mvc/app/models/OPNsense/IPsec/Migrations/M1_0_2.php
/usr/local/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.php
/usr/local/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.xml
/usr/local/opnsense/mvc/app/models/OPNsense/Interfaces/ACL/ACL.xml
@ -860,6 +864,7 @@
/usr/local/opnsense/mvc/app/views/OPNsense/IPsec/pre_shared_keys.volt
/usr/local/opnsense/mvc/app/views/OPNsense/IPsec/sad.volt
/usr/local/opnsense/mvc/app/views/OPNsense/IPsec/sessions.volt
/usr/local/opnsense/mvc/app/views/OPNsense/IPsec/settings.volt
/usr/local/opnsense/mvc/app/views/OPNsense/IPsec/spd.volt
/usr/local/opnsense/mvc/app/views/OPNsense/IPsec/tunnels.volt
/usr/local/opnsense/mvc/app/views/OPNsense/IPsec/vti.volt
@ -2196,7 +2201,6 @@
/usr/local/www/vpn_ipsec_mobile.php
/usr/local/www/vpn_ipsec_phase1.php
/usr/local/www/vpn_ipsec_phase2.php
/usr/local/www/vpn_ipsec_settings.php
/usr/local/www/vpn_openvpn_client.php
/usr/local/www/vpn_openvpn_server.php
/usr/local/www/wizard.php

View File

@ -227,9 +227,8 @@ function ipsec_devices()
function ipsec_firewall(\OPNsense\Firewall\Plugin $fw)
{
global $config;
if (
!isset($config['system']['disablevpnrules']) &&
empty((new \OPNsense\IPsec\IPsec())->general->disablevpnrules) &&
isset($config['ipsec']['enable']) && isset($config['ipsec']['phase1'])
) {
$enable_replyto = empty($config['system']['disablereplyto']);
@ -264,7 +263,7 @@ function ipsec_firewall(\OPNsense\Firewall\Plugin $fw)
"quick" => false,
"type" => "pass",
"statetype" => "keep",
"#ref" => "vpn_ipsec_settings.php#disablevpnrules",
"#ref" => "ui/ipsec/connections/settings",
"descr" => "IPsec: " . (!empty($ph1ent['descr']) ? $ph1ent['descr'] : $rgip)
);
@ -923,25 +922,8 @@ function ipsec_write_strongswan_conf()
$a_phase1 = isset($config['ipsec']['phase1']) ? $config['ipsec']['phase1'] : [];
$a_phase2 = isset($config['ipsec']['phase2']) ? $config['ipsec']['phase2'] : [];
$a_client = isset($config['ipsec']['client']) ? $config['ipsec']['client'] : [];
$strongswanTree = [
'# Automatically generated, please do not modify' => '',
'starter' => [
'load_warning' => 'no'
],
'charon' => [
'threads' => 16,
'ikesa_table_size' => 32,
'ikesa_table_segments' => 4,
'init_limit_half_open' => 1000,
'ignore_acquire_ts' => 'yes',
'syslog' => [
'identifier' => 'charon',
'daemon' => [
'ike_name' => 'yes'
]
]
]
];
$strongswanTree = (new \OPNsense\IPsec\IPsec())->strongswanTree();
foreach ($a_phase1 as $ph1ent) {
if (isset($ph1ent['disabled'])) {
@ -958,21 +940,6 @@ function ipsec_write_strongswan_conf()
if (isset($a_client['enable']) && isset($a_client['net_list'])) {
$strongswanTree['charon']['cisco_unity'] = 'yes';
}
if (!empty($config['ipsec']['max_ikev1_exchanges'])) {
$strongswanTree['charon']['max_ikev1_exchanges'] = $config['ipsec']['max_ikev1_exchanges'];
}
// Debugging configuration
// lkey is the log key, which is a three-letter abbreviation of the subsystem to log, e.g. `ike`.
// The value will be a number between -1 (silent) and 4 (highest verbosity).
foreach (array_keys(IPSEC_LOG_SUBSYSTEMS) as $lkey) {
if (
isset($config['ipsec']["ipsec_{$lkey}"]) && is_numeric($config['ipsec']["ipsec_{$lkey}"]) &&
array_key_exists(intval($config['ipsec']["ipsec_{$lkey}"]), IPSEC_LOG_LEVELS)
) {
$strongswanTree['charon']['syslog']['daemon'][$lkey] = $config['ipsec']["ipsec_{$lkey}"];
}
}
$strongswanTree['charon']['plugins'] = [];
@ -1282,6 +1249,7 @@ function ipsec_configure_do($verbose = false, $interface = '')
return;
}
}
$ipsec_mdl = new \OPNsense\IPsec\IPsec();
/* configure VTI if needed */
ipsec_configure_vti();
@ -1289,12 +1257,13 @@ function ipsec_configure_do($verbose = false, $interface = '')
ipsec_setup_pinghosts();
// Prefer older IPsec SAs (advanced setting)
if (isset($config['ipsec']['preferoldsa'])) {
if (!empty((string)$ipsec_mdl->general->preferred_oldsa)) {
set_single_sysctl('net.key.preferred_oldsa', '-30');
} else {
set_single_sysctl('net.key.preferred_oldsa', '0');
}
$ipseccfg = $config['ipsec'] ?? [];
$a_phase1 = isset($config['ipsec']['phase1']) ? $config['ipsec']['phase1'] : [];
$a_phase2 = isset($config['ipsec']['phase2']) ? $config['ipsec']['phase2'] : [];
@ -1333,14 +1302,14 @@ function ipsec_configure_do($verbose = false, $interface = '')
$swanctl = (new \OPNsense\IPsec\Swanctl())->getConfig();
$swanctl['secrets'] = ipsec_write_secrets();
if (!empty($config['ipsec']['passthrough_networks'])) {
if ((string)$ipsec_mdl->general->passthrough_networks) {
$swanctl['connections']['pass'] = [
'remote_addrs' => '127.0.0.1',
'unique' => 'replace',
'children' => [
'pass' => [
'local_ts' => $config['ipsec']['passthrough_networks'],
'remote_ts' => $config['ipsec']['passthrough_networks'],
'local_ts' => (string)$ipsec_mdl->general->passthrough_networks,
'remote_ts' => (string)$ipsec_mdl->general->passthrough_networks,
'mode' => 'pass',
'start_action' => 'route'
]

View File

@ -0,0 +1,55 @@
<?php
/*
* Copyright (C) 2024 Deciso B.V.
* 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.
*/
namespace OPNsense\IPsec\Api;
use OPNsense\Base\ApiMutableModelControllerBase;
/**
* Class SetttingsController
* @package OPNsense\IPsec\Api
*/
class SettingsController extends ApiMutableModelControllerBase
{
protected static $internalModelName = 'ipsec';
protected static $internalModelClass = 'OPNsense\IPsec\IPsec';
/**
* @inheritdoc
*/
public function getAction()
{
$data = parent::getAction();
return [
self::$internalModelName => [
'general' => $data[self::$internalModelName]['general'],
'charon' => $data[self::$internalModelName]['charon'],
]
];
}
}

View File

@ -39,4 +39,10 @@ class ConnectionsController extends \OPNsense\Base\IndexController
$this->view->formDialogChild = $this->getForm('dialogChild');
$this->view->formDialogPool = $this->getForm('dialogPool');
}
public function settingsAction()
{
$this->view->pick('OPNsense/IPsec/settings');
$this->view->formSettings = $this->getForm('settings');
}
}

View File

@ -0,0 +1,200 @@
<form>
<tab id="ipsec-general" description="General">
<!-- <field>
<id>ipsec.general.enabled</id>
<label>enabled</label>
<type>checkbox</type>
</field> -->
<field>
<id>ipsec.general.max_ikev1_exchanges</id>
<label>Maximum IKEv1 phase 2 exchanges</label>
<type>checkbox</type>
<help>
Maximum number of IKEv1 phase 2 exchanges per IKE_SA to keep state about and track concurrently.
When using multiple phase 2 definitions a higher value than the default (3) would be advisable to prevent re-keying issues
</help>
</field>
<field>
<id>ipsec.general.preferred_oldsa</id>
<label>Prefer older IPsec SAs</label>
<type>checkbox</type>
<help>
By default, if several SAs match, the newest one is preferred if it's at least 30 seconds old.
Select this option to always prefer old SAs over new ones.
</help>
</field>
<field>
<id>ipsec.general.disablevpnrules</id>
<label>Disable legacy auto-added VPN rules.</label>
<type>checkbox</type>
<help>
This option only applies to legacy tunnel configurations, connections do require manual firewall
rules being setup.
</help>
</field>
<field>
<id>ipsec.general.passthrough_networks</id>
<label>Passthrough networks</label>
<type>select_multiple</type>
<style>tokenize</style>
<help>
This exempts traffic for one or more subnets from getting processed by the IPsec stack in the kernel.
When sending all traffic to the remote location, you probably want to add your lan network(s) here.
</help>
</field>
</tab>
<tab id="ipsec-charon" description="Charon">
<field>
<id>ipsec.charon.ignore_acquire_ts</id>
<label>Ignore acquire ts</label>
<type>checkbox</type>
<help>
If this is disabled the traffic selectors from the kernels acquire events,
which are derived from the triggering packet, are prepended to the traffic selectors from the
configuration for IKEv2 connection. By enabling this, such specific traffic selectors will be ignored and
only the ones in the config will be sent.
This always happens for IKEv1 connections as the protocol only supports one set of traffic selectors per CHILD SA
</help>
</field>
<field>
<id>ipsec.charon.threads</id>
<label>Threads</label>
<type>text</type>
<help>
Number of worker threads in Several of these are reserved for long running tasks in internal modules and plugins.
Therefore, make sure you dont set this value too low.
</help>
</field>
<field>
<id>ipsec.charon.ikesa_table_size</id>
<label>IKESA table size</label>
<type>text</type>
<help>Size of the IKE SA hash table</help>
</field>
<field>
<id>ipsec.charon.ikesa_table_segments</id>
<label>IKESA table segments</label>
<type>text</type>
<help>Number of exclusively locked segments in the hash table.</help>
</field>
<field>
<id>ipsec.charon.init_limit_half_open</id>
<label>Init limit half open</label>
<type>text</type>
<help>Limit new connections based on the current number of half open IKE_SAs.</help>
</field>
</tab>
<tab id="ipsec-syslog" description="Syslog">
<field>
<type>header</type>
<label>Generic settings</label>
</field>
<field>
<id>ipsec.charon.syslog.ike_name</id>
<label>Ike Name</label>
<type>checkbox</type>
<help>Prefix each log entry with the connection name and a unique numerical identifier for each IKE_SA.</help>
</field>
<field>
<id>ipsec.charon.syslog.log_level</id>
<label>Log Level</label>
<type>checkbox</type>
<help>Add the log level of each message after the subsystem (e.g. [IKE2]).</help>
</field>
<field>
<type>header</type>
<label>Loglevel</label>
</field>
<field>
<id>ipsec.charon.syslog.daemon.app</id>
<label>Applications other than daemons</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.asn</id>
<label>Low-level encoding/decoding (ASN.1, X.509 etc.)</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.cfg</id>
<label>Configuration management and plugins</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.chd</id>
<label>CHILD_SA/IPsec SA</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.dmn</id>
<label>Main daemon setup/cleanup/signal handling</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.enc</id>
<label>Packet encoding/decoding encryption/decryption operations</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.esp</id>
<label>libipsec library messages</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.ike</id>
<label>IKE_SA/ISAKMP SA</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.imc</id>
<label>Integrity Measurement Collector</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.imv</id>
<label>Integrity Measurement Verifier</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.job</id>
<label>Jobs queuing/processing and thread pool management</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.knl</id>
<label>IPsec/Networking kernel interface</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.lib</id>
<label>libstrongwan library messages</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.mgr</id>
<label>IKE_SA manager, handling synchronization for IKE_SA access</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.net</id>
<label>IKE network communication</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.pts</id>
<label>Platform Trust Service</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.tls</id>
<label>libtls library messages</label>
<type>dropdown</type>
</field>
<field>
<id>ipsec.charon.syslog.daemon.tnc</id>
<label>Trusted Network Connect</label>
<type>dropdown</type>
</field>
</tab>
<activetab>ipsec-general</activetab>
</form>

View File

@ -0,0 +1,69 @@
<?php
/*
* Copyright (C) 2022-2023 Deciso B.V.
* 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.
*/
namespace OPNsense\IPsec\FieldTypes;
use OPNsense\Base\FieldTypes\BaseListField;
/**
* @package OPNsense\Base\FieldTypes
*/
class CharonLogLevelField extends BaseListField
{
/**
* {@inheritdoc}
*/
protected $internalDefaultValue = "1";
/**
* {@inheritdoc}
*/
protected $internalValue = "1";
/**
* {@inheritdoc}
*/
protected $internalIsRequired = true;
/**
* {@inheritdoc}
*/
protected function actionPostLoadingEvent()
{
$this->internalOptionList = [
"-1" => gettext("Absolutely silent"),
"0" => gettext("Very basic auditing logs, (e.g. SA up/SA down)"),
"1" => gettext("Generic control flow with errors (default)"),
"2" => gettext("More detailed debugging control flow"),
"3" => gettext("Including RAW data dumps in hex"),
"4" => gettext("Also include sensitive material in dumps, e.g. keys"),
];
return parent::actionPostLoadingEvent();
}
}

View File

@ -183,4 +183,31 @@ class IPsec extends BaseModel
'type' => $keyType
];
}
private function traverseItems($node)
{
$result = [];
foreach ($node->iterateItems() as $key => $item) {
if ($item->isContainer()) {
$result[$key] = $this->traverseItems($item);
} elseif (is_a($item, "OPNsense\\Base\\FieldTypes\\BooleanField")) {
$result[$key] = !empty((string)$item) ? 'yes' : 'no';
} else {
$result[$key] = (string)$item;
}
}
return $result;
}
public function strongswanTree()
{
$result = [
'# Automatically generated, please do not modify' => '',
'starter' => [
'load_warning' => 'no'
],
'charon' => $this->traverseItems($this->charon)
];
return $result;
}
}

View File

@ -1,13 +1,92 @@
<model>
<mount>//OPNsense/IPsec</mount>
<version>1.0.1</version>
<version>1.0.2</version>
<description>OPNsense IPsec</description>
<items>
<general>
<enabled type="LegacyLinkField">
<Source>ipsec.enable</Source>
</enabled>
<preferred_oldsa type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
</preferred_oldsa>
<disablevpnrules type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
</disablevpnrules>
<passthrough_networks type="NetworkField">
<FieldSeparator>,</FieldSeparator>
<asList>Y</asList>
<WildcardEnabled>N</WildcardEnabled>
</passthrough_networks>
</general>
<charon>
<max_ikev1_exchanges type="IntegerField">
<MinimumValue>0</MinimumValue>
<MaximumValue>65536</MaximumValue>
<ValidationMessage>Maximum IKEv1 phase 2 exchanges should be a positive integer number.</ValidationMessage>
</max_ikev1_exchanges>
<threads type="IntegerField">
<Default>16</Default>
<MinimumValue>1</MinimumValue>
<MaximumValue>65536</MaximumValue>
<Required>Y</Required>
</threads>
<ikesa_table_size type="IntegerField">
<Default>32</Default>
<MinimumValue>1</MinimumValue>
<MaximumValue>65536</MaximumValue>
<Required>Y</Required>
</ikesa_table_size>
<ikesa_table_segments type="IntegerField">
<Default>4</Default>
<MinimumValue>1</MinimumValue>
<MaximumValue>65536</MaximumValue>
<Required>Y</Required>
</ikesa_table_segments>
<init_limit_half_open type="IntegerField">
<Default>1000</Default>
<MinimumValue>1</MinimumValue>
<MaximumValue>65536</MaximumValue>
<Required>Y</Required>
</init_limit_half_open>
<ignore_acquire_ts type="BooleanField">
<Default>1</Default>
<Required>Y</Required>
</ignore_acquire_ts>
<syslog>
<ike_name type="BooleanField">
<Default>1</Default>
<Required>Y</Required>
</ike_name>
<log_level type="BooleanField">
<Default>0</Default>
<Required>Y</Required>
</log_level>
<daemon>
<app type=".\CharonLogLevelField"/>
<asn type=".\CharonLogLevelField"/>
<cfg type=".\CharonLogLevelField"/>
<chd type=".\CharonLogLevelField"/>
<dmn type=".\CharonLogLevelField"/>
<enc type=".\CharonLogLevelField"/>
<esp type=".\CharonLogLevelField"/>
<ike type=".\CharonLogLevelField"/>
<imc type=".\CharonLogLevelField"/>
<imv type=".\CharonLogLevelField"/>
<imv type=".\CharonLogLevelField"/>
<job type=".\CharonLogLevelField"/>
<knl type=".\CharonLogLevelField"/>
<lib type=".\CharonLogLevelField"/>
<mgr type=".\CharonLogLevelField"/>
<net type=".\CharonLogLevelField"/>
<pts type=".\CharonLogLevelField"/>
<tls type=".\CharonLogLevelField"/>
<tnc type=".\CharonLogLevelField"/>
</daemon>
</syslog>
</charon>
<keyPairs>
<keyPair type="ArrayField">
<name type="TextField">

View File

@ -11,7 +11,7 @@
</Mobile>
<Keys order="30" VisibleName="Pre-Shared Keys" url="/ui/ipsec/pre_shared_keys/"/>
<KeyPairs order="40" VisibleName="Key Pairs" url="/ui/ipsec/key_pairs" />
<Settings order="50" VisibleName="Advanced Settings" url="/vpn_ipsec_settings.php"/>
<Settings order="50" VisibleName="Advanced Settings" url="/ui/ipsec/connections/settings"/>
<Status order="60" VisibleName="Status Overview" url="/ui/ipsec/sessions"/>
<Leases order="70" VisibleName="Lease Status" url="/ui/ipsec/leases"/>
<SAD order="80" VisibleName="Security Association Database" url="/ui/ipsec/sad"/>

View File

@ -30,7 +30,7 @@ namespace OPNsense\IPsec\Migrations;
use OPNsense\Base\BaseModelMigration;
use OPNsense\Core\Config;
use OPNsense\Core\Shell;
use OPNsense\IPsec\IPsec;
class M1_0_0 extends BaseModelMigration
{
@ -39,6 +39,9 @@ class M1_0_0 extends BaseModelMigration
*/
public function post($model)
{
if (!$model instanceof IPsec) {
return;
}
$cnf = Config::getInstance()->object();
if (isset($cnf->ipsec->phase1) && isset($cnf->ipsec->phase2)) {
$reqids = [];

View File

@ -30,7 +30,7 @@ namespace OPNsense\IPsec\Migrations;
use OPNsense\Base\BaseModelMigration;
use OPNsense\Core\Config;
use OPNsense\Core\Shell;
use OPNsense\IPsec\IPsec;
class M1_0_1 extends BaseModelMigration
{
@ -39,6 +39,9 @@ class M1_0_1 extends BaseModelMigration
*/
public function run($model)
{
if (!$model instanceof IPsec) {
return;
}
$cnf = Config::getInstance()->object();
$all_idents = [];
if (isset($cnf->system->user)) {

View File

@ -0,0 +1,80 @@
<?php
/*
* Copyright (C) 2024 Deciso B.V.
* 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.
*/
namespace OPNsense\IPsec\Migrations;
use OPNsense\Base\BaseModelMigration;
use OPNsense\Core\Config;
use OPNsense\IPsec\IPsec;
class M1_0_2 extends BaseModelMigration
{
/**
* Migrate pre-shared-keys from both IPsec legacy and user administration
*/
public function run($model)
{
if (!$model instanceof IPsec) {
return;
}
$cnf = Config::getInstance()->object();
if (!isset($cnf->ipsec)) {
return;
}
$all_idents = [];
if (isset($cnf->ipsec->max_ikev1_exchanges) && $cnf->ipsec->max_ikev1_exchanges != '') {
$model->charon->max_ikev1_exchanges = (string)$cnf->ipsec->max_ikev1_exchanges;
unset($cnf->ipsec->max_ikev1_exchanges);
}
$keys = [];
foreach ($cnf->ipsec->children() as $key => $value) {
if (strpos($key, 'ipsec_') === 0 && strlen($key) == 9) {
$log_item = substr($key, 6);
$model->charon->syslog->daemon->$log_item = (string)$value;
$keys[] = $key;
}
}
foreach ($keys as $key) {
unset($cnf->ipsec->$key);
}
if (isset($cnf->ipsec->passthrough_networks) && $cnf->ipsec->passthrough_networks != '') {
$model->general->passthrough_networks = (string)$cnf->ipsec->passthrough_networks;
unset($cnf->ipsec->passthrough_networks);
}
if (isset($cnf->ipsec->disablevpnrules) && !empty((string)$cnf->ipsec->disablevpnrules)) {
$model->general->disablevpnrules = "1";
unset($cnf->ipsec->disablevpnrules);
}
if (isset($cnf->ipsec->preferred_oldsa) && !empty((string)$cnf->ipsec->preferred_oldsa)) {
$model->general->preferred_oldsa = "1";
unset($cnf->ipsec->preferred_oldsa);
}
}
}

View File

@ -0,0 +1,47 @@
<script>
$( document ).ready(function() {
$('[id*="save_"]').each(function(){
$(this).closest('tr').hide();
});
mapDataToFormUI({'mainform': '/api/ipsec/settings/get'}).done(function(){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
updateServiceControlUI('ipsec');
$("#reconfigureAct").SimpleActionButton({
onPreAction: function() {
const dfObj = new $.Deferred();
saveFormToEndpoint("/api/ipsec/settings/set", 'mainform', function(){
dfObj.resolve();
});
return dfObj;
}
});
});
});
</script>
<ul class="nav nav-tabs" role="tablist" id="maintabs">
{{ partial("layout_partials/base_tabs_header",['formData':formSettings]) }}
</ul>
<form id="mainform">
<div class="content-box tab-content">
{{ partial("layout_partials/base_tabs_content",['formData':formSettings]) }}
</div>
</form>
<div class="content-box tab-content">
<div class="col-md-12">
<br/>
<button class="btn btn-primary" id="reconfigureAct"
data-endpoint='/api/ipsec/service/reconfigure'
data-label="{{ lang._('Apply') }}"
data-error-title="{{ lang._('Error reconfiguring IPsec') }}"
type="button"
></button>
<br/><br/>
</div>
</div>

View File

@ -1,241 +0,0 @@
<?php
/*
* Copyright (C) 2014-2015 Deciso B.V.
* Copyright (C) 2014 Electric Sheep Fencing, LLC
* 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("filter.inc");
require_once("interfaces.inc");
require_once("plugins.inc.d/ipsec.inc");
config_read_array('ipsec');
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
// fetch form data
$pconfig = array();
$pconfig['disablevpnrules'] = isset($config['system']['disablevpnrules']);
$pconfig['preferoldsa_enable'] = isset($config['ipsec']['preferoldsa']);
$pconfig['max_ikev1_exchanges'] = !empty($config['ipsec']['max_ikev1_exchanges']) ? $config['ipsec']['max_ikev1_exchanges'] : null;
if (!empty($config['ipsec']['passthrough_networks'])) {
$pconfig['passthrough_networks'] = explode(',', $config['ipsec']['passthrough_networks']);
} else {
$pconfig['passthrough_networks'] = array();
}
foreach (array_keys(IPSEC_LOG_SUBSYSTEMS) as $lkey) {
if (isset($config['ipsec']["ipsec_{$lkey}"])) {
$pconfig["ipsec_{$lkey}"] = $config['ipsec']["ipsec_{$lkey}"];
} else {
$pconfig["ipsec_{$lkey}"] = '1';
}
}
} elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
$pconfig = $_POST;
// validate
$input_errors = array();
if (!empty($pconfig['passthrough_networks'])) {
foreach ($pconfig['passthrough_networks'] as $ptnet) {
if (!is_subnet($ptnet)) {
$input_errors[] = sprintf(gettext('Entry "%s" is not a valid network.'), $ptnet);
}
}
} else {
$pconfig['passthrough_networks'] = array();
}
if (!empty($pconfig['max_ikev1_exchanges']) && (
(int)$pconfig['max_ikev1_exchanges'] != $pconfig['max_ikev1_exchanges'] ||
(int)$pconfig['max_ikev1_exchanges'] < 0
)) {
$input_errors[] = gettext('Maximum IKEv1 phase 2 exchanges should be a positive integer number.');
}
// save form data
if (count($input_errors) == 0) {
if (!empty($pconfig['disablevpnrules'])) {
$config['system']['disablevpnrules'] = true;
} elseif (isset($config['system']['disablevpnrules'])) {
unset($config['system']['disablevpnrules']);
}
if (isset($pconfig['preferoldsa_enable']) && $pconfig['preferoldsa_enable'] == "yes") {
$config['ipsec']['preferoldsa'] = true;
} elseif (isset($config['ipsec']['preferoldsa'])) {
unset($config['ipsec']['preferoldsa']);
}
if (!empty($config['ipsec'])) {
foreach (array_keys(IPSEC_LOG_SUBSYSTEMS) as $lkey) {
$config['ipsec']["ipsec_{$lkey}"] = $pconfig["ipsec_{$lkey}"];
}
}
if (count($pconfig['passthrough_networks'])) {
$config['ipsec']['passthrough_networks'] = implode(',', $pconfig['passthrough_networks']);
} elseif (isset($config['ipsec']['passthrough_networks'])) {
unset($config['ipsec']['passthrough_networks']);
}
if (!empty($pconfig['max_ikev1_exchanges'])) {
$config['ipsec']['max_ikev1_exchanges'] = $pconfig['max_ikev1_exchanges'];
} elseif (isset($config['ipsec']['max_ikev1_exchanges'])) {
unset($config['ipsec']['max_ikev1_exchanges']);
}
write_config();
$savemsg = get_std_save_message();
filter_configure();
ipsec_configure_do();
}
}
$service_hook = 'strongswan';
legacy_html_escape_form_data($pconfig);
include("head.inc");
?>
<!-- JQuery Tokenize2 (https://zellerda.github.io/Tokenize2/) -->
<script src="<?= cache_safe('/ui/js/tokenize2.js') ?>"></script>
<link rel="stylesheet" type="text/css" href="<?= cache_safe(get_themed_filename('/css/tokenize2.css')) ?>">
<script src="<?= cache_safe('/ui/js/opnsense_ui.js') ?>"></script>
<script>
$( document ).ready(function() {
formatTokenizersUI();
window_highlight_table_option();
});
</script>
<body>
<?php include("fbegin.inc"); ?>
<section class="page-content-main">
<div class="container-fluid">
<div class="row">
<?php
if (isset($savemsg)) {
print_info_box($savemsg);
}
if (isset($input_errors) && count($input_errors) > 0) {
print_input_errors($input_errors);
}
?>
<section class="col-xs-12">
<div class="tab-content content-box col-xs-12">
<form method="post" name="iform" id="iform">
<div class="table-responsive">
<table class="table table-striped opnsense_standard_table_form">
<tr>
<td><strong><?=gettext("IPsec Advanced Settings"); ?></strong></td>
<td style="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><i class="fa fa-info-circle text-muted"></i> <?=gettext('Disable Auto-added VPN rules') ?></td>
<td>
<input name="disablevpnrules" type="checkbox" value="yes" <?=!empty($pconfig['disablevpnrules']) ? "checked=\"checked\"" :"";?> />
<strong><?=gettext("Disable all auto-added VPN rules.");?></strong>
</td>
</tr>
<tr>
<td><a id="help_for_preferoldsa_enable" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Security Associations"); ?></td>
<td style="width:78%" class="vtable">
<input name="preferoldsa_enable" type="checkbox" id="preferoldsa_enable" value="yes" <?= !empty($pconfig['preferoldsa_enable']) ? "checked=\"checked\"" : "";?> />
<strong><?=gettext("Prefer older IPsec SAs"); ?></strong>
<div class="hidden" data-for="help_for_preferoldsa_enable">
<?=gettext("By default, if several SAs match, the newest one is " .
"preferred if it's at least 30 seconds old. Select this " .
"option to always prefer old SAs over new ones."); ?>
</div>
</td>
</tr>
<tr>
<td><a id="help_for_passthrough_networks" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Passthrough networks"); ?></td>
<td>
<select name="passthrough_networks[]" multiple="multiple" class="tokenize" data-width="348px" data-allownew="true" data-nbdropdownelements="10">
<?php
foreach ($pconfig['passthrough_networks'] as $ptnet):?>
<option value="<?=$ptnet;?>" selected="selected"><?=$ptnet;?></option>
<?php endforeach; ?>
</select>
<div class="hidden" data-for="help_for_passthrough_networks">
<?=gettext("This exempts traffic for one or more subnets from getting processed by the IPsec stack in the kernel. ".
"When sending all traffic to the remote location, you probably want to add your lan network(s) here"); ?>
</div>
</td>
</tr>
<tr>
<td><a id="help_for_max_ikev1_exchanges" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Maximum IKEv1 phase 2 exchanges"); ?></td>
<td style="width:78%" class="vtable">
<input name="max_ikev1_exchanges" type="text" id="max_ikev1_exchanges" value="<?=$pconfig['max_ikev1_exchanges'];?>" />
<div class="hidden" data-for="help_for_max_ikev1_exchanges">
<?=gettext(
"Maximum number of IKEv1 phase 2 exchanges per IKE_SA to keep state about and track concurrently. ".
"When using multiple phase 2 definitions a higher value than the default (3) would be advisable to prevent re-keying issues."
); ?>
</div>
</td>
</tr>
<tr>
<td><a id="help_for_ipsec_debug" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("IPsec Debug"); ?></td>
<td>
<div class="hidden" data-for="help_for_ipsec_debug">
<strong><?=gettext("Start IPsec in debug mode based on sections selected"); ?></strong> <br/>
</div>
<?php foreach (IPSEC_LOG_SUBSYSTEMS as $lkey => $ldescr): ?>
<?= $ldescr ?>
<select name="ipsec_<?=$lkey?>" id="ipsec_<?=$lkey?>">
<?php foreach (IPSEC_LOG_LEVELS as $lidx => $lvalue): ?>
<option value="<?=$lidx?>" <?=$pconfig["ipsec_{$lkey}"] == $lidx ? 'selected="selected"' : '' ?>>
<?=$lvalue?>
</option>
<?php endforeach ?>
</select>
<?php endforeach ?>
<div class="hidden" data-for="help_for_ipsec_debug">
<?=gettext("Launch IPsec in debug mode so that more verbose logs will be generated to aid in troubleshooting."); ?>
</div>
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>
<input name="submit" type="submit" class="btn btn-primary" value="<?=html_safe(gettext('Save')); ?>" />
</td>
</tr>
</table>
</div>
</form>
</div>
</section>
</div>
</div>
</section>
<?php include("foot.inc");