(tinc) work in progress

This commit is contained in:
Ad Schellevis
2016-11-07 21:03:48 +01:00
parent 9920af61cc
commit e73df13288
15 changed files with 1029 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
PLUGIN_NAME= tinc
PLUGIN_VERSION= 0.1
PLUGIN_COMMENT= Tinc VPN
PLUGIN_DEPENDS= tinc
PLUGIN_MAINTAINER= ad@opnsense.org
.include "../../Mk/plugins.mk"
@@ -0,0 +1,56 @@
<?php
/**
* Copyright (C) 2016 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\Tinc\Api;
use \OPNsense\Base\ApiControllerBase;
use \OPNsense\Core\Backend;
/**
* Class ServiceController
* @package OPNsense\Tinc
*/
class ServiceController extends ApiControllerBase
{
/**
* reconfigure captive portal
*/
public function reconfigureAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$backend = new Backend();
$backend->configdRun('template reload OPNsense/Tinc');
return array("status" => "ok");
} else {
return array("status" => "failed");
}
}
}
@@ -0,0 +1,250 @@
<?php
/**
* Copyright (C) 2016 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\Tinc\Api;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Base\UIModelGrid;
use \OPNsense\Core\Backend;
/**
* Class SettingsController Handles settings related API actions for Tinc VPN
* @package OPNsense\Tinc
*/
class SettingsController extends ApiMutableModelControllerBase
{
static protected $internalModelName = 'tinc';
static protected $internalModelClass = '\OPNsense\Tinc\Tinc';
/**
* get network action
* @param string $uuid item unique id
* @return array
*/
public function getNetworkAction($uuid = null)
{
if ($uuid == null) {
// generate new node, but don't save to disc
$node = $this->getModel()->networks->network->Add();
return array("network" => $node->getNodes());
} else {
$node = $this->getModel()->getNodeByReference('networks.network.'.$uuid);
if ($node != null) {
// return node
return array("network" => $node->getNodes());
}
}
return array() ;
}
/**
* set network action
* @param string $uuid item unique id
* @return array
*/
public function setNetworkAction($uuid = null)
{
if ($this->request->isPost() && $this->request->hasPost("network")) {
if ($uuid != null) {
$node = $this->getModel()->getNodeByReference('networks.network.'.$uuid);
} else {
$node = $this->getModel()->networks->network->Add();
}
$node->setNodes($this->request->getPost("network"));
if (empty((string)$node->pubkey) || empty((string)$node->privkey)){
// generate new keypair
$backend = new Backend();
$keys = json_decode(trim($backend->configdRun("tinc gen-key")), true);
$node->pubkey = (string)$keys['pub'];
$node->privkey = $keys['priv'];
}
return $this->validateAndSave($node, 'network');
}
return array("result"=>"failed");
}
/**
* search user defined rules
* @return array list of found user rules
*/
public function searchNetworkAction()
{
$this->sessionClose();
$grid = new UIModelGrid($this->getModel()->networks->network);
return $grid->fetchBindRequest(
$this->request,
array("enabled", "name"),
"name"
);
}
/**
* del network action
* @param string $uuid item unique id
* @return array
*/
public function delNetworkAction($uuid)
{
$result = array('result' => 'failed');
if ($this->request->isPost()) {
if ($this->getModel()->networks->network->del($uuid)) {
$result = $this->validateAndSave();
}
}
return $result ;
}
/**
* toggle network item action
* @param string $uuid item unique id
* @param boolean $enabled
* @return array
*/
public function toggleNetworkAction($uuid, $enabled = null)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
if ($uuid != null) {
$node = $this->getModel()->getNodeByReference('networks.network.' . $uuid);
if ($node != null) {
if ($enabled == "0" || $enabled == "1") {
$node->enabled = (string)$enabled;
} elseif ((string)$node->enabled == "1") {
$node->enabled = "0";
} else {
$node->enabled = "1";
}
$result['result'] = $node->enabled;
$this->save();
}
}
}
return $result;
}
/**
* get host action
* @param string $uuid item unique id
* @return array
*/
public function getHostAction($uuid = null)
{
if ($uuid == null) {
// generate new node, but don't save to disc
$node = $this->getModel()->hosts->host->Add();
return array("host" => $node->getNodes());
} else {
$node = $this->getModel()->getNodeByReference('hosts.host.'.$uuid);
if ($node != null) {
// return node
return array("host" => $node->getNodes());
}
}
return array() ;
}
/**
* set host action
* @param string $uuid item unique id
* @return array
*/
public function setHostAction($uuid = null)
{
if ($this->request->isPost() && $this->request->hasPost("host")) {
if ($uuid != null) {
$node = $this->getModel()->getNodeByReference('hosts.host.'.$uuid);
} else {
$node = $this->getModel()->hosts->host->Add();
}
$node->setNodes($this->request->getPost("host"));
return $this->validateAndSave($node, 'host');
}
return array("result"=>"failed");
}
/**
* search user defined rules
* @return array list of found user rules
*/
public function searchHostAction()
{
$this->sessionClose();
$grid = new UIModelGrid($this->getModel()->hosts->host);
return $grid->fetchBindRequest(
$this->request,
array("enabled", "hostname", 'network'),
"name"
);
}
/**
* del host action
* @param string $uuid item unique id
* @return array
*/
public function delHostAction($uuid)
{
$result = array('result' => 'failed');
if ($this->request->isPost()) {
if ($this->getModel()->hosts->host->del($uuid)) {
$result = $this->validateAndSave();
}
}
return $result ;
}
/**
* toggle host item action
* @param string $uuid item unique id
* @param boolean $enabled
* @return array
*/
public function toggleHostAction($uuid, $enabled = null)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
if ($uuid != null) {
$node = $this->getModel()->getNodeByReference('hosts.host.' . $uuid);
if ($node != null) {
if ($enabled == "0" || $enabled == "1") {
$node->enabled = (string)$enabled;
} elseif ((string)$node->enabled == "1") {
$node->enabled = "0";
} else {
$node->enabled = "1";
}
$result['result'] = $node->enabled;
$this->save();
}
}
}
return $result;
}
}
@@ -0,0 +1,48 @@
<?php
/**
* Copyright (C) 2016 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\Tinc;
/**
* Class IndexController
* @package OPNsense\Tinc
*/
class IndexController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->title = gettext('Tinc VPN');
// link dialogs
$this->view->formDialogNetwork = $this->getForm("dialogNetwork");
$this->view->formDialogHost = $this->getForm("dialogHost");
// choose template
$this->view->pick('OPNsense/Tinc/index');
}
}
@@ -0,0 +1,44 @@
<form>
<field>
<id>host.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>Enable this network</help>
</field>
<field>
<id>host.network</id>
<label>Network</label>
<type>dropdown</type>
<help>The network for this host</help>
</field>
<field>
<id>host.hostname</id>
<label>Hostname</label>
<type>text</type>
<help>The hostname for the selected machine in the network</help>
</field>
<field>
<id>host.extaddress</id>
<label>Ext. Address</label>
<type>text</type>
<help>This machines external address to use</help>
</field>
<field>
<id>host.subnet</id>
<label>Subnet</label>
<type>text</type>
<help>This machines part of the network</help>
</field>
<field>
<id>host.pubkey</id>
<label>Public key</label>
<type>textbox</type>
<help>Public key for this host in the network</help>
</field>
<field>
<id>host.connectTo</id>
<label>Connect To</label>
<type>checkbox</type>
<help>Connect to this host</help>
</field>
</form>
@@ -0,0 +1,60 @@
<form>
<field>
<id>network.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>Enable this network</help>
</field>
<field>
<id>network.name</id>
<label>Network Name</label>
<type>text</type>
<help>Name used for this network</help>
</field>
<field>
<id>network.network</id>
<label>VPN network</label>
<type>text</type>
<help>Network for this VPN, where all hosts should fit in.</help>
</field>
<field>
<label>This Host</label>
<type>header</type>
</field>
<field>
<id>network.hostname</id>
<label>Hostname</label>
<type>text</type>
<help>The hostname for this machine in the network</help>
</field>
<field>
<id>network.extaddress</id>
<label>Ext. Address</label>
<type>text</type>
<help>This machines external address to use</help>
</field>
<field>
<id>network.intaddress</id>
<label>Int. Address</label>
<type>text</type>
<help>This machines internal address to use (within specified subnet)</help>
</field>
<field>
<id>network.subnet</id>
<label>Subnet</label>
<type>text</type>
<help>This machines part of the network</help>
</field>
<field>
<id>network.privkey</id>
<label>Private key</label>
<type>textbox</type>
<help>Private key for this host in the network (leave empty to generate)</help>
</field>
<field>
<id>network.pubkey</id>
<label>Public key</label>
<type>textbox</type>
<help>Public key for this host in the network (leave empty to generate)</help>
</field>
</form>
@@ -0,0 +1,39 @@
<?php
/**
* Copyright (C) 2016 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\Tinc;
use OPNsense\Base\BaseModel;
/**
* Class Tinc
* @package OPNsense\Tinc
*/
class Tinc extends BaseModel
{
}
@@ -0,0 +1,99 @@
<model>
<mount>//OPNsense/Tinc</mount>
<version>1.0.0</version>
<description>
OPNsense Tinc VPN
</description>
<items>
<networks>
<network type="ArrayField">
<id type="AutoNumberField">
<ValidationMessage>ID should be a number.</ValidationMessage>
<Required>Y</Required>
</id>
<name type="TextField">
<Required>Y</Required>
<mask>/^([0-9a-zA-Z]){1,50}$/u</mask>
<ValidationMessage>The name should contain only alphanumeric characters.</ValidationMessage>
</name>
<hostname type="TextField">
<Required>Y</Required>
<mask>/^([0-9a-zA-Z\.]){1,1024}$/u</mask>
<ValidationMessage>Please specify a valid hostname.</ValidationMessage>
</hostname>
<extaddress type="NetworkField">
<Required>Y</Required>
<WildcardEnabled>N</WildcardEnabled>
<FieldSeparator>,</FieldSeparator>
</extaddress>
<intaddress type="NetworkField">
<Required>Y</Required>
<WildcardEnabled>N</WildcardEnabled>
</intaddress>
<subnet type="NetworkField">
<Required>Y</Required>
<WildcardEnabled>N</WildcardEnabled>
<NetMaskRequired>Y</NetMaskRequired>
<FieldSeparator>,</FieldSeparator>
</subnet>
<network type="NetworkField">
<Required>Y</Required>
<WildcardEnabled>N</WildcardEnabled>
<NetMaskRequired>Y</NetMaskRequired>
</network>
<privkey type="TextField">
<Required>Y</Required>
</privkey>
<pubkey type="TextField">
<Required>Y</Required>
</pubkey>
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
</network>
</networks>
<hosts>
<host type="ArrayField">
<network type="ModelRelationField">
<Model>
<hosts>
<source>OPNsense.Tinc.Tinc</source>
<items>networks.network</items>
<display>name</display>
</hosts>
</Model>
<ValidationMessage>Related pipe or queue not found</ValidationMessage>
<Required>Y</Required>
</network>
<hostname type="TextField">
<Required>Y</Required>
<mask>/^([0-9a-zA-Z\.]){1,1024}$/u</mask>
<ValidationMessage>Please specify a valid hostname.</ValidationMessage>
</hostname>
<extaddress type="NetworkField">
<Required>Y</Required>
<WildcardEnabled>N</WildcardEnabled>
<FieldSeparator>,</FieldSeparator>
</extaddress>
<subnet type="NetworkField">
<Required>Y</Required>
<WildcardEnabled>N</WildcardEnabled>
<NetMaskRequired>Y</NetMaskRequired>
<FieldSeparator>,</FieldSeparator>
</subnet>
<pubkey type="TextField">
<Required>Y</Required>
</pubkey>
<connectTo type="BooleanField">
<default>1</default>
<Required>Y</Required>
</connectTo>
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
</host>
</hosts>
</items>
</model>
@@ -0,0 +1,155 @@
{#
OPNsense® is Copyright © 2014 2016 by 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.
#}
<script type="text/javascript">
$( document ).ready(function() {
/*************************************************************************************************************
* link grid actions
*************************************************************************************************************/
$("#grid-networks").UIBootgrid(
{ search:'/api/tinc/settings/searchNetwork',
get:'/api/tinc/settings/getNetwork/',
set:'/api/tinc/settings/setNetwork/',
add:'/api/tinc/settings/setNetwork/',
del:'/api/tinc/settings/delNetwork/',
toggle:'/api/tinc/settings/toggleNetwork/'
}
);
$("#grid-hosts").UIBootgrid(
{ search:'/api/tinc/settings/searchHost',
get:'/api/tinc/settings/getHost/',
set:'/api/tinc/settings/setHost/',
add:'/api/tinc/settings/setHost/',
del:'/api/tinc/settings/delHost/',
toggle:'/api/tinc/settings/toggleHost/'
}
);
/*************************************************************************************************************
* Commands
*************************************************************************************************************/
/**
* Reconfigure
*/
$("#reconfigureAct").click(function(){
$("#reconfigureAct_progress").addClass("fa fa-spinner fa-pulse");
ajaxCall(url="/api/tinc/service/reconfigure", sendData={}, callback=function(data,status) {
// when done, disable progress animation.
$("#reconfigureAct_progress").removeClass("fa fa-spinner fa-pulse");
if (status != "success" || data['status'] != 'ok') {
BootstrapDialog.show({
type: BootstrapDialog.TYPE_WARNING,
title: "{{ lang._('Error reconfiguring Tinc') }}",
message: data['status'],
draggable: true
});
}
});
});
});
</script>
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
<li class="active"><a data-toggle="tab" href="#networks">{{ lang._('Networks') }}</a></li>
<li><a data-toggle="tab" href="#hosts">{{ lang._('Hosts') }}</a></li>
</ul>
<div class="tab-content content-box tab-content">
<div id="networks" class="tab-pane fade in active">
<!-- tab page "networks" -->
<table id="grid-networks" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="DialogNetwork">
<thead>
<tr>
<th data-column-id="enabled" data-width="6em" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="id" data-type="number" data-visible="false">{{ lang._('ID') }}</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>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
<div id="hosts" class="tab-pane fade in">
<div class="col-md-12">
<!-- tab page "networks" -->
<table id="grid-hosts" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="DialogHost">
<thead>
<tr>
<th data-column-id="enabled" data-width="6em" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="network" data-type="string">{{ lang._('Network') }}</th>
<th data-column-id="hostname" data-type="string">{{ lang._('Hostname') }}</th>
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
<div class="col-md-12">
<hr/>
<button class="btn btn-primary" id="reconfigureAct" type="button"><b>{{ lang._('Apply') }}</b><i id="reconfigureAct_progress" class=""></i></button>
<br/><br/>
</div>
</div>
{# include dialogs #}
{{ partial("layout_partials/base_dialog",['fields':formDialogNetwork,'id':'DialogNetwork','label':'Edit Network'])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogHost,'id':'DialogHost','label':'Edit Host'])}}
@@ -0,0 +1,55 @@
#!/usr/local/bin/python2.7
"""
Copyright (c) 2016 Deciso B.V. - Ad Schellevis
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.
--------------------------------------------------------------------------------------
generate new keypair
"""
import os
import tempfile
import glob
import ujson
# create temp directory
temp_dir = tempfile.mkdtemp()
# generate certs
os.system('echo | /usr/local/sbin/tincd -K --config=%s 2>/dev/null' % (temp_dir))
# read and remove certs
response=dict()
for filename in glob.glob('%s/*'%temp_dir):
data = open(filename,'r').read().strip()
if filename.endswith('.priv'):
response['priv'] = data
elif filename.endswith('.pub'):
response['pub'] = data
os.remove(filename)
# cleanup
os.rmdir(temp_dir)
# output generated keys
print(ujson.dumps(response))
@@ -0,0 +1,116 @@
"""
Copyright (c) 2016 Deciso B.V. - Ad Schellevis
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.
"""
class NetwConfObject(object):
def __init__(self):
self._payload = dict()
self._payload['hostname'] = None
self._payload['network'] = None
def is_valid(self):
for key in self._payload:
if self._payload[key] is None:
return False
return True
def set(self, prop, value):
if ('set_%s' % prop) in dir(self):
getattr(self,'set_%s' % prop)(value)
else:
# default copy propery to _payload
self._payload[prop] = value.text
def get_hostname(self):
return self._payload['hostname']
def get_basepath(self):
return '/usr/local/etc/tinc/%(network)s' % self._payload
class Network(NetwConfObject):
def __init__(self):
super(Network, self).__init__()
self._payload['id'] = None
self._payload['privkey'] = None
self._hosts = list()
def set_id(self, value):
self._payload['id'] = value.text
def set_hosts(self, hosts):
for host in hosts:
hostObj = Host()
for host_prop in host:
hostObj.set(host_prop.tag, host_prop)
self._hosts.append(hostObj)
def config_text(self):
result = list()
result.append('AddressFamily=any')
for host in self._hosts:
if host.connect_to_this_host():
result.append('ConnectTo = %s' % (host.get_hostname(),))
result.append('Device=/dev/tinc%(id)s' % self._payload)
result.append('Name=%(hostname)s' % self._payload)
return '\n'.join(result)
def filename(self):
return self.get_basepath() + '/tinc.conf'
def privkey(self):
return {'filename': self.get_basepath() + '/rsa_key.priv', 'content': self._payload['privkey']}
def all(self):
yield self
for host in self._hosts:
yield host
class Host(NetwConfObject):
def __init__(self):
super(Host, self).__init__()
self._connectTo = "0"
self._payload['address'] = None
self._payload['subnet'] = None
self._payload['pubkey'] = None
def connect_to_this_host(self):
if self.is_valid() and self._connectTo == "1":
return True
else:
return False
def set_connectto(self, value):
self._connectTo = value.text
def config_text(self):
result = list()
result.append('Address=%(address)s'%self._payload)
result.append('Subnet=%(subnet)s'%self._payload)
result.append(self._payload['pubkey'])
return '\n'.join(result)
def filename(self):
return '%s/hosts/%s' % (self.get_basepath(), self._payload['hostname'])
+65
View File
@@ -0,0 +1,65 @@
#!/usr/local/bin/python2.7
"""
Copyright (c) 2016 Deciso B.V. - Ad Schellevis
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.
--------------------------------------------------------------------------------------
reconfigure tincd, using the supplied configuration
"""
import os
import tempfile
import glob
import xml.etree.ElementTree
from lib import objects
def write_file(filename, content):
dirname = '/'.join(filename.split('/')[0:-1])
if not os.path.isdir(dirname):
os.makedirs(dirname)
open(filename, 'w').write(content)
def deploy(config_filename):
# collect file info
config_files=dict()
if os.path.isfile(config_filename):
for network in xml.etree.ElementTree.parse(config_filename).getroot():
Network_obj = objects.Network()
for network_prop in network:
Network_obj.set(network_prop.tag, network_prop)
# check if config is complete before collecting output files
if Network_obj.is_valid():
for conf_obj in Network_obj.all():
if conf_obj.is_valid():
config_files[conf_obj.filename()] = conf_obj.config_text()
# private key
tmp = Network_obj.privkey()
config_files[tmp['filename']] = tmp['content']
# remove previous configuration
os.system('rm -rf /usr/local/etc/tinc')
# write output
for filename in config_files:
write_file(filename, config_files[filename])
deploy('/usr/local/etc/tinc_deploy.xml')
@@ -0,0 +1 @@
tinc_deploy.xml:/usr/local/etc/tinc_deploy.xml
@@ -0,0 +1,34 @@
<networks>
{% if helpers.exists('OPNsense.Tinc.networks.network') %}
{% for network in helpers.toList('OPNsense.Tinc.networks.network', 'id') %}
<network>
<id>{{network.id}}</id>
<hostname>{{network.hostname}}</hostname>
<network>{{network.name}}</network>
<privkey><![CDATA[{{network.privkey}}]]></privkey>
<hosts>
<host>
<hostname>{{network.hostname}}</hostname>
<network>{{network.name}}</network>
<address>{{network.extaddress}}</address>
<subnet>{{network.subnet}}</subnet>
<pubkey><![CDATA[{{network.pubkey}}]]></pubkey>
<connectto>0</connectto>
</host>
{% for host in helpers.toList('OPNsense.Tinc.hosts.host', 'hostname') %}
{% if helpers.getUUID(host.network).id == network.id %}
<host>
<hostname>{{host.hostname}}</hostname>
<network>{{network.name}}</network>
<address>{{host.extaddress}}</address>
<subnet>{{host.subnet}}</subnet>
<pubkey><![CDATA[{{host.pubkey}}]]></pubkey>
<connectto>{{host.connectTo}}</connectto>
</host>
{% endif %}
{% endfor %}
</hosts>
</network>
{% endfor %}
{% endif %}
</networks>