From 72a71eba0331b3114c794682f7e13f63dd6b9377 Mon Sep 17 00:00:00 2001 From: David Harrigan Date: Fri, 28 Jul 2017 20:20:20 +0100 Subject: [PATCH] Zerotier Plugin (#211) * Introduce Zerotier * Add in services configuration. * Add in Save callback to restart Zerotier Service * Ensure interface is removed when deleting network. --- net/zerotier/Makefile | 7 + net/zerotier/pkg-descr | 6 + .../src/etc/inc/plugins.inc.d/zerotier.inc | 44 ++++ .../Zerotier/Api/ZerotierController.php | 193 ++++++++++++++++++ .../OPNsense/Zerotier/IndexController.php | 40 ++++ .../OPNsense/Zerotier/forms/dialogNetwork.xml | 14 ++ .../app/models/OPNsense/Zerotier/ACL/ACL.xml | 9 + .../models/OPNsense/Zerotier/Menu/Menu.xml | 5 + .../app/models/OPNsense/Zerotier/Zerotier.php | 37 ++++ .../app/models/OPNsense/Zerotier/Zerotier.xml | 24 +++ .../app/views/OPNsense/Zerotier/index.volt | 99 +++++++++ .../conf/actions.d/actions_zerotier.conf | 29 +++ .../templates/OPNsense/zerotier/+TARGETS | 1 + .../templates/OPNsense/zerotier/zerotier | 1 + 14 files changed, 509 insertions(+) create mode 100644 net/zerotier/Makefile create mode 100644 net/zerotier/pkg-descr create mode 100644 net/zerotier/src/etc/inc/plugins.inc.d/zerotier.inc create mode 100644 net/zerotier/src/opnsense/mvc/app/controllers/OPNsense/Zerotier/Api/ZerotierController.php create mode 100644 net/zerotier/src/opnsense/mvc/app/controllers/OPNsense/Zerotier/IndexController.php create mode 100644 net/zerotier/src/opnsense/mvc/app/controllers/OPNsense/Zerotier/forms/dialogNetwork.xml create mode 100644 net/zerotier/src/opnsense/mvc/app/models/OPNsense/Zerotier/ACL/ACL.xml create mode 100644 net/zerotier/src/opnsense/mvc/app/models/OPNsense/Zerotier/Menu/Menu.xml create mode 100644 net/zerotier/src/opnsense/mvc/app/models/OPNsense/Zerotier/Zerotier.php create mode 100644 net/zerotier/src/opnsense/mvc/app/models/OPNsense/Zerotier/Zerotier.xml create mode 100644 net/zerotier/src/opnsense/mvc/app/views/OPNsense/Zerotier/index.volt create mode 100644 net/zerotier/src/opnsense/service/conf/actions.d/actions_zerotier.conf create mode 100644 net/zerotier/src/opnsense/service/templates/OPNsense/zerotier/+TARGETS create mode 100644 net/zerotier/src/opnsense/service/templates/OPNsense/zerotier/zerotier diff --git a/net/zerotier/Makefile b/net/zerotier/Makefile new file mode 100644 index 000000000..18ed4344e --- /dev/null +++ b/net/zerotier/Makefile @@ -0,0 +1,7 @@ +PLUGIN_NAME= zerotier +PLUGIN_VERSION= 0.1.0 +PLUGIN_COMMENT= Network virtualization everywhere +PLUGIN_DEPENDS= zerotier +PLUGIN_MAINTAINER= dharrigan@gmail.com + +.include "../../Mk/plugins.mk" diff --git a/net/zerotier/pkg-descr b/net/zerotier/pkg-descr new file mode 100644 index 000000000..86055c593 --- /dev/null +++ b/net/zerotier/pkg-descr @@ -0,0 +1,6 @@ +ZeroTier can be used for on-premise network virtualization, as a +peer to peer VPN for mobile teams, for hybrid or multi-data-center +cloud deployments, or just about anywhere else secure software +defined virtual networking is useful. + +WWW: https://www.zerotier.com diff --git a/net/zerotier/src/etc/inc/plugins.inc.d/zerotier.inc b/net/zerotier/src/etc/inc/plugins.inc.d/zerotier.inc new file mode 100644 index 000000000..234eb3c68 --- /dev/null +++ b/net/zerotier/src/etc/inc/plugins.inc.d/zerotier.inc @@ -0,0 +1,44 @@ + gettext('Zerotier'), + 'configd' => array( + 'restart' => array('zerotier restart'), + 'start' => array('zerotier start'), + 'stop' => array('zerotier stop'), + ), + 'name' => 'zerotier', + 'pidfile' => '/var/db/zerotier-one/zerotier-one.pid' + ); + return $services; +} diff --git a/net/zerotier/src/opnsense/mvc/app/controllers/OPNsense/Zerotier/Api/ZerotierController.php b/net/zerotier/src/opnsense/mvc/app/controllers/OPNsense/Zerotier/Api/ZerotierController.php new file mode 100644 index 000000000..11ddd3c1c --- /dev/null +++ b/net/zerotier/src/opnsense/mvc/app/controllers/OPNsense/Zerotier/Api/ZerotierController.php @@ -0,0 +1,193 @@ +request->isGet()) { + $mdlZerotier = new Zerotier(); + $result['zerotier'] = $mdlZerotier->getNodes(); + } + return $result; + } + + public function searchNetworkAction() + { + $this->sessionClose(); + $mdlZerotier = $this->getModel(); + $grid = new UIModelGrid($mdlZerotier->networks->network); + return $grid->fetchBindRequest( + $this->request, + array("enabled", "networkId", "description") + ); + } + + public function getNetworkAction($uuid = null) + { + $mdlZerotier = $this->getModel(); + if ($uuid != null) { + $network = $mdlZerotier->getNodeByReference('networks.network.' . $uuid); + if ($network != null) { + return array("network" => $network->getNodes()); + } + } else { + $network = $mdlZerotier->networks->network->add(); + return array("network" => $network->getNodes()); + } + return array(); + } + + public function setNetworkAction() + { + $result = array("result" => "failed"); + if ($this->request->isPost()) { + $mdlZerotier = new Zerotier(); + $mdlZerotier->setNodes($this->request->getPost("network")); + $validationMessages = $mdlZerotier->performValidation(); + foreach ($validationMessages as $field => $msg) { + if(!array_key_exists("validation", $result)) { + $result["validations"] = array(); + } + $result["validation"]["network.".$msg->getField()] = $msg->getMessage(); + } + if($validationMessages->count() == 0) { + unset($result["validations"]); + $mdlZerotier->serializeToConfig(); + Config::getInstance()->save(); + $result["result"] = "saved"; + } + } + return $result; + } + + public function addNetworkAction() + { + $result = array("result" => "failed"); + if ($this->request->isPost() && $this->request->hasPost("network")) { + $result = array("result" => "failed", "validations" => array()); + $mdlZerotier = $this->getModel(); + $network = $mdlZerotier->networks->network->add(); + $network->setNodes($this->request->getPost("network")); + $validationMessages = $mdlZerotier->performValidation(); + foreach ($validationMessages as $field => $msg) { + $fieldName = str_replace($network->__reference, "network", $msg->getField()); + $result["validations"][$fieldName] = $msg->getMessage(); + } + if ($validationMessages->count() == 0) { + unset($result["validations"]); + $mdlZerotier->serializeToConfig(); + Config::getInstance()->save(); + $result["result"] = "saved"; + } + + } + return $result; + } + + public function delNetworkAction($uuid = null) + { + $result = array("result" => "failed"); + if ($this->request->isPost()) { + $mdlZerotier = $this->getModel(); + if ($uuid != null) { + $node = $mdlZerotier->getNodeByReference('networks.network.' . $uuid); + if ($node->enabled->__toString() == "1") { + # Ensure we remove the interface before deleting the network + $this->toggleZerotierNetwork($node->networkId, 0); + } + if ($mdlZerotier->networks->network->del($uuid)) { + $mdlZerotier->serializeToConfig(); + Config::getInstance()->save(); + $result["result"] = "deleted"; + } else { + $result["result"] = "not found"; + } + } + } + return $result; + } + + public function toggleNetworkAction($uuid) + { + $result = array("result" => "failed"); + if ($this->request->isPost()) { + $mdlZerotier = $this->getModel(); + if ($uuid != null) { + $node = $mdlZerotier->getNodeByReference('networks.network.' . $uuid); + if ($node != null) { + $networkId = $node->networkId; + if ($node->enabled->__toString() == "1") { + $node->enabled = "0"; + $result['result'] = $this->toggleZerotierNetwork($networkId, 0); + } else { + $node->enabled = "1"; + $result['result'] = $this->toggleZerotierNetwork($networkId, 1); + } + $mdlZerotier->serializeToConfig(); + Config::getInstance()->save(); + } + } + } + return $result; + } + + public function reconfigureZerotierAction() + { + if ($this->request->isPost()) { + $this->sessionClose(); + $backend = new Backend(); + $backend->configdRun("template reload OPNsense/zerotier"); + $result = trim($backend->configdRun("zerotier restart")); + return array("status" => $result); + } else { + return array("status" => "failed"); + } + } + + private function toggleZerotierNetwork($networkId, $enabled) + { + $backend = new Backend(); + return trim($backend->configdRun("zerotier ".($enabled ? "join " : "leave ").$networkId)); + } + +} diff --git a/net/zerotier/src/opnsense/mvc/app/controllers/OPNsense/Zerotier/IndexController.php b/net/zerotier/src/opnsense/mvc/app/controllers/OPNsense/Zerotier/IndexController.php new file mode 100644 index 000000000..cfa96678b --- /dev/null +++ b/net/zerotier/src/opnsense/mvc/app/controllers/OPNsense/Zerotier/IndexController.php @@ -0,0 +1,40 @@ +view->title = "VPN: Zerotier"; + $this->view->pick('OPNsense/Zerotier/index'); + $this->view->formDialogNetwork = $this->getForm("dialogNetwork"); + } +} diff --git a/net/zerotier/src/opnsense/mvc/app/controllers/OPNsense/Zerotier/forms/dialogNetwork.xml b/net/zerotier/src/opnsense/mvc/app/controllers/OPNsense/Zerotier/forms/dialogNetwork.xml new file mode 100644 index 000000000..7f153b64b --- /dev/null +++ b/net/zerotier/src/opnsense/mvc/app/controllers/OPNsense/Zerotier/forms/dialogNetwork.xml @@ -0,0 +1,14 @@ +
+ + network.networkId + + text + Zerotier Network ID e.g., 161411d4f6abe4a7 + + + network.description + + text + Description to help identify this network + +
diff --git a/net/zerotier/src/opnsense/mvc/app/models/OPNsense/Zerotier/ACL/ACL.xml b/net/zerotier/src/opnsense/mvc/app/models/OPNsense/Zerotier/ACL/ACL.xml new file mode 100644 index 000000000..144ce82e5 --- /dev/null +++ b/net/zerotier/src/opnsense/mvc/app/models/OPNsense/Zerotier/ACL/ACL.xml @@ -0,0 +1,9 @@ + + + VPN: Zerotier + + ui/zerotier/* + api/zerotier/* + + + diff --git a/net/zerotier/src/opnsense/mvc/app/models/OPNsense/Zerotier/Menu/Menu.xml b/net/zerotier/src/opnsense/mvc/app/models/OPNsense/Zerotier/Menu/Menu.xml new file mode 100644 index 000000000..55c880fef --- /dev/null +++ b/net/zerotier/src/opnsense/mvc/app/models/OPNsense/Zerotier/Menu/Menu.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/net/zerotier/src/opnsense/mvc/app/models/OPNsense/Zerotier/Zerotier.php b/net/zerotier/src/opnsense/mvc/app/models/OPNsense/Zerotier/Zerotier.php new file mode 100644 index 000000000..5c7197136 --- /dev/null +++ b/net/zerotier/src/opnsense/mvc/app/models/OPNsense/Zerotier/Zerotier.php @@ -0,0 +1,37 @@ + + //OPNsense/zerotier + + Zerotier - Virtual Networks That Just Work. + + + + + + 0 + Y + + + + Y + + + + N + + + + + diff --git a/net/zerotier/src/opnsense/mvc/app/views/OPNsense/Zerotier/index.volt b/net/zerotier/src/opnsense/mvc/app/views/OPNsense/Zerotier/index.volt new file mode 100644 index 000000000..7fa725644 --- /dev/null +++ b/net/zerotier/src/opnsense/mvc/app/views/OPNsense/Zerotier/index.volt @@ -0,0 +1,99 @@ +{# + +OPNsense® is Copyright © 2014 – 2017 by Deciso B.V. +Copyright (C) 2017 David Harrigan + +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. + +#} + + + + +
+
+ + + + + + + + + + + + + + + + + +
{{ lang._('Enabled') }}{{ lang._('Network Id') }}{{ lang._('Description') }}{{ lang._('ID') }}
+ + +
+
+
+
+ +

+
+
+ +{{ partial("layout_partials/base_dialog",['fields':formDialogNetwork,'id':'dialogNetwork','label':lang._('Edit Zerotier Network')]) }} diff --git a/net/zerotier/src/opnsense/service/conf/actions.d/actions_zerotier.conf b/net/zerotier/src/opnsense/service/conf/actions.d/actions_zerotier.conf new file mode 100644 index 000000000..43a130f70 --- /dev/null +++ b/net/zerotier/src/opnsense/service/conf/actions.d/actions_zerotier.conf @@ -0,0 +1,29 @@ +[start] +command:/usr/local/etc/rc.d/zerotier start +parameters: +type:script +message:Starting Zerotier Service + +[stop] +command:/usr/local/etc/rc.d/zerotier stop +parameters: +type:script +message:Stopping Zerotier Service + +[restart] +command:/usr/local/etc/rc.d/zerotier restart +parameters: +type:script +message:Restarting Zerotier Service + +[join] +command:/usr/local/bin/zerotier-cli +parameters: join %s +type:script_output +message:Joining Zerotier Network + +[leave] +command:/usr/local/bin/zerotier-cli +parameters: leave %s +type:script_output +message:Leaving Zerotier Network diff --git a/net/zerotier/src/opnsense/service/templates/OPNsense/zerotier/+TARGETS b/net/zerotier/src/opnsense/service/templates/OPNsense/zerotier/+TARGETS new file mode 100644 index 000000000..7eb39ec11 --- /dev/null +++ b/net/zerotier/src/opnsense/service/templates/OPNsense/zerotier/+TARGETS @@ -0,0 +1 @@ +zerotier:/etc/rc.conf.d/zerotier diff --git a/net/zerotier/src/opnsense/service/templates/OPNsense/zerotier/zerotier b/net/zerotier/src/opnsense/service/templates/OPNsense/zerotier/zerotier new file mode 100644 index 000000000..4fcc16cf5 --- /dev/null +++ b/net/zerotier/src/opnsense/service/templates/OPNsense/zerotier/zerotier @@ -0,0 +1 @@ +zerotier_enable="YES"