diff --git a/plist b/plist index bba087a26..cceea7c91 100644 --- a/plist +++ b/plist @@ -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 diff --git a/src/etc/inc/plugins.inc.d/ipsec.inc b/src/etc/inc/plugins.inc.d/ipsec.inc index 4d77fe613..e6737de8a 100644 --- a/src/etc/inc/plugins.inc.d/ipsec.inc +++ b/src/etc/inc/plugins.inc.d/ipsec.inc @@ -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' ] diff --git a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/SettingsController.php b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/SettingsController.php new file mode 100644 index 000000000..7a38bcb81 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/SettingsController.php @@ -0,0 +1,55 @@ + [ + 'general' => $data[self::$internalModelName]['general'], + 'charon' => $data[self::$internalModelName]['charon'], + ] + ]; + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/ConnectionsController.php b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/ConnectionsController.php index e273641a9..c7dfa4574 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/ConnectionsController.php +++ b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/ConnectionsController.php @@ -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'); + } } diff --git a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/settings.xml b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/settings.xml new file mode 100644 index 000000000..1864db80b --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/settings.xml @@ -0,0 +1,200 @@ +
+ + + + ipsec.general.max_ikev1_exchanges + + checkbox + + 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 + + + + ipsec.general.preferred_oldsa + + checkbox + + 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. + + + + ipsec.general.disablevpnrules + + checkbox + + This option only applies to legacy tunnel configurations, connections do require manual firewall + rules being setup. + + + + ipsec.general.passthrough_networks + + select_multiple + + + 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. + + + + + + ipsec.charon.ignore_acquire_ts + + checkbox + + If this is disabled the traffic selectors from the kernel’s 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 + + + + ipsec.charon.threads + + text + + Number of worker threads in Several of these are reserved for long running tasks in internal modules and plugins. + Therefore, make sure you don’t set this value too low. + + + + ipsec.charon.ikesa_table_size + + text + Size of the IKE SA hash table + + + ipsec.charon.ikesa_table_segments + + text + Number of exclusively locked segments in the hash table. + + + ipsec.charon.init_limit_half_open + + text + Limit new connections based on the current number of half open IKE_SAs. + + + + + header + + + + ipsec.charon.syslog.ike_name + + checkbox + Prefix each log entry with the connection name and a unique numerical identifier for each IKE_SA. + + + ipsec.charon.syslog.log_level + + checkbox + Add the log level of each message after the subsystem (e.g. [IKE2]). + + + header + + + + ipsec.charon.syslog.daemon.app + + dropdown + + + ipsec.charon.syslog.daemon.asn + + dropdown + + + ipsec.charon.syslog.daemon.cfg + + dropdown + + + ipsec.charon.syslog.daemon.chd + + dropdown + + + ipsec.charon.syslog.daemon.dmn + + dropdown + + + ipsec.charon.syslog.daemon.enc + + dropdown + + + ipsec.charon.syslog.daemon.esp + + dropdown + + + ipsec.charon.syslog.daemon.ike + + dropdown + + + ipsec.charon.syslog.daemon.imc + + dropdown + + + ipsec.charon.syslog.daemon.imv + + dropdown + + + ipsec.charon.syslog.daemon.job + + dropdown + + + ipsec.charon.syslog.daemon.knl + + dropdown + + + ipsec.charon.syslog.daemon.lib + + dropdown + + + ipsec.charon.syslog.daemon.mgr + + dropdown + + + ipsec.charon.syslog.daemon.net + + dropdown + + + ipsec.charon.syslog.daemon.pts + + dropdown + + + ipsec.charon.syslog.daemon.tls + + dropdown + + + ipsec.charon.syslog.daemon.tnc + + dropdown + + + ipsec-general +
\ No newline at end of file diff --git a/src/opnsense/mvc/app/models/OPNsense/IPsec/FieldTypes/CharonLogLevelField.php b/src/opnsense/mvc/app/models/OPNsense/IPsec/FieldTypes/CharonLogLevelField.php new file mode 100644 index 000000000..8c12deaa8 --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/IPsec/FieldTypes/CharonLogLevelField.php @@ -0,0 +1,69 @@ +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(); + } +} diff --git a/src/opnsense/mvc/app/models/OPNsense/IPsec/IPsec.php b/src/opnsense/mvc/app/models/OPNsense/IPsec/IPsec.php index 48c39fa18..a918fcf65 100644 --- a/src/opnsense/mvc/app/models/OPNsense/IPsec/IPsec.php +++ b/src/opnsense/mvc/app/models/OPNsense/IPsec/IPsec.php @@ -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; + } } diff --git a/src/opnsense/mvc/app/models/OPNsense/IPsec/IPsec.xml b/src/opnsense/mvc/app/models/OPNsense/IPsec/IPsec.xml index a9bdbe071..fbcade759 100644 --- a/src/opnsense/mvc/app/models/OPNsense/IPsec/IPsec.xml +++ b/src/opnsense/mvc/app/models/OPNsense/IPsec/IPsec.xml @@ -1,13 +1,92 @@ //OPNsense/IPsec - 1.0.1 + 1.0.2 OPNsense IPsec ipsec.enable + + 0 + Y + + + 0 + Y + + + , + Y + N + + + + 0 + 65536 + Maximum IKEv1 phase 2 exchanges should be a positive integer number. + + + 16 + 1 + 65536 + Y + + + 32 + 1 + 65536 + Y + + + 4 + 1 + 65536 + Y + + + 1000 + 1 + 65536 + Y + + + 1 + Y + + + + 1 + Y + + + 0 + Y + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/opnsense/mvc/app/models/OPNsense/IPsec/Menu/Menu.xml b/src/opnsense/mvc/app/models/OPNsense/IPsec/Menu/Menu.xml index 2a1a19ec3..8e9a6232f 100644 --- a/src/opnsense/mvc/app/models/OPNsense/IPsec/Menu/Menu.xml +++ b/src/opnsense/mvc/app/models/OPNsense/IPsec/Menu/Menu.xml @@ -11,7 +11,7 @@ - + diff --git a/src/opnsense/mvc/app/models/OPNsense/IPsec/Migrations/M1_0_0.php b/src/opnsense/mvc/app/models/OPNsense/IPsec/Migrations/M1_0_0.php index ca917b70b..0a3f07fd7 100644 --- a/src/opnsense/mvc/app/models/OPNsense/IPsec/Migrations/M1_0_0.php +++ b/src/opnsense/mvc/app/models/OPNsense/IPsec/Migrations/M1_0_0.php @@ -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 = []; diff --git a/src/opnsense/mvc/app/models/OPNsense/IPsec/Migrations/M1_0_1.php b/src/opnsense/mvc/app/models/OPNsense/IPsec/Migrations/M1_0_1.php index 6ce8c2e2a..26e0af49b 100644 --- a/src/opnsense/mvc/app/models/OPNsense/IPsec/Migrations/M1_0_1.php +++ b/src/opnsense/mvc/app/models/OPNsense/IPsec/Migrations/M1_0_1.php @@ -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)) { diff --git a/src/opnsense/mvc/app/models/OPNsense/IPsec/Migrations/M1_0_2.php b/src/opnsense/mvc/app/models/OPNsense/IPsec/Migrations/M1_0_2.php new file mode 100644 index 000000000..868dbc167 --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/IPsec/Migrations/M1_0_2.php @@ -0,0 +1,80 @@ +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); + } + } +} diff --git a/src/opnsense/mvc/app/views/OPNsense/IPsec/settings.volt b/src/opnsense/mvc/app/views/OPNsense/IPsec/settings.volt new file mode 100644 index 000000000..444021516 --- /dev/null +++ b/src/opnsense/mvc/app/views/OPNsense/IPsec/settings.volt @@ -0,0 +1,47 @@ + + + + +
+
+ {{ partial("layout_partials/base_tabs_content",['formData':formSettings]) }} +
+
+ +
+
+
+ +

+
+
diff --git a/src/www/vpn_ipsec_settings.php b/src/www/vpn_ipsec_settings.php deleted file mode 100644 index e4854e263..000000000 --- a/src/www/vpn_ipsec_settings.php +++ /dev/null @@ -1,241 +0,0 @@ - - - - - - - - - - - - -
-
-
- - 0) { - print_input_errors($input_errors); -} -?> -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
- /> - -
- /> - - -
- - -
- - -
- - $ldescr): ?> - - - - -
  - -
-
-
-
-
-
-
-
-