diff --git a/src/etc/inc/plugins.inc.d/ipsec.inc b/src/etc/inc/plugins.inc.d/ipsec.inc index 05e39015e..2e6f72cae 100644 --- a/src/etc/inc/plugins.inc.d/ipsec.inc +++ b/src/etc/inc/plugins.inc.d/ipsec.inc @@ -176,7 +176,8 @@ function ipsec_interfaces() } } - foreach (ipsec_get_configured_vtis() as $intf => $details) { + $vtis = array_merge(ipsec_get_configured_vtis(), (new \OPNsense\IPsec\Swanctl())->getVtiDevices()); + foreach ($vtis as $intf => $details) { $interfaces[$intf] = [ 'enable' => true, 'descr' => preg_replace('/[^a-z_0-9]/i', '', $details['descr']), @@ -194,7 +195,8 @@ function ipsec_devices() $devices = []; $names = []; - foreach (ipsec_get_configured_vtis() as $device => $details) { + $vtis = array_merge(ipsec_get_configured_vtis(), (new \OPNsense\IPsec\Swanctl())->getVtiDevices()); + foreach ($vtis as $device => $details) { $names[$device] = [ 'descr' => sprintf('%s (%s)', $device, $details['descr']), 'ifdescr' => sprintf('%s', $details['descr']), @@ -1199,10 +1201,12 @@ function ipsec_write_secrets() foreach ((new \OPNsense\IPsec\IPsec())->preSharedKeys->preSharedKey->iterateItems() as $uuid => $psk) { $keytype = strtolower($psk->keyType); - $secrets["{$keytype}-{$uuid}"] = [ - 'id-0' => (string)$psk->ident, - 'secret' => '0s' . base64_encode((string)$psk->Key) - ]; + $dataKey = "{$keytype}-{$uuid}"; + $secrets[$dataKey] = ['id-0' => (string)$psk->ident]; + if (!empty((string)$psk->remote_ident)) { + $secrets[$dataKey]['id-1'] = (string)$psk->remote_ident; + } + $secrets[$dataKey]['secret'] = '0s' . base64_encode((string)$psk->Key); } return $secrets; @@ -1272,12 +1276,10 @@ function ipsec_configure_do($verbose = false, $interface = '') ipsec_write_certs(); ipsec_write_keypairs(); - /* begin ipsec.conf */ - $swanctl = [ - 'connections' => [], - 'pools' => [], - 'secrets' => ipsec_write_secrets() - ]; + /* begin ipsec.conf, hook mvc configuration first */ + $swanctl = (new \OPNsense\IPsec\Swanctl())->getConfig(); + $swanctl['secrets'] = ipsec_write_secrets(); + if (count($a_phase1)) { if (!empty($config['ipsec']['passthrough_networks'])) { $swanctl['connections']['pass'] = [ @@ -1652,7 +1654,7 @@ function ipsec_get_configured_vtis() function ipsec_configure_vti($verbose = false, $device = null) { // query planned and configured interfaces - $configured_intf = ipsec_get_configured_vtis(); + $configured_intf = array_merge(ipsec_get_configured_vtis(), (new \OPNsense\IPsec\Swanctl())->getVtiDevices()); $current_interfaces = []; foreach (legacy_interfaces_details() as $intf => $intf_details) { @@ -1669,14 +1671,18 @@ function ipsec_configure_vti($verbose = false, $device = null) continue; } - $local_configured = $configured_intf[$intf]['local']; - $remote_configured = $configured_intf[$intf]['remote']; + $local_configured = null; + $remote_configured = null; if (!empty($configured_intf[$intf])) { if (!is_ipaddr($configured_intf[$intf]['local'])) { $local_configured = ipsec_resolve($configured_intf[$intf]['local']); + } else { + $local_configured = $configured_intf[$intf]['local']; } if (!is_ipaddr($configured_intf[$intf]['remote'])) { $remote_configured = ipsec_resolve($configured_intf[$intf]['remote']); + } else { + $remote_configured = $configured_intf[$intf]['remote']; } } if ( diff --git a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/ConnectionsController.php b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/ConnectionsController.php new file mode 100644 index 000000000..6173dbe10 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/ConnectionsController.php @@ -0,0 +1,278 @@ +request->get('connection'); + $filter_func = null; + if (!empty($connection)) { + $filter_func = function ($record) use ($connection) { + return $record->connection == $connection; + }; + } + return $filter_func; + } + + /** + * @param array $payload result array + * @param string $topic topic used as root container + * @return array $payload with optional preselected connection defaults (to be used by children of connection) + */ + private function wrapDefaults($payload, $topic) + { + $conn_uuid = $this->request->get('connection'); + if (!empty($conn_uuid)) { + foreach ($payload[$topic]['connection'] as $key => &$value) { + if ($key == $conn_uuid) { + $value['selected'] = 1; + } else { + $value['selected'] = 0; + } + } + } + return $payload; + } + + public function searchConnectionAction() + { + return $this->searchBase( + 'Connections.Connection', + ['description', 'enabled', 'local_addrs', 'remote_addrs', 'local_ts', 'remote_ts'] + ); + } + + public function setConnectionAction($uuid = null) + { + $copy_uuid = null; + $post = $this->request->getPost('connection'); + if (empty($uuid) && !empty($post) && !empty($post['uuid'])) { + // use form provided uuid when not provided as uri parameter + $uuid = $post['uuid']; + $copy_uuid = $post['org_uuid'] ?? null; + } + $result = $this->setBase('connection', 'Connections.Connection', $uuid); + // copy children (when none exist) + if (!empty($copy_uuid) && $result['result'] != 'failed') { + $changed = False; + foreach (['locals.local', 'remotes.remote', 'children.child'] as $ref) { + $container = $this->getModel()->getNodeByReference($ref); + if ($container != null) { + $orignal_items = []; + $has_children = False; + foreach ($container->iterateItems() as $node_uuid => $node) { + if ($node->connection == $copy_uuid) { + $record = []; + foreach ($node->iterateItems() as $key => $field) { + $record[$key] = (string)$field; + } + $orignal_items[] = $record; + } elseif ($node->connection == $uuid) { + $has_children = True; + } + } + if (!$has_children) { + foreach ($orignal_items as $record) { + $node = $container->Add(); + $record['connection'] = $uuid; + $node->setNodes($record); + $changed = True; + } + } + } + } + if ($changed) { + $this->save(); + } + } + return $result; + } + + public function addConnectionAction() + { + return $this->addBase('connection', 'Connections.Connection'); + } + + public function getConnectionAction($uuid = null) + { + $result = $this->getBase('connection', 'Connections.Connection', $uuid); + if (!empty($result['connection'])) { + $fetchmode = $this->request->has("fetchmode") ? $this->request->get("fetchmode") : null; + $result['connection']['org_uuid'] = $uuid; + if (empty($uuid) || $fetchmode == 'copy') { + $result['connection']['uuid'] = $this->getModel()->Connections->generateUUID(); + } else { + $result['connection']['uuid'] = $uuid; + } + } + return $result; + } + + public function toggleConnectionAction($uuid, $enabled = null) + { + return $this->toggleBase('Connections.Connection', $uuid, $enabled); + } + + public function connectionExistsAction($uuid) + { + return [ + "exists" => isset($this->getModel()->Connections->Connection->$uuid) + ]; + } + + public function delConnectionAction($uuid) + { + // remove children + foreach (['locals.local', 'remotes.remote', 'children.child'] as $ref) { + $tmp = $this->getModel()->getNodeByReference($ref); + if ($tmp != null) { + foreach ($tmp->iterateItems() as $node_uuid => $node) { + if ($node->connection == $uuid) { + $this->delBase($ref, $node_uuid); + } + } + } + } + return $this->delBase('Connections.Connection', $uuid); + } + + public function searchLocalAction() + { + return $this->searchBase( + 'locals.local', + ['description', 'round', 'auth', 'enabled'], + 'description', + $this->connectionFilter() + ); + } + public function getLocalAction($uuid = null) + { + return $this->wrapDefaults( + $this->getBase('local', 'locals.local', $uuid), + 'local' + ); + } + public function setLocalAction($uuid = null) + { + return $this->setBase('local', 'locals.local', $uuid); + } + public function addLocalAction() + { + return $this->addBase('local', 'locals.local'); + } + public function toggleLocalAction($uuid, $enabled = null) + { + return $this->toggleBase('locals.local', $uuid, $enabled); + } + public function delLocalAction($uuid) + { + return $this->delBase('locals.local', $uuid); + } + + public function searchRemoteAction() + { + return $this->searchBase( + 'remotes.remote', + ['description', 'round', 'auth', 'enabled'], + 'description', + $this->connectionFilter() + ); + } + public function getRemoteAction($uuid = null) + { + return $this->wrapDefaults( + $this->getBase('remote', 'remotes.remote', $uuid), + 'remote' + ); + } + public function setRemoteAction($uuid = null) + { + return $this->setBase('remote', 'remotes.remote', $uuid); + } + public function addRemoteAction() + { + return $this->addBase('remote', 'remotes.remote'); + } + public function toggleRemoteAction($uuid, $enabled = null) + { + return $this->toggleBase('remotes.remote', $uuid, $enabled); + } + public function delRemoteAction($uuid) + { + return $this->delBase('remotes.remote', $uuid); + } + + public function searchChildAction() + { + return $this->searchBase( + 'children.child', + ['description', 'enabled', 'local_ts', 'remote_ts'], + 'description', + $this->connectionFilter() + ); + } + public function getChildAction($uuid = null) + { + return $this->wrapDefaults( + $this->getBase('child', 'children.child', $uuid), + 'child' + ); + } + public function setChildAction($uuid = null) + { + return $this->setBase('child', 'children.child', $uuid); + } + public function addChildAction() + { + return $this->addBase('child', 'children.child'); + } + public function toggleChildAction($uuid, $enabled = null) + { + return $this->toggleBase('children.child', $uuid, $enabled); + } + public function delChildAction($uuid) + { + return $this->delBase('children.child', $uuid); + } + +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/PoolsController.php b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/PoolsController.php new file mode 100644 index 000000000..2bb02673a --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/PoolsController.php @@ -0,0 +1,71 @@ +searchBase('Pools.Pool', ['name', 'enabled']); + } + + public function setAction($uuid = null) + { + return $this->setBase('pool', 'Pools.Pool', $uuid); + } + + public function addAction() + { + return $this->addBase('pool', 'Pools.Pool'); + } + + public function getAction($uuid = null) + { + return $this->getBase('pool', 'Pools.Pool', $uuid); + } + + public function toggleAction($uuid, $enabled = null) + { + return $this->toggleBase('Pools.Pool', $uuid, $enabled); + } + + public function delAction($uuid) + { + return $this->delBase('Pools.Pool', $uuid); + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/PreSharedKeysController.php b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/PreSharedKeysController.php index d6f278747..4a66bee16 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/PreSharedKeysController.php +++ b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/PreSharedKeysController.php @@ -46,7 +46,7 @@ class PreSharedKeysController extends ApiMutableModelControllerBase */ public function searchItemAction() { - return $this->searchBase('preSharedKeys.preSharedKey', ['ident', 'keyType']); + return $this->searchBase('preSharedKeys.preSharedKey', ['ident', 'remote_ident', 'keyType']); } /** diff --git a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/VtiController.php b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/VtiController.php new file mode 100644 index 000000000..2c1bad453 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/Api/VtiController.php @@ -0,0 +1,74 @@ +searchBase( + 'VTIs.VTI', + ['enabled', 'description', 'origin', 'reqid', 'local', 'remote', 'tunnel_local', 'tunnel_remote'] + ); + } + + public function setAction($uuid = null) + { + return $this->setBase('vti', 'VTIs.VTI', $uuid); + } + + public function addAction() + { + return $this->addBase('vti', 'VTIs.VTI'); + } + + public function getAction($uuid = null) + { + return $this->getBase('vti', 'VTIs.VTI', $uuid); + } + + public function toggleAction($uuid, $enabled = null) + { + return $this->toggleBase('VTIs.VTI', $uuid, $enabled); + } + + public function delAction($uuid) + { + return $this->delBase('VTIs.VTI', $uuid); + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/ConnectionsController.php b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/ConnectionsController.php new file mode 100644 index 000000000..e273641a9 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/ConnectionsController.php @@ -0,0 +1,42 @@ +view->pick('OPNsense/IPsec/connections'); + $this->view->formDialogConnection = $this->getForm('dialogConnection'); + $this->view->formDialogLocal = $this->getForm('dialogLocal'); + $this->view->formDialogRemote = $this->getForm('dialogRemote'); + $this->view->formDialogChild = $this->getForm('dialogChild'); + $this->view->formDialogPool = $this->getForm('dialogPool'); + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/VtiController.php b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/VtiController.php new file mode 100644 index 000000000..f631c9eea --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/VtiController.php @@ -0,0 +1,38 @@ +view->pick('OPNsense/IPsec/vti'); + $this->view->formDialogVTI = $this->getForm('dialogVTI'); + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogChild.xml b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogChild.xml new file mode 100644 index 000000000..abe6eef08 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogChild.xml @@ -0,0 +1,132 @@ +
diff --git a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogConnection.xml b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogConnection.xml new file mode 100644 index 000000000..cc47bb207 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogConnection.xml @@ -0,0 +1,234 @@ + diff --git a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogLocal.xml b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogLocal.xml new file mode 100644 index 000000000..3590e5d4c --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogLocal.xml @@ -0,0 +1,62 @@ + diff --git a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogPSK.xml b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogPSK.xml index 19552c757..27b63716e 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogPSK.xml +++ b/src/opnsense/mvc/app/controllers/OPNsense/IPsec/forms/dialogPSK.xml @@ -1,10 +1,16 @@