mirror of
https://github.com/lucaspalomodevelop/core.git
synced 2026-03-15 09:04:39 +00:00
VPN/IPsec add new MVC module (#6187)
Add new component to manage IPsec connections in a similar format as `swanctl.conf` is defined (https://docs.strongswan.org/docs/5.9/swanctl/swanctlConf.html). As this needs to work in conjunction with the legacy IPsec module, some minor changes are needed to the current state. o VPN/IPsec/Pre-Shared Keys - add optional remote identifier (merges in `ipsec.inc`) o VPN/IPsec/Virtual Tunnel Interfaces - new component to show existing VTI's and add new ones (as these are separate entities) o VPN/IPsec/Connections [new] - configuration tool to build `swanctl.conf` o Integrate MVC generated `swanctl.conf` into `ipsec.inc` (legacy overlays) o Integrate manually configured VTI's into `ipsec.inc` (`array_merge(ipsec_get_configured_vtis(), (new \OPNsense\IPsec\Swanctl())->getVtiDevices())`) o fix minor php warning when changing reqid's (`$local|remote_configured` initialisation when `$configured_intf[$intf]` not found)
This commit is contained in:
parent
d25318a483
commit
5752bd6eb3
@ -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 (
|
||||
|
||||
@ -0,0 +1,278 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 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 ConnectionsController
|
||||
* @package OPNsense\IPsec\Api
|
||||
*/
|
||||
class ConnectionsController extends ApiMutableModelControllerBase
|
||||
{
|
||||
protected static $internalModelName = 'swanctl';
|
||||
protected static $internalModelClass = 'OPNsense\IPsec\Swanctl';
|
||||
|
||||
/**
|
||||
* @return null|function lambda to filter on provided connection uuid in GET['connection']
|
||||
*/
|
||||
private function connectionFilter()
|
||||
{
|
||||
$connection = $this->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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 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 PoolsController
|
||||
* @package OPNsense\IPsec\Api
|
||||
*/
|
||||
class PoolsController extends ApiMutableModelControllerBase
|
||||
{
|
||||
protected static $internalModelName = 'swanctl';
|
||||
protected static $internalModelClass = 'OPNsense\IPsec\Swanctl';
|
||||
|
||||
public function searchAction()
|
||||
{
|
||||
return $this->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);
|
||||
}
|
||||
}
|
||||
@ -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']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 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 VtiController
|
||||
* @package OPNsense\IPsec\Api
|
||||
*/
|
||||
class VtiController extends ApiMutableModelControllerBase
|
||||
{
|
||||
protected static $internalModelName = 'swanctl';
|
||||
protected static $internalModelClass = 'OPNsense\IPsec\Swanctl';
|
||||
|
||||
public function searchAction()
|
||||
{
|
||||
return $this->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);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 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;
|
||||
|
||||
class ConnectionsController extends \OPNsense\Base\IndexController
|
||||
{
|
||||
public function indexAction()
|
||||
{
|
||||
$this->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');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 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;
|
||||
|
||||
class VtiController extends \OPNsense\Base\IndexController
|
||||
{
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->pick('OPNsense/IPsec/vti');
|
||||
$this->view->formDialogVTI = $this->getForm('dialogVTI');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,132 @@
|
||||
<form>
|
||||
<field>
|
||||
<id>child.enabled</id>
|
||||
<label>enabled</label>
|
||||
<type>checkbox</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>child.connection</id>
|
||||
<label>Connection</label>
|
||||
<type>dropdown</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>child.sha256_96</id>
|
||||
<label>sha256_96</label>
|
||||
<type>checkbox</type>
|
||||
<help>
|
||||
HMAC-SHA-256 is used with 128-bit truncation with IPsec.
|
||||
For compatibility with implementations that incorrectly use 96-bit truncation this option may be enabled to
|
||||
configure the shorter truncation length in the kernel.
|
||||
This is not negotiated, so this only works with peers that use the incorrect truncation length (or have this option enabled)
|
||||
</help>
|
||||
<advanced>true</advanced>
|
||||
</field>
|
||||
<field>
|
||||
<id>child.mode</id>
|
||||
<label>Mode</label>
|
||||
<type>dropdown</type>
|
||||
<help>
|
||||
IPsec Mode to establish CHILD_SA with.
|
||||
tunnel negotiates the CHILD_SA in IPsec Tunnel Mode whereas transport uses IPsec Transport Mode.
|
||||
pass and drop are used to install shunt policies which explicitly bypass the defined traffic from IPsec processing or drop it, respectively.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>child.policies</id>
|
||||
<label>Policies</label>
|
||||
<type>checkbox</type>
|
||||
<help>
|
||||
Whether to install IPsec policies or not.
|
||||
Disabling this can be useful in some scenarios e.g. VTI where policies are not managed by the IKE daemon
|
||||
</help>
|
||||
<advanced>true</advanced>
|
||||
</field>
|
||||
<field>
|
||||
<id>child.start_action</id>
|
||||
<label>Start action</label>
|
||||
<type>dropdown</type>
|
||||
<help>
|
||||
Action to perform after loading the configuration.
|
||||
The default of none loads the connection only, which then can be manually initiated or used as a responder configuration.
|
||||
The value trap installs a trap policy which triggers the tunnel as soon as matching traffic has been detected.
|
||||
The value start initiates the connection actively.
|
||||
To immediately initiate a connection for which trap policies have been installed, user Trap+start.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>child.close_action</id>
|
||||
<label>Close action</label>
|
||||
<type>dropdown</type>
|
||||
<advanced>true</advanced>
|
||||
<help>
|
||||
Action to perform after a CHILD_SA gets closed by the peer.
|
||||
The default of none does not take any action.
|
||||
trap installs a trap policy for the CHILD_SA (note that this is redundant if start_action includes trap).
|
||||
start tries to immediately re-create the CHILD_SA.
|
||||
|
||||
close_action does not provide any guarantee that the CHILD_SA is kept alive.
|
||||
It acts on explicit close messages only but not on negotiation failures.
|
||||
Use trap policies to reliably re-create failed CHILD_SAs
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>child.dpd_action</id>
|
||||
<label>DPD action</label>
|
||||
<type>dropdown</type>
|
||||
<help>
|
||||
Action to perform for this CHILD_SA on DPD timeout.
|
||||
The default clear closes the CHILD_SA and does not take further action.
|
||||
trap installs a trap policy, which will catch matching traffic and tries to re-negotiate the tunnel on-demand
|
||||
(note that this is redundant if start_action includes trap.
|
||||
restart immediately tries to re-negotiate the CHILD_SA under a fresh IKE_SA.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>child.reqid</id>
|
||||
<label>Reqid</label>
|
||||
<type>text</type>
|
||||
<help>
|
||||
This might be helpful in some scenarios, like route based tunnels (VTI), but works only if each CHILD_SA configuration is instantiated not more than once.
|
||||
The default uses dynamic reqids, allocated incrementally
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>child.esp_proposals</id>
|
||||
<label>ESP proposals</label>
|
||||
<type>select_multiple</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>child.local_ts</id>
|
||||
<label>Local</label>
|
||||
<type>select_multiple</type>
|
||||
<style>tokenize</style>
|
||||
<allownew>true</allownew>
|
||||
<help>List of local traffic selectors to include in CHILD_SA. Each selector is a CIDR subnet definition.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>child.remote_ts</id>
|
||||
<label>Remote</label>
|
||||
<type>select_multiple</type>
|
||||
<style>tokenize</style>
|
||||
<allownew>true</allownew>
|
||||
<help>List of remote traffic selectors to include in CHILD_SA. Each selector is a CIDR subnet definition.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>child.rekey_time</id>
|
||||
<label>Rekey time (s)</label>
|
||||
<type>text</type>
|
||||
<help>
|
||||
Time to schedule CHILD_SA rekeying.
|
||||
CHILD_SA rekeying refreshes key material, optionally using a Diffie-Hellman exchange if a group is specified in the proposal.
|
||||
To avoid rekey collisions initiated by both ends simultaneously, a value in the range of rand_time
|
||||
gets subtracted to form the effective soft lifetime.
|
||||
By default CHILD_SA rekeying is scheduled every hour, minus rand_time
|
||||
</help>
|
||||
<advanced>true</advanced>
|
||||
</field>
|
||||
<field>
|
||||
<id>child.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
</form>
|
||||
@ -0,0 +1,234 @@
|
||||
<form>
|
||||
<field>
|
||||
<id>connection.uuid</id>
|
||||
<label>uuid</label>
|
||||
<type>text</type>
|
||||
<style>hidden_attr</style>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.org_uuid</id>
|
||||
<label>orignal uuid</label>
|
||||
<type>text</type>
|
||||
<style>hidden_attr</style>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.enabled</id>
|
||||
<label>enabled</label>
|
||||
<type>checkbox</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.proposals</id>
|
||||
<label>Proposals</label>
|
||||
<type>select_multiple</type>
|
||||
<help>
|
||||
A proposal is a set of algorithms.
|
||||
For non-AEAD algorithms this includes IKE an encryption algorithm, an integrity algorithm,
|
||||
a pseudo random function (PRF) and a Diffie-Hellman key exchange group.
|
||||
For AEAD algorithms, instead of encryption and integrity algorithms a combined algorithm is used.
|
||||
With IKEv2 multiple algorithms of the same kind can be specified in a single proposal, from which one gets selected.
|
||||
For IKEv1 only one algorithm per kind is allowed per proposal, more algorithms get implicitly stripped.
|
||||
Use multiple proposals to offer different algorithm combinations with IKEv1. Algorithm keywords get separated using dashes.
|
||||
Multiple proposals may be separated by commas.
|
||||
The special value default adds a default proposal of supported algorithms considered safe and is usually a good choice for interoperability.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.unique</id>
|
||||
<label>Unique</label>
|
||||
<type>dropdown</type>
|
||||
<help>Connection uniqueness policy to enforce.
|
||||
To avoid multiple connections from the same user, a uniqueness policy can be enforced.
|
||||
</help>
|
||||
<advanced>true</advanced>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.aggressive</id>
|
||||
<label>Aggressive</label>
|
||||
<type>checkbox</type>
|
||||
<advanced>true</advanced>
|
||||
<help>
|
||||
Enables IKEv1 Aggressive Mode instead of IKEv1 Main Mode with Identity Protection.
|
||||
Aggressive Mode is considered less secure because the ID and HASH payloads are exchanged unprotected.
|
||||
This allows a passive attacker to snoop peer identities and even worse, start dictionary attacks on the Preshared Key
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.version</id>
|
||||
<label>Version</label>
|
||||
<type>dropdown</type>
|
||||
<help>
|
||||
IKE major version to use for connection. 1 uses IKEv1 aka ISAKMP, 2 uses IKEv2.
|
||||
A connection using IKEv1+IKEv2 accepts both IKEv1 and IKEv2 as a responder
|
||||
and initiates the connection actively with IKEv2
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.mobike</id>
|
||||
<label>MOBIKE</label>
|
||||
<type>checkbox</type>
|
||||
<help>
|
||||
Enables MOBIKE on IKEv2 connections.
|
||||
MOBIKE is enabled by default on IKEv2 connections and allows mobility of clients and multi-homing on servers
|
||||
by migrating active IPsec tunnels.
|
||||
Usually keeping MOBIKE enabled is unproblematic, as it is not used if the peer does not indicate support for it.
|
||||
However, due to the design of MOBIKE, IKEv2 always floats to UDP port 4500 starting from the second exchange.
|
||||
Some implementations don’t like this behavior, hence it can be disabled
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.local_addrs</id>
|
||||
<label>Local addresses</label>
|
||||
<type>select_multiple</type>
|
||||
<style>tokenize</style>
|
||||
<allownew>true</allownew>
|
||||
<help>
|
||||
Local address[es] to use for IKE communication.
|
||||
Accepts single IPv4/IPv6 addresses, DNS names, CIDR subnets or IP address ranges.
|
||||
As an initiator, the first non-range/non-subnet is used to initiate the connection from.
|
||||
As a responder the local destination address must match at least to one of the specified addresses, subnets or ranges.
|
||||
If FQDNs are assigned, they are resolved every time a configuration lookup is done.
|
||||
If DNS resolution times out, the lookup is delayed for that time. When left empty %any is choosen as default.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.remote_addrs</id>
|
||||
<label>Remote addresses</label>
|
||||
<type>select_multiple</type>
|
||||
<style>tokenize</style>
|
||||
<allownew>true</allownew>
|
||||
<help>
|
||||
Remote address[es] to use for IKE communication.
|
||||
Accepts single IPv4/IPv6 addresses, DNS names, CIDR subnets or IP address ranges.
|
||||
As an initiator, the first non-range/non-subnet is used to initiate the connection to.
|
||||
As a responder, the initiator source address must match at least to one of the specified addresses, subnets or ranges.
|
||||
If FQDNs are assigned they are resolved every time a configuration lookup is done.
|
||||
If DNS resolution times out, the lookup is delayed for that time.
|
||||
To initiate a connection, at least one specific address or DNS name must be specified.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.encap</id>
|
||||
<label>UDP encapsulation</label>
|
||||
<type>checkbox</type>
|
||||
<advanced>true</advanced>
|
||||
<help>
|
||||
To enforce UDP encapsulation of ESP packets, the IKE daemon can manipulate the NAT detection payloads.
|
||||
This makes the peer believe that a NAT situation exist on the transmission path, forcing it to encapsulate ESP packets in UDP.
|
||||
Usually this is not required but it can help to work around connectivity issues with too restrictive intermediary
|
||||
firewalls that block ESP packets
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.reauth_time</id>
|
||||
<label>Re-auth time (s)</label>
|
||||
<type>text</type>
|
||||
<advanced>true</advanced>
|
||||
<help>
|
||||
Time to schedule IKE reauthentication.
|
||||
IKE reauthentication recreates the IKE/ISAKMP SA from scratch and re-evaluates the credentials.
|
||||
In asymmetric configurations (with EAP or configuration payloads) it might not be possible to actively reauthenticate as responder.
|
||||
The IKEv2 reauthentication lifetime negotiation can instruct the client to perform reauthentication.
|
||||
Reauthentication is disabled by default (0).
|
||||
Enabling it usually may lead to small connection interruptions as strongSwan uses a break-before-make policy with IKEv2 by default.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.rekey_time</id>
|
||||
<label>Rekey time (s)</label>
|
||||
<type>text</type>
|
||||
<advanced>true</advanced>
|
||||
<help>
|
||||
IKE rekeying refreshes key material using a Diffie-Hellman key exchange, but does not re-check associated credentials.
|
||||
It is supported with IKEv2 only. IKEv1 performs a reauthentication procedure instead.
|
||||
With the default value, IKE rekeying is scheduled every 4 hours minus the configured rand_time.
|
||||
If a reauth_time is configured, rekey_time defaults to zero, disabling rekeying.
|
||||
In that case set rekey_time explicitly to both enforce rekeying and reauthentication
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.over_time</id>
|
||||
<label>Over time (s)</label>
|
||||
<type>text</type>
|
||||
<advanced>true</advanced>
|
||||
<help>
|
||||
Hard IKE_SA lifetime if rekey/reauth does not complete, as time.
|
||||
To avoid having an IKE or ISAKMP connection kept alive if IKE reauthentication or rekeying fails perpetually,
|
||||
a maximum hard lifetime may be specified.
|
||||
If the IKE_SA fails to rekey or reauthenticate within the specified time, the IKE_SA gets closed.
|
||||
In contrast to CHILD_SA rekeying, over_time is relative in time to the rekey_time and reauth_time values, as it applies to both.
|
||||
The default is 10% of either rekey_time or reauth_time, whichever value is larger. [0.1 * max(rekey_time, reauth_time)]
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.dpd_delay</id>
|
||||
<label>DPD delay (s)</label>
|
||||
<type>text</type>
|
||||
<help>
|
||||
Interval to check the liveness of a peer actively using IKEv2 INFORMATIONAL exchanges or IKEv1 R_U_THERE messages.
|
||||
Active DPD checking is only enforced if no IKE or ESP/AH packet has been received for the configured DPD delay. Defaults to 0s
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.dpd_timeout</id>
|
||||
<label>DPD timeout (s)</label>
|
||||
<type>text</type>
|
||||
<advanced>true</advanced>
|
||||
<help>
|
||||
Charon by default uses the normal retransmission mechanism and timeouts to check the liveness of a peer,
|
||||
as all messages are used for liveness checking.
|
||||
For compatibility reasons, with IKEv1 a custom interval may be specified.
|
||||
This option has no effect on IKEv2 connections
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.pools</id>
|
||||
<label>Pools</label>
|
||||
<type>select_multiple</type>
|
||||
<help>
|
||||
List of named IP pools to allocate virtual IP addresses and other configuration attributes from.
|
||||
Each name references a pool by name from either the pools section or an external pool.
|
||||
Note that the order in which they are queried primarily depends on the plugin order.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.send_certreq</id>
|
||||
<label>Send cert req</label>
|
||||
<type>checkbox</type>
|
||||
<advanced>true</advanced>
|
||||
<help>
|
||||
Send certificate request payloads to offer trusted root CA certificates to the peer.
|
||||
Certificate requests help the peer to choose an appropriate certificate/private key for authentication and are enabled by default.
|
||||
Disabling certificate requests can be useful if too many trusted root CA certificates are installed,
|
||||
as each certificate request increases the size of the initial IKE packets
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.send_cert</id>
|
||||
<label>Send certificate</label>
|
||||
<type>dropdown</type>
|
||||
<advanced>true</advanced>
|
||||
<help>
|
||||
Send certificate payloads when using certificate authentication.
|
||||
With the default of [ifasked] the daemon sends certificate payloads only if certificate requests have been received.
|
||||
[never] disables sending of certificate payloads altogether whereas [always] causes certificate payloads to be sent unconditionally
|
||||
whenever certificate-based authentication is used.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.keyingtries</id>
|
||||
<label>Keyingtries</label>
|
||||
<type>text</type>
|
||||
<advanced>true</advanced>
|
||||
<help>
|
||||
Number of retransmission sequences to perform during initial connect.
|
||||
Instead of giving up initiation after the first retransmission sequence with the default value of 1,
|
||||
additional sequences may be started according to the configured value.
|
||||
A value of 0 initiates a new sequence until the connection establishes or fails with a permanent error
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connection.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
</form>
|
||||
@ -0,0 +1,62 @@
|
||||
<form>
|
||||
<field>
|
||||
<id>local.enabled</id>
|
||||
<label>enabled</label>
|
||||
<type>checkbox</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>local.connection</id>
|
||||
<label>Connection</label>
|
||||
<type>dropdown</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>local.round</id>
|
||||
<label>Round</label>
|
||||
<type>text</type>
|
||||
<help>Numeric identifier by which authentication rounds are sorted.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>local.auth</id>
|
||||
<label>Authentication</label>
|
||||
<type>dropdown</type>
|
||||
<help>Authentication to perform for this round, when using Pre-Shared key make sure to define one under "VPN->IPsec->Pre-Shared Keys"</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>local.id</id>
|
||||
<label>Id</label>
|
||||
<type>text</type>
|
||||
<help>IKE identity to use for authentication round.
|
||||
When using certificate authentication.
|
||||
The IKE identity must be contained in the certificate,
|
||||
either as the subject DN or as a subjectAltName
|
||||
(the identity will default to the certificate’s subject DN if not specified).
|
||||
Refer to https://docs.strongswan.org/docs/5.9/config/identityParsing.html for details on how
|
||||
identities are parsed and may be configured.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>local.eap_id</id>
|
||||
<label>EAP Id</label>
|
||||
<type>text</type>
|
||||
<help>Client EAP-Identity to use in EAP-Identity exchange and the EAP method</help>
|
||||
<style>local_auth local_auth_eap-mschapv2 local_auth_eap-tls local_auth_eap-radius</style>
|
||||
</field>
|
||||
<field>
|
||||
<id>local.certs</id>
|
||||
<label>Certificates</label>
|
||||
<type>select_multiple</type>
|
||||
<help>List of certificate candidates to use for authentication.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>local.pubkeys</id>
|
||||
<label>Public Keys</label>
|
||||
<type>select_multiple</type>
|
||||
<help>List of raw public key candidates to use for authentication.</help>
|
||||
<style>local_auth local_auth_pubkey</style>
|
||||
</field>
|
||||
<field>
|
||||
<id>local.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
</form>
|
||||
@ -1,10 +1,16 @@
|
||||
<form>
|
||||
<field>
|
||||
<id>preSharedKey.ident</id>
|
||||
<label>Identifier</label>
|
||||
<label>Local Identifier</label>
|
||||
<type>text</type>
|
||||
<help>This can be either an IP address, fully qualified domain name or an email address.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>preSharedKey.remote_ident</id>
|
||||
<label>Remote Identifier</label>
|
||||
<type>text</type>
|
||||
<help>(optional) This can be either an IP address, fully qualified domain name or an email address to identify the remote host.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>preSharedKey.Key</id>
|
||||
<label>Pre-Shared Key</label>
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
<form>
|
||||
<field>
|
||||
<id>pool.enabled</id>
|
||||
<label>enabled</label>
|
||||
<type>checkbox</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>pool.name</id>
|
||||
<label>Name</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>pool.addrs</id>
|
||||
<label>Network</label>
|
||||
<type>text</type>
|
||||
<help>
|
||||
Subnet or range defining addresses allocated in pool.
|
||||
Accepts a single CIDR subnet defining the pool to allocate addresses from
|
||||
</help>
|
||||
</field>
|
||||
|
||||
</form>
|
||||
@ -0,0 +1,62 @@
|
||||
<form>
|
||||
<field>
|
||||
<id>remote.enabled</id>
|
||||
<label>enabled</label>
|
||||
<type>checkbox</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>remote.connection</id>
|
||||
<label>Connection</label>
|
||||
<type>dropdown</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>remote.round</id>
|
||||
<label>Round</label>
|
||||
<type>text</type>
|
||||
<help>Numeric identifier by which authentication rounds are sorted.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>remote.auth</id>
|
||||
<label>Authentication</label>
|
||||
<type>dropdown</type>
|
||||
<help>Authentication to perform for this round</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>remote.id</id>
|
||||
<label>Id</label>
|
||||
<type>text</type>
|
||||
<help>IKE identity to use for authentication round.
|
||||
When using certificate authentication.
|
||||
The IKE identity must be contained in the certificate,
|
||||
either as the subject DN or as a subjectAltName
|
||||
(the identity will default to the certificate’s subject DN if not specified).
|
||||
Refer to https://docs.strongswan.org/docs/5.9/config/identityParsing.html for details on how
|
||||
identities are parsed and may be configured.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>remote.eap_id</id>
|
||||
<label>EAP Id</label>
|
||||
<type>text</type>
|
||||
<help>Client EAP-Identity to use in EAP-Identity exchange and the EAP method</help>
|
||||
<style>remote_auth remote_auth_eap-mschapv2 remote_auth_eap-tls remote_auth_eap-radius</style>
|
||||
</field>
|
||||
<field>
|
||||
<id>remote.certs</id>
|
||||
<label>Certificates</label>
|
||||
<type>select_multiple</type>
|
||||
<help>List of certificate candidates to use for authentication.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>remote.pubkeys</id>
|
||||
<label>Public Keys</label>
|
||||
<type>select_multiple</type>
|
||||
<help>List of raw public key candidates to use for authentication.</help>
|
||||
<style>remote_auth remote_auth_pubkey</style>
|
||||
</field>
|
||||
<field>
|
||||
<id>remote.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
</form>
|
||||
@ -0,0 +1,47 @@
|
||||
<form>
|
||||
<field>
|
||||
<id>vti.enabled</id>
|
||||
<label>enabled</label>
|
||||
<type>checkbox</type>
|
||||
</field>
|
||||
<field>
|
||||
<id>vti.reqid</id>
|
||||
<label>Reqid</label>
|
||||
<type>text</type>
|
||||
<help>
|
||||
This id is used to distinguish traffic and security policies between several if_ipsec interfaces.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>vti.local</id>
|
||||
<label>Local address</label>
|
||||
<type>text</type>
|
||||
<help>Local tunnel address used for the outer IP header of ESP packets</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>vti.remote</id>
|
||||
<label>Remote address</label>
|
||||
<type>text</type>
|
||||
<help>Remote tunnel address used for the outer IP header of ESP packets</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>vti.tunnel_local</id>
|
||||
<label>Tunnel local address</label>
|
||||
<type>text</type>
|
||||
<help>Inner tunnel local address to be used for routing purposes.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>vti.tunnel_remote</id>
|
||||
<label>Tunnel remote address</label>
|
||||
<type>text</type>
|
||||
<help>
|
||||
Inner tunnel remote address to be used for routing purposes.
|
||||
The size of the subnet containing local and remote will be calculated automatically
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>vti.description</id>
|
||||
<label>Name</label>
|
||||
<type>text</type>
|
||||
</field>
|
||||
</form>
|
||||
@ -17,6 +17,17 @@
|
||||
<pattern>api/ipsec/legacy-subsystem/*</pattern>
|
||||
</patterns>
|
||||
</page-vpn-ipsec>
|
||||
<page-vpn-ipsec-connections>
|
||||
<name>VPN: IPsec connections [new]</name>
|
||||
<patterns>
|
||||
<pattern>ui/ipsec/connections</pattern>
|
||||
<pattern>ui/ipsec/vti</pattern>
|
||||
<pattern>api/ipsec/connections/*</pattern>
|
||||
<pattern>api/ipsec/pools/*</pattern>
|
||||
<pattern>api/ipsec/vti/*</pattern>
|
||||
<pattern>api/ipsec/legacy-subsystem/*</pattern>
|
||||
</patterns>
|
||||
</page-vpn-ipsec-connections>
|
||||
|
||||
<!-- ACLs for legacy code -->
|
||||
<page-vpn-ipsec-editphase1>
|
||||
|
||||
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2022 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\ArrayField;
|
||||
use OPNsense\Base\FieldTypes\TextField;
|
||||
|
||||
class ConnnectionField extends ArrayField
|
||||
{
|
||||
private static $child_attrs = ['local_ts', 'remote_ts'];
|
||||
private static $child_data = null;
|
||||
|
||||
/**
|
||||
* Add child attributes (virtual / read-only) to connection for query purposes
|
||||
*/
|
||||
protected function actionPostLoadingEvent()
|
||||
{
|
||||
if (self::$child_data === null) {
|
||||
self::$child_data = [];
|
||||
foreach ($this->getParentModel()->children->child->iterateItems() as $node_uuid => $node) {
|
||||
if (empty((string)$node->enabled)) {
|
||||
continue;
|
||||
}
|
||||
$conn_uuid = (string)$node->connection;
|
||||
if (!isset(self::$child_data[$conn_uuid])) {
|
||||
self::$child_data[$conn_uuid] = [];
|
||||
}
|
||||
foreach (self::$child_attrs as $key) {
|
||||
if (!isset(self::$child_data[$conn_uuid][$key])) {
|
||||
self::$child_data[$conn_uuid][$key] = [];
|
||||
}
|
||||
self::$child_data[$conn_uuid][$key][] = (string)$node->$key;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($this->internalChildnodes as $node) {
|
||||
if (!$node->getInternalIsVirtual()) {
|
||||
$extra_attr = ['local_ts' => '', 'remote_ts' => ''];
|
||||
$conn_uuid = (string)$node->getAttribute('uuid');
|
||||
foreach (self::$child_attrs as $key) {
|
||||
$child_node = new TextField();
|
||||
$child_node->setInternalIsVirtual();
|
||||
if (isset(self::$child_data[$conn_uuid]) && !empty(self::$child_data[$conn_uuid][$key])) {
|
||||
$child_node->setValue(implode(',', array_unique(self::$child_data[$conn_uuid][$key])));
|
||||
}
|
||||
$node->addChildNode($key, $child_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
return parent::actionPostLoadingEvent();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 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\BaseField;
|
||||
use OPNsense\Base\Validators\CallbackValidator;
|
||||
use OPNsense\Firewall\Util;
|
||||
|
||||
/**
|
||||
* @package OPNsense\Base\FieldTypes
|
||||
*/
|
||||
class IKEAdressField extends BaseField
|
||||
{
|
||||
/**
|
||||
* @var bool marks if this is a data node or a container
|
||||
*/
|
||||
protected $internalIsContainer = false;
|
||||
|
||||
/**
|
||||
* get valid options, descriptions and selected value
|
||||
* @return array
|
||||
*/
|
||||
public function getNodeData()
|
||||
{
|
||||
$result = [];
|
||||
foreach (explode(',', $this->internalValue) as $net) {
|
||||
$result[$net] = array("value" => $net, "selected" => 1);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
public function getValidators()
|
||||
{
|
||||
$validators = parent::getValidators();
|
||||
if ($this->internalValue != null) {
|
||||
$validators[] = new CallbackValidator(["callback" => function ($data) {
|
||||
$messages = [];
|
||||
foreach (explode(",", $data) as $entry) {
|
||||
if (Util::isIpAddress($entry) || Util::isSubnet($entry) || Util::isDomain($entry)) {
|
||||
continue;
|
||||
}
|
||||
$messages[] = sprintf(
|
||||
gettext('Entry "%s" is not a valid hostname, IP address or range.'),
|
||||
$entry
|
||||
);
|
||||
}
|
||||
return $messages;
|
||||
}
|
||||
]);
|
||||
}
|
||||
return $validators;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 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 IPsecProposalField extends BaseListField
|
||||
{
|
||||
private static $internalCacheOptionList = [];
|
||||
|
||||
protected function actionPostLoadingEvent()
|
||||
{
|
||||
if (empty(self::$internalCacheOptionList)) {
|
||||
self::$internalCacheOptionList['default'] = 'default';
|
||||
foreach (['aes128', 'aes192', 'aes256', 'aes128gcm16', 'aes192gcm16', 'aes256gcm16',
|
||||
'chacha20poly1305'] as $encalg
|
||||
) {
|
||||
foreach (['sha256', 'sha384', 'sha512', 'aesxcbc'] as $intalg) {
|
||||
foreach ([
|
||||
'modp2048', 'modp3072', 'modp4096', 'modp6144', 'modp8192', 'ecp224',
|
||||
'ecp256', 'ecp384', 'ecp521', 'ecp224bp', 'ecp256bp', 'ecp384bp', 'ecp512bp',
|
||||
'x25519', 'x448'] as $dhgroup
|
||||
) {
|
||||
$cipher = "{$encalg}-{$intalg}-{$dhgroup}";
|
||||
self::$internalCacheOptionList[$cipher] = $cipher;
|
||||
}
|
||||
}
|
||||
}
|
||||
natcasesort(self::$internalCacheOptionList);
|
||||
}
|
||||
$this->internalOptionList = self::$internalCacheOptionList;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 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 PoolsField extends BaseListField
|
||||
{
|
||||
private static $internalCacheOptionList = [];
|
||||
|
||||
protected function actionPostLoadingEvent()
|
||||
{
|
||||
if (empty(self::$internalCacheOptionList)) {
|
||||
foreach ($this->getParentModel()->Pools->Pool->iterateItems() as $node_uuid => $node) {
|
||||
self::$internalCacheOptionList[$node_uuid] = (string)$node->name;
|
||||
}
|
||||
// internal (plugin) pools
|
||||
self::$internalCacheOptionList['radius'] = 'radius';
|
||||
natcasesort(self::$internalCacheOptionList);
|
||||
}
|
||||
$this->internalOptionList = self::$internalCacheOptionList;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2022 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\ArrayField;
|
||||
use OPNsense\Base\FieldTypes\TextField;
|
||||
use OPNsense\Core\Backend;
|
||||
|
||||
class VTIField extends ArrayField
|
||||
{
|
||||
private static $legacyItems = [];
|
||||
|
||||
public function __construct($ref = null, $tagname = null)
|
||||
{
|
||||
if (empty(self::$legacyItems)) {
|
||||
// query legacy VTI devices, valid for the duration of this script execution
|
||||
$legacy_vtis = json_decode((new Backend())->configdRun('ipsec list legacy_vti'), true);
|
||||
if (!empty($legacy_vtis)) {
|
||||
foreach ($legacy_vtis as $vti) {
|
||||
$vti['enabled'] = '1';
|
||||
self::$legacyItems['ipsec'.$vti['reqid']] = $vti;
|
||||
}
|
||||
}
|
||||
}
|
||||
parent::__construct($ref, $tagname);
|
||||
}
|
||||
|
||||
/**
|
||||
* create virtual VTI nodes
|
||||
*/
|
||||
private function createReservedNodes()
|
||||
{
|
||||
$result = [];
|
||||
foreach (self::$legacyItems as $vtiName => $vtiContent) {
|
||||
$container_node = $this->newContainerField($this->__reference . "." . $vtiName, $this->internalXMLTagName);
|
||||
$container_node->setAttributeValue("uuid", $vtiName);
|
||||
$container_node->setInternalIsVirtual();
|
||||
foreach ($this->getTemplateNode()->iterateItems() as $key => $value) {
|
||||
$node = clone $value;
|
||||
$node->setInternalReference($container_node->__reference . "." . $key);
|
||||
if (isset($vtiContent[$key])) {
|
||||
$node->setValue($vtiContent[$key]);
|
||||
}
|
||||
$node->markUnchanged();
|
||||
$container_node->addChildNode($key, $node);
|
||||
}
|
||||
$type_node = new TextField();
|
||||
$type_node->setInternalIsVirtual();
|
||||
$type_node->setValue('legacy');
|
||||
$container_node->addChildNode('origin', $type_node);
|
||||
$result[$vtiName] = $container_node;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function actionPostLoadingEvent()
|
||||
{
|
||||
foreach ($this->internalChildnodes as $node) {
|
||||
if (!$node->getInternalIsVirtual()) {
|
||||
$type_node = new TextField();
|
||||
$type_node->setInternalIsVirtual();
|
||||
$type_node->setValue('vti');
|
||||
$node->addChildNode('origin', $type_node);
|
||||
}
|
||||
}
|
||||
return parent::actionPostLoadingEvent();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function hasChild($name)
|
||||
{
|
||||
if (isset(self::$reservedItems[$name])) {
|
||||
return true;
|
||||
} else {
|
||||
return parent::hasChild($name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getChild($name)
|
||||
{
|
||||
if (isset(self::$reservedItems[$name])) {
|
||||
return $this->createReservedNodes()[$name];
|
||||
} else {
|
||||
return parent::getChild($name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function iterateItems()
|
||||
{
|
||||
foreach (parent::iterateItems() as $key => $value) {
|
||||
yield $key => $value;
|
||||
}
|
||||
foreach ($this->createReservedNodes() as $key => $node) {
|
||||
yield $key => $node;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -43,9 +43,18 @@
|
||||
<check001>
|
||||
<ValidationMessage>Another entry with the same identifier already exists.</ValidationMessage>
|
||||
<type>UniqueConstraint</type>
|
||||
<addField>remote_ident</addField>
|
||||
</check001>
|
||||
</Constraints>
|
||||
</ident>
|
||||
<remote_ident type="TextField">
|
||||
<Required>N</Required>
|
||||
<mask>/^([a-zA-Z0-9@\.\-]*)/u</mask>
|
||||
<ValidationMessage>The identifier contains invalid characters.</ValidationMessage>
|
||||
<Constraints>
|
||||
<reference>ident.check001</reference>
|
||||
</Constraints>
|
||||
</remote_ident>
|
||||
<keyType type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<default>PSK</default>
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<menu>
|
||||
<VPN>
|
||||
<IPsec cssClass="fa fa-lock fa-fw" order="10">
|
||||
<Connections order="5" VisibleName="Connections [new]" url="/ui/ipsec/connections"/>
|
||||
<Tunnels order="10" VisibleName="Tunnel Settings" url="/ui/ipsec/tunnels">
|
||||
<Phase1 url="/vpn_ipsec_phase1.php*" visibility="hidden"/>
|
||||
<Phase2 url="/vpn_ipsec_phase2.php*" visibility="hidden"/>
|
||||
@ -15,6 +16,7 @@
|
||||
<Leases order="70" VisibleName="Lease Status" url="/ui/ipsec/leases"/>
|
||||
<SAD order="80" VisibleName="Security Association Database" url="/ui/ipsec/sad"/>
|
||||
<SPD order="90" VisibleName="Security Policy Database" url="/ui/ipsec/spd"/>
|
||||
<VTI order="90" VisibleName="Virtual Tunnel Interfaces" url="/ui/ipsec/vti"/>
|
||||
<LogFile order="100" VisibleName="Log File" url="/ui/diagnostics/log/core/ipsec"/>
|
||||
</IPsec>
|
||||
</VPN>
|
||||
|
||||
191
src/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.php
Normal file
191
src/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.php
Normal file
@ -0,0 +1,191 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 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;
|
||||
|
||||
use Phalcon\Messages\Message;
|
||||
use OPNsense\Base\BaseModel;
|
||||
use OPNsense\Firewall\Util;
|
||||
|
||||
/**
|
||||
* Class Swanctl
|
||||
* @package OPNsense\IPsec
|
||||
*/
|
||||
class Swanctl extends BaseModel
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function performValidation($validateFullModel = false)
|
||||
{
|
||||
$messages = parent::performValidation($validateFullModel);
|
||||
$vtis = [];
|
||||
|
||||
foreach ($this->getFlatNodes() as $key => $node) {
|
||||
if ($validateFullModel || $node->isFieldChanged()) {
|
||||
$tagName = $node->getInternalXMLTagName();
|
||||
$parentNode = $node->getParentNode();
|
||||
$parentKey = $parentNode->__reference;
|
||||
$parentTagName = $parentNode->getInternalXMLTagName();
|
||||
if ($parentTagName === 'VTI') {
|
||||
$vtis[$parentKey] = $parentNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($vtis as $key => $node) {
|
||||
$vti_inets = [];
|
||||
foreach (['local', 'remote', 'tunnel_local', 'tunnel_remote'] as $prop) {
|
||||
$vti_inets[$prop] = strpos((string)$node->$prop, ':') > 0 ? 'inet6' : 'inet';
|
||||
}
|
||||
|
||||
if ($vti_inets['local'] != $vti_inets['remote']) {
|
||||
$messages->appendMessage(new Message(gettext("Protocol families should match"), $key . ".local"));
|
||||
}
|
||||
if ($vti_inets['tunnel_local'] != $vti_inets['tunnel_remote']) {
|
||||
$messages->appendMessage(new Message(gettext("Protocol families should match"), $key . ".tunnel_local"));
|
||||
}
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
/**
|
||||
* generate swanctl configuration output, containing "pools" and "connections", locals, remotes and children
|
||||
* are treated as children of connection.
|
||||
* @return array
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
$data = ['connections' => [], 'pools' => []];
|
||||
$references = [
|
||||
'pools' => 'Pools.Pool',
|
||||
'connections' => 'Connections.Connection',
|
||||
'locals' => 'locals.local',
|
||||
'remotes' => 'remotes.remote',
|
||||
'children' => 'children.child',
|
||||
];
|
||||
foreach ($references as $key => $ref) {
|
||||
foreach ($this->getNodeByReference($ref)->iterateItems() as $node_uuid => $node) {
|
||||
if (empty((string)$node->enabled)) {
|
||||
continue;
|
||||
}
|
||||
$parent = null;
|
||||
$thisnode = [];
|
||||
foreach ($node->iterateItems() as $attr_name => $attr) {
|
||||
if ($attr_name == 'connection' && isset($data['connections'][(string)$attr])) {
|
||||
$parent = (string)$attr;
|
||||
continue;
|
||||
} elseif ($attr_name == 'pools') {
|
||||
// pools are mapped by name for clearer identification and legacy support
|
||||
if ((string)$attr != '') {
|
||||
$pools = [];
|
||||
foreach (explode(',', (string)$attr) as $pool_id) {
|
||||
$is_uuid = preg_match(
|
||||
'/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/', $pool_id
|
||||
) == 1;
|
||||
if (isset($data['pools'][$pool_id])) {
|
||||
$pools[] = $data['pools'][$pool_id]['name'];
|
||||
} elseif (!$is_uuid) {
|
||||
$pools[] = $pool_id;
|
||||
}
|
||||
}
|
||||
if (!empty($pools)) {
|
||||
$thisnode['pools'] = implode(',', $pools);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} elseif ($attr_name == 'enabled') {
|
||||
if (empty((string)$attr)) {
|
||||
// disabled entity
|
||||
$thisnode = [];
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} elseif ((string)$attr == '') {
|
||||
continue;
|
||||
} elseif (is_a($attr, 'OPNsense\Base\FieldTypes\BooleanField')) {
|
||||
$thisnode[$attr_name] = (string)$attr == '1' ? 'yes' : 'no';
|
||||
} elseif ($attr_name == 'pubkeys') {
|
||||
$tmp = [];
|
||||
foreach (explode(',', (string)$attr) as $item) {
|
||||
$tmp[] = $item . '.pem';
|
||||
}
|
||||
$thisnode[$attr_name] = implode(',', $tmp);
|
||||
} else {
|
||||
$thisnode[$attr_name] = (string)$attr;
|
||||
}
|
||||
}
|
||||
if (empty($thisnode)) {
|
||||
continue;
|
||||
} elseif (!empty($parent)) {
|
||||
if (!isset($data['connections'][$parent][$key])) {
|
||||
$data['connections'][$parent][$key] = [];
|
||||
}
|
||||
$data['connections'][$parent][$key][] = $thisnode;
|
||||
} else {
|
||||
if (!isset($data[$key])) {
|
||||
$data[$key] = [];
|
||||
}
|
||||
$data[$key][$node_uuid] = $thisnode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* return non legacy vti devices formatted like ipsec_get_configured_vtis()
|
||||
*/
|
||||
public function getVtiDevices()
|
||||
{
|
||||
$result = [];
|
||||
foreach ($this->VTIs->VTI->iterateItems() as $node_uuid => $node) {
|
||||
if ((string)$node->origin != 'legacy' && (string)$node->enabled == '1') {
|
||||
$inet = strpos((string)$node->local_tunnel, ':') > 0 ? 'inet6' : 'inet';
|
||||
$result['ipsec' . (string)$node->reqid] = [
|
||||
'reqid' => (string)$node->reqid,
|
||||
'local' => (string)$node->local,
|
||||
'remote' => (string)$node->remote,
|
||||
'descr' => (string)$node->description,
|
||||
'networks' => [
|
||||
[
|
||||
'inet' => $inet,
|
||||
'tunnel_local' => (string)$node->tunnel_local,
|
||||
'tunnel_remote' => (string)$node->tunnel_remote,
|
||||
'mask' => Util::smallestCIDR(
|
||||
[(string)$node->tunnel_local, (string)$node->tunnel_remote],
|
||||
$inet
|
||||
)
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
392
src/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.xml
Normal file
392
src/opnsense/mvc/app/models/OPNsense/IPsec/Swanctl.xml
Normal file
@ -0,0 +1,392 @@
|
||||
<model>
|
||||
<mount>//OPNsense/Swanctl</mount>
|
||||
<version>1.0.0</version>
|
||||
<description>OPNsense IPsec Connections</description>
|
||||
<items>
|
||||
<Connections>
|
||||
<Connection type=".\ConnnectionField">
|
||||
<enabled type="BooleanField">
|
||||
<default>1</default>
|
||||
<Required>Y</Required>
|
||||
</enabled>
|
||||
<proposals type=".\IPsecProposalField">
|
||||
<default>default</default>
|
||||
<Required>Y</Required>
|
||||
</proposals>
|
||||
<unique type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<default>no</default>
|
||||
<OptionValues>
|
||||
<no>No (default)</no>
|
||||
<never>Never</never>
|
||||
<keep>Keep</keep>
|
||||
<replace>Replace</replace>
|
||||
</OptionValues>
|
||||
</unique>
|
||||
<aggressive type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>Y</Required>
|
||||
</aggressive>
|
||||
<version type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<default>0</default>
|
||||
<OptionValues>
|
||||
<ike value="0">IKEv1+IKEv2</ike>
|
||||
<ikev1 value="1">IKEv1</ikev1>
|
||||
<ikev2 value="2">IKEv2</ikev2>
|
||||
</OptionValues>
|
||||
</version>
|
||||
<mobike type="BooleanField">
|
||||
<default>1</default>
|
||||
<Required>Y</Required>
|
||||
</mobike>
|
||||
<local_addrs type=".\IKEAdressField">
|
||||
<Required>N</Required>
|
||||
</local_addrs>
|
||||
<remote_addrs type=".\IKEAdressField">
|
||||
<Required>N</Required>
|
||||
</remote_addrs>
|
||||
<encap type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>Y</Required>
|
||||
</encap>
|
||||
<reauth_time type="IntegerField">
|
||||
<MinimumValue>0</MinimumValue>
|
||||
<MaximumValue>500000</MaximumValue>
|
||||
<Required>N</Required>
|
||||
</reauth_time>
|
||||
<rekey_time type="IntegerField">
|
||||
<MinimumValue>0</MinimumValue>
|
||||
<MaximumValue>500000</MaximumValue>
|
||||
<Required>N</Required>
|
||||
</rekey_time>
|
||||
<over_time type="IntegerField">
|
||||
<MinimumValue>0</MinimumValue>
|
||||
<MaximumValue>500000</MaximumValue>
|
||||
<Required>N</Required>
|
||||
</over_time>
|
||||
<dpd_delay type="IntegerField">
|
||||
<MinimumValue>0</MinimumValue>
|
||||
<MaximumValue>500000</MaximumValue>
|
||||
<Required>N</Required>
|
||||
</dpd_delay>
|
||||
<dpd_timeout type="IntegerField">
|
||||
<MinimumValue>0</MinimumValue>
|
||||
<MaximumValue>500000</MaximumValue>
|
||||
<Required>N</Required>
|
||||
</dpd_timeout>
|
||||
<pools type=".\PoolsField">
|
||||
<Required>N</Required>
|
||||
<Multiple>Y</Multiple>
|
||||
</pools>
|
||||
<send_certreq type="BooleanField">
|
||||
<default>1</default>
|
||||
<Required>Y</Required>
|
||||
</send_certreq>
|
||||
<send_cert type="OptionField">
|
||||
<Required>N</Required>
|
||||
<BlankDesc>Default</BlankDesc>
|
||||
<OptionValues>
|
||||
<ifasked>If asked</ifasked>
|
||||
<never>Never</never>
|
||||
<always>Always</always>
|
||||
</OptionValues>
|
||||
</send_cert>
|
||||
<keyingtries type="IntegerField">
|
||||
<MinimumValue>0</MinimumValue>
|
||||
<MaximumValue>1000</MaximumValue>
|
||||
<Required>N</Required>
|
||||
</keyingtries>
|
||||
<description type="TextField">
|
||||
<Required>N</Required>
|
||||
</description>
|
||||
</Connection>
|
||||
</Connections>
|
||||
<locals>
|
||||
<local type="ArrayField">
|
||||
<enabled type="BooleanField">
|
||||
<default>1</default>
|
||||
<Required>Y</Required>
|
||||
</enabled>
|
||||
<connection type="ModelRelationField">
|
||||
<Model>
|
||||
<host>
|
||||
<source>OPNsense.IPsec.Swanctl</source>
|
||||
<items>Connections.Connection</items>
|
||||
<display>description</display>
|
||||
</host>
|
||||
</Model>
|
||||
<Required>Y</Required>
|
||||
</connection>
|
||||
<round type="IntegerField">
|
||||
<Required>Y</Required>
|
||||
<MinimumValue>0</MinimumValue>
|
||||
<MaximumValue>10</MaximumValue>
|
||||
<default>0</default>
|
||||
</round>
|
||||
<auth type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<default>psk</default>
|
||||
<OptionValues>
|
||||
<psk>Pre-Shared Key</psk>
|
||||
<pubkey>Public Key</pubkey>
|
||||
<eap_tls value="eap-tls">EAP TLS</eap_tls>
|
||||
<eap_mschapv2 value="eap-mschapv2">EAP-MSCHAPv2</eap_mschapv2>
|
||||
<xauth_pam value="xauth-pam">Xauth PAM</xauth_pam>
|
||||
<eap_radius value="eap-radius">EAP RADIUS</eap_radius>
|
||||
</OptionValues>
|
||||
</auth>
|
||||
<id type="TextField">
|
||||
<Required>N</Required>
|
||||
<mask>/^([0-9a-zA-Z.\-,_\:){0,4196}$/u</mask>
|
||||
</id>
|
||||
<eap_id type="TextField">
|
||||
<Required>N</Required>
|
||||
<mask>/^([0-9a-zA-Z.\-,_\:){0,4196}$/u</mask>
|
||||
</eap_id>
|
||||
<certs type="CertificateField">
|
||||
<Required>N</Required>
|
||||
<Multiple>Y</Multiple>
|
||||
<ValidationMessage>Please select a valid certificate from the list</ValidationMessage>
|
||||
</certs>
|
||||
<pubkeys type="ModelRelationField">
|
||||
<Model>
|
||||
<host>
|
||||
<source>OPNsense.IPsec.IPsec</source>
|
||||
<items>keyPairs.keyPair</items>
|
||||
<display>name</display>
|
||||
</host>
|
||||
</Model>
|
||||
<Multiple>Y</Multiple>
|
||||
<Required>N</Required>
|
||||
</pubkeys>
|
||||
<description type="TextField">
|
||||
<Required>N</Required>
|
||||
</description>
|
||||
</local>
|
||||
</locals>
|
||||
<remotes>
|
||||
<remote type="ArrayField">
|
||||
<enabled type="BooleanField">
|
||||
<default>1</default>
|
||||
<Required>Y</Required>
|
||||
</enabled>
|
||||
<connection type="ModelRelationField">
|
||||
<Model>
|
||||
<host>
|
||||
<source>OPNsense.IPsec.Swanctl</source>
|
||||
<items>Connections.Connection</items>
|
||||
<display>description</display>
|
||||
</host>
|
||||
</Model>
|
||||
<Required>Y</Required>
|
||||
</connection>
|
||||
<round type="IntegerField">
|
||||
<Required>Y</Required>
|
||||
<MinimumValue>0</MinimumValue>
|
||||
<MaximumValue>10</MaximumValue>
|
||||
<default>0</default>
|
||||
</round>
|
||||
<auth type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<default>psk</default>
|
||||
<OptionValues>
|
||||
<psk>Pre-Shared Key</psk>
|
||||
<pubkey>Public Key</pubkey>
|
||||
<eap_tls value="eap-tls">EAP TLS</eap_tls>
|
||||
<eap_mschapv2 value="eap-mschapv2">EAP-MSCHAPv2</eap_mschapv2>
|
||||
<xauth_pam value="xauth-pam">Xauth PAM</xauth_pam>
|
||||
<eap_radius value="eap-radius">EAP RADIUS</eap_radius>
|
||||
</OptionValues>
|
||||
</auth>
|
||||
<id type="TextField">
|
||||
<Required>N</Required>
|
||||
<mask>/^([0-9a-zA-Z.\-,_\:){0,4196}$/u</mask>
|
||||
</id>
|
||||
<eap_id type="TextField">
|
||||
<Required>N</Required>
|
||||
<mask>/^([0-9a-zA-Z.\-,_\:){0,4196}$/u</mask>
|
||||
</eap_id>
|
||||
<certs type="CertificateField">
|
||||
<Required>N</Required>
|
||||
<Multiple>Y</Multiple>
|
||||
<ValidationMessage>Please select a valid certificate from the list</ValidationMessage>
|
||||
</certs>
|
||||
<pubkeys type="ModelRelationField">
|
||||
<Model>
|
||||
<host>
|
||||
<source>OPNsense.IPsec.IPsec</source>
|
||||
<items>keyPairs.keyPair</items>
|
||||
<display>name</display>
|
||||
</host>
|
||||
</Model>
|
||||
<Multiple>Y</Multiple>
|
||||
<Required>N</Required>
|
||||
</pubkeys>
|
||||
<description type="TextField">
|
||||
<Required>N</Required>
|
||||
</description>
|
||||
</remote>
|
||||
</remotes>
|
||||
<children>
|
||||
<child type="ArrayField">
|
||||
<enabled type="BooleanField">
|
||||
<default>1</default>
|
||||
<Required>Y</Required>
|
||||
</enabled>
|
||||
<connection type="ModelRelationField">
|
||||
<Model>
|
||||
<host>
|
||||
<source>OPNsense.IPsec.Swanctl</source>
|
||||
<items>Connections.Connection</items>
|
||||
<display>description</display>
|
||||
</host>
|
||||
</Model>
|
||||
<Required>Y</Required>
|
||||
</connection>
|
||||
<reqid type="IntegerField">
|
||||
<MinimumValue>1</MinimumValue>
|
||||
<MaximumValue>65535</MaximumValue>
|
||||
<Required>N</Required>
|
||||
</reqid>
|
||||
<esp_proposals type=".\IPsecProposalField">
|
||||
<default>default</default>
|
||||
<Required>Y</Required>
|
||||
</esp_proposals>
|
||||
<sha256_96 type="BooleanField">
|
||||
<default>0</default>
|
||||
<Required>Y</Required>
|
||||
</sha256_96>
|
||||
<start_action type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<default>start</default>
|
||||
<OptionValues>
|
||||
<none>None</none>
|
||||
<trap_start value='trap|start'>Trap+start</trap_start>
|
||||
<route>Route</route>
|
||||
<start>Start</start>
|
||||
<trap>Trap</trap>
|
||||
</OptionValues>
|
||||
</start_action>
|
||||
<close_action type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<default>none</default>
|
||||
<OptionValues>
|
||||
<none>None</none>
|
||||
<trap>Trap</trap>
|
||||
<start>Start</start>
|
||||
</OptionValues>
|
||||
</close_action>
|
||||
<dpd_action type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<default>clear</default>
|
||||
<OptionValues>
|
||||
<clear>Clear</clear>
|
||||
<trap>Trap</trap>
|
||||
<start>Start</start>
|
||||
</OptionValues>
|
||||
</dpd_action>
|
||||
<mode type="OptionField">
|
||||
<Required>Y</Required>
|
||||
<default>tunnel</default>
|
||||
<OptionValues>
|
||||
<tunnel>Tunnel</tunnel>
|
||||
<transport>Transport</transport>
|
||||
<pass>Pass</pass>
|
||||
<drop>Drop</drop>
|
||||
</OptionValues>
|
||||
</mode>
|
||||
<local_ts type="NetworkField">
|
||||
<Required>Y</Required>
|
||||
<FieldSeparator>,</FieldSeparator>
|
||||
<asList>Y</asList>
|
||||
<WildcardEnabled>N</WildcardEnabled>
|
||||
</local_ts>
|
||||
<remote_ts type="NetworkField">
|
||||
<Required>Y</Required>
|
||||
<FieldSeparator>,</FieldSeparator>
|
||||
<asList>Y</asList>
|
||||
<WildcardEnabled>N</WildcardEnabled>
|
||||
</remote_ts>
|
||||
<rekey_time type="IntegerField">
|
||||
<default>3600</default>
|
||||
<MinimumValue>0</MinimumValue>
|
||||
<MaximumValue>500000</MaximumValue>
|
||||
<Required>Y</Required>
|
||||
</rekey_time>
|
||||
<description type="TextField">
|
||||
<Required>N</Required>
|
||||
</description>
|
||||
</child>
|
||||
</children>
|
||||
<Pools>
|
||||
<Pool type="ArrayField">
|
||||
<enabled type="BooleanField">
|
||||
<default>1</default>
|
||||
<Required>Y</Required>
|
||||
</enabled>
|
||||
<name type="TextField">
|
||||
<Required>N</Required>
|
||||
<Constraints>
|
||||
<check001>
|
||||
<ValidationMessage>Pool name must be unique.</ValidationMessage>
|
||||
<type>UniqueConstraint</type>
|
||||
</check001>
|
||||
</Constraints>
|
||||
</name>
|
||||
<addrs type="NetworkField">
|
||||
<Required>Y</Required>
|
||||
<WildcardEnabled>N</WildcardEnabled>
|
||||
<NetMaskRequired>Y</NetMaskRequired>
|
||||
<ValidationMessage>Please specify a valid CIDR subnet.</ValidationMessage>
|
||||
</addrs>
|
||||
</Pool>
|
||||
</Pools>
|
||||
<VTIs>
|
||||
<VTI type=".\VTIField">
|
||||
<enabled type="BooleanField">
|
||||
<default>1</default>
|
||||
<Required>Y</Required>
|
||||
</enabled>
|
||||
<reqid type="IntegerField">
|
||||
<MinimumValue>1</MinimumValue>
|
||||
<MaximumValue>65535</MaximumValue>
|
||||
<Required>Y</Required>
|
||||
<Constraints>
|
||||
<check001>
|
||||
<ValidationMessage>Reqid must be unique.</ValidationMessage>
|
||||
<type>UniqueConstraint</type>
|
||||
</check001>
|
||||
</Constraints>
|
||||
</reqid>
|
||||
<local type="NetworkField">
|
||||
<NetMaskAllowed>N</NetMaskAllowed>
|
||||
<WildcardEnabled>N</WildcardEnabled>
|
||||
<Required>Y</Required>
|
||||
<ValidationMessage>Please specify a valid address.</ValidationMessage>
|
||||
</local>
|
||||
<remote type="NetworkField">
|
||||
<NetMaskAllowed>N</NetMaskAllowed>
|
||||
<WildcardEnabled>N</WildcardEnabled>
|
||||
<Required>Y</Required>
|
||||
<ValidationMessage>Please specify a valid address.</ValidationMessage>
|
||||
</remote>
|
||||
<tunnel_local type="NetworkField">
|
||||
<NetMaskAllowed>N</NetMaskAllowed>
|
||||
<WildcardEnabled>N</WildcardEnabled>
|
||||
<Required>Y</Required>
|
||||
<ValidationMessage>Please specify a valid address.</ValidationMessage>
|
||||
</tunnel_local>
|
||||
<tunnel_remote type="NetworkField">
|
||||
<NetMaskAllowed>N</NetMaskAllowed>
|
||||
<WildcardEnabled>N</WildcardEnabled>
|
||||
<Required>Y</Required>
|
||||
<ValidationMessage>Please specify a valid address.</ValidationMessage>
|
||||
</tunnel_remote>
|
||||
<description type="TextField">
|
||||
<Required>N</Required>
|
||||
</description>
|
||||
</VTI>
|
||||
</VTIs>
|
||||
</items>
|
||||
</model>
|
||||
311
src/opnsense/mvc/app/views/OPNsense/IPsec/connections.volt
Normal file
311
src/opnsense/mvc/app/views/OPNsense/IPsec/connections.volt
Normal file
@ -0,0 +1,311 @@
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
let grid_connections = $("#grid-connections").UIBootgrid({
|
||||
search:'/api/ipsec/connections/search_connection',
|
||||
get:'/api/ipsec/connections/get_connection/',
|
||||
set:'/api/ipsec/connections/set_connection/',
|
||||
add:'/api/ipsec/connections/set_connection/',
|
||||
del:'/api/ipsec/connections/del_connection/',
|
||||
toggle:'/api/ipsec/connections/toggle_connection/',
|
||||
});
|
||||
|
||||
let grid_pools = $("#grid-pools").UIBootgrid({
|
||||
search:'/api/ipsec/pools/search',
|
||||
get:'/api/ipsec/pools/get/',
|
||||
set:'/api/ipsec/pools/set/',
|
||||
add:'/api/ipsec/pools/add/',
|
||||
del:'/api/ipsec/pools/del/',
|
||||
toggle:'/api/ipsec/pools/toggle/',
|
||||
});
|
||||
|
||||
let detail_grids = {
|
||||
locals: 'local',
|
||||
remotes: 'remote',
|
||||
children: 'child',
|
||||
};
|
||||
for (const [grid_key, obj_type] of Object.entries(detail_grids)) {
|
||||
$("#grid-" + grid_key).UIBootgrid({
|
||||
search:'/api/ipsec/connections/search_' + obj_type,
|
||||
get:'/api/ipsec/connections/get_' + obj_type + '/',
|
||||
set:'/api/ipsec/connections/set_' + obj_type + '/',
|
||||
add:'/api/ipsec/connections/add_' + obj_type + '/',
|
||||
del:'/api/ipsec/connections/del_' + obj_type + '/',
|
||||
toggle:'/api/ipsec/connections/toggle_' + obj_type + '/',
|
||||
options:{
|
||||
navigation: obj_type === 'child' ? 3 : 0,
|
||||
selection: obj_type === 'child' ? true : false,
|
||||
useRequestHandlerOnGet: true,
|
||||
requestHandler: function(request) {
|
||||
request['connection'] = $("#connection\\.uuid").val();
|
||||
if (request.rowCount === undefined) {
|
||||
// XXX: We can't easily see if we're being called by GET or POST, buf if no rowCount is being offered
|
||||
// it's highly likely a POST from bootgrid
|
||||
return new URLSearchParams(request).toString();
|
||||
} else {
|
||||
return request
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
if (obj_type !== 'child') {
|
||||
$("#"+obj_type+"\\.auth").change(function(){
|
||||
$("."+obj_type+"_auth").closest("tr").hide();
|
||||
$("."+obj_type+"_auth_"+$(this).val()).each(function(){
|
||||
$(this).closest("tr").show();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$(".hidden_attr").closest('tr').hide();
|
||||
|
||||
$("#ConnectionDialog").click(function(){
|
||||
$("#connection_details").hide();
|
||||
ajaxGet("/api/ipsec/connections/connection_exists/" + $("#connection\\.uuid").val(), {}, function(data){
|
||||
if (data.exists) {
|
||||
$("#connection_details").show();
|
||||
$("#grid-locals").bootgrid("reload");
|
||||
$("#grid-remotes").bootgrid("reload");
|
||||
$("#grid-children").bootgrid("reload");
|
||||
}
|
||||
});
|
||||
$(this).show();
|
||||
});
|
||||
|
||||
$("#ConnectionDialog").change(function(){
|
||||
if ($("#connection_details").is(':visible')) {
|
||||
$("#tab_connections").click();
|
||||
$("#ConnectionDialog").hide();
|
||||
} else {
|
||||
$("#ConnectionDialog").click();
|
||||
}
|
||||
});
|
||||
|
||||
$("#connection\\.description").change(function(){
|
||||
if ($(this).val() !== '') {
|
||||
$("#ConnectionDialog").text($(this).val());
|
||||
} else {
|
||||
$("#ConnectionDialog").text('-');
|
||||
}
|
||||
});
|
||||
|
||||
$("#frm_ConnectionDialog").append($("#frm_DialogConnection").detach());
|
||||
updateServiceControlUI('ipsec');
|
||||
|
||||
/**
|
||||
* reconfigure
|
||||
*/
|
||||
$("#reconfigureAct").SimpleActionButton();
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
div.section_header > hr {
|
||||
margin: 0px;
|
||||
}
|
||||
div.section_header > h2 {
|
||||
padding-left: 5px;
|
||||
margin: 0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
|
||||
<li class="active"><a data-toggle="tab" id="tab_connections" href="#connections">{{ lang._('Connections') }}</a></li>
|
||||
<li><a data-toggle="tab" href="#edit_connection" id="ConnectionDialog" style="display: none;"> </a></li>
|
||||
<li><a data-toggle="tab" href="#pools" id="tab_pools"> {{ lang._('Pools') }} </a></li>
|
||||
</ul>
|
||||
<div class="tab-content content-box">
|
||||
<div id="connections" class="tab-pane fade in active">
|
||||
<table id="grid-connections" class="table table-condensed table-hover table-striped" data-editDialog="ConnectionDialog" data-editAlert="ConnectionChangeMessage">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
|
||||
<th data-column-id="enabled" data-width="6em" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
|
||||
<th data-column-id="description" data-type="string">{{ lang._('Description') }}</th>
|
||||
<th data-column-id="local_addrs" data-type="string">{{ lang._('Local') }}</th>
|
||||
<th data-column-id="remote_addrs" data-type="string">{{ lang._('Remote') }}</th>
|
||||
<th data-column-id="local_ts" data-type="string">{{ lang._('Local Nets') }}</th>
|
||||
<th data-column-id="remote_ts" data-type="string">{{ lang._('Remote Nets') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-primary"><span class="fa fa-fw fa-plus"></span></button>
|
||||
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-fw fa-trash-o"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<div class="col-md-12">
|
||||
<div id="ConnectionChangeMessage" class="alert alert-info" style="display: none" role="alert">
|
||||
{{ lang._('After changing settings, please remember to apply them with the button below') }}
|
||||
</div>
|
||||
<hr/>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<button class="btn btn-primary" id="reconfigureAct"
|
||||
data-endpoint='/api/ipsec/legacy-subsystem/applyConfig'
|
||||
data-label="{{ lang._('Apply') }}"
|
||||
data-error-title="{{ lang._('Error reconfiguring IPsec') }}"
|
||||
type="button"
|
||||
></button>
|
||||
<br/><br/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="edit_connection" class="tab-pane fade in">
|
||||
<div class="section_header">
|
||||
<h2>{{ lang._('General settings')}}</h2>
|
||||
<hr/>
|
||||
</div>
|
||||
<div>
|
||||
<form id="frm_ConnectionDialog">
|
||||
</form>
|
||||
</div>
|
||||
<div id="connection_details">
|
||||
<div class="row">
|
||||
<hr/>
|
||||
<div class="col-xs-6">
|
||||
<div class="section_header">
|
||||
<h2>{{ lang._('Local Authentication')}}</h2>
|
||||
<hr/>
|
||||
</div>
|
||||
<table id="grid-locals" class="table table-condensed table-hover table-striped" data-editDialog="DialogLocal">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
|
||||
<th data-column-id="enabled" data-width="6em" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
|
||||
<th data-column-id="round" data-type="string">{{ lang._('Round') }}</th>
|
||||
<th data-column-id="auth" data-type="string">{{ lang._('Authentication') }}</th>
|
||||
<th data-column-id="description" data-type="string">{{ lang._('Description') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-primary pull-right"><span class="fa fa-fw fa-plus"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<div class="section_header">
|
||||
<h2>{{ lang._('Remote Authentication')}}</h2>
|
||||
<hr/>
|
||||
</div>
|
||||
<table id="grid-remotes" class="table table-condensed table-hover table-striped" data-editDialog="DialogRemote">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
|
||||
<th data-column-id="enabled" data-width="6em" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
|
||||
<th data-column-id="round" data-type="string">{{ lang._('Round') }}</th>
|
||||
<th data-column-id="auth" data-type="string">{{ lang._('Authentication') }}</th>
|
||||
<th data-column-id="description" data-type="string">{{ lang._('Description') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-primary pull-right"><span class="fa fa-fw fa-plus"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="section_header">
|
||||
<h2>{{ lang._('Children')}}</h2>
|
||||
<hr/>
|
||||
</div>
|
||||
<table id="grid-children" class="table table-condensed table-hover table-striped" data-editDialog="DialogChild">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
|
||||
<th data-column-id="enabled" data-width="6em" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
|
||||
<th data-column-id="description" data-type="string">{{ lang._('Description') }}</th>
|
||||
<th data-column-id="local_ts" data-type="string">{{ lang._('Local Nets') }}</th>
|
||||
<th data-column-id="remote_ts" data-type="string">{{ lang._('Remote Nets') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-primary"><span class="fa fa-fw fa-plus"></span></button>
|
||||
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-fw fa-trash-o"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div id="ConnectionDialogBtns">
|
||||
<button type="button" class="btn btn-primary" id="btn_ConnectionDialog_save">
|
||||
<strong>{{ lang._('Save')}}</strong>
|
||||
<i id="btn_ConnectionDialog_save_progress" class=""></i>
|
||||
</button>
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="pools" class="tab-pane fade in">
|
||||
<table id="grid-pools" class="table table-condensed table-hover table-striped" data-editDialog="DialogPool" data-editAlert="PoolChangeMessage">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
|
||||
<th data-column-id="enabled" data-width="6em" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
|
||||
<th data-column-id="name" data-type="string">{{ lang._('Name') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-primary"><span class="fa fa-fw fa-plus"></span></button>
|
||||
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-fw fa-trash-o"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<div class="col-md-12">
|
||||
<div id="PoolChangeMessage" class="alert alert-info" style="display: none" role="alert">
|
||||
{{ lang._('After changing settings, please remember to apply them') }}
|
||||
</div>
|
||||
<hr/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{{ partial("layout_partials/base_dialog",['fields':formDialogConnection,'id':'DialogConnection','label':lang._('Edit Connection')])}}
|
||||
{{ partial("layout_partials/base_dialog",['fields':formDialogLocal,'id':'DialogLocal','label':lang._('Edit Local')])}}
|
||||
{{ partial("layout_partials/base_dialog",['fields':formDialogRemote,'id':'DialogRemote','label':lang._('Edit Remote')])}}
|
||||
{{ partial("layout_partials/base_dialog",['fields':formDialogChild,'id':'DialogChild','label':lang._('Edit Child')])}}
|
||||
{{ partial("layout_partials/base_dialog",['fields':formDialogPool,'id':'DialogPool','label':lang._('Edit Pool')])}}
|
||||
@ -16,7 +16,8 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
|
||||
<th data-column-id="ident" data-type="string">{{ lang._('Identifier') }}</th>
|
||||
<th data-column-id="ident" data-type="string">{{ lang._('Local Identifier') }}</th>
|
||||
<th data-column-id="remote_ident" data-type="string">{{ lang._('Remote Identifier') }}</th>
|
||||
<th data-column-id="keyType" data-width="20em" data-type="string">{{ lang._('Key Type') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
|
||||
94
src/opnsense/mvc/app/views/OPNsense/IPsec/vti.volt
Normal file
94
src/opnsense/mvc/app/views/OPNsense/IPsec/vti.volt
Normal file
@ -0,0 +1,94 @@
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
let grid_vti = $("#grid-vti").UIBootgrid({
|
||||
search:'/api/ipsec/vti/search',
|
||||
get:'/api/ipsec/vti/get/',
|
||||
set:'/api/ipsec/vti/set/',
|
||||
add:'/api/ipsec/vti/add/',
|
||||
del:'/api/ipsec/vti/del/',
|
||||
toggle:'/api/ipsec/vti/toggle/',
|
||||
options:{
|
||||
formatters: {
|
||||
commands: function (column, row) {
|
||||
if (row.uuid.includes('-') === true) {
|
||||
// exclude buttons for internal aliases (which uses names instead of valid uuid's)
|
||||
return '<button type="button" class="btn btn-xs btn-default command-edit bootgrid-tooltip" data-row-id="' + row.uuid + '"><span class="fa fa-fw fa-pencil"></span></button> ' +
|
||||
'<button type="button" class="btn btn-xs btn-default command-copy bootgrid-tooltip" data-row-id="' + row.uuid + '"><span class="fa fa-fw fa-clone"></span></button>' +
|
||||
'<button type="button" class="btn btn-xs btn-default command-delete bootgrid-tooltip" data-row-id="' + row.uuid + '"><span class="fa fa-fw fa-trash-o"></span></button>';
|
||||
}
|
||||
},
|
||||
tunnel: function (column, row) {
|
||||
return row.tunnel_local + ' <-> ' + row.tunnel_remote;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateServiceControlUI('ipsec');
|
||||
|
||||
/**
|
||||
* reconfigure
|
||||
*/
|
||||
$("#reconfigureAct").SimpleActionButton();
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
div.section_header > hr {
|
||||
margin: 0px;
|
||||
}
|
||||
div.section_header > h2 {
|
||||
padding-left: 5px;
|
||||
margin: 0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="content-box">
|
||||
<table id="grid-vti" class="table table-condensed table-hover table-striped" data-editDialog="DialogVTI" data-editAlert="VTIChangeMessage">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
|
||||
<th data-column-id="origin" data-type="string" data-visible="false">{{ lang._('Origin') }}</th>
|
||||
<th data-column-id="enabled" data-width="6em" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
|
||||
<th data-column-id="reqid" data-type="string">{{ lang._('Reqid') }}</th>
|
||||
<th data-column-id="local" data-type="string">{{ lang._('Local') }}</th>
|
||||
<th data-column-id="remote" data-type="string">{{ lang._('Remote') }}</th>
|
||||
<th data-column-id="tunnel_local" data-sortable="false" data-formatter="tunnel">{{ lang._('Tunnel') }}</th>
|
||||
<th data-column-id="description" data-type="string">{{ lang._('Description') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-primary"><span class="fa fa-fw fa-plus"></span></button>
|
||||
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-fw fa-trash-o"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<div class="col-md-12">
|
||||
<div id="VTIChangeMessage" class="alert alert-info" style="display: none" role="alert">
|
||||
{{ lang._('After changing settings, please remember to apply them with the button below') }}
|
||||
</div>
|
||||
<hr/>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<button class="btn btn-primary" id="reconfigureAct"
|
||||
data-endpoint='/api/ipsec/legacy-subsystem/applyConfig'
|
||||
data-label="{{ lang._('Apply') }}"
|
||||
data-error-title="{{ lang._('Error reconfiguring IPsec') }}"
|
||||
type="button"
|
||||
></button>
|
||||
<br/><br/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{{ partial("layout_partials/base_dialog",['fields':formDialogVTI,'id':'DialogVTI','label':lang._('Edit VirtualTunnelInterface')])}}
|
||||
50
src/opnsense/scripts/ipsec/get_legacy_vti.php
Executable file
50
src/opnsense/scripts/ipsec/get_legacy_vti.php
Executable file
@ -0,0 +1,50 @@
|
||||
#!/usr/local/bin/php
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
require_once("util.inc");
|
||||
require_once("interfaces.inc");
|
||||
require_once("config.inc");
|
||||
require_once("plugins.inc.d/ipsec.inc");
|
||||
|
||||
$result = [];
|
||||
foreach (ipsec_get_configured_vtis() as $vti) {
|
||||
$record = [
|
||||
'reqid' => $vti['reqid'],
|
||||
'local' => $vti['local'],
|
||||
'remote' => $vti['remote'],
|
||||
'description' => $vti['descr']
|
||||
];
|
||||
if (!empty($vti['networks'])) {
|
||||
$record['tunnel_local'] = $vti['networks'][0]['tunnel_local'];
|
||||
$record['tunnel_remote'] = $vti['networks'][0]['tunnel_remote'];
|
||||
}
|
||||
$result[] = $record;
|
||||
}
|
||||
|
||||
echo json_encode($result);
|
||||
@ -28,6 +28,12 @@ parameters:
|
||||
type:script_output
|
||||
message:List SAD entries
|
||||
|
||||
[list.legacy_vti]
|
||||
command:/usr/local/opnsense/scripts/ipsec/get_legacy_vti.php
|
||||
parameters:
|
||||
type:script_output
|
||||
message:IPsec list legacy VirtualTunnelInterfaces
|
||||
|
||||
[connect]
|
||||
command:/usr/local/opnsense/scripts/ipsec/connect.py
|
||||
parameters:%s
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user