+
+
+{# 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'])}}
diff --git a/net/tinc/src/opnsense/scripts/OPNsense/Tinc/generate_keypair.py b/net/tinc/src/opnsense/scripts/OPNsense/Tinc/generate_keypair.py
new file mode 100755
index 000000000..879661ea9
--- /dev/null
+++ b/net/tinc/src/opnsense/scripts/OPNsense/Tinc/generate_keypair.py
@@ -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))
diff --git a/net/tinc/src/opnsense/scripts/OPNsense/Tinc/lib/__init__.py b/net/tinc/src/opnsense/scripts/OPNsense/Tinc/lib/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/net/tinc/src/opnsense/scripts/OPNsense/Tinc/lib/objects.py b/net/tinc/src/opnsense/scripts/OPNsense/Tinc/lib/objects.py
new file mode 100644
index 000000000..19cce73bd
--- /dev/null
+++ b/net/tinc/src/opnsense/scripts/OPNsense/Tinc/lib/objects.py
@@ -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'])
diff --git a/net/tinc/src/opnsense/scripts/OPNsense/Tinc/tincd.py b/net/tinc/src/opnsense/scripts/OPNsense/Tinc/tincd.py
new file mode 100755
index 000000000..331b84f9e
--- /dev/null
+++ b/net/tinc/src/opnsense/scripts/OPNsense/Tinc/tincd.py
@@ -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')
diff --git a/net/tinc/src/opnsense/service/templates/OPNsense/Tinc/+TARGETS b/net/tinc/src/opnsense/service/templates/OPNsense/Tinc/+TARGETS
new file mode 100644
index 000000000..fd832e540
--- /dev/null
+++ b/net/tinc/src/opnsense/service/templates/OPNsense/Tinc/+TARGETS
@@ -0,0 +1 @@
+tinc_deploy.xml:/usr/local/etc/tinc_deploy.xml
diff --git a/net/tinc/src/opnsense/service/templates/OPNsense/Tinc/tinc_deploy.xml b/net/tinc/src/opnsense/service/templates/OPNsense/Tinc/tinc_deploy.xml
new file mode 100644
index 000000000..3d11b8739
--- /dev/null
+++ b/net/tinc/src/opnsense/service/templates/OPNsense/Tinc/tinc_deploy.xml
@@ -0,0 +1,34 @@
+
+{% if helpers.exists('OPNsense.Tinc.networks.network') %}
+{% for network in helpers.toList('OPNsense.Tinc.networks.network', 'id') %}
+
+ {{network.id}}
+ {{network.hostname}}
+ {{network.name}}
+
+
+
+ {{network.hostname}}
+ {{network.name}}
+ {{network.extaddress}}
+ {{network.subnet}}
+
+ 0
+
+{% for host in helpers.toList('OPNsense.Tinc.hosts.host', 'hostname') %}
+{% if helpers.getUUID(host.network).id == network.id %}
+
+ {{host.hostname}}
+ {{network.name}}
+ {{host.extaddress}}
+ {{host.subnet}}
+
+ {{host.connectTo}}
+
+{% endif %}
+{% endfor %}
+
+
+{% endfor %}
+{% endif %}
+
\ No newline at end of file