From ba645c25a67f96f53ce7d554c10ba180f4609f39 Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Mon, 15 Oct 2018 18:22:13 +0200 Subject: [PATCH] OpenVPN export, work in progress for https://github.com/opnsense/core/issues/2787 * Add factory class to request export template types * Add some test code to show/hide options depending on supported functions * Use our normal form type to construct the UI * Use stored ip/hostname when available or determine target based on ip address, the previous hostname resolution type will be replaced. * List configured templates using /api/openvpn/export/templates/ --- .../OPNsense/OpenVPN/Api/ExportController.php | 90 ++++++++++++++++++- .../OPNsense/OpenVPN/ExportController.php | 1 + .../OPNsense/OpenVPN/forms/export_options.xml | 40 +++++++++ .../OPNsense/OpenVPN/ArchiveOpenVPN.php | 42 +++++++++ .../library/OPNsense/OpenVPN/BaseExporter.php | 38 ++++++++ .../OPNsense/OpenVPN/ExportFactory.php | 81 +++++++++++++++++ .../OPNsense/OpenVPN/IExportProvider.php | 47 ++++++++++ .../library/OPNsense/OpenVPN/PlainOpenVPN.php | 42 +++++++++ .../app/models/OPNsense/OpenVPN/Export.php | 57 ++++++++++++ .../app/models/OPNsense/OpenVPN/Export.xml | 16 ++++ .../app/views/OPNsense/OpenVPN/export.volt | 46 ++++++++++ 11 files changed, 499 insertions(+), 1 deletion(-) create mode 100644 src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/forms/export_options.xml create mode 100644 src/opnsense/mvc/app/library/OPNsense/OpenVPN/ArchiveOpenVPN.php create mode 100644 src/opnsense/mvc/app/library/OPNsense/OpenVPN/BaseExporter.php create mode 100644 src/opnsense/mvc/app/library/OPNsense/OpenVPN/ExportFactory.php create mode 100644 src/opnsense/mvc/app/library/OPNsense/OpenVPN/IExportProvider.php create mode 100644 src/opnsense/mvc/app/library/OPNsense/OpenVPN/PlainOpenVPN.php create mode 100644 src/opnsense/mvc/app/models/OPNsense/OpenVPN/Export.php create mode 100644 src/opnsense/mvc/app/models/OPNsense/OpenVPN/Export.xml diff --git a/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/Api/ExportController.php b/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/Api/ExportController.php index 57729dbff..316d61a94 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/Api/ExportController.php +++ b/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/Api/ExportController.php @@ -30,6 +30,10 @@ namespace OPNsense\OpenVPN\Api; use \OPNsense\Base\ApiControllerBase; use \OPNsense\Core\Config; +use \OPNsense\Core\Backend; +use \OPNsense\OpenVPN\Export; +use \OPNsense\OpenVPN\ExportFactory; + /** * Class ExportController handles client export functions @@ -37,6 +41,51 @@ use \OPNsense\Core\Config; */ class ExportController extends ApiControllerBase { + /** + * @var null|Export model object to work on + */ + private $modelHandle = null; + + /** + * @var array list of configured interfaces (addresses) + */ + private $physicalInterfaces = array(); + + /** + * Get (or create) model object + * @return Export + * @throws \OPNsense\Base\ModelException when unable to create model + */ + private function getModel() + { + if ($this->modelHandle == null) { + $this->modelHandle = new Export(); + } + return $this->modelHandle; + } + + /** + * collect (and store) configured interfaces by name [lan, wan, optX] + * @return mixed + * @throws \Exception when unable to contact configd + */ + private function getInterfaces() + { + if (empty($this->physicalInterfaces)) { + $ifconfig = json_decode((new Backend())->configdRun('interface list ifconfig'), true); + $config = Config::getInstance()->object(); + if ($config->interfaces->count() > 0) { + foreach ($config->interfaces->children() as $key => $node) { + $this->physicalInterfaces[(string)$key] = array(); + if (!empty($ifconfig[(string)($node->if)])){ + $this->physicalInterfaces[(string)$key] = $ifconfig[(string)($node->if)]; + } + } + } + } + return $this->physicalInterfaces; + } + /** * find configured servers * @param bool $active only active servers @@ -55,6 +104,32 @@ class ExportController extends ApiControllerBase } } + /** + * Determine configured hostname for selected server + * @param $vpnid server handle + * @return string hostname + * @throws \OPNsense\Base\ModelException when unable to create model + */ + private function configuredHostname($vpnid) + { + $result = ""; + $allInterfaces = $this->getInterfaces(); + $serverModel = $this->getModel()->getServer($vpnid); + $server = $this->findServer($vpnid); + if (!empty((string)$serverModel->hostname)) { + $result = (string)$serverModel->hostname; + } elseif (!empty($allInterfaces[(string)$server->interface])) { + if (strstr((string)$server->protocol, "6") !== false) { + if (!empty($allInterfaces[(string)$server->interface]['ipv6'])) { + $result = $allInterfaces[(string)$server->interface]['ipv6'][0]['ipaddr']; + } + } elseif (!empty($allInterfaces[(string)$server->interface]['ipv4'])) { + $result = $allInterfaces[(string)$server->interface]['ipv4'][0]['ipaddr']; + } + } + return $result; + } + /** * find server by vpnid * @param string $vpnid reference @@ -70,12 +145,15 @@ class ExportController extends ApiControllerBase return null; } + /** * list providers * @return array list of configured openvpn providers (servers) + * @throws \Exception when unable to contact configd */ public function providersAction() { + $result = array(); foreach ($this->servers() as $server) { $vpnid = (string)$server->vpnid; @@ -86,6 +164,7 @@ class ExportController extends ApiControllerBase // relevant properties $result[$vpnid]["mode"] = (string)$server->mode; $result[$vpnid]["vpnid"] = $vpnid; + $result[$vpnid]["hostname"] = $this->configuredHostname($vpnid); } return $result; } @@ -132,6 +211,15 @@ class ExportController extends ApiControllerBase */ public function templatesAction() { - return array(); + $result = array(); + $factory = new ExportFactory(); + foreach ($factory->listProviders() as $key => $provider) { + $result[$key] = array( + "name" => $provider['handle']->getName(), + "supportedOptions" => $provider['handle']->supportedOptions() + ); + } + + return $result; } } diff --git a/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/ExportController.php b/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/ExportController.php index 8354e9ce6..6bafeb109 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/ExportController.php +++ b/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/ExportController.php @@ -45,5 +45,6 @@ class ExportController extends BaseIndexController public function indexAction() { $this->view->pick('OPNsense/OpenVPN/export'); + $this->view->exportForm = $this->getForm("export_options"); } } diff --git a/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/forms/export_options.xml b/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/forms/export_options.xml new file mode 100644 index 000000000..70c21b060 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/OpenVPN/forms/export_options.xml @@ -0,0 +1,40 @@ +
+ + openvpn_export.servers + + dropdown + + + + openvpn_export.template + + dropdown + + + + openvpn_export.hostname + + text + + Address(es) or hostname(s) to which this client should connect to, use comma's to provide more then one + + + + openvpn_export.testxx1 + + + text + + + openvpn_export.testxx2 + + + text + + + openvpn_export.testxx3 + + + text + +
diff --git a/src/opnsense/mvc/app/library/OPNsense/OpenVPN/ArchiveOpenVPN.php b/src/opnsense/mvc/app/library/OPNsense/OpenVPN/ArchiveOpenVPN.php new file mode 100644 index 000000000..1010354a6 --- /dev/null +++ b/src/opnsense/mvc/app/library/OPNsense/OpenVPN/ArchiveOpenVPN.php @@ -0,0 +1,42 @@ +implementsInterface('OPNsense\\OpenVPN\\IExportProvider') + && !$reflClass->isInterface()) { + $providers[$classname] = array( + "class" => "{$vendor}\\{$module}\\{$classname}", + "handle" => $reflClass->newInstance() + ); + } + } catch (\ReflectionException $e) { + null; // skip when unable to parse + } + } + return $providers; + } + + /** + * return a specific provider by class name (without namespace) + * @param string $className without namespace + * @return mixed|null + */ + public function getProvider($className) + { + $providers = $this->listProviders(); + if (!empty($providers[$className])) { + return $providers[$className]; + } else { + return null; + } + } +} diff --git a/src/opnsense/mvc/app/library/OPNsense/OpenVPN/IExportProvider.php b/src/opnsense/mvc/app/library/OPNsense/OpenVPN/IExportProvider.php new file mode 100644 index 000000000..1fe41075e --- /dev/null +++ b/src/opnsense/mvc/app/library/OPNsense/OpenVPN/IExportProvider.php @@ -0,0 +1,47 @@ +servers->server->iterateItems() as $uuid => $server) { + if ((string)$server->vpnid == (string)$vpnid) { + return $server; + } + } + $server = $this->servers->server->add(); + $server->vpnid = (string)$vpnid; + return $server; + } +} diff --git a/src/opnsense/mvc/app/models/OPNsense/OpenVPN/Export.xml b/src/opnsense/mvc/app/models/OPNsense/OpenVPN/Export.xml new file mode 100644 index 000000000..0c1b2bbae --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/OpenVPN/Export.xml @@ -0,0 +1,16 @@ + + //OPNsense/OpenVPNExport + 0.0.1 + OpenVPN export presets + + + + + Y + + + + + + + diff --git a/src/opnsense/mvc/app/views/OPNsense/OpenVPN/export.volt b/src/opnsense/mvc/app/views/OPNsense/OpenVPN/export.volt index f2ca352e2..ae2198a24 100644 --- a/src/opnsense/mvc/app/views/OPNsense/OpenVPN/export.volt +++ b/src/opnsense/mvc/app/views/OPNsense/OpenVPN/export.volt @@ -29,10 +29,56 @@ POSSIBILITY OF SUCH DAMAGE.
+ {{ partial("layout_partials/base_form",['fields':exportForm,'id':'frm_ExportSettings'])}} +